diff --git a/build-utils/README_series_r_p701.txt b/build-utils/README_series_r_p701.txt new file mode 100644 index 000000000..ad3b4d2a5 --- /dev/null +++ b/build-utils/README_series_r_p701.txt @@ -0,0 +1,20 @@ +--------------------------------------------------------------------|---------------------------------- +files/202511/PATCH_NAME |submodule-directory +--------------------------------------------------------------------|---------------------------------- +0041-buildimage-print-each-build-target-on-separated-line.patch |sonic-buildimage +0064-build_templates-marvell-blacklist-with-kempld.patch |sonic-buildimage +0031-Falcon-usb-disk-hung_task-WA.patch |sonic-buildimage +0041-grub2-grub_cmd_sleep-increase-tolerance-to-14sec.patch |sonic-buildimage +0043-marvell-prestera-rpc-pin-ptf_nn_agent.py-to-use-nnpy.patch |sonic-buildimage + +0013-sonic_installer-add-sync-before-migration.patch |src/sonic-utilities +0060-sonic-ext.target-wrapper-for-sonic.target.patch |platform/marvell-prestera/mrvl-prestera +0061-sonic.target-no-install-oveload-for-sonic-ext.target.patch |platform/marvell-prestera/mrvl-prestera +0104-platform-X-arm64-mrvl-pcie-ep-check-reboot-on-EP-miss.patch |platform/marvell-prestera/mrvl-prestera + +--------------------------------------------------------------------|---------------------------------- +files/202511/1/PATCH_NAME (applied for AMD64 only) |submodule-directory +--------------------------------------------------------------------|---------------------------------- +1001-vlan1-CLI-changes-to-allow-vlan1.patch |src/sonic-utilities +1002-vlan1-Yang-changes-to-allow-vlan-1.patch |sonic-buildimage +1003-vlan1-orchagent-changes-to-skip-addition-and-deletio.patch |src/sonic-swss diff --git a/build-utils/arti-copy.sh b/build-utils/arti-copy.sh index 10cc5ba79..348a72b13 100755 --- a/build-utils/arti-copy.sh +++ b/build-utils/arti-copy.sh @@ -13,7 +13,7 @@ SONIC_SOURCE_DIR="$(basename "$(dirname "$CURR_DIR")")" # Extract BRANCH as second field between first and second '-' BRANCH="$(echo "$SONIC_SOURCE_DIR" | cut -d'-' -f2)" case "$BRANCH" in - master|202505|202511) + master|202505|202511|202605) l_DEBIAN=bookworm ;; trixie) @@ -78,10 +78,10 @@ copy_build_artifacts() if [ "$TARG_SUFFIX" = "" ]; then cp -a ${TARGET} $BUILD_ARTIFACTS_DIR echo "${LOG_PATH}/$TARGET_FILE" >> $ARTIFACTS_LOG - if [ -f target/debs/${l_DEBIAN}/swss-dbg_1.0.0_*.deb ]; then - cp -a target/debs/${l_DEBIAN}/swss-dbg_1.0.0_*.deb $BUILD_ARTIFACTS_DIR - fi - cp -a target/debs/${l_DEBIAN}/sonic-platform-*.deb $BUILD_ARTIFACTS_DIR + #if [ -f target/debs/${l_DEBIAN}/swss-dbg_1.0.0_*.deb ]; then + # cp -a target/debs/${l_DEBIAN}/swss-dbg_1.0.0_*.deb $BUILD_ARTIFACTS_DIR + #fi + #cp -a target/debs/${l_DEBIAN}/sonic-platform-*.deb $BUILD_ARTIFACTS_DIR if [ -f target/docker-saiserverv2-${PLATFORM_SHORT_NAME}.gz ]; then cp -a target/docker-saiserverv2-${PLATFORM_SHORT_NAME}.gz $BUILD_ARTIFACTS_DIR fi diff --git a/build-utils/create-script-tarball.sh b/build-utils/create-script-tarball.sh index baef2b7af..250d2a7e9 100755 --- a/build-utils/create-script-tarball.sh +++ b/build-utils/create-script-tarball.sh @@ -13,12 +13,13 @@ cd "$PROJECT_DIR" rm -f $R_TAR_GZ sonic_build_r_*.sh cp build-utils/sbuild_r_${RELEASE}*.sh . +cp build-utils/README_series_r_${RELEASE}.txt . tar czf $R_TAR_GZ \ --exclude='files/master/TBD' \ --exclude='files/master/tl' \ --exclude='files/202511/tl' \ files/202511 \ files/master \ - *.sh - + *.sh \ + README_series_r_${RELEASE}.txt diff --git a/files/202605/0013-sonic_installer-add-sync-before-migration.patch b/files/202605/0013-sonic_installer-add-sync-before-migration.patch new file mode 100644 index 000000000..073470375 --- /dev/null +++ b/files/202605/0013-sonic_installer-add-sync-before-migration.patch @@ -0,0 +1,38 @@ +From c113b0d1d550b8c51cd31b1af5c29840bb9e325f Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Sun, 22 Jun 2025 18:09:40 +0300 +Subject: [PATCH 1/1] sonic_installer: add sync before migration + +Add extra 'sync' command to the sonic_installer to eliminate +timeout failure in the following command + chroot /tmp/image-fs sonic-package-manager \ + migrate /tmp/packages.json --dockerd-socket /tmp/docker.sock +on a slow or removable disk (for example - on Intel-Falcon board). + +This sync should be called before first chroot. + +Signed-off-by: Yan Markman +--- + sonic_installer/main.py | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sonic_installer/main.py b/sonic_installer/main.py +index 6a445504..4cc48725 100644 +--- a/sonic_installer/main.py ++++ b/sonic_installer/main.py +@@ -358,6 +358,12 @@ def migrate_sonic_packages(bootloader, binary_image_version): + run_command_or_raise(["mkdir", "-p", new_image_work_dir]) + mount_overlay_fs(new_image_mount, new_image_upper_dir, new_image_work_dir, new_image_mount) + mount_bind(new_image_docker_dir, new_image_docker_mount) ++ ++ # sync to eliminate timeout on the ++ # chroot /tmp/image-fs SONIC_PACKAGE_MANAGER migrate /tmp/packages.json --dockerd-socket DOCKERD_SOCK ++ click.echo('Command sync ... could take several seconds on slow or removable disk') ++ run_command(["sync"]) ++ + mount_procfs_chroot(new_image_mount) + mount_sysfs_chroot(new_image_mount) + # Assume if docker.sh script exists we are installing Application Extension compatible image. +-- +2.25.1 + diff --git a/files/202605/0016-swss-syncd-time.monotonic.patch b/files/202605/0016-swss-syncd-time.monotonic.patch new file mode 100644 index 000000000..e3282d8f3 --- /dev/null +++ b/files/202605/0016-swss-syncd-time.monotonic.patch @@ -0,0 +1,56 @@ +From 57334c606a7841b89e1e09ea6f3aeb7071ea7a4b Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Mon, 1 Jun 2026 19:21:54 +0300 +Subject: [PATCH 1/1] swss-syncd time.monotonic + +PROBLEM: +On chrony or "date -s SET" command the wall-time is changed +and abrupts the wall/realtime taken by the time.time(). +FIX: +Use the time.monotonic() which is not changed un date/wall-time. + +Signed-off-by: Yan Markman +--- + config/main.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/config/main.py b/config/main.py +index a495c933..ce222fe1 100644 +--- a/config/main.py ++++ b/config/main.py +@@ -857,12 +857,12 @@ def storm_control_delete_entry(port_name, storm_type): + def _wait_until_clear(tables, interval=0.5, timeout=30, verbose=False): + if timeout == 0: + return True +- start = time.time() ++ start = time.monotonic() + empty = False + app_db = SonicV2Connector(host='127.0.0.1') + app_db.connect(app_db.APPL_DB) + +- while not empty and time.time() - start < timeout: ++ while not empty and time.monotonic() - start < timeout: + non_empty_table_count = 0 + for table in tables: + keys = app_db.keys(app_db.APPL_DB, table) +@@ -1006,7 +1006,7 @@ def get_service_finish_timestamp(service): + + + def wait_service_restart_finish(service, last_timestamp, timeout=30): +- start_time = time.time() ++ start_time = time.monotonic() + elapsed_time = 0 + while elapsed_time < timeout: + current_timestamp = get_service_finish_timestamp(service) +@@ -1014,7 +1014,7 @@ def wait_service_restart_finish(service, last_timestamp, timeout=30): + return + + time.sleep(1) +- elapsed_time = time.time() - start_time ++ elapsed_time = time.monotonic() - start_time + + log.log_warning("Service: {} does not restart in {} seconds, stop waiting".format(service, timeout)) + +-- +2.34.1 + diff --git a/files/202605/0020-arm64-kdump-support-add-support-in-kdump-config.patch b/files/202605/0020-arm64-kdump-support-add-support-in-kdump-config.patch new file mode 100644 index 000000000..2f4eba214 --- /dev/null +++ b/files/202605/0020-arm64-kdump-support-add-support-in-kdump-config.patch @@ -0,0 +1,182 @@ +From 8ef4bfe5667bf23b5eea389982323f5091cf47e4 Mon Sep 17 00:00:00 2001 +From: Elad Nachman +Date: Sun, 18 May 2025 14:00:52 +0000 +Subject: [PATCH] arm64 kdump support - add support in kdump config + +Signed-off-by: Elad Nachman +--- + scripts/sonic-kdump-config | 102 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 101 insertions(+), 1 deletion(-) + +diff --git a/scripts/sonic-kdump-config b/scripts/sonic-kdump-config +index d7304758..2f22b4ae 100755 +--- a/scripts/sonic-kdump-config ++++ b/scripts/sonic-kdump-config +@@ -31,6 +31,7 @@ from sonic_installer.common import IMAGE_PREFIX + + aboot_cfg_template ="/host/image-%s/kernel-cmdline" + grub_cfg = "/host/grub/grub.cfg" ++uboot_cfg = "uboot-env.txt" + kdump_cfg = "/etc/default/kdump-tools" + kdump_mem_file = "/sys/kernel/kexec_crash_size" + machine_cfg = "/host/machine.conf" +@@ -104,6 +105,89 @@ def get_next_image(): + print_err("Unable to locate next SONiC image") + sys.exit(1) + ++## Detect if U-Boot is the bootloader by checking for the presence of `fw_printenv`. ++def is_uboot_present(): ++ try: ++ # Check if the `fw_printenv` command exists ++ result = subprocess.run(['which', 'fw_printenv'], capture_output=True, text=True) ++ if result.returncode == 0: ++ print("U-Boot detected: `fw_printenv` command is available.") ++ return True ++ else: ++ print("U-Boot not detected: `fw_printenv` command is not available.") ++ return False ++ except Exception as e: ++ print(f"An error occurred while checking for U-Boot: {e}") ++ return False ++ ++## Retrieve the current U-Boot environment variables. ++def get_uboot_env(): ++ try: ++ result = subprocess.run(['fw_printenv'], capture_output=True, text=True, check=True) ++ env_vars = {} ++ for line in result.stdout.splitlines(): ++ if '=' in line: ++ key, value = line.split('=', 1) ++ env_vars[key] = value ++ return env_vars ++ except subprocess.CalledProcessError as e: ++ print(f"Error retrieving U-Boot environment: {e}") ++ return None ++ ++## Dump the U-Boot environment variables into a file. ++def dump_uboot_env(output_file): ++ try: ++ # Run the `fw_printenv` command to get the U-Boot environment ++ result = subprocess.run(['fw_printenv'], capture_output=True, text=True, check=True) ++ ++ # Write the output to the specified file ++ with open(output_file, 'w', encoding='utf-8') as file: ++ file.write(result.stdout) ++ ++ print(f"U-Boot environment variables have been dumped to {output_file}") ++ except FileNotFoundError: ++ print("Error: `fw_printenv` command not found. Ensure U-Boot tools are installed.") ++ except subprocess.CalledProcessError as e: ++ print(f"Error while running `fw_printenv`: {e}") ++ except Exception as e: ++ print(f"An unexpected error occurred: {e}") ++ ++## Set a U-Boot environment variable. ++def set_uboot_env(key, value): ++ try: ++ subprocess.run(['fw_setenv', key, value], check=True) ++ print(f"Successfully set {key}={value}") ++ except subprocess.CalledProcessError as e: ++ print(f"Error setting U-Boot environment variable {key}: {e}") ++ ++## Modify the U-Boot parameters to add or update the crashkernel parameter. ++def modify_crashkernel_param_uboot_env(crashkernel_value): ++ env_vars = get_uboot_env() ++ if env_vars is None: ++ print("Failed to retrieve U-Boot environment variables.") ++ return ++ ++ # Get the current bootargs ++ bootargs = env_vars.get('linuxargs', '') ++ ++ # Check if crashkernel is already present ++ if 'crashkernel=' in bootargs: ++ # Update the existing crashkernel parameter ++ new_bootargs = [] ++ for param in bootargs.split(): ++ if (param.startswith('crashkernel=')): ++ if (crashkernel_value != "0"): ++ new_bootargs.append(f'crashkernel={crashkernel_value}') ++ else: ++ new_bootargs.append(param) ++ bootargs = ' '.join(new_bootargs) ++ else: ++ # Add the crashkernel parameter ++ bootargs += f' crashkernel={crashkernel_value}' ++ ++ # Set the updated bootargs ++ set_uboot_env('linuxargs', bootargs) ++ + ## Search for Current/Next SONiC image in grub configuration + # + # @param lines Lines read from grub.cfg/cmdline file +@@ -371,7 +455,7 @@ def get_kdump_ssh_path(): + # + # @return The integer value X from USE_KDUMP=X in /etc/default/kdump-tools + def read_use_kdump(): +- (rc, lines, err_str) = run_command("grep 'USE_KDUMP=.*' %s | cut -d = -f 2" % kdump_cfg, use_shell=False); ++ (rc, lines, err_str) = run_command("grep 'USE_KDUMP=.*' %s | cut -d = -f 2" % kdump_cfg, use_shell=True); + if rc == 0 and type(lines) == list and len(lines) >= 1: + try: + return int(lines[0]) +@@ -516,6 +600,9 @@ def kdump_enable(verbose, kdump_enabled, memory, num_dumps, image, cmdline_file, + if verbose: + print("Enabling kdump for image=[%s]" % image) + ++ if (cmdline_file == uboot_cfg): ++ dump_uboot_env(uboot_cfg) ++ + # Existing functionality: Reading the kernel command line file + try: + lines = [line.rstrip('\n') for line in open(cmdline_file)] +@@ -555,6 +642,9 @@ def kdump_enable(verbose, kdump_enabled, memory, num_dumps, image, cmdline_file, + + if changed: + rewrite_cfg(lines, cmdline_file) ++ if (cmdline_file == uboot_cfg): ++ modify_crashkernel_param_uboot_env(memory) ++ os.remove(uboot_cfg) + + # Enable kdump + write_use_kdump(1) +@@ -626,6 +716,8 @@ def cmd_kdump_enable(verbose, image): + elif open(machine_cfg, 'r').read().find('aboot_platform') >= 0: + aboot_cfg = aboot_cfg_template % image + return kdump_enable(verbose, kdump_enabled, memory, num_dumps, image, aboot_cfg, remote, ssh_string, ssh_path) ++ elif is_uboot_present(): ++ return kdump_enable(verbose, kdump_enabled, memory, num_dumps, image, uboot_cfg, remote, ssh_string, ssh_path) + else: + print("Feature not supported on this platform") + return False +@@ -657,6 +749,9 @@ def kdump_disable(verbose, image, booter_config_file_path): + if verbose: + print("Disabling kdump for image=[%s]\n" % image) + ++ if (booter_config_file_path == uboot_cfg): ++ dump_uboot_env(uboot_cfg) ++ + try: + with open(booter_config_file_path) as config_file_handler: + lines = [line.rstrip('\n') for line in config_file_handler] +@@ -680,6 +775,9 @@ def kdump_disable(verbose, image, booter_config_file_path): + + if changed: + rewrite_cfg(lines, booter_config_file_path) ++ if (booter_config_file_path == uboot_cfg): ++ modify_crashkernel_param_uboot_env("0") ++ os.remove(uboot_cfg) + + if not os.path.exists('/etc/sonic/config_db.json'): + print_err("Startup configuration not found, Kdump configuration is not saved") +@@ -708,6 +806,8 @@ def cmd_kdump_disable(verbose): + elif open(machine_cfg, 'r').read().find('aboot_platform') >= 0: + aboot_cfg = aboot_cfg_template % image + return kdump_disable(verbose, image, aboot_cfg) ++ elif is_uboot_present(): ++ return kdump_disable(verbose, image, uboot_cfg) + else: + print("Feature not supported on this platform") + return False +-- +2.25.1 + diff --git a/files/202605/0021-arm64-kdump-support-Install-kdump-utils-for-either-a.patch b/files/202605/0021-arm64-kdump-support-Install-kdump-utils-for-either-a.patch new file mode 100644 index 000000000..2d9997edb --- /dev/null +++ b/files/202605/0021-arm64-kdump-support-Install-kdump-utils-for-either-a.patch @@ -0,0 +1,27 @@ +From d5dba9fc5ed0add1d0eaed07d9d1d083ce35aa81 Mon Sep 17 00:00:00 2001 +From: Elad Nachman +Date: Sun, 18 May 2025 13:57:21 +0000 +Subject: [PATCH] arm64 kdump support - Install kdump utils for either amd64 or + arm64 + +Signed-off-by: Elad Nachman +--- + files/build_templates/sonic_debian_extension.j2 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 +index 579c165d9..a8c0217ef 100644 +--- a/files/build_templates/sonic_debian_extension.j2 ++++ b/files/build_templates/sonic_debian_extension.j2 +@@ -326,7 +326,7 @@ install_deb_package $debs_path/libnss-radius_*.deb + sudo sed -i -e '/^passwd/s/ radius//' $FILESYSTEM_ROOT/etc/nsswitch.conf + + # Install a custom version of kdump-tools (and its dependencies via 'apt-get -y install -f') +-if [ "$TARGET_BOOTLOADER" != uboot ]; then ++if [[ $CONFIGURED_ARCH == amd64 || $CONFIGURED_ARCH == arm64 ]]; then + install_deb_package $debs_path/kdump-tools_*.deb + cat $IMAGE_CONFIGS/kdump/kdump-tools | sudo tee -a $FILESYSTEM_ROOT/etc/default/kdump-tools > /dev/null + +-- +2.25.1 + diff --git a/files/202605/0031-Falcon-usb-disk-hung_task-WA.patch b/files/202605/0031-Falcon-usb-disk-hung_task-WA.patch new file mode 100644 index 000000000..5b1c1dbcc --- /dev/null +++ b/files/202605/0031-Falcon-usb-disk-hung_task-WA.patch @@ -0,0 +1,27 @@ +From 29cf8032aff6843919708334f2e95aa373d961b4 Mon Sep 17 00:00:00 2001 +From: Pavan Naregundi +Date: Thu, 21 Mar 2024 09:21:39 +0000 +Subject: Falcon usb disk hung_task WA + +Signed-off-by: Pavan Naregundi +--- + installer/install.sh | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/installer/install.sh b/installer/install.sh +index 557358fd5..13d2fc3a8 100755 +--- a/installer/install.sh ++++ b/installer/install.sh +@@ -44,6 +44,9 @@ read_conf_file() { + } + + set -e ++{ echo 0 > /proc/sys/kernel/hung_task_timeout_secs; } 2>/dev/null || true ++sync ++echo 3 > /proc/sys/vm/drop_caches + + if [ -d "/etc/sonic" ]; then + echo "Installing SONiC in SONiC" +-- +2.25.1 + diff --git a/files/202605/0041-buildimage-print-each-build-target-on-separated-line.patch b/files/202605/0041-buildimage-print-each-build-target-on-separated-line.patch new file mode 100644 index 000000000..4755c3883 --- /dev/null +++ b/files/202605/0041-buildimage-print-each-build-target-on-separated-line.patch @@ -0,0 +1,50 @@ +From fc83b05c736974cc7937af33993169b29a1824da Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Sun, 27 Apr 2025 13:22:16 +0000 +Subject: [PATCH 1/1] buildimage: print each build-target on separated line + +=== SUMMARY: +For SONIC_BUILD_JOBS=1 print each build-target on a separated line, +so finally, there is a list of built targets like +[ 01 ] [ target/debs/bookworm/libdashapi_1.0.0_arm64.deb-install ] +[ 01 ] [ target/debs/bookworm/swss_1.0.0_arm64.deb ] +[ 01 ] [ target/python-wheels/bookworm/sonic_bgpcfgd-1.0-py3-none-any.whl ] +Keep original print if SONIC_BUILD_JOBS is undefined or >1 + +=== Why this is needed: +- Good for understanding what is built and in which order +- Easy to see which package-versions are used for current build + and to compare packages with previous builds + +== How it is done: +Just use Double Carriage-Return in printf "\n\n" instead of single CR. + +== TEST: +Build without SONIC_BUILD_JOBS declaration, with SONIC_BUILD_JOBS=4 and +with SONIC_BUILD_JOBS=1. + +Signed-off-by: Yan Markman +--- + update_screen.sh | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/update_screen.sh b/update_screen.sh +index af272843d..37da3a2df 100755 +--- a/update_screen.sh ++++ b/update_screen.sh +@@ -21,7 +21,11 @@ function print_targets { + + count=1 + for i in $(cat ${target_list_file}); do +- printf "[ %02d ] [ %s ]\n" "${count}" "$i" ++ if [[ -v SONIC_BUILD_JOBS && "${SONIC_BUILD_JOBS}" -eq 1 ]]; then ++ printf "[ %02d ] [ %s ]\n\n" "${count}" "$i" ++ else ++ printf "[ %02d ] [ %s ]\n" "${count}" "$i" ++ fi + ((count++)) + done + } +-- +2.25.1 + diff --git a/files/202605/0041-grub2-grub_cmd_sleep-increase-tolerance-to-14sec.patch b/files/202605/0041-grub2-grub_cmd_sleep-increase-tolerance-to-14sec.patch new file mode 100644 index 000000000..f0ebd6711 --- /dev/null +++ b/files/202605/0041-grub2-grub_cmd_sleep-increase-tolerance-to-14sec.patch @@ -0,0 +1,69 @@ +From 20ebfb6df993ec44b97582d885dd324030fc2e70 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Thu, 12 Feb 2026 14:32:34 +0200 +Subject: [PATCH 1/1] grub2: grub_cmd_sleep increase tolerance to 14sec + +Why I did it: +Under build with SONIC_BUILD_JOBS>1 the wall-clock sleep checked by the +'grub_cmd_sleep' test may be blocked/delayed for some seconds +(e.g., sleep(10) measuring 13 seconds). +This failure is not due to GRUB logic. + +How I did it: +Do not SLKIP this flake test, do not use SONIC_BUILD_JOBS=1, +but just Increase the fail-decision tolerance from 11sec to 14sec. + +Signed-off-by: Yan Markman +--- + ...d_sleep-increase-tolerance-to-14-sec.patch | 29 +++++++++++++++++++ + src/grub2/patch/series | 1 + + 2 files changed, 30 insertions(+) + create mode 100644 src/grub2/patch/grub_cmd_sleep-increase-tolerance-to-14-sec.patch + +diff --git a/src/grub2/patch/grub_cmd_sleep-increase-tolerance-to-14-sec.patch b/src/grub2/patch/grub_cmd_sleep-increase-tolerance-to-14-sec.patch +new file mode 100644 +index 000000000..eef61c3d3 +--- /dev/null ++++ b/src/grub2/patch/grub_cmd_sleep-increase-tolerance-to-14-sec.patch +@@ -0,0 +1,29 @@ ++From 6c83ac29ab6f095214914bee379b78d0c86387b3 Mon Sep 17 00:00:00 2001 ++From: Yan Markman ++Date: Tue, 24 Feb 2026 21:44:01 +0200 ++Subject: [PATCH 1/1] grub_cmd_sleep: increase tolerance to 14 sec ++ ++The sleep(10) wall-clock timing is flake under several parallel build-jobs. ++Do not SKIP it but increase fail threshold tolerance from 11 sec to 14 sec. ++ ++Signed-off-by: Yan Markman ++--- ++ tests/grub_cmd_sleep.in | 2 +- ++ 1 file changed, 1 insertion(+), 1 deletion(-) ++ ++diff --git a/tests/grub_cmd_sleep.in b/tests/grub_cmd_sleep.in ++index 8797f6632..11d1b2775 100644 ++--- a/tests/grub_cmd_sleep.in +++++ b/tests/grub_cmd_sleep.in ++@@ -19,7 +19,7 @@ if [ "${grub_modinfo_target_cpu}" = arm ] && [ $((dt2 - dt1)) -ge 15 ] && [ $((d ++ exit 0; ++ fi ++ ++-if [ $((dt2 - dt1)) -gt 11 ] || [ $((dt2 - dt1)) -lt 9 ]; then +++if [ $((dt2 - dt1)) -gt 14 ] || [ $((dt2 - dt1)) -lt 9 ]; then ++ echo "Interval not in range $dt2-$dt1 != 10" ++ exit 1 ++ fi ++-- ++2.34.1 ++ +diff --git a/src/grub2/patch/series b/src/grub2/patch/series +index 5aa942ab3..003fdee33 100644 +--- a/src/grub2/patch/series ++++ b/src/grub2/patch/series +@@ -1,3 +1,4 @@ ++grub_cmd_sleep-increase-tolerance-to-14-sec.patch + # This series applies on GIT commit f954d68d5e8dc7eb0081ad7bc1ced9ff5ca687a7 + adjust-build-rules-for-debian.patch + large-uid-skip-cpio-ustar.patch +-- +2.34.1 + diff --git a/files/202605/0043-marvell-prestera-rpc-pin-ptf_nn_agent.py-to-use-nnpy.patch b/files/202605/0043-marvell-prestera-rpc-pin-ptf_nn_agent.py-to-use-nnpy.patch new file mode 100644 index 000000000..4f3313102 --- /dev/null +++ b/files/202605/0043-marvell-prestera-rpc-pin-ptf_nn_agent.py-to-use-nnpy.patch @@ -0,0 +1,38 @@ +From bfd6fea5e030ed94109ca5861104e8d619077fd7 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Mon, 25 May 2026 15:20:42 +0300 +Subject: [PATCH 1/1] marvell-prestera-rpc: pin ptf_nn_agent.py to use nnpy in + copp ptf + +Pin(revert) ptf_nn_agent.py download URL to the last upstream PTF commit +(23ebe7237f) that still uses nnpy, matching the fix already applied +to docker-ptf in PR #26912. + +The upstream p4lang/ptf master branch switched from nnpy to pynng +(p4lang/ptf@ebc00f9), but docker-syncd-mrvl-teralynx-rpc only +installs nnpy, causing ptf_nn_agent.py to fail with: + Cannot find pynng package + +This blocks COPP module tests from running. + +Signed-off-by: Yan Markman +--- + .../docker-syncd-mrvl-prestera-rpc/Dockerfile.j2 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/platform/marvell-prestera/docker-syncd-mrvl-prestera-rpc/Dockerfile.j2 b/platform/marvell-prestera/docker-syncd-mrvl-prestera-rpc/Dockerfile.j2 +index 3941d8b15..6f82f3ee5 100644 +--- a/platform/marvell-prestera/docker-syncd-mrvl-prestera-rpc/Dockerfile.j2 ++++ b/platform/marvell-prestera/docker-syncd-mrvl-prestera-rpc/Dockerfile.j2 +@@ -37,7 +37,7 @@ RUN pip3 install cffi \ + && pip3 install nnpy \ + && mkdir -p /opt \ + && cd /opt \ +- && wget https://raw.githubusercontent.com/p4lang/ptf/master/ptf_nn/ptf_nn_agent.py ++ && wget https://raw.githubusercontent.com/p4lang/ptf/23ebe7237f3c284032bda02fbd1f4a98f1bc12f4/ptf_nn/ptf_nn_agent.py + + COPY ["ptf_nn_agent.conf", "/etc/supervisor/conf.d/"] + +-- +2.34.1 + diff --git a/files/202605/0057-sonic-platform-wistron-rules-for-trixie.patch b/files/202605/0057-sonic-platform-wistron-rules-for-trixie.patch new file mode 100644 index 000000000..ce51b5540 --- /dev/null +++ b/files/202605/0057-sonic-platform-wistron-rules-for-trixie.patch @@ -0,0 +1,109 @@ +From 9891e6664e457c7aa6e83148e2327e993e847ccb Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Mon, 29 Sep 2025 14:47:08 +0300 +Subject: [PATCH 1/1] sonic-platform-wistron: rules for trixie + +Signed-off-by: Yan Markman +--- + .../sonic-platform-wistron/debian/rules | 66 +++++++++---------- + 1 file changed, 30 insertions(+), 36 deletions(-) + +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/rules b/platform/marvell-prestera/sonic-platform-wistron/debian/rules +index 328196af1..fbcb56b25 100755 +--- a/platform/marvell-prestera/sonic-platform-wistron/debian/rules ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/rules +@@ -19,38 +19,51 @@ SERVICE_DIR := service + PRESTERA_MODULE_SRC := mrvl-prestera/drivers/generic/cpssEnabler/linuxNoKernelModule/drivers + + %: +- dh $@ --with systemd,python3 --buildsystem=pybuild ++ dh $@ --with python3 --buildsystem=pybuild + +-clean: +- dh_testdir +- dh_testroot ++override_dh_auto_clean: ++ (for mod in $(MODULE_DIRS); do \ ++ $(MAKE) clean -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ ++ if [ -f $(MOD_SRC_DIR)/$${mod}/setup.py ]; then \ ++ PYBUILD_NAME=$${mod} pybuild --clean -d $${mod}; \ ++ fi; \ ++ cd $(MOD_SRC_DIR)/$${mod}; \ ++ rm -rf $(MRVL_MODULE_DIR)/; \ ++ rm -rf *.egg-info/; \ ++ rm -f *.whl; \ ++ cd $(MOD_SRC_DIR)/; \ ++ done) + dh_clean + +-build: ++override_dh_auto_configure: ++ (for mod in $(MODULE_DIRS); do \ ++ if [ -f $(MOD_SRC_DIR)/$${mod}/setup.py ]; then \ ++ PYBUILD_NAME=$${mod} pybuild --configure -d $${mod}; \ ++ fi; \ ++ done) ++ ++override_dh_auto_build: + (for mod in $(MODULE_DIRS); do \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + cd $(MOD_SRC_DIR)/../$(PRESTERA_MODULE_SRC)/; \ + make clean; \ + make modules -C $(KERNEL_SRC)/build M=`pwd` CONFIG_KM_MVPCI=y CONFIG_KM_MVINT=y || exit 1; \ +- cp *.ko $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/; \ +- cd $(MOD_SRC_DIR)/$${mod}; \ ++ cp *.ko $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/; \ ++ cd $(MOD_SRC_DIR)/$${mod}; \ ++ python3 setup.py build; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ +- echo "Finished making whl package for $$mod"; \ + cd $(MOD_SRC_DIR); \ + done) + +-binary: binary-arch binary-indep +- # Nothing to do + +-binary-arch: +- # Nothing to do ++override_dh_auto_test: ++ # No tests to run + +-binary-indep: +- dh_testdir +- dh_installdirs ++override_dh_usrlocal: ++ # debian/sonic-platform-<>-<>/usr/local/bin/* are already done + +- # Custom package commands +- (for mod in $(MODULE_DIRS); do \ ++override_dh_auto_install: ++ (set -e; for mod in $(MODULE_DIRS); do \ + if [ $$mod = "es1227_54ts" ]; then \ + pkg="es1227-54ts"; \ + elif [ $$mod = "es2227_54ts" ]; then \ +@@ -66,22 +79,3 @@ binary-indep: + cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/sonic-platform-$${pkg}/lib/systemd/system/; \ + #python3 $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/sonic-platform-$${pkg} --install-layout=deb; \ + done) +- +- # Resuming debhelper scripts +- dh_testroot +- dh_install +- dh_installchangelogs +- dh_installdocs +- dh_systemd_enable +- dh_installinit +- dh_systemd_start +- dh_link +- dh_fixperms +- dh_compress +- dh_strip +- dh_installdeb +- dh_gencontrol +- dh_md5sums +- dh_builddeb +- +-.PHONY: build binary binary-arch binary-indep clean +-- +2.34.1 + diff --git a/files/202605/0060-sonic-ext.target-wrapper-for-sonic.target.patch b/files/202605/0060-sonic-ext.target-wrapper-for-sonic.target.patch new file mode 100644 index 000000000..1a2b2bd25 --- /dev/null +++ b/files/202605/0060-sonic-ext.target-wrapper-for-sonic.target.patch @@ -0,0 +1,143 @@ +From 25c8855121ba5c65f9005166dea37c9c044f8c57 Mon Sep 17 00:00:00 2001 +From: Yan Markman <32263981+yanmarkman@users.noreply.github.com> +Date: Thu, 15 Jan 2026 20:13:02 +0200 +Subject: [PATCH 1/1] sonic-ext.target wrapper for sonic.target (#60) + +Create and enable sonic-ext.target wrapper acrivated on boot +instead of regular sonic.target and applying the sonic-pre.service +with "hook" sonic-ext.sh before activating for sonic.target. + +This wrapper does not impacts the SONiC commands having +sonic.target start/stop/restart inside, but the bootup only. + +On devices slow CPU (armhf) this permits to "split/delay" between +Debian bootup and SONiC. + +Signed-off-by: Yan Markman +--- + debian/mrvlprestera.install.template | 1 + + debian/rules | 2 ++ + .../multi-user.target.wants/sonic-ext.target | 1 + + .../usr/lib/systemd/system/sonic-ext.target | 5 +++ + .../usr/lib/systemd/system/sonic-pre.service | 18 ++++++++++ + platform/common/usr/local/bin/sonic-pre.sh | 36 +++++++++++++++++++ + platform/common/usr/local/bin/sonic_firstboot | 0 + 7 files changed, 63 insertions(+) + create mode 120000 platform/common/etc/systemd/system/multi-user.target.wants/sonic-ext.target + create mode 100644 platform/common/usr/lib/systemd/system/sonic-ext.target + create mode 100644 platform/common/usr/lib/systemd/system/sonic-pre.service + create mode 100755 platform/common/usr/local/bin/sonic-pre.sh + create mode 100644 platform/common/usr/local/bin/sonic_firstboot + +diff --git a/debian/mrvlprestera.install.template b/debian/mrvlprestera.install.template +index 5d3ea0d..8af809b 100644 +--- a/debian/mrvlprestera.install.template ++++ b/debian/mrvlprestera.install.template +@@ -1,2 +1,3 @@ ++platform/common/* / + platform/ARCH/common/boot/*.dtb /boot + platform/ARCH/common/usr/local/bin/* /usr/local/bin +diff --git a/debian/rules b/debian/rules +index a50fb85..ab9c4b9 100755 +--- a/debian/rules ++++ b/debian/rules +@@ -24,6 +24,8 @@ override_dh_auto_build: + @if [ "$(CONFIGURED_ARCH)" = "amd64" ]; then \ + echo "platform/$(CONFIGURED_ARCH)/common/usr/local/bin/* /usr/local/bin" > \ + ${MOD_SRC_DIR}/debian/mrvlprestera.install; \ ++ echo "platform/common/* /" >> \ ++ ${MOD_SRC_DIR}/debian/mrvlprestera.install; \ + else \ + sed "s/ARCH/${CONFIGURED_ARCH}/g" \ + ${MOD_SRC_DIR}/debian/mrvlprestera.install.template \ +diff --git a/platform/common/etc/systemd/system/multi-user.target.wants/sonic-ext.target b/platform/common/etc/systemd/system/multi-user.target.wants/sonic-ext.target +new file mode 120000 +index 0000000..5c398e5 +--- /dev/null ++++ b/platform/common/etc/systemd/system/multi-user.target.wants/sonic-ext.target +@@ -0,0 +1 @@ ++/lib/systemd/system/sonic-ext.target +\ No newline at end of file +diff --git a/platform/common/usr/lib/systemd/system/sonic-ext.target b/platform/common/usr/lib/systemd/system/sonic-ext.target +new file mode 100644 +index 0000000..f81ad7e +--- /dev/null ++++ b/platform/common/usr/lib/systemd/system/sonic-ext.target +@@ -0,0 +1,5 @@ ++[Unit] ++Description=SONiC extended target starting sonic.target after pre.service ++Requires=sonic-pre.service ++After=sonic-pre.service ++Wants=sonic.target +diff --git a/platform/common/usr/lib/systemd/system/sonic-pre.service b/platform/common/usr/lib/systemd/system/sonic-pre.service +new file mode 100644 +index 0000000..efb0ff7 +--- /dev/null ++++ b/platform/common/usr/lib/systemd/system/sonic-pre.service +@@ -0,0 +1,18 @@ ++[Unit] ++Description=SONiC pre-start service ++Before=sonic.target ++ConditionPathExists=/usr/local/bin/sonic-pre.sh ++DefaultDependencies=no ++After=local-fs.target ++Requires=network-online.target ++Wants=network-online.target ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/sonic-pre.sh ++RemainAfterExit=yes ++TimeoutStartSec=0 ++ ++[Install] ++WantedBy=sonic-ext.target ++ +diff --git a/platform/common/usr/local/bin/sonic-pre.sh b/platform/common/usr/local/bin/sonic-pre.sh +new file mode 100755 +index 0000000..ca0cce6 +--- /dev/null ++++ b/platform/common/usr/local/bin/sonic-pre.sh +@@ -0,0 +1,36 @@ ++#!/bin/bash ++ ++MACHINE=$(uname -m) ++ ++if [ -f /usr/local/bin/sonic_firstboot ]; then ++ rm -f /usr/local/bin/sonic_firstboot ++ case $MACHINE in ++ armv7l) ++ DELAY=30 ++ ;; ++ aarch64|x86_64) ++ DELAY=2 ++ ;; ++ *) ++ DELAY=0 ++ ;; ++ esac ++else ++ case $MACHINE in ++ armv7l) ++ DELAY=20 ++ ;; ++ aarch64|x86_64) ++ DELAY=0 ++ ;; ++ *) ++ DELAY=0 ++ ;; ++ esac ++fi ++ ++echo "sonic-pre start with delay $DELAY sec" > /dev/kmsg ++if [ "$DELAY" -eq 0 ]; then exit 0; fi ++sleep $DELAY ++echo "sonic-pre end. Start sonic" > /dev/kmsg ++ +diff --git a/platform/common/usr/local/bin/sonic_firstboot b/platform/common/usr/local/bin/sonic_firstboot +new file mode 100644 +index 0000000..e69de29 +-- +2.34.1 + diff --git a/files/202605/0061-sonic.target-no-install-oveload-for-sonic-ext.target.patch b/files/202605/0061-sonic.target-no-install-oveload-for-sonic-ext.target.patch new file mode 100644 index 000000000..601b7b240 --- /dev/null +++ b/files/202605/0061-sonic.target-no-install-oveload-for-sonic-ext.target.patch @@ -0,0 +1,44 @@ +From 52cdc81db3585515f9c16be2c295e9c2d5f0b3ea Mon Sep 17 00:00:00 2001 +From: Yan Markman <32263981+yanmarkman@users.noreply.github.com> +Date: Mon, 19 Jan 2026 20:16:24 +0200 +Subject: [PATCH 1/1] sonic.target no-install oveload for sonic-ext.target + (#61) + +Overload an original source-file files/build_templates/sonic.target +with Disabled [Install] section. +Needed for correct/designed sonic-ext.target work. + +Signed-off-by: Yan Markman +--- + debian/rules | 2 ++ + platform/files-overload/sonic.target | 5 +++++ + 2 files changed, 7 insertions(+) + create mode 100644 platform/files-overload/sonic.target + +diff --git a/debian/rules b/debian/rules +index ab9c4b9..5ade2fe 100755 +--- a/debian/rules ++++ b/debian/rules +@@ -31,6 +31,8 @@ override_dh_auto_build: + ${MOD_SRC_DIR}/debian/mrvlprestera.install.template \ + > ${MOD_SRC_DIR}/debian/mrvlprestera.install; \ + fi ++ cp -f ${MOD_SRC_DIR}/platform/files-overload/sonic.target \ ++ ${MOD_SRC_DIR}/../../../files/build_templates/sonic.target + + override_dh_auto_test: + # No tests to run +diff --git a/platform/files-overload/sonic.target b/platform/files-overload/sonic.target +new file mode 100644 +index 0000000..b088699 +--- /dev/null ++++ b/platform/files-overload/sonic.target +@@ -0,0 +1,5 @@ ++[Unit] ++Description=SONiC services target. ++ ++#[Install] ++#WantedBy=multi-user.target +-- +2.34.1 + diff --git a/files/202605/0064-build_templates-marvell-blacklist-with-kempld.patch b/files/202605/0064-build_templates-marvell-blacklist-with-kempld.patch new file mode 100644 index 000000000..814b41a72 --- /dev/null +++ b/files/202605/0064-build_templates-marvell-blacklist-with-kempld.patch @@ -0,0 +1,43 @@ +From f3232eefe642601ba2bf8f8baea3c23860032c44 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Tue, 31 Mar 2026 12:11:15 +0300 +Subject: [PATCH 1/1] build_templates: marvell blacklist with kempld + +Expand into build_templates basic rootfs with blacklist file +/etc/modprobe.d/50-kempld.conf specifically for +Marvell AMD64 Kontron/kemld modules wich lead to +- occasional i2c SMBUS and KEMPLD bus enumeration swap with further PMON failure +- I2c-mux collision and bus-stuck on a Marvell device + +Signed-off-by: Yan Markman +--- + files/build_templates/sonic_debian_extension.j2 | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 +index 757260cd2..b097e2468 100644 +--- a/files/build_templates/sonic_debian_extension.j2 ++++ b/files/build_templates/sonic_debian_extension.j2 +@@ -867,6 +867,19 @@ fi + ## copy blacklist file + sudo cp $IMAGE_CONFIGS/platform/linux_kernel_bde.conf $FILESYSTEM_ROOT/etc/modprobe.d/ + ++# Marvell AMD64 blacklist with Kontron/kemld modules wich lead to ++# - occasional i2c SMBUS and KEMPLD bus enumeration swap with further PMON failure ++# - I2c-mux collision and bus-stuck on a Marvell device ++if [[ "$CONFIGURED_PLATFORM" == "marvell-prestera" && "$CONFIGURED_ARCH" == "amd64" ]]; then ++FILE="$FILESYSTEM_ROOT/etc/modprobe.d/50-kempld.conf" ++sudo mkdir -p "$(dirname "$FILE")" ++grep -q kempld_core "$FILE" 2>/dev/null || sudo tee -a "$FILE" > /dev/null <<'EOF' ++blacklist kempld_core ++blacklist gpio_kempld ++blacklist i2c_kempld ++EOF ++fi ++ + # Enable psample drivers to support sFlow on vs + {% if sonic_asic_platform == "vs" %} + sudo tee -a $FILESYSTEM_ROOT/etc/modules-load.d/modules.conf > /dev/null < +Date: Sat, 22 Nov 2025 15:05:44 +0200 +Subject: [PATCH 1/1] marvell-prestera: Uboot print_menu improve + +Signed-off-by: Yan Markman +--- + platform/marvell-prestera/platform_arm64.conf | 12 +++++++----- + platform/marvell-prestera/platform_armhf.conf | 14 ++++++++------ + 2 files changed, 15 insertions(+), 11 deletions(-) + +diff --git a/platform/marvell-prestera/platform_arm64.conf b/platform/marvell-prestera/platform_arm64.conf +index 5c4be072c..3f9bd8582 100644 +--- a/platform/marvell-prestera/platform_arm64.conf ++++ b/platform/marvell-prestera/platform_arm64.conf +@@ -244,11 +244,13 @@ prepare_boot_menu() { + fw_setenv ${FW_ARG} fdt_name $fdt_name > /dev/null + fw_setenv ${FW_ARG} fit_name $fit_name > /dev/null + fw_setenv ${FW_ARG} sonic_version_1 $demo_volume_revision_label > /dev/null +- BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";echo;' +- BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";echo;' +- BOOT3='echo " > Boot3: ONIE - run onie_boot";echo;' +- BORDER='echo "---------------------------------------------------";echo;' +- fw_setenv ${FW_ARG} print_menu "$BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER" > /dev/null ++ BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";' ++ BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";' ++ BOOT3='echo " > Boot3: ONIE - run onie_boot";' ++ BORDER='echo "---------------------------------------------------";' ++ CURR="echo " Current $do_boot_once;" ++ BORD='echo "---------";echo;' ++ fw_setenv ${FW_ARG} print_menu "$BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER $CURR $BORD" > /dev/null + + fw_setenv ${FW_ARG} linuxargs "net.ifnames=0 loopfstype=squashfs loop=$image_dir/$FILESYSTEM_SQUASHFS varlog_size=$VAR_LOG ${ONIE_PLATFORM_EXTRA_CMDLINE_LINUX}" > /dev/null + uuid=$(blkid | grep "$demo_volume_label" | sed -ne 's/.* UUID=\"\([^"]*\)\".*/\1/p') +diff --git a/platform/marvell-prestera/platform_armhf.conf b/platform/marvell-prestera/platform_armhf.conf +index 189ae0a45..3b432551e 100644 +--- a/platform/marvell-prestera/platform_armhf.conf ++++ b/platform/marvell-prestera/platform_armhf.conf +@@ -183,15 +183,17 @@ prepare_boot_menu() { + fw_setenv ${FW_ARG} initrd_name_old $initrd_name_old > /dev/null + fw_setenv ${FW_ARG} fdt_name_old $fdt_name_old > /dev/null + fw_setenv ${FW_ARG} sonic_version_2 $sonic_version_2 > /dev/null +- BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";echo;' +- BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";echo;' ++ BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";' ++ BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";' + if [ "$PLATFORM" = "armhf-nokia_ixs7215_52x-r0" ]; then +- BOOT3='echo " > Boot3: ONIE - run onie_bootcmd";echo;' ++ BOOT3='echo " > Boot3: ONIE - run onie_bootcmd";' + else +- BOOT3='echo " > Boot3: ONIE - run onie_nand_boot";echo;' ++ BOOT3='echo " > Boot3: ONIE - run onie_nand_boot";' + fi +- BORDER='echo "---------------------------------------------------";echo;' +- fw_setenv ${FW_ARG} print_menu "$BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER" > /dev/null ++ BORDER='echo "---------------------------------------------------";' ++ CURR="echo " Current $do_boot_once;" ++ BORD='echo "---------";echo;' ++ fw_setenv ${FW_ARG} print_menu "$BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER $CURR $BORD" > /dev/null + + fw_setenv ${FW_ARG} linuxargs "net.ifnames=0 loopfstype=squashfs loop=$image_dir/$FILESYSTEM_SQUASHFS varlog_size=$VAR_LOG_SIZE loglevel=4 ${ONIE_PLATFORM_EXTRA_CMDLINE_LINUX}" > /dev/null + fw_setenv ${FW_ARG} linuxargs_old "net.ifnames=0 loopfstype=squashfs loop=$image_dir_old/$FILESYSTEM_SQUASHFS varlog_size=$VAR_LOG_SIZE loglevel=4 ${ONIE_PLATFORM_EXTRA_CMDLINE_LINUX}" > /dev/null +-- +2.34.1 + diff --git a/files/202605/0104-platform-X-arm64-mrvl-pcie-ep-check-reboot-on-EP-miss.patch b/files/202605/0104-platform-X-arm64-mrvl-pcie-ep-check-reboot-on-EP-miss.patch new file mode 100644 index 000000000..bc00a9e38 --- /dev/null +++ b/files/202605/0104-platform-X-arm64-mrvl-pcie-ep-check-reboot-on-EP-miss.patch @@ -0,0 +1,112 @@ +From 3cd1f51080db8510ba059caa335aa0904a675702 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Thu, 27 Nov 2025 13:38:56 +0200 +Subject: [PATCH 1/1] arm64: mrvl-pcie-ep-check.service, reboot on EP miss + +HW Problem: After reboot a Board with external-CPU connected +over cable (but not directly to PCIE) not always see CPSS/Prestera +EndPoint device on PCIE-bus. + +As workaround, check Marvell EP presence on PCIE. If missed - make the reboot. + +Signed-off-by: Yan Markman +--- + .../mrvl-pcie-ep-check.service | 1 + + .../systemd/system/mrvl-pcie-ep-check.service | 15 ++++++ + .../usr/local/bin/mrvl-pcie-ep-check.sh | 53 +++++++++++++++++++ + 3 files changed, 69 insertions(+) + create mode 120000 platform/arm64/common/etc/systemd/system/multi-user.target.wants/mrvl-pcie-ep-check.service + create mode 100644 platform/arm64/common/usr/lib/systemd/system/mrvl-pcie-ep-check.service + create mode 100755 platform/arm64/common/usr/local/bin/mrvl-pcie-ep-check.sh + +diff --git a/platform/arm64/common/etc/systemd/system/multi-user.target.wants/mrvl-pcie-ep-check.service b/platform/arm64/common/etc/systemd/system/multi-user.target.wants/mrvl-pcie-ep-check.service +new file mode 120000 +index 0000000..43c8620 +--- /dev/null ++++ b/platform/arm64/common/etc/systemd/system/multi-user.target.wants/mrvl-pcie-ep-check.service +@@ -0,0 +1 @@ ++/usr/lib/systemd/system/mrvl-pcie-ep-check.service +\ No newline at end of file +diff --git a/platform/arm64/common/usr/lib/systemd/system/mrvl-pcie-ep-check.service b/platform/arm64/common/usr/lib/systemd/system/mrvl-pcie-ep-check.service +new file mode 100644 +index 0000000..0b6e486 +--- /dev/null ++++ b/platform/arm64/common/usr/lib/systemd/system/mrvl-pcie-ep-check.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Marvell PCIe-EP check ++DefaultDependencies=no ++After=local-fs.target ++Wants=local-fs.target ++Before=multi-user.target ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/mrvl-pcie-ep-check.sh ++ ++[Install] ++WantedBy=sysinit.target ++#WantedBy=multi-user.target ++ +diff --git a/platform/arm64/common/usr/local/bin/mrvl-pcie-ep-check.sh b/platform/arm64/common/usr/local/bin/mrvl-pcie-ep-check.sh +new file mode 100755 +index 0000000..4df67e5 +--- /dev/null ++++ b/platform/arm64/common/usr/local/bin/mrvl-pcie-ep-check.sh +@@ -0,0 +1,53 @@ ++#!/bin/sh ++# mrvl-check-pcie-ep.sh ++# Check Marvell-End-Point presence, reboot if not found ++# ++# Run on Init context, service-safe, logs via /dev/kmsg ++ ++# Conditional: only for CN9131-DB-Comexpress ++if ! grep -iq "CN9131-DB-Comexpress" /proc/device-tree/model 2>/dev/null; then ++ # Not the target model -> exit clean ++ exit 0 ++fi ++ ++# EVENT_FILE is persistent marker file preventing loop on persistent miss ++EVENT_FILE="/var/lib/mrvl-pcie-ep-reboot-req" ++STAT_PASS="/var/lib/mrvl-pcie-ep-reboot.pass" ++STAT_FAIL="/var/lib/mrvl-pcie-ep-reboot.fail" ++ ++# Find PCIe endpoint (Marvell vendor, not root-port) ++EP="" ++for d in /sys/bus/pci/devices/*; do ++ vend=$(cat "$d/vendor" 2>/dev/null) ++ cls=$(cat "$d/class" 2>/dev/null) ++ ++ case "$vend:$cls" in ++ 0x11ab:0x0604??) ;; # skip bridges/root-ports ++ 0x11ab:0x??????) EP="$d"; break ;; # endpoint 020000 found ++ esac ++done ++ ++# Handle PCIe endpoint presence ++if [ ! -z "$EP" ]; then ++ # PCIe OK -> remove any previous marker ++ [ -f "$EVENT_FILE" ] && rm -f "$EVENT_FILE" ++ CNTR_PASS=$(cat "$STAT_PASS" 2>/dev/null) ++ CNTR_PASS=$((CNTR_PASS + 1)) ++ echo "$CNTR_PASS" > "$STAT_PASS" ++ exit 0 ++fi ++ ++CNTR_FLT=$(cat "$STAT_FAIL" 2>/dev/null) ++CNTR_FLT=$((CNTR_FLT + 1)) ++echo "$CNTR_FLT" > "$STAT_FAIL" ++ ++echo "ERROR: Marvell PCIe endpoint missing" >/dev/kmsg ++echo "=================================================" >/dev/console ++echo "ERROR: Marvell PCIe endpoint missing" >/dev/console ++echo "=================================================" >/dev/console ++if [ ! -f "$EVENT_FILE" ]; then ++ touch "$EVENT_FILE" ++ sync ++ reboot ++fi ++exit 0 +-- +2.34.1 + diff --git a/files/202605/0777-marvell-prestera-sai-1.17.1-13.patch b/files/202605/0777-marvell-prestera-sai-1.17.1-13.patch new file mode 100644 index 000000000..d91d91945 --- /dev/null +++ b/files/202605/0777-marvell-prestera-sai-1.17.1-13.patch @@ -0,0 +1,29 @@ +From e3cb639c155fd8a43948d5113c6431313fa4f3d1 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Wed, 17 Dec 2025 17:41:07 +0200 +Subject: [PATCH] marvell-prestera: sai-1.17.1-13 + +Signed-off-by: Yan Markman + +diff --git a/platform/marvell-prestera/sai.mk b/platform/marvell-prestera/sai.mk +index 49643c401..75a121126 100644 +--- a/platform/marvell-prestera/sai.mk ++++ b/platform/marvell-prestera/sai.mk +@@ -2,11 +2,11 @@ + + BRANCH = master + ifeq ($(CONFIGURED_ARCH),arm64) +-MRVL_SAI_VERSION = 1.17.1-13 ++MRVL_SAI_VERSION = 1.17.1-nn + else ifeq ($(CONFIGURED_ARCH),armhf) +-MRVL_SAI_VERSION = 1.17.1-13 ++MRVL_SAI_VERSION = 1.17.1-nn + else +-MRVL_SAI_VERSION = 1.17.1-13 ++MRVL_SAI_VERSION = 1.17.1-nn + endif + + MRVL_SAI_URL_PREFIX = https://github.com/Marvell-switching/sonic-marvell-binaries/raw/master/$(CONFIGURED_ARCH)/sai-plugin/$(BRANCH)/ +-- +2.34.1 + diff --git a/files/202605/20250-1-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch b/files/202605/20250-1-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch new file mode 100644 index 000000000..228095a39 --- /dev/null +++ b/files/202605/20250-1-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch @@ -0,0 +1,49172 @@ +From ee513176fbbe1a554a38519e903e776e8c070911 Mon Sep 17 00:00:00 2001 +From: Pavan Naregundi +Date: Thu, 23 Jan 2025 12:42:12 +0000 +Subject: [PATCH 1/1] Add Wistron platform ES1227-54TS and ES2227-54TS + +Add Wistron platform ES1227-54TS and ES2227-54TS +aligned to the Wistron SKU/XML version="2024-10-24-1.10". + +Done as patch 20250.patch propagation from branch '202411' to 'master'. +There are 2 differences between '202411' and 'master': +1). Shange platform name from "marvell" to "marvell-prestera". +2). NOT include Wistron's changes in files + platform/marvell-prestera/one-image.mk + platform/marvell-prestera/platform_arm64.conf + because their changes interfere with AC5P-RD adding, + and should be done by separated patch. + +NOTE: The patch adds binary/executable files which cannot be done by + "patch -p1 <.." but by "git am ..." only. + +Signed-off-by: Pavan Naregundi +Signed-off-by: Yan Markman +--- + .../arm64-wistron_es1227_54ts-r0/default_sku | 1 + + .../installer.conf | 1 + + .../arm64-wistron_es1227_54ts-r0/pcie.yaml | 10 + + .../platform.json | 560 +++++ + .../platform_afi.json | 560 +++++ + .../platform_afo.json | 560 +++++ + .../platform_asic | 1 + + .../platform_components.json | 11 + + .../pmon_daemon_control.json | 4 + + .../arm64-wistron_es1227_54ts-r0/sensors.conf | 59 + + .../sensors_afi.conf | 59 + + .../sensors_afo.conf | 59 + + .../system_health_monitoring_config.json | 12 + + .../thermal_policy.json | 110 + + ...-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + ...-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 1825 ++++++++++++++ + ...ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + ...ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 1215 ++++++++++ + .../ASK-PP-ES1227-54TS.md5 | 1 + + .../ASK-PP-ES1227-54TS.xml | 891 +++++++ + .../SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + .../SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 511 ++++ + .../wistron_es1227_54ts/hwsku.json | 322 +++ + .../wistron_es1227_54ts/port_config.ini | 55 + + .../wistron_es1227_54ts/profile.ini | 1 + + .../wistron_es1227_54ts/sai.profile | 4 + + .../arm64-wistron_es2227_54ts-r0/default_sku | 1 + + .../installer.conf | 1 + + .../arm64-wistron_es2227_54ts-r0/pcie.yaml | 10 + + .../platform.json | 560 +++++ + .../platform_afi.json | 560 +++++ + .../platform_afo.json | 560 +++++ + .../platform_asic | 1 + + .../platform_components.json | 11 + + .../pmon_daemon_control.json | 4 + + .../arm64-wistron_es2227_54ts-r0/sensors.conf | 59 + + .../sensors_afi.conf | 59 + + .../sensors_afo.conf | 59 + + .../system_health_monitoring_config.json | 12 + + .../thermal_policy.json | 110 + + ...-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + ...-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 1825 ++++++++++++++ + ...ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + ...ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 1215 ++++++++++ + .../ASK-PP-ES1227-54TS.md5 | 1 + + .../ASK-PP-ES1227-54TS.xml | 891 +++++++ + .../SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + .../SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 511 ++++ + .../wistron_es2227_54ts/hwsku.json | 322 +++ + .../wistron_es2227_54ts/port_config.ini | 55 + + .../wistron_es2227_54ts/profile.ini | 1 + + .../wistron_es2227_54ts/sai.profile | 4 + + .../default_sku | 1 + + .../installer.conf | 1 + + .../arm64-wistron_es2227_54ts_p-r0/pcie.yaml | 10 + + .../platform.json | 567 +++++ + .../platform_asic | 1 + + .../platform_components.json | 12 + + .../plugins/eeprom.py | 13 + + .../pmon_daemon_control.json | 4 + + .../sensors.conf | 59 + + .../system_health_monitoring_config.json | 12 + + .../thermal_policy.json | 110 + + ...-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + ...-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 1785 ++++++++++++++ + ...ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + ...ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 1493 ++++++++++++ + .../ASK-PP-ES1227-54TS.md5 | 1 + + .../ASK-PP-ES1227-54TS.xml | 896 +++++++ + .../SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 | 1 + + .../SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml | 536 ++++ + .../wistron_es2227_54ts_p/hwsku.json | 322 +++ + .../wistron_es2227_54ts_p/media_settings.json | 28 + + .../poe_default_cfg.json | 382 +++ + .../wistron_es2227_54ts_p/port_config.ini | 55 + + .../wistron_es2227_54ts_p/profile.ini | 1 + + .../wistron_es2227_54ts_p/sai.profile | 4 + + .../marvell-prestera/platform-wistron.dep | 8 + + platform/marvell-prestera/platform-wistron.mk | 26 + + platform/marvell-prestera/rules.dep | 1 + + platform/marvell-prestera/rules.mk | 1 + + .../sonic-platform-wistron/debian/changelog | 5 + + .../sonic-platform-wistron/debian/compat | 1 + + .../sonic-platform-wistron/debian/control | 24 + + .../sonic-platform-wistron/debian/rules | 87 + + .../debian/sonic-platform-es1227-54ts.install | 16 + + .../sonic-platform-es1227-54ts.postinst | 51 + + .../sonic-platform-es2227-54ts-p.install | 24 + + .../sonic-platform-es2227-54ts-p.postinst | 51 + + .../debian/sonic-platform-es2227-54ts.install | 18 + + .../sonic-platform-es2227-54ts.postinst | 51 + + .../es1227_54ts/modules/Makefile | 17 + + .../es1227_54ts/modules/pmbus.h | 511 ++++ + .../es1227_54ts/modules/wistron_cpld.c | 2154 ++++++++++++++++ + .../es1227_54ts/modules/wistron_cpld.h | 298 +++ + .../es1227_54ts/modules/wistron_max31790.c | 604 +++++ + .../es1227_54ts/modules/wistron_psu.c | 248 ++ + .../es1227_54ts/scripts/entropy.py | 19 + + .../es1227_54ts/scripts/es1227_54ts-init.sh | 106 + + .../scripts/es1227_54ts_plt_setup.sh | 33 + + .../es1227_54ts/scripts/fw_env.config | 1 + + .../service/es1227_54ts-init.service | 15 + + .../service/es1227_54ts-psu-monitor.service | 15 + + .../service/es1227_54ts-rst_button.service | 16 + + .../service/es1227_54ts-sensor_conf.service | 16 + + .../service/es1227_54ts-sysled.service | 15 + + .../es1227_54ts/setup.py | 32 + + .../es1227_54ts/sonic_platform/__init__.py | 3 + + .../es1227_54ts/sonic_platform/chassis.py | 464 ++++ + .../es1227_54ts/sonic_platform/component.py | 186 ++ + .../es1227_54ts/sonic_platform/eeprom.py | 120 + + .../es1227_54ts/sonic_platform/fan.py | 366 +++ + .../es1227_54ts/sonic_platform/fan_drawer.py | 108 + + .../es1227_54ts/sonic_platform/pcie.py | 47 + + .../es1227_54ts/sonic_platform/platform.py | 22 + + .../es1227_54ts/sonic_platform/psu.py | 359 +++ + .../es1227_54ts/sonic_platform/sfp.py | 379 +++ + .../es1227_54ts/sonic_platform/thermal.py | 303 +++ + .../sonic_platform/thermal_actions.py | 240 ++ + .../sonic_platform/thermal_conditions.py | 110 + + .../sonic_platform/thermal_infos.py | 210 ++ + .../sonic_platform/thermal_manager.py | 10 + + .../es1227_54ts/sonic_platform/watchdog.py | 199 ++ + .../es1227_54ts/utils/get-base-mac.py | 20 + + .../es1227_54ts/utils/phytool | Bin 0 -> 24440 bytes + .../es1227_54ts/utils/psu_detect.py | 56 + + .../es1227_54ts/utils/rst_button.py | 66 + + .../es1227_54ts/utils/sensor_conf.sh | 13 + + .../es1227_54ts/utils/sysled_health.py | 14 + + .../es1227_54ts/utils/updateCPLD | Bin 0 -> 23328 bytes + .../es2227_54ts/modules/Makefile | 17 + + .../es2227_54ts/modules/pmbus.h | 511 ++++ + .../es2227_54ts/modules/wistron_cpld.c | 2154 ++++++++++++++++ + .../es2227_54ts/modules/wistron_cpld.h | 298 +++ + .../es2227_54ts/modules/wistron_max31790.c | 604 +++++ + .../es2227_54ts/modules/wistron_psu.c | 248 ++ + .../es2227_54ts/scripts/entropy.py | 19 + + .../es2227_54ts/scripts/es2227_54ts-init.sh | 72 + + .../scripts/es2227_54ts_plt_setup.sh | 33 + + .../es2227_54ts/scripts/fw_env.config | 1 + + .../service/es2227_54ts-init.service | 15 + + .../service/es2227_54ts-oob-led.service | 16 + + .../service/es2227_54ts-psu-monitor.service | 15 + + .../service/es2227_54ts-rst_button.service | 16 + + .../service/es2227_54ts-sensor_conf.service | 16 + + .../service/es2227_54ts-sysled.service | 15 + + .../es2227_54ts/setup.py | 32 + + .../es2227_54ts/sonic_platform/__init__.py | 3 + + .../es2227_54ts/sonic_platform/chassis.py | 464 ++++ + .../es2227_54ts/sonic_platform/component.py | 186 ++ + .../es2227_54ts/sonic_platform/eeprom.py | 120 + + .../es2227_54ts/sonic_platform/fan.py | 366 +++ + .../es2227_54ts/sonic_platform/fan_drawer.py | 108 + + .../es2227_54ts/sonic_platform/pcie.py | 47 + + .../es2227_54ts/sonic_platform/platform.py | 22 + + .../es2227_54ts/sonic_platform/psu.py | 359 +++ + .../es2227_54ts/sonic_platform/sfp.py | 379 +++ + .../es2227_54ts/sonic_platform/thermal.py | 303 +++ + .../sonic_platform/thermal_actions.py | 240 ++ + .../sonic_platform/thermal_conditions.py | 110 + + .../sonic_platform/thermal_infos.py | 210 ++ + .../sonic_platform/thermal_manager.py | 10 + + .../es2227_54ts/sonic_platform/watchdog.py | 199 ++ + .../es2227_54ts/utils/es2227_54ts-oob-led.sh | 103 + + .../es2227_54ts/utils/get-base-mac.py | 20 + + .../es2227_54ts/utils/phytool | Bin 0 -> 24440 bytes + .../es2227_54ts/utils/psu_detect.py | 56 + + .../es2227_54ts/utils/rst_button.py | 66 + + .../es2227_54ts/utils/sensor_conf.sh | 13 + + .../es2227_54ts/utils/sysled_health.py | 14 + + .../es2227_54ts/utils/updateCPLD | Bin 0 -> 23328 bytes + .../es2227_54ts_p/modules/Makefile | 17 + + .../es2227_54ts_p/modules/wistron_cpld.c | 2156 +++++++++++++++++ + .../es2227_54ts_p/modules/wistron_cpld.h | 299 +++ + .../es2227_54ts_p/modules/wistron_eeprom.c | 281 +++ + .../es2227_54ts_p/modules/wistron_max31790.c | 604 +++++ + .../es2227_54ts_p/scripts/entropy.py | 19 + + .../scripts/es2227_54ts_p-init.sh | 76 + + .../scripts/es2227_54ts_p_plt_setup.sh | 33 + + .../es2227_54ts_p/scripts/fw_env.config | 1 + + .../service/es2227_54ts_p-init.service | 15 + + .../service/es2227_54ts_p-led-monitor.service | 14 + + .../service/es2227_54ts_p-oob-led.service | 16 + + .../service/es2227_54ts_p-poe_lldp.service | 15 + + .../service/es2227_54ts_p-psu-monitor.service | 15 + + .../service/es2227_54ts_p-rst_button.service | 16 + + .../service/es2227_54ts_p-sysled.service | 15 + + .../es2227_54ts_p/setup.py | 32 + + .../es2227_54ts_p/sonic_platform/__init__.py | 3 + + .../es2227_54ts_p/sonic_platform/chassis.py | 463 ++++ + .../es2227_54ts_p/sonic_platform/component.py | 194 ++ + .../es2227_54ts_p/sonic_platform/eeprom.py | 120 + + .../es2227_54ts_p/sonic_platform/fan.py | 353 +++ + .../sonic_platform/fan_drawer.py | 108 + + .../es2227_54ts_p/sonic_platform/pcie.py | 47 + + .../es2227_54ts_p/sonic_platform/platform.py | 22 + + .../es2227_54ts_p/sonic_platform/psu.py | 359 +++ + .../es2227_54ts_p/sonic_platform/sfp.py | 379 +++ + .../es2227_54ts_p/sonic_platform/thermal.py | 305 +++ + .../sonic_platform/thermal_actions.py | 218 ++ + .../sonic_platform/thermal_conditions.py | 110 + + .../sonic_platform/thermal_infos.py | 210 ++ + .../sonic_platform/thermal_manager.py | 10 + + .../es2227_54ts_p/sonic_platform/watchdog.py | 199 ++ + .../utils/es2227_54ts_p-oob-led.sh | 103 + + .../es2227_54ts_p/utils/es2227_54ts_p_led.py | 103 + + .../es2227_54ts_p/utils/get-base-mac.py | 20 + + .../es2227_54ts_p/utils/phytool | Bin 0 -> 24440 bytes + .../es2227_54ts_p/utils/poe_cfg_init.py | 370 +++ + .../es2227_54ts_p/utils/poe_cfg_lldp.py | 691 ++++++ + .../es2227_54ts_p/utils/poe_init.sh | 77 + + .../es2227_54ts_p/utils/poe_lldp.py | 440 ++++ + .../es2227_54ts_p/utils/poe_power.sh | 107 + + .../es2227_54ts_p/utils/poetool | Bin 0 -> 1338224 bytes + .../es2227_54ts_p/utils/psu_detect.py | 64 + + .../es2227_54ts_p/utils/rst_button.py | 66 + + .../es2227_54ts_p/utils/sysled_health.py | 14 + + .../es2227_54ts_p/utils/updateCPLD | Bin 0 -> 23328 bytes + platform/marvell-prestera/sonic_fit.its | 43 + + 219 files changed, 44027 insertions(+) + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/default_sku + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/installer.conf + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/pcie.yaml + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/platform.json + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/platform_afi.json + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/platform_afo.json + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/platform_asic + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/platform_components.json + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/pmon_daemon_control.json + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/sensors.conf + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afi.conf + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afo.conf + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/system_health_monitoring_config.json + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/thermal_policy.json + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.md5 + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.xml + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/hwsku.json + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/port_config.ini + create mode 100644 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/profile.ini + create mode 100755 device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/sai.profile + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/default_sku + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/installer.conf + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/pcie.yaml + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/platform.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/platform_afi.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/platform_afo.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/platform_asic + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/platform_components.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/pmon_daemon_control.json + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/sensors.conf + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afi.conf + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afo.conf + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/system_health_monitoring_config.json + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/thermal_policy.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.md5 + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.xml + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/hwsku.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/port_config.ini + create mode 100644 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/profile.ini + create mode 100755 device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/sai.profile + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/default_sku + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/installer.conf + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/pcie.yaml + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/platform.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_asic + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_components.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/plugins/eeprom.py + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/pmon_daemon_control.json + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/sensors.conf + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/system_health_monitoring_config.json + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/thermal_policy.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.md5 + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.xml + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/hwsku.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/media_settings.json + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/poe_default_cfg.json + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/port_config.ini + create mode 100644 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/profile.ini + create mode 100755 device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/sai.profile + create mode 100644 platform/marvell-prestera/platform-wistron.dep + create mode 100644 platform/marvell-prestera/platform-wistron.mk + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/changelog + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/compat + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/control + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/debian/rules + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.install + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.postinst + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.install + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.postinst + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.install + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.postinst + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/Makefile + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/pmbus.h + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.c + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.h + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_max31790.c + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_psu.c + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/entropy.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts-init.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts_plt_setup.sh + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/fw_env.config + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-init.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-psu-monitor.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-rst_button.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sensor_conf.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sysled.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/setup.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/__init__.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/chassis.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/component.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/eeprom.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan_drawer.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/pcie.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/platform.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/psu.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/sfp.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_actions.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_conditions.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_infos.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_manager.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/watchdog.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/get-base-mac.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/phytool + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/psu_detect.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/rst_button.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sensor_conf.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sysled_health.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/updateCPLD + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/Makefile + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/pmbus.h + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.c + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.h + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_max31790.c + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_psu.c + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/entropy.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts-init.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts_plt_setup.sh + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/fw_env.config + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-init.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-oob-led.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-psu-monitor.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-rst_button.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sensor_conf.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sysled.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/setup.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/__init__.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/chassis.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/component.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/eeprom.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan_drawer.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/pcie.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/platform.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/psu.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/sfp.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_actions.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_conditions.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_infos.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_manager.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/watchdog.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/es2227_54ts-oob-led.sh + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/get-base-mac.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/phytool + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/psu_detect.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/rst_button.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sensor_conf.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sysled_health.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/updateCPLD + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/Makefile + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.c + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.h + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_eeprom.c + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_max31790.c + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/entropy.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p-init.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p_plt_setup.sh + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/fw_env.config + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-init.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-led-monitor.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-oob-led.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-poe_lldp.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-psu-monitor.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-rst_button.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-sysled.service + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/setup.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/__init__.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/chassis.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/component.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/eeprom.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan_drawer.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/pcie.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/platform.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/psu.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/sfp.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_actions.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_conditions.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_infos.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_manager.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/watchdog.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p-oob-led.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p_led.py + create mode 100644 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/get-base-mac.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/phytool + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_init.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_lldp.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_init.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_lldp.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_power.sh + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poetool + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/psu_detect.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/rst_button.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/sysled_health.py + create mode 100755 platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/updateCPLD + +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/default_sku b/device/wistron/arm64-wistron_es1227_54ts-r0/default_sku +new file mode 100644 +index 000000000..b6809748b +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/default_sku +@@ -0,0 +1 @@ ++wistron_es1227_54ts t1 +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/installer.conf b/device/wistron/arm64-wistron_es1227_54ts-r0/installer.conf +new file mode 100644 +index 000000000..28757b561 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/installer.conf +@@ -0,0 +1 @@ ++ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="default_hugepagesz=2M hugepages=256 pci=noaer" +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/pcie.yaml b/device/wistron/arm64-wistron_es1227_54ts-r0/pcie.yaml +new file mode 100644 +index 000000000..84faf76b2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/pcie.yaml +@@ -0,0 +1,10 @@ ++- bus: '00' ++ dev: '00' ++ fn: '0' ++ id: '0110' ++ name: 'PCI bridge: Marvell Technology Group Ltd. Device 0110' ++- bus: '01' ++ dev: '00' ++ fn: '0' ++ id: '9823' ++ name: 'Ethernet controller: Marvell Technology Group Ltd. Device 9823' +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/platform.json b/device/wistron/arm64-wistron_es1227_54ts-r0/platform.json +new file mode 100644 +index 000000000..c652e0b92 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/platform.json +@@ -0,0 +1,560 @@ ++{ ++ "chassis": { ++ "name": "wistron_es1227_54ts", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "DDR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XFMR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/platform_afi.json b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_afi.json +new file mode 100644 +index 000000000..22bf87911 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_afi.json +@@ -0,0 +1,560 @@ ++{ ++ "chassis": { ++ "name": "wistron_es1227_54ts", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "FAN Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "CPU Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/platform_afo.json b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_afo.json +new file mode 100644 +index 000000000..c652e0b92 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_afo.json +@@ -0,0 +1,560 @@ ++{ ++ "chassis": { ++ "name": "wistron_es1227_54ts", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "DDR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XFMR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/platform_asic b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_asic +new file mode 100644 +index 000000000..5cbe9d002 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_asic +@@ -0,0 +1 @@ ++marvell-prestera +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/platform_components.json b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_components.json +new file mode 100644 +index 000000000..934e05abb +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/platform_components.json +@@ -0,0 +1,11 @@ ++{ ++ "chassis": { ++ "wistron_es1227_54ts": { ++ "component": { ++ "U-Boot": { }, ++ "ONIE-VERSION": { }, ++ "CPLD": { } ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/pmon_daemon_control.json b/device/wistron/arm64-wistron_es1227_54ts-r0/pmon_daemon_control.json +new file mode 100644 +index 000000000..689def2c1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/pmon_daemon_control.json +@@ -0,0 +1,4 @@ ++{ ++ "skip_ledd": true, ++ "skip_pcied": true ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/sensors.conf b/device/wistron/arm64-wistron_es1227_54ts-r0/sensors.conf +new file mode 100755 +index 000000000..9c67f1fa6 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/sensors.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "1227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "wistron_psu-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "wistron_psu-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "XFMR Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "DDR Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "System Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afi.conf b/device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afi.conf +new file mode 100755 +index 000000000..78af494f9 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afi.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "1227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "wistron_psu-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "wistron_psu-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "System Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "FAN Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "CPU Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afo.conf b/device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afo.conf +new file mode 100755 +index 000000000..9c67f1fa6 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/sensors_afo.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "1227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "wistron_psu-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "wistron_psu-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "XFMR Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "DDR Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "System Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/system_health_monitoring_config.json b/device/wistron/arm64-wistron_es1227_54ts-r0/system_health_monitoring_config.json +new file mode 100644 +index 000000000..b6aa813f1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/system_health_monitoring_config.json +@@ -0,0 +1,12 @@ ++{ ++ "services_to_ignore": [], ++ "devices_to_ignore": ["asic"], ++ "user_defined_checkers": [], ++ "polling_interval": 60, ++ "led_color": { ++ "fault": "red", ++ "normal": "green", ++ "booting": "green_blinking" ++ } ++} ++ +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/thermal_policy.json b/device/wistron/arm64-wistron_es1227_54ts-r0/thermal_policy.json +new file mode 100755 +index 000000000..da35ff6d2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/thermal_policy.json +@@ -0,0 +1,110 @@ ++{ ++ "thermal_control_algorithm": { ++ "run_at_boot_up": "false", ++ "interval": "60" ++ }, ++ "info_types": [ ++ { ++ "type": "fan_info" ++ }, ++ { ++ "type": "thermal_info" ++ }, ++ { ++ "type": "chassis_info" ++ } ++ ], ++ "policies": [ ++ { ++ "name": "any fan absence", ++ "conditions": [ ++ { ++ "type": "fan.any.absence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.all.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "all fan presence", ++ "conditions": [ ++ { ++ "type": "fan.all.presence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "any fan new", ++ "conditions": [ ++ { ++ "type": "fan.any.new" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.new.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "all fan absence", ++ "conditions": [ ++ { ++ "type": "fan.all.absence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ }, ++ { ++ "name": "temp over high critical threshold", ++ "conditions": [ ++ { ++ "type": "thermal.over.high_critical_threshold" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ }, ++ { ++ "name": "temp over high threshold", ++ "conditions": [ ++ { ++ "type": "thermal.over.high_threshold" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "high_threshold.control" ++ } ++ ] ++ }, ++ { ++ "name": "temp over threshold after cool down", ++ "conditions": [ ++ { ++ "type": "thermal.over.threshold_after_cool_down" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ } ++ ] ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100644 +index 000000000..66bfd55e3 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++8f1de4b7c3a39dfafa16bf03a194962c +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100644 +index 000000000..a9d9a8f45 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,1825 @@ ++ ++ ++ ++ ++ ++ std-string ++ string ++ standard string. ++ 1 ++ 100 ++ ++ ++ board-callback-type ++ enumeration ++ Specifies os/ext drv callback types. ++ ++ linux-static ++ Linux Static ++ 0 ++ ++ ++ linux-shared ++ Linux Shared Lib mode ++ 1 ++ ++ ++ external ++ External Os ++ 3 ++ ++ ++ freeBsd ++ Free BSD ++ 4 ++ ++ ++ ++ board-pp-map-type ++ enumeration ++ Specifies pci info types. ++ ++ fixed ++ Fixed ++ 0 ++ ++ ++ autoscan ++ Auto scan ++ 1 ++ ++ ++ ++ board-pp-interface-channel-type ++ enumeration ++ Specifies channel interface type. ++ ++ pci ++ PCI ++ 0 ++ ++ ++ smi ++ SMI ++ 1 ++ ++ ++ twsi ++ TWSI ++ 2 ++ ++ ++ ++ board-pp-as-type ++ enumeration ++ Specifies Address space type. ++ ++ 4_regions ++ address-space 4 regions ++ 0 ++ ++ ++ 8_regions ++ address-space 8 regions ++ 1 ++ ++ ++ atu ++ address translation unit ++ 2 ++ ++ ++ ++ device-id-type ++ uint32 ++ Device ID 0..1 ++ 0 ++ 1 ++ ++ ++ port-mapping-type ++ enumeration ++ Specifies port map type. ++ ++ ethernet_mac ++ ETHERNET_MAC ++ 0 ++ ++ ++ cpu_sdma ++ CPU_SDMA ++ 1 ++ ++ ++ ++ interface-num-type ++ uint32 ++ Interface number ++ 0 ++ 1023 ++ ++ ++ txq-port-number-type ++ uint32 ++ TXq port number ++ 0 ++ 99 ++ ++ ++ phy-smi-interface-type ++ uint32 ++ Phy SMI interface type. ++ 0 ++ 3 ++ ++ ++ phy-xsmi-interface-type ++ uint32 ++ Phy XSMI interface type. ++ 0 ++ 15 ++ ++ ++ phy-type ++ enumeration ++ Specifies the PHY Part Identifier. ++ ++ NA ++ No Phy ++ 0 ++ ++ ++ alaska-88E1543 ++ Specifies PHY identifier 88E1543, used for Combo ports. ++ 1 ++ ++ ++ alaska-88E1545 ++ Specifies PHY identifier 88E1545, used for Copper GE with MAC on PHY support. ++ 2 ++ ++ ++ alaska-88E1680 ++ Specifies PHY identifier 88E1680, used for Copper with speeds of 10M/100M/1G. ++ 3 ++ ++ ++ alaska-88E151X ++ Specifies PHY identifier 88E151X, used for Copper (HW supports combo and fiber). ++ 4 ++ ++ ++ alaska-88E3140 ++ Specifies PHY identifier 88E3140, used for Copper with speeds of 100M/1G/10G. ++Uses with FW SolarFlare next generation. ++ 5 ++ ++ ++ alaska-88E3240 ++ Specifies PHY identifier 88E3240, used for Copper with speeds of 100M/1G/10G. ++Uses with FW, SolarFlare next generation. ++ 6 ++ ++ ++ alaska-88E3680 ++ Specifies PHY identifier 88E3680, used for Octal Copper 100M. ++ 7 ++ ++ ++ alaska-88E3220 ++ Specifies PHY identifier 88E3220, used for Combo port with speeds of 100M/1G/10G. ++Uses FW, SolarFlare next generation. ++ 8 ++ ++ ++ alaska-88E1680L ++ Specifies PHY identifier 88E1680L, used for Copper with speeds of 10M/100M/1G. ++ 9 ++ ++ ++ alaska-88E33X0 ++ Specifies PHY identifier 88E33X0, used for MGIG Combo. ++ 10 ++ ++ ++ alaska-88E1548 ++ Specifies PHY identifier 88E1548, used for Fiber GE. ++ 11 ++ ++ ++ alaska-88E20X0 ++ Specifies PHY identifier 88E20X0, used for Copper with speeds of 10M/100M/1G/2.5G/5G. ++ 12 ++ ++ ++ alaska-88E1512 ++ Specifies PHY identifier 88E1512, used for Copper with speeds of 10M/100M/1G. ++ 13 ++ ++ ++ alaska-88E2180 ++ Specifies PHY identifier 88E2180, used for Copper with speeds of 10M/100M/1G/2.5G/5G. ++ 14 ++ ++ ++ alaska-88E1780 ++ Specifies PHY identifier 88E1780, Integrated Octal 10/100/1000 Mbps Energy ++Efficient Ethernet Transceiver ++ 15 ++ ++ ++ alaska-88E2540 ++ Specifies PHY identifier 88E2540, 4 ports 10/100/1000/2.5G/5GBASE-T Ethernet ++Transceiver with IEEE 1588v2 PTP Support ++ 16 ++ ++ ++ alaska-88E2580 ++ Specifies PHY identifier 88E12580, Octal 10/100/1000/2.5G/5GBASE-T Ethernet Transceiver ++with IEEE 1588v2 PTP Support ++ 17 ++ ++ ++ ++ physical-port-num-type ++ uint32 ++ PHYSICAL PORT NUM ++ 0 ++ 1023 ++ ++ ++ led-stream-port-type ++ enumeration ++ Specifies the ledstream port type. ++ ++ PORT_TYPE_TRI_SPEED ++ tri-speed port. ++ 1 ++ ++ ++ PORT_TYPE_XG ++ XG port. ++ 2 ++ ++ ++ ++ led-stream-blink-select-type ++ enumeration ++ Specifies the LED stream blink select type. ++ ++ BLINK_SELECT_0 ++ Blink 0 signal. ++ 1 ++ ++ ++ BLINK_SELECT_1 ++ Blink 1 signal ++ 2 ++ ++ ++ ++ led-stream-order-mode-type ++ enumeration ++ Specifies the LED stream ordering mode. ++ ++ ORDER_MODE_BY_PORT ++ the indication order is arranged by port. ++ 1 ++ ++ ++ ORDER_MODE_BY_CLASS ++ the indication order is arranged by class. ++ 2 ++ ++ ++ ++ led-stream-blink-duty-cycle-type ++ enumeration ++ Specifies the LED stream blink cycle duty cycle type. ++ ++ BLINK_DUTY_CYCLE_0 ++ 25% on, 75% off. ++ 1 ++ ++ ++ BLINK_DUTY_CYCLE_1 ++ 50% on, 50% off. ++ 2 ++ ++ ++ BLINK_DUTY_CYCLE_2 ++ 50% on, 50% off. ++ 3 ++ ++ ++ BLINK_DUTY_CYCLE_3 ++ 75% on, 25% off. ++ 4 ++ ++ ++ ++ led-stream-blink-duration-type ++ enumeration ++ Specifies the LED stream blink period type. ++ ++ BLINK_DURATION_0 ++ BLINK_DURATION_0. ++ 1 ++ ++ ++ BLINK_DURATION_1 ++ BLINK_DURATION_1. ++ 2 ++ ++ ++ BLINK_DURATION_2 ++ BLINK_DURATION_2. ++ 3 ++ ++ ++ BLINK_DURATION_3 ++ BLINK_DURATION_3. ++ 4 ++ ++ ++ BLINK_DURATION_4 ++ BLINK_DURATION_4. ++ 5 ++ ++ ++ BLINK_DURATION_5 ++ BLINK_DURATION_5. ++ 6 ++ ++ ++ BLINK_DURATION_6 ++ (APPLICABLE DEVICES: xCat3; AC5; Lion2; Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Pipe) . ++ 7 ++ ++ ++ BLINK_DURATION_7 ++ APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Pipe). ++ 8 ++ ++ ++ ++ led-stream-pulse-stretch-type ++ enumeration ++ Specifies the LED stream length of stretching for dynamic signals. ++ ++ PULSE_STRETCH_0_NO ++ PULSE_STRETCH_0_NO. ++ 1 ++ ++ ++ PULSE_STRETCH_1 ++ PULSE_STRETCH_1. ++ 2 ++ ++ ++ PULSE_STRETCH_2 ++ PULSE_STRETCH_2. ++ 3 ++ ++ ++ PULSE_STRETCH_3 ++ PULSE_STRETCH_3. ++ 4 ++ ++ ++ PULSE_STRETCH_4 ++ PULSE_STRETCH_4. ++ 5 ++ ++ ++ PULSE_STRETCH_5 ++ PULSE_STRETCH_5. ++ 6 ++ ++ ++ PULSE_STRETCH_6 ++ (APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Falcon; AC5P; Pipe). ++ 7 ++ ++ ++ PULSE_STRETCH_7 ++ (APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Falcon; AC5P; Pipe). ++ 8 ++ ++ ++ ++ led-stream-clock-out-frequency-type ++ enumeration ++ Specifies the LED stream blink cycle duty cycle type. ++ ++ _CLOCK_OUT_FREQUENCY_500 ++ 500 KHz LED clock frequency. ++ 1 ++ ++ ++ CLOCK_OUT_FREQUENCY_1000 ++ 1 MHz LED clock frequency. ++ 2 ++ ++ ++ CLOCK_OUT_FREQUENCY_2000 ++ 2 MHz LED clock frequency. ++ 3 ++ ++ ++ CLOCK_OUT_FREQUENCY_3000 ++ 3 MHz LED clock frequency. ++ 4 ++ ++ ++ ++ led-stream-class5-select-type ++ enumeration ++ Specifies the LED stream indication displayed on class5 (for dual-media port/phy). ++ ++ CLASS_5_SELECT_HALF_DUPLEX ++ Half Duplex is displayed on class5. ++ 1 ++ ++ ++ CLASS_5_SELECT_FIBER_LINK_UP ++ If port is a dual media port, Fiber Link Up is displayed on class5. ++ 2 ++ ++ ++ ++ led-stream-class13-select-type ++ enumeration ++ Specifies the LED stream indication displayed on class13 (for dual-media port/phy). ++ ++ CLASS_13_SELECT_LINK_DOWN ++ Link Down is displayed on class13. ++ 1 ++ ++ ++ CLASS_13_SELECT_COPPER_LINK_UP ++ If port is a dual media port, Copper Link Up is displayed on class13. ++ 2 ++ ++ ++ ++ led-class-num-type ++ uint32 ++ Led Class number ++ 0 ++ 11 ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ bus-id-type ++ uint32 ++ Bus Id Type, PCI/SMI ++ 0 ++ 255 ++ ++ ++ function-id-type ++ uint32 ++ Function Id Type, PCI/SMI ++ 0 ++ 255 ++ ++ ++ domain-type ++ uint32 ++ Domain, PCI/SMI ++ 0 ++ 255 ++ ++ ++ led-interface-type ++ uint32 ++ Led interface ++ 0 ++ 255 ++ ++ ++ led-position-type ++ uint32 ++ Led position ++ 0 ++ 63 ++ ++ ++ serdes-lane-type ++ uint32 ++ serdes lane ++ 0 ++ 7 ++ ++ ++ cpu-type ++ enumeration ++ The CPU Internal/External ++ ++ external ++ Extrenal connected CPU ++ 0 ++ ++ ++ internal ++ Internal CPU ++ 1 ++ ++ ++ ++ led-stream-clock-frequency-type ++ uint32 ++ Led Clock Frequency Sip6 ++ 500 ++ 80000 ++ ++ ++ led-unit-type ++ uint32 ++ Led units ++ 1 ++ 16 ++ ++ ++ led-unit-or-no-unit-type ++ uint32 ++ Led units, 0 for no Unit ++ 0 ++ 16 ++ ++ ++ led-group-type ++ uint32 ++ Led Group ++ 0 ++ 1 ++ ++ ++ led-stream-force-data-type ++ string ++ A hexadecimal string with octets represented as hex digits ++separated by colons. The canonical representation uses ++lowercase characters. ++ 3 ++ 11 ++ ++ ++ bit-type ++ uint32 ++ Bit range 0..31 ++ 0 ++ 31 ++ ++ ++ bit-size-type ++ uint32 ++ Bit leng 1..32 ++ 1 ++ 32 ++ ++ ++ led-sip-type ++ enumeration ++ The LED scehme ++ ++ na ++ NA ++ 0 ++ ++ ++ sip5 ++ SIP5: AC3x ++ 5 ++ ++ ++ sip6 ++ SIP6: Falcon, AC5x ++ 6 ++ ++ ++ ++ port-cscd-type ++ enumeration ++ Specifies the cascade port type. ++ ++ DSA_1_WORD ++ DSA Regular ++ 0 ++ ++ ++ DSA_2_WORDS ++ DSA Extended ++ 1 ++ ++ ++ NETWORK ++ Network. ++ 2 ++ ++ ++ DSA_3_WORDS ++ DSA 3 Words ++ 3 ++ ++ ++ DSA_4_WORD ++ DSA 4 Words ++ 4 ++ ++ ++ ++ trunk-cscd-type ++ uint32 ++ Specifies the Cascade Trunk id. ++ 0 ++ 127 ++ ++ ++ port-trunk-cscd-type ++ enumeration ++ Specifies the cascade port type. ++ ++ cscdPort ++ Cascade port ++ 0 ++ ++ ++ cscdTrunk ++ Csacde trunk ++ 1 ++ ++ ++ ++ hash-cscd-type ++ enumeration ++ Specifies the hash used by cascade trunk. ++ ++ pkt ++ Hash based on packet ++ 0 ++ ++ ++ srcPort ++ Hash based on source port ++ 1 ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ES1227-54TS-32x1G-16x2.5G-6x25G ++ linux-static ++ linux-static ++ autoscan ++ external ++ pci ++ atu ++ ++ 0 ++ 0 ++ ASK-PP-ES1227-54TS.xml ++ ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++ sip6 ++ ++ 0 ++ ++ ethernet_mac ++ 0 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 0 ++ 0 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 1 ++ ++ ethernet_mac ++ 1 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 1 ++ 0 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 2 ++ ++ ethernet_mac ++ 2 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 2 ++ 0 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 3 ++ ++ ethernet_mac ++ 3 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 3 ++ 0 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 4 ++ ++ ethernet_mac ++ 4 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 4 ++ 0 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 5 ++ ++ ethernet_mac ++ 5 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 5 ++ 0 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 6 ++ ++ ethernet_mac ++ 6 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 6 ++ 0 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 7 ++ ++ ethernet_mac ++ 7 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 7 ++ 0 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 8 ++ ++ ethernet_mac ++ 8 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 8 ++ 0 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 9 ++ ++ ethernet_mac ++ 9 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 9 ++ 0 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 10 ++ ++ ethernet_mac ++ 10 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 10 ++ 0 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 11 ++ ++ ethernet_mac ++ 11 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 11 ++ 0 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 12 ++ ++ ethernet_mac ++ 12 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 12 ++ 0 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 13 ++ ++ ethernet_mac ++ 13 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 13 ++ 0 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 14 ++ ++ ethernet_mac ++ 14 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 14 ++ 0 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 15 ++ ++ ethernet_mac ++ 15 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 15 ++ 0 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 16 ++ ++ ethernet_mac ++ 16 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 16 ++ 0 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 17 ++ ++ ethernet_mac ++ 17 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 17 ++ 0 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 18 ++ ++ ethernet_mac ++ 18 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 18 ++ 0 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 19 ++ ++ ethernet_mac ++ 19 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 19 ++ 0 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 20 ++ ++ ethernet_mac ++ 20 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 20 ++ 0 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 21 ++ ++ ethernet_mac ++ 21 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 21 ++ 0 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 22 ++ ++ ethernet_mac ++ 22 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 22 ++ 0 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 23 ++ ++ ethernet_mac ++ 23 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 23 ++ 0 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 24 ++ ++ ethernet_mac ++ 24 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 24 ++ 0 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 25 ++ ++ ethernet_mac ++ 25 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 25 ++ 0 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 26 ++ ++ ethernet_mac ++ 26 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 26 ++ 0 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 27 ++ ++ ethernet_mac ++ 27 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 27 ++ 0 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 28 ++ ++ ethernet_mac ++ 28 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 28 ++ 0 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 29 ++ ++ ethernet_mac ++ 29 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 29 ++ 0 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 30 ++ ++ ethernet_mac ++ 30 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 30 ++ 0 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 31 ++ ++ ethernet_mac ++ 31 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 31 ++ 0 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 32 ++ ++ ethernet_mac ++ 33 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 1 ++ 1 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 33 ++ ++ ethernet_mac ++ 32 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 0 ++ 1 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 34 ++ ++ ethernet_mac ++ 35 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 3 ++ 1 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 35 ++ ++ ethernet_mac ++ 34 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 2 ++ 1 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 36 ++ ++ ethernet_mac ++ 37 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 5 ++ 1 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 37 ++ ++ ethernet_mac ++ 36 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 4 ++ 1 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 38 ++ ++ ethernet_mac ++ 39 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 7 ++ 1 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 39 ++ ++ ethernet_mac ++ 38 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 6 ++ 1 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 40 ++ ++ ethernet_mac ++ 41 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 9 ++ 1 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 41 ++ ++ ethernet_mac ++ 40 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 8 ++ 1 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 42 ++ ++ ethernet_mac ++ 43 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 11 ++ 1 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 43 ++ ++ ethernet_mac ++ 42 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 10 ++ 1 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 44 ++ ++ ethernet_mac ++ 45 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 13 ++ 1 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 45 ++ ++ ethernet_mac ++ 44 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 12 ++ 1 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 46 ++ ++ ethernet_mac ++ 47 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 15 ++ 1 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 47 ++ ++ ethernet_mac ++ 46 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 14 ++ 1 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 48 ++ ++ ethernet_mac ++ 49 ++ false ++ ++ ++ NA ++ ++ ++ 1 ++ false ++ ++ ++ ++ 49 ++ ++ ethernet_mac ++ 48 ++ false ++ ++ ++ NA ++ ++ ++ 0 ++ false ++ ++ ++ ++ 50 ++ ++ ethernet_mac ++ 51 ++ false ++ ++ ++ NA ++ ++ ++ 1 ++ false ++ ++ ++ ++ 51 ++ ++ ethernet_mac ++ 50 ++ false ++ ++ ++ NA ++ ++ ++ 0 ++ false ++ ++ ++ ++ 52 ++ ++ ethernet_mac ++ 53 ++ false ++ ++ ++ NA ++ ++ ++ 3 ++ false ++ ++ ++ ++ 53 ++ ++ ethernet_mac ++ 52 ++ false ++ ++ ++ NA ++ ++ ++ 2 ++ false ++ ++ ++ ++ 60 ++ ++ cpu_sdma ++ 55 ++ false ++ ++ ++ ++ 63 ++ ++ cpu_sdma ++ 54 ++ false ++ ++ ++ ++ 0 ++ false ++ false ++ ++ ++ 1 ++ false ++ false ++ ++ ++ 2 ++ false ++ false ++ ++ ++ 3 ++ false ++ false ++ ++ ++ 4 ++ false ++ false ++ ++ ++ 5 ++ false ++ false ++ ++ ++ 6 ++ false ++ false ++ ++ ++ 7 ++ false ++ false ++ ++ ++ 8 ++ false ++ false ++ ++ ++ 9 ++ false ++ false ++ ++ ++ 10 ++ false ++ false ++ ++ ++ 11 ++ false ++ false ++ ++ ++ 0 ++ ++ ORDER_MODE_BY_CLASS ++ BLINK_DUTY_CYCLE_1 ++ BLINK_DURATION_0 ++ BLINK_DUTY_CYCLE_1 ++ BLINK_DURATION_0 ++ PULSE_STRETCH_1 ++ false ++ 1627 ++ false ++ ++ 1 ++ 0 ++ 95 ++ false ++ ++ ++ 2 ++ 0 ++ 95 ++ false ++ ++ ++ 3 ++ 0 ++ 95 ++ false ++ ++ ++ 4 ++ 0 ++ 95 ++ false ++ ++ ++ 5 ++ 0 ++ 95 ++ false ++ ++ ++ ++ 0 ++ PORT_TYPE_XG ++ false ++ BLINK_SELECT_0 ++ true ++ 0xffffffff ++ false ++ false ++ ++ ++ 1 ++ PORT_TYPE_XG ++ false ++ BLINK_SELECT_0 ++ false ++ false ++ false ++ ++ ++ 2 ++ PORT_TYPE_XG ++ true ++ BLINK_SELECT_0 ++ false ++ true ++ true ++ ++ ++ ++ . ++ ++ 1 ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100644 +index 000000000..e473ecc38 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++936ee72e62232a32ba78351b17a67321 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100644 +index 000000000..7590d96b4 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,1215 @@ ++ ++ ++ ++ ++ ++ interface-mode-type ++ enumeration ++ Specifies supported Interface modes ++ ++ 1000BASE_X ++ 1G ++ 6 ++ ++ ++ SGMII ++ 1G , 2.5G ++ 3 ++ ++ ++ QSGMII ++ 1G ++ 13 ++ ++ ++ KR ++ 10G, 12G, 20G, 40G, 100G ++ 16 ++ ++ ++ SR_LR ++ 5G, 10G, 12G, 20G, 40G ++ 20 ++ ++ ++ KR2 ++ ++ 27 ++ ++ ++ KR4 ++ ++ 28 ++ ++ ++ SR_LR2 ++ ++ 29 ++ ++ ++ SR_LR4 ++ 100G ++ 30 ++ ++ ++ KR_C ++ CONSORTIUM - 25G ++ 32 ++ ++ ++ CR_C ++ CONSORTIUM - 25G ++ 33 ++ ++ ++ KR2_C ++ CONSORTIUM - 50G ++ 34 ++ ++ ++ CR2_C ++ CONSORTIUM - 50G ++ 35 ++ ++ ++ CR ++ ++ 36 ++ ++ ++ CR2 ++ ++ 37 ++ ++ ++ CR4 ++ ++ 38 ++ ++ ++ KR_S ++ ++ 39 ++ ++ ++ CR_S ++ ++ 40 ++ ++ ++ KR8 ++ ++ 41 ++ ++ ++ CR8 ++ ++ 42 ++ ++ ++ SR_LR8 ++ ++ 43 ++ ++ ++ USX_10G_QXGMII ++ ++ 51 ++ ++ ++ USX_20G_QXGMII ++ ++ 52 ++ ++ ++ USX_OUSGMII ++ ++ 53 ++ ++ ++ USX_20G_OXGMII ++ ++ 54 ++ ++ ++ NA ++ ++ 57 ++ ++ ++ ++ port-speed-type ++ enumeration ++ Specifies supported speeds ++ ++ 1G ++ 1G ++ 2 ++ ++ ++ 10G ++ 10G ++ 3 ++ ++ ++ 2500M ++ 2.5G ++ 5 ++ ++ ++ 5G ++ 5G ++ 6 ++ ++ ++ 25G ++ 25G, used in combination with CPSS_PORT_INTERFACE_MODE_KR_E, CPSS_PORT_INTERFACE_MODE_KR2_E ++ 21 ++ ++ ++ 40G ++ 40G ++ 9 ++ ++ ++ 50G ++ 50G ++ 14 ++ ++ ++ 100G ++ 100G ++ 13 ++ ++ ++ 200G ++ 200G ++ 24 ++ ++ ++ 400G ++ 400G ++ 25 ++ ++ ++ NA ++ NA ++ 35 ++ ++ ++ ++ fec-type ++ enumeration ++ Rx parameter type ++ ++ enabled ++ Enabled ++ 0 ++ ++ ++ disabled ++ Disabled ++ 1 ++ ++ ++ rs_enabled ++ RS FEC enabled ++ 2 ++ ++ ++ both_enabled ++ Both enabled ++ 3 ++ ++ ++ rs_544_514_enabled ++ RS FEC 544 and 514 ++ 4 ++ ++ ++ ++ physical-port-num-type ++ uint32 ++ PHYSICAL PORT NUM ++ 0 ++ 1023 ++ ++ ++ tx-param-type ++ enumeration ++ Tx parameter type ++ ++ pre ++ pre ++ 0 ++ ++ ++ post ++ post ++ 1 ++ ++ ++ peak ++ peak ++ 2 ++ ++ ++ ++ rx-param-type ++ enumeration ++ Rx parameter type ++ ++ dataRate ++ dataRate ++ 0 ++ ++ ++ res1Sel ++ res1Sel ++ 1 ++ ++ ++ res2Sel ++ res2Sel ++ 2 ++ ++ ++ cap1Sel ++ cap1Sel ++ 3 ++ ++ ++ cap2Sel ++ cap2Sel ++ 4 ++ ++ ++ minCap ++ minCap ++ 5 ++ ++ ++ minCapN ++ minCapN ++ 6 ++ ++ ++ sumfBoostTargetC0 ++ sumfBoostTargetC0 ++ 7 ++ ++ ++ sumfBoostTargetC1 ++ sumfBoostTargetC1 ++ 8 ++ ++ ++ sumfBoostTargetC2 ++ sumfBoostTargetC2 ++ 9 ++ ++ ++ midpointPhaseOs0 ++ midpointPhaseOs0 ++ 10 ++ ++ ++ midpointPhaseOs1 ++ midpointPhaseOs1 ++ 11 ++ ++ ++ midpointPhaseOs2 ++ midpointPhaseOs2 ++ 12 ++ ++ ++ selmufi ++ selmufi ++ 13 ++ ++ ++ selmuff ++ selmuff ++ 14 ++ ++ ++ selmupi ++ selmupi ++ 15 ++ ++ ++ selmupf ++ selmupf ++ 16 ++ ++ ++ midpointLargeThresKLane ++ midpointLargeThresKLane ++ 17 ++ ++ ++ midpointSmallThresKLane ++ midpointSmallThresKLane ++ 18 ++ ++ ++ midpointLargeThresCLane ++ midpointLargeThresCLane ++ 19 ++ ++ ++ midpointSmallThresCLane ++ midpointSmallThresCLane ++ 20 ++ ++ ++ inxSumfMidpointAdatptiveEnLane ++ inxSumfMidpointAdatptiveEnLane ++ 21 ++ ++ ++ dfeResF0aHighThresInitLane ++ dfeResF0aHighThresInitLane ++ 22 ++ ++ ++ dfeResF0aHighThresEndLane ++ dfeResF0aHighThresEndLane ++ 23 ++ ++ ++ squelch ++ squelch ++ 24 ++ ++ ++ align90 ++ align90 ++ 25 ++ ++ ++ sampler ++ sampler ++ 26 ++ ++ ++ slewRateCtrl0 ++ slewRateCtrl0 ++ 27 ++ ++ ++ slewRateCtrl1 ++ slewRateCtrl1 ++ 28 ++ ++ ++ EO ++ EO ++ 29 ++ ++ ++ minCap1 ++ minCap1 ++ 30 ++ ++ ++ maxCap1 ++ maxCap1 ++ 31 ++ ++ ++ minRes1 ++ minRes1 ++ 32 ++ ++ ++ maxRes1 ++ maxRes1 ++ 33 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to big endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ serdes-type ++ enumeration ++ Serdes Type ++ ++ NA ++ No serdes ++ 0 ++ ++ ++ AVAGO ++ AVAGO ++ 1 ++ ++ ++ COMPHY ++ COMPHY ++ 2 ++ ++ ++ COMPHY_C12G ++ COMPHY_C12G ++ 3 ++ ++ ++ COMPHY_C28G ++ COMPHY_C28G ++ 4 ++ ++ ++ COMPHY_C112G ++ COMPHY_C112G ++ 5 ++ ++ ++ ++ port-interconnect-profile-type ++ enumeration ++ Enumerator of interconnect profile. ++ ++ profile_default ++ Profile Default ++ 0 ++ ++ ++ profile_1 ++ Profile 1 ++ 1 ++ ++ ++ profile_2 ++ Profile 2 ++ 2 ++ ++ ++ ++ ++ ++ 1000MR1 ++ ++ USX_OUSGMII ++ 1G ++ disabled ++ ++ ++ USX_OUSGMII ++ 1G ++ disabled ++ disabled ++ ++ ++ ++ 2500MR1 ++ ++ USX_20G_OXGMII ++ 2500M ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 1G ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 2500M ++ rs_enabled ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 1G ++ rs_enabled ++ rs_enabled ++ ++ ++ ++ 25GR1 ++ ++ SR_LR ++ 25G ++ rs_enabled ++ ++ ++ CR ++ 25G ++ rs_enabled ++ ++ ++ KR ++ 25G ++ rs_enabled ++ ++ ++ SR_LR ++ 10G ++ enabled ++ ++ ++ KR ++ 10G ++ enabled ++ ++ ++ 1000BASE_X ++ 1G ++ ++ ++ CR ++ 25G ++ rs_enabled ++ rs_enabled ++ ++ ++ KR ++ 25G ++ rs_enabled ++ rs_enabled ++ ++ ++ KR ++ 10G ++ enabled ++ enabled ++ ++ ++ 1000BASE_X ++ 1G ++ disabled ++ disabled ++ ++ ++ ++ ++ ++ 0 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 1 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 2 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 3 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 4 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 5 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 6 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 7 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 8 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 9 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 10 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 11 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 12 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 13 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 14 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 15 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 16 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 17 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 18 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 19 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 20 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 21 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 22 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 23 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 24 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 25 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 26 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 27 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 28 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 29 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 30 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 31 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 32 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 33 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 34 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 35 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 36 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 37 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 38 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 39 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 40 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 41 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 42 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 43 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 44 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 45 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 46 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 47 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 48 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 6 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 49 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 7 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 50 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 8 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 51 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 9 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 52 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 10 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 53 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 11 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.md5 b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.md5 +new file mode 100755 +index 000000000..9f71d8823 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.md5 +@@ -0,0 +1 @@ ++80b909e1f812ad0c16aff3b1f13ba696 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.xml b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.xml +new file mode 100755 +index 000000000..85a73f08c +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/ASK-PP-ES1227-54TS.xml +@@ -0,0 +1,891 @@ ++ ++ ++ ++ ++ ++ std-string ++ string ++ standard string. ++ 1 ++ 100 ++ ++ ++ queue-id-type ++ uint32 ++ Queue id ++ 0 ++ 7 ++ ++ ++ precent-type ++ uint32 ++ Precent ++ 0 ++ 100 ++ ++ ++ phaThreadId-type ++ uint32 ++ Thread id ++ 1 ++ 255 ++ ++ ++ routing-mode-type ++ enumeration ++ Specifies routing mode. ++ ++ POLICY_BASED_ROUTING_ONLY ++ PBR only ++ 0 ++ ++ ++ TCAM_ROUTER_BASED ++ Router engine or PBR ++ 1 ++ ++ ++ ++ shared-table-mode-type ++ enumeration ++ Specifies table sharing modes for L3 (LPM), L2 (FDB), EM (Exact Match) ++ ++ MID_L3_MID_L2_NO_EM ++ MID_L3_MID_L2_NO_EM ++ 0 ++ ++ ++ MID_L3_MID_L2_MIN_EM ++ MID_L3_MID_L2_MIN_EM ++ 1 ++ ++ ++ LOW_MAX_L3_MID_LOW_L2_NO_EM ++ LOW_MAX_L3_MID_LOW_L2_NO_EM ++ 2 ++ ++ ++ MAX_L3_MIN_L2_NO_EM ++ MAX_L3_MIN_L2_NO_EM ++ 3 ++ ++ ++ ++ pha-firmware-image-id-type ++ enumeration ++ Specifies supported Pha image id ++ ++ DEFAULT ++ Default PHA firmware image ID ++ 0 ++ ++ ++ 01 ++ 01 firmware image ID ++ 1 ++ ++ ++ 02 ++ 02 PHA firmware image ID ++ 2 ++ ++ ++ ++ pha-firmware-thread-type ++ enumeration ++ Specifies supported Pha thread type ++ ++ IOAM_INGRESS_SWITCH_IPV4 ++ IOAM_INGRESS_SWITCH_IPV4 ++ 1 ++ ++ ++ IOAM_INGRESS_SWITCH_IPV6 ++ IOAM_INGRESS_SWITCH_IPV6 ++ 2 ++ ++ ++ IOAM_TRANSIT_SWITCH_IPV4 ++ IOAM_TRANSIT_SWITCH_IPV4 ++ 3 ++ ++ ++ IOAM_TRANSIT_SWITCH_IPV6 ++ IOAM_TRANSIT_SWITCH_IPV6 ++ 4 ++ ++ ++ INT_IOAM_MIRRORING ++ INT_IOAM_MIRRORING ++ 5 ++ ++ ++ INT_IOAM_EGRESS_SWITCH ++ INT_IOAM_EGRESS_SWITCH ++ 6 ++ ++ ++ MPLS_SR_NO_EL ++ MPLS_SR_NO_EL ++ 7 ++ ++ ++ MPLS_SR_ONE_EL ++ MPLS_SR_ONE_EL ++ 8 ++ ++ ++ MPLS_SR_TWO_EL ++ MPLS_SR_TWO_EL ++ 9 ++ ++ ++ MPLS_SR_THREE_EL ++ MPLS_SR_THREE_EL ++ 10 ++ ++ ++ UNIFIED_SR ++ UNIFIED_SR ++ 11 ++ ++ ++ CLASSIFIER_NSH_OVER_ETHERNET ++ CLASSIFIER_NSH_OVER_ETHERNET ++ 12 ++ ++ ++ CLASSIFIER_NSH_OVER_VXLAN_GPE ++ CLASSIFIER_NSH_OVER_VXLAN_GPE ++ 13 ++ ++ ++ SFF_NSH_VXLAN_GPE_TO_ETHERNET ++ SFF_NSH_VXLAN_GPE_TO_ETHERNET ++ 14 ++ ++ ++ SFF_NSH_ETHERNET_TO_VXLAN_GPE ++ SFF_NSH_ETHERNET_TO_VXLAN_GPE ++ 15 ++ ++ ++ IOAM_EGRESS_SWITCH_IPV6 ++ IOAM_EGRESS_SWITCH_IPV6 ++ 16 ++ ++ ++ SRV6_END_NODE ++ SRV6_END_NODE ++ 17 ++ ++ ++ SRV6_PENULTIMATE_END_NODE ++ SRV6_PENULTIMATE_END_NODE ++ 18 ++ ++ ++ SRV6_SRC_NODE_1_SEGMENT ++ SRV6_SRC_NODE_1_SEGMENT ++ 19 ++ ++ ++ SRV6_SRC_NODE_FIRST_PASS_2_3_SEGMENTS ++ SRV6_SRC_NODE_FIRST_PASS_2_3_SEGMENTS ++ 20 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_3_SEGMENTS ++ SRV6_SRC_NODE_SECOND_PASS_3_SEGMENTS ++ 21 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_2_SEGMENTS ++ SRV6_SRC_NODE_SECOND_PASS_2_SEGMENTS ++ 22 ++ ++ ++ SGT_NETWORK_ADD_MSB ++ SGT_NETWORK_ADD_MSB ++ 23 ++ ++ ++ SGT_NETWORK_FIX ++ SGT_NETWORK_FIX ++ 24 ++ ++ ++ SGT_NETWORK_REMOVE ++ SGT_NETWORK_REMOVE ++ 25 ++ ++ ++ SGT_EDSA_FIX ++ SGT_EDSA_FIX ++ 26 ++ ++ ++ SGT_EDSA_REMOVE ++ SGT_EDSA_REMOVE ++ 27 ++ ++ ++ SGT_GBP_FIX_IPV4 ++ SGT_GBP_FIX_IPV4 ++ 28 ++ ++ ++ SGT_GBP_FIX_IPV6 ++ SGT_GBP_FIX_IPV6 ++ 29 ++ ++ ++ SGT_GBP_REMOVE_IPV4 ++ SGT_GBP_REMOVE_IPV4 ++ 30 ++ ++ ++ SGT_GBP_REMOVE_IPV6 ++ SGT_GBP_REMOVE_IPV6 ++ 31 ++ ++ ++ PTP_PHY_1_STEP ++ PTP_PHY_1_STEP ++ 32 ++ ++ ++ EGRESS_MIRRORING_METADATA ++ EGRESS_MIRRORING_METADATA ++ 33 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV4 ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV4 ++ 34 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV6 ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV6 ++ 35 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV4 ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV4 ++ 36 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV6 ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV6 ++ 37 ++ ++ ++ CC_ERSPAN_TYPE_II_SRC_DEV ++ CC_ERSPAN_TYPE_II_SRC_DEV ++ 38 ++ ++ ++ VXLAN_GBP_SOURCE_GROUP_POLICY_ID ++ VXLAN_GBP_SOURCE_GROUP_POLICY_ID ++ 39 ++ ++ ++ SRV6_BEST_EFFORT ++ SRV6_BEST_EFFORT ++ 40 ++ ++ ++ SRV6_SRC_NODE_1_CONTAINER ++ SRV6_SRC_NODE_1_CONTAINER ++ 41 ++ ++ ++ SRV6_SRC_NODE_FIRST_PASS_2_3_CONTAINERS ++ SRV6_SRC_NODE_FIRST_PASS_2_3_CONTAINERS ++ 42 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_2_CONTAINERS ++ SRV6_SRC_NODE_SECOND_PASS_2_CONTAINERS ++ 43 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_3_CONTAINERS ++ SRV6_SRC_NODE_SECOND_PASS_3_CONTAINERS ++ 44 ++ ++ ++ SRV6_END_NODE_COC32_GSID ++ SRV6_END_NODE_COC32_GSID ++ 45 ++ ++ ++ IPV4_TTL_INCREMENT ++ IPV4_TTL_INCREMENT ++ 46 ++ ++ ++ IPV6_HOP_LIMIT_INCREMENT ++ IPV6_HOP_LIMIT_INCREMENT ++ 47 ++ ++ ++ CLEAR_OUTGOING_MTAG_COMMAND ++ CLEAR_OUTGOING_MTAG_COMMAND ++ 48 ++ ++ ++ SFLOW_V5_IPV4 ++ SFLOW_V5_IPV4 ++ 49 ++ ++ ++ SFLOW_V5_IPV6 ++ SFLOW_V5_IPV6 ++ 50 ++ ++ ++ SLS ++ SLS ++ 51 ++ ++ ++ ++ trunk-member-mode-type ++ enumeration ++ Specifies supported Pha image id ++ ++ NATIVE ++ NATIVE ++* the trunk members are filled ++* according to the order given by application. ++* Regular trunk may hold max of 8 members. ++* Cascade trunk may hold : ++* max of 64 members ++ 0 ++ ++ ++ FLEX ++ FLEX ++* A mode to allows flexibility for ++* each Regular trunk to state it's max number of members (before starting to add members). ++* (this mode not effect 'cascade trunk' members) ++* Regular trunk may hold : max of 4K members. (each trunk set it's own limit) ++* Cascade trunk may hold : max of 64 members. ++ 2 ++ ++ ++ ++ number-physical-port-type ++ enumeration ++ AC3X/AC5X 128, falcon 64, 128, 256, 512, 1024 ++ ++ no-ports ++ no-ports ++ 0 ++ ++ ++ 64-ports ++ 64-ports ++ 64 ++ ++ ++ 128-ports ++ 128-ports ++ 128 ++ ++ ++ 256-ports ++ 256-ports ++ 256 ++ ++ ++ 512-ports ++ 512-ports ++ 512 ++ ++ ++ 1024-ports ++ 1024-ports ++ 1024 ++ ++ ++ ++ serdes-ref-clock-type ++ enumeration ++ Specifies serdes refernce clock. ++ ++ external_25_single_ended ++ EXTERNAL_25_SINGLE_ENDED ++ 0 ++ ++ ++ external_125_single_ended ++ EXTERNAL_125_SINGLE_ENDED ++ 1 ++ ++ ++ external_125_diff ++ EXTERNAL_125_DIFF ++ 2 ++ ++ ++ external_156_25_single_ended ++ EXTERNAL_156_25_SINGLE_ENDED ++ 3 ++ ++ ++ external_156_25_diff ++ EXTERNAL_156_25_DIFF ++ 4 ++ ++ ++ internal_125 ++ INTERNAL_125 ++ 5 ++ ++ ++ ++ cpu-port-id-type ++ uint32 ++ CPU port id ++ 0 ++ 7 ++ ++ ++ rx-buffer-size-type ++ uint32 ++ Rx Buffer size ++ 64 ++ 10240 ++ ++ ++ tx-sdma-queue-mode-type ++ enumeration ++ Specifies TX queue mode. ++ ++ Normal ++ Application ++ 0 ++ ++ ++ Packet_Generator ++ Traffic generator ++ 1 ++ ++ ++ ++ alloc-method-type ++ enumeration ++ Specifies Buffers allocation method. ++ ++ Dynamic_Alloc ++ Dynamic ++ 0 ++ ++ ++ Static_Alloc ++ Static ++ 1 ++ ++ ++ ++ au_mesage_lenght-type ++ enumeration ++ Specifies Buffers allocation method. ++ ++ 4_words ++ 4 Words ++ 0 ++ ++ ++ 8_words ++ 8 Words ++ 1 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ++ AC5X-RD ++ ++ 4294967295 ++ external_25_single_ended ++ 2 ++ 60 ++ 128-ports ++ false ++ false ++ 0 ++ ++ ++ true ++ ++ 4096 ++ ++ ++ 2048 ++ ++ ++ ++ 0 ++ 0 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 7 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 6 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 5 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 4 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 3 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 2 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 1 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 0 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 7 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 6 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 5 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 4 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 3 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 2 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 1 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 0 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 1 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 2 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 3 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 4 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 5 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 6 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 7 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 0 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 1 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 2 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 3 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 4 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 5 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 6 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 7 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ ++ false ++ false ++ false ++ 0 ++ 8_words ++ false ++ ++ ++ ++ TCAM_ROUTER_BASED ++ 0 ++ true ++ ++ ++ true ++ true ++ true ++ true ++ true ++ true ++ ++ 511 ++ FLEX ++ ++ true ++ true ++ true ++ true ++ ++ false ++ 01 ++ 0 ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100755 +index 000000000..46ef35490 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++aed8ffe4d26f6366411562f09695d033 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100755 +index 000000000..a00b5b254 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,511 @@ ++ ++ ++ ++ ++ ++ device-id-type ++ uint32 ++ Device ID 0..1 ++ 0 ++ 1 ++ ++ ++ port-id-type ++ uint32 ++ Interface number ++ 0 ++ 1023 ++ ++ ++ logDest-type ++ enumeration ++ Logging Feature Options ++ ++ SAI_LOG_SYSLOG ++ SYSLOG {Syslog service should be running to use this option} ++ 0 ++ ++ ++ SAI_LOG_CONSOLE ++ CONSOLE ++ 1 ++ ++ ++ SAI_LOG_FILE ++ FILE {Warning !!! Use with caution. Can cause disk full issues} ++ 2 ++ ++ ++ ++ InDropCounter-type ++ enumeration ++ Router In Drop Reason Feature Options ++ ++ TTL_HOPLIMIT_EXCEEDED ++ Router In Drop Counters track TTL & Hop Limit Exceeded Packets ++ 0 ++ ++ ++ ROUTE_BLACKHOLE ++ Router In Drop Counters track Route Black Hole Packets ++ 1 ++ ++ ++ ++ Feature-enable ++ enumeration ++ Feature Enabled/Disabled ++ ++ Disabled ++ Disabled ++ 0 ++ ++ ++ Enabled ++ Enabled ++ 1 ++ ++ ++ ++ log-dest-file-path-type ++ string ++ A string with path to file for logging feature ++ 2 ++ 30 ++ ++ ++ acl-feature-name-type ++ enumeration ++ ++ ++ port-sFlow ++ SFlow over Port ++ 0 ++ ++ ++ port-counters-ipv4-ipv6 ++ Port ipv4/ipv6 counters ++ 1 ++ ++ ++ control-acl ++ ACLs for control packet handling ++ 2 ++ ++ ++ debug-counter-acl ++ ACLs for Debug Counters ++ 3 ++ ++ ++ ++ ingress-acl-stage-type ++ enumeration ++ ++ ++ disabled ++ Feature not enabled ++ 0 ++ ++ ++ IPCL0 ++ Stage IPCL0 ++ 1 ++ ++ ++ IPCL1 ++ Stage IPCL1 ++ 2 ++ ++ ++ ++ egress-acl-stage-type ++ enumeration ++ ++ ++ disabled ++ Feature not enabled ++ 0 ++ ++ ++ EPCL0 ++ Stage EPCL0 ++ 2 ++ ++ ++ ++ feature-priority-type ++ uint32 ++ Feature priority ++ 2 ++ 15 ++ ++ ++ hit-number-type ++ uint32 ++ Hit/lookup number ++ 0 ++ 3 ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++ ++ ++ 0 ++ 0 ++ 0 ++ ++ ++ 1 ++ 0 ++ 1 ++ ++ ++ 2 ++ 0 ++ 2 ++ ++ ++ 3 ++ 0 ++ 3 ++ ++ ++ 4 ++ 0 ++ 4 ++ ++ ++ 5 ++ 0 ++ 5 ++ ++ ++ 6 ++ 0 ++ 6 ++ ++ ++ 7 ++ 0 ++ 7 ++ ++ ++ 8 ++ 0 ++ 8 ++ ++ ++ 9 ++ 0 ++ 9 ++ ++ ++ 10 ++ 0 ++ 10 ++ ++ ++ 11 ++ 0 ++ 11 ++ ++ ++ 12 ++ 0 ++ 12 ++ ++ ++ 13 ++ 0 ++ 13 ++ ++ ++ 14 ++ 0 ++ 14 ++ ++ ++ 15 ++ 0 ++ 15 ++ ++ ++ 16 ++ 0 ++ 16 ++ ++ ++ 17 ++ 0 ++ 17 ++ ++ ++ 18 ++ 0 ++ 18 ++ ++ ++ 19 ++ 0 ++ 19 ++ ++ ++ 20 ++ 0 ++ 20 ++ ++ ++ 21 ++ 0 ++ 21 ++ ++ ++ 22 ++ 0 ++ 22 ++ ++ ++ 23 ++ 0 ++ 23 ++ ++ ++ 24 ++ 0 ++ 24 ++ ++ ++ 25 ++ 0 ++ 25 ++ ++ ++ 26 ++ 0 ++ 26 ++ ++ ++ 27 ++ 0 ++ 27 ++ ++ ++ 28 ++ 0 ++ 28 ++ ++ ++ 29 ++ 0 ++ 29 ++ ++ ++ 30 ++ 0 ++ 30 ++ ++ ++ 31 ++ 0 ++ 31 ++ ++ ++ 32 ++ 0 ++ 32 ++ ++ ++ 33 ++ 0 ++ 33 ++ ++ ++ 34 ++ 0 ++ 34 ++ ++ ++ 35 ++ 0 ++ 35 ++ ++ ++ 36 ++ 0 ++ 36 ++ ++ ++ 37 ++ 0 ++ 37 ++ ++ ++ 38 ++ 0 ++ 38 ++ ++ ++ 39 ++ 0 ++ 39 ++ ++ ++ 40 ++ 0 ++ 40 ++ ++ ++ 41 ++ 0 ++ 41 ++ ++ ++ 42 ++ 0 ++ 42 ++ ++ ++ 43 ++ 0 ++ 43 ++ ++ ++ 44 ++ 0 ++ 44 ++ ++ ++ 45 ++ 0 ++ 45 ++ ++ ++ 46 ++ 0 ++ 46 ++ ++ ++ 47 ++ 0 ++ 47 ++ ++ ++ 48 ++ 0 ++ 48 ++ ++ ++ 49 ++ 0 ++ 49 ++ ++ ++ 50 ++ 0 ++ 50 ++ ++ ++ 51 ++ 0 ++ 51 ++ ++ ++ 52 ++ 0 ++ 52 ++ ++ ++ 53 ++ 0 ++ 53 ++ ++ ++ ++ 8 ++ 0 ++ 0 ++ 64 ++ 8 ++ 8 ++ 1024 ++ ++ ++ 0 ++ ROUTE_BLACKHOLE ++ ++ ++ SAI_LOG_SYSLOG ++ ++ ++ Disabled ++ ++ ++ control-acl ++ 3 ++ ++ IPCL0 ++ 1 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ port-sFlow ++ 4 ++ ++ IPCL0 ++ 0 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ port-counters-ipv4-ipv6 ++ 5 ++ ++ IPCL0 ++ 3 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ debug-counter-acl ++ 2 ++ ++ disabled ++ ++ ++ disabled ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/hwsku.json b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/hwsku.json +new file mode 100644 +index 000000000..0b0014edd +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/hwsku.json +@@ -0,0 +1,322 @@ ++{ ++ "interfaces": { ++ "Ethernet0": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet1": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet2": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet3": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet4": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet5": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet6": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet7": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet8": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet9": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet10": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet11": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet12": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet13": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet14": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet15": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet16": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet17": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet18": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet19": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet20": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet21": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet22": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet23": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet24": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet25": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet26": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet27": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet28": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet29": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet30": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet31": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet32": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet33": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet34": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet35": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet36": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet37": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet38": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet39": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet40": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet41": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet42": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet43": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet44": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet45": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet46": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet47": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet48": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet49": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet50": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet51": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet52": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet53": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/port_config.ini b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/port_config.ini +new file mode 100644 +index 000000000..42593c8e2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/port_config.ini +@@ -0,0 +1,55 @@ ++# name lanes alias speed autoneg fec index poe_pri poe_status poe_maxpower poe_tlv ++Ethernet0 0 Eth1 1000 on none 1 critical enable 0 disable ++Ethernet1 1 Eth2 1000 on none 2 critical enable 0 disable ++Ethernet2 2 Eth3 1000 on none 3 critical enable 0 disable ++Ethernet3 3 Eth4 1000 on none 4 critical enable 0 disable ++Ethernet4 4 Eth5 1000 on none 5 low enable 0 disable ++Ethernet5 5 Eth6 1000 on none 6 low enable 0 disable ++Ethernet6 6 Eth7 1000 on none 7 low enable 0 disable ++Ethernet7 7 Eth8 1000 on none 8 low enable 0 disable ++Ethernet8 8 Eth9 1000 on none 9 low enable 0 disable ++Ethernet9 9 Eth10 1000 on none 10 low enable 0 disable ++Ethernet10 10 Eth11 1000 on none 11 low enable 0 disable ++Ethernet11 11 Eth12 1000 on none 12 low enable 0 disable ++Ethernet12 12 Eth13 1000 on none 13 low enable 0 disable ++Ethernet13 13 Eth14 1000 on none 14 low enable 0 disable ++Ethernet14 14 Eth15 1000 on none 15 low enable 0 disable ++Ethernet15 15 Eth16 1000 on none 16 low enable 0 disable ++Ethernet16 16 Eth17 1000 on none 17 low enable 0 disable ++Ethernet17 17 Eth18 1000 on none 18 low enable 0 disable ++Ethernet18 18 Eth19 1000 on none 19 low enable 0 disable ++Ethernet19 19 Eth20 1000 on none 20 low enable 0 disable ++Ethernet20 20 Eth21 1000 on none 21 low enable 0 disable ++Ethernet21 21 Eth22 1000 on none 22 low enable 0 disable ++Ethernet22 22 Eth23 1000 on none 23 low enable 0 disable ++Ethernet23 23 Eth24 1000 on none 24 low enable 0 disable ++Ethernet24 24 Eth25 1000 on none 25 low enable 0 disable ++Ethernet25 25 Eth26 1000 on none 26 low enable 0 disable ++Ethernet26 26 Eth27 1000 on none 27 low enable 0 disable ++Ethernet27 27 Eth28 1000 on none 28 low enable 0 disable ++Ethernet28 28 Eth29 1000 on none 29 low enable 0 disable ++Ethernet29 29 Eth30 1000 on none 30 low enable 0 disable ++Ethernet30 30 Eth31 1000 on none 31 low enable 0 disable ++Ethernet31 31 Eth32 1000 on none 32 low enable 0 disable ++Ethernet32 32 Eth33 1000 on rs 33 low enable 0 disable ++Ethernet33 33 Eth34 1000 on rs 34 low enable 0 disable ++Ethernet34 34 Eth35 1000 on rs 35 low enable 0 disable ++Ethernet35 35 Eth36 1000 on rs 36 low enable 0 disable ++Ethernet36 36 Eth37 1000 on rs 37 low enable 0 disable ++Ethernet37 37 Eth38 1000 on rs 38 low enable 0 disable ++Ethernet38 38 Eth39 1000 on rs 39 low enable 0 disable ++Ethernet39 39 Eth40 1000 on rs 40 low enable 0 disable ++Ethernet40 40 Eth41 1000 on rs 41 low enable 0 disable ++Ethernet41 41 Eth42 1000 on rs 42 low enable 0 disable ++Ethernet42 42 Eth43 1000 on rs 43 low enable 0 disable ++Ethernet43 43 Eth44 1000 on rs 44 low enable 0 disable ++Ethernet44 44 Eth45 1000 on rs 45 critical enable 0 disable ++Ethernet45 45 Eth46 1000 on rs 46 critical enable 0 disable ++Ethernet46 46 Eth47 1000 on rs 47 critical enable 0 disable ++Ethernet47 47 Eth48 1000 on rs 48 critical enable 0 disable ++Ethernet48 48 Eth49 25000 off none 49 NA NA 0 NA ++Ethernet49 49 Eth50 25000 off none 50 NA NA 0 NA ++Ethernet50 50 Eth51 25000 off none 51 NA NA 0 NA ++Ethernet51 51 Eth52 25000 off none 52 NA NA 0 NA ++Ethernet52 52 Eth53 25000 off none 53 NA NA 0 NA ++Ethernet53 53 Eth54 25000 off none 54 NA NA 0 NA +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/profile.ini b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/profile.ini +new file mode 100644 +index 000000000..c2f77685a +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/profile.ini +@@ -0,0 +1 @@ ++switchMacAddress=00:01:02:03:04:05 +diff --git a/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/sai.profile b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/sai.profile +new file mode 100755 +index 000000000..938b288ad +--- /dev/null ++++ b/device/wistron/arm64-wistron_es1227_54ts-r0/wistron_es1227_54ts/sai.profile +@@ -0,0 +1,4 @@ ++mode=1 ++hwId=AC5XRD ++switchProfile=/usr/share/sonic/hwsku/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/profile.ini +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/default_sku b/device/wistron/arm64-wistron_es2227_54ts-r0/default_sku +new file mode 100644 +index 000000000..281327959 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/default_sku +@@ -0,0 +1 @@ ++wistron_es2227_54ts t1 +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/installer.conf b/device/wistron/arm64-wistron_es2227_54ts-r0/installer.conf +new file mode 100644 +index 000000000..28757b561 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/installer.conf +@@ -0,0 +1 @@ ++ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="default_hugepagesz=2M hugepages=256 pci=noaer" +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/pcie.yaml b/device/wistron/arm64-wistron_es2227_54ts-r0/pcie.yaml +new file mode 100644 +index 000000000..84faf76b2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/pcie.yaml +@@ -0,0 +1,10 @@ ++- bus: '00' ++ dev: '00' ++ fn: '0' ++ id: '0110' ++ name: 'PCI bridge: Marvell Technology Group Ltd. Device 0110' ++- bus: '01' ++ dev: '00' ++ fn: '0' ++ id: '9823' ++ name: 'Ethernet controller: Marvell Technology Group Ltd. Device 9823' +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/platform.json b/device/wistron/arm64-wistron_es2227_54ts-r0/platform.json +new file mode 100644 +index 000000000..2160b59a9 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/platform.json +@@ -0,0 +1,560 @@ ++{ ++ "chassis": { ++ "name": "wistron_es2227_54ts", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "DDR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XFMR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/platform_afi.json b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_afi.json +new file mode 100644 +index 000000000..4b2b632b3 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_afi.json +@@ -0,0 +1,560 @@ ++{ ++ "chassis": { ++ "name": "wistron_es2227_54ts", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "FAN Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "CPU Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/platform_afo.json b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_afo.json +new file mode 100644 +index 000000000..2160b59a9 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_afo.json +@@ -0,0 +1,560 @@ ++{ ++ "chassis": { ++ "name": "wistron_es2227_54ts", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "DDR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XFMR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/platform_asic b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_asic +new file mode 100644 +index 000000000..5cbe9d002 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_asic +@@ -0,0 +1 @@ ++marvell-prestera +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/platform_components.json b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_components.json +new file mode 100644 +index 000000000..5df6f2120 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/platform_components.json +@@ -0,0 +1,11 @@ ++{ ++ "chassis": { ++ "wistron_es2227_54ts": { ++ "component": { ++ "U-Boot": { }, ++ "ONIE-VERSION": { }, ++ "CPLD": { } ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/pmon_daemon_control.json b/device/wistron/arm64-wistron_es2227_54ts-r0/pmon_daemon_control.json +new file mode 100644 +index 000000000..689def2c1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/pmon_daemon_control.json +@@ -0,0 +1,4 @@ ++{ ++ "skip_ledd": true, ++ "skip_pcied": true ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/sensors.conf b/device/wistron/arm64-wistron_es2227_54ts-r0/sensors.conf +new file mode 100755 +index 000000000..9c67f1fa6 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/sensors.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "1227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "wistron_psu-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "wistron_psu-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "XFMR Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "DDR Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "System Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afi.conf b/device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afi.conf +new file mode 100755 +index 000000000..78af494f9 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afi.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "1227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "wistron_psu-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "wistron_psu-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "System Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "FAN Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "CPU Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afo.conf b/device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afo.conf +new file mode 100755 +index 000000000..9c67f1fa6 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/sensors_afo.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "1227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "wistron_psu-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "wistron_psu-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "XFMR Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "DDR Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "System Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/system_health_monitoring_config.json b/device/wistron/arm64-wistron_es2227_54ts-r0/system_health_monitoring_config.json +new file mode 100644 +index 000000000..b6aa813f1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/system_health_monitoring_config.json +@@ -0,0 +1,12 @@ ++{ ++ "services_to_ignore": [], ++ "devices_to_ignore": ["asic"], ++ "user_defined_checkers": [], ++ "polling_interval": 60, ++ "led_color": { ++ "fault": "red", ++ "normal": "green", ++ "booting": "green_blinking" ++ } ++} ++ +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/thermal_policy.json b/device/wistron/arm64-wistron_es2227_54ts-r0/thermal_policy.json +new file mode 100755 +index 000000000..da35ff6d2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/thermal_policy.json +@@ -0,0 +1,110 @@ ++{ ++ "thermal_control_algorithm": { ++ "run_at_boot_up": "false", ++ "interval": "60" ++ }, ++ "info_types": [ ++ { ++ "type": "fan_info" ++ }, ++ { ++ "type": "thermal_info" ++ }, ++ { ++ "type": "chassis_info" ++ } ++ ], ++ "policies": [ ++ { ++ "name": "any fan absence", ++ "conditions": [ ++ { ++ "type": "fan.any.absence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.all.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "all fan presence", ++ "conditions": [ ++ { ++ "type": "fan.all.presence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "any fan new", ++ "conditions": [ ++ { ++ "type": "fan.any.new" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.new.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "all fan absence", ++ "conditions": [ ++ { ++ "type": "fan.all.absence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ }, ++ { ++ "name": "temp over high critical threshold", ++ "conditions": [ ++ { ++ "type": "thermal.over.high_critical_threshold" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ }, ++ { ++ "name": "temp over high threshold", ++ "conditions": [ ++ { ++ "type": "thermal.over.high_threshold" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "high_threshold.control" ++ } ++ ] ++ }, ++ { ++ "name": "temp over threshold after cool down", ++ "conditions": [ ++ { ++ "type": "thermal.over.threshold_after_cool_down" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ } ++ ] ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100644 +index 000000000..66bfd55e3 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++8f1de4b7c3a39dfafa16bf03a194962c +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100644 +index 000000000..a9d9a8f45 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,1825 @@ ++ ++ ++ ++ ++ ++ std-string ++ string ++ standard string. ++ 1 ++ 100 ++ ++ ++ board-callback-type ++ enumeration ++ Specifies os/ext drv callback types. ++ ++ linux-static ++ Linux Static ++ 0 ++ ++ ++ linux-shared ++ Linux Shared Lib mode ++ 1 ++ ++ ++ external ++ External Os ++ 3 ++ ++ ++ freeBsd ++ Free BSD ++ 4 ++ ++ ++ ++ board-pp-map-type ++ enumeration ++ Specifies pci info types. ++ ++ fixed ++ Fixed ++ 0 ++ ++ ++ autoscan ++ Auto scan ++ 1 ++ ++ ++ ++ board-pp-interface-channel-type ++ enumeration ++ Specifies channel interface type. ++ ++ pci ++ PCI ++ 0 ++ ++ ++ smi ++ SMI ++ 1 ++ ++ ++ twsi ++ TWSI ++ 2 ++ ++ ++ ++ board-pp-as-type ++ enumeration ++ Specifies Address space type. ++ ++ 4_regions ++ address-space 4 regions ++ 0 ++ ++ ++ 8_regions ++ address-space 8 regions ++ 1 ++ ++ ++ atu ++ address translation unit ++ 2 ++ ++ ++ ++ device-id-type ++ uint32 ++ Device ID 0..1 ++ 0 ++ 1 ++ ++ ++ port-mapping-type ++ enumeration ++ Specifies port map type. ++ ++ ethernet_mac ++ ETHERNET_MAC ++ 0 ++ ++ ++ cpu_sdma ++ CPU_SDMA ++ 1 ++ ++ ++ ++ interface-num-type ++ uint32 ++ Interface number ++ 0 ++ 1023 ++ ++ ++ txq-port-number-type ++ uint32 ++ TXq port number ++ 0 ++ 99 ++ ++ ++ phy-smi-interface-type ++ uint32 ++ Phy SMI interface type. ++ 0 ++ 3 ++ ++ ++ phy-xsmi-interface-type ++ uint32 ++ Phy XSMI interface type. ++ 0 ++ 15 ++ ++ ++ phy-type ++ enumeration ++ Specifies the PHY Part Identifier. ++ ++ NA ++ No Phy ++ 0 ++ ++ ++ alaska-88E1543 ++ Specifies PHY identifier 88E1543, used for Combo ports. ++ 1 ++ ++ ++ alaska-88E1545 ++ Specifies PHY identifier 88E1545, used for Copper GE with MAC on PHY support. ++ 2 ++ ++ ++ alaska-88E1680 ++ Specifies PHY identifier 88E1680, used for Copper with speeds of 10M/100M/1G. ++ 3 ++ ++ ++ alaska-88E151X ++ Specifies PHY identifier 88E151X, used for Copper (HW supports combo and fiber). ++ 4 ++ ++ ++ alaska-88E3140 ++ Specifies PHY identifier 88E3140, used for Copper with speeds of 100M/1G/10G. ++Uses with FW SolarFlare next generation. ++ 5 ++ ++ ++ alaska-88E3240 ++ Specifies PHY identifier 88E3240, used for Copper with speeds of 100M/1G/10G. ++Uses with FW, SolarFlare next generation. ++ 6 ++ ++ ++ alaska-88E3680 ++ Specifies PHY identifier 88E3680, used for Octal Copper 100M. ++ 7 ++ ++ ++ alaska-88E3220 ++ Specifies PHY identifier 88E3220, used for Combo port with speeds of 100M/1G/10G. ++Uses FW, SolarFlare next generation. ++ 8 ++ ++ ++ alaska-88E1680L ++ Specifies PHY identifier 88E1680L, used for Copper with speeds of 10M/100M/1G. ++ 9 ++ ++ ++ alaska-88E33X0 ++ Specifies PHY identifier 88E33X0, used for MGIG Combo. ++ 10 ++ ++ ++ alaska-88E1548 ++ Specifies PHY identifier 88E1548, used for Fiber GE. ++ 11 ++ ++ ++ alaska-88E20X0 ++ Specifies PHY identifier 88E20X0, used for Copper with speeds of 10M/100M/1G/2.5G/5G. ++ 12 ++ ++ ++ alaska-88E1512 ++ Specifies PHY identifier 88E1512, used for Copper with speeds of 10M/100M/1G. ++ 13 ++ ++ ++ alaska-88E2180 ++ Specifies PHY identifier 88E2180, used for Copper with speeds of 10M/100M/1G/2.5G/5G. ++ 14 ++ ++ ++ alaska-88E1780 ++ Specifies PHY identifier 88E1780, Integrated Octal 10/100/1000 Mbps Energy ++Efficient Ethernet Transceiver ++ 15 ++ ++ ++ alaska-88E2540 ++ Specifies PHY identifier 88E2540, 4 ports 10/100/1000/2.5G/5GBASE-T Ethernet ++Transceiver with IEEE 1588v2 PTP Support ++ 16 ++ ++ ++ alaska-88E2580 ++ Specifies PHY identifier 88E12580, Octal 10/100/1000/2.5G/5GBASE-T Ethernet Transceiver ++with IEEE 1588v2 PTP Support ++ 17 ++ ++ ++ ++ physical-port-num-type ++ uint32 ++ PHYSICAL PORT NUM ++ 0 ++ 1023 ++ ++ ++ led-stream-port-type ++ enumeration ++ Specifies the ledstream port type. ++ ++ PORT_TYPE_TRI_SPEED ++ tri-speed port. ++ 1 ++ ++ ++ PORT_TYPE_XG ++ XG port. ++ 2 ++ ++ ++ ++ led-stream-blink-select-type ++ enumeration ++ Specifies the LED stream blink select type. ++ ++ BLINK_SELECT_0 ++ Blink 0 signal. ++ 1 ++ ++ ++ BLINK_SELECT_1 ++ Blink 1 signal ++ 2 ++ ++ ++ ++ led-stream-order-mode-type ++ enumeration ++ Specifies the LED stream ordering mode. ++ ++ ORDER_MODE_BY_PORT ++ the indication order is arranged by port. ++ 1 ++ ++ ++ ORDER_MODE_BY_CLASS ++ the indication order is arranged by class. ++ 2 ++ ++ ++ ++ led-stream-blink-duty-cycle-type ++ enumeration ++ Specifies the LED stream blink cycle duty cycle type. ++ ++ BLINK_DUTY_CYCLE_0 ++ 25% on, 75% off. ++ 1 ++ ++ ++ BLINK_DUTY_CYCLE_1 ++ 50% on, 50% off. ++ 2 ++ ++ ++ BLINK_DUTY_CYCLE_2 ++ 50% on, 50% off. ++ 3 ++ ++ ++ BLINK_DUTY_CYCLE_3 ++ 75% on, 25% off. ++ 4 ++ ++ ++ ++ led-stream-blink-duration-type ++ enumeration ++ Specifies the LED stream blink period type. ++ ++ BLINK_DURATION_0 ++ BLINK_DURATION_0. ++ 1 ++ ++ ++ BLINK_DURATION_1 ++ BLINK_DURATION_1. ++ 2 ++ ++ ++ BLINK_DURATION_2 ++ BLINK_DURATION_2. ++ 3 ++ ++ ++ BLINK_DURATION_3 ++ BLINK_DURATION_3. ++ 4 ++ ++ ++ BLINK_DURATION_4 ++ BLINK_DURATION_4. ++ 5 ++ ++ ++ BLINK_DURATION_5 ++ BLINK_DURATION_5. ++ 6 ++ ++ ++ BLINK_DURATION_6 ++ (APPLICABLE DEVICES: xCat3; AC5; Lion2; Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Pipe) . ++ 7 ++ ++ ++ BLINK_DURATION_7 ++ APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Pipe). ++ 8 ++ ++ ++ ++ led-stream-pulse-stretch-type ++ enumeration ++ Specifies the LED stream length of stretching for dynamic signals. ++ ++ PULSE_STRETCH_0_NO ++ PULSE_STRETCH_0_NO. ++ 1 ++ ++ ++ PULSE_STRETCH_1 ++ PULSE_STRETCH_1. ++ 2 ++ ++ ++ PULSE_STRETCH_2 ++ PULSE_STRETCH_2. ++ 3 ++ ++ ++ PULSE_STRETCH_3 ++ PULSE_STRETCH_3. ++ 4 ++ ++ ++ PULSE_STRETCH_4 ++ PULSE_STRETCH_4. ++ 5 ++ ++ ++ PULSE_STRETCH_5 ++ PULSE_STRETCH_5. ++ 6 ++ ++ ++ PULSE_STRETCH_6 ++ (APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Falcon; AC5P; Pipe). ++ 7 ++ ++ ++ PULSE_STRETCH_7 ++ (APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Falcon; AC5P; Pipe). ++ 8 ++ ++ ++ ++ led-stream-clock-out-frequency-type ++ enumeration ++ Specifies the LED stream blink cycle duty cycle type. ++ ++ _CLOCK_OUT_FREQUENCY_500 ++ 500 KHz LED clock frequency. ++ 1 ++ ++ ++ CLOCK_OUT_FREQUENCY_1000 ++ 1 MHz LED clock frequency. ++ 2 ++ ++ ++ CLOCK_OUT_FREQUENCY_2000 ++ 2 MHz LED clock frequency. ++ 3 ++ ++ ++ CLOCK_OUT_FREQUENCY_3000 ++ 3 MHz LED clock frequency. ++ 4 ++ ++ ++ ++ led-stream-class5-select-type ++ enumeration ++ Specifies the LED stream indication displayed on class5 (for dual-media port/phy). ++ ++ CLASS_5_SELECT_HALF_DUPLEX ++ Half Duplex is displayed on class5. ++ 1 ++ ++ ++ CLASS_5_SELECT_FIBER_LINK_UP ++ If port is a dual media port, Fiber Link Up is displayed on class5. ++ 2 ++ ++ ++ ++ led-stream-class13-select-type ++ enumeration ++ Specifies the LED stream indication displayed on class13 (for dual-media port/phy). ++ ++ CLASS_13_SELECT_LINK_DOWN ++ Link Down is displayed on class13. ++ 1 ++ ++ ++ CLASS_13_SELECT_COPPER_LINK_UP ++ If port is a dual media port, Copper Link Up is displayed on class13. ++ 2 ++ ++ ++ ++ led-class-num-type ++ uint32 ++ Led Class number ++ 0 ++ 11 ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ bus-id-type ++ uint32 ++ Bus Id Type, PCI/SMI ++ 0 ++ 255 ++ ++ ++ function-id-type ++ uint32 ++ Function Id Type, PCI/SMI ++ 0 ++ 255 ++ ++ ++ domain-type ++ uint32 ++ Domain, PCI/SMI ++ 0 ++ 255 ++ ++ ++ led-interface-type ++ uint32 ++ Led interface ++ 0 ++ 255 ++ ++ ++ led-position-type ++ uint32 ++ Led position ++ 0 ++ 63 ++ ++ ++ serdes-lane-type ++ uint32 ++ serdes lane ++ 0 ++ 7 ++ ++ ++ cpu-type ++ enumeration ++ The CPU Internal/External ++ ++ external ++ Extrenal connected CPU ++ 0 ++ ++ ++ internal ++ Internal CPU ++ 1 ++ ++ ++ ++ led-stream-clock-frequency-type ++ uint32 ++ Led Clock Frequency Sip6 ++ 500 ++ 80000 ++ ++ ++ led-unit-type ++ uint32 ++ Led units ++ 1 ++ 16 ++ ++ ++ led-unit-or-no-unit-type ++ uint32 ++ Led units, 0 for no Unit ++ 0 ++ 16 ++ ++ ++ led-group-type ++ uint32 ++ Led Group ++ 0 ++ 1 ++ ++ ++ led-stream-force-data-type ++ string ++ A hexadecimal string with octets represented as hex digits ++separated by colons. The canonical representation uses ++lowercase characters. ++ 3 ++ 11 ++ ++ ++ bit-type ++ uint32 ++ Bit range 0..31 ++ 0 ++ 31 ++ ++ ++ bit-size-type ++ uint32 ++ Bit leng 1..32 ++ 1 ++ 32 ++ ++ ++ led-sip-type ++ enumeration ++ The LED scehme ++ ++ na ++ NA ++ 0 ++ ++ ++ sip5 ++ SIP5: AC3x ++ 5 ++ ++ ++ sip6 ++ SIP6: Falcon, AC5x ++ 6 ++ ++ ++ ++ port-cscd-type ++ enumeration ++ Specifies the cascade port type. ++ ++ DSA_1_WORD ++ DSA Regular ++ 0 ++ ++ ++ DSA_2_WORDS ++ DSA Extended ++ 1 ++ ++ ++ NETWORK ++ Network. ++ 2 ++ ++ ++ DSA_3_WORDS ++ DSA 3 Words ++ 3 ++ ++ ++ DSA_4_WORD ++ DSA 4 Words ++ 4 ++ ++ ++ ++ trunk-cscd-type ++ uint32 ++ Specifies the Cascade Trunk id. ++ 0 ++ 127 ++ ++ ++ port-trunk-cscd-type ++ enumeration ++ Specifies the cascade port type. ++ ++ cscdPort ++ Cascade port ++ 0 ++ ++ ++ cscdTrunk ++ Csacde trunk ++ 1 ++ ++ ++ ++ hash-cscd-type ++ enumeration ++ Specifies the hash used by cascade trunk. ++ ++ pkt ++ Hash based on packet ++ 0 ++ ++ ++ srcPort ++ Hash based on source port ++ 1 ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ES1227-54TS-32x1G-16x2.5G-6x25G ++ linux-static ++ linux-static ++ autoscan ++ external ++ pci ++ atu ++ ++ 0 ++ 0 ++ ASK-PP-ES1227-54TS.xml ++ ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++ sip6 ++ ++ 0 ++ ++ ethernet_mac ++ 0 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 0 ++ 0 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 1 ++ ++ ethernet_mac ++ 1 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 1 ++ 0 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 2 ++ ++ ethernet_mac ++ 2 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 2 ++ 0 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 3 ++ ++ ethernet_mac ++ 3 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 3 ++ 0 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 4 ++ ++ ethernet_mac ++ 4 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 4 ++ 0 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 5 ++ ++ ethernet_mac ++ 5 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 5 ++ 0 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 6 ++ ++ ethernet_mac ++ 6 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 6 ++ 0 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 7 ++ ++ ethernet_mac ++ 7 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 7 ++ 0 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 8 ++ ++ ethernet_mac ++ 8 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 8 ++ 0 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 9 ++ ++ ethernet_mac ++ 9 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 9 ++ 0 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 10 ++ ++ ethernet_mac ++ 10 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 10 ++ 0 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 11 ++ ++ ethernet_mac ++ 11 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 11 ++ 0 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 12 ++ ++ ethernet_mac ++ 12 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 12 ++ 0 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 13 ++ ++ ethernet_mac ++ 13 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 13 ++ 0 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 14 ++ ++ ethernet_mac ++ 14 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 14 ++ 0 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 15 ++ ++ ethernet_mac ++ 15 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 15 ++ 0 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 16 ++ ++ ethernet_mac ++ 16 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 16 ++ 0 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 17 ++ ++ ethernet_mac ++ 17 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 17 ++ 0 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 18 ++ ++ ethernet_mac ++ 18 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 18 ++ 0 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 19 ++ ++ ethernet_mac ++ 19 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 19 ++ 0 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 20 ++ ++ ethernet_mac ++ 20 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 20 ++ 0 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 21 ++ ++ ethernet_mac ++ 21 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 21 ++ 0 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 22 ++ ++ ethernet_mac ++ 22 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 22 ++ 0 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 23 ++ ++ ethernet_mac ++ 23 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 23 ++ 0 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 24 ++ ++ ethernet_mac ++ 24 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 24 ++ 0 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 25 ++ ++ ethernet_mac ++ 25 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 25 ++ 0 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 26 ++ ++ ethernet_mac ++ 26 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 26 ++ 0 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 27 ++ ++ ethernet_mac ++ 27 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 27 ++ 0 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 28 ++ ++ ethernet_mac ++ 28 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 28 ++ 0 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 29 ++ ++ ethernet_mac ++ 29 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 29 ++ 0 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 30 ++ ++ ethernet_mac ++ 30 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 30 ++ 0 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 31 ++ ++ ethernet_mac ++ 31 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 31 ++ 0 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 32 ++ ++ ethernet_mac ++ 33 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 1 ++ 1 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 33 ++ ++ ethernet_mac ++ 32 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 0 ++ 1 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 34 ++ ++ ethernet_mac ++ 35 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 3 ++ 1 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 35 ++ ++ ethernet_mac ++ 34 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 2 ++ 1 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 36 ++ ++ ethernet_mac ++ 37 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 5 ++ 1 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 37 ++ ++ ethernet_mac ++ 36 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 4 ++ 1 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 38 ++ ++ ethernet_mac ++ 39 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 7 ++ 1 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 39 ++ ++ ethernet_mac ++ 38 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 6 ++ 1 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 40 ++ ++ ethernet_mac ++ 41 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 9 ++ 1 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 41 ++ ++ ethernet_mac ++ 40 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 8 ++ 1 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 42 ++ ++ ethernet_mac ++ 43 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 11 ++ 1 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 43 ++ ++ ethernet_mac ++ 42 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 10 ++ 1 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 44 ++ ++ ethernet_mac ++ 45 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 13 ++ 1 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 45 ++ ++ ethernet_mac ++ 44 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 12 ++ 1 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 46 ++ ++ ethernet_mac ++ 47 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 15 ++ 1 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 47 ++ ++ ethernet_mac ++ 46 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 14 ++ 1 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 48 ++ ++ ethernet_mac ++ 49 ++ false ++ ++ ++ NA ++ ++ ++ 1 ++ false ++ ++ ++ ++ 49 ++ ++ ethernet_mac ++ 48 ++ false ++ ++ ++ NA ++ ++ ++ 0 ++ false ++ ++ ++ ++ 50 ++ ++ ethernet_mac ++ 51 ++ false ++ ++ ++ NA ++ ++ ++ 1 ++ false ++ ++ ++ ++ 51 ++ ++ ethernet_mac ++ 50 ++ false ++ ++ ++ NA ++ ++ ++ 0 ++ false ++ ++ ++ ++ 52 ++ ++ ethernet_mac ++ 53 ++ false ++ ++ ++ NA ++ ++ ++ 3 ++ false ++ ++ ++ ++ 53 ++ ++ ethernet_mac ++ 52 ++ false ++ ++ ++ NA ++ ++ ++ 2 ++ false ++ ++ ++ ++ 60 ++ ++ cpu_sdma ++ 55 ++ false ++ ++ ++ ++ 63 ++ ++ cpu_sdma ++ 54 ++ false ++ ++ ++ ++ 0 ++ false ++ false ++ ++ ++ 1 ++ false ++ false ++ ++ ++ 2 ++ false ++ false ++ ++ ++ 3 ++ false ++ false ++ ++ ++ 4 ++ false ++ false ++ ++ ++ 5 ++ false ++ false ++ ++ ++ 6 ++ false ++ false ++ ++ ++ 7 ++ false ++ false ++ ++ ++ 8 ++ false ++ false ++ ++ ++ 9 ++ false ++ false ++ ++ ++ 10 ++ false ++ false ++ ++ ++ 11 ++ false ++ false ++ ++ ++ 0 ++ ++ ORDER_MODE_BY_CLASS ++ BLINK_DUTY_CYCLE_1 ++ BLINK_DURATION_0 ++ BLINK_DUTY_CYCLE_1 ++ BLINK_DURATION_0 ++ PULSE_STRETCH_1 ++ false ++ 1627 ++ false ++ ++ 1 ++ 0 ++ 95 ++ false ++ ++ ++ 2 ++ 0 ++ 95 ++ false ++ ++ ++ 3 ++ 0 ++ 95 ++ false ++ ++ ++ 4 ++ 0 ++ 95 ++ false ++ ++ ++ 5 ++ 0 ++ 95 ++ false ++ ++ ++ ++ 0 ++ PORT_TYPE_XG ++ false ++ BLINK_SELECT_0 ++ true ++ 0xffffffff ++ false ++ false ++ ++ ++ 1 ++ PORT_TYPE_XG ++ false ++ BLINK_SELECT_0 ++ false ++ false ++ false ++ ++ ++ 2 ++ PORT_TYPE_XG ++ true ++ BLINK_SELECT_0 ++ false ++ true ++ true ++ ++ ++ ++ . ++ ++ 1 ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100644 +index 000000000..e473ecc38 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++936ee72e62232a32ba78351b17a67321 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100644 +index 000000000..7590d96b4 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,1215 @@ ++ ++ ++ ++ ++ ++ interface-mode-type ++ enumeration ++ Specifies supported Interface modes ++ ++ 1000BASE_X ++ 1G ++ 6 ++ ++ ++ SGMII ++ 1G , 2.5G ++ 3 ++ ++ ++ QSGMII ++ 1G ++ 13 ++ ++ ++ KR ++ 10G, 12G, 20G, 40G, 100G ++ 16 ++ ++ ++ SR_LR ++ 5G, 10G, 12G, 20G, 40G ++ 20 ++ ++ ++ KR2 ++ ++ 27 ++ ++ ++ KR4 ++ ++ 28 ++ ++ ++ SR_LR2 ++ ++ 29 ++ ++ ++ SR_LR4 ++ 100G ++ 30 ++ ++ ++ KR_C ++ CONSORTIUM - 25G ++ 32 ++ ++ ++ CR_C ++ CONSORTIUM - 25G ++ 33 ++ ++ ++ KR2_C ++ CONSORTIUM - 50G ++ 34 ++ ++ ++ CR2_C ++ CONSORTIUM - 50G ++ 35 ++ ++ ++ CR ++ ++ 36 ++ ++ ++ CR2 ++ ++ 37 ++ ++ ++ CR4 ++ ++ 38 ++ ++ ++ KR_S ++ ++ 39 ++ ++ ++ CR_S ++ ++ 40 ++ ++ ++ KR8 ++ ++ 41 ++ ++ ++ CR8 ++ ++ 42 ++ ++ ++ SR_LR8 ++ ++ 43 ++ ++ ++ USX_10G_QXGMII ++ ++ 51 ++ ++ ++ USX_20G_QXGMII ++ ++ 52 ++ ++ ++ USX_OUSGMII ++ ++ 53 ++ ++ ++ USX_20G_OXGMII ++ ++ 54 ++ ++ ++ NA ++ ++ 57 ++ ++ ++ ++ port-speed-type ++ enumeration ++ Specifies supported speeds ++ ++ 1G ++ 1G ++ 2 ++ ++ ++ 10G ++ 10G ++ 3 ++ ++ ++ 2500M ++ 2.5G ++ 5 ++ ++ ++ 5G ++ 5G ++ 6 ++ ++ ++ 25G ++ 25G, used in combination with CPSS_PORT_INTERFACE_MODE_KR_E, CPSS_PORT_INTERFACE_MODE_KR2_E ++ 21 ++ ++ ++ 40G ++ 40G ++ 9 ++ ++ ++ 50G ++ 50G ++ 14 ++ ++ ++ 100G ++ 100G ++ 13 ++ ++ ++ 200G ++ 200G ++ 24 ++ ++ ++ 400G ++ 400G ++ 25 ++ ++ ++ NA ++ NA ++ 35 ++ ++ ++ ++ fec-type ++ enumeration ++ Rx parameter type ++ ++ enabled ++ Enabled ++ 0 ++ ++ ++ disabled ++ Disabled ++ 1 ++ ++ ++ rs_enabled ++ RS FEC enabled ++ 2 ++ ++ ++ both_enabled ++ Both enabled ++ 3 ++ ++ ++ rs_544_514_enabled ++ RS FEC 544 and 514 ++ 4 ++ ++ ++ ++ physical-port-num-type ++ uint32 ++ PHYSICAL PORT NUM ++ 0 ++ 1023 ++ ++ ++ tx-param-type ++ enumeration ++ Tx parameter type ++ ++ pre ++ pre ++ 0 ++ ++ ++ post ++ post ++ 1 ++ ++ ++ peak ++ peak ++ 2 ++ ++ ++ ++ rx-param-type ++ enumeration ++ Rx parameter type ++ ++ dataRate ++ dataRate ++ 0 ++ ++ ++ res1Sel ++ res1Sel ++ 1 ++ ++ ++ res2Sel ++ res2Sel ++ 2 ++ ++ ++ cap1Sel ++ cap1Sel ++ 3 ++ ++ ++ cap2Sel ++ cap2Sel ++ 4 ++ ++ ++ minCap ++ minCap ++ 5 ++ ++ ++ minCapN ++ minCapN ++ 6 ++ ++ ++ sumfBoostTargetC0 ++ sumfBoostTargetC0 ++ 7 ++ ++ ++ sumfBoostTargetC1 ++ sumfBoostTargetC1 ++ 8 ++ ++ ++ sumfBoostTargetC2 ++ sumfBoostTargetC2 ++ 9 ++ ++ ++ midpointPhaseOs0 ++ midpointPhaseOs0 ++ 10 ++ ++ ++ midpointPhaseOs1 ++ midpointPhaseOs1 ++ 11 ++ ++ ++ midpointPhaseOs2 ++ midpointPhaseOs2 ++ 12 ++ ++ ++ selmufi ++ selmufi ++ 13 ++ ++ ++ selmuff ++ selmuff ++ 14 ++ ++ ++ selmupi ++ selmupi ++ 15 ++ ++ ++ selmupf ++ selmupf ++ 16 ++ ++ ++ midpointLargeThresKLane ++ midpointLargeThresKLane ++ 17 ++ ++ ++ midpointSmallThresKLane ++ midpointSmallThresKLane ++ 18 ++ ++ ++ midpointLargeThresCLane ++ midpointLargeThresCLane ++ 19 ++ ++ ++ midpointSmallThresCLane ++ midpointSmallThresCLane ++ 20 ++ ++ ++ inxSumfMidpointAdatptiveEnLane ++ inxSumfMidpointAdatptiveEnLane ++ 21 ++ ++ ++ dfeResF0aHighThresInitLane ++ dfeResF0aHighThresInitLane ++ 22 ++ ++ ++ dfeResF0aHighThresEndLane ++ dfeResF0aHighThresEndLane ++ 23 ++ ++ ++ squelch ++ squelch ++ 24 ++ ++ ++ align90 ++ align90 ++ 25 ++ ++ ++ sampler ++ sampler ++ 26 ++ ++ ++ slewRateCtrl0 ++ slewRateCtrl0 ++ 27 ++ ++ ++ slewRateCtrl1 ++ slewRateCtrl1 ++ 28 ++ ++ ++ EO ++ EO ++ 29 ++ ++ ++ minCap1 ++ minCap1 ++ 30 ++ ++ ++ maxCap1 ++ maxCap1 ++ 31 ++ ++ ++ minRes1 ++ minRes1 ++ 32 ++ ++ ++ maxRes1 ++ maxRes1 ++ 33 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to big endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ serdes-type ++ enumeration ++ Serdes Type ++ ++ NA ++ No serdes ++ 0 ++ ++ ++ AVAGO ++ AVAGO ++ 1 ++ ++ ++ COMPHY ++ COMPHY ++ 2 ++ ++ ++ COMPHY_C12G ++ COMPHY_C12G ++ 3 ++ ++ ++ COMPHY_C28G ++ COMPHY_C28G ++ 4 ++ ++ ++ COMPHY_C112G ++ COMPHY_C112G ++ 5 ++ ++ ++ ++ port-interconnect-profile-type ++ enumeration ++ Enumerator of interconnect profile. ++ ++ profile_default ++ Profile Default ++ 0 ++ ++ ++ profile_1 ++ Profile 1 ++ 1 ++ ++ ++ profile_2 ++ Profile 2 ++ 2 ++ ++ ++ ++ ++ ++ 1000MR1 ++ ++ USX_OUSGMII ++ 1G ++ disabled ++ ++ ++ USX_OUSGMII ++ 1G ++ disabled ++ disabled ++ ++ ++ ++ 2500MR1 ++ ++ USX_20G_OXGMII ++ 2500M ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 1G ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 2500M ++ rs_enabled ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 1G ++ rs_enabled ++ rs_enabled ++ ++ ++ ++ 25GR1 ++ ++ SR_LR ++ 25G ++ rs_enabled ++ ++ ++ CR ++ 25G ++ rs_enabled ++ ++ ++ KR ++ 25G ++ rs_enabled ++ ++ ++ SR_LR ++ 10G ++ enabled ++ ++ ++ KR ++ 10G ++ enabled ++ ++ ++ 1000BASE_X ++ 1G ++ ++ ++ CR ++ 25G ++ rs_enabled ++ rs_enabled ++ ++ ++ KR ++ 25G ++ rs_enabled ++ rs_enabled ++ ++ ++ KR ++ 10G ++ enabled ++ enabled ++ ++ ++ 1000BASE_X ++ 1G ++ disabled ++ disabled ++ ++ ++ ++ ++ ++ 0 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 1 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 2 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 3 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 4 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 5 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 6 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 7 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ ++ ++ 8 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 9 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 10 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 11 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 12 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 13 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 14 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 15 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ ++ ++ 16 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 17 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 18 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 19 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 20 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 21 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 22 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 23 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ ++ ++ 24 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 25 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 26 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 27 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 28 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 29 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 30 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 31 ++ COMPHY_C28G ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ ++ ++ 32 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 33 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 34 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 35 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 36 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 37 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 38 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 39 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ ++ ++ 40 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 41 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 42 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 43 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 44 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 45 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 46 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 47 ++ COMPHY_C28G ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ ++ ++ 48 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 6 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 49 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 7 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 50 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 8 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 51 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 9 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 52 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 10 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ 53 ++ COMPHY_C28G ++ profile_default ++ 25GR1 ++ false ++ ++ 11 ++ ++ pre ++ 8 ++ ++ ++ peak ++ 8 ++ ++ ++ post ++ 2 ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.md5 b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.md5 +new file mode 100755 +index 000000000..9f71d8823 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.md5 +@@ -0,0 +1 @@ ++80b909e1f812ad0c16aff3b1f13ba696 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.xml b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.xml +new file mode 100755 +index 000000000..85a73f08c +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/ASK-PP-ES1227-54TS.xml +@@ -0,0 +1,891 @@ ++ ++ ++ ++ ++ ++ std-string ++ string ++ standard string. ++ 1 ++ 100 ++ ++ ++ queue-id-type ++ uint32 ++ Queue id ++ 0 ++ 7 ++ ++ ++ precent-type ++ uint32 ++ Precent ++ 0 ++ 100 ++ ++ ++ phaThreadId-type ++ uint32 ++ Thread id ++ 1 ++ 255 ++ ++ ++ routing-mode-type ++ enumeration ++ Specifies routing mode. ++ ++ POLICY_BASED_ROUTING_ONLY ++ PBR only ++ 0 ++ ++ ++ TCAM_ROUTER_BASED ++ Router engine or PBR ++ 1 ++ ++ ++ ++ shared-table-mode-type ++ enumeration ++ Specifies table sharing modes for L3 (LPM), L2 (FDB), EM (Exact Match) ++ ++ MID_L3_MID_L2_NO_EM ++ MID_L3_MID_L2_NO_EM ++ 0 ++ ++ ++ MID_L3_MID_L2_MIN_EM ++ MID_L3_MID_L2_MIN_EM ++ 1 ++ ++ ++ LOW_MAX_L3_MID_LOW_L2_NO_EM ++ LOW_MAX_L3_MID_LOW_L2_NO_EM ++ 2 ++ ++ ++ MAX_L3_MIN_L2_NO_EM ++ MAX_L3_MIN_L2_NO_EM ++ 3 ++ ++ ++ ++ pha-firmware-image-id-type ++ enumeration ++ Specifies supported Pha image id ++ ++ DEFAULT ++ Default PHA firmware image ID ++ 0 ++ ++ ++ 01 ++ 01 firmware image ID ++ 1 ++ ++ ++ 02 ++ 02 PHA firmware image ID ++ 2 ++ ++ ++ ++ pha-firmware-thread-type ++ enumeration ++ Specifies supported Pha thread type ++ ++ IOAM_INGRESS_SWITCH_IPV4 ++ IOAM_INGRESS_SWITCH_IPV4 ++ 1 ++ ++ ++ IOAM_INGRESS_SWITCH_IPV6 ++ IOAM_INGRESS_SWITCH_IPV6 ++ 2 ++ ++ ++ IOAM_TRANSIT_SWITCH_IPV4 ++ IOAM_TRANSIT_SWITCH_IPV4 ++ 3 ++ ++ ++ IOAM_TRANSIT_SWITCH_IPV6 ++ IOAM_TRANSIT_SWITCH_IPV6 ++ 4 ++ ++ ++ INT_IOAM_MIRRORING ++ INT_IOAM_MIRRORING ++ 5 ++ ++ ++ INT_IOAM_EGRESS_SWITCH ++ INT_IOAM_EGRESS_SWITCH ++ 6 ++ ++ ++ MPLS_SR_NO_EL ++ MPLS_SR_NO_EL ++ 7 ++ ++ ++ MPLS_SR_ONE_EL ++ MPLS_SR_ONE_EL ++ 8 ++ ++ ++ MPLS_SR_TWO_EL ++ MPLS_SR_TWO_EL ++ 9 ++ ++ ++ MPLS_SR_THREE_EL ++ MPLS_SR_THREE_EL ++ 10 ++ ++ ++ UNIFIED_SR ++ UNIFIED_SR ++ 11 ++ ++ ++ CLASSIFIER_NSH_OVER_ETHERNET ++ CLASSIFIER_NSH_OVER_ETHERNET ++ 12 ++ ++ ++ CLASSIFIER_NSH_OVER_VXLAN_GPE ++ CLASSIFIER_NSH_OVER_VXLAN_GPE ++ 13 ++ ++ ++ SFF_NSH_VXLAN_GPE_TO_ETHERNET ++ SFF_NSH_VXLAN_GPE_TO_ETHERNET ++ 14 ++ ++ ++ SFF_NSH_ETHERNET_TO_VXLAN_GPE ++ SFF_NSH_ETHERNET_TO_VXLAN_GPE ++ 15 ++ ++ ++ IOAM_EGRESS_SWITCH_IPV6 ++ IOAM_EGRESS_SWITCH_IPV6 ++ 16 ++ ++ ++ SRV6_END_NODE ++ SRV6_END_NODE ++ 17 ++ ++ ++ SRV6_PENULTIMATE_END_NODE ++ SRV6_PENULTIMATE_END_NODE ++ 18 ++ ++ ++ SRV6_SRC_NODE_1_SEGMENT ++ SRV6_SRC_NODE_1_SEGMENT ++ 19 ++ ++ ++ SRV6_SRC_NODE_FIRST_PASS_2_3_SEGMENTS ++ SRV6_SRC_NODE_FIRST_PASS_2_3_SEGMENTS ++ 20 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_3_SEGMENTS ++ SRV6_SRC_NODE_SECOND_PASS_3_SEGMENTS ++ 21 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_2_SEGMENTS ++ SRV6_SRC_NODE_SECOND_PASS_2_SEGMENTS ++ 22 ++ ++ ++ SGT_NETWORK_ADD_MSB ++ SGT_NETWORK_ADD_MSB ++ 23 ++ ++ ++ SGT_NETWORK_FIX ++ SGT_NETWORK_FIX ++ 24 ++ ++ ++ SGT_NETWORK_REMOVE ++ SGT_NETWORK_REMOVE ++ 25 ++ ++ ++ SGT_EDSA_FIX ++ SGT_EDSA_FIX ++ 26 ++ ++ ++ SGT_EDSA_REMOVE ++ SGT_EDSA_REMOVE ++ 27 ++ ++ ++ SGT_GBP_FIX_IPV4 ++ SGT_GBP_FIX_IPV4 ++ 28 ++ ++ ++ SGT_GBP_FIX_IPV6 ++ SGT_GBP_FIX_IPV6 ++ 29 ++ ++ ++ SGT_GBP_REMOVE_IPV4 ++ SGT_GBP_REMOVE_IPV4 ++ 30 ++ ++ ++ SGT_GBP_REMOVE_IPV6 ++ SGT_GBP_REMOVE_IPV6 ++ 31 ++ ++ ++ PTP_PHY_1_STEP ++ PTP_PHY_1_STEP ++ 32 ++ ++ ++ EGRESS_MIRRORING_METADATA ++ EGRESS_MIRRORING_METADATA ++ 33 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV4 ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV4 ++ 34 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV6 ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV6 ++ 35 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV4 ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV4 ++ 36 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV6 ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV6 ++ 37 ++ ++ ++ CC_ERSPAN_TYPE_II_SRC_DEV ++ CC_ERSPAN_TYPE_II_SRC_DEV ++ 38 ++ ++ ++ VXLAN_GBP_SOURCE_GROUP_POLICY_ID ++ VXLAN_GBP_SOURCE_GROUP_POLICY_ID ++ 39 ++ ++ ++ SRV6_BEST_EFFORT ++ SRV6_BEST_EFFORT ++ 40 ++ ++ ++ SRV6_SRC_NODE_1_CONTAINER ++ SRV6_SRC_NODE_1_CONTAINER ++ 41 ++ ++ ++ SRV6_SRC_NODE_FIRST_PASS_2_3_CONTAINERS ++ SRV6_SRC_NODE_FIRST_PASS_2_3_CONTAINERS ++ 42 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_2_CONTAINERS ++ SRV6_SRC_NODE_SECOND_PASS_2_CONTAINERS ++ 43 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_3_CONTAINERS ++ SRV6_SRC_NODE_SECOND_PASS_3_CONTAINERS ++ 44 ++ ++ ++ SRV6_END_NODE_COC32_GSID ++ SRV6_END_NODE_COC32_GSID ++ 45 ++ ++ ++ IPV4_TTL_INCREMENT ++ IPV4_TTL_INCREMENT ++ 46 ++ ++ ++ IPV6_HOP_LIMIT_INCREMENT ++ IPV6_HOP_LIMIT_INCREMENT ++ 47 ++ ++ ++ CLEAR_OUTGOING_MTAG_COMMAND ++ CLEAR_OUTGOING_MTAG_COMMAND ++ 48 ++ ++ ++ SFLOW_V5_IPV4 ++ SFLOW_V5_IPV4 ++ 49 ++ ++ ++ SFLOW_V5_IPV6 ++ SFLOW_V5_IPV6 ++ 50 ++ ++ ++ SLS ++ SLS ++ 51 ++ ++ ++ ++ trunk-member-mode-type ++ enumeration ++ Specifies supported Pha image id ++ ++ NATIVE ++ NATIVE ++* the trunk members are filled ++* according to the order given by application. ++* Regular trunk may hold max of 8 members. ++* Cascade trunk may hold : ++* max of 64 members ++ 0 ++ ++ ++ FLEX ++ FLEX ++* A mode to allows flexibility for ++* each Regular trunk to state it's max number of members (before starting to add members). ++* (this mode not effect 'cascade trunk' members) ++* Regular trunk may hold : max of 4K members. (each trunk set it's own limit) ++* Cascade trunk may hold : max of 64 members. ++ 2 ++ ++ ++ ++ number-physical-port-type ++ enumeration ++ AC3X/AC5X 128, falcon 64, 128, 256, 512, 1024 ++ ++ no-ports ++ no-ports ++ 0 ++ ++ ++ 64-ports ++ 64-ports ++ 64 ++ ++ ++ 128-ports ++ 128-ports ++ 128 ++ ++ ++ 256-ports ++ 256-ports ++ 256 ++ ++ ++ 512-ports ++ 512-ports ++ 512 ++ ++ ++ 1024-ports ++ 1024-ports ++ 1024 ++ ++ ++ ++ serdes-ref-clock-type ++ enumeration ++ Specifies serdes refernce clock. ++ ++ external_25_single_ended ++ EXTERNAL_25_SINGLE_ENDED ++ 0 ++ ++ ++ external_125_single_ended ++ EXTERNAL_125_SINGLE_ENDED ++ 1 ++ ++ ++ external_125_diff ++ EXTERNAL_125_DIFF ++ 2 ++ ++ ++ external_156_25_single_ended ++ EXTERNAL_156_25_SINGLE_ENDED ++ 3 ++ ++ ++ external_156_25_diff ++ EXTERNAL_156_25_DIFF ++ 4 ++ ++ ++ internal_125 ++ INTERNAL_125 ++ 5 ++ ++ ++ ++ cpu-port-id-type ++ uint32 ++ CPU port id ++ 0 ++ 7 ++ ++ ++ rx-buffer-size-type ++ uint32 ++ Rx Buffer size ++ 64 ++ 10240 ++ ++ ++ tx-sdma-queue-mode-type ++ enumeration ++ Specifies TX queue mode. ++ ++ Normal ++ Application ++ 0 ++ ++ ++ Packet_Generator ++ Traffic generator ++ 1 ++ ++ ++ ++ alloc-method-type ++ enumeration ++ Specifies Buffers allocation method. ++ ++ Dynamic_Alloc ++ Dynamic ++ 0 ++ ++ ++ Static_Alloc ++ Static ++ 1 ++ ++ ++ ++ au_mesage_lenght-type ++ enumeration ++ Specifies Buffers allocation method. ++ ++ 4_words ++ 4 Words ++ 0 ++ ++ ++ 8_words ++ 8 Words ++ 1 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ++ AC5X-RD ++ ++ 4294967295 ++ external_25_single_ended ++ 2 ++ 60 ++ 128-ports ++ false ++ false ++ 0 ++ ++ ++ true ++ ++ 4096 ++ ++ ++ 2048 ++ ++ ++ ++ 0 ++ 0 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 7 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 6 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 5 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 4 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 3 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 2 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 1 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 0 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 7 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 6 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 5 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 4 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 3 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 2 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 1 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 0 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 1 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 2 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 3 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 4 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 5 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 6 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 7 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 0 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 1 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 2 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 3 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 4 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 5 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 6 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 7 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ ++ false ++ false ++ false ++ 0 ++ 8_words ++ false ++ ++ ++ ++ TCAM_ROUTER_BASED ++ 0 ++ true ++ ++ ++ true ++ true ++ true ++ true ++ true ++ true ++ ++ 511 ++ FLEX ++ ++ true ++ true ++ true ++ true ++ ++ false ++ 01 ++ 0 ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100755 +index 000000000..46ef35490 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++aed8ffe4d26f6366411562f09695d033 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100755 +index 000000000..a00b5b254 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,511 @@ ++ ++ ++ ++ ++ ++ device-id-type ++ uint32 ++ Device ID 0..1 ++ 0 ++ 1 ++ ++ ++ port-id-type ++ uint32 ++ Interface number ++ 0 ++ 1023 ++ ++ ++ logDest-type ++ enumeration ++ Logging Feature Options ++ ++ SAI_LOG_SYSLOG ++ SYSLOG {Syslog service should be running to use this option} ++ 0 ++ ++ ++ SAI_LOG_CONSOLE ++ CONSOLE ++ 1 ++ ++ ++ SAI_LOG_FILE ++ FILE {Warning !!! Use with caution. Can cause disk full issues} ++ 2 ++ ++ ++ ++ InDropCounter-type ++ enumeration ++ Router In Drop Reason Feature Options ++ ++ TTL_HOPLIMIT_EXCEEDED ++ Router In Drop Counters track TTL & Hop Limit Exceeded Packets ++ 0 ++ ++ ++ ROUTE_BLACKHOLE ++ Router In Drop Counters track Route Black Hole Packets ++ 1 ++ ++ ++ ++ Feature-enable ++ enumeration ++ Feature Enabled/Disabled ++ ++ Disabled ++ Disabled ++ 0 ++ ++ ++ Enabled ++ Enabled ++ 1 ++ ++ ++ ++ log-dest-file-path-type ++ string ++ A string with path to file for logging feature ++ 2 ++ 30 ++ ++ ++ acl-feature-name-type ++ enumeration ++ ++ ++ port-sFlow ++ SFlow over Port ++ 0 ++ ++ ++ port-counters-ipv4-ipv6 ++ Port ipv4/ipv6 counters ++ 1 ++ ++ ++ control-acl ++ ACLs for control packet handling ++ 2 ++ ++ ++ debug-counter-acl ++ ACLs for Debug Counters ++ 3 ++ ++ ++ ++ ingress-acl-stage-type ++ enumeration ++ ++ ++ disabled ++ Feature not enabled ++ 0 ++ ++ ++ IPCL0 ++ Stage IPCL0 ++ 1 ++ ++ ++ IPCL1 ++ Stage IPCL1 ++ 2 ++ ++ ++ ++ egress-acl-stage-type ++ enumeration ++ ++ ++ disabled ++ Feature not enabled ++ 0 ++ ++ ++ EPCL0 ++ Stage EPCL0 ++ 2 ++ ++ ++ ++ feature-priority-type ++ uint32 ++ Feature priority ++ 2 ++ 15 ++ ++ ++ hit-number-type ++ uint32 ++ Hit/lookup number ++ 0 ++ 3 ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++ ++ ++ 0 ++ 0 ++ 0 ++ ++ ++ 1 ++ 0 ++ 1 ++ ++ ++ 2 ++ 0 ++ 2 ++ ++ ++ 3 ++ 0 ++ 3 ++ ++ ++ 4 ++ 0 ++ 4 ++ ++ ++ 5 ++ 0 ++ 5 ++ ++ ++ 6 ++ 0 ++ 6 ++ ++ ++ 7 ++ 0 ++ 7 ++ ++ ++ 8 ++ 0 ++ 8 ++ ++ ++ 9 ++ 0 ++ 9 ++ ++ ++ 10 ++ 0 ++ 10 ++ ++ ++ 11 ++ 0 ++ 11 ++ ++ ++ 12 ++ 0 ++ 12 ++ ++ ++ 13 ++ 0 ++ 13 ++ ++ ++ 14 ++ 0 ++ 14 ++ ++ ++ 15 ++ 0 ++ 15 ++ ++ ++ 16 ++ 0 ++ 16 ++ ++ ++ 17 ++ 0 ++ 17 ++ ++ ++ 18 ++ 0 ++ 18 ++ ++ ++ 19 ++ 0 ++ 19 ++ ++ ++ 20 ++ 0 ++ 20 ++ ++ ++ 21 ++ 0 ++ 21 ++ ++ ++ 22 ++ 0 ++ 22 ++ ++ ++ 23 ++ 0 ++ 23 ++ ++ ++ 24 ++ 0 ++ 24 ++ ++ ++ 25 ++ 0 ++ 25 ++ ++ ++ 26 ++ 0 ++ 26 ++ ++ ++ 27 ++ 0 ++ 27 ++ ++ ++ 28 ++ 0 ++ 28 ++ ++ ++ 29 ++ 0 ++ 29 ++ ++ ++ 30 ++ 0 ++ 30 ++ ++ ++ 31 ++ 0 ++ 31 ++ ++ ++ 32 ++ 0 ++ 32 ++ ++ ++ 33 ++ 0 ++ 33 ++ ++ ++ 34 ++ 0 ++ 34 ++ ++ ++ 35 ++ 0 ++ 35 ++ ++ ++ 36 ++ 0 ++ 36 ++ ++ ++ 37 ++ 0 ++ 37 ++ ++ ++ 38 ++ 0 ++ 38 ++ ++ ++ 39 ++ 0 ++ 39 ++ ++ ++ 40 ++ 0 ++ 40 ++ ++ ++ 41 ++ 0 ++ 41 ++ ++ ++ 42 ++ 0 ++ 42 ++ ++ ++ 43 ++ 0 ++ 43 ++ ++ ++ 44 ++ 0 ++ 44 ++ ++ ++ 45 ++ 0 ++ 45 ++ ++ ++ 46 ++ 0 ++ 46 ++ ++ ++ 47 ++ 0 ++ 47 ++ ++ ++ 48 ++ 0 ++ 48 ++ ++ ++ 49 ++ 0 ++ 49 ++ ++ ++ 50 ++ 0 ++ 50 ++ ++ ++ 51 ++ 0 ++ 51 ++ ++ ++ 52 ++ 0 ++ 52 ++ ++ ++ 53 ++ 0 ++ 53 ++ ++ ++ ++ 8 ++ 0 ++ 0 ++ 64 ++ 8 ++ 8 ++ 1024 ++ ++ ++ 0 ++ ROUTE_BLACKHOLE ++ ++ ++ SAI_LOG_SYSLOG ++ ++ ++ Disabled ++ ++ ++ control-acl ++ 3 ++ ++ IPCL0 ++ 1 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ port-sFlow ++ 4 ++ ++ IPCL0 ++ 0 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ port-counters-ipv4-ipv6 ++ 5 ++ ++ IPCL0 ++ 3 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ debug-counter-acl ++ 2 ++ ++ disabled ++ ++ ++ disabled ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/hwsku.json b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/hwsku.json +new file mode 100644 +index 000000000..e1a5b7980 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/hwsku.json +@@ -0,0 +1,322 @@ ++{ ++ "interfaces": { ++ "Ethernet0": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet1": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet2": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet3": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet4": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet5": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet6": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet7": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet8": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet9": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet10": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet11": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet12": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet13": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet14": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet15": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet16": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet17": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet18": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet19": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet20": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet21": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet22": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet23": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet24": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet25": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet26": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet27": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet28": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet29": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet30": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet31": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet32": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet33": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet34": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet35": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet36": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet37": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet38": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet39": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet40": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet41": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet42": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet43": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet44": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet45": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet46": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet47": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet48": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet49": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet50": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet51": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet52": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet53": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/port_config.ini b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/port_config.ini +new file mode 100644 +index 000000000..60ec33e24 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/port_config.ini +@@ -0,0 +1,55 @@ ++# name lanes alias speed autoneg fec index poe_pri poe_status poe_maxpower poe_tlv ++Ethernet0 0 Eth1 1000 on none 1 critical enable 0 disable ++Ethernet1 1 Eth2 1000 on none 2 critical enable 0 disable ++Ethernet2 2 Eth3 1000 on none 3 critical enable 0 disable ++Ethernet3 3 Eth4 1000 on none 4 critical enable 0 disable ++Ethernet4 4 Eth5 1000 on none 5 low enable 0 disable ++Ethernet5 5 Eth6 1000 on none 6 low enable 0 disable ++Ethernet6 6 Eth7 1000 on none 7 low enable 0 disable ++Ethernet7 7 Eth8 1000 on none 8 low enable 0 disable ++Ethernet8 8 Eth9 1000 on none 9 low enable 0 disable ++Ethernet9 9 Eth10 1000 on none 10 low enable 0 disable ++Ethernet10 10 Eth11 1000 on none 11 low enable 0 disable ++Ethernet11 11 Eth12 1000 on none 12 low enable 0 disable ++Ethernet12 12 Eth13 1000 on none 13 low enable 0 disable ++Ethernet13 13 Eth14 1000 on none 14 low enable 0 disable ++Ethernet14 14 Eth15 1000 on none 15 low enable 0 disable ++Ethernet15 15 Eth16 1000 on none 16 low enable 0 disable ++Ethernet16 16 Eth17 1000 on none 17 low enable 0 disable ++Ethernet17 17 Eth18 1000 on none 18 low enable 0 disable ++Ethernet18 18 Eth19 1000 on none 19 low enable 0 disable ++Ethernet19 19 Eth20 1000 on none 20 low enable 0 disable ++Ethernet20 20 Eth21 1000 on none 21 low enable 0 disable ++Ethernet21 21 Eth22 1000 on none 22 low enable 0 disable ++Ethernet22 22 Eth23 1000 on none 23 low enable 0 disable ++Ethernet23 23 Eth24 1000 on none 24 low enable 0 disable ++Ethernet24 24 Eth25 1000 on none 25 low enable 0 disable ++Ethernet25 25 Eth26 1000 on none 26 low enable 0 disable ++Ethernet26 26 Eth27 1000 on none 27 low enable 0 disable ++Ethernet27 27 Eth28 1000 on none 28 low enable 0 disable ++Ethernet28 28 Eth29 1000 on none 29 low enable 0 disable ++Ethernet29 29 Eth30 1000 on none 30 low enable 0 disable ++Ethernet30 30 Eth31 1000 on none 31 low enable 0 disable ++Ethernet31 31 Eth32 1000 on none 32 low enable 0 disable ++Ethernet32 32 Eth33 2500 on rs 33 low enable 0 disable ++Ethernet33 33 Eth34 2500 on rs 34 low enable 0 disable ++Ethernet34 34 Eth35 2500 on rs 35 low enable 0 disable ++Ethernet35 35 Eth36 2500 on rs 36 low enable 0 disable ++Ethernet36 36 Eth37 2500 on rs 37 low enable 0 disable ++Ethernet37 37 Eth38 2500 on rs 38 low enable 0 disable ++Ethernet38 38 Eth39 2500 on rs 39 low enable 0 disable ++Ethernet39 39 Eth40 2500 on rs 40 low enable 0 disable ++Ethernet40 40 Eth41 2500 on rs 41 low enable 0 disable ++Ethernet41 41 Eth42 2500 on rs 42 low enable 0 disable ++Ethernet42 42 Eth43 2500 on rs 43 low enable 0 disable ++Ethernet43 43 Eth44 2500 on rs 44 low enable 0 disable ++Ethernet44 44 Eth45 2500 on rs 45 critical enable 0 disable ++Ethernet45 45 Eth46 2500 on rs 46 critical enable 0 disable ++Ethernet46 46 Eth47 2500 on rs 47 critical enable 0 disable ++Ethernet47 47 Eth48 2500 on rs 48 critical enable 0 disable ++Ethernet48 48 Eth49 25000 off none 49 NA NA 0 NA ++Ethernet49 49 Eth50 25000 off none 50 NA NA 0 NA ++Ethernet50 50 Eth51 25000 off none 51 NA NA 0 NA ++Ethernet51 51 Eth52 25000 off none 52 NA NA 0 NA ++Ethernet52 52 Eth53 25000 off none 53 NA NA 0 NA ++Ethernet53 53 Eth54 25000 off none 54 NA NA 0 NA +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/profile.ini b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/profile.ini +new file mode 100644 +index 000000000..c2f77685a +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/profile.ini +@@ -0,0 +1 @@ ++switchMacAddress=00:01:02:03:04:05 +diff --git a/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/sai.profile b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/sai.profile +new file mode 100755 +index 000000000..938b288ad +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts-r0/wistron_es2227_54ts/sai.profile +@@ -0,0 +1,4 @@ ++mode=1 ++hwId=AC5XRD ++switchProfile=/usr/share/sonic/hwsku/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/profile.ini +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/default_sku b/device/wistron/arm64-wistron_es2227_54ts_p-r0/default_sku +new file mode 100644 +index 000000000..2aea253d1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/default_sku +@@ -0,0 +1 @@ ++wistron_es2227_54ts_p t1 +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/installer.conf b/device/wistron/arm64-wistron_es2227_54ts_p-r0/installer.conf +new file mode 100644 +index 000000000..28757b561 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/installer.conf +@@ -0,0 +1 @@ ++ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="default_hugepagesz=2M hugepages=256 pci=noaer" +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/pcie.yaml b/device/wistron/arm64-wistron_es2227_54ts_p-r0/pcie.yaml +new file mode 100644 +index 000000000..84faf76b2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/pcie.yaml +@@ -0,0 +1,10 @@ ++- bus: '00' ++ dev: '00' ++ fn: '0' ++ id: '0110' ++ name: 'PCI bridge: Marvell Technology Group Ltd. Device 0110' ++- bus: '01' ++ dev: '00' ++ fn: '0' ++ id: '9823' ++ name: 'Ethernet controller: Marvell Technology Group Ltd. Device 9823' +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform.json +new file mode 100644 +index 000000000..dbdfbf083 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform.json +@@ -0,0 +1,567 @@ ++{ ++ "chassis": { ++ "name": "wistron_es2227_54ts_p", ++ "components": [ ++ { ++ "name": "U-Boot" ++ }, ++ { ++ "name": "ONIE-VERSION" ++ }, ++ { ++ "name": "CPLD" ++ }, ++ { ++ "name": "PoE" ++ } ++ ], ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "fan_drawers": [ ++ { ++ "name": "FanTray1", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "num_fans" : 1, ++ "status_led": { ++ "controllable": false ++ }, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ } ++ ], ++ "psus": [ ++ { ++ "name": "PSU-1", ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ }, ++ { ++ "name": "PSU-2", ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1", ++ "speed": { ++ "controllable": false ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "CPU Temp", ++ "controllable": false ++ }, ++ { ++ "name": "DDR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "Dimm Temp", ++ "controllable": false ++ }, ++ { ++ "name": "MAC Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PHY Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PSU 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "PoE Temp", ++ "controllable": false ++ }, ++ { ++ "name": "System Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XFMR Ambient", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 1 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 2 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 3 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 4 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 5 Temp", ++ "controllable": false ++ }, ++ { ++ "name": "XCVR 6 Temp", ++ "controllable": false ++ } ++ ], ++ "sfps": [ ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "Ethernet53" ++ } ++ ] ++ }, ++ "interfaces": { ++ "Ethernet0": { ++ "index": "1", ++ "lanes": "0", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth1"] ++ } ++ }, ++ "Ethernet1": { ++ "index": "2", ++ "lanes": "1", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth2"] ++ } ++ }, ++ "Ethernet2": { ++ "index": "3", ++ "lanes": "2", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth3"] ++ } ++ }, ++ "Ethernet3": { ++ "index": "4", ++ "lanes": "3", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth4"] ++ } ++ }, ++ "Ethernet4": { ++ "index": "5", ++ "lanes": "4", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth5"] ++ } ++ }, ++ "Ethernet5": { ++ "index": "6", ++ "lanes": "5", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth6"] ++ } ++ }, ++ "Ethernet6": { ++ "index": "7", ++ "lanes": "6", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth7"] ++ } ++ }, ++ "Ethernet7": { ++ "index": "8", ++ "lanes": "7", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth8"] ++ } ++ }, ++ "Ethernet8": { ++ "index": "9", ++ "lanes": "8", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth9"] ++ } ++ }, ++ "Ethernet9": { ++ "index": "10", ++ "lanes": "9", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth10"] ++ } ++ }, ++ "Ethernet10": { ++ "index": "11", ++ "lanes": "10", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth11"] ++ } ++ }, ++ "Ethernet11": { ++ "index": "12", ++ "lanes": "11", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth12"] ++ } ++ }, ++ "Ethernet12": { ++ "index": "13", ++ "lanes": "12", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth13"] ++ } ++ }, ++ "Ethernet13": { ++ "index": "14", ++ "lanes": "13", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth14"] ++ } ++ }, ++ "Ethernet14": { ++ "index": "15", ++ "lanes": "14", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth15"] ++ } ++ }, ++ "Ethernet15": { ++ "index": "16", ++ "lanes": "15", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth16"] ++ } ++ }, ++ "Ethernet16": { ++ "index": "17", ++ "lanes": "16", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth17"] ++ } ++ }, ++ "Ethernet17": { ++ "index": "18", ++ "lanes": "17", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth18"] ++ } ++ }, ++ "Ethernet18": { ++ "index": "19", ++ "lanes": "18", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth19"] ++ } ++ }, ++ "Ethernet19": { ++ "index": "20", ++ "lanes": "19", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth20"] ++ } ++ }, ++ "Ethernet20": { ++ "index": "21", ++ "lanes": "20", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth21"] ++ } ++ }, ++ "Ethernet21": { ++ "index": "22", ++ "lanes": "21", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth22"] ++ } ++ }, ++ "Ethernet22": { ++ "index": "23", ++ "lanes": "22", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth23"] ++ } ++ }, ++ "Ethernet23": { ++ "index": "24", ++ "lanes": "23", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth24"] ++ } ++ }, ++ "Ethernet24": { ++ "index": "25", ++ "lanes": "24", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth25"] ++ } ++ }, ++ "Ethernet25": { ++ "index": "26", ++ "lanes": "25", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth26"] ++ } ++ }, ++ "Ethernet26": { ++ "index": "27", ++ "lanes": "26", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth27"] ++ } ++ }, ++ "Ethernet27": { ++ "index": "28", ++ "lanes": "27", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth28"] ++ } ++ }, ++ "Ethernet28": { ++ "index": "29", ++ "lanes": "28", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth29"] ++ } ++ }, ++ "Ethernet29": { ++ "index": "30", ++ "lanes": "29", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth30"] ++ } ++ }, ++ "Ethernet30": { ++ "index": "31", ++ "lanes": "30", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth31"] ++ } ++ }, ++ "Ethernet31": { ++ "index": "32", ++ "lanes": "31", ++ "breakout_modes": { ++ "1x1000[100,10]": ["Eth32"] ++ } ++ }, ++ "Ethernet32": { ++ "index": "33", ++ "lanes": "32", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth33"] ++ } ++ }, ++ "Ethernet33": { ++ "index": "34", ++ "lanes": "33", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth34"] ++ } ++ }, ++ "Ethernet34": { ++ "index": "35", ++ "lanes": "34", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth35"] ++ } ++ }, ++ "Ethernet35": { ++ "index": "36", ++ "lanes": "35", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth36"] ++ } ++ }, ++ "Ethernet36": { ++ "index": "37", ++ "lanes": "36", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth37"] ++ } ++ }, ++ "Ethernet37": { ++ "index": "38", ++ "lanes": "37", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth38"] ++ } ++ }, ++ "Ethernet38": { ++ "index": "39", ++ "lanes": "38", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth39"] ++ } ++ }, ++ "Ethernet39": { ++ "index": "40", ++ "lanes": "39", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth40"] ++ } ++ }, ++ "Ethernet40": { ++ "index": "41", ++ "lanes": "40", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth41"] ++ } ++ }, ++ "Ethernet41": { ++ "index": "42", ++ "lanes": "41", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth42"] ++ } ++ }, ++ "Ethernet42": { ++ "index": "43", ++ "lanes": "42", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth43"] ++ } ++ }, ++ "Ethernet43": { ++ "index": "44", ++ "lanes": "43", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth44"] ++ } ++ }, ++ "Ethernet44": { ++ "index": "45", ++ "lanes": "44", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth45"] ++ } ++ }, ++ "Ethernet45": { ++ "index": "46", ++ "lanes": "45", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth46"] ++ } ++ }, ++ "Ethernet46": { ++ "index": "47", ++ "lanes": "46", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth47"] ++ } ++ }, ++ "Ethernet47": { ++ "index": "48", ++ "lanes": "47", ++ "breakout_modes": { ++ "1x2500[1000,100]": ["Eth48"] ++ } ++ }, ++ "Ethernet48": { ++ "index": "49", ++ "lanes": "48", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth49"] ++ } ++ }, ++ "Ethernet49": { ++ "index": "50", ++ "lanes": "49", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth50"] ++ } ++ }, ++ "Ethernet50": { ++ "index": "51", ++ "lanes": "50", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth51"] ++ } ++ }, ++ "Ethernet51": { ++ "index": "52", ++ "lanes": "51", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth52"] ++ } ++ }, ++ "Ethernet52": { ++ "index": "53", ++ "lanes": "52", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth53"] ++ } ++ }, ++ "Ethernet53": { ++ "index": "54", ++ "lanes": "53", ++ "breakout_modes": { ++ "1x25G[10G]": ["Eth54"] ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_asic b/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_asic +new file mode 100644 +index 000000000..5cbe9d002 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_asic +@@ -0,0 +1 @@ ++marvell-prestera +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_components.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_components.json +new file mode 100644 +index 000000000..288345ef8 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/platform_components.json +@@ -0,0 +1,12 @@ ++{ ++ "chassis": { ++ "wistron_es2227_54ts_p": { ++ "component": { ++ "U-Boot": { }, ++ "ONIE-VERSION": { }, ++ "CPLD": { }, ++ "PoE": { } ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/plugins/eeprom.py b/device/wistron/arm64-wistron_es2227_54ts_p-r0/plugins/eeprom.py +new file mode 100644 +index 000000000..a5461871c +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/plugins/eeprom.py +@@ -0,0 +1,13 @@ ++#!/usr/bin/env python ++ ++try: ++ from sonic_eeprom import eeprom_tlvinfo ++except ImportError as e: ++ raise ImportError (str(e) + "- required module not found") ++ ++ ++class board(eeprom_tlvinfo.TlvInfoDecoder): ++ ++ def __init__(self, name, path, cpld_root, ro): ++ self.eeprom_path = "/etc/sonic/eeprom" ++ super(board, self).__init__(self.eeprom_path, 0, '', True) +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/pmon_daemon_control.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/pmon_daemon_control.json +new file mode 100644 +index 000000000..689def2c1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/pmon_daemon_control.json +@@ -0,0 +1,4 @@ ++{ ++ "skip_ledd": true, ++ "skip_pcied": true ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/sensors.conf b/device/wistron/arm64-wistron_es2227_54ts_p-r0/sensors.conf +new file mode 100755 +index 000000000..d549834fb +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/sensors.conf +@@ -0,0 +1,59 @@ ++# libsensors configuration file for Wistron ES1227-54TS ++# The i2c bus portion is omit because adapter name ++# changes every time when system boot up. ++ ++bus "i2c-0" "mv64xxx_i2c adapter" ++bus "i2c-2" "i2c-0-mux (chan_id 0)" ++bus "i2c-3" "i2c-0-mux (chan_id 1)" ++ ++ ++chip "2227_max31790-i2c-2-2f" ++ ignore fan1 ++ ignore fan2 ++ ignore fan3 ++ ignore fan5 ++ ignore fan6 ++ ignore fan11 ++ ignore fan12 ++ label fan4 "Fan 1" ++ label fan8 "Fan 2" ++ ++chip "pmbus-i2c-3-58" ++ label power1 "PSU 2 Input Power" ++ label power2 "PSU 2 Output Power 1" ++ label power3 "PSU 2 Output Power 2" ++ label curr1 "PSU 2 Input Current" ++ label curr2 "PSU 2 Output Current 1" ++ label curr3 "PSU 2 Output Current 2" ++ label in1 "PSU 2 Input Voltage" ++ label in2 "PSU 2 Output Voltage" ++ label fan1 "PSU 2 Fan RPM" ++ label temp1 "PSU 2 Temperature 1" ++ label temp2 "PSU 2 Temperature 2" ++ label temp3 "PSU 2 Temperature 3" ++ ++chip "pmbus-i2c-3-59" ++ label power1 "PSU 1 Input Power" ++ label power2 "PSU 1 Output Power 1" ++ label power3 "PSU 1 Output Power 2" ++ label curr1 "PSU 1 Input Current" ++ label curr2 "PSU 1 Output Current 1" ++ label curr3 "PSU 1 Output Current 2" ++ label in1 "PSU 1 Input Voltage" ++ label in2 "PSU 1 Output Voltage" ++ label fan1 "PSU 1 Fan RPM" ++ label temp1 "PSU 1 Temperature 1" ++ label temp2 "PSU 1 Temperature 2" ++ label temp3 "PSU 1 Temperature 3" ++ ++chip "tmp75-i2c-2-4a" ++ label temp1 "XFMR Ambient Temp" ++ ++chip "tmp75-i2c-2-49" ++ label temp1 "DDR Ambient Temp" ++ ++chip "tmp75-i2c-2-4b" ++ label temp1 "System Ambient Temp" ++ ++chip "jc42-i2c-0-1b" ++ label temp1 "DDR Temp" +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/system_health_monitoring_config.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/system_health_monitoring_config.json +new file mode 100644 +index 000000000..b6aa813f1 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/system_health_monitoring_config.json +@@ -0,0 +1,12 @@ ++{ ++ "services_to_ignore": [], ++ "devices_to_ignore": ["asic"], ++ "user_defined_checkers": [], ++ "polling_interval": 60, ++ "led_color": { ++ "fault": "red", ++ "normal": "green", ++ "booting": "green_blinking" ++ } ++} ++ +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/thermal_policy.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/thermal_policy.json +new file mode 100755 +index 000000000..da35ff6d2 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/thermal_policy.json +@@ -0,0 +1,110 @@ ++{ ++ "thermal_control_algorithm": { ++ "run_at_boot_up": "false", ++ "interval": "60" ++ }, ++ "info_types": [ ++ { ++ "type": "fan_info" ++ }, ++ { ++ "type": "thermal_info" ++ }, ++ { ++ "type": "chassis_info" ++ } ++ ], ++ "policies": [ ++ { ++ "name": "any fan absence", ++ "conditions": [ ++ { ++ "type": "fan.any.absence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.all.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "all fan presence", ++ "conditions": [ ++ { ++ "type": "fan.all.presence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "any fan new", ++ "conditions": [ ++ { ++ "type": "fan.any.new" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "fan.new.set_speed" ++ } ++ ] ++ }, ++ { ++ "name": "all fan absence", ++ "conditions": [ ++ { ++ "type": "fan.all.absence" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ }, ++ { ++ "name": "temp over high critical threshold", ++ "conditions": [ ++ { ++ "type": "thermal.over.high_critical_threshold" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ }, ++ { ++ "name": "temp over high threshold", ++ "conditions": [ ++ { ++ "type": "thermal.over.high_threshold" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "high_threshold.control" ++ } ++ ] ++ }, ++ { ++ "name": "temp over threshold after cool down", ++ "conditions": [ ++ { ++ "type": "thermal.over.threshold_after_cool_down" ++ } ++ ], ++ "actions": [ ++ { ++ "type": "switch.shutdown" ++ } ++ ] ++ } ++ ] ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100644 +index 000000000..cad0e25e9 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++0b9f1b73ba179e2b977bc116732f4d14 +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100644 +index 000000000..b48ff5155 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,1785 @@ ++ ++ ++ ++ ++ ++ std-string ++ string ++ standard string. ++ 1 ++ 100 ++ ++ ++ board-callback-type ++ enumeration ++ Specifies os/ext drv callback types. ++ ++ linux-static ++ Linux Static ++ 0 ++ ++ ++ linux-shared ++ Linux Shared Lib mode ++ 1 ++ ++ ++ external ++ External Os ++ 3 ++ ++ ++ freeBsd ++ Free BSD ++ 4 ++ ++ ++ ++ board-pp-map-type ++ enumeration ++ Specifies pci info types. ++ ++ fixed ++ Fixed ++ 0 ++ ++ ++ autoscan ++ Auto scan ++ 1 ++ ++ ++ ++ board-pp-interface-channel-type ++ enumeration ++ Specifies channel interface type. ++ ++ pci ++ PCI ++ 0 ++ ++ ++ smi ++ SMI ++ 1 ++ ++ ++ twsi ++ TWSI ++ 2 ++ ++ ++ ++ board-pp-as-type ++ enumeration ++ Specifies Address space type. ++ ++ 4_regions ++ address-space 4 regions ++ 0 ++ ++ ++ 8_regions ++ address-space 8 regions ++ 1 ++ ++ ++ atu ++ address translation unit ++ 2 ++ ++ ++ ++ device-id-type ++ uint32 ++ Device ID 0..1 ++ 0 ++ 1 ++ ++ ++ port-mapping-type ++ enumeration ++ Specifies port map type. ++ ++ ethernet_mac ++ ETHERNET_MAC ++ 0 ++ ++ ++ cpu_sdma ++ CPU_SDMA ++ 1 ++ ++ ++ ++ interface-num-type ++ uint32 ++ Interface number ++ 0 ++ 1023 ++ ++ ++ txq-port-number-type ++ uint32 ++ TXq port number ++ 0 ++ 99 ++ ++ ++ phy-smi-interface-type ++ uint32 ++ Phy SMI interface type. ++ 0 ++ 3 ++ ++ ++ phy-xsmi-interface-type ++ uint32 ++ Phy XSMI interface type. ++ 0 ++ 15 ++ ++ ++ phy-type ++ enumeration ++ Specifies the PHY Part Identifier. ++ ++ NA ++ No Phy ++ 0 ++ ++ ++ alaska-88E1680 ++ Specifies PHY identifier 88E1680, used for Copper with speeds of 10M/100M/1G. ++ 1 ++ ++ ++ alaska-88E1780 ++ Specifies PHY identifier 88E1780, Integrated Octal 10/100/1000 Mbps Energy ++Efficient Ethernet Transceiver ++ 2 ++ ++ ++ alaska-88E2540 ++ Specifies PHY identifier 88E2540, 4 ports 10/100/1000/2.5G/5GBASE-T Ethernet ++Transceiver with IEEE 1588v2 PTP Support ++ 3 ++ ++ ++ alaska-88E2580 ++ Specifies PHY identifier 88E2580, Octal 10/100/1000/2.5G/5GBASE-T Ethernet Transceiver ++with IEEE 1588v2 PTP Support ++ 4 ++ ++ ++ alaska-88E2780 ++ Specifies PHY identifier 88E2780, Octal 10/100/1000/2.5G/5GBASE-T Ethernet Transceiver ++with IEEE 1588v2 PTP Support ++ 5 ++ ++ ++ alaska-MVCUE1786 ++ Specifies PHY identifier alaska V MV-CUE 1786, Octal 100/1000BASE-T Ethernet Transceiver ++with IEEE 1588v2 PTP Support ++ 6 ++ ++ ++ alaska-88E1781 ++ Specifies PHY identifier 88E1781, Integrated Octal 10/100/1000 Mbps Energy ++Efficient Ethernet Transceiver ++ 7 ++ ++ ++ ++ physical-port-num-type ++ uint32 ++ PHYSICAL PORT NUM ++ 0 ++ 1023 ++ ++ ++ led-stream-port-type ++ enumeration ++ Specifies the ledstream port type. ++ ++ PORT_TYPE_TRI_SPEED ++ tri-speed port. ++ 1 ++ ++ ++ PORT_TYPE_XG ++ XG port. ++ 2 ++ ++ ++ ++ led-stream-blink-select-type ++ enumeration ++ Specifies the LED stream blink select type. ++ ++ BLINK_SELECT_0 ++ Blink 0 signal. ++ 1 ++ ++ ++ BLINK_SELECT_1 ++ Blink 1 signal ++ 2 ++ ++ ++ ++ led-stream-order-mode-type ++ enumeration ++ Specifies the LED stream ordering mode. ++ ++ ORDER_MODE_BY_PORT ++ the indication order is arranged by port. ++ 1 ++ ++ ++ ORDER_MODE_BY_CLASS ++ the indication order is arranged by class. ++ 2 ++ ++ ++ ++ led-stream-blink-duty-cycle-type ++ enumeration ++ Specifies the LED stream blink cycle duty cycle type. ++ ++ BLINK_DUTY_CYCLE_0 ++ 25% on, 75% off. ++ 1 ++ ++ ++ BLINK_DUTY_CYCLE_1 ++ 50% on, 50% off. ++ 2 ++ ++ ++ BLINK_DUTY_CYCLE_2 ++ 50% on, 50% off. ++ 3 ++ ++ ++ BLINK_DUTY_CYCLE_3 ++ 75% on, 25% off. ++ 4 ++ ++ ++ ++ led-stream-blink-duration-type ++ enumeration ++ Specifies the LED stream blink period type. ++ ++ BLINK_DURATION_0 ++ BLINK_DURATION_0. ++ 1 ++ ++ ++ BLINK_DURATION_1 ++ BLINK_DURATION_1. ++ 2 ++ ++ ++ BLINK_DURATION_2 ++ BLINK_DURATION_2. ++ 3 ++ ++ ++ BLINK_DURATION_3 ++ BLINK_DURATION_3. ++ 4 ++ ++ ++ BLINK_DURATION_4 ++ BLINK_DURATION_4. ++ 5 ++ ++ ++ BLINK_DURATION_5 ++ BLINK_DURATION_5. ++ 6 ++ ++ ++ BLINK_DURATION_6 ++ (APPLICABLE DEVICES: xCat3; AC5; Lion2; Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Pipe) . ++ 7 ++ ++ ++ BLINK_DURATION_7 ++ APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Pipe). ++ 8 ++ ++ ++ ++ led-stream-pulse-stretch-type ++ enumeration ++ Specifies the LED stream length of stretching for dynamic signals. ++ ++ PULSE_STRETCH_0_NO ++ PULSE_STRETCH_0_NO. ++ 1 ++ ++ ++ PULSE_STRETCH_1 ++ PULSE_STRETCH_1. ++ 2 ++ ++ ++ PULSE_STRETCH_2 ++ PULSE_STRETCH_2. ++ 3 ++ ++ ++ PULSE_STRETCH_3 ++ PULSE_STRETCH_3. ++ 4 ++ ++ ++ PULSE_STRETCH_4 ++ PULSE_STRETCH_4. ++ 5 ++ ++ ++ PULSE_STRETCH_5 ++ PULSE_STRETCH_5. ++ 6 ++ ++ ++ PULSE_STRETCH_6 ++ (APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Falcon; AC5P; Pipe). ++ 7 ++ ++ ++ PULSE_STRETCH_7 ++ (APPLICABLE DEVICES: Bobcat2; Caelum; Aldrin; AC3X; Bobcat3; Aldrin2; Falcon; AC5P; Pipe). ++ 8 ++ ++ ++ ++ led-stream-clock-out-frequency-type ++ enumeration ++ Specifies the LED stream blink cycle duty cycle type. ++ ++ _CLOCK_OUT_FREQUENCY_500 ++ 500 KHz LED clock frequency. ++ 1 ++ ++ ++ CLOCK_OUT_FREQUENCY_1000 ++ 1 MHz LED clock frequency. ++ 2 ++ ++ ++ CLOCK_OUT_FREQUENCY_2000 ++ 2 MHz LED clock frequency. ++ 3 ++ ++ ++ CLOCK_OUT_FREQUENCY_3000 ++ 3 MHz LED clock frequency. ++ 4 ++ ++ ++ ++ led-stream-class5-select-type ++ enumeration ++ Specifies the LED stream indication displayed on class5 (for dual-media port/phy). ++ ++ CLASS_5_SELECT_HALF_DUPLEX ++ Half Duplex is displayed on class5. ++ 1 ++ ++ ++ CLASS_5_SELECT_FIBER_LINK_UP ++ If port is a dual media port, Fiber Link Up is displayed on class5. ++ 2 ++ ++ ++ ++ led-stream-class13-select-type ++ enumeration ++ Specifies the LED stream indication displayed on class13 (for dual-media port/phy). ++ ++ CLASS_13_SELECT_LINK_DOWN ++ Link Down is displayed on class13. ++ 1 ++ ++ ++ CLASS_13_SELECT_COPPER_LINK_UP ++ If port is a dual media port, Copper Link Up is displayed on class13. ++ 2 ++ ++ ++ ++ led-class-num-type ++ uint32 ++ Led Class number ++ 0 ++ 11 ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ bus-id-type ++ uint32 ++ Bus Id Type, PCI/SMI ++ 0 ++ 255 ++ ++ ++ function-id-type ++ uint32 ++ Function Id Type, PCI/SMI ++ 0 ++ 255 ++ ++ ++ domain-type ++ uint32 ++ Domain, PCI/SMI ++ 0 ++ 255 ++ ++ ++ led-interface-type ++ uint32 ++ Led interface ++ 0 ++ 255 ++ ++ ++ led-position-type ++ uint32 ++ Led position ++ 0 ++ 63 ++ ++ ++ serdes-lane-type ++ uint32 ++ serdes lane ++ 0 ++ 7 ++ ++ ++ cpu-type ++ enumeration ++ The CPU Internal/External ++ ++ external ++ Extrenal connected CPU ++ 0 ++ ++ ++ internal ++ Internal CPU ++ 1 ++ ++ ++ ++ led-stream-clock-frequency-type ++ uint32 ++ Led Clock Frequency Sip6 ++ 500 ++ 80000 ++ ++ ++ led-unit-type ++ uint32 ++ Led units ++ 1 ++ 16 ++ ++ ++ led-unit-or-no-unit-type ++ uint32 ++ Led units, 0 for no Unit ++ 0 ++ 16 ++ ++ ++ led-group-type ++ uint32 ++ Led Group ++ 0 ++ 1 ++ ++ ++ bit-type ++ uint32 ++ Bit range 0..31 ++ 0 ++ 31 ++ ++ ++ bit-size-type ++ uint32 ++ Bit leng 1..32 ++ 1 ++ 32 ++ ++ ++ led-sip-type ++ enumeration ++ The LED scehme ++ ++ na ++ NA ++ 0 ++ ++ ++ sip5 ++ SIP5: AC3x ++ 5 ++ ++ ++ sip6 ++ SIP6: Falcon, AC5x ++ 6 ++ ++ ++ ++ port-cscd-type ++ enumeration ++ Specifies the cascade port type. ++ ++ DSA_1_WORD ++ DSA Regular ++ 0 ++ ++ ++ DSA_2_WORDS ++ DSA Extended ++ 1 ++ ++ ++ NETWORK ++ Network. ++ 2 ++ ++ ++ DSA_3_WORDS ++ DSA 3 Words ++ 3 ++ ++ ++ DSA_4_WORD ++ DSA 4 Words ++ 4 ++ ++ ++ ++ trunk-cscd-type ++ uint32 ++ Specifies the Cascade Trunk id. ++ 0 ++ 127 ++ ++ ++ port-trunk-cscd-type ++ enumeration ++ Specifies the cascade port type. ++ ++ cscdPort ++ Cascade port ++ 0 ++ ++ ++ cscdTrunk ++ Csacde trunk ++ 1 ++ ++ ++ ++ hash-cscd-type ++ enumeration ++ Specifies the hash used by cascade trunk. ++ ++ pkt ++ Hash based on packet ++ 0 ++ ++ ++ srcPort ++ Hash based on source port ++ 1 ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ASIC_AC5P ++ AC5P ++ 3 ++ ++ ++ ++ mpp-num-type ++ uint8 ++ Specifies the MPP pin number. ++ 0 ++ 63 ++ ++ ++ mpp-select-type ++ uint8 ++ Specifies the MPP pin value. ++ 0 ++ 15 ++ ++ ++ ASIC_AC5X ++ ES1227-54TS-32x1G-16x2.5G-6x25G ++ linux-static ++ linux-static ++ autoscan ++ external ++ pci ++ atu ++ ++ 0 ++ 0 ++ ASK-PP-ES1227-54TS.xml ++ ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++ sip6 ++ ++ 0 ++ ++ ethernet_mac ++ 0 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 0 ++ 0 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 1 ++ ++ ethernet_mac ++ 1 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 1 ++ 0 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 2 ++ ++ ethernet_mac ++ 2 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 2 ++ 0 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 3 ++ ++ ethernet_mac ++ 3 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 3 ++ 0 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 4 ++ ++ ethernet_mac ++ 4 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 4 ++ 0 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 5 ++ ++ ethernet_mac ++ 5 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 5 ++ 0 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 6 ++ ++ ethernet_mac ++ 6 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 6 ++ 0 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 7 ++ ++ ethernet_mac ++ 7 ++ false ++ ++ ++ alaska-88E1780 ++ 0 ++ 7 ++ 0 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 8 ++ ++ ethernet_mac ++ 8 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 8 ++ 0 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 9 ++ ++ ethernet_mac ++ 9 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 9 ++ 0 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 10 ++ ++ ethernet_mac ++ 10 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 10 ++ 0 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 11 ++ ++ ethernet_mac ++ 11 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 11 ++ 0 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 12 ++ ++ ethernet_mac ++ 12 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 12 ++ 0 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 13 ++ ++ ethernet_mac ++ 13 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 13 ++ 0 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 14 ++ ++ ethernet_mac ++ 14 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 14 ++ 0 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 15 ++ ++ ethernet_mac ++ 15 ++ false ++ ++ ++ alaska-88E1780 ++ 1 ++ 15 ++ 0 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 16 ++ ++ ethernet_mac ++ 16 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 16 ++ 0 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 17 ++ ++ ethernet_mac ++ 17 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 17 ++ 0 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 18 ++ ++ ethernet_mac ++ 18 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 18 ++ 0 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 19 ++ ++ ethernet_mac ++ 19 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 19 ++ 0 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 20 ++ ++ ethernet_mac ++ 20 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 20 ++ 0 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 21 ++ ++ ethernet_mac ++ 21 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 21 ++ 0 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 22 ++ ++ ethernet_mac ++ 22 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 22 ++ 0 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 23 ++ ++ ethernet_mac ++ 23 ++ false ++ ++ ++ alaska-88E1780 ++ 2 ++ 23 ++ 0 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 24 ++ ++ ethernet_mac ++ 24 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 24 ++ 0 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 25 ++ ++ ethernet_mac ++ 25 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 25 ++ 0 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 26 ++ ++ ethernet_mac ++ 26 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 26 ++ 0 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 27 ++ ++ ethernet_mac ++ 27 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 27 ++ 0 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 28 ++ ++ ethernet_mac ++ 28 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 28 ++ 0 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 29 ++ ++ ethernet_mac ++ 29 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 29 ++ 0 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 30 ++ ++ ethernet_mac ++ 30 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 30 ++ 0 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 31 ++ ++ ethernet_mac ++ 31 ++ false ++ ++ ++ alaska-88E1780 ++ 3 ++ 31 ++ 0 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 32 ++ ++ ethernet_mac ++ 33 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 1 ++ 1 ++ ++ ++ 1 ++ false ++ ++ ++ ++ 33 ++ ++ ethernet_mac ++ 32 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 0 ++ 1 ++ ++ ++ 0 ++ false ++ ++ ++ ++ 34 ++ ++ ethernet_mac ++ 35 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 3 ++ 1 ++ ++ ++ 3 ++ false ++ ++ ++ ++ 35 ++ ++ ethernet_mac ++ 34 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 2 ++ 1 ++ ++ ++ 2 ++ false ++ ++ ++ ++ 36 ++ ++ ethernet_mac ++ 37 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 5 ++ 1 ++ ++ ++ 5 ++ false ++ ++ ++ ++ 37 ++ ++ ethernet_mac ++ 36 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 4 ++ 1 ++ ++ ++ 4 ++ false ++ ++ ++ ++ 38 ++ ++ ethernet_mac ++ 39 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 7 ++ 1 ++ ++ ++ 7 ++ false ++ ++ ++ ++ 39 ++ ++ ethernet_mac ++ 38 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 6 ++ 1 ++ ++ ++ 6 ++ false ++ ++ ++ ++ 40 ++ ++ ethernet_mac ++ 41 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 9 ++ 1 ++ ++ ++ 9 ++ false ++ ++ ++ ++ 41 ++ ++ ethernet_mac ++ 40 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 8 ++ 1 ++ ++ ++ 8 ++ false ++ ++ ++ ++ 42 ++ ++ ethernet_mac ++ 43 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 11 ++ 1 ++ ++ ++ 11 ++ false ++ ++ ++ ++ 43 ++ ++ ethernet_mac ++ 42 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 10 ++ 1 ++ ++ ++ 10 ++ false ++ ++ ++ ++ 44 ++ ++ ethernet_mac ++ 45 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 13 ++ 1 ++ ++ ++ 13 ++ false ++ ++ ++ ++ 45 ++ ++ ethernet_mac ++ 44 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 12 ++ 1 ++ ++ ++ 12 ++ false ++ ++ ++ ++ 46 ++ ++ ethernet_mac ++ 47 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 15 ++ 1 ++ ++ ++ 15 ++ false ++ ++ ++ ++ 47 ++ ++ ethernet_mac ++ 46 ++ false ++ ++ ++ alaska-88E2580 ++ 0 ++ 14 ++ 1 ++ ++ ++ 14 ++ false ++ ++ ++ ++ 48 ++ ++ ethernet_mac ++ 49 ++ false ++ ++ ++ NA ++ ++ ++ 1 ++ false ++ ++ ++ ++ 49 ++ ++ ethernet_mac ++ 48 ++ false ++ ++ ++ NA ++ ++ ++ 0 ++ false ++ ++ ++ ++ 50 ++ ++ ethernet_mac ++ 51 ++ false ++ ++ ++ NA ++ ++ ++ 1 ++ false ++ ++ ++ ++ 51 ++ ++ ethernet_mac ++ 50 ++ false ++ ++ ++ NA ++ ++ ++ 0 ++ false ++ ++ ++ ++ 52 ++ ++ ethernet_mac ++ 53 ++ false ++ ++ ++ NA ++ ++ ++ 3 ++ false ++ ++ ++ ++ 53 ++ ++ ethernet_mac ++ 52 ++ false ++ ++ ++ NA ++ ++ ++ 2 ++ false ++ ++ ++ ++ 60 ++ ++ cpu_sdma ++ 55 ++ false ++ ++ ++ ++ 63 ++ ++ cpu_sdma ++ 54 ++ false ++ ++ ++ ++ 0 ++ false ++ false ++ ++ ++ 1 ++ false ++ false ++ ++ ++ 2 ++ false ++ false ++ ++ ++ 3 ++ false ++ false ++ ++ ++ 4 ++ false ++ false ++ ++ ++ 5 ++ false ++ false ++ ++ ++ 6 ++ false ++ false ++ ++ ++ 7 ++ false ++ false ++ ++ ++ 8 ++ false ++ false ++ ++ ++ 9 ++ false ++ false ++ ++ ++ 10 ++ false ++ false ++ ++ ++ 11 ++ false ++ false ++ ++ ++ 0 ++ ++ ORDER_MODE_BY_CLASS ++ BLINK_DUTY_CYCLE_1 ++ BLINK_DURATION_0 ++ BLINK_DUTY_CYCLE_1 ++ BLINK_DURATION_0 ++ PULSE_STRETCH_1 ++ false ++ 1627 ++ false ++ ++ 1 ++ 0 ++ 95 ++ false ++ ++ ++ 2 ++ 0 ++ 95 ++ false ++ ++ ++ 3 ++ 0 ++ 95 ++ false ++ ++ ++ 4 ++ 0 ++ 95 ++ false ++ ++ ++ 5 ++ 0 ++ 95 ++ false ++ ++ ++ ++ 0 ++ PORT_TYPE_XG ++ false ++ BLINK_SELECT_0 ++ true ++ 0xffffffff ++ false ++ false ++ ++ ++ 1 ++ PORT_TYPE_XG ++ false ++ BLINK_SELECT_0 ++ false ++ false ++ false ++ ++ ++ 2 ++ PORT_TYPE_XG ++ true ++ BLINK_SELECT_0 ++ false ++ true ++ true ++ ++ ++ ++ . ++ ++ 1 ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100644 +index 000000000..44fd9ed0a +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++e8294f5ddaac1c4aaca60fd1456281ba +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100644 +index 000000000..d7262231a +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-L1-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,1493 @@ ++ ++ ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ASIC_AC5P ++ AC5P ++ 3 ++ ++ ++ ++ interface-mode-type ++ enumeration ++ Specifies supported Interface modes ++ ++ 1000BASE_X ++ 1G ++ 6 ++ ++ ++ SGMII ++ 1G , 2.5G ++ 3 ++ ++ ++ QSGMII ++ 1G ++ 13 ++ ++ ++ KR ++ 10G, 12G, 20G, 40G, 100G ++ 16 ++ ++ ++ SR_LR ++ 5G, 10G, 12G, 20G, 40G ++ 20 ++ ++ ++ KR2 ++ ++ 27 ++ ++ ++ KR4 ++ ++ 28 ++ ++ ++ SR_LR2 ++ ++ 29 ++ ++ ++ SR_LR4 ++ 100G ++ 30 ++ ++ ++ KR_C ++ CONSORTIUM - 25G ++ 32 ++ ++ ++ CR_C ++ CONSORTIUM - 25G ++ 33 ++ ++ ++ KR2_C ++ CONSORTIUM - 50G ++ 34 ++ ++ ++ CR2_C ++ CONSORTIUM - 50G ++ 35 ++ ++ ++ CR ++ ++ 36 ++ ++ ++ CR2 ++ ++ 37 ++ ++ ++ CR4 ++ ++ 38 ++ ++ ++ KR_S ++ ++ 39 ++ ++ ++ CR_S ++ ++ 40 ++ ++ ++ KR8 ++ ++ 41 ++ ++ ++ CR8 ++ ++ 42 ++ ++ ++ SR_LR8 ++ ++ 43 ++ ++ ++ USX_10G_QXGMII ++ ++ 51 ++ ++ ++ USX_20G_QXGMII ++ ++ 52 ++ ++ ++ USX_OUSGMII ++ ++ 53 ++ ++ ++ USX_20G_OXGMII ++ ++ 54 ++ ++ ++ NA ++ ++ 57 ++ ++ ++ ++ port-speed-type ++ enumeration ++ Specifies supported speeds ++ ++ 1G ++ 1G ++ 2 ++ ++ ++ 10G ++ 10G ++ 3 ++ ++ ++ 2500M ++ 2.5G ++ 5 ++ ++ ++ 5G ++ 5G ++ 6 ++ ++ ++ 25G ++ 25G, used in combination with CPSS_PORT_INTERFACE_MODE_KR_E, CPSS_PORT_INTERFACE_MODE_KR2_E ++ 21 ++ ++ ++ 40G ++ 40G ++ 9 ++ ++ ++ 50G ++ 50G ++ 14 ++ ++ ++ 100G ++ 100G ++ 13 ++ ++ ++ 200G ++ 200G ++ 24 ++ ++ ++ 400G ++ 400G ++ 25 ++ ++ ++ NA ++ NA ++ 35 ++ ++ ++ ++ fec-type ++ enumeration ++ Rx parameter type ++ ++ enabled ++ Enabled ++ 0 ++ ++ ++ disabled ++ Disabled ++ 1 ++ ++ ++ rs_enabled ++ RS FEC enabled ++ 2 ++ ++ ++ both_enabled ++ Both enabled ++ 3 ++ ++ ++ rs_544_514_enabled ++ RS FEC 544 and 514 ++ 4 ++ ++ ++ ++ physical-port-num-type ++ uint32 ++ PHYSICAL PORT NUM ++ 0 ++ 1023 ++ ++ ++ rx-param-type ++ enumeration ++ Rx parameter type ++ ++ dataRate ++ dataRate ++ 0 ++ ++ ++ res1Sel ++ res1Sel ++ 1 ++ ++ ++ res2Sel ++ res2Sel ++ 2 ++ ++ ++ cap1Sel ++ cap1Sel ++ 3 ++ ++ ++ cap2Sel ++ cap2Sel ++ 4 ++ ++ ++ minCap ++ minCap ++ 5 ++ ++ ++ minCapN ++ minCapN ++ 6 ++ ++ ++ sumfBoostTargetC0 ++ sumfBoostTargetC0 ++ 7 ++ ++ ++ sumfBoostTargetC1 ++ sumfBoostTargetC1 ++ 8 ++ ++ ++ sumfBoostTargetC2 ++ sumfBoostTargetC2 ++ 9 ++ ++ ++ midpointPhaseOs0 ++ midpointPhaseOs0 ++ 10 ++ ++ ++ midpointPhaseOs1 ++ midpointPhaseOs1 ++ 11 ++ ++ ++ midpointPhaseOs2 ++ midpointPhaseOs2 ++ 12 ++ ++ ++ selmufi ++ selmufi ++ 13 ++ ++ ++ selmuff ++ selmuff ++ 14 ++ ++ ++ selmupi ++ selmupi ++ 15 ++ ++ ++ selmupf ++ selmupf ++ 16 ++ ++ ++ midpointLargeThresKLane ++ midpointLargeThresKLane ++ 17 ++ ++ ++ midpointSmallThresKLane ++ midpointSmallThresKLane ++ 18 ++ ++ ++ midpointLargeThresCLane ++ midpointLargeThresCLane ++ 19 ++ ++ ++ midpointSmallThresCLane ++ midpointSmallThresCLane ++ 20 ++ ++ ++ inxSumfMidpointAdatptiveEnLane ++ inxSumfMidpointAdatptiveEnLane ++ 21 ++ ++ ++ dfeResF0aHighThresInitLane ++ dfeResF0aHighThresInitLane ++ 22 ++ ++ ++ dfeResF0aHighThresEndLane ++ dfeResF0aHighThresEndLane ++ 23 ++ ++ ++ squelch ++ squelch ++ 24 ++ ++ ++ align90 ++ align90 ++ 25 ++ ++ ++ sampler ++ sampler ++ 26 ++ ++ ++ slewRateCtrl0 ++ slewRateCtrl0 ++ 27 ++ ++ ++ slewRateCtrl1 ++ slewRateCtrl1 ++ 28 ++ ++ ++ EO ++ EO ++ 29 ++ ++ ++ minCap1 ++ minCap1 ++ 30 ++ ++ ++ maxCap1 ++ maxCap1 ++ 31 ++ ++ ++ minRes1 ++ minRes1 ++ 32 ++ ++ ++ maxRes1 ++ maxRes1 ++ 33 ++ ++ ++ current1Sel ++ current1Sel ++ 34 ++ ++ ++ rl1Sel ++ rl1Sel ++ 35 ++ ++ ++ rl1Extra ++ rl1Extra ++ 36 ++ ++ ++ cl1Ctrl ++ cl1Ctrl ++ 37 ++ ++ ++ enMidFreq ++ enMidFreq ++ 38 ++ ++ ++ cs1Mid ++ cs1Mid ++ 39 ++ ++ ++ rs1Mid ++ rs1Mid ++ 40 ++ ++ ++ rfCtrl ++ rfCtrl ++ 41 ++ ++ ++ rl1TiaSel ++ rl1TiaSel ++ 42 ++ ++ ++ rl1TiaExtra ++ rl1TiaExtra ++ 43 ++ ++ ++ hpfRSel1st ++ hpfRSel1st ++ 44 ++ ++ ++ current1TiaSel ++ current1TiaSel ++ 45 ++ ++ ++ rl2Tune ++ rl2Tune ++ 46 ++ ++ ++ rl2Sel ++ rl2Sel ++ 47 ++ ++ ++ rs2Sel ++ rs2Sel ++ 48 ++ ++ ++ current2Sel ++ current2Sel ++ 49 ++ ++ ++ hpfRsel2nd ++ hpfRsel2nd ++ 50 ++ ++ ++ align90AnaReg ++ align90AnaReg ++ 51 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to big endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ serdes-type ++ enumeration ++ Serdes Type ++ ++ NA ++ No serdes ++ 0 ++ ++ ++ AVAGO ++ AVAGO ++ 1 ++ ++ ++ COMPHY ++ COMPHY ++ 2 ++ ++ ++ COMPHY_C12G ++ COMPHY_C12G ++ 3 ++ ++ ++ COMPHY_C28G ++ COMPHY_C28G ++ 4 ++ ++ ++ COMPHY_C112G ++ COMPHY_C112G ++ 5 ++ ++ ++ ++ phy-serdes-type ++ enumeration ++ Phy Serdes Type ++ ++ NA ++ No serdes ++ 0 ++ ++ ++ COMPHY ++ COMPHY ++ 1 ++ ++ ++ COMPHY_C28G ++ COMPHY_C28G ++ 2 ++ ++ ++ ++ port-interconnect-profile-type ++ enumeration ++ Enumerator of interconnect profile. ++ ++ profile_default ++ Profile Default ++ 0 ++ ++ ++ profile_1 ++ Profile 1 ++ 1 ++ ++ ++ profile_2 ++ Profile 2 ++ 2 ++ ++ ++ ++ ASIC_AC5X ++ ++ ++ 1000MR1 ++ ++ USX_OUSGMII ++ 1G ++ disabled ++ ++ ++ USX_OUSGMII ++ 1G ++ disabled ++ disabled ++ ++ ++ ++ 2500MR1 ++ ++ USX_20G_OXGMII ++ 2500M ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 1G ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 2500M ++ rs_enabled ++ rs_enabled ++ ++ ++ USX_20G_OXGMII ++ 1G ++ rs_enabled ++ rs_enabled ++ ++ ++ ++ 25GR1 ++ ++ SR_LR ++ 25G ++ rs_enabled ++ ++ ++ CR ++ 25G ++ rs_enabled ++ ++ ++ KR ++ 25G ++ rs_enabled ++ ++ ++ SR_LR ++ 10G ++ enabled ++ ++ ++ KR ++ 10G ++ enabled ++ ++ ++ 1000BASE_X ++ 1G ++ ++ ++ CR ++ 25G ++ rs_enabled ++ rs_enabled ++ ++ ++ KR ++ 25G ++ rs_enabled ++ rs_enabled ++ ++ ++ KR ++ 10G ++ enabled ++ enabled ++ ++ ++ 1000BASE_X ++ 1G ++ disabled ++ disabled ++ ++ ++ ++ ++ ++ 0 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 1 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 2 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 3 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 4 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 5 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 6 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 7 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 0 ++ ++ false ++ ++ ++ ++ ++ 8 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 9 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 10 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 11 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 12 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 13 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 14 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 15 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 1 ++ ++ false ++ ++ ++ ++ ++ 16 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 17 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 18 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 19 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 20 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 21 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 22 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 23 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 2 ++ ++ false ++ ++ ++ ++ ++ 24 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 25 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 26 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 27 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 28 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 29 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 30 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 31 ++ COMPHY_C28G ++ NA ++ profile_default ++ 1000MR1 ++ false ++ ++ 3 ++ ++ false ++ ++ ++ ++ ++ 32 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 33 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 34 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 35 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 36 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 37 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 38 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 39 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 4 ++ ++ false ++ ++ ++ ++ ++ 40 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 41 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 42 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 43 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 44 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 45 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 46 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 47 ++ COMPHY_C28G ++ NA ++ profile_default ++ 2500MR1 ++ false ++ ++ 5 ++ ++ false ++ ++ ++ ++ ++ 48 ++ COMPHY_C28G ++ NA ++ profile_default ++ 25GR1 ++ false ++ ++ 0 ++ ++ true ++ 8 ++ 8 ++ 2 ++ ++ ++ ++ ++ 49 ++ COMPHY_C28G ++ NA ++ profile_default ++ 25GR1 ++ false ++ ++ 0 ++ ++ true ++ 8 ++ 8 ++ 2 ++ ++ ++ ++ ++ 50 ++ COMPHY_C28G ++ NA ++ profile_default ++ 25GR1 ++ false ++ ++ 0 ++ ++ true ++ 8 ++ 8 ++ 2 ++ ++ ++ ++ ++ 51 ++ COMPHY_C28G ++ NA ++ profile_default ++ 25GR1 ++ false ++ ++ 0 ++ ++ true ++ 8 ++ 8 ++ 2 ++ ++ ++ ++ ++ 52 ++ COMPHY_C28G ++ NA ++ profile_default ++ 25GR1 ++ false ++ ++ 0 ++ ++ true ++ 8 ++ 8 ++ 2 ++ ++ ++ ++ ++ 53 ++ COMPHY_C28G ++ NA ++ profile_default ++ 25GR1 ++ false ++ ++ 0 ++ ++ true ++ 8 ++ 8 ++ 2 ++ ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.md5 b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.md5 +new file mode 100755 +index 000000000..f2c340a08 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.md5 +@@ -0,0 +1 @@ ++3010be072d1acf56947d57f43204dd3b +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.xml b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.xml +new file mode 100755 +index 000000000..4d2de0b5b +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/ASK-PP-ES1227-54TS.xml +@@ -0,0 +1,896 @@ ++ ++ ++ ++ ++ ++ std-string ++ string ++ standard string. ++ 1 ++ 100 ++ ++ ++ queue-id-type ++ uint32 ++ Queue id ++ 0 ++ 7 ++ ++ ++ precent-type ++ uint32 ++ Precent ++ 0 ++ 100 ++ ++ ++ phaThreadId-type ++ uint32 ++ Thread id ++ 1 ++ 255 ++ ++ ++ routing-mode-type ++ enumeration ++ Specifies routing mode. ++ ++ POLICY_BASED_ROUTING_ONLY ++ PBR only ++ 0 ++ ++ ++ TCAM_ROUTER_BASED ++ Router engine or PBR ++ 1 ++ ++ ++ ++ shared-table-mode-type ++ enumeration ++ Specifies table sharing modes for L3 (LPM), L2 (FDB), EM (Exact Match) ++ ++ MID_L3_MID_L2_NO_EM ++ MID_L3_MID_L2_NO_EM ++ 0 ++ ++ ++ MID_L3_MID_L2_MIN_EM ++ MID_L3_MID_L2_MIN_EM ++ 1 ++ ++ ++ LOW_MAX_L3_MID_LOW_L2_NO_EM ++ LOW_MAX_L3_MID_LOW_L2_NO_EM ++ 2 ++ ++ ++ MAX_L3_MIN_L2_NO_EM ++ MAX_L3_MIN_L2_NO_EM ++ 3 ++ ++ ++ ++ pha-firmware-image-id-type ++ enumeration ++ Specifies supported Pha image id ++ ++ DEFAULT ++ Default PHA firmware image ID ++ 0 ++ ++ ++ 01 ++ 01 firmware image ID ++ 1 ++ ++ ++ 02 ++ 02 PHA firmware image ID ++ 2 ++ ++ ++ ++ pha-firmware-thread-type ++ enumeration ++ Specifies supported Pha thread type ++ ++ IOAM_INGRESS_SWITCH_IPV4 ++ IOAM_INGRESS_SWITCH_IPV4 ++ 1 ++ ++ ++ IOAM_INGRESS_SWITCH_IPV6 ++ IOAM_INGRESS_SWITCH_IPV6 ++ 2 ++ ++ ++ IOAM_TRANSIT_SWITCH_IPV4 ++ IOAM_TRANSIT_SWITCH_IPV4 ++ 3 ++ ++ ++ IOAM_TRANSIT_SWITCH_IPV6 ++ IOAM_TRANSIT_SWITCH_IPV6 ++ 4 ++ ++ ++ INT_IOAM_MIRRORING ++ INT_IOAM_MIRRORING ++ 5 ++ ++ ++ INT_IOAM_EGRESS_SWITCH ++ INT_IOAM_EGRESS_SWITCH ++ 6 ++ ++ ++ MPLS_SR_NO_EL ++ MPLS_SR_NO_EL ++ 7 ++ ++ ++ MPLS_SR_ONE_EL ++ MPLS_SR_ONE_EL ++ 8 ++ ++ ++ MPLS_SR_TWO_EL ++ MPLS_SR_TWO_EL ++ 9 ++ ++ ++ MPLS_SR_THREE_EL ++ MPLS_SR_THREE_EL ++ 10 ++ ++ ++ UNIFIED_SR ++ UNIFIED_SR ++ 11 ++ ++ ++ CLASSIFIER_NSH_OVER_ETHERNET ++ CLASSIFIER_NSH_OVER_ETHERNET ++ 12 ++ ++ ++ CLASSIFIER_NSH_OVER_VXLAN_GPE ++ CLASSIFIER_NSH_OVER_VXLAN_GPE ++ 13 ++ ++ ++ SFF_NSH_VXLAN_GPE_TO_ETHERNET ++ SFF_NSH_VXLAN_GPE_TO_ETHERNET ++ 14 ++ ++ ++ SFF_NSH_ETHERNET_TO_VXLAN_GPE ++ SFF_NSH_ETHERNET_TO_VXLAN_GPE ++ 15 ++ ++ ++ IOAM_EGRESS_SWITCH_IPV6 ++ IOAM_EGRESS_SWITCH_IPV6 ++ 16 ++ ++ ++ SRV6_END_NODE ++ SRV6_END_NODE ++ 17 ++ ++ ++ SRV6_PENULTIMATE_END_NODE ++ SRV6_PENULTIMATE_END_NODE ++ 18 ++ ++ ++ SRV6_SRC_NODE_1_SEGMENT ++ SRV6_SRC_NODE_1_SEGMENT ++ 19 ++ ++ ++ SRV6_SRC_NODE_FIRST_PASS_2_3_SEGMENTS ++ SRV6_SRC_NODE_FIRST_PASS_2_3_SEGMENTS ++ 20 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_3_SEGMENTS ++ SRV6_SRC_NODE_SECOND_PASS_3_SEGMENTS ++ 21 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_2_SEGMENTS ++ SRV6_SRC_NODE_SECOND_PASS_2_SEGMENTS ++ 22 ++ ++ ++ SGT_NETWORK_ADD_MSB ++ SGT_NETWORK_ADD_MSB ++ 23 ++ ++ ++ SGT_NETWORK_FIX ++ SGT_NETWORK_FIX ++ 24 ++ ++ ++ SGT_NETWORK_REMOVE ++ SGT_NETWORK_REMOVE ++ 25 ++ ++ ++ SGT_EDSA_FIX ++ SGT_EDSA_FIX ++ 26 ++ ++ ++ SGT_EDSA_REMOVE ++ SGT_EDSA_REMOVE ++ 27 ++ ++ ++ SGT_GBP_FIX_IPV4 ++ SGT_GBP_FIX_IPV4 ++ 28 ++ ++ ++ SGT_GBP_FIX_IPV6 ++ SGT_GBP_FIX_IPV6 ++ 29 ++ ++ ++ SGT_GBP_REMOVE_IPV4 ++ SGT_GBP_REMOVE_IPV4 ++ 30 ++ ++ ++ SGT_GBP_REMOVE_IPV6 ++ SGT_GBP_REMOVE_IPV6 ++ 31 ++ ++ ++ PTP_PHY_1_STEP ++ PTP_PHY_1_STEP ++ 32 ++ ++ ++ EGRESS_MIRRORING_METADATA ++ EGRESS_MIRRORING_METADATA ++ 33 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV4 ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV4 ++ 34 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV6 ++ CC_ERSPAN_TYPE_II_TRG_DEV_LC_IPV6 ++ 35 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV4 ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV4 ++ 36 ++ ++ ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV6 ++ CC_ERSPAN_TYPE_II_TRG_DEV_DIRECT_IPV6 ++ 37 ++ ++ ++ CC_ERSPAN_TYPE_II_SRC_DEV ++ CC_ERSPAN_TYPE_II_SRC_DEV ++ 38 ++ ++ ++ VXLAN_GBP_SOURCE_GROUP_POLICY_ID ++ VXLAN_GBP_SOURCE_GROUP_POLICY_ID ++ 39 ++ ++ ++ SRV6_BEST_EFFORT ++ SRV6_BEST_EFFORT ++ 40 ++ ++ ++ SRV6_SRC_NODE_1_CONTAINER ++ SRV6_SRC_NODE_1_CONTAINER ++ 41 ++ ++ ++ SRV6_SRC_NODE_FIRST_PASS_2_3_CONTAINERS ++ SRV6_SRC_NODE_FIRST_PASS_2_3_CONTAINERS ++ 42 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_2_CONTAINERS ++ SRV6_SRC_NODE_SECOND_PASS_2_CONTAINERS ++ 43 ++ ++ ++ SRV6_SRC_NODE_SECOND_PASS_3_CONTAINERS ++ SRV6_SRC_NODE_SECOND_PASS_3_CONTAINERS ++ 44 ++ ++ ++ SRV6_END_NODE_COC32_GSID ++ SRV6_END_NODE_COC32_GSID ++ 45 ++ ++ ++ IPV4_TTL_INCREMENT ++ IPV4_TTL_INCREMENT ++ 46 ++ ++ ++ IPV6_HOP_LIMIT_INCREMENT ++ IPV6_HOP_LIMIT_INCREMENT ++ 47 ++ ++ ++ CLEAR_OUTGOING_MTAG_COMMAND ++ CLEAR_OUTGOING_MTAG_COMMAND ++ 48 ++ ++ ++ SFLOW_V5_IPV4 ++ SFLOW_V5_IPV4 ++ 49 ++ ++ ++ SFLOW_V5_IPV6 ++ SFLOW_V5_IPV6 ++ 50 ++ ++ ++ SLS ++ SLS ++ 51 ++ ++ ++ ++ trunk-member-mode-type ++ enumeration ++ Specifies supported Pha image id ++ ++ NATIVE ++ NATIVE ++* the trunk members are filled ++* according to the order given by application. ++* Regular trunk may hold max of 8 members. ++* Cascade trunk may hold : ++* max of 64 members ++ 0 ++ ++ ++ FLEX ++ FLEX ++* A mode to allows flexibility for ++* each Regular trunk to state it's max number of members (before starting to add members). ++* (this mode not effect 'cascade trunk' members) ++* Regular trunk may hold : max of 4K members. (each trunk set it's own limit) ++* Cascade trunk may hold : max of 64 members. ++ 2 ++ ++ ++ ++ number-physical-port-type ++ enumeration ++ AC3X/AC5X/AC5P 128, falcon 64, 128, 256, 512, 1024 ++ ++ no-ports ++ no-ports ++ 0 ++ ++ ++ 64-ports ++ 64-ports ++ 64 ++ ++ ++ 128-ports ++ 128-ports ++ 128 ++ ++ ++ 256-ports ++ 256-ports ++ 256 ++ ++ ++ 512-ports ++ 512-ports ++ 512 ++ ++ ++ 1024-ports ++ 1024-ports ++ 1024 ++ ++ ++ ++ serdes-ref-clock-type ++ enumeration ++ Specifies serdes refernce clock. ++ ++ external_25_single_ended ++ EXTERNAL_25_SINGLE_ENDED ++ 0 ++ ++ ++ external_125_single_ended ++ EXTERNAL_125_SINGLE_ENDED ++ 1 ++ ++ ++ external_125_diff ++ EXTERNAL_125_DIFF ++ 2 ++ ++ ++ external_156_25_single_ended ++ EXTERNAL_156_25_SINGLE_ENDED ++ 3 ++ ++ ++ external_156_25_diff ++ EXTERNAL_156_25_DIFF ++ 4 ++ ++ ++ internal_125 ++ INTERNAL_125 ++ 5 ++ ++ ++ ++ cpu-port-id-type ++ uint32 ++ CPU port id ++ 0 ++ 7 ++ ++ ++ rx-buffer-size-type ++ uint32 ++ Rx Buffer size ++ 64 ++ 10240 ++ ++ ++ tx-sdma-queue-mode-type ++ enumeration ++ Specifies TX queue mode. ++ ++ Normal ++ Application ++ 0 ++ ++ ++ Packet_Generator ++ Traffic generator ++ 1 ++ ++ ++ ++ alloc-method-type ++ enumeration ++ Specifies Buffers allocation method. ++ ++ Dynamic_Alloc ++ Dynamic ++ 0 ++ ++ ++ Static_Alloc ++ Static ++ 1 ++ ++ ++ ++ au_mesage_lenght-type ++ enumeration ++ Specifies Buffers allocation method. ++ ++ 4_words ++ 4 Words ++ 0 ++ ++ ++ 8_words ++ 8 Words ++ 1 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ASIC_AC5P ++ AC5P ++ 3 ++ ++ ++ ++ ASIC_AC5X ++ ++ AC5X-RD ++ ++ 4294967295 ++ external_25_single_ended ++ 2 ++ 60 ++ 128-ports ++ false ++ false ++ 0 ++ ++ ++ true ++ ++ 4096 ++ ++ ++ 2048 ++ ++ ++ ++ 0 ++ 0 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 7 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 6 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 5 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 4 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 3 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 2 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 1 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 1 ++ 0 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 7 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 6 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 5 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 4 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 3 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 2 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 1 ++ Static_Alloc ++ 20 ++ 20 ++ 2048 ++ 0 ++ ++ ++ 0 ++ 0 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 1 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 2 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 3 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 4 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 5 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 6 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 0 ++ 7 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 0 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 1 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 2 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 3 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 4 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 5 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 6 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ 1 ++ 7 ++ Static_Alloc ++ Normal ++ 20 ++ 0 ++ 128 ++ ++ ++ ++ false ++ false ++ false ++ 0 ++ 8_words ++ false ++ ++ ++ ++ TCAM_ROUTER_BASED ++ 0 ++ true ++ ++ ++ true ++ true ++ true ++ true ++ true ++ true ++ ++ 511 ++ FLEX ++ ++ true ++ true ++ true ++ true ++ ++ false ++ 01 ++ 0 ++ ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +new file mode 100755 +index 000000000..85b36413c +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.md5 +@@ -0,0 +1 @@ ++04f31871ede105d525d4da489cdc447e +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +new file mode 100755 +index 000000000..70906bf1c +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml +@@ -0,0 +1,536 @@ ++ ++ ++ ++ ++ ++ device-id-type ++ uint32 ++ Device ID 0..1 ++ 0 ++ 1 ++ ++ ++ port-id-type ++ uint32 ++ Interface number ++ 0 ++ 1023 ++ ++ ++ logDest-type ++ enumeration ++ Logging Feature Options ++ ++ SAI_LOG_SYSLOG ++ SYSLOG {Syslog service should be running to use this option} ++ 0 ++ ++ ++ SAI_LOG_CONSOLE ++ CONSOLE ++ 1 ++ ++ ++ SAI_LOG_FILE ++ FILE {Warning !!! Use with caution. Can cause disk full issues} ++ 2 ++ ++ ++ ++ InDropCounter-type ++ enumeration ++ Router In Drop Reason Feature Options ++ ++ TTL_HOPLIMIT_EXCEEDED ++ Router In Drop Counters track TTL & Hop Limit Exceeded Packets ++ 0 ++ ++ ++ ROUTE_BLACKHOLE ++ Router In Drop Counters track Route Black Hole Packets ++ 1 ++ ++ ++ ++ Feature-enable ++ enumeration ++ Feature Enabled/Disabled ++ ++ Disabled ++ Disabled ++ 0 ++ ++ ++ Enabled ++ Enabled ++ 1 ++ ++ ++ ++ log-dest-file-path-type ++ string ++ A string with path to file for logging feature ++ 2 ++ 30 ++ ++ ++ acl-feature-name-type ++ enumeration ++ ++ ++ port-sFlow ++ SFlow over Port ++ 0 ++ ++ ++ port-counters-ipv4-ipv6 ++ Port ipv4/ipv6 counters ++ 1 ++ ++ ++ control-acl ++ ACLs for control packet handling ++ 2 ++ ++ ++ debug-counter-acl ++ ACLs for Debug Counters ++ 3 ++ ++ ++ ++ ingress-acl-stage-type ++ enumeration ++ ++ ++ disabled ++ Feature not enabled ++ 0 ++ ++ ++ IPCL0 ++ Stage IPCL0 ++ 1 ++ ++ ++ IPCL1 ++ Stage IPCL1 ++ 2 ++ ++ ++ ++ egress-acl-stage-type ++ enumeration ++ ++ ++ disabled ++ Feature not enabled ++ 0 ++ ++ ++ EPCL0 ++ Stage EPCL0 ++ 2 ++ ++ ++ ++ feature-priority-type ++ uint32 ++ Feature priority ++ 2 ++ 15 ++ ++ ++ hit-number-type ++ uint32 ++ Hit/lookup number ++ 0 ++ 3 ++ ++ ++ asic-type ++ enumeration ++ ASIC Type ++ ++ ASIC_AC3X ++ AC3X ++ 0 ++ ++ ++ ASIC_AC5X ++ AC5X ++ 1 ++ ++ ++ ASIC_Falcon ++ FALCON ++ 2 ++ ++ ++ ASIC_AC5P ++ AC5P ++ 3 ++ ++ ++ ++ boolean-type ++ enumeration ++ Boolean 32 bits , due to bing endian ++ ++ false ++ False ++ 0 ++ ++ ++ true ++ True ++ 1 ++ ++ ++ ++ ASIC_AC5X ++ ASK-Board-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++ ++ ++ 0 ++ 0 ++ 0 ++ ++ ++ 1 ++ 0 ++ 1 ++ ++ ++ 2 ++ 0 ++ 2 ++ ++ ++ 3 ++ 0 ++ 3 ++ ++ ++ 4 ++ 0 ++ 4 ++ ++ ++ 5 ++ 0 ++ 5 ++ ++ ++ 6 ++ 0 ++ 6 ++ ++ ++ 7 ++ 0 ++ 7 ++ ++ ++ 8 ++ 0 ++ 8 ++ ++ ++ 9 ++ 0 ++ 9 ++ ++ ++ 10 ++ 0 ++ 10 ++ ++ ++ 11 ++ 0 ++ 11 ++ ++ ++ 12 ++ 0 ++ 12 ++ ++ ++ 13 ++ 0 ++ 13 ++ ++ ++ 14 ++ 0 ++ 14 ++ ++ ++ 15 ++ 0 ++ 15 ++ ++ ++ 16 ++ 0 ++ 16 ++ ++ ++ 17 ++ 0 ++ 17 ++ ++ ++ 18 ++ 0 ++ 18 ++ ++ ++ 19 ++ 0 ++ 19 ++ ++ ++ 20 ++ 0 ++ 20 ++ ++ ++ 21 ++ 0 ++ 21 ++ ++ ++ 22 ++ 0 ++ 22 ++ ++ ++ 23 ++ 0 ++ 23 ++ ++ ++ 24 ++ 0 ++ 24 ++ ++ ++ 25 ++ 0 ++ 25 ++ ++ ++ 26 ++ 0 ++ 26 ++ ++ ++ 27 ++ 0 ++ 27 ++ ++ ++ 28 ++ 0 ++ 28 ++ ++ ++ 29 ++ 0 ++ 29 ++ ++ ++ 30 ++ 0 ++ 30 ++ ++ ++ 31 ++ 0 ++ 31 ++ ++ ++ 32 ++ 0 ++ 32 ++ ++ ++ 33 ++ 0 ++ 33 ++ ++ ++ 34 ++ 0 ++ 34 ++ ++ ++ 35 ++ 0 ++ 35 ++ ++ ++ 36 ++ 0 ++ 36 ++ ++ ++ 37 ++ 0 ++ 37 ++ ++ ++ 38 ++ 0 ++ 38 ++ ++ ++ 39 ++ 0 ++ 39 ++ ++ ++ 40 ++ 0 ++ 40 ++ ++ ++ 41 ++ 0 ++ 41 ++ ++ ++ 42 ++ 0 ++ 42 ++ ++ ++ 43 ++ 0 ++ 43 ++ ++ ++ 44 ++ 0 ++ 44 ++ ++ ++ 45 ++ 0 ++ 45 ++ ++ ++ 46 ++ 0 ++ 46 ++ ++ ++ 47 ++ 0 ++ 47 ++ ++ ++ 48 ++ 0 ++ 48 ++ ++ ++ 49 ++ 0 ++ 49 ++ ++ ++ 50 ++ 0 ++ 50 ++ ++ ++ 51 ++ 0 ++ 51 ++ ++ ++ 52 ++ 0 ++ 52 ++ ++ ++ 53 ++ 0 ++ 53 ++ ++ ++ ++ 8 ++ 0 ++ 0 ++ 64 ++ 8 ++ 8 ++ 1024 ++ ++ ++ 0 ++ ROUTE_BLACKHOLE ++ ++ Disabled ++ Disabled ++ ++ ++ ++ SAI_LOG_CONSOLE ++ ++ ++ Disabled ++ Disabled ++ ++ ++ control-acl ++ 3 ++ ++ IPCL0 ++ 1 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ port-sFlow ++ 4 ++ ++ IPCL0 ++ 0 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ port-counters-ipv4-ipv6 ++ 5 ++ ++ IPCL0 ++ 3 ++ ++ ++ EPCL0 ++ 0 ++ ++ ++ ++ debug-counter-acl ++ 2 ++ ++ disabled ++ ++ ++ disabled ++ ++ ++ ++ +\ No newline at end of file +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/hwsku.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/hwsku.json +new file mode 100644 +index 000000000..e1a5b7980 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/hwsku.json +@@ -0,0 +1,322 @@ ++{ ++ "interfaces": { ++ "Ethernet0": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet1": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet2": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet3": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet4": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet5": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet6": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet7": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet8": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet9": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet10": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet11": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet12": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet13": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet14": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet15": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet16": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet17": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet18": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet19": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet20": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet21": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet22": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet23": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet24": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet25": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet26": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet27": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet28": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet29": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet30": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet31": { ++ "default_brkout_mode": "1x1000[100,10]", ++ "fec" : "none", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet32": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet33": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet34": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet35": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet36": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet37": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet38": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet39": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet40": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet41": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet42": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet43": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet44": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet45": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet46": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet47": { ++ "default_brkout_mode": "1x2500[1000,100]", ++ "fec" : "rs", ++ "autoneg" : "on", ++ "port_type": "RJ45" ++ }, ++ "Ethernet48": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet49": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet50": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet51": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet52": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ }, ++ "Ethernet53": { ++ "default_brkout_mode": "1x25G[10G]", ++ "fec" : "none", ++ "autoneg" : "off" ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/media_settings.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/media_settings.json +new file mode 100644 +index 000000000..e1efb2de9 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/media_settings.json +@@ -0,0 +1,28 @@ ++{ ++ "GLOBAL_MEDIA_SETTINGS": { ++ "49-54": { ++ "MELLANOX": { ++ "pre1": { ++ "lane0":"0x8" ++ }, ++ "main": { ++ "lane0":"0x8" ++ }, ++ "post1": { ++ "lane0":"0x2" ++ } ++ }, ++ "Default": { ++ "pre1": { ++ "lane0":"0x8" ++ }, ++ "main": { ++ "lane0":"0x8" ++ }, ++ "post1": { ++ "lane0":"0x2" ++ } ++ } ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/poe_default_cfg.json b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/poe_default_cfg.json +new file mode 100755 +index 000000000..15e6f8c84 +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/poe_default_cfg.json +@@ -0,0 +1,382 @@ ++{ ++ "PORT": { ++ "Ethernet0": { ++ "lanes": "0", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet1": { ++ "lanes": "1", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet2": { ++ "lanes": "2", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet3": { ++ "lanes": "3", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet4": { ++ "lanes": "4", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet5": { ++ "lanes": "5", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet6": { ++ "lanes": "6", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet7": { ++ "lanes": "7", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet8": { ++ "lanes": "8", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet9": { ++ "lanes": "9", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet10": { ++ "lanes": "10", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet11": { ++ "lanes": "11", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet12": { ++ "lanes": "12", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet13": { ++ "lanes": "13", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet14": { ++ "lanes": "14", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet15": { ++ "lanes": "15", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet16": { ++ "lanes": "16", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet17": { ++ "lanes": "17", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet18": { ++ "lanes": "18", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet19": { ++ "lanes": "19", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet20": { ++ "lanes": "20", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet21": { ++ "lanes": "21", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet22": { ++ "lanes": "22", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet23": { ++ "lanes": "23", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet24": { ++ "lanes": "24", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet25": { ++ "lanes": "25", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet26": { ++ "lanes": "26", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet27": { ++ "lanes": "27", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet28": { ++ "lanes": "28", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet29": { ++ "lanes": "29", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet30": { ++ "lanes": "30", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet31": { ++ "lanes": "31", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet32": { ++ "lanes": "32", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet33": { ++ "lanes": "33", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet34": { ++ "lanes": "34", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet35": { ++ "lanes": "35", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet36": { ++ "lanes": "36", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet37": { ++ "lanes": "37", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet38": { ++ "lanes": "38", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet39": { ++ "lanes": "39", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet40": { ++ "lanes": "40", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet41": { ++ "lanes": "41", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet42": { ++ "lanes": "42", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet43": { ++ "lanes": "43", ++ "poe_pri": "low", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet44": { ++ "lanes": "44", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet45": { ++ "lanes": "45", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet46": { ++ "lanes": "46", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet47": { ++ "lanes": "47", ++ "poe_pri": "critical", ++ "poe_status": "enableDynamic", ++ "poe_maxpower": "0", ++ "poe_tlv": "disable" ++ }, ++ "Ethernet48": { ++ "lanes": "48", ++ "poe_pri": "NA", ++ "poe_status": "NA", ++ "poe_maxpower": "0", ++ "poe_tlv": "NA" ++ }, ++ "Ethernet49": { ++ "lanes": "49", ++ "poe_pri": "NA", ++ "poe_status": "NA", ++ "poe_maxpower": "0", ++ "poe_tlv": "NA" ++ }, ++ "Ethernet50": { ++ "lanes": "50", ++ "poe_pri": "NA", ++ "poe_status": "NA", ++ "poe_maxpower": "0", ++ "poe_tlv": "NA" ++ }, ++ "Ethernet51": { ++ "lanes": "51", ++ "poe_pri": "NA", ++ "poe_status": "NA", ++ "poe_maxpower": "0", ++ "poe_tlv": "NA" ++ }, ++ "Ethernet52": { ++ "lanes": "52", ++ "poe_pri": "NA", ++ "poe_status": "NA", ++ "poe_maxpower": "0", ++ "poe_tlv": "NA" ++ }, ++ "Ethernet53": { ++ "lanes": "52", ++ "poe_pri": "NA", ++ "poe_status": "NA", ++ "poe_maxpower": "0", ++ "poe_tlv": "NA" ++ } ++ } ++} +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/port_config.ini b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/port_config.ini +new file mode 100644 +index 000000000..0351411bf +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/port_config.ini +@@ -0,0 +1,55 @@ ++# name lanes alias speed autoneg fec index poe_pri poe_status poe_maxpower poe_tlv ++Ethernet0 0 Eth1 1000 on none 1 critical enableDynamic 0 disable ++Ethernet1 1 Eth2 1000 on none 2 critical enableDynamic 0 disable ++Ethernet2 2 Eth3 1000 on none 3 critical enableDynamic 0 disable ++Ethernet3 3 Eth4 1000 on none 4 critical enableDynamic 0 disable ++Ethernet4 4 Eth5 1000 on none 5 low enableDynamic 0 disable ++Ethernet5 5 Eth6 1000 on none 6 low enableDynamic 0 disable ++Ethernet6 6 Eth7 1000 on none 7 low enableDynamic 0 disable ++Ethernet7 7 Eth8 1000 on none 8 low enableDynamic 0 disable ++Ethernet8 8 Eth9 1000 on none 9 low enableDynamic 0 disable ++Ethernet9 9 Eth10 1000 on none 10 low enableDynamic 0 disable ++Ethernet10 10 Eth11 1000 on none 11 low enableDynamic 0 disable ++Ethernet11 11 Eth12 1000 on none 12 low enableDynamic 0 disable ++Ethernet12 12 Eth13 1000 on none 13 low enableDynamic 0 disable ++Ethernet13 13 Eth14 1000 on none 14 low enableDynamic 0 disable ++Ethernet14 14 Eth15 1000 on none 15 low enableDynamic 0 disable ++Ethernet15 15 Eth16 1000 on none 16 low enableDynamic 0 disable ++Ethernet16 16 Eth17 1000 on none 17 low enableDynamic 0 disable ++Ethernet17 17 Eth18 1000 on none 18 low enableDynamic 0 disable ++Ethernet18 18 Eth19 1000 on none 19 low enableDynamic 0 disable ++Ethernet19 19 Eth20 1000 on none 20 low enableDynamic 0 disable ++Ethernet20 20 Eth21 1000 on none 21 low enableDynamic 0 disable ++Ethernet21 21 Eth22 1000 on none 22 low enableDynamic 0 disable ++Ethernet22 22 Eth23 1000 on none 23 low enableDynamic 0 disable ++Ethernet23 23 Eth24 1000 on none 24 low enableDynamic 0 disable ++Ethernet24 24 Eth25 1000 on none 25 low enableDynamic 0 disable ++Ethernet25 25 Eth26 1000 on none 26 low enableDynamic 0 disable ++Ethernet26 26 Eth27 1000 on none 27 low enableDynamic 0 disable ++Ethernet27 27 Eth28 1000 on none 28 low enableDynamic 0 disable ++Ethernet28 28 Eth29 1000 on none 29 low enableDynamic 0 disable ++Ethernet29 29 Eth30 1000 on none 30 low enableDynamic 0 disable ++Ethernet30 30 Eth31 1000 on none 31 low enableDynamic 0 disable ++Ethernet31 31 Eth32 1000 on none 32 low enableDynamic 0 disable ++Ethernet32 32 Eth33 2500 on rs 33 low enableDynamic 0 disable ++Ethernet33 33 Eth34 2500 on rs 34 low enableDynamic 0 disable ++Ethernet34 34 Eth35 2500 on rs 35 low enableDynamic 0 disable ++Ethernet35 35 Eth36 2500 on rs 36 low enableDynamic 0 disable ++Ethernet36 36 Eth37 2500 on rs 37 low enableDynamic 0 disable ++Ethernet37 37 Eth38 2500 on rs 38 low enableDynamic 0 disable ++Ethernet38 38 Eth39 2500 on rs 39 low enableDynamic 0 disable ++Ethernet39 39 Eth40 2500 on rs 40 low enableDynamic 0 disable ++Ethernet40 40 Eth41 2500 on rs 41 low enableDynamic 0 disable ++Ethernet41 41 Eth42 2500 on rs 42 low enableDynamic 0 disable ++Ethernet42 42 Eth43 2500 on rs 43 low enableDynamic 0 disable ++Ethernet43 43 Eth44 2500 on rs 44 low enableDynamic 0 disable ++Ethernet44 44 Eth45 2500 on rs 45 critical enableDynamic 0 disable ++Ethernet45 45 Eth46 2500 on rs 46 critical enableDynamic 0 disable ++Ethernet46 46 Eth47 2500 on rs 47 critical enableDynamic 0 disable ++Ethernet47 47 Eth48 2500 on rs 48 critical enableDynamic 0 disable ++Ethernet48 48 Eth49 25000 off none 49 NA NA 0 NA ++Ethernet49 49 Eth50 25000 off none 50 NA NA 0 NA ++Ethernet50 50 Eth51 25000 off none 51 NA NA 0 NA ++Ethernet51 51 Eth52 25000 off none 52 NA NA 0 NA ++Ethernet52 52 Eth53 25000 off none 53 NA NA 0 NA ++Ethernet53 53 Eth54 25000 off none 54 NA NA 0 NA +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/profile.ini b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/profile.ini +new file mode 100644 +index 000000000..c2f77685a +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/profile.ini +@@ -0,0 +1 @@ ++switchMacAddress=00:01:02:03:04:05 +diff --git a/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/sai.profile b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/sai.profile +new file mode 100755 +index 000000000..938b288ad +--- /dev/null ++++ b/device/wistron/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/sai.profile +@@ -0,0 +1,4 @@ ++mode=1 ++hwId=AC5XRD ++switchProfile=/usr/share/sonic/hwsku/SAI-ES1227-54TS-32x1G-16x2_5G-6x25G.xml ++SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/profile.ini +diff --git a/platform/marvell-prestera/platform-wistron.dep b/platform/marvell-prestera/platform-wistron.dep +new file mode 100644 +index 000000000..7ed0bcf46 +--- /dev/null ++++ b/platform/marvell-prestera/platform-wistron.dep +@@ -0,0 +1,8 @@ ++MPATH := $($(WISTRON_ES1227_PLATFORM)_SRC_PATH) ++DEP_FILES := $(SONIC_COMMON_FILES_LIST) $(PLATFORM_PATH)/platform-wistron.mk $(PLATFORM_PATH)/platform-wistron.dep ++DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) ++DEP_FILES += $(shell git ls-files $(MPATH)) ++ ++$(WISTRON_ES1227_PLATFORM)_CACHE_MODE := GIT_CONTENT_SHA ++$(WISTRON_ES1227_PLATFORM)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) ++$(WISTRON_ES1227_PLATFORM)_DEP_FILES := $(DEP_FILES) +diff --git a/platform/marvell-prestera/platform-wistron.mk b/platform/marvell-prestera/platform-wistron.mk +new file mode 100644 +index 000000000..91773924b +--- /dev/null ++++ b/platform/marvell-prestera/platform-wistron.mk +@@ -0,0 +1,26 @@ ++ ++WISTRON_ES1227_VERSION=0.1 ++WISTRON_ES2227_VERSION=0.1 ++WISTRON_ES2227_P_VERSION=0.1 ++ ++export WISTRON_ES1227_VERSION ++export WISTRON_ES2227_VERSION ++export WISTRON_ES2227_p_VERSION ++ ++#ES-1227-54TS ++WISTRON_ES1227_PLATFORM = sonic-platform-es1227-54ts_$(WISTRON_ES1227_VERSION)_$(CONFIGURED_ARCH).deb ++$(WISTRON_ES1227_PLATFORM)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-wistron ++$(WISTRON_ES1227_PLATFORM)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) ++$(WISTRON_ES1227_PLATFORM)_PLATFORM = arm64-wistron_es1227_54ts-r0 ++SONIC_DPKG_DEBS += $(WISTRON_ES1227_PLATFORM) ++ ++#ES-2227-54TS ++WISTRON_ES2227_PLATFORM = sonic-platform-es2227-54ts_$(WISTRON_ES2227_VERSION)_$(CONFIGURED_ARCH).deb ++$(WISTRON_ES2227_PLATFORM)_PLATFORM = arm64-wistron_es2227_54ts-r0 ++ ++#ES-2227-54TS_P ++WISTRON_ES2227_P_PLATFORM = sonic-platform-es2227-54ts-p_$(WISTRON_ES2227_P_VERSION)_$(CONFIGURED_ARCH).deb ++$(WISTRON_ES2227_P_PLATFORM)_PLATFORM = arm64-wistron_es2227_54ts_p-r0 ++ ++$(eval $(call add_extra_package,$(WISTRON_ES1227_PLATFORM),$(WISTRON_ES2227_PLATFORM))) ++$(eval $(call add_extra_package,$(WISTRON_ES1227_PLATFORM),$(WISTRON_ES2227_P_PLATFORM))) +diff --git a/platform/marvell-prestera/rules.dep b/platform/marvell-prestera/rules.dep +index c31677b4a..f88d1054c 100644 +--- a/platform/marvell-prestera/rules.dep ++++ b/platform/marvell-prestera/rules.dep +@@ -7,5 +7,6 @@ include $(PLATFORM_PATH)/platform-marvell.dep + ifeq ($(CONFIGURED_ARCH),$(filter $(CONFIGURED_ARCH),arm64 armhf)) + include $(PLATFORM_PATH)/mrvl-prestera.dep + include $(PLATFORM_PATH)/platform-nokia.dep ++include $(PLATFORM_PATH)/platform-wistron.dep + endif + include $(PLATFORM_PATH)/sai.dep +diff --git a/platform/marvell-prestera/rules.mk b/platform/marvell-prestera/rules.mk +index 74792e988..862224b4d 100644 +--- a/platform/marvell-prestera/rules.mk ++++ b/platform/marvell-prestera/rules.mk +@@ -8,6 +8,7 @@ include $(PLATFORM_PATH)/platform-marvell.mk + ifeq ($(CONFIGURED_ARCH),$(filter $(CONFIGURED_ARCH),arm64 armhf)) + include $(PLATFORM_PATH)/mrvl-prestera.mk + include $(PLATFORM_PATH)/platform-nokia.mk ++include $(PLATFORM_PATH)/platform-wistron.mk + endif + + SONIC_ALL += $(SONIC_ONE_IMAGE) \ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/changelog b/platform/marvell-prestera/sonic-platform-wistron/debian/changelog +new file mode 100644 +index 000000000..6aa47c2e0 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/changelog +@@ -0,0 +1,5 @@ ++sonic-platform-wistron (0.1) unstable; urgency=low ++ ++ * Initial release with support for es1227-54ts, es2227-54ts, es2227-54ts-p. ++ ++ -- Wistron Wed, 23 Nov 2021 09:57:58 +0800 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/compat b/platform/marvell-prestera/sonic-platform-wistron/debian/compat +new file mode 100644 +index 000000000..f599e28b8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/compat +@@ -0,0 +1 @@ ++10 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/control b/platform/marvell-prestera/sonic-platform-wistron/debian/control +new file mode 100644 +index 000000000..771826adc +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/control +@@ -0,0 +1,24 @@ ++Source: sonic-platform-wistron ++Section: unknown ++Priority: optional ++Maintainer: Wistron ++Build-Depends: debhelper (>=9) ++Standards-Version: 3.9.6 ++ ++Package: sonic-platform-es1227-54ts ++Architecture: arm64 ++Depends: ${misc:Depends} ++Description: ++ ++ ++Package: sonic-platform-es2227-54ts ++Architecture: arm64 ++Depends: ${misc:Depends} ++Description: ++ ++ ++Package: sonic-platform-es2227-54ts-p ++Architecture: arm64 ++Depends: ${misc:Depends} ++Description: ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/rules b/platform/marvell-prestera/sonic-platform-wistron/debian/rules +new file mode 100755 +index 000000000..328196af1 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/rules +@@ -0,0 +1,87 @@ ++#!/usr/bin/make -f ++# See debhelper(7) (uncomment to enable) ++# output every command that modifies files on the build system. ++#export DH_VERBOSE = 1 ++ ++include /usr/share/dpkg/pkg-info.mk ++#-------------------------------------------------------- ++ ++ifneq ($(CROSS_BUILD_ENVIRON), y) ++KVERSION ?= $(shell uname -r) ++endif ++KERNEL_SRC := /lib/modules/$(KVERSION) ++INSTALL_MOD_DIR := kernel/extra/ ++MOD_SRC_DIR:= $(shell pwd) ++MODULE_DIRS:= es1227_54ts es2227_54ts es2227_54ts_p ++MODULE_DIR := modules ++UTILS_DIR := utils ++SERVICE_DIR := service ++PRESTERA_MODULE_SRC := mrvl-prestera/drivers/generic/cpssEnabler/linuxNoKernelModule/drivers ++ ++%: ++ dh $@ --with systemd,python3 --buildsystem=pybuild ++ ++clean: ++ dh_testdir ++ dh_testroot ++ dh_clean ++ ++build: ++ (for mod in $(MODULE_DIRS); do \ ++ make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ ++ cd $(MOD_SRC_DIR)/../$(PRESTERA_MODULE_SRC)/; \ ++ make clean; \ ++ make modules -C $(KERNEL_SRC)/build M=`pwd` CONFIG_KM_MVPCI=y CONFIG_KM_MVINT=y || exit 1; \ ++ cp *.ko $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/; \ ++ cd $(MOD_SRC_DIR)/$${mod}; \ ++ python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ ++ echo "Finished making whl package for $$mod"; \ ++ cd $(MOD_SRC_DIR); \ ++ done) ++ ++binary: binary-arch binary-indep ++ # Nothing to do ++ ++binary-arch: ++ # Nothing to do ++ ++binary-indep: ++ dh_testdir ++ dh_installdirs ++ ++ # Custom package commands ++ (for mod in $(MODULE_DIRS); do \ ++ if [ $$mod = "es1227_54ts" ]; then \ ++ pkg="es1227-54ts"; \ ++ elif [ $$mod = "es2227_54ts" ]; then \ ++ pkg="es2227-54ts"; \ ++ else \ ++ pkg="es2227-54ts-p"; \ ++ fi; \ ++ dh_installdirs -psonic-platform-$${pkg} /$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ ++ dh_installdirs -psonic-platform-$${pkg} /usr/local/bin; \ ++ dh_installdirs -psonic-platform-$${pkg} lib/systemd/system; \ ++ cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/sonic-platform-$${pkg}/usr/local/bin/; \ ++ cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/sonic-platform-$${pkg}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ ++ cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/sonic-platform-$${pkg}/lib/systemd/system/; \ ++ #python3 $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/sonic-platform-$${pkg} --install-layout=deb; \ ++ done) ++ ++ # Resuming debhelper scripts ++ dh_testroot ++ dh_install ++ dh_installchangelogs ++ dh_installdocs ++ dh_systemd_enable ++ dh_installinit ++ dh_systemd_start ++ dh_link ++ dh_fixperms ++ dh_compress ++ dh_strip ++ dh_installdeb ++ dh_gencontrol ++ dh_md5sums ++ dh_builddeb ++ ++.PHONY: build binary binary-arch binary-indep clean +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.install b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.install +new file mode 100644 +index 000000000..ec78cbe0f +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.install +@@ -0,0 +1,16 @@ ++es1227_54ts/scripts/es1227_54ts_plt_setup.sh usr/local/bin ++es1227_54ts/scripts/entropy.py etc/ ++es1227_54ts/scripts/fw_env.config etc/ ++es1227_54ts/scripts/es1227_54ts-init.sh usr/local/bin ++es1227_54ts/service/es1227_54ts-init.service etc/systemd/system ++es1227_54ts/service/es1227_54ts-sysled.service etc/systemd/system ++es1227_54ts/service/es1227_54ts-rst_button.service etc/systemd/system ++es1227_54ts/service/es1227_54ts-psu-monitor.service etc/systemd/system ++es1227_54ts/service/es1227_54ts-sensor_conf.service etc/systemd/system ++es1227_54ts/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-wistron_es1227_54ts-r0 ++es1227_54ts/utils/updateCPLD usr/local/bin ++es1227_54ts/utils/sysled_health.py usr/local/bin ++es1227_54ts/utils/phytool usr/local/bin ++es1227_54ts/utils/rst_button.py usr/local/bin ++es1227_54ts/utils/psu_detect.py usr/local/bin ++es1227_54ts/utils/sensor_conf.sh usr/local/bin +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.postinst b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.postinst +new file mode 100644 +index 000000000..8eef2a01d +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es1227-54ts.postinst +@@ -0,0 +1,51 @@ ++#!/bin/sh ++# postinst script for sonic-platform-rd98dx7312 ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# * `configure' ++# * `abort-upgrade' ++# * `abort-remove' `in-favour' ++# ++# * `abort-remove' ++# * `abort-deconfigure' `in-favour' ++# `removing' ++# ++# for details, see https://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++ ++case "$1" in ++ configure) ++ depmod -a ++ sh /usr/local/bin/es1227_54ts_plt_setup.sh ++ chmod a+x /usr/local/bin/es1227_54ts-init.sh ++ systemctl enable es1227_54ts-init.service ++ systemctl start es1227_54ts-init.service ++ ++ ;; ++ ++ abort-upgrade|abort-remove|abort-deconfigure) ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++DEVICE="/usr/share/sonic/device" ++PLATFORM=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) ++if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ]; then ++ pip3 install --force-reinstall $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ++fi ++ ++exit 0 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.install b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.install +new file mode 100644 +index 000000000..c132a6899 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.install +@@ -0,0 +1,24 @@ ++es2227_54ts_p/scripts/es2227_54ts_p_plt_setup.sh usr/local/bin ++es2227_54ts_p/scripts/entropy.py etc/ ++es2227_54ts_p/scripts/fw_env.config etc/ ++es2227_54ts_p/scripts/es2227_54ts_p-init.sh usr/local/bin ++es2227_54ts_p/service/es2227_54ts_p-init.service etc/systemd/system ++es2227_54ts_p/service/es2227_54ts_p-led-monitor.service etc/systemd/system ++es2227_54ts_p/service/es2227_54ts_p-sysled.service etc/systemd/system ++es2227_54ts_p/service/es2227_54ts_p-oob-led.service etc/systemd/system ++es2227_54ts_p/service/es2227_54ts_p-rst_button.service etc/systemd/system ++es2227_54ts_p/service/es2227_54ts_p-psu-monitor.service etc/systemd/system ++es2227_54ts_p/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-wistron_es2227_54ts_p-r0 ++es2227_54ts_p/utils/poetool usr/local/bin ++es2227_54ts_p/utils/es2227_54ts_p_led.py usr/local/bin ++es2227_54ts_p/utils/updateCPLD usr/local/bin ++es2227_54ts_p/utils/sysled_health.py usr/local/bin ++es2227_54ts_p/utils/poe_init.sh usr/local/bin ++es2227_54ts_p/utils/es2227_54ts_p-oob-led.sh usr/local/bin ++es2227_54ts_p/utils/phytool usr/local/bin ++es2227_54ts_p/utils/poe_cfg_init.py usr/local/bin ++es2227_54ts_p/utils/poe_lldp.py usr/local/bin ++es2227_54ts_p/utils/poe_cfg_lldp.py usr/local/bin ++es2227_54ts_p/utils/poe_power.sh usr/local/bin ++es2227_54ts_p/utils/rst_button.py usr/local/bin ++es2227_54ts_p/utils/psu_detect.py usr/local/bin +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.postinst b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.postinst +new file mode 100644 +index 000000000..54753db37 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts-p.postinst +@@ -0,0 +1,51 @@ ++#!/bin/sh ++# postinst script for sonic-platform-rd98dx7312 ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# * `configure' ++# * `abort-upgrade' ++# * `abort-remove' `in-favour' ++# ++# * `abort-remove' ++# * `abort-deconfigure' `in-favour' ++# `removing' ++# ++# for details, see https://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++ ++case "$1" in ++ configure) ++ depmod -a ++ sh /usr/local/bin/es2227_54ts_p_plt_setup.sh ++ chmod a+x /usr/local/bin/es2227_54ts_p-init.sh ++ systemctl enable es2227_54ts_p-init.service ++ systemctl start es2227_54ts_p-init.service ++ ++ ;; ++ ++ abort-upgrade|abort-remove|abort-deconfigure) ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++DEVICE="/usr/share/sonic/device" ++PLATFORM=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) ++if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ]; then ++ pip3 install --force-reinstall $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ++fi ++ ++exit 0 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.install b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.install +new file mode 100644 +index 000000000..bdfafdd60 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.install +@@ -0,0 +1,18 @@ ++es2227_54ts/scripts/es2227_54ts_plt_setup.sh usr/local/bin ++es2227_54ts/scripts/entropy.py etc/ ++es2227_54ts/scripts/fw_env.config etc/ ++es2227_54ts/scripts/es2227_54ts-init.sh usr/local/bin ++es2227_54ts/service/es2227_54ts-init.service etc/systemd/system ++es2227_54ts/service/es2227_54ts-sysled.service etc/systemd/system ++es2227_54ts/service/es2227_54ts-oob-led.service etc/systemd/system ++es2227_54ts/service/es2227_54ts-rst_button.service etc/systemd/system ++es2227_54ts/service/es2227_54ts-psu-monitor.service etc/systemd/system ++es2227_54ts/service/es2227_54ts-sensor_conf.service etc/systemd/system ++es2227_54ts/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-wistron_es2227_54ts-r0 ++es2227_54ts/utils/updateCPLD usr/local/bin ++es2227_54ts/utils/sysled_health.py usr/local/bin ++es2227_54ts/utils/es2227_54ts-oob-led.sh usr/local/bin ++es2227_54ts/utils/phytool usr/local/bin ++es2227_54ts/utils/rst_button.py usr/local/bin ++es2227_54ts/utils/psu_detect.py usr/local/bin ++es2227_54ts/utils/sensor_conf.sh usr/local/bin +diff --git a/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.postinst b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.postinst +new file mode 100644 +index 000000000..619c26f53 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/debian/sonic-platform-es2227-54ts.postinst +@@ -0,0 +1,51 @@ ++#!/bin/sh ++# postinst script for sonic-platform-rd98dx7312 ++# ++# see: dh_installdeb(1) ++ ++set -e ++ ++# summary of how this script can be called: ++# * `configure' ++# * `abort-upgrade' ++# * `abort-remove' `in-favour' ++# ++# * `abort-remove' ++# * `abort-deconfigure' `in-favour' ++# `removing' ++# ++# for details, see https://www.debian.org/doc/debian-policy/ or ++# the debian-policy package ++ ++ ++case "$1" in ++ configure) ++ depmod -a ++ sh /usr/local/bin/es2227_54ts_plt_setup.sh ++ chmod a+x /usr/local/bin/es2227_54ts-init.sh ++ systemctl enable es2227_54ts-init.service ++ systemctl start es2227_54ts-init.service ++ ++ ;; ++ ++ abort-upgrade|abort-remove|abort-deconfigure) ++ ;; ++ ++ *) ++ echo "postinst called with unknown argument \`$1'" >&2 ++ exit 1 ++ ;; ++esac ++ ++# dh_installdeb will replace this with shell code automatically ++# generated by other debhelper scripts. ++ ++#DEBHELPER# ++ ++DEVICE="/usr/share/sonic/device" ++PLATFORM=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) ++if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ]; then ++ pip3 install --force-reinstall $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ++fi ++ ++exit 0 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/Makefile b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/Makefile +new file mode 100755 +index 000000000..70f03cb6c +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/Makefile +@@ -0,0 +1,17 @@ ++ifneq ($(KERNELRELEASE),) ++obj-m:= wistron_cpld.o wistron_max31790.o wistron_psu.o ++else ++ifeq (,$(KERNEL_SRC)) ++#$(error KERNEL_SRC is not defined) ++KVERSION=3.16.0-8-amd64 ++KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/ ++KERNELDIR:=$(KERNEL_DIR) ++else ++KERNELDIR:=$(KERNEL_SRC) ++endif ++PWD:=$(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++clean: ++ rm -rf *.o *.mod.o *.mod.o *.ko .*cmd *.mod.c .tmp_versions Module.markers Module.symvers modules.order *.mod ++endif +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/pmbus.h b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/pmbus.h +new file mode 100644 +index 000000000..10fb17879 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/pmbus.h +@@ -0,0 +1,511 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * pmbus.h - Common defines and structures for PMBus devices ++ * ++ * Copyright (c) 2010, 2011 Ericsson AB. ++ * Copyright (c) 2012 Guenter Roeck ++ */ ++ ++#ifndef PMBUS_H ++#define PMBUS_H ++ ++#include ++#include ++ ++/* ++ * Registers ++ */ ++enum pmbus_regs { ++ PMBUS_PAGE = 0x00, ++ PMBUS_OPERATION = 0x01, ++ PMBUS_ON_OFF_CONFIG = 0x02, ++ PMBUS_CLEAR_FAULTS = 0x03, ++ PMBUS_PHASE = 0x04, ++ ++ PMBUS_WRITE_PROTECT = 0x10, ++ ++ PMBUS_CAPABILITY = 0x19, ++ PMBUS_QUERY = 0x1A, ++ ++ PMBUS_VOUT_MODE = 0x20, ++ PMBUS_VOUT_COMMAND = 0x21, ++ PMBUS_VOUT_TRIM = 0x22, ++ PMBUS_VOUT_CAL_OFFSET = 0x23, ++ PMBUS_VOUT_MAX = 0x24, ++ PMBUS_VOUT_MARGIN_HIGH = 0x25, ++ PMBUS_VOUT_MARGIN_LOW = 0x26, ++ PMBUS_VOUT_TRANSITION_RATE = 0x27, ++ PMBUS_VOUT_DROOP = 0x28, ++ PMBUS_VOUT_SCALE_LOOP = 0x29, ++ PMBUS_VOUT_SCALE_MONITOR = 0x2A, ++ ++ PMBUS_COEFFICIENTS = 0x30, ++ PMBUS_POUT_MAX = 0x31, ++ ++ PMBUS_FAN_CONFIG_12 = 0x3A, ++ PMBUS_FAN_COMMAND_1 = 0x3B, ++ PMBUS_FAN_COMMAND_2 = 0x3C, ++ PMBUS_FAN_CONFIG_34 = 0x3D, ++ PMBUS_FAN_COMMAND_3 = 0x3E, ++ PMBUS_FAN_COMMAND_4 = 0x3F, ++ ++ PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, ++ PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, ++ PMBUS_VOUT_OV_WARN_LIMIT = 0x42, ++ PMBUS_VOUT_UV_WARN_LIMIT = 0x43, ++ PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, ++ PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, ++ PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, ++ PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, ++ PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, ++ PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, ++ PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, ++ PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, ++ PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, ++ ++ PMBUS_OT_FAULT_LIMIT = 0x4F, ++ PMBUS_OT_FAULT_RESPONSE = 0x50, ++ PMBUS_OT_WARN_LIMIT = 0x51, ++ PMBUS_UT_WARN_LIMIT = 0x52, ++ PMBUS_UT_FAULT_LIMIT = 0x53, ++ PMBUS_UT_FAULT_RESPONSE = 0x54, ++ PMBUS_VIN_OV_FAULT_LIMIT = 0x55, ++ PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, ++ PMBUS_VIN_OV_WARN_LIMIT = 0x57, ++ PMBUS_VIN_UV_WARN_LIMIT = 0x58, ++ PMBUS_VIN_UV_FAULT_LIMIT = 0x59, ++ ++ PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, ++ PMBUS_IIN_OC_WARN_LIMIT = 0x5D, ++ ++ PMBUS_POUT_OP_FAULT_LIMIT = 0x68, ++ PMBUS_POUT_OP_WARN_LIMIT = 0x6A, ++ PMBUS_PIN_OP_WARN_LIMIT = 0x6B, ++ ++ PMBUS_STATUS_BYTE = 0x78, ++ PMBUS_STATUS_WORD = 0x79, ++ PMBUS_STATUS_VOUT = 0x7A, ++ PMBUS_STATUS_IOUT = 0x7B, ++ PMBUS_STATUS_INPUT = 0x7C, ++ PMBUS_STATUS_TEMPERATURE = 0x7D, ++ PMBUS_STATUS_CML = 0x7E, ++ PMBUS_STATUS_OTHER = 0x7F, ++ PMBUS_STATUS_MFR_SPECIFIC = 0x80, ++ PMBUS_STATUS_FAN_12 = 0x81, ++ PMBUS_STATUS_FAN_34 = 0x82, ++ ++ PMBUS_READ_VIN = 0x88, ++ PMBUS_READ_IIN = 0x89, ++ PMBUS_READ_VCAP = 0x8A, ++ PMBUS_READ_VOUT = 0x8B, ++ PMBUS_READ_IOUT = 0x8C, ++ PMBUS_READ_TEMPERATURE_1 = 0x8D, ++ PMBUS_READ_TEMPERATURE_2 = 0x8E, ++ PMBUS_READ_TEMPERATURE_3 = 0x8F, ++ PMBUS_READ_FAN_SPEED_1 = 0x90, ++ PMBUS_READ_FAN_SPEED_2 = 0x91, ++ PMBUS_READ_FAN_SPEED_3 = 0x92, ++ PMBUS_READ_FAN_SPEED_4 = 0x93, ++ PMBUS_READ_DUTY_CYCLE = 0x94, ++ PMBUS_READ_FREQUENCY = 0x95, ++ PMBUS_READ_POUT = 0x96, ++ PMBUS_READ_PIN = 0x97, ++ ++ PMBUS_REVISION = 0x98, ++ PMBUS_MFR_ID = 0x99, ++ PMBUS_MFR_MODEL = 0x9A, ++ PMBUS_MFR_REVISION = 0x9B, ++ PMBUS_MFR_LOCATION = 0x9C, ++ PMBUS_MFR_DATE = 0x9D, ++ PMBUS_MFR_SERIAL = 0x9E, ++ ++ PMBUS_MFR_VIN_MIN = 0xA0, ++ PMBUS_MFR_VIN_MAX = 0xA1, ++ PMBUS_MFR_IIN_MAX = 0xA2, ++ PMBUS_MFR_PIN_MAX = 0xA3, ++ PMBUS_MFR_VOUT_MIN = 0xA4, ++ PMBUS_MFR_VOUT_MAX = 0xA5, ++ PMBUS_MFR_IOUT_MAX = 0xA6, ++ PMBUS_MFR_POUT_MAX = 0xA7, ++ ++ PMBUS_IC_DEVICE_ID = 0xAD, ++ PMBUS_IC_DEVICE_REV = 0xAE, ++ ++ PMBUS_MFR_MAX_TEMP_1 = 0xC0, ++ PMBUS_MFR_MAX_TEMP_2 = 0xC1, ++ PMBUS_MFR_MAX_TEMP_3 = 0xC2, ++ ++/* ++ * Virtual registers. ++ * Useful to support attributes which are not supported by standard PMBus ++ * registers but exist as manufacturer specific registers on individual chips. ++ * Must be mapped to real registers in device specific code. ++ * ++ * Semantics: ++ * Virtual registers are all word size. ++ * READ registers are read-only; writes are either ignored or return an error. ++ * RESET registers are read/write. Reading reset registers returns zero ++ * (used for detection), writing any value causes the associated history to be ++ * reset. ++ * Virtual registers have to be handled in device specific driver code. Chip ++ * driver code returns non-negative register values if a virtual register is ++ * supported, or a negative error code if not. The chip driver may return ++ * -ENODATA or any other error code in this case, though an error code other ++ * than -ENODATA is handled more efficiently and thus preferred. Either case, ++ * the calling PMBus core code will abort if the chip driver returns an error ++ * code when reading or writing virtual registers. ++ */ ++ PMBUS_VIRT_BASE = 0x100, ++ PMBUS_VIRT_READ_TEMP_AVG, ++ PMBUS_VIRT_READ_TEMP_MIN, ++ PMBUS_VIRT_READ_TEMP_MAX, ++ PMBUS_VIRT_RESET_TEMP_HISTORY, ++ PMBUS_VIRT_READ_VIN_AVG, ++ PMBUS_VIRT_READ_VIN_MIN, ++ PMBUS_VIRT_READ_VIN_MAX, ++ PMBUS_VIRT_RESET_VIN_HISTORY, ++ PMBUS_VIRT_READ_IIN_AVG, ++ PMBUS_VIRT_READ_IIN_MIN, ++ PMBUS_VIRT_READ_IIN_MAX, ++ PMBUS_VIRT_RESET_IIN_HISTORY, ++ PMBUS_VIRT_READ_PIN_AVG, ++ PMBUS_VIRT_READ_PIN_MIN, ++ PMBUS_VIRT_READ_PIN_MAX, ++ PMBUS_VIRT_RESET_PIN_HISTORY, ++ PMBUS_VIRT_READ_POUT_AVG, ++ PMBUS_VIRT_READ_POUT_MIN, ++ PMBUS_VIRT_READ_POUT_MAX, ++ PMBUS_VIRT_RESET_POUT_HISTORY, ++ PMBUS_VIRT_READ_VOUT_AVG, ++ PMBUS_VIRT_READ_VOUT_MIN, ++ PMBUS_VIRT_READ_VOUT_MAX, ++ PMBUS_VIRT_RESET_VOUT_HISTORY, ++ PMBUS_VIRT_READ_IOUT_AVG, ++ PMBUS_VIRT_READ_IOUT_MIN, ++ PMBUS_VIRT_READ_IOUT_MAX, ++ PMBUS_VIRT_RESET_IOUT_HISTORY, ++ PMBUS_VIRT_READ_TEMP2_AVG, ++ PMBUS_VIRT_READ_TEMP2_MIN, ++ PMBUS_VIRT_READ_TEMP2_MAX, ++ PMBUS_VIRT_RESET_TEMP2_HISTORY, ++ ++ PMBUS_VIRT_READ_VMON, ++ PMBUS_VIRT_VMON_UV_WARN_LIMIT, ++ PMBUS_VIRT_VMON_OV_WARN_LIMIT, ++ PMBUS_VIRT_VMON_UV_FAULT_LIMIT, ++ PMBUS_VIRT_VMON_OV_FAULT_LIMIT, ++ PMBUS_VIRT_STATUS_VMON, ++ ++ /* ++ * RPM and PWM Fan control ++ * ++ * Drivers wanting to expose PWM control must define the behaviour of ++ * PMBUS_VIRT_PWM_[1-4] and PMBUS_VIRT_PWM_ENABLE_[1-4] in the ++ * {read,write}_word_data callback. ++ * ++ * pmbus core provides a default implementation for ++ * PMBUS_VIRT_FAN_TARGET_[1-4]. ++ * ++ * TARGET, PWM and PWM_ENABLE members must be defined sequentially; ++ * pmbus core uses the difference between the provided register and ++ * it's _1 counterpart to calculate the FAN/PWM ID. ++ */ ++ PMBUS_VIRT_FAN_TARGET_1, ++ PMBUS_VIRT_FAN_TARGET_2, ++ PMBUS_VIRT_FAN_TARGET_3, ++ PMBUS_VIRT_FAN_TARGET_4, ++ PMBUS_VIRT_PWM_1, ++ PMBUS_VIRT_PWM_2, ++ PMBUS_VIRT_PWM_3, ++ PMBUS_VIRT_PWM_4, ++ PMBUS_VIRT_PWM_ENABLE_1, ++ PMBUS_VIRT_PWM_ENABLE_2, ++ PMBUS_VIRT_PWM_ENABLE_3, ++ PMBUS_VIRT_PWM_ENABLE_4, ++ ++ /* Samples for average ++ * ++ * Drivers wanting to expose functionality for changing the number of ++ * samples used for average values should implement support in ++ * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it ++ * applies to all types of measurements, or any number of specific ++ * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. ++ */ ++ PMBUS_VIRT_SAMPLES, ++ PMBUS_VIRT_IN_SAMPLES, ++ PMBUS_VIRT_CURR_SAMPLES, ++ PMBUS_VIRT_POWER_SAMPLES, ++ PMBUS_VIRT_TEMP_SAMPLES, ++}; ++ ++/* ++ * OPERATION ++ */ ++#define PB_OPERATION_CONTROL_ON BIT(7) ++ ++/* ++ * WRITE_PROTECT ++ */ ++#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */ ++#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */ ++#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */ ++ ++#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT) ++ ++/* ++ * CAPABILITY ++ */ ++#define PB_CAPABILITY_SMBALERT BIT(4) ++#define PB_CAPABILITY_ERROR_CHECK BIT(7) ++ ++/* ++ * VOUT_MODE ++ */ ++#define PB_VOUT_MODE_MODE_MASK 0xe0 ++#define PB_VOUT_MODE_PARAM_MASK 0x1f ++ ++#define PB_VOUT_MODE_LINEAR 0x00 ++#define PB_VOUT_MODE_VID 0x20 ++#define PB_VOUT_MODE_DIRECT 0x40 ++ ++/* ++ * Fan configuration ++ */ ++#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) ++#define PB_FAN_2_RPM BIT(2) ++#define PB_FAN_2_INSTALLED BIT(3) ++#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) ++#define PB_FAN_1_RPM BIT(6) ++#define PB_FAN_1_INSTALLED BIT(7) ++ ++enum pmbus_fan_mode { percent = 0, rpm }; ++ ++/* ++ * STATUS_BYTE, STATUS_WORD (lower) ++ */ ++#define PB_STATUS_NONE_ABOVE BIT(0) ++#define PB_STATUS_CML BIT(1) ++#define PB_STATUS_TEMPERATURE BIT(2) ++#define PB_STATUS_VIN_UV BIT(3) ++#define PB_STATUS_IOUT_OC BIT(4) ++#define PB_STATUS_VOUT_OV BIT(5) ++#define PB_STATUS_OFF BIT(6) ++#define PB_STATUS_BUSY BIT(7) ++ ++/* ++ * STATUS_WORD (upper) ++ */ ++#define PB_STATUS_UNKNOWN BIT(8) ++#define PB_STATUS_OTHER BIT(9) ++#define PB_STATUS_FANS BIT(10) ++#define PB_STATUS_POWER_GOOD_N BIT(11) ++#define PB_STATUS_WORD_MFR BIT(12) ++#define PB_STATUS_INPUT BIT(13) ++#define PB_STATUS_IOUT_POUT BIT(14) ++#define PB_STATUS_VOUT BIT(15) ++ ++/* ++ * STATUS_IOUT ++ */ ++#define PB_POUT_OP_WARNING BIT(0) ++#define PB_POUT_OP_FAULT BIT(1) ++#define PB_POWER_LIMITING BIT(2) ++#define PB_CURRENT_SHARE_FAULT BIT(3) ++#define PB_IOUT_UC_FAULT BIT(4) ++#define PB_IOUT_OC_WARNING BIT(5) ++#define PB_IOUT_OC_LV_FAULT BIT(6) ++#define PB_IOUT_OC_FAULT BIT(7) ++ ++/* ++ * STATUS_VOUT, STATUS_INPUT ++ */ ++#define PB_VOLTAGE_VIN_OFF BIT(3) ++#define PB_VOLTAGE_UV_FAULT BIT(4) ++#define PB_VOLTAGE_UV_WARNING BIT(5) ++#define PB_VOLTAGE_OV_WARNING BIT(6) ++#define PB_VOLTAGE_OV_FAULT BIT(7) ++ ++/* ++ * STATUS_INPUT ++ */ ++#define PB_PIN_OP_WARNING BIT(0) ++#define PB_IIN_OC_WARNING BIT(1) ++#define PB_IIN_OC_FAULT BIT(2) ++ ++/* ++ * STATUS_TEMPERATURE ++ */ ++#define PB_TEMP_UT_FAULT BIT(4) ++#define PB_TEMP_UT_WARNING BIT(5) ++#define PB_TEMP_OT_WARNING BIT(6) ++#define PB_TEMP_OT_FAULT BIT(7) ++ ++/* ++ * STATUS_FAN ++ */ ++#define PB_FAN_AIRFLOW_WARNING BIT(0) ++#define PB_FAN_AIRFLOW_FAULT BIT(1) ++#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) ++#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) ++#define PB_FAN_FAN2_WARNING BIT(4) ++#define PB_FAN_FAN1_WARNING BIT(5) ++#define PB_FAN_FAN2_FAULT BIT(6) ++#define PB_FAN_FAN1_FAULT BIT(7) ++ ++/* ++ * CML_FAULT_STATUS ++ */ ++#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) ++#define PB_CML_FAULT_OTHER_COMM BIT(1) ++#define PB_CML_FAULT_PROCESSOR BIT(3) ++#define PB_CML_FAULT_MEMORY BIT(4) ++#define PB_CML_FAULT_PACKET_ERROR BIT(5) ++#define PB_CML_FAULT_INVALID_DATA BIT(6) ++#define PB_CML_FAULT_INVALID_COMMAND BIT(7) ++ ++enum pmbus_sensor_classes { ++ PSC_VOLTAGE_IN = 0, ++ PSC_VOLTAGE_OUT, ++ PSC_CURRENT_IN, ++ PSC_CURRENT_OUT, ++ PSC_POWER, ++ PSC_TEMPERATURE, ++ PSC_FAN, ++ PSC_PWM, ++ PSC_NUM_CLASSES /* Number of power sensor classes */ ++}; ++ ++#define PMBUS_PAGES 32 /* Per PMBus specification */ ++#define PMBUS_PHASES 10 /* Maximum number of phases per page */ ++ ++/* Functionality bit mask */ ++#define PMBUS_HAVE_VIN BIT(0) ++#define PMBUS_HAVE_VCAP BIT(1) ++#define PMBUS_HAVE_VOUT BIT(2) ++#define PMBUS_HAVE_IIN BIT(3) ++#define PMBUS_HAVE_IOUT BIT(4) ++#define PMBUS_HAVE_PIN BIT(5) ++#define PMBUS_HAVE_POUT BIT(6) ++#define PMBUS_HAVE_FAN12 BIT(7) ++#define PMBUS_HAVE_FAN34 BIT(8) ++#define PMBUS_HAVE_TEMP BIT(9) ++#define PMBUS_HAVE_TEMP2 BIT(10) ++#define PMBUS_HAVE_TEMP3 BIT(11) ++#define PMBUS_HAVE_STATUS_VOUT BIT(12) ++#define PMBUS_HAVE_STATUS_IOUT BIT(13) ++#define PMBUS_HAVE_STATUS_INPUT BIT(14) ++#define PMBUS_HAVE_STATUS_TEMP BIT(15) ++#define PMBUS_HAVE_STATUS_FAN12 BIT(16) ++#define PMBUS_HAVE_STATUS_FAN34 BIT(17) ++#define PMBUS_HAVE_VMON BIT(18) ++#define PMBUS_HAVE_STATUS_VMON BIT(19) ++#define PMBUS_HAVE_PWM12 BIT(20) ++#define PMBUS_HAVE_PWM34 BIT(21) ++#define PMBUS_HAVE_SAMPLES BIT(22) ++ ++#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ ++#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ ++ ++enum pmbus_data_format { linear = 0, ieee754, direct, vid }; ++enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; ++ ++struct pmbus_driver_info { ++ int pages; /* Total number of pages */ ++ u8 phases[PMBUS_PAGES]; /* Number of phases per page */ ++ enum pmbus_data_format format[PSC_NUM_CLASSES]; ++ enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ ++ /* ++ * Support one set of coefficients for each sensor type ++ * Used for chips providing data in direct mode. ++ */ ++ int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ ++ int b[PSC_NUM_CLASSES]; /* offset */ ++ int R[PSC_NUM_CLASSES]; /* exponent */ ++ ++ u32 func[PMBUS_PAGES]; /* Functionality, per page */ ++ u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ ++ /* ++ * The following functions map manufacturing specific register values ++ * to PMBus standard register values. Specify only if mapping is ++ * necessary. ++ * Functions return the register value (read) or zero (write) if ++ * successful. A return value of -ENODATA indicates that there is no ++ * manufacturer specific register, but that a standard PMBus register ++ * may exist. Any other negative return value indicates that the ++ * register does not exist, and that no attempt should be made to read ++ * the standard register. ++ */ ++ int (*read_byte_data)(struct i2c_client *client, int page, int reg); ++ int (*read_word_data)(struct i2c_client *client, int page, int phase, ++ int reg); ++ int (*write_byte_data)(struct i2c_client *client, int page, int reg, ++ u8 byte); ++ int (*write_word_data)(struct i2c_client *client, int page, int reg, ++ u16 word); ++ int (*write_byte)(struct i2c_client *client, int page, u8 value); ++ /* ++ * The identify function determines supported PMBus functionality. ++ * This function is only necessary if a chip driver supports multiple ++ * chips, and the chip functionality is not pre-determined. ++ */ ++ int (*identify)(struct i2c_client *client, ++ struct pmbus_driver_info *info); ++ ++ /* Regulator functionality, if supported by this chip driver. */ ++ int num_regulators; ++ const struct regulator_desc *reg_desc; ++ ++ /* custom attributes */ ++ const struct attribute_group **groups; ++}; ++ ++/* Regulator ops */ ++ ++extern const struct regulator_ops pmbus_regulator_ops; ++ ++/* Macros for filling in array of struct regulator_desc */ ++#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \ ++ [_id] = { \ ++ .name = (_name # _id), \ ++ .id = (_id), \ ++ .of_match = of_match_ptr(_name # _id), \ ++ .regulators_node = of_match_ptr("regulators"), \ ++ .ops = &pmbus_regulator_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE, \ ++ .n_voltages = _voltages, \ ++ .uV_step = _step, \ ++ } ++ ++#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0) ++ ++/* Function declarations */ ++ ++void pmbus_clear_cache(struct i2c_client *client); ++void pmbus_set_update(struct i2c_client *client, u8 reg, bool update); ++int pmbus_set_page(struct i2c_client *client, int page, int phase); ++int pmbus_read_word_data(struct i2c_client *client, int page, int phase, ++ u8 reg); ++int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, ++ u16 word); ++int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); ++int pmbus_write_byte(struct i2c_client *client, int page, u8 value); ++int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 value); ++int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 mask, u8 value); ++void pmbus_clear_faults(struct i2c_client *client); ++bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); ++bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); ++int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); ++const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client ++ *client); ++int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode); ++int pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode); ++int pmbus_update_fan(struct i2c_client *client, int page, int id, ++ u8 config, u8 mask, u16 command); ++struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client); ++ ++#endif /* PMBUS_H */ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.c b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.c +new file mode 100755 +index 000000000..a55c6a0b3 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.c +@@ -0,0 +1,2154 @@ ++/* ++ * A hwmon driver for the wistron_switch_cpld ++ * ++ */ ++ ++/* ---------------------------------------------------------------------------- ++ * Include files ++ * ---------------------------------------------------------------------------- ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* --------------------------------------------------------------------------- ++ * Constant ++ * ---------------------------------------------------------------------------- ++ */ ++#include "wistron_cpld.h" ++ ++static LIST_HEAD(cpld_client_list); ++static struct mutex list_lock; ++ ++struct cpld_client_node { ++ struct i2c_client *client; ++ struct list_head list; ++}; ++ ++/* ---------------------------------------------------------------------------- ++ * ++ * Module attribute functions ++ * ---------------------------------------------------------------------------- ++ */ ++/* ++static ssize_t cpld_show_board_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, ver = 0, ver2 = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0xf0) >> 4; ++ ver2 = (val & 0xf); ++ return sprintf(buf, "%s %s\n", (ver == 0) ? "EVT" : (ver == 1) ? "DVT" : "PVT", (ver2 == 0) ? "with CPU" : "without CPU" ); ++} ++*/ ++ ++static ssize_t cpld_show_board_id(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, ver = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0x7); ++ ++ return sprintf(buf, "%d\n", ver); ++} ++ ++static ssize_t cpld_show_fan_direction(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, ver = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0x4) >> 2; ++ ++ return sprintf(buf, "%d\n", ver); ++} ++ ++static ssize_t cpld_show_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, mjr_ver = 0, mnr_ver = 0; ++ unsigned char command = CPLD_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ mjr_ver = (val & 0xf0) >> 4; ++ mnr_ver = (val & 0xf) ; ++ ++ return sprintf(buf, "%d.%d\n", mjr_ver, mnr_ver); ++} ++ ++static ssize_t cpld_show_build_date(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, b_year = 0, b_month = 0, b_day = 0; ++ unsigned char command = CPLD_BUILD_YEAR_REG; ++ unsigned char command2 = CPLD_BUILD_DATE_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ b_year = (val & 0xfe) >> 1; ++ b_month = ((val & 0x1) << 3) + ((val2 & 0xe0) >> 5); ++ b_day = val2 & 0x1f; ++ return sprintf(buf, "20%02d %02d %02d\n", b_year, b_month, b_day); ++} ++ ++static ssize_t cpld_read_psu_status(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0; ++ unsigned char command = CPLD_PSU_CHECK_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & (1 << bit)) >> bit; ++ //0 : present ++ //1 : not present ++ //0 : power on ++ //1 : power off ++ if ( (bit == PSU2_PRESENT) || (bit == PSU1_PRESENT) || (bit == PSU2_ON) || (bit == PSU1_ON) ) ++ res = (res) ? 0 : 1; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t cpld_write_psu_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_PSU_CHECK_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask << bit); ++ ++ val |= (~(res) << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t cpld_show_power_ctrl(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, i = 0; ++ unsigned char command = CPLD_POWER_CTL1_REG; ++ unsigned char command2 = CPLD_POWER_CTL2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_ctrl_str1[i], ((val & (1 << i)) >> i) ? "Enable" : "Disable"); ++ } ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_ctrl_str2[i], ((val2 & (1 << i)) >> i) ? "Enable" : "Disable"); ++ } ++ ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t cpld_show_power_good(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, i = 0; ++ unsigned char command = CPLD_POWER_GOOD_REG; ++ unsigned char command2 = CPLD_POWER_GOOD2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ mutex_unlock(&list_lock); ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_good_str1[i], ((val & (1 << i)) >> i) ? "OK" : "Failed"); ++ } ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_good_str2[i], ((val2 & (1 << i)) >> i) ? "OK" : "Failed"); ++ } ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t port_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT1) || (sda->index == PORT2)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT3) || (sda->index == PORT4)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT5) || (sda->index == PORT6)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT7) || (sda->index == PORT8)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT9) || (sda->index == PORT10)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT11) || (sda->index == PORT12)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT13) || (sda->index == PORT14)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT15) || (sda->index == PORT16)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT17) || (sda->index == PORT18)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT19) || (sda->index == PORT20)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT21) || (sda->index == PORT22)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT23) || (sda->index == PORT24)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT25) || (sda->index == PORT26)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT27) || (sda->index == PORT28)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT29) || (sda->index == PORT30)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT31) || (sda->index == PORT32)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT33) || (sda->index == PORT34)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT35) || (sda->index == PORT36)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT37) || (sda->index == PORT38)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT39) || (sda->index == PORT40)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT41) || (sda->index == PORT42)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT43) || (sda->index == PORT44)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT45) || (sda->index == PORT46)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT47) || (sda->index == PORT48)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT49) || (sda->index == PORT50)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT51) || (sda->index == PORT52)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT53) || (sda->index == PORT54)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 2) * 4; ++ mask = (0x7) << bit; ++ } else{ ++ bit = ((sda->index + 1) % 2) * 4; ++ mask = (0x7) << bit; ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT1) || (sda->index == PORT2)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT3) || (sda->index == PORT4)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT5) || (sda->index == PORT6)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT7) || (sda->index == PORT8)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT9) || (sda->index == PORT10)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT11) || (sda->index == PORT12)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT13) || (sda->index == PORT14)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT15) || (sda->index == PORT16)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT17) || (sda->index == PORT18)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT19) || (sda->index == PORT20)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT21) || (sda->index == PORT22)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT23) || (sda->index == PORT24)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT25) || (sda->index == PORT26)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT27) || (sda->index == PORT28)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT29) || (sda->index == PORT30)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT31) || (sda->index == PORT32)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT33) || (sda->index == PORT34)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT35) || (sda->index == PORT36)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT37) || (sda->index == PORT38)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT39) || (sda->index == PORT40)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT41) || (sda->index == PORT42)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT43) || (sda->index == PORT44)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT45) || (sda->index == PORT46)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT47) || (sda->index == PORT48)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT49) || (sda->index == PORT50)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT51) || (sda->index == PORT52)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT53) || (sda->index == PORT54)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ if (res < 0 || res > 4) ++ return -EINVAL; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 2) * 4; ++ mask = (0x7) << bit; ++ } else{ ++ bit = ((sda->index + 1) % 2) * 4; ++ mask = (0x7) << bit; ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++/* ++static ssize_t port_led_act_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT0) || (sda->index == PORT1)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT2) || (sda->index == PORT3)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT4) || (sda->index == PORT5)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT6) || (sda->index == PORT7)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT8) || (sda->index == PORT9)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT10) || (sda->index == PORT11)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT12) || (sda->index == PORT13)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT14) || (sda->index == PORT15)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT16) || (sda->index == PORT17)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT18) || (sda->index == PORT19)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT20) || (sda->index == PORT21)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT22) || (sda->index == PORT23)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT24) || (sda->index == PORT25)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT26) || (sda->index == PORT27)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT28) || (sda->index == PORT29)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT30) || (sda->index == PORT31)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT32) || (sda->index == PORT33)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT34) || (sda->index == PORT35)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT36) || (sda->index == PORT37)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT38) || (sda->index == PORT39)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT40) || (sda->index == PORT41)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT42) || (sda->index == PORT43)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT44) || (sda->index == PORT45)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT46) || (sda->index == PORT47)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT48) || (sda->index == PORT49)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT50) || (sda->index == PORT51)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT52) || (sda->index == PORT53)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ bit = (((sda->index) % 2) * 4) + 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_act_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT0) || (sda->index == PORT1)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT2) || (sda->index == PORT3)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT4) || (sda->index == PORT5)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT6) || (sda->index == PORT7)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT8) || (sda->index == PORT9)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT10) || (sda->index == PORT11)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT12) || (sda->index == PORT13)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT14) || (sda->index == PORT15)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT16) || (sda->index == PORT17)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT18) || (sda->index == PORT19)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT20) || (sda->index == PORT21)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT22) || (sda->index == PORT23)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT24) || (sda->index == PORT25)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT26) || (sda->index == PORT27)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT28) || (sda->index == PORT29)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT30) || (sda->index == PORT31)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT32) || (sda->index == PORT33)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT34) || (sda->index == PORT35)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT36) || (sda->index == PORT37)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT38) || (sda->index == PORT39)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT40) || (sda->index == PORT41)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT42) || (sda->index == PORT43)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT44) || (sda->index == PORT45)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT46) || (sda->index == PORT47)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT48) || (sda->index == PORT49)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT50) || (sda->index == PORT51)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT52) || (sda->index == PORT53)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (sda->index < PORT48){ ++ if (res < 0 || res > 3) ++ return -EINVAL; ++ }else{ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ } ++ ++ bit = (((sda->index) % 2) * 4) + 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++*/ ++static ssize_t port_poe_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if (sda->index < PORT5) ++ command = CPLD_POE_PRT_LED_CTL1_REG; ++ else if (sda->index < PORT9) ++ command = CPLD_POE_PRT_LED_CTL2_REG; ++ else if (sda->index < PORT13) ++ command = CPLD_POE_PRT_LED_CTL3_REG; ++ else if (sda->index < PORT17) ++ command = CPLD_POE_PRT_LED_CTL4_REG; ++ else if (sda->index < PORT21) ++ command = CPLD_POE_PRT_LED_CTL5_REG; ++ else if (sda->index < PORT25) ++ command = CPLD_POE_PRT_LED_CTL6_REG; ++ else if (sda->index < PORT29) ++ command = CPLD_POE_PRT_LED_CTL7_REG; ++ else if (sda->index < PORT33) ++ command = CPLD_POE_PRT_LED_CTL8_REG; ++ else if (sda->index < PORT37) ++ command = CPLD_POE_PRT_LED_CTL9_REG; ++ else if (sda->index < PORT41) ++ command = CPLD_POE_PRT_LED_CTL10_REG; ++ else if (sda->index < PORT45) ++ command = CPLD_POE_PRT_LED_CTL11_REG; ++ else if (sda->index < PORT49) ++ command = CPLD_POE_PRT_LED_CTL12_REG; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 4) * 2; ++ mask = (0x3) << bit; ++ } else { ++ switch( (sda->index) % 4 ){ ++ case 0: ++ bit = 2; ++ mask = (0x3) << bit; ++ break; ++ case 1: ++ bit = 0; ++ mask = (0x3) << bit; ++ break; ++ case 2: ++ bit = 6; ++ mask = (0x3) << bit; ++ break; ++ case 3: ++ bit = 4; ++ mask = (0x3) << bit; ++ break; ++ } ++ } ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_poe_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if (sda->index < PORT5) ++ command = CPLD_POE_PRT_LED_CTL1_REG; ++ else if (sda->index < PORT9) ++ command = CPLD_POE_PRT_LED_CTL2_REG; ++ else if (sda->index < PORT13) ++ command = CPLD_POE_PRT_LED_CTL3_REG; ++ else if (sda->index < PORT17) ++ command = CPLD_POE_PRT_LED_CTL4_REG; ++ else if (sda->index < PORT21) ++ command = CPLD_POE_PRT_LED_CTL5_REG; ++ else if (sda->index < PORT25) ++ command = CPLD_POE_PRT_LED_CTL6_REG; ++ else if (sda->index < PORT29) ++ command = CPLD_POE_PRT_LED_CTL7_REG; ++ else if (sda->index < PORT33) ++ command = CPLD_POE_PRT_LED_CTL8_REG; ++ else if (sda->index < PORT37) ++ command = CPLD_POE_PRT_LED_CTL9_REG; ++ else if (sda->index < PORT41) ++ command = CPLD_POE_PRT_LED_CTL10_REG; ++ else if (sda->index < PORT45) ++ command = CPLD_POE_PRT_LED_CTL11_REG; ++ else if (sda->index < PORT49) ++ command = CPLD_POE_PRT_LED_CTL12_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 4) * 2; ++ mask = (0x3) << bit; ++ } else { ++ switch( (sda->index) % 4 ){ ++ case 0: ++ bit = 2; ++ mask = (0x3) << bit; ++ break; ++ case 1: ++ bit = 0; ++ mask = (0x3) << bit; ++ break; ++ case 2: ++ bit = 6; ++ mask = (0x3) << bit; ++ break; ++ case 3: ++ bit = 4; ++ mask = (0x3) << bit; ++ break; ++ } ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t fan_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_FAN_LED_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index * 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t fan_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_FAN_LED_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ ++ bit = sda->index * 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t sys_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_SYS_LED_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t sys_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_SYS_LED_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 3) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t rst_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index > RST_MAC_JTAG){ ++ command = CPLD_RESET_CTL2_REG; ++ bit = (sda->index - 8); ++ } else { ++ command = CPLD_RESET_CTL1_REG; ++ bit = sda->index; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++/* ++static ssize_t rst_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ if (sda->index > RST_MAC_JTAG){ ++ command = CPLD_RESET_CTL2_REG; ++ bit = (sda->index - 8); ++ } else { ++ command = CPLD_RESET_CTL1_REG; ++ bit = sda->index; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t int_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index < INT_OOB_IOIEXP){ ++ command = CPLD_INT_CTL1_REG; ++ bit = sda->index; ++ } else if (sda->index < DEV_INIT_DONE){ ++ command = CPLD_INT_CTL2_REG; ++ bit = sda->index - 8; ++ } else if (sda->index < MB_SYSTEM_INT){ ++ command = CPLD_INT_CTL3_REG; ++ bit = sda->index - 16; ++ } else { ++ command = CPLD_INT_CTL4_REG; ++ bit = sda->index - 19; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t int_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ if (sda->index < INT_OOB_IOIEXP){ ++ command = CPLD_INT_CTL1_REG; ++ bit = sda->index; ++ } else if (sda->index < DEV_INIT_DONE){ ++ command = CPLD_INT_CTL2_REG; ++ bit = sda->index - 8; ++ } else if (sda->index < MB_SYSTEM_INT){ ++ command = CPLD_INT_CTL3_REG; ++ bit = sda->index - 16; ++ } else { ++ command = CPLD_INT_CTL4_REG; ++ bit = sda->index - 19; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++*/ ++static ssize_t fan_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index < PWRGD_VR_P12V_FAN3){ ++ command = CPLD_FAN_CTL1_REG; ++ bit = sda->index; ++ } else { ++ command = CPLD_FAN_CTL2_REG; ++ bit = sda->index - PWRGD_VR_P12V_FAN3; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ // fan present bit is active low ++ if ( (sda->index == CNFAN1_PRESENT) || (sda->index == CNFAN2_PRESENT) || (sda->index == CNFAN3_PRESENT) ) ++ res = (res) ? 0 : 1; ++ ++ // fan enable bit is active low ++ //if ( (sda->index == FM_FAN1_EN) || (sda->index == FM_FAN2_EN) || (sda->index == FM_FAN3_EN) ) ++ // res = (res) ? 0 : 1; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t fan_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ command = CPLD_FAN_CTL1_REG; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t port_led_auto_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_PORT_LED_MANUAL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ mutex_lock(&list_lock); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_auto_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_PORT_LED_MANUAL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t poe_enable_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_MSCI_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t poe_enable_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_MSCI_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t msci_ctl2_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_MSCI_CTL2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t msci_ctl2_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_MSCI_CTL2_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_enable_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ unsigned char command = CPLD_WATCHDOG_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t watchdog_enable_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_refresh(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 1, bit = 1, mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_timer_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 2, mask = (0x7) << bit; ++ unsigned char command = CPLD_WATCHDOG_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t watchdog_timer_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 0, bit = 2, mask = (0x7) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < WATCHDOG_180S || res > WATCHDOG_300S) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t power_down_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ unsigned char command = CPLD_SYS_POWER_DOWN_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t power_down_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_SYS_POWER_DOWN_REG; ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++//static SENSOR_DEVICE_ATTR(board_rev, S_IRUGO, cpld_show_board_version, NULL, 0); ++static SENSOR_DEVICE_ATTR(board_id, S_IRUGO, cpld_show_board_id, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan_direction, S_IRUGO, cpld_show_fan_direction, NULL, 0); ++static SENSOR_DEVICE_ATTR(cpld_rev, S_IRUGO, cpld_show_version, NULL, 0); ++static SENSOR_DEVICE_ATTR(build_date, S_IRUGO, cpld_show_build_date, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(psu2_on, S_IRUGO | S_IWUSR, cpld_read_psu_status, cpld_write_psu_status, PSU2_ON); ++static SENSOR_DEVICE_ATTR(psu1_on, S_IRUGO | S_IWUSR, cpld_read_psu_status, cpld_write_psu_status, PSU1_ON); ++static SENSOR_DEVICE_ATTR(psu2_ac_ok, S_IRUGO, cpld_read_psu_status, NULL, PSU2_AC_OK); ++static SENSOR_DEVICE_ATTR(psu1_ac_ok, S_IRUGO, cpld_read_psu_status, NULL, PSU1_AC_OK); ++static SENSOR_DEVICE_ATTR(psu2_present, S_IRUGO, cpld_read_psu_status, NULL, PSU2_PRESENT); ++static SENSOR_DEVICE_ATTR(psu1_present, S_IRUGO, cpld_read_psu_status, NULL, PSU1_PRESENT); ++static SENSOR_DEVICE_ATTR(psu2_power_good, S_IRUGO, cpld_read_psu_status, NULL, PSU2_PWRGD); ++static SENSOR_DEVICE_ATTR(psu1_power_good, S_IRUGO, cpld_read_psu_status, NULL, PSU1_PWRGD); ++ ++ ++static SENSOR_DEVICE_ATTR(power_ctrl, S_IRUGO, cpld_show_power_ctrl, NULL, 0); ++static SENSOR_DEVICE_ATTR(power_good, S_IRUGO, cpld_show_power_good, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(fan_full_speed, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FAN_FULL_SPEED); ++static SENSOR_DEVICE_ATTR(fm_fan3_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN3_EN); ++static SENSOR_DEVICE_ATTR(fm_fan2_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN2_EN); ++static SENSOR_DEVICE_ATTR(fm_fan1_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN1_EN); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan3, S_IRUGO , fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN3); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan2, S_IRUGO, fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN2); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan1, S_IRUGO, fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN1); ++static SENSOR_DEVICE_ATTR(cnfan3_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN3_PRESENT); ++static SENSOR_DEVICE_ATTR(cnfan2_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN2_PRESENT); ++static SENSOR_DEVICE_ATTR(cnfan1_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN1_PRESENT); ++ ++static SENSOR_DEVICE_ATTR(port1_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT48); ++static SENSOR_DEVICE_ATTR(port49_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT49); ++static SENSOR_DEVICE_ATTR(port50_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT50); ++static SENSOR_DEVICE_ATTR(port51_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT51); ++static SENSOR_DEVICE_ATTR(port52_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT52); ++static SENSOR_DEVICE_ATTR(port53_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT53); ++static SENSOR_DEVICE_ATTR(port54_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT54); ++/* ++static SENSOR_DEVICE_ATTR(port0_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT0); ++static SENSOR_DEVICE_ATTR(port1_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT48); ++static SENSOR_DEVICE_ATTR(port49_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT49); ++static SENSOR_DEVICE_ATTR(port50_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT50); ++static SENSOR_DEVICE_ATTR(port51_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT51); ++static SENSOR_DEVICE_ATTR(port52_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT52); ++static SENSOR_DEVICE_ATTR(port53_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT53); ++*/ ++ ++static SENSOR_DEVICE_ATTR(port1_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT48); ++ ++static SENSOR_DEVICE_ATTR(fan1_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN1); ++static SENSOR_DEVICE_ATTR(fan2_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN2); ++static SENSOR_DEVICE_ATTR(fan3_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN3); ++ ++static SENSOR_DEVICE_ATTR(loc_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, LOC_LED); ++static SENSOR_DEVICE_ATTR(psu_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, PSU_LED); ++static SENSOR_DEVICE_ATTR(sys_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, SYS_LED); ++static SENSOR_DEVICE_ATTR(fan_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, FAN_LED); ++ ++static SENSOR_DEVICE_ATTR(port_led_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_PORT_LED_EN); ++static SENSOR_DEVICE_ATTR(sysled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_SYS_LED_EN); ++static SENSOR_DEVICE_ATTR(psuled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_PSU_LED_EN); ++static SENSOR_DEVICE_ATTR(fanled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_FAN_LED_EN); ++static SENSOR_DEVICE_ATTR(locled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_LOC_LED_EN); ++ ++static SENSOR_DEVICE_ATTR(poe_en_ctrl, S_IRUGO | S_IWUSR, poe_enable_read, poe_enable_write, 0); ++ ++static SENSOR_DEVICE_ATTR(psu_vsense, S_IRUGO | S_IWUSR, msci_ctl2_read, msci_ctl2_write, PSU_VSENSE); ++static SENSOR_DEVICE_ATTR(psu_pwrgd, S_IRUGO, msci_ctl2_read, NULL, PSU_PWRGD); ++static SENSOR_DEVICE_ATTR(rst_button_10s, S_IRUGO, rst_ctrl_read, NULL, RST_BUTTON_10S); ++ ++static SENSOR_DEVICE_ATTR(watchdog_timer, S_IRUGO | S_IWUSR, watchdog_timer_read, watchdog_timer_write, 0); ++static SENSOR_DEVICE_ATTR(watchdog_kick, S_IWUSR, NULL, watchdog_refresh, 0); ++static SENSOR_DEVICE_ATTR(watchdog_en, S_IRUGO | S_IWUSR, watchdog_enable_read, watchdog_enable_write, 0); ++ ++ ++static SENSOR_DEVICE_ATTR(system_power_down, S_IRUGO | S_IWUSR, power_down_read, power_down_write, 0); ++/* ++static SENSOR_DEVICE_ATTR(rst_mb_ioiexp, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MB_IOIEXP); ++static SENSOR_DEVICE_ATTR(rst_phy0_5, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_PHY0_5); ++static SENSOR_DEVICE_ATTR(rst_poe_ctr, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_POE_CTR); ++static SENSOR_DEVICE_ATTR(cpld_sysrst_mac_rst, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, CPLD_SYSRST_MAC_RST); ++static SENSOR_DEVICE_ATTR(rst_cpu_sysrst_out, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_CPU_SYSRST_OUT); ++static SENSOR_DEVICE_ATTR(rst_gphy_rst, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_GPHY_RST); ++static SENSOR_DEVICE_ATTR(rst_i2c_mux, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_I2C_MUX); ++static SENSOR_DEVICE_ATTR(rst_mac_jtag, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MAC_JTAG); ++static SENSOR_DEVICE_ATTR(rst_button_cpld_cpu, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_BUTTON_CPLD_CPU); ++static SENSOR_DEVICE_ATTR(rst_button, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_BUTTON); ++static SENSOR_DEVICE_ATTR(rst_cpld_i2c_mux, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_CPLD_I2C_MUX); ++static SENSOR_DEVICE_ATTR(rst_mac_sys, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MAC_SYS); ++ ++static SENSOR_DEVICE_ATTR(int_phy0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY0); ++static SENSOR_DEVICE_ATTR(int_phy1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY1); ++static SENSOR_DEVICE_ATTR(int_phy2, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY2); ++static SENSOR_DEVICE_ATTR(int_phy3, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY3); ++static SENSOR_DEVICE_ATTR(int_phy4_0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY4_0); ++static SENSOR_DEVICE_ATTR(int_phy4_1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY4_1); ++static SENSOR_DEVICE_ATTR(int_phy5_0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY5_0); ++static SENSOR_DEVICE_ATTR(int_phy5_1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY5_1); ++static SENSOR_DEVICE_ATTR(int_oob_ioiexp, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_OOB_IOIEXP); ++static SENSOR_DEVICE_ATTR(int_mb_ioiexp, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_MB_IOIEXP); ++static SENSOR_DEVICE_ATTR(usb_ocp_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, USB_OCP_ALERT); ++static SENSOR_DEVICE_ATTR(temp_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, TEMP_ALERT); ++static SENSOR_DEVICE_ATTR(rtc_irq, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, RTC_IRQ); ++static SENSOR_DEVICE_ATTR(psu2_int_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, PSU2_INT_ALERT); ++static SENSOR_DEVICE_ATTR(psu1_int_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, PSU1_INT_ALERT); ++static SENSOR_DEVICE_ATTR(int_pd69210, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PD69210); ++static SENSOR_DEVICE_ATTR(dev_init_done, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, DEV_INIT_DONE); ++static SENSOR_DEVICE_ATTR(fan_ctl_fail, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, FAN_CTL_FAIL); ++static SENSOR_DEVICE_ATTR(memhot, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MEMHOT); ++static SENSOR_DEVICE_ATTR(mb_system_int, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MB_SYSTEM_INT); ++static SENSOR_DEVICE_ATTR(mb_mod_pre_int, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MB_MOD_PRE_INT); ++*/ ++static struct attribute *wistron_switch_cpld_attributes[] = { ++// &sensor_dev_attr_board_rev.dev_attr.attr, ++ &sensor_dev_attr_board_id.dev_attr.attr, ++ &sensor_dev_attr_fan_direction.dev_attr.attr, ++ &sensor_dev_attr_cpld_rev.dev_attr.attr, ++ &sensor_dev_attr_build_date.dev_attr.attr, ++ ++ &sensor_dev_attr_psu2_on.dev_attr.attr, ++ &sensor_dev_attr_psu1_on.dev_attr.attr, ++ &sensor_dev_attr_psu2_ac_ok.dev_attr.attr, ++ &sensor_dev_attr_psu1_ac_ok.dev_attr.attr, ++ &sensor_dev_attr_psu2_present.dev_attr.attr, ++ &sensor_dev_attr_psu1_present.dev_attr.attr, ++ &sensor_dev_attr_psu2_power_good.dev_attr.attr, ++ &sensor_dev_attr_psu1_power_good.dev_attr.attr, ++ ++ &sensor_dev_attr_power_ctrl.dev_attr.attr, ++ &sensor_dev_attr_power_good.dev_attr.attr, ++ ++ &sensor_dev_attr_fan_full_speed.dev_attr.attr, ++ &sensor_dev_attr_fm_fan3_en.dev_attr.attr, ++ &sensor_dev_attr_fm_fan2_en.dev_attr.attr, ++ &sensor_dev_attr_fm_fan1_en.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan3.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan2.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan1.dev_attr.attr, ++ &sensor_dev_attr_cnfan3_present.dev_attr.attr, ++ &sensor_dev_attr_cnfan2_present.dev_attr.attr, ++ &sensor_dev_attr_cnfan1_present.dev_attr.attr, ++ ++ &sensor_dev_attr_port1_led.dev_attr.attr, ++ &sensor_dev_attr_port2_led.dev_attr.attr, ++ &sensor_dev_attr_port3_led.dev_attr.attr, ++ &sensor_dev_attr_port4_led.dev_attr.attr, ++ &sensor_dev_attr_port5_led.dev_attr.attr, ++ &sensor_dev_attr_port6_led.dev_attr.attr, ++ &sensor_dev_attr_port7_led.dev_attr.attr, ++ &sensor_dev_attr_port8_led.dev_attr.attr, ++ &sensor_dev_attr_port9_led.dev_attr.attr, ++ &sensor_dev_attr_port10_led.dev_attr.attr, ++ &sensor_dev_attr_port11_led.dev_attr.attr, ++ &sensor_dev_attr_port12_led.dev_attr.attr, ++ &sensor_dev_attr_port13_led.dev_attr.attr, ++ &sensor_dev_attr_port14_led.dev_attr.attr, ++ &sensor_dev_attr_port15_led.dev_attr.attr, ++ &sensor_dev_attr_port16_led.dev_attr.attr, ++ &sensor_dev_attr_port17_led.dev_attr.attr, ++ &sensor_dev_attr_port18_led.dev_attr.attr, ++ &sensor_dev_attr_port19_led.dev_attr.attr, ++ &sensor_dev_attr_port20_led.dev_attr.attr, ++ &sensor_dev_attr_port21_led.dev_attr.attr, ++ &sensor_dev_attr_port22_led.dev_attr.attr, ++ &sensor_dev_attr_port23_led.dev_attr.attr, ++ &sensor_dev_attr_port24_led.dev_attr.attr, ++ &sensor_dev_attr_port25_led.dev_attr.attr, ++ &sensor_dev_attr_port26_led.dev_attr.attr, ++ &sensor_dev_attr_port27_led.dev_attr.attr, ++ &sensor_dev_attr_port28_led.dev_attr.attr, ++ &sensor_dev_attr_port29_led.dev_attr.attr, ++ &sensor_dev_attr_port30_led.dev_attr.attr, ++ &sensor_dev_attr_port31_led.dev_attr.attr, ++ &sensor_dev_attr_port32_led.dev_attr.attr, ++ &sensor_dev_attr_port33_led.dev_attr.attr, ++ &sensor_dev_attr_port34_led.dev_attr.attr, ++ &sensor_dev_attr_port35_led.dev_attr.attr, ++ &sensor_dev_attr_port36_led.dev_attr.attr, ++ &sensor_dev_attr_port37_led.dev_attr.attr, ++ &sensor_dev_attr_port38_led.dev_attr.attr, ++ &sensor_dev_attr_port39_led.dev_attr.attr, ++ &sensor_dev_attr_port40_led.dev_attr.attr, ++ &sensor_dev_attr_port41_led.dev_attr.attr, ++ &sensor_dev_attr_port42_led.dev_attr.attr, ++ &sensor_dev_attr_port43_led.dev_attr.attr, ++ &sensor_dev_attr_port44_led.dev_attr.attr, ++ &sensor_dev_attr_port45_led.dev_attr.attr, ++ &sensor_dev_attr_port46_led.dev_attr.attr, ++ &sensor_dev_attr_port47_led.dev_attr.attr, ++ &sensor_dev_attr_port48_led.dev_attr.attr, ++ &sensor_dev_attr_port49_led.dev_attr.attr, ++ &sensor_dev_attr_port50_led.dev_attr.attr, ++ &sensor_dev_attr_port51_led.dev_attr.attr, ++ &sensor_dev_attr_port52_led.dev_attr.attr, ++ &sensor_dev_attr_port53_led.dev_attr.attr, ++ &sensor_dev_attr_port54_led.dev_attr.attr, ++/* ++ &sensor_dev_attr_port0_act_led.dev_attr.attr, ++ &sensor_dev_attr_port1_act_led.dev_attr.attr, ++ &sensor_dev_attr_port2_act_led.dev_attr.attr, ++ &sensor_dev_attr_port3_act_led.dev_attr.attr, ++ &sensor_dev_attr_port4_act_led.dev_attr.attr, ++ &sensor_dev_attr_port5_act_led.dev_attr.attr, ++ &sensor_dev_attr_port6_act_led.dev_attr.attr, ++ &sensor_dev_attr_port7_act_led.dev_attr.attr, ++ &sensor_dev_attr_port8_act_led.dev_attr.attr, ++ &sensor_dev_attr_port9_act_led.dev_attr.attr, ++ &sensor_dev_attr_port10_act_led.dev_attr.attr, ++ &sensor_dev_attr_port11_act_led.dev_attr.attr, ++ &sensor_dev_attr_port12_act_led.dev_attr.attr, ++ &sensor_dev_attr_port13_act_led.dev_attr.attr, ++ &sensor_dev_attr_port14_act_led.dev_attr.attr, ++ &sensor_dev_attr_port15_act_led.dev_attr.attr, ++ &sensor_dev_attr_port16_act_led.dev_attr.attr, ++ &sensor_dev_attr_port17_act_led.dev_attr.attr, ++ &sensor_dev_attr_port18_act_led.dev_attr.attr, ++ &sensor_dev_attr_port19_act_led.dev_attr.attr, ++ &sensor_dev_attr_port20_act_led.dev_attr.attr, ++ &sensor_dev_attr_port21_act_led.dev_attr.attr, ++ &sensor_dev_attr_port22_act_led.dev_attr.attr, ++ &sensor_dev_attr_port23_act_led.dev_attr.attr, ++ &sensor_dev_attr_port24_act_led.dev_attr.attr, ++ &sensor_dev_attr_port25_act_led.dev_attr.attr, ++ &sensor_dev_attr_port26_act_led.dev_attr.attr, ++ &sensor_dev_attr_port27_act_led.dev_attr.attr, ++ &sensor_dev_attr_port28_act_led.dev_attr.attr, ++ &sensor_dev_attr_port29_act_led.dev_attr.attr, ++ &sensor_dev_attr_port30_act_led.dev_attr.attr, ++ &sensor_dev_attr_port31_act_led.dev_attr.attr, ++ &sensor_dev_attr_port32_act_led.dev_attr.attr, ++ &sensor_dev_attr_port33_act_led.dev_attr.attr, ++ &sensor_dev_attr_port34_act_led.dev_attr.attr, ++ &sensor_dev_attr_port35_act_led.dev_attr.attr, ++ &sensor_dev_attr_port36_act_led.dev_attr.attr, ++ &sensor_dev_attr_port37_act_led.dev_attr.attr, ++ &sensor_dev_attr_port38_act_led.dev_attr.attr, ++ &sensor_dev_attr_port39_act_led.dev_attr.attr, ++ &sensor_dev_attr_port40_act_led.dev_attr.attr, ++ &sensor_dev_attr_port41_act_led.dev_attr.attr, ++ &sensor_dev_attr_port42_act_led.dev_attr.attr, ++ &sensor_dev_attr_port43_act_led.dev_attr.attr, ++ &sensor_dev_attr_port44_act_led.dev_attr.attr, ++ &sensor_dev_attr_port45_act_led.dev_attr.attr, ++ &sensor_dev_attr_port46_act_led.dev_attr.attr, ++ &sensor_dev_attr_port47_act_led.dev_attr.attr, ++ &sensor_dev_attr_port48_act_led.dev_attr.attr, ++ &sensor_dev_attr_port49_act_led.dev_attr.attr, ++ &sensor_dev_attr_port50_act_led.dev_attr.attr, ++ &sensor_dev_attr_port51_act_led.dev_attr.attr, ++ &sensor_dev_attr_port52_act_led.dev_attr.attr, ++ &sensor_dev_attr_port53_act_led.dev_attr.attr, ++*/ ++ ++ &sensor_dev_attr_port1_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port2_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port3_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port4_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port5_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port6_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port7_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port8_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port9_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port10_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port11_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port12_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port13_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port14_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port15_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port16_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port17_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port18_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port19_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port20_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port21_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port22_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port23_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port24_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port25_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port26_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port27_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port28_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port29_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port30_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port31_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port32_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port33_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port34_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port35_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port36_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port37_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port38_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port39_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port40_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port41_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port42_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port43_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port44_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port45_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port46_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port47_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port48_poe_led.dev_attr.attr, ++ ++ &sensor_dev_attr_fan1_led.dev_attr.attr, ++ &sensor_dev_attr_fan2_led.dev_attr.attr, ++ &sensor_dev_attr_fan3_led.dev_attr.attr, ++ ++ &sensor_dev_attr_loc_led.dev_attr.attr, ++ &sensor_dev_attr_psu_led.dev_attr.attr, ++ &sensor_dev_attr_sys_led.dev_attr.attr, ++ &sensor_dev_attr_fan_led.dev_attr.attr, ++ ++ &sensor_dev_attr_port_led_auto.dev_attr.attr, ++ &sensor_dev_attr_sysled_auto.dev_attr.attr, ++ &sensor_dev_attr_fanled_auto.dev_attr.attr, ++ &sensor_dev_attr_psuled_auto.dev_attr.attr, ++ &sensor_dev_attr_locled_auto.dev_attr.attr, ++ ++ &sensor_dev_attr_poe_en_ctrl.dev_attr.attr, ++ ++ &sensor_dev_attr_psu_vsense.dev_attr.attr, ++ &sensor_dev_attr_psu_pwrgd.dev_attr.attr, ++ &sensor_dev_attr_rst_button_10s.dev_attr.attr, ++ ++ &sensor_dev_attr_watchdog_timer.dev_attr.attr, ++ &sensor_dev_attr_watchdog_kick.dev_attr.attr, ++ &sensor_dev_attr_watchdog_en.dev_attr.attr, ++ ++ &sensor_dev_attr_system_power_down.dev_attr.attr, ++/* ++ &sensor_dev_attr_rst_mb_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_rst_phy0_5.dev_attr.attr, ++ &sensor_dev_attr_rst_poe_ctr.dev_attr.attr, ++ &sensor_dev_attr_cpld_sysrst_mac_rst.dev_attr.attr, ++ &sensor_dev_attr_rst_cpu_sysrst_out.dev_attr.attr, ++ &sensor_dev_attr_rst_gphy_rst.dev_attr.attr, ++ &sensor_dev_attr_rst_i2c_mux.dev_attr.attr, ++ &sensor_dev_attr_rst_mac_jtag.dev_attr.attr, ++ &sensor_dev_attr_rst_button_cpld_cpu.dev_attr.attr, ++ &sensor_dev_attr_rst_button.dev_attr.attr, ++ &sensor_dev_attr_rst_cpld_i2c_mux.dev_attr.attr, ++ &sensor_dev_attr_rst_mac_sys.dev_attr.attr, ++ ++ &sensor_dev_attr_int_phy0.dev_attr.attr, ++ &sensor_dev_attr_int_phy1.dev_attr.attr, ++ &sensor_dev_attr_int_phy2.dev_attr.attr, ++ &sensor_dev_attr_int_phy3.dev_attr.attr, ++ &sensor_dev_attr_int_phy4_0.dev_attr.attr, ++ &sensor_dev_attr_int_phy4_1.dev_attr.attr, ++ &sensor_dev_attr_int_phy5_0.dev_attr.attr, ++ &sensor_dev_attr_int_phy5_1.dev_attr.attr, ++ &sensor_dev_attr_int_oob_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_int_mb_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_usb_ocp_alert.dev_attr.attr, ++ &sensor_dev_attr_temp_alert.dev_attr.attr, ++ &sensor_dev_attr_rtc_irq.dev_attr.attr, ++ &sensor_dev_attr_psu2_int_alert.dev_attr.attr, ++ &sensor_dev_attr_psu1_int_alert.dev_attr.attr, ++ &sensor_dev_attr_int_pd69210.dev_attr.attr, ++ &sensor_dev_attr_dev_init_done.dev_attr.attr, ++ &sensor_dev_attr_fan_ctl_fail.dev_attr.attr, ++ &sensor_dev_attr_memhot.dev_attr.attr, ++ &sensor_dev_attr_mb_system_int.dev_attr.attr, ++ &sensor_dev_attr_mb_mod_pre_int.dev_attr.attr, ++*/ ++ NULL ++}; ++ ++static const struct attribute_group wistron_switch_cpld_group = { ++ .attrs = wistron_switch_cpld_attributes, ++}; ++ ++ ++/* ---------------------------------------------------------------------------- ++ * Module probe/remove functions ++ * ---------------------------------------------------------------------------- ++ */ ++static int _add_client(struct i2c_client *client) ++{ ++ struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); ++ if (!node) { ++ dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); ++ return -ENOMEM; ++ } ++ ++ node->client = client; ++ ++ mutex_lock(&list_lock); ++ list_add(&node->list, &cpld_client_list); ++ mutex_unlock(&list_lock); ++ ++ return 0; ++} ++ ++static int _remove_client(struct i2c_client *client) ++{ ++ struct list_head *list_node = NULL; ++ struct cpld_client_node *cpld_node = NULL; ++ int found = 0; ++ ++ mutex_lock(&list_lock); ++ ++ list_for_each(list_node, &cpld_client_list) { ++ cpld_node = list_entry(list_node, struct cpld_client_node, list); ++ ++ if (cpld_node->client == client) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (found) { ++ list_del(list_node); ++ kfree(cpld_node); ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ return 0; ++} ++ ++/* Probe I2C driver */ ++static int wistron_i2c_cpld_probe(struct i2c_client *client, ++ const struct i2c_device_id *dev_id) ++{ ++ int status; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); ++ status = -EIO; ++ goto exit; ++ } ++ ++ status = _add_client(client); ++ if (status < 0) { ++ dev_err(&client->dev, "Failed to add client\n"); ++ goto exit; ++ } ++ ++ status = sysfs_create_group(&client->dev.kobj, &wistron_switch_cpld_group); ++ ++ if (status) { ++ goto exit; ++ } ++ ++ dev_info(&client->dev, "chip found\n"); ++ ++ return 0; ++ ++exit: ++ return status; ++} ++ ++static void wistron_i2c_cpld_remove(struct i2c_client *client) ++{ ++ _remove_client(client); ++ ++ sysfs_remove_group(&client->dev.kobj, &wistron_switch_cpld_group); ++ ++} ++ ++/* ---------------------------------------------------------------------------- ++ * Module main functions ++ * ---------------------------------------------------------------------------- ++ */ ++static const struct i2c_device_id wistron_i2c_cpld_id[] = { ++ {"wistron_cpld", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, wistron_i2c_cpld_id); ++ ++static struct i2c_driver wistron_i2c_cpld_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "wistron_cpld", ++ }, ++ .probe = wistron_i2c_cpld_probe, ++ .remove = wistron_i2c_cpld_remove, ++ .id_table = wistron_i2c_cpld_id, ++}; ++ ++static int __init wistron_i2c_cpld_init(void) ++{ ++ mutex_init(&list_lock); ++ ++ return i2c_add_driver(&wistron_i2c_cpld_driver); ++} ++ ++static void __exit wistron_i2c_cpld_exit(void) ++{ ++ i2c_del_driver(&wistron_i2c_cpld_driver); ++} ++ ++ ++MODULE_AUTHOR("Wistron"); ++MODULE_DESCRIPTION("SONiC platform driver for Wistron CPLD"); ++MODULE_LICENSE("GPL"); ++ ++module_init(wistron_i2c_cpld_init); ++module_exit(wistron_i2c_cpld_exit); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.h b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.h +new file mode 100755 +index 000000000..db3475da4 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_cpld.h +@@ -0,0 +1,298 @@ ++ ++/*************************************************************************** ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ ***************************************************************************/ ++ ++ ++#ifndef _WISTRON_SWITCH_CPLD_H ++#define _WISTRON_SWITCH_CPLD_H ++ ++//#define CPLD_REVISION_REG 0x0 ++#define CPLD_HW_REVISION_REG 0x1 ++#define CPLD_REVISION_REG 0x2 ++#define CPLD_BUILD_YEAR_REG 0x3 ++#define CPLD_BUILD_DATE_REG 0x4 ++#define CPLD_RW_TEST_REG 0x5 ++#define CPLD_PSU_CHECK_REG 0x6 ++ ++#define CPLD_POWER_CTL1_REG 0x7 ++#define CPLD_POWER_CTL2_REG 0x8 ++ ++#define CPLD_POWER_GOOD_REG 0x9 ++#define CPLD_POWER_GOOD2_REG 0xA ++ ++#define CPLD_FAN_CTL1_REG 0xB ++#define CPLD_FAN_CTL2_REG 0xC ++ ++ ++#define CPLD_1G_LED_CTL1_REG 0xD ++#define CPLD_1G_LED_CTL2_REG 0xE ++#define CPLD_1G_LED_CTL3_REG 0xF ++#define CPLD_1G_LED_CTL4_REG 0x10 ++#define CPLD_1G_LED_CTL5_REG 0x11 ++#define CPLD_1G_LED_CTL6_REG 0x12 ++#define CPLD_1G_LED_CTL7_REG 0x13 ++#define CPLD_1G_LED_CTL8_REG 0x14 ++#define CPLD_1G_LED_CTL9_REG 0x15 ++#define CPLD_1G_LED_CTL10_REG 0x16 ++#define CPLD_1G_LED_CTL11_REG 0x17 ++#define CPLD_1G_LED_CTL12_REG 0x18 ++#define CPLD_1G_LED_CTL13_REG 0x19 ++#define CPLD_1G_LED_CTL14_REG 0x1A ++#define CPLD_1G_LED_CTL15_REG 0x1B ++#define CPLD_1G_LED_CTL16_REG 0x1C ++ ++#define CPLD_2_5G_LED_CTL1_REG 0x1D ++#define CPLD_2_5G_LED_CTL2_REG 0x1E ++#define CPLD_2_5G_LED_CTL3_REG 0x1F ++#define CPLD_2_5G_LED_CTL4_REG 0x20 ++#define CPLD_2_5G_LED_CTL5_REG 0x21 ++#define CPLD_2_5G_LED_CTL6_REG 0x22 ++#define CPLD_2_5G_LED_CTL7_REG 0x23 ++#define CPLD_2_5G_LED_CTL8_REG 0x24 ++ ++#define CPLD_POE_PRT_LED_CTL1_REG 0x25 ++#define CPLD_POE_PRT_LED_CTL2_REG 0x26 ++#define CPLD_POE_PRT_LED_CTL3_REG 0x27 ++#define CPLD_POE_PRT_LED_CTL4_REG 0x28 ++#define CPLD_POE_PRT_LED_CTL5_REG 0x29 ++#define CPLD_POE_PRT_LED_CTL6_REG 0x2A ++#define CPLD_POE_PRT_LED_CTL7_REG 0x2B ++#define CPLD_POE_PRT_LED_CTL8_REG 0x2C ++#define CPLD_POE_PRT_LED_CTL9_REG 0x2D ++#define CPLD_POE_PRT_LED_CTL10_REG 0x2E ++#define CPLD_POE_PRT_LED_CTL11_REG 0x2F ++#define CPLD_POE_PRT_LED_CTL12_REG 0x30 ++ ++#define CPLD_SFP_LED_CTL1_REG 0x31 ++#define CPLD_SFP_LED_CTL2_REG 0x32 ++#define CPLD_SFP_LED_CTL3_REG 0x33 ++ ++ ++#define CPLD_FAN_LED_CTL_REG 0x34 ++#define CPLD_SYS_LED_CTL_REG 0x35 ++ ++#define CPLD_RESET_CTL1_REG 0x36 ++#define CPLD_RESET_CTL2_REG 0x37 ++ ++#define CPLD_INT_CTL1_REG 0x38 ++#define CPLD_INT_CTL2_REG 0x39 ++#define CPLD_INT_CTL3_REG 0x3A ++#define CPLD_INT_CTL4_REG 0x3B ++#define CPLD_MSCI_CTL_REG 0x3C ++#define CPLD_PORT_LED_MANUAL_REG 0x3D ++#define CPLD_RESET_CTL3_REG 0x3E ++#define CPLD_MSCI_CTL2_REG 0x3F ++#define CPLD_WATCHDOG_REG 0x40 ++#define CPLD_SYS_POWER_DOWN_REG 0x41 ++ ++static char* power_ctrl_str1[] = { ++ "P1V2_OOB_EN", // 0 ++ "P1V5_EN", ++ "P1V8_CPU_EN", ++ "P1V8", ++ "P2V5_CPU_DDR4_EN", ++ "P2V5_EN", ++ "P3V3_EN", ++ "P5V0_EN", // 7 ++}; ++ ++static char* power_ctrl_str2[] = { ++ "PHY_P0V8_EN", // 0 ++ "P0V8_MAC_EN", ++ "P0V85_CPU_AP_VDD_EN", ++ "P1V15_EN", ++ "P0V6_CPU_DDR4_VTT_EN", ++ "P0V6_EN", ++ "P1V2_CPU_DDR4_EN", ++ "P1V2_EN", // 7 ++}; ++ ++static char* power_good_str1[] = { ++ "PWRGD_VR_P1V2_OOB", // 0 ++ "PWRGD_P1V5", ++ "PWRGD_P1V8_CPU", ++ "PWRGD_P1V8", ++ "PWRGD_P2V5_CPU_DDR4", ++ "PWRGD_P2V5", ++ "PWRGD_P3V3", ++ "PWRGD_P5V0", // 7 ++}; ++ ++static char* power_good_str2[] = { ++ "PWRGD_PHY_P0V8", // 0 ++ "PWRGD_VR_MAC_P0V8", ++ "PWRGD_P0V85_CPU_AP_VDD", ++ "PWRGD_P1V15", ++ "PWRGD_VR_P0V6_CPU_DDR4_VTT", ++ "PWRGD_VR_P0V6", ++ "PWRGD_P1V2_CPU_DDR4", ++ "PWRGD_P1V2", ++}; ++ ++enum psu_status_bit { ++ PSU2_ON = 0, ++ PSU1_ON, ++ PSU2_AC_OK, ++ PSU1_AC_OK, ++ PSU2_PRESENT, ++ PSU1_PRESENT, ++ PSU2_PWRGD, ++ PSU1_PWRGD, ++}; ++ ++enum fan_control_bit { ++ FAN_FULL_SPEED = 0, ++ FM_FAN3_EN = 1, ++ FM_FAN2_EN = 2, ++ FM_FAN1_EN = 3, ++ FM_FAN3_TYPE = 4, ++ FM_FAN2_TYPE = 5, ++ FM_FAN1_TYPE = 6, ++ PWRGD_VR_P12V_FAN3 = 7, ++ PWRGD_VR_P12V_FAN2 = 8, ++ PWRGD_VR_P12V_FAN1 = 9, ++ CNFAN3_PRESENT = 10, ++ CNFAN2_PRESENT = 11, ++ CNFAN1_PRESENT = 12, ++}; ++ ++enum fan_id { ++ FAN3 = 0, ++ FAN2, ++ FAN1, ++}; ++ ++enum port_id { ++ PORT1 = 0, ++ PORT2, ++ PORT3, ++ PORT4, ++ PORT5, ++ PORT6, ++ PORT7, ++ PORT8, ++ PORT9, ++ PORT10, ++ PORT11, ++ PORT12, ++ PORT13, ++ PORT14, ++ PORT15, ++ PORT16, ++ PORT17, ++ PORT18, ++ PORT19, ++ PORT20, ++ PORT21, ++ PORT22, ++ PORT23, ++ PORT24, ++ PORT25, ++ PORT26, ++ PORT27, ++ PORT28, ++ PORT29, ++ PORT30, ++ PORT31, ++ PORT32, ++ PORT33, ++ PORT34, ++ PORT35, ++ PORT36, ++ PORT37, ++ PORT38, ++ PORT39, ++ PORT40, ++ PORT41, ++ PORT42, ++ PORT43, ++ PORT44, ++ PORT45, ++ PORT46, ++ PORT47, ++ PORT48, ++ PORT49, ++ PORT50, ++ PORT51, ++ PORT52, ++ PORT53, ++ PORT54, ++}; ++ ++enum led_status_shift_bit { ++ LOC_LED = 0, ++ PSU_LED = 2, ++ SYS_LED = 4, ++ FAN_LED = 6, ++}; ++ ++enum rst_shift_bit { ++ RST_MB_IOIEXP = 0, ++ RST_PHY0_5 = 1, ++ RST_POE_CTR = 2, ++ CPLD_SYSRST_MAC_RST = 3, ++ RST_CPU_SYSRST_OUT = 4, ++ RST_GPHY_RST = 5, ++ RST_I2C_MUX = 6, ++ RST_MAC_JTAG = 7, ++ RST_BUTTON_CPLD_CPU = 8, ++ RST_BUTTON = 9, ++ RST_CPLD_I2C_MUX = 10, ++ RST_BUTTON_10S = 1, ++}; ++ ++enum int_shift_bit { ++ INT_PHY0 = 0, ++ INT_PHY1 = 1, ++ INT_PHY2 = 2, ++ INT_PHY3 = 3, ++ INT_PHY4_0 = 4, ++ INT_PHY4_1 = 5, ++ INT_PHY5_0 = 6, ++ INT_PHY5_1 = 7, ++ ++ INT_OOB_IOIEXP = 8, ++ INT_MB_IOIEXP = 9, ++ USB_OCP_ALERT = 10, ++ TEMP_ALERT = 11, ++ RTC_IRQ = 12, ++ PSU2_INT_ALERT = 13, ++ PSU1_INT_ALERT = 14, ++ INT_PD69210 = 15, ++ ++ DEV_INIT_DONE = 16, ++ FAN_CTL_FAIL = 17, ++ MEMHOT = 18, ++ ++ MB_SYSTEM_INT = 19, ++ MB_MOD_PRE_INT = 20, ++}; ++ ++enum msci_ctl2_shift_bit { ++ PSU_VSENSE = 0, ++ PSU_PWRGD = 1, ++}; ++ ++enum sysled_en_shift_bit { ++ FRONT_PORT_LED_EN = 0, ++ FRONT_SYS_LED_EN = 1, ++ FRONT_PSU_LED_EN = 2, ++ FRONT_FAN_LED_EN = 3, ++ FRONT_LOC_LED_EN = 4, ++}; ++ ++enum watchdog_timer_def { ++ WATCHDOG_180S = 0, ++ WATCHDOG_210S = 1, ++ WATCHDOG_240S = 2, ++ WATCHDOG_270S = 3, ++ WATCHDOG_300S = 4, ++}; ++ ++#endif /* _WISTRON_SWITCH_CPLD_H */ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_max31790.c b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_max31790.c +new file mode 100755 +index 000000000..78a0daadf +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_max31790.c +@@ -0,0 +1,604 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * max31790.c - Part of lm_sensors, Linux kernel modules for hardware ++ * monitoring. ++ * ++ * (C) 2015 by Il Han ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MAX31790 registers */ ++#define MAX31790_REG_GLOBAL_CONFIG 0x00 ++#define MAX31790_REG_FAN_CONFIG(ch) (0x02 + (ch)) ++#define MAX31790_REG_FAN_DYNAMICS(ch) (0x08 + (ch)) ++#define MAX31790_REG_FAN_FAULT_STATUS2 0x10 ++#define MAX31790_REG_FAN_FAULT_STATUS1 0x11 ++#define MAX31790_REG_TACH_COUNT(ch) (0x18 + (ch) * 2) ++#define MAX31790_REG_PWM_DUTY_CYCLE(ch) (0x30 + (ch) * 2) ++#define MAX31790_REG_PWMOUT(ch) (0x40 + (ch) * 2) ++#define MAX31790_REG_TARGET_COUNT(ch) (0x50 + (ch) * 2) ++ ++/* Fan Config register bits */ ++#define MAX31790_FAN_CFG_RPM_MODE 0x80 ++#define MAX31790_FAN_CFG_CTRL_MON 0x10 ++#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08 ++#define MAX31790_FAN_CFG_TACH_INPUT 0x01 ++ ++/* Fan Dynamics register bits */ ++#define MAX31790_FAN_DYN_SR_SHIFT 5 ++#define MAX31790_FAN_DYN_SR_MASK 0xE0 ++#define SR_FROM_REG(reg) (((reg) & MAX31790_FAN_DYN_SR_MASK) \ ++ >> MAX31790_FAN_DYN_SR_SHIFT) ++ ++#define FAN_RPM_MIN 120 ++#define FAN_RPM_MAX 7864320 ++ ++#define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \ ++ ((60 * (sr) * 8192) / ((reg) >> 4)) : \ ++ FAN_RPM_MAX) ++#define RPM_TO_REG(rpm, sr) ((60 * (sr) * 8192) / ((rpm) * 2)) ++ ++#define NR_CHANNEL 6 ++ ++#define MAX31790_REG_FREQ_CONFIG 0x01 ++#define MAX31790_REG_FAIL_MASK2 0x12 ++#define MAX31790_REG_FAIL_MASK1 0x13 ++#define MAX31790_REG_FAIL_CTRL 0x14 ++static char *platform; ++module_param(platform, charp, 0000); ++MODULE_PARM_DESC(platform, "platform name (support ES-1227)."); ++ ++enum { ++ PLATFORM_ES1227 = 1, ++ PLATFORM_LAST, ++}; ++ ++struct max31790_init_data { ++ u8 freq; ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++#if 0 ++ u8 fail_mask[2]; ++ u8 fail_ctrl; ++#endif ++}; ++ ++struct max31790_init_data platform_init_data[PLATFORM_LAST - 1] = ++{ ++ { ++ .freq = 0xbb, ++ .fan_config = {0x68, 0x79, 0x68, 0x68, 0x79, 0x79}, ++ .fan_dynamics = {0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c}, ++#if 0 ++ .fail_mask = {0x3d, 0x20}, ++ .fail_ctrl = 0x45, ++#endif ++ }, ++}; ++/* ++ * Client data (each client gets its own) ++ */ ++struct max31790_data { ++ struct i2c_client *client; ++ struct mutex update_lock; ++ bool valid; /* zero until following fields are valid */ ++ unsigned long last_updated; /* in jiffies */ ++ ++ /* register values */ ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++ u16 fault_status; ++ u16 tach[NR_CHANNEL * 2]; ++ u16 pwm[NR_CHANNEL]; ++ u16 target_count[NR_CHANNEL]; ++}; ++ ++static struct max31790_data *max31790_update_device(struct device *dev) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ struct max31790_data *ret = data; ++ int i; ++ int rv; ++ ++ mutex_lock(&data->update_lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS1); ++ if (rv < 0) ++ goto abort; ++ data->fault_status = rv & 0x3F; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS2); ++ if (rv < 0) ++ goto abort; ++ data->fault_status |= (rv & 0x3F) << 6; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(NR_CHANNEL ++ + i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[NR_CHANNEL + i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_PWMOUT(i)); ++ if (rv < 0) ++ goto abort; ++ data->pwm[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->target_count[i] = rv; ++ } ++ ++ data->last_updated = jiffies; ++ data->valid = true; ++ } ++ goto done; ++ ++abort: ++ data->valid = false; ++ ret = ERR_PTR(rv); ++ ++done: ++ mutex_unlock(&data->update_lock); ++ ++ return ret; ++} ++ ++static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; ++ ++static u8 get_tach_period(u8 fan_dynamics) ++{ ++ return tach_period[SR_FROM_REG(fan_dynamics)]; ++} ++ ++static u8 bits_for_tach_period(int rpm) ++{ ++ u8 bits; ++ ++ if (rpm < 500) ++ bits = 0x0; ++ else if (rpm < 1000) ++ bits = 0x1; ++ else if (rpm < 2000) ++ bits = 0x2; ++ else if (rpm < 4000) ++ bits = 0x3; ++ else if (rpm < 8000) ++ bits = 0x4; ++ else ++ bits = 0x5; ++ ++ return bits; ++} ++ ++static int max31790_read_fan(struct device *dev, u32 attr, int channel, ++ long *val) ++{ ++ struct max31790_data *data = max31790_update_device(dev); ++ int sr, rpm; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]); ++ rpm = RPM_FROM_REG(data->tach[channel], sr); ++ *val = rpm; ++ return 0; ++ case hwmon_fan_target: ++ sr = get_tach_period(data->fan_dynamics[channel]); ++ rpm = RPM_FROM_REG(data->target_count[channel], sr); ++ *val = rpm; ++ return 0; ++ case hwmon_fan_fault: ++ *val = !!(data->fault_status & (1 << channel)); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write_fan(struct device *dev, u32 attr, int channel, ++ long val) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ int target_count; ++ int err = 0; ++ u8 bits; ++ int sr; ++ ++ mutex_lock(&data->update_lock); ++ ++ switch (attr) { ++ case hwmon_fan_target: ++ val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX); ++ bits = bits_for_tach_period(val); ++ data->fan_dynamics[channel] = ++ ((data->fan_dynamics[channel] & ++ ~MAX31790_FAN_DYN_SR_MASK) | ++ (bits << MAX31790_FAN_DYN_SR_SHIFT)); ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(channel), ++ data->fan_dynamics[channel]); ++ if (err < 0) ++ break; ++ ++ sr = get_tach_period(data->fan_dynamics[channel]); ++ target_count = RPM_TO_REG(val, sr); ++ target_count = clamp_val(target_count, 0x1, 0x7FF); ++ ++ data->target_count[channel] = target_count << 5; ++ ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(channel), ++ data->target_count[channel]); ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return err; ++} ++ ++static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) ++{ ++ const struct max31790_data *data = _data; ++ u8 fan_config = data->fan_config[channel % NR_CHANNEL]; ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ case hwmon_fan_fault: ++ if (channel < NR_CHANNEL || ++ (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0444; ++ return 0; ++ case hwmon_fan_target: ++ if (channel < NR_CHANNEL && ++ !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0644; ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int max31790_read_pwm(struct device *dev, u32 attr, int channel, ++ long *val) ++{ ++ struct max31790_data *data = max31790_update_device(dev); ++ u8 fan_config; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ fan_config = data->fan_config[channel]; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ *val = data->pwm[channel] >> 8; ++ return 0; ++ case hwmon_pwm_enable: ++ if (fan_config & MAX31790_FAN_CFG_CTRL_MON) ++ *val = 0; ++ else if (fan_config & MAX31790_FAN_CFG_RPM_MODE) ++ *val = 2; ++ else ++ *val = 1; ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write_pwm(struct device *dev, u32 attr, int channel, ++ long val) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ u8 fan_config; ++ int err = 0; ++ int i = 0; ++ ++ mutex_lock(&data->update_lock); ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ if (val < 0 || val > 255) { ++ err = -EINVAL; ++ break; ++ } ++ data->pwm[channel] = val << 8; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_PWMOUT(i), ++ data->pwm[channel]); ++ } ++ break; ++ case hwmon_pwm_enable: ++ fan_config = data->fan_config[channel]; ++ if (val == 0) { ++ fan_config |= MAX31790_FAN_CFG_CTRL_MON; ++ /* ++ * Disable RPM mode; otherwise disabling fan speed ++ * monitoring is not possible. ++ */ ++ fan_config &= ~MAX31790_FAN_CFG_RPM_MODE; ++ } else if (val == 1) { ++ fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE); ++ } else if (val == 2) { ++ fan_config &= ~MAX31790_FAN_CFG_CTRL_MON; ++ /* ++ * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its ++ * own if MAX31790_FAN_CFG_RPM_MODE is set. ++ * Do it here as well to reflect the actual register ++ * value in the cache. ++ */ ++ fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN); ++ } else { ++ err = -EINVAL; ++ break; ++ } ++ if (fan_config != data->fan_config[channel]) { ++ err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel), ++ fan_config); ++ if (!err) ++ data->fan_config[channel] = fan_config; ++ } ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return err; ++} ++ ++static umode_t max31790_pwm_is_visible(const void *_data, u32 attr, int channel) ++{ ++ const struct max31790_data *data = _data; ++ u8 fan_config = data->fan_config[channel]; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ case hwmon_pwm_enable: ++ if (!(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0644; ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int max31790_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_read_fan(dev, attr, channel, val); ++ case hwmon_pwm: ++ return max31790_read_pwm(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_write_fan(dev, attr, channel, val); ++ case hwmon_pwm: ++ return max31790_write_pwm(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static umode_t max31790_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_fan_is_visible(data, attr, channel); ++ case hwmon_pwm: ++ return max31790_pwm_is_visible(data, attr, channel); ++ default: ++ return 0; ++ } ++} ++ ++static const struct hwmon_channel_info *max31790_info[] = { ++ HWMON_CHANNEL_INFO(fan, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT), ++ HWMON_CHANNEL_INFO(pwm, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE), ++ NULL ++}; ++ ++static const struct hwmon_ops max31790_hwmon_ops = { ++ .is_visible = max31790_is_visible, ++ .read = max31790_read, ++ .write = max31790_write, ++}; ++ ++static const struct hwmon_chip_info max31790_chip_info = { ++ .ops = &max31790_hwmon_ops, ++ .info = max31790_info, ++}; ++ ++static int max31790_init_setup(struct i2c_client *client, ++ int platform_id) ++{ ++ int i, rv; ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FREQ_CONFIG, ++ platform_init_data[platform_id - 1].freq); ++ if (rv < 0) ++ return rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i), ++ platform_init_data[platform_id - 1].fan_config[i]); ++ if (rv < 0) ++ return rv; ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i), ++ platform_init_data[platform_id - 1].fan_dynamics[i]); ++ if (rv < 0) ++ return rv; ++ } ++ ++#if 0 ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_MASK2, ++ platform_init_data[platform_id - 1].fail_mask[0]); ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_MASK1, ++ platform_init_data[platform_id - 1].fail_mask[1]); ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_CTRL, ++ platform_init_data[platform_id - 1].fail_ctrl); ++#endif ++ return 0; ++} ++ ++static int max31790_init_client(struct i2c_client *client, ++ struct max31790_data *data) ++{ ++ int i, rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_config[i] = rv; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_dynamics[i] = rv; ++ } ++ ++ return 0; ++} ++ ++static int max31790_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct device *dev = &client->dev; ++ struct max31790_data *data; ++ struct device *hwmon_dev; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) ++ return -ENODEV; ++ ++ data = devm_kzalloc(dev, sizeof(struct max31790_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ mutex_init(&data->update_lock); ++ ++ /* ++ * Initialize the max31790 chip ++ */ ++ if (id->driver_data != 0) { ++ err = max31790_init_setup(client, id->driver_data); ++ } else { ++ if (!strcmp(platform, "1227")) ++ err = max31790_init_setup(client, PLATFORM_ES1227); ++ } ++ ++ if (err) ++ return err; ++ ++ err = max31790_init_client(client, data); ++ if (err) ++ return err; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ++ data, ++ &max31790_chip_info, ++ NULL); ++ ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static const struct i2c_device_id max31790_id[] = { ++ { "max31790", 0 }, ++ { "1227_max31790", PLATFORM_ES1227}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max31790_id); ++ ++static struct i2c_driver max31790_driver = { ++ .class = I2C_CLASS_HWMON, ++ .probe = max31790_probe, ++ .driver = { ++ .name = "wistron_max31790", ++ }, ++ .id_table = max31790_id, ++}; ++ ++module_i2c_driver(max31790_driver); ++ ++MODULE_AUTHOR("Il Han "); ++MODULE_DESCRIPTION("MAX31790 sensor driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_psu.c b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_psu.c +new file mode 100755 +index 000000000..d873fe3aa +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/modules/wistron_psu.c +@@ -0,0 +1,248 @@ ++/* ++ * Wistron Generic PMBUS driver ++ * ++ * ++ * Based on pmbus_core driver and ltc2978 driver ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pmbus.h" ++ ++static int pmbus_read_block_data(struct i2c_client *client, u8 command, u8 *data) ++{ ++ int result = 0; ++ int retry_count = 3; ++ ++ while (retry_count) { ++ retry_count--; ++ ++ result = i2c_smbus_read_i2c_block_data(client, command, I2C_SMBUS_BLOCK_MAX, data); ++ ++ if (result < 0) { ++ msleep(10); ++ continue; ++ } ++ ++ result = 0; ++ break; ++ } ++ ++ return result; ++} ++ ++/* ---------------------------------------------------------------------------- ++ * export function for specified use ++ * ---------------------------------------------------------------------------- ++ */ ++ ++static ssize_t wistron_psu_get_vendor(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer ID\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++ ++} ++ ++static ssize_t wistron_psu_get_model(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer Model\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static ssize_t wistron_psu_get_version(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_REVISION, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer Revision\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static ssize_t wistron_psu_get_location(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_LOCATION, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacture Location\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static ssize_t wistron_psu_get_serial(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_SERIAL, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer Serial\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static DEVICE_ATTR(mfr_id, S_IRUGO, wistron_psu_get_vendor, NULL); ++static DEVICE_ATTR(mfr_model, S_IRUGO, wistron_psu_get_model, NULL); ++static DEVICE_ATTR(mfr_revision, S_IRUGO, wistron_psu_get_version, NULL); ++static DEVICE_ATTR(mfr_location, S_IRUGO, wistron_psu_get_location, NULL); ++static DEVICE_ATTR(mfr_serial, S_IRUGO, wistron_psu_get_serial, NULL); ++ ++static struct attribute *wistron_pmbus_attributes[] = { ++ &dev_attr_mfr_id.attr, ++ &dev_attr_mfr_model.attr, ++ &dev_attr_mfr_revision.attr, ++ &dev_attr_mfr_location.attr, ++ &dev_attr_mfr_serial.attr, ++ NULL ++}; ++ ++static const struct attribute_group wistron_pmbus_group = { ++ .attrs = wistron_pmbus_attributes, ++}; ++ ++static const struct i2c_device_id pmbus_id[] = { ++ {"wistron_psu", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, pmbus_id); ++ ++struct pmbus_driver_info wistron_psu_info = { ++ .pages = 1, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | ++ PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | ++ PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | ++ PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_POUT, ++}; ++ ++static int pmbus_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ int ret; ++ ++ dev_info(dev, "wistron-psu pmbus_probe\n"); ++ ++ if (!i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_WORD_DATA)) ++ return -ENODEV; ++ ++ /* Register sysfs hooks */ ++ ret = sysfs_create_group(&client->dev.kobj, &wistron_pmbus_group); ++ if (ret) { ++ dev_err(dev, "Failed to create sysfs entries\n"); ++ goto exit; ++ } ++ ++ return pmbus_do_probe(client, &wistron_psu_info); ++ ++exit: ++ return ret; ++} ++ ++static struct i2c_driver pmbus_driver = { ++ .driver = { ++ .name = "wistron-psu", ++ }, ++ .probe = pmbus_probe, ++ .id_table = pmbus_id, ++}; ++ ++static int __init pmbus_driver_init(void) ++{ ++ return i2c_add_driver(&pmbus_driver); ++} ++ ++static void __exit pmbus_driver_exit(void) ++{ ++ i2c_del_driver(&pmbus_driver); ++} ++ ++module_init(pmbus_driver_init); ++module_exit(pmbus_driver_exit); ++ ++MODULE_AUTHOR("Wistron"); ++MODULE_VERSION("1.0"); ++MODULE_DESCRIPTION("SONiC platform driver for Wistron PSU"); ++MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(PMBUS); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/entropy.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/entropy.py +new file mode 100644 +index 000000000..338e2ad9b +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/entropy.py +@@ -0,0 +1,19 @@ ++#!/usr/bin/python ++import fcntl, struct ++import time ++from os import path ++ ++RNDADDENTROPY=0x40085203 ++ ++def avail(): ++ with open("/proc/sys/kernel/random/entropy_avail", mode='r') as avail: ++ return int(avail.read()) ++ ++if path.exists("/proc/sys/kernel/random/entropy_avail"): ++ while 1: ++ while avail() < 2048: ++ with open('/dev/urandom', 'rb') as urnd, open("/dev/random", mode='wb') as rnd: ++ d = urnd.read(512) ++ t = struct.pack('ii', 4 * len(d), len(d)) + d ++ fcntl.ioctl(rnd, RNDADDENTROPY, t) ++ time.sleep(30) +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts-init.sh b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts-init.sh +new file mode 100755 +index 000000000..e823bb8a8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts-init.sh +@@ -0,0 +1,106 @@ ++#!/bin/bash ++ ++# Platform init script ++ ++# Load required kernel-mode drivers ++load_kernel_drivers() { ++ # Remove modules loaded during Linux init ++ # FIX-ME: This will be removed in the future when Linux init no longer loads these ++ rmmod i2c_dev ++ rmmod i2c_mv64xxx ++ ++ # Carefully control the load order here to ensure consistent i2c bus numbering ++ modprobe i2c_mv64xxx ++ modprobe i2c_dev ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_cpld.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_max31790.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_psu.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/mvcpss.ko ++ modprobe optoe ++ modprobe jc42 ++} ++ ++# - Main entry ++ ++# Install kernel drivers required for i2c bus access ++load_kernel_drivers ++#entropy setting ++#python /etc/entropy.py ++ echo wistron_cpld 0x33 > /sys/bus/i2c/devices/i2c-0/new_device ++ echo 1227_max31790 0x2f > /sys/bus/i2c/devices/i2c-2/new_device ++ ++ echo jc42 0x1b > /sys/bus/i2c/devices/i2c-0/new_device ++ echo wistron_psu 0x58 > /sys/bus/i2c/devices/i2c-3/new_device ++ echo wistron_psu 0x59 > /sys/bus/i2c/devices/i2c-3/new_device ++ ++ tca_detect=$(i2cget -f -y 5 0x22 0x40 1>/dev/null 2>/dev/null; echo $?) ++ if [ $tca_detect -eq 0 ]; then ++ i2cset -y 5 0x22 0x54 0x22 ++ i2cset -y 5 0x22 0x55 0x22 ++ i2cset -y 5 0x22 0x56 0x22 ++ echo pcal6524 0x22 > /sys/bus/i2c/devices/i2c-5/new_device ++ else ++ echo tca6424 0x22 > /sys/bus/i2c/devices/i2c-5/new_device ++ fi ++ ++ local i ++ for i in {4..9}; ++ do ++ echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device ++ done ++ local j ++ for j in {472..495}; ++ do ++ echo $j > /sys/class/gpio/export ++ done ++ local k ++ for k in $(seq 473 4 493); do ++ echo out > /sys/class/gpio/gpio$k/direction ++ done ++ ++ for i in {0..2}; ++ do ++ echo 85000 > /sys/class/hwmon/hwmon$i/temp1_max ++ echo 80000 > /sys/class/hwmon/hwmon$i/temp1_max_hyst ++ done ++ ++ echo 80000 > /sys/class/hwmon/hwmon4/temp1_max ++ echo 85000 > /sys/class/hwmon/hwmon4/temp1_crit ++ ++ echo 1 > /sys/bus/i2c/devices/0-0033/port_led_auto ++ ++ # init oob port led ++ phytool write eth0/0/22 3; ++ phytool write eth0/0/17 0x44a5; ++ phytool write eth0/0/22 3; ++ phytool write eth0/0/16 0x0240; ++ phytool write eth0/0/22 0 ++ ++ # set rj port sgmii amplitude ++ phytool write eth0/0/22 2; ++ phytool write eth0/0/26 0x8004; ++ phytool write eth0/0/22 0 ++ ++ echo 496 > /sys/class/gpio/export ++ echo out > /sys/class/gpio/gpio496/direction ++ for k in $(seq 498 499); do ++ echo $k > /sys/class/gpio/export ++ echo out > /sys/class/gpio/gpio$k/direction ++ done ++ ++ # default set sfp txdisable to off ++ echo 0 > /sys/class/gpio/gpio496/value ++ ++ a=0; b=1 ++ ++ echo $a > /sys/class/gpio/gpio498/value; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 1; fi ++ ++ echo $b > /sys/class/gpio/gpio499/value; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 2; fi ++ ++ # Set auto select mode - Prefer copper medium ++ phytool write eth0/0/22 2; ++ phytool write eth0/0/16 0xa88; ++ phytool write eth0/0/22 0; ++exit 0 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts_plt_setup.sh b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts_plt_setup.sh +new file mode 100755 +index 000000000..e1df59d26 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/es1227_54ts_plt_setup.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++ ++fw_uboot_env_cfg() ++{ ++ echo "Setting up U-Boot environment..." ++ MACH_FILE="/host/machine.conf" ++ PLATFORM=`sed -n 's/onie_platform=\(.*\)/\1/p' $MACH_FILE` ++} ++ ++es1227_54ts_profile() ++{ ++ MAC_ADDR=$(fw_printenv -n ethaddr) ++ find /usr/share/sonic/device/*es1227_54ts* -name profile.ini | xargs sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" ++ echo "es1227_54ts: Updating switch mac address ${MAC_ADDR}" ++} ++ ++update_modulelist() ++{ ++ MODULE_FILE="/etc/modules-load.d/marvell.conf" ++ ++ echo "# Module list to load during the boot" > $MODULE_FILE ++ echo "mvcpss" >> $MODULE_FILE ++ echo "psample" >> $MODULE_FILE ++} ++ ++main() ++{ ++ fw_uboot_env_cfg ++ es1227_54ts_profile ++ update_modulelist ++} ++ ++main $@ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/fw_env.config b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/fw_env.config +new file mode 100644 +index 000000000..ea22bf4a3 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/scripts/fw_env.config +@@ -0,0 +1 @@ ++/dev/mtd1 0x0 0x10000 0x10000 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-init.service b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-init.service +new file mode 100644 +index 000000000..db3f1bebc +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-init.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es1227_54ts Service ++Before=pmon.service ++After=sysinit.target ++DefaultDependencies=no ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/es1227_54ts-init.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-psu-monitor.service b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-psu-monitor.service +new file mode 100644 +index 000000000..5091cab40 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-psu-monitor.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es1227_54ts psu monitor Service ++After=pmon.service es1227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/psu_detect.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-rst_button.service b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-rst_button.service +new file mode 100644 +index 000000000..f4358c95d +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-rst_button.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es1227_54ts Reset Button Service ++After=pmon.service es1227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/usr/bin/sleep 20 ++ExecStart=/usr/bin/python3 /usr/local/bin/rst_button.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sensor_conf.service b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sensor_conf.service +new file mode 100644 +index 000000000..336887013 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sensor_conf.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es1227_54ts sensor conf Service ++After=pmon.service es1227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/bin/sleep 60 ++ExecStart=/bin/bash /usr/local/bin/sensor_conf.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=60s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sysled.service b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sysled.service +new file mode 100644 +index 000000000..a62f31bd4 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/service/es1227_54ts-sysled.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es1227_54ts system LED Service ++After=pmon.service es1227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/sysled_health.py ++Restart=on-failure ++RestartSec=5 ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/setup.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/setup.py +new file mode 100644 +index 000000000..7675f61d2 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/setup.py +@@ -0,0 +1,32 @@ ++from setuptools import setup ++ ++ ++setup( ++ name='sonic-platform', ++ version='1.0', ++ description='SONiC platform API implementation on Wistron Platforms', ++ license='Apache 2.0', ++ author='SONiC Team', ++ author_email='linuxnetdev@microsoft.com', ++ url='https://github.com/Azure/sonic-buildimage', ++ maintainer='ChihPei Chang', ++ maintainer_email='ChihPei_Chang@wistron.com', ++ packages=[ ++ 'sonic_platform', ++ ], ++ package_dir={'sonic_platform': 'sonic_platform'}, ++ classifiers=[ ++ 'Development Status :: 3 - Alpha', ++ 'Environment :: Plugins', ++ 'Intended Audience :: Developers', ++ 'Intended Audience :: Information Technology', ++ 'Intended Audience :: System Administrators', ++ 'License :: OSI Approved :: Apache Software License', ++ 'Natural Language :: English', ++ 'Operating System :: POSIX :: Linux', ++ 'Programming Language :: Python :: 2.7', ++ 'Topic :: Utilities', ++ ], ++ keywords='sonic SONiC platform PLATFORM', ++) ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/__init__.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/__init__.py +new file mode 100644 +index 000000000..4bfefa0fb +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/__init__.py +@@ -0,0 +1,3 @@ ++__all__ = ["platform", "chassis"] ++from sonic_platform import * ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/chassis.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/chassis.py +new file mode 100644 +index 000000000..2a08dbda2 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/chassis.py +@@ -0,0 +1,464 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Chassis information which are available in the platform ++# ++############################################################################# ++try: ++ import sys ++ import os ++ import time ++ import subprocess ++ from sonic_platform_base.chassis_base import ChassisBase ++ from sonic_platform.fan import Fan ++ from sonic_platform.psu import Psu ++ from sonic_platform.component import Component ++ from sonic_platform.thermal import Thermal ++ from sonic_platform.sfp import Sfp ++ from sonic_platform.eeprom import Tlv ++ from sonic_platform.fan_drawer import FanDrawer ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++NUM_FANTRAY = 2 ++NUM_PSU = 2 ++NUM_THERMAL = 14 ++COPPER_PORT_START = 1 ++COPPER_PORT_END = 48 ++SFP_BASE = 49 ++NUM_SFP = 6 ++NUM_COMPONENT = 3 ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" ++PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" ++REBOOT_CAUSE_FILE = "reboot-cause.txt" ++PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" ++HOST_CHK_CMD = "docker > /dev/null 2>&1" ++GET_HWSKU_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.hwsku" ++GET_PLATFORM_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.platform" ++GET_HOST_HWSKU_CMD = 'grep ^onie_machine= /host/machine.conf | cut -f2 -d"="' ++GET_HOST_PLATFORM_CMD = 'grep ^onie_platform /host/machine.conf | cut -f2 -d"="' ++ ++class Chassis(ChassisBase): ++ """Platform-specific Chassis class""" ++ ++ def __init__(self): ++ super(Chassis, self).__init__() ++ ++ # Initialize SKU name and Platform name ++ self.sku_name = self._get_sku_name() ++ self.platform_name = self._get_platform_name() ++ self.name = self.sku_name ++ self.COPPER_PORT_START = COPPER_PORT_START ++ self.COPPER_PORT_END = COPPER_PORT_END ++ ++ ++ for fan_index in range(0, NUM_FANTRAY): ++ fandrawer = FanDrawer(fan_index) ++ self._fan_drawer_list.append(fandrawer) ++ self._fan_list.extend(fandrawer._fan_list) ++ ++ for index in range(0, NUM_PSU): ++ psu = Psu(index) ++ self._psu_list.append(psu) ++ ++ for index in range(0, NUM_THERMAL): ++ thermal = Thermal(index) ++ self._thermal_list.append(thermal) ++ ++ # for non-sfp ports create dummy objects for copper / non-sfp ports ++ for index in range(self.COPPER_PORT_START, self.COPPER_PORT_END+1): ++ port=index-1 ++ sfp_node = Sfp(index, 'COPPER') ++ self._sfp_list.append(sfp_node) ++ ++ for index in range(SFP_BASE, SFP_BASE + NUM_SFP): ++ sfp_module = Sfp(index, 'SFP') ++ self._sfp_list.append(sfp_module) ++ ++ from sonic_platform.component import Component ++ for index in range(0, NUM_COMPONENT): ++ component = Component(index) ++ self._component_list.append(component) ++ ++ self._eeprom = Tlv() ++ self._transceiver_presence = [0] * (SFP_BASE + NUM_SFP - 1) ++ ++ def __is_host(self): ++ return os.system(HOST_CHK_CMD) == 0 ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def get_base_mac(self): ++ """ ++ Retrieves the base MAC address for the chassis ++ Returns: ++ A string containing the MAC address in the format ++ 'XX:XX:XX:XX:XX:XX' ++ """ ++ return self._eeprom.get_mac() ++ ++ def get_serial(self): ++ """ ++ Retrieves the hardware serial number for the chassis ++ Returns: ++ A string containing the hardware serial number for this chassis. ++ """ ++ return self._eeprom.get_serial() ++ ++ def get_system_eeprom_info(self): ++ """ ++ Retrieves the full content of system EEPROM information for the chassis ++ Returns: ++ A dictionary where keys are the type code defined in ++ OCP ONIE TlvInfo EEPROM format and values are their corresponding ++ values. ++ """ ++ return self._eeprom.get_eeprom() ++ ++ def get_firmware_version(self, component_name): ++ """ ++ Retrieves platform-specific hardware/firmware versions for chassis ++ componenets such as BIOS, CPLD, FPGA, etc. ++ Args: ++ type: A string, component name ++ ++ Returns: ++ A string containing platform-specific component versions ++ """ ++ self.component = Component(component_name) ++ if component_name not in self._component_name_list: ++ return None ++ return self.component.get_firmware_version() ++ ++ def install_component_firmware(self, component_name, image_path): ++ """ ++ Install firmware to module ++ Args: ++ type: A string, component name. ++ image_path: A string, path to firmware image. ++ ++ Returns: ++ A boolean, True if install successfully, False if not ++ """ ++ self.component = Component(component_name) ++ if component_name not in self._component_name_list: ++ return False ++ return self.component.upgrade_firmware(image_path) ++ ++ def get_reboot_cause(self): ++ """ ++ Retrieves the cause of the previous reboot ++ ++ Returns: ++ A tuple (string, string) where the first element is a string ++ containing the cause of the previous reboot. This string must be ++ one of the predefined strings in this class. If the first string ++ is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used ++ to pass a description of the reboot cause. ++ """ ++ ++ reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host( ++ ) else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE ++ sw_reboot_cause = self.__read_txt_file( ++ reboot_cause_path) or "Unknown" ++ ++ if sw_reboot_cause != "Unknown": ++ reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE ++ description = sw_reboot_cause ++ else: ++ reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER ++ description = 'Unknown reason' ++ ++ return (reboot_cause, description) ++ ++ def _get_sku_name(self): ++ if self.__is_host(): ++ p = subprocess.Popen(GET_HOST_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) ++ else: ++ p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) ++ out, err = p.communicate() ++ return out.decode().rstrip('\n') ++ ++ def _get_platform_name(self): ++ if self.__is_host(): ++ p = subprocess.Popen(GET_HOST_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) ++ else: ++ p = subprocess.Popen(GET_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) ++ out, err = p.communicate() ++ return out.decode().rstrip('\n') ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return self.name ++ ++ def get_sfp(self, index): ++ sfp = None ++ try: ++ sfp = self._sfp_list[index - 1] ++ except IndexError: ++ sys.stderr.write("SFP index {} out of range (1-{})\n".format(index, len(self._sfp_list))) ++ ++ return sfp ++ ++ def _get_sfp_presence(self): ++ port_pres = {} ++ for port in range(0, SFP_BASE + NUM_SFP - 1): ++ sfp = self._sfp_list[port] ++ port_pres[port] = sfp.get_presence() ++ ++ return port_pres ++ ++ def get_change_event(self, timeout=0): ++ port_dict = {} ++ ret_dict = {'sfp': port_dict} ++ forever = False ++ change_event = False ++ ++ if timeout == 0: ++ forever = True ++ elif timeout > 0: ++ timeout = timeout / float(1000) ++ else: ++ return False, ret_dict #Incorrect timeout ++ ++ while True: ++ if forever: ++ timer = 1 ++ else: ++ timer = min(timeout, 1) ++ start_time = time.time() ++ ++ time.sleep(timer) ++ cur_presence = self._get_sfp_presence() ++ for port in range(0, SFP_BASE + NUM_SFP - 1): ++ if cur_presence[port] != self._transceiver_presence[port]: ++ change_event = True ++ if cur_presence[port] == 1: ++ port_dict[port + 1] = '1' ++ else: ++ port_dict[port + 1] = '0' ++ ++ self._transceiver_presence = cur_presence ++ if change_event == True: ++ break ++ ++ if not forever: ++ elapsed_time = time.time() - start_time ++ timeout = round(timeout - elapsed_time, 3) ++ if timeout <= 0: ++ break ++ ++ return True, ret_dict ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._eeprom.get_model() ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ ++ return '0' ++ ++ def get_watchdog(self): ++ """ ++ Retrieves hardware watchdog device on this chassis ++ ++ Returns: ++ An object derived from WatchdogBase representing the hardware ++ watchdog device ++ """ ++ try: ++ if self._watchdog is None: ++ from sonic_platform.watchdog import WatchdogImplBase ++ watchdog_device = "watchdog1" ++ self._watchdog = WatchdogImplBase(watchdog_device) ++ except Exception as e: ++ sonic_logger.log_warning(" Fail to load watchdog {}".format(repr(e))) ++ ++ return self._watchdog ++ ++ def initizalize_system_led(self): ++ self.system_led = "" ++ return True ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the system LED ++ ++ Args: ++ color: A string representing the color with which to set the ++ system LED ++ ++ Returns: ++ bool: True if system LED state is set successfully, False if not ++ """ ++ ++ self.system_led = color ++ ++ sysled_path="{}/sys_led".format(CPLD_SYSFS_DIR) ++ psuled_path="{}/psu_led".format(CPLD_SYSFS_DIR) ++ fanled_path="{}/fan_led".format(CPLD_SYSFS_DIR) ++ watchdog_update_path="{}/watchdog_kick".format(CPLD_SYSFS_DIR) ++ ++ #if color == "red": ++ # val = 2 ++ #elif color == "green_blinking": ++ # val = 3 ++ #elif color == "green": ++ # val = 1 ++ ++ color=int(self.__read_txt_file(sysled_path)) ++ if color is None: ++ return True ++ if color != 1 and color != 2: ++ self.__write_txt_file(sysled_path, str(1)) ++ self.__write_txt_file(watchdog_update_path, str(1)) ++ ++ fan_sta = True ++ psu_sta = True ++ ++ #clear fault before we update the fan statue led ++ for fan_index in range(0, NUM_FANTRAY): ++ sta=self._fan_drawer_list[fan_index].get_status() ++ if not sta: ++ self._fan_drawer_list[fan_index]._fan_list[0].try_clear_fault() ++ ++ for fan_index in range(0, NUM_FANTRAY): ++ sta=self._fan_drawer_list[fan_index].get_status() ++ prs=self._fan_drawer_list[fan_index].get_presence() ++ fan_sta = fan_sta & sta ++ if sta and prs: ++ val=1 ++ else: ++ val=2 ++ led_path="{}/fan{}_led".format(CPLD_SYSFS_DIR, fan_index+1) ++ self.__write_txt_file(led_path, str(val)) ++ ++ if fan_sta: ++ val = 1 ++ else: ++ val = 2 ++ self.__write_txt_file(fanled_path, str(val)) ++ ++ for index in range(0, NUM_PSU): ++ sta=self._psu_list[index].get_status() ++ psu_sta = psu_sta & sta ++ if psu_sta: ++ val = 1 ++ else: ++ val = 2 ++ self.__write_txt_file(psuled_path, str(val)) ++ ++ return True ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the system LED ++ ++ Returns: ++ A string, one of the valid LED color strings which could be vendor ++ specified. ++ """ ++ return self.system_led ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ return None ++ ++ def get_port_or_cage_type(self, index): ++ """ ++ Retrieves sfp port or cage type corresponding to physical port ++ ++ Args: ++ index: An integer (>=0), the index of the sfp to retrieve. ++ The index should correspond to the physical port in a chassis. ++ For example:- ++ 1 for Ethernet0, 2 for Ethernet4 and so on for one platform. ++ 0 for Ethernet0, 1 for Ethernet4 and so on for another platform. ++ ++ Returns: ++ The masks of all types of port or cage that can be supported on the port ++ Types are defined in sfp_base.py ++ Eg. ++ Both SFP and SFP+ are supported on the port, the return value should be 0x0a ++ which is 0x02 | 0x08 ++ """ ++ index = index - 1 ++ if index < COPPER_PORT_END: ++ from sonic_platform_base.sfp_base import SfpBase ++ return SfpBase.SFP_PORT_TYPE_BIT_RJ45 ++ raise NotImplementedError ++ ++ def power_down(self): ++ power_down_path="{}/system_power_down".format(CPLD_SYSFS_DIR) ++ self.__write_txt_file(power_down_path, str(0)) ++ ++ def set_sysled_red(self): ++ sysled_path="{}/sys_led".format(CPLD_SYSFS_DIR) ++ self.__write_txt_file(sysled_path, str(2)) ++ ++ def get_thermal_manager(self): ++ from .thermal_manager import ThermalManager ++ return ThermalManager ++ ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the Chassis ++ Returns: ++ bool: True if Chassis is present, False if not ++ """ ++ return True ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/component.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/component.py +new file mode 100644 +index 000000000..c2760be45 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/component.py +@@ -0,0 +1,186 @@ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in ++# the platform ++# ++######################################################################## ++ ++try: ++ import sys ++ import subprocess ++ from sonic_platform_base.component_base import ComponentBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++if sys.version_info[0] < 3: ++ import commands as cmd ++else: ++ import subprocess as cmd ++ ++ ++class Component(ComponentBase): ++ """platform-specific Component class""" ++ ++ CHASSIS_COMPONENTS = [ ++ ["U-Boot", "Performs initialization during booting"], ++ ["ONIE-VERSION", "ONIE - Open Network Install Environment"], ++ ["CPLD", "CPLD firmware"], ++ ] ++ ++ def __init__(self, component_index): ++ self.index = component_index ++ self.name = self.CHASSIS_COMPONENTS[self.index][0] ++ self.description = self.CHASSIS_COMPONENTS[self.index][1] ++ ++ def _get_command_result(self, cmdline): ++ try: ++ proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ stdout = proc.communicate()[0] ++ proc.wait() ++ result = stdout.rstrip('\n') ++ except OSError: ++ result = None ++ ++ return result ++ ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the component ++ ++ Returns: ++ A string containing the name of the component ++ """ ++ return self.name ++ ++ def get_description(self): ++ """ ++ Retrieves the description of the component ++ ++ Returns: ++ A string containing the description of the component ++ """ ++ return self.description ++ ++ def get_firmware_version(self): ++ """ ++ Retrieves the firmware version of the component ++ ++ Returns: ++ A string containing the firmware version of the component ++ """ ++ ++ if self.index == 0: ++ cmdstatus, uboot_version = cmd.getstatusoutput('grep --null-data ^U-Boot /dev/mtd0 | tail -n 1 | cut -d" " -f2') ++ return uboot_version ++ ++ if self.index == 1: ++ cmdstatus, onie_version = cmd.getstatusoutput('grep ^onie_version /host/machine.conf | cut -f2 -d"="') ++ return onie_version ++ ++ if self.index == 2: ++ cmdstatus, cpld_ver = cmd.getstatusoutput('cat /sys/bus/i2c/devices/0-0033/cpld_rev') ++ return cpld_ver ++ ++ def install_firmware(self, image_path): ++ """ ++ Installs firmware to the component ++ ++ Args: ++ image_path: A string, path to firmware image ++ ++ Returns: ++ A boolean, True if install was successful, False if not ++ """ ++ return False ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if FAN is present, False if not ++ """ ++ return True ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return 'N/A' ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return 'N/A' ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False ++ ++ def get_available_firmware_version(self, image_path): ++ """ ++ Retrieves the available firmware version of the component ++ Note: the firmware version will be read from image ++ Args: ++ image_path: A string, path to firmware image ++ Returns: ++ A string containing the available firmware version of the component ++ """ ++ return "N/A" ++ ++ def get_firmware_update_notification(self, image_path): ++ """ ++ Retrieves a notification on what should be done in order to complete ++ the component firmware update ++ Args: ++ image_path: A string, path to firmware image ++ Returns: ++ A string containing the component firmware update notification if required. ++ By default 'None' value will be used, which indicates that no actions are required ++ """ ++ return "None" ++ ++ def update_firmware(self, image_path): ++ """ ++ Updates firmware of the component ++ This API performs firmware update: it assumes firmware installation and loading in a single call. ++ In case platform component requires some extra steps (apart from calling Low Level Utility) ++ to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API ++ Args: ++ image_path: A string, path to firmware image ++ Raises: ++ RuntimeError: update failed ++ """ ++ return False +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/eeprom.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/eeprom.py +new file mode 100644 +index 000000000..ae9fe3513 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/eeprom.py +@@ -0,0 +1,120 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# Platform and model specific eeprom subclass, inherits from the base class, ++# and provides the followings: ++# - the eeprom format definition ++# - specific encoder/decoder if there is special need ++############################################################################# ++ ++try: ++ import glob ++ import os ++ import sys ++ import imp ++ import re ++ from array import array ++ from io import StringIO ++ from sonic_platform_base.sonic_eeprom import eeprom_dts ++ from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' ++CACHE_FILE = 'syseeprom_cache' ++ ++ ++class Tlv(eeprom_tlvinfo.TlvInfoDecoder): ++ ++ EEPROM_DECODE_HEADLINES = 6 ++ ++ def __init__(self): ++ self._eeprom_path = "/sys/bus/i2c/devices/0-0055/eeprom" ++ super(Tlv, self).__init__(self._eeprom_path, 0, '', True) ++ self._eeprom = self._load_eeprom() ++ ++ def __parse_output(self, decode_output): ++ decode_output.replace('\0', '') ++ lines = decode_output.split('\n') ++ lines = lines[self.EEPROM_DECODE_HEADLINES:] ++ _eeprom_info_dict = dict() ++ ++ for line in lines: ++ try: ++ match = re.search( ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+[\s]+[\S]+)', line) ++ if match is not None and match.group(1) == '0x25': ++ idx = match.group(1) ++ value = match.group(3).rstrip('\0') ++ _eeprom_info_dict[idx] = value ++ else: ++ match = re.search( ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) ++ if match is not None: ++ idx = match.group(1) ++ value = match.group(3).rstrip('\0') ++ _eeprom_info_dict[idx] = value ++ ++ except BaseException: ++ pass ++ return _eeprom_info_dict ++ ++ def _load_eeprom(self): ++ original_stdout = sys.stdout ++ sys.stdout = StringIO() ++ try: ++ self.read_eeprom_db() ++ except Exception: ++ decode_output = sys.stdout.getvalue() ++ sys.stdout = original_stdout ++ return self.__parse_output(decode_output) ++ ++ status = self.check_status() ++ if status < 'ok': ++ return False ++ ++ if not os.path.exists(CACHE_ROOT): ++ try: ++ os.makedirs(CACHE_ROOT) ++ except: ++ pass ++ ++ # ++ # only the eeprom classes that inherit from eeprom_base ++ # support caching. Others will work normally ++ # ++ try: ++ self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) ++ except: ++ pass ++ ++ e = self.read_eeprom() ++ if e is None: ++ return 0 ++ ++ try: ++ self.update_cache(e) ++ except: ++ pass ++ ++ self.decode_eeprom(e) ++ decode_output = sys.stdout.getvalue() ++ sys.stdout = original_stdout ++ ++ (is_valid, valid_crc) = self.is_checksum_valid(e) ++ if not is_valid: ++ return False ++ ++ return self.__parse_output(decode_output) ++ ++ def get_eeprom(self): ++ return self._eeprom ++ ++ def get_serial(self): ++ return self._eeprom.get('0x23', "Undefined.") ++ ++ def get_mac(self): ++ return self._eeprom.get('0x24', "Undefined.") ++ ++ def get_model(self): ++ return self._eeprom.get('0x21', "Undefined.") +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan.py +new file mode 100644 +index 000000000..7ace53617 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan.py +@@ -0,0 +1,366 @@ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the fan status which are available in the platform ++# ++############################################################################# ++ ++ ++import os.path ++import time ++ ++try: ++ from sonic_platform.eeprom import Tlv ++ from sonic_platform_base.fan_base import FanBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++PSU_FAN_MAX_RPM = 18000 ++SPEED_TOLERANCE = 15 ++SYSFS_PATH = "/sys/bus/i2c/devices/{0}-00{1}" ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++HWMON_PATH = "/sys/bus/i2c/devices/{0}-00{1}/hwmon" ++PSU_HWMON_I2C_MAPPING = { ++ 0: { ++ "num": 3, ++ "addr": "59" ++ }, ++ 1: { ++ "num": 3, ++ "addr": "58" ++ }, ++} ++ ++FAN_HWMON_I2C_MAPPING = { ++ 0: { ++ "num": 2, ++ "addr": "2f" ++ }, ++} ++ ++#FAN_PCA9539_I2C_MAPPING = { ++# 0: { ++# "num": 9, ++# "addr": "74" ++# }, ++# 1: { ++# "num": 9, ++# "addr": "76" ++# }, ++#} ++ ++# 3 fan sku not exist now ++#FAN_ROTOR_MAPPING = { ++# 0: 1, ++# 1: 8, ++# 2: 4 ++#} ++ ++#FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"] ++ ++FAN_ROTOR_MAPPING = { ++ 0: 4, ++ 1: 8 ++} ++ ++FAN_NAME_LIST = ["FAN-1", "FAN-2"] ++ ++class Fan(FanBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): ++ self.fan_index = fan_index ++ self.fan_tray_index = fan_tray_index ++ self.is_psu_fan = is_psu_fan ++ self.pwm_conv=[] ++ ++ if self.is_psu_fan: ++ self.psu_index = psu_index ++ self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] ++ self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] ++ hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++ self.psu_i2c_num, self.psu_i2c_addr)) ++ self.psu_hwmon_path = os.path.join(HWMON_PATH.format(self.psu_i2c_num, self.psu_i2c_addr), hwmon_dir) ++ ++ self.psu_status_path = CPLD_SYSFS_DIR ++ else: ++ self.fan_i2c_num = FAN_HWMON_I2C_MAPPING[0]['num'] ++ self.fan_i2c_addr = FAN_HWMON_I2C_MAPPING[0]['addr'] ++ hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++ self.fan_i2c_num, self.fan_i2c_addr)) ++ self.fan_hwmon_path = os.path.join(HWMON_PATH.format(self.fan_i2c_num, self.fan_i2c_addr), hwmon_dir) ++ ++ self.fan_status_path = CPLD_SYSFS_DIR ++ ++# self.an_fan_i2c_num = FAN_HWMON_I2C_MAPPING[1]['num'] ++# self.an_fan_i2c_addr = FAN_HWMON_I2C_MAPPING[1]['addr'] ++# hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++# self.fan_i2c_num, self.fan_i2c_addr)) ++# self.an_fan_hwmon_path = os.path.join(HWMON_PATH.format(self.fan_i2c_num, self.fan_i2c_addr), hwmon_dir) ++ ++# self.fan_sts_i2c_num = FAN_PCA9539_I2C_MAPPING[0 if fan_tray_index < 3 else 1]['num'] ++# self.fan_sts_i2c_addr = FAN_PCA9539_I2C_MAPPING[0 if fan_tray_index < 3 else 1]['addr'] ++# self.fan_status_path = SYSFS_PATH.format(self.fan_sts_i2c_num, self.fan_sts_i2c_addr) ++ ++ ++ self._eeprom = Tlv() ++ ++ for i in range(0, 101): ++ self.pwm_conv.append(int(i * 255 / 100)) ++ ++ FanBase.__init__(self) ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ 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 = 0 ++ if self.is_psu_fan: ++ if self.get_presence(): ++ path_pre=SYSFS_PATH.format(self.psu_i2c_num, self.psu_i2c_addr) ++ psu_fan_path= "{}/{}".format(path_pre, 'mfr_model') ++ model=self.__read_txt_file(psu_fan_path) ++ if model is None: ++ direction = 0 ++ direction = 0 if 'WNA' in model else 1 ++ elif self.get_presence(): ++ part=self._eeprom.get_model() ++ direction = 0 if 'ES-1227-54TS-O' in part else 1 ++ ++ return self.FAN_DIRECTION_EXHAUST if int(direction) == 0 else self.FAN_DIRECTION_INTAKE ++ ++ def get_speed(self): ++ """ ++ Retrieves the speed of fan as a percentage of full speed ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ ++ """ ++ speed = 0 ++ if self.is_psu_fan: ++ psu_fan_path= "{}/{}".format(self.psu_hwmon_path, 'fan1_input') ++ rpm=self.__read_txt_file(psu_fan_path) ++ if rpm is None: ++ return 0 ++ speed = int(int(rpm) * 100 / PSU_FAN_MAX_RPM) ++ elif self.get_presence(): ++ path= "{}/pwm1".format(self.fan_hwmon_path) ++ pwm=self.__read_txt_file(path) ++ if pwm is None: ++ return 0 ++ elif int(pwm) == 77: ++ pwm = 76 ++ speed = self.pwm_conv.index(int(pwm)) ++ ++ return int(speed) ++ ++ def get_target_speed(self): ++ """ ++ Retrieves the target (expected) speed of the fan ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ ++ Note: ++ speed_pc = pwm_target/255*100 ++ ++ 0 : when PWM mode is use ++ pwm : when pwm mode is not use ++ """ ++ return self.get_speed() ++ ++ def get_speed_tolerance(self): ++ """ ++ Retrieves the speed tolerance of the fan ++ Returns: ++ An integer, the percentage of variance from target speed which is ++ considered tolerable ++ """ ++ return SPEED_TOLERANCE ++ ++ def set_speed(self, speed): ++ """ ++ Sets the fan speed ++ Args: ++ speed: An integer, the percentage of full fan speed to set fan to, ++ in the range 0 (off) to 100 (full speed) ++ Returns: ++ A boolean, True if speed is set successfully, False if not ++ ++ """ ++ ++ if not self.is_psu_fan and self.get_presence(): ++ pwm = int((speed * 255) / 100) ++ speed_path = "{}/{}".format(self.fan_hwmon_path, 'pwm1') ++ self.__write_txt_file(speed_path, str(pwm)) ++# speed_path = "{}/{}".format(self.an_fan_hwmon_path, 'pwm1') ++# self.__write_txt_file(speed_path, int(speed)) ++ ++ return True ++ ++ return False ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the fan module status LED ++ Args: ++ color: A string representing the color with which to set the ++ fan module status LED ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ if color is self.STATUS_LED_COLOR_GREEN: ++ val = 1 ++ else: ++ val = 2 ++ ++ led_path="{}/fan{}_led".format(self.fan_status_path, self.fan_tray_index+1) ++ self.__write_txt_file(led_path, str(val)) ++ ++ return True ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ status=self.get_presence() ++ if status is None: ++ return self.STATUS_LED_COLOR_OFF ++ ++ return { ++ 1: self.STATUS_LED_COLOR_GREEN, ++ 0: self.STATUS_LED_COLOR_RED ++ }.get(status, self.STATUS_LED_COLOR_OFF) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ fan_name = FAN_NAME_LIST[self.fan_tray_index + self.fan_index] \ ++ if not self.is_psu_fan \ ++ else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) ++ ++ return fan_name ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if FAN is present, False if not ++ """ ++ ++ ++ if self.is_psu_fan: ++ present_path="{}/psu{}_present".format(self.psu_status_path, self.psu_index+1) ++ else: ++ present_path="{}/cnfan{}_present".format(self.fan_status_path, self.fan_tray_index+1) ++ ++ val=self.__read_txt_file(present_path) ++ if val is not None: ++ return int(val, 10)==1 ++ else: ++ return False ++ ++ def try_clear_fault(self): ++ path= "{}/pwm1".format(self.fan_hwmon_path) ++ speed=self.__read_txt_file(path) ++ ++ self.__write_txt_file(path, str(speed)) ++ time.sleep(2) ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ if self.is_psu_fan: ++ psu_fan_path= "{}/{}".format(self.psu_hwmon_path, 'fan1_fault') ++ val=self.__read_txt_file(psu_fan_path) ++ if val is not None: ++ return int(val, 10)==0 ++ else: ++ return False ++ else: ++ path= "{}/fan{}_fault".format(self.fan_hwmon_path, FAN_ROTOR_MAPPING[self.fan_tray_index + self.fan_index]) ++ val=self.__read_txt_file(path) ++ if val is not None: ++ return int(val, 10)==0 ++ else: ++ return False ++ ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ ++ return "N/A" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "N/A" ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return (self.fan_tray_index+1) \ ++ if not self.is_psu_fan else (self.psu_index+1) ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return True if not self.is_psu_fan else False ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan_drawer.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan_drawer.py +new file mode 100644 +index 000000000..0f9f7c31b +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/fan_drawer.py +@@ -0,0 +1,108 @@ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Fan-Drawers' information available in the platform. ++# ++######################################################################## ++ ++try: ++ from sonic_platform_base.fan_drawer_base import FanDrawerBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++FANS_PER_FANTRAY = 1 ++MAX_FAN_WATT = 7.2 ++ ++class FanDrawer(FanDrawerBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, fantray_index): ++ ++ FanDrawerBase.__init__(self) ++ # FanTray is 0-based in platforms ++ self.fantrayindex = fantray_index ++ self.__initialize_fan_drawer() ++ ++ ++ def __initialize_fan_drawer(self): ++ from sonic_platform.fan import Fan ++ for i in range(FANS_PER_FANTRAY): ++ self._fan_list.append(Fan(self.fantrayindex, i)) ++ ++ def get_name(self): ++ """ ++ Retrieves the fan drawer name ++ Returns: ++ string: The name of the device ++ """ ++ return "FanTray{}".format(self.fantrayindex+1) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ return self._fan_list[0].get_presence() ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._fan_list[0].get_model() ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return self._fan_list[0].get_serial() ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return self._fan_list[0].get_status() ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan drawer LED ++ ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ return self._fan_list[0].get_status_led() ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return (self.fantrayindex+1) ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return True ++ ++ def get_maximum_consumed_power(self): ++ """ ++ Retrives the maximum power drawn by Fan Drawer ++ Returns: ++ A float, with value of the maximum consumable power of the ++ component. ++ """ ++ return MAX_FAN_WATT +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/pcie.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/pcie.py +new file mode 100644 +index 000000000..273767cfb +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/pcie.py +@@ -0,0 +1,47 @@ ++######################################################################## ++# Copyright (C) 2021, mrvl CORPORATION & AFFILIATES. All rights reserved. ++# Module contains a platform specific implementation of SONiC Platform ++# Base PCIe class ++######################################################################## ++import os ++import re ++ ++try: ++ from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++SYSFS_PCI_DEVICE_PATH = '/sys/bus/pci/devices/' ++ ++class Pcie(PcieUtil): ++ def get_pcie_check(self): ++ self.load_config_file() ++ for item_conf in self.confInfo: ++ id_conf = item_conf["id"] ++ dev_conf = item_conf["dev"] ++ fn_conf = item_conf["fn"] ++ bus_conf = self._device_id_to_bus_map.get(str(id_conf)) ++ if bus_conf and self.check_pcie_sysfs(bus=int(bus_conf, base=16), device=int(dev_conf, base=16), ++ func=int(fn_conf, base=16)): ++ item_conf["result"] = "Passed" ++ else: ++ item_conf["result"] = "Failed" ++ return self.confInfo ++ ++ def _create_device_id_to_bus_map(self): ++ self._device_id_to_bus_map = {} ++ self.load_config_file() ++ device_folders = os.listdir(SYSFS_PCI_DEVICE_PATH) ++ for folder in device_folders: ++ pattern_for_device_folder = re.search('....:(..):..\..', folder) ++ if pattern_for_device_folder: ++ bus = pattern_for_device_folder.group(1) ++ with open(os.path.join(SYSFS_PCI_DEVICE_PATH, folder, 'device'), 'r') as device_file: ++ # The 'device' file contain an hex repesantaion of the id key in the yaml file. ++ # We will strip the new line character, and remove the 0x prefix that is not needed. ++ device_id = device_file.read().strip().replace('0x', '') ++ self._device_id_to_bus_map[device_id] = bus ++ ++ def __init__(self, platform_path): ++ PcieUtil.__init__(self, platform_path) ++ self._create_device_id_to_bus_map() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/platform.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/platform.py +new file mode 100644 +index 000000000..0b67a68b8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/platform.py +@@ -0,0 +1,22 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the platform information ++# ++############################################################################# ++ ++try: ++ from sonic_platform_base.platform_base import PlatformBase ++ from sonic_platform.chassis import Chassis ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Platform(PlatformBase): ++ ++ def __init__(self): ++ PlatformBase.__init__(self) ++ self._chassis = Chassis() ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/psu.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/psu.py +new file mode 100755 +index 000000000..928fae682 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/psu.py +@@ -0,0 +1,359 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# psuutil.py ++# Platform-specific PSU status interface for SONiC ++############################################################################# ++ ++import os.path ++import sonic_platform ++ ++try: ++ from sonic_platform_base.psu_base import PsuBase ++ from sonic_platform.fan import Fan ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++PSU_NAME_LIST = ["PSU-1", "PSU-2"] ++ ++PSU_HWMON_PATH = "/sys/bus/i2c/devices/{0}-00{1}/hwmon" ++PSU_SYSFS_PATH = "/sys/bus/i2c/devices/{0}-00{1}" ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++PSU_I2C_MAPPING = { ++ 0: { ++ "bus": 3, ++ "addr": "59" ++ }, ++ 1: { ++ "bus": 3, ++ "addr": "58" ++ }, ++} ++ ++ ++class Psu(PsuBase): ++ """Platform-specific Psu class""" ++ ++ def __init__(self, psu_index): ++ self.PSU_TEMP_MAX = 68000 ++ self.PSU_OUTPUT_POWER_MAX = 420000000 ++ self.PSU_OUTPUT_VOLTAGE_MIN = 40000 ++ self.PSU_OUTPUT_VOLTAGE_MAX = 62000 ++ self.index = psu_index ++ PsuBase.__init__(self) ++ self.i2c_num = PSU_I2C_MAPPING[self.index]["bus"] ++ self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] ++ self.hwmon_path = PSU_HWMON_PATH.format(self.i2c_num, self.i2c_addr) ++ self.sysfs_path = PSU_SYSFS_PATH.format(self.i2c_num, str( ++ int(self.i2c_addr))) ++ self.__initialize_fan() ++ ++ def __initialize_fan(self): ++ from sonic_platform.fan import Fan ++ for fan_index in range(0, 1): ++ fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) ++ self._fan_list.append(fan) ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def get_fan(self, index): ++ """ ++ Retrieves object representing the fan module contained in this PSU ++ Returns: ++ An object dervied from FanBase representing the fan module ++ contained in this PSU ++ """ ++ return self._fan_list[index] ++ ++ def get_powergood_status(self): ++ """ ++ Retrieves the powergood status of PSU ++ Returns: ++ A boolean, True if PSU has stablized its output voltages and passed all ++ its internal self-tests, False if not. ++ """ ++ return self.get_status() ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the PSU status LED ++ Args: ++ color: A string representing the color with which to set the PSU status LED ++ Note: Only support green and off ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ # Hardware not supported ++ return False ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the PSU status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ if self.get_presence(): ++ if self.get_powergood_status(): ++ return self.STATUS_LED_COLOR_GREEN ++ else: ++ return self.STATUS_LED_COLOR_RED ++ else: ++ return None ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return PSU_NAME_LIST[self.index] ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the PSU ++ Returns: ++ bool: True if PSU is present, False if not ++ """ ++ attr_file = 'psu{}_present'.format(self.index + 1) ++ attr_path = CPLD_SYSFS_DIR + '/' + attr_file ++ status = 0 ++ try: ++ with open(attr_path, 'r') as psu_prs: ++ status = int(psu_prs.read()) ++ except IOError: ++ return False ++ ++ return status == 1 ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ attr_file = 'psu{}_power_good'.format(self.index + 1) ++ attr_path = CPLD_SYSFS_DIR + '/' + attr_file ++ status = 0 ++ if self.get_presence(): ++ try: ++ with open(attr_path, 'r') as power_status: ++ status = int(power_status.read()) ++ except IOError: ++ return False ++ ++ return status == 1 ++ ++ def get_model(self): ++ """ ++ Retrieves the model name of the PSU ++ Returns: ++ model name ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "mfr_model") ++ if os.path.exists(file_path): ++ model = self.__read_txt_file(file_path) ++ return model ++ ++ return None ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the PSU ++ Returns: ++ model serial ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "mfr_serial") ++ if os.path.exists(file_path): ++ serial = self.__read_txt_file(file_path) ++ return serial ++ ++ return None ++ ++ def get_revision(self): ++ """ ++ Retrieves the hw rev of the PSU ++ Returns: ++ model rev ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "mfr_revision") ++ if os.path.exists(file_path): ++ rev = self.__read_txt_file(file_path) ++ return rev ++ ++ return None ++ ++ def get_voltage(self): ++ """ ++ Retrieves current PSU voltage output ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 12.1 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "in2_input") ++ voltage = self.__read_txt_file(file_path) ++ if not voltage: ++ return None ++ return float(voltage) / 1000 ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from PSU ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "temp1_input") ++ temp = self.__read_txt_file(file_path) ++ if not temp: ++ return None ++ return float(temp) / 1000 ++ ++ def get_current(self): ++ """ ++ Retrieves present electric current supplied by PSU ++ Returns: ++ A float number, the electric current in amperes, e.g 15.4 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "curr2_input") ++ current = self.__read_txt_file(file_path) ++ if not current: ++ return None ++ return float(current) / 1000 ++ ++ def get_power(self): ++ """ ++ Retrieves current energy supplied by PSU ++ Returns: ++ A float number, the power in watts, e.g. 302.6 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "power2_input") ++ power = self.__read_txt_file(file_path) ++ if not power: ++ return None ++ return float(power) / 1000000 ++ ++ def get_voltage_vin(self): ++ """ ++ Retrieves current PSU voltage output ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 220.0 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "in1_input") ++ voltage = self.__read_txt_file(file_path) ++ if not voltage: ++ return None ++ return float(voltage) / 1000 ++ ++ def get_temperature_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of PSU ++ Returns: ++ A float number, the high threshold temperature of PSU in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ return float(self.PSU_TEMP_MAX/1000) ++ ++ def get_voltage_high_threshold(self): ++ """ ++ Retrieves the high threshold PSU voltage output ++ Returns: ++ A float number, the high threshold output voltage in volts, ++ e.g. 12.1 ++ """ ++ return float(self.PSU_OUTPUT_VOLTAGE_MAX/1000) ++ ++ def get_voltage_low_threshold(self): ++ """ ++ Retrieves the low threshold PSU voltage output ++ Returns: ++ A float number, the low threshold output voltage in volts, ++ e.g. 12.1 ++ """ ++ return float(self.PSU_OUTPUT_VOLTAGE_MIN/1000) ++ ++ def get_maximum_supplied_power(self): ++ """ ++ Retrieves the maximum supplied power by PSU ++ Returns: ++ A float number, the maximum power output in Watts. ++ e.g. 1200.1 ++ """ ++ return float(self.PSU_OUTPUT_POWER_MAX/(1000 * 1000)) ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.index + 1 ++ ++ def is_replaceable(self): ++ return True ++ ++ def get_num_fans(self): ++ """ ++ Retrieves the number of fan modules available on this PSU ++ ++ Returns: ++ An integer, the number of fan modules available on this PSU ++ """ ++ return len(self._fan_list) ++ ++ def get_all_fans(self): ++ """ ++ Retrieves all fan modules available on this PSU ++ ++ Returns: ++ A list of objects derived from FanBase representing all fan ++ modules available on this PSU ++ """ ++ return self._fan_list +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/sfp.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/sfp.py +new file mode 100644 +index 000000000..be5468308 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/sfp.py +@@ -0,0 +1,379 @@ ++import os ++import time ++import sys ++import subprocess ++from ctypes import create_string_buffer ++ ++try: ++ from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase ++ from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper ++ from sonic_py_common import logger ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++if sys.version_info[0] < 3: ++ import commands as cmd ++else: ++ import subprocess as cmd ++ ++COPPER_TYPE = "COPPER" ++SFP_TYPE = "SFP" ++ ++SYSLOG_IDENTIFIER = "xcvrd" ++sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) ++ ++class Sfp(SfpOptoeBase): ++ """Platform-specific Sfp class""" ++ ++ # Paths ++ EEPROM_PATH = "/sys/bus/i2c/devices/{0}-0050/eeprom" ++ GPIO_PATH = "/sys/class/gpio/gpio{0}/value" ++ ++ PORT_EEPROM_I2C_MAPPING = { ++ 49: 5, ++ 50: 4, ++ 51: 7, ++ 52: 6, ++ 53: 9, ++ 54: 8, ++ } ++ ++ PORT_PRESENT_GPIO_MAPPING = { ++ 50: 472, ++ 49: 476, ++ 52: 480, ++ 51: 484, ++ 54: 488, ++ 53: 492, ++ } ++ ++ PORT_TX_DISABLE_GPIO_MAPPING = { ++ 50: 473, ++ 49: 477, ++ 52: 481, ++ 51: 485, ++ 54: 489, ++ 53: 493, ++ } ++ ++ PORT_RX_LOS_GPIO_MAPPING = { ++ 50: 474, ++ 49: 478, ++ 52: 482, ++ 51: 486, ++ 54: 490, ++ 53: 494, ++ } ++ ++ PORT_TX_FAULT_GPIO_MAPPING = { ++ 50: 475, ++ 49: 479, ++ 52: 483, ++ 51: 487, ++ 54: 491, ++ 53: 495, ++ } ++ ++ port_to_i2c_mapping = 0 ++ ++ def __init__(self, index, sfp_type): ++ SfpOptoeBase.__init__(self) ++ # Init index ++ self.index = index ++ self.port_num = index ++ self.sfp_type = sfp_type ++ #self.eeprom_path = eeprom_path ++ #self.port_to_i2c_mapping = port_i2c_map ++ self.port_to_eeprom_mapping = {} ++ ++ if self.sfp_type == COPPER_TYPE: ++ self.port_to_eeprom_mapping[index] = 'N/A' ++ else: ++ self.port_to_eeprom_mapping[index] = self.EEPROM_PATH.format(self.PORT_EEPROM_I2C_MAPPING[self.index]) ++ ++ def get_eeprom_path(self): ++ return self.port_to_eeprom_mapping[self.port_num] ++ ++ def __read_eeprom_specific_bytes(self, offset, num_bytes): ++ sysfsfile_eeprom = None ++ eeprom_raw = [] ++ for i in range(0, num_bytes): ++ eeprom_raw.append("0x00") ++ ++ sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] ++ try: ++ sysfsfile_eeprom = open( ++ sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) ++ sysfsfile_eeprom.seek(offset) ++ raw = sysfsfile_eeprom.read(num_bytes) ++ for n in range(0, num_bytes): ++ if sys.version_info[0] >= 3: ++ eeprom_raw[n] = hex(raw[n])[2:].zfill(2) ++ else: ++ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) ++ except Exception: ++ pass ++ finally: ++ if sysfsfile_eeprom: ++ sysfsfile_eeprom.close() ++ ++ return eeprom_raw ++ ++ def get_reset_status(self): ++ """ ++ Retrieves the reset status of SFP ++ Returns: ++ A Boolean, True if reset enabled, False if disabled ++ """ ++ return False # SFP port doesn't support this feature ++ ++ ++ def get_rx_los(self): ++ """ ++ Retrieves the RX LOS (lost-of-signal) status of SFP ++ Returns: ++ A Boolean, True if SFP has RX LOS, False if not. ++ Note : RX LOS status is latched until a call to get_rx_los or a reset. ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_RX_LOS_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp rx los cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return True ++ else: ++ return False ++ ++ def get_tx_fault(self): ++ """ ++ Retrieves the TX fault status of SFP ++ ++ Returns: ++ A list of boolean values, representing the TX fault status ++ of each available channel, value is True if SFP channel ++ has TX fault, False if not. ++ E.g., for a tranceiver with four channels: [False, False, True, False] ++ Note : TX fault status is lached until a call to get_tx_fault or a reset. ++ """ ++ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_TX_FAULT_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp tx fault cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return True ++ else: ++ return False ++ ++ ++ def get_tx_disable(self): ++ """ ++ Retrieves the tx_disable status of this SFP ++ Returns: ++ A list of boolean values, representing the TX disable status ++ of each available channel, value is True if SFP channel ++ is TX disabled, False if not. ++ E.g., for a tranceiver with four channels: [False, False, True, False] ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return None ++ else: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_TX_DISABLE_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp present cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return [True] ++ else: ++ return [False] ++ ++ ++ def get_tx_disable_channel(self): ++ """ ++ Retrieves the TX disabled channels in this SFP ++ Returns: ++ A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent ++ TX channels which have been disabled in this SFP. ++ As an example, a returned value of 0x5 indicates that channel 0 ++ and channel 2 have been disabled. ++ """ ++ tx_disable_list = self.get_tx_disable() ++ if tx_disable_list is None: ++ return 0 ++ tx_disabled = 0 ++ for i in range(len(tx_disable_list)): ++ if tx_disable_list[i]: ++ tx_disabled |= 1 << i ++ return tx_disabled ++ ++ def get_lpmode(self): ++ """ ++ Retrieves the lpmode (low power mode) status of this SFP ++ Returns: ++ A Boolean, True if lpmode is enabled, False if disabled ++ """ ++ # SFP doesn't support this feature ++ return False ++ ++ def get_power_set(self): ++ ++ # SFP doesn't support this feature ++ return False ++ ++ def get_power_override(self): ++ """ ++ Retrieves the power-override status of this SFP ++ Returns: ++ A Boolean, True if power-override is enabled, False if disabled ++ """ ++ return False # SFP doesn't support this feature ++ ++ def reset(self): ++ """ ++ Reset SFP and return all user module settings to their default srate. ++ Returns: ++ A boolean, True if successful, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def tx_disable(self, tx_disable): ++ """ ++ Disable SFP TX for all channels ++ Args: ++ tx_disable : A Boolean, True to enable tx_disable mode, False to disable ++ tx_disable mode. ++ Returns: ++ A boolean, True if tx_disable is set successfully, False if not ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ gpiopin = self.GPIO_PATH.format(self.PORT_TX_DISABLE_GPIO_MAPPING[self.index]) ++ cmdstatus, value = cmd.getstatusoutput('echo {} > {}'.format(tx_disable, gpiopin)) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp tx_disable cmdstatus get failed") ++ return False ++ return True ++ ++ def tx_disable_channel(self, channel, disable): ++ """ ++ Sets the tx_disable for specified SFP channels ++ Args: ++ channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, ++ e.g. 0x5 for channel 0 and channel 2. ++ disable : A boolean, True to disable TX channels specified in channel, ++ False to enable ++ Returns: ++ A boolean, True if successful, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def set_lpmode(self, lpmode): ++ """ ++ Sets the lpmode (low power mode) of SFP ++ Args: ++ lpmode: A Boolean, True to enable lpmode, False to disable it ++ Note : lpmode can be overridden by set_power_override ++ Returns: ++ A boolean, True if lpmode is set successfully, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def set_power_override(self, power_override, power_set): ++ """ ++ Sets SFP power level using power_override and power_set ++ Args: ++ power_override : ++ A Boolean, True to override set_lpmode and use power_set ++ to control SFP power, False to disable SFP power control ++ through power_override/power_set and use set_lpmode ++ to control SFP power. ++ power_set : ++ Only valid when power_override is True. ++ A Boolean, True to set SFP to low power mode, False to set ++ SFP to high power mode. ++ Returns: ++ A boolean, True if power-override and power_set are set successfully, ++ False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return "Ethernet" + str(self.index - 1) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_PRESENT_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp present cmdstatus get failed") ++ return False ++ if int(value) == 0: ++ return True ++ else: ++ return False ++ ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return self.get_presence() ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.port_num ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ if self.sfp_type == "SFP": ++ return True ++ else: ++ return False ++ ++ def get_error_description(self): ++ """ ++ Retrives the error descriptions of the SFP module ++ Returns: ++ String that represents the current error descriptions of vendor specific errors ++ In case there are multiple errors, they should be joined by '|', ++ like: "Bad EEPROM|Unsupported cable" ++ """ ++ if not self.get_presence(): ++ err_descr = self.SFP_STATUS_UNPLUGGED ++ else: ++ err_descr = self.SFP_STATUS_OK ++ ++ return err_descr +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal.py +new file mode 100644 +index 000000000..a92ed271c +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal.py +@@ -0,0 +1,303 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# 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.sfp import Sfp ++ from sonic_platform.fan import Fan ++ from sonic_platform_base.thermal_base import ThermalBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Thermal(ThermalBase): ++ """Platform-specific Thermal class""" ++ ++ THERMAL_NAME_LIST = [] ++ SYSFS_THERMAL_DIR = ["/sys/bus/i2c/devices/2-004a/hwmon/", ++ "/sys/bus/i2c/devices/2-0049/hwmon/", ++ "/sys/bus/i2c/devices/2-004b/hwmon/", ++ "/sys/bus/i2c/devices/3-0059/hwmon/", ++ "/sys/bus/i2c/devices/3-0058/hwmon/", ++ "/sys/devices/virtual/thermal/thermal_zone1/", ++ "/sys/bus/i2c/devices/0-001b/hwmon/"] ++ ++ def __init__(self, thermal_index): ++ self.index = thermal_index ++ self.fan = Fan(0, 0) ++ self.direction = self.fan.get_direction() ++ if thermal_index >= 8: ++ self.sfp_module = Sfp(49 + (thermal_index - 8), 'SFP') ++ ++ # Add thermal name ++ if self.direction == "exhaust": ++ self.THERMAL_NAME_LIST.append("XFMR Ambient") ++ self.THERMAL_NAME_LIST.append("DDR Ambient") ++ self.THERMAL_NAME_LIST.append("System Ambient") ++ else: ++ self.THERMAL_NAME_LIST.append("System Ambient") ++ self.THERMAL_NAME_LIST.append("FAN Ambient") ++ self.THERMAL_NAME_LIST.append("CPU Ambient") ++ ++ self.THERMAL_NAME_LIST.append("PSU 1 Temp") ++ self.THERMAL_NAME_LIST.append("PSU 2 Temp") ++ self.THERMAL_NAME_LIST.append("CPU Temp") ++ self.THERMAL_NAME_LIST.append("Dimm Temp") ++ self.THERMAL_NAME_LIST.append("MAC Temp") ++ ++ self.THERMAL_NAME_LIST.append("XCVR 1 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 2 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 3 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 4 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 5 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 6 Temp") ++ ThermalBase.__init__(self) ++ self.minimum_thermal = 150.0 ++ self.maximum_thermal = 0.0 ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return "" ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def __get_temp(self, temp_file): ++ hwmon_dir = self.__search_hwmon_dir_name(self.SYSFS_THERMAL_DIR[self.index]) ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], hwmon_dir, temp_file) ++ raw_temp = self.__read_txt_file(temp_file_path) ++ temp = float(raw_temp)/1000 ++ return "{:.3f}".format(temp) ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from thermal ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 5 or self.index == 6: ++ temp_file = "temp1_input" ++ if self.get_presence(): ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ temp_file = "temp" ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], temp_file) ++ raw_temp = self.__read_txt_file(temp_file_path) ++ temp = float(raw_temp)/1000 ++ return float("{:.3f}".format(temp)) ++ elif self.index == 7: ++ from swsscommon.swsscommon import DBConnector ++ temp = 0 ++ try: ++ stateDB = DBConnector('STATE_DB', 0, True, '') ++ temp = int(stateDB.hget('ASIC_TEMPERATURE_INFO', 'temperature_0')) ++ except Exception as E: ++ print("get_temperature (MAC) failed, cause by {}".format(E)) ++ return float("{:.3f}".format(temp)) ++ else: ++ if self.get_presence(): ++ return float("{:.3f}".format(self.sfp_module.get_temperature())) ++ ++ def get_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of thermal ++ Returns: ++ A float number, the high threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 3 or self.index == 6: ++ return float("{:.3f}".format(80)) ++ elif self.index < 5: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ return float("{:.3f}".format(90)) ++ elif self.index == 7: ++ return float("{:.3f}".format(100)) ++ else: ++ return float("{:.3f}".format(68)) ++ ++ def get_caution2_threshold(self): ++ """ ++ Retrieves the T-caution2 threshold temperature of thermal ++ Returns: ++ A float number, the high threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 3 or self.index == 6: ++ return float("{:.3f}".format(82)) ++ elif self.index < 5: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) + 2 ++ elif self.index == 5: ++ return float("{:.3f}".format(92)) ++ elif self.index == 7: ++ return float("{:.3f}".format(105)) ++ else: ++ return float("{:.3f}".format(69)) ++ ++ def get_high_critical_threshold(self): ++ """ ++ Retrieves the high critical threshold temperature of thermal ++ :return: A float number, the high critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ ++ if self.index < 3: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) ++ elif self.index < 5: ++ temp_file = "temp1_crit" ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ return float("{:.3f}".format(95)) ++ elif self.index == 6: ++ return float("{:.3f}".format(85)) ++ elif self.index == 7: ++ return float("{:.3f}".format(108)) ++ else: ++ return float("{:.3f}".format(70)) ++ ++ ++ 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 ++ """ ++ if self.index < 5 or self.index == 6: ++ temp_file = "temp1_input" ++ hwmon_dir = self.__search_hwmon_dir_name(self.SYSFS_THERMAL_DIR[self.index]) ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], hwmon_dir, temp_file) ++ return os.path.isfile(temp_file_path) ++ elif self.index == 5: ++ temp_file = "temp" ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], temp_file) ++ return os.path.isfile(temp_file_path) ++ elif self.index > 7: ++ return self.sfp_module.get_presence() ++ return True ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ if self.index > 6 and self.index < 8: ++ return True ++ if not self.get_presence(): ++ return False ++ ++ return True ++ ++ def get_low_threshold(self): ++ """ ++ Retrieves the low threshold temperature of thermal ++ :return: A float number, the low threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ # work temperatur is 0~40, hyst is 2 ++ return 2.0 ++ ++ def get_low_critical_threshold(self): ++ """ ++ Retrieves the low critical threshold temperature of thermal ++ :return: A float number, the low critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ # work temperatur is 0~40 ++ return 0.0 ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return "None" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "None" ++ ++ def is_replaceable(self): ++ """ ++ Retrieves whether thermal module is replaceable ++ Returns: ++ A boolean value, True if replaceable, False if not ++ """ ++ return False ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return self.index + 1 ++ ++ def get_minimum_recorded(self): ++ """ ++ Retrieves the minimum recorded temperature of thermal ++ Returns: ++ A float number, the minimum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ tmp = self.get_temperature() ++ if tmp is None: ++ return self.minimum_thermal ++ if tmp < self.minimum_thermal: ++ self.minimum_thermal = tmp ++ return self.minimum_thermal ++ ++ def get_maximum_recorded(self): ++ """ ++ Retrieves the maximum recorded temperature of thermal ++ Returns: ++ A float number, the maximum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ tmp = self.get_temperature() ++ if tmp is None: ++ return self.maximum_thermal ++ if tmp > self.maximum_thermal: ++ self.maximum_thermal = tmp ++ return self.maximum_thermal +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_actions.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_actions.py +new file mode 100755 +index 000000000..2f024d052 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_actions.py +@@ -0,0 +1,240 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++import math ++import time ++import sonic_platform.platform ++try: ++ from sonic_platform.thermal import Thermal ++except Exception as e: ++ print(e) ++ ++from sonic_py_common import daemon_base, logger ++ ++sonic_logger = logger.Logger('thermal_actions') ++ ++SENSORS_NUM = 5 ++ ++TEMP_INFO = [] ++ ++SENSOR_INDEX = { ++ 0: 0, ++ 1: 1, ++ 2: 2, ++ 3: 5, ++ 4: 7 ++} ++ ++COFF_KA = { ++ 'exhaust': { ++ 0: 2.62, ++ 1: 2.15, ++ 2: 2.23, ++ 3: 2.51, ++ 4: 1.6 ++ }, ++ 'intake': { ++ 0: 2.5, ++ 1: 1.8, ++ 2: 1.9, ++ 3: 1.5, ++ 4: 1.1 ++ } ++} ++ ++COFF_KB = { ++ 'exhaust': { ++ 0: 110, ++ 1: 72, ++ 2: 78, ++ 3: 126, ++ 4: 60 ++ }, ++ 'intake': { ++ 0: 100, ++ 1: 44, ++ 2: 52, ++ 3: 35, ++ 4: 10 ++ } ++} ++ ++class SetFanSpeedAction(ThermalPolicyActionBase): ++ """ ++ Base thermal action class to set speed for fans ++ """ ++ # JSON field definition ++ JSON_FIELD_SPEED = 'speed' ++ ++ def __init__(self): ++ """ ++ Constructor of SetFanSpeedAction ++ """ ++ self.default_speed = 50 ++ self.high_temp_speed = 100 ++ self.speed = self.default_speed ++ self.chassis = sonic_platform.platform.Platform().get_chassis() ++ self.direction = self.chassis.get_fan(0).get_direction() ++ ++ ++ def load_from_json(self, json_obj): ++ """ ++ Construct SetFanSpeedAction via JSON. JSON example: ++ { ++ "type": "fan.all.set_speed" ++ "speed": "100" ++ } ++ :param json_obj: A JSON object representing a SetFanSpeedAction action. ++ :return: ++ """ ++ if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj: ++ speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) ++ if speed < 0 or speed > 100: ++ raise ValueError( ++ 'SetFanSpeedAction invalid speed value {} in JSON policy file, valid value should be [0, 100]'. ++ format(speed)) ++ self.speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) ++ # else: ++ # raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. ++ # format(SetFanSpeedAction.JSON_FIELD_SPEED)) ++ ++ def get_chassis(self): ++ return self.chassis ++ ++ def get_direction(self): ++ return self.direction ++ ++ @classmethod ++ def set_all_fan_speed(cls, thermal_info_dict, speed): ++ from .thermal_infos import FanInfo ++ if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): ++ fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME] ++ for fan in fan_info_obj.get_presence_fans(): ++ fan.set_speed(int(speed)) ++ ++ @classmethod ++ def calc_fan_speed(cls, index, temp): ++ direction = cls().get_direction() ++ fan_speed = int((temp * COFF_KA[direction][index] - COFF_KB[direction][index])) ++ ++ if fan_speed < 30: ++ fan_speed = 30 ++ elif fan_speed > 100: ++ fan_speed = 100 ++ ++ return fan_speed ++ ++ @classmethod ++ def power_down(cls): ++ chassis = cls().get_chassis() ++ chassis.power_down() ++ ++ @classmethod ++ def get_temp(cls, thermal_info_dict): ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ return thermal_info_obj.get_temp_list() ++ ++@thermal_json_object('fan.all.set_speed') ++class SetAllFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) ++ ++ ++@thermal_json_object('fan.new.set_speed') ++class SetNewFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.default_speed) ++ time.sleep(8) ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) ++ ++ ++@thermal_json_object('switch.shutdown') ++class SwitchPolicyAction(ThermalPolicyActionBase): ++ """ ++ Base class for thermal action. Once all thermal conditions in a thermal policy are matched, ++ all predefined thermal action will be executed. ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Take action when thermal condition matches. For example, adjust speed of fan or shut ++ down the switch. ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ temp_info = thermal_info_obj.get_temp_dict() ++ for key in temp_info: ++ sonic_logger.log_warning( ++ "Temp is over high critical threshold, system shutdown {} temperature is {}".format(key, temp_info[key])) ++ import os ++ os.system('sync') ++ SetFanSpeedAction.power_down() ++ # import os ++ # os.system('reboot') ++ ++ ++@thermal_json_object('fan.set_speed') ++class SetAllFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ temp_info = thermal_info_obj.get_temp_dict() ++ temp_list = [] ++ for key in temp_info: ++ temp_list.append(temp_info[key]) ++ speed = 0 ++ for i in range(0, SENSORS_NUM): ++ if SetFanSpeedAction.calc_fan_speed(i, temp_list[SENSOR_INDEX[i]]) > speed: ++ speed = SetFanSpeedAction.calc_fan_speed(i, temp_list[SENSOR_INDEX[i]]) ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, speed) ++ ++@thermal_json_object('high_threshold.control') ++class ThermalOverHighThresholdAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_conditions.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_conditions.py +new file mode 100755 +index 000000000..66f92c720 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_conditions.py +@@ -0,0 +1,110 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++ ++ ++class ThermalCondition(ThermalPolicyConditionBase): ++ def get_thermal_info(self, thermal_info_dict): ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ++ ThermalInfo): ++ return thermal_info_dict[ThermalInfo.INFO_NAME] ++ else: ++ return None ++ ++ ++@thermal_json_object('thermal.over.high_threshold') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ if thermal_info_obj: ++ return thermal_info_obj.is_over_high_threshold() ++ else: ++ return False ++ ++ ++@thermal_json_object('thermal.over.high_critical_threshold') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ return thermal_info_obj.is_over_high_critical_threshold() if thermal_info_obj else False ++ ++ ++@thermal_json_object('thermal.over.threshold_after_cool_down') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ return thermal_info_obj.is_warm_up_and_over_high_threshold() if thermal_info_obj else False ++ ++ ++class FanCondition(ThermalPolicyConditionBase): ++ old_presence = True ++ interval_cnt = 0 ++ ++ def get_fan_info(self, thermal_info_dict): ++ from .thermal_infos import FanInfo ++ if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): ++ return thermal_info_dict[FanInfo.INFO_NAME] ++ else: ++ return None ++ ++ ++@thermal_json_object('fan.any.absence') ++class AnyFanAbsenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if len(fan_info_obj.get_absence_fans()) > 0: ++ self.old_presence = False ++ result = len(fan_info_obj.get_absence_fans()) == 1 if fan_info_obj else False ++ return result ++ ++ ++@thermal_json_object('fan.all.absence') ++class AllFanAbsenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if len(fan_info_obj.get_absence_fans()) > 0: ++ self.old_presence = False ++ return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False ++ ++ ++@thermal_json_object('fan.any.new') ++class AllFanNewCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ # Update status ++ self.all_presence = True ++ if len(fan_info_obj.get_absence_fans()) == 0: ++ self.all_presence = True ++ else: ++ self.all_presence = False ++ if self.all_presence == True and self.old_presence == False: ++ self.new_fan_insert = True ++ else: ++ self.new_fan_insert = False ++ self.old_presence = self.all_presence ++ return self.new_fan_insert if fan_info_obj else False ++ ++ ++@thermal_json_object('fan.all.presence') ++class AllFanPresenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if not self.old_presence and len(fan_info_obj.get_absence_fans()) == 0: ++ self.old_presence = True ++ return False ++ elif not self.old_presence and len(fan_info_obj.get_absence_fans()) != 0: ++ self.old_presence = False ++ return False ++ else: ++ if len(fan_info_obj.get_absence_fans()) != 0: ++ self.old_presence = False ++ return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False ++ ++ ++class PsuCondition(ThermalPolicyConditionBase): ++ def get_psu_info(self, thermal_info_dict): ++ from .thermal_infos import PsuInfo ++ if PsuInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[PsuInfo.INFO_NAME], PsuInfo): ++ return thermal_info_dict[PsuInfo.INFO_NAME] ++ else: ++ return None +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_infos.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_infos.py +new file mode 100755 +index 000000000..72dbfa546 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_infos.py +@@ -0,0 +1,210 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++ ++ ++@thermal_json_object('fan_info') ++class FanInfo(ThermalPolicyInfoBase): ++ """ ++ Fan information needed by thermal policy ++ """ ++ ++ # Fan information name ++ INFO_NAME = 'fan_info' ++ ++ def __init__(self): ++ self._absence_fans = set() ++ self._presence_fans = set() ++ self._fault_fans = set() ++ self._status_changed = False ++ ++ def collect(self, chassis): ++ """ ++ Collect absence and presence fans. ++ :param chassis: The chassis object ++ :return: ++ """ ++ self._status_changed = False ++ for fan in chassis.get_all_fans(): ++ status = fan.get_status() ++ if fan.get_presence() and fan not in self._presence_fans: ++ self._presence_fans.add(fan) ++ self._status_changed = True ++ if fan in self._absence_fans: ++ self._absence_fans.remove(fan) ++ elif not fan.get_presence() and fan not in self._absence_fans: ++ self._absence_fans.add(fan) ++ self._status_changed = True ++ if fan in self._presence_fans: ++ self._presence_fans.remove(fan) ++ ++ if not status and fan not in self._fault_fans: ++ self._fault_fans.add(fan) ++ self._status_changed = True ++ elif status and fan in self._fault_fans: ++ self._fault_fans.remove(fan) ++ self._status_changed = True ++ ++ def get_absence_fans(self): ++ """ ++ Retrieves absence fans ++ :return: A set of absence fans ++ """ ++ return self._absence_fans ++ ++ def get_presence_fans(self): ++ """ ++ Retrieves presence fans ++ :return: A set of presence fans ++ """ ++ return self._presence_fans ++ ++ def get_fault_fans(self): ++ """ ++ Retrieves fault fans ++ :return: A set of fault fans ++ """ ++ return self._fault_fans ++ ++ def is_status_changed(self): ++ """ ++ Retrieves if the status of fan information changed ++ :return: True if status changed else False ++ """ ++ return self._status_changed ++ ++ ++@thermal_json_object('thermal_info') ++class ThermalInfo(ThermalPolicyInfoBase): ++ """ ++ Thermal information needed by thermal policy ++ """ ++ ++ # Fan information name ++ INFO_NAME = 'thermal_info' ++ ++ def __init__(self): ++ self._state = ["N/A"] * 15 ++ self._enter_warm_up_state = [False] * 15 ++ self.init = False ++ self.normal_thres = False ++ self.high_thres = False ++ self.critical_high_thres = False ++ self.warm_up_thres = False ++ self._temp_dict = {} ++ ++ def collect(self, chassis): ++ """ ++ Collect thermal sensor temperature change status ++ :param chassis: The chassis object ++ :return: ++ """ ++ # self._cool_down_and_below_low_threshold = False ++ ++ # Calculate average temp within the device ++ num_of_thermals = chassis.get_num_thermals() ++ ++ # Initial the to default ++ self.normal_thres = False ++ self.high_thres = False ++ self.critical_high_thres = False ++ self.warm_up_thres = False ++ ++ # Collect the information ++ for index in range(num_of_thermals): ++ if not chassis.get_thermal(index).get_presence(): ++ continue ++ ++ # Store the temperature in the DB ++ name = chassis.get_thermal(index).get_name() ++ temp = chassis.get_thermal(index).get_temperature() ++ self._temp_dict[name] = temp ++ ++ # Get the threshold ++ normal_temp = chassis.get_thermal(index).get_high_threshold() ++ high_temp = chassis.get_thermal(index).get_caution2_threshold() ++ critical_high_temp = chassis.get_thermal(index).get_high_critical_threshold() ++ ++ # Check if the temperature is over the threshold ++ if temp < normal_temp: ++ self._state[index] = "n/a" ++ elif normal_temp <= temp < high_temp: ++ self._state[index] = "normal" ++ elif high_temp <= temp < critical_high_temp: ++ if self._state[index] == "high": ++ self._enter_warm_up_state[index] = True ++ self._state[index] = "high" ++ elif temp >= critical_high_temp: ++ self._state[index] = "critical" ++ ++ # Check the system status ++ if self._state[index] == "critical": ++ self.critical_high_thres = True ++ elif self._state[index] == "high": ++ self.high_thres = True ++ elif self._state[index] == "normal": ++ self.normal_thres = True ++ ++ if self._enter_warm_up_state[index]: ++ self.warm_up_thres = True ++ ++ def get_temp_dict(self): ++ return self._temp_dict ++ ++ def is_over_high_threshold(self): ++ """ ++ Retrieves if the temperature is over high threshold ++ :return: True if the temperature is over high threshold else False ++ """ ++ if self.high_thres and not self.critical_high_thres: ++ return True ++ return False ++ ++ def is_warm_up_and_over_high_threshold(self): ++ """ ++ Retrieves if the temperature is warm up and over high threshold ++ :return: True if the temperature is warm up and over high threshold else False ++ """ ++ ++ return self.warm_up_thres ++ ++ def is_over_high_critical_threshold(self): ++ """ ++ Retrieves if the temperature is over high critical threshold ++ :return: True if the temperature is over high critical threshold else False ++ """ ++ return self.critical_high_thres ++ ++ def is_over_normal_threshold(self): ++ """ ++ Retrieves if the temperature is over high critical threshold ++ :return: True if the temperature is over high critical threshold else False ++ """ ++ if self.normal_thres and not self.critical_high_thres and not self.high_thres: ++ return True ++ return False ++ ++ ++@thermal_json_object('chassis_info') ++class ChassisInfo(ThermalPolicyInfoBase): ++ """ ++ Chassis information needed by thermal policy ++ """ ++ INFO_NAME = 'chassis_info' ++ ++ def __init__(self): ++ self._chassis = None ++ ++ def collect(self, chassis): ++ """ ++ Collect platform chassis. ++ :param chassis: The chassis object ++ :return: ++ """ ++ self._chassis = chassis ++ ++ def get_chassis(self): ++ """ ++ Retrieves platform chassis object ++ :return: A platform chassis object. ++ """ ++ return self._chassis +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_manager.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_manager.py +new file mode 100755 +index 000000000..3fe0942bd +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/thermal_manager.py +@@ -0,0 +1,10 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase ++from .thermal_actions import * ++from .thermal_conditions import * ++from .thermal_infos import * ++ ++ ++class ThermalManager(ThermalManagerBase): ++ @classmethod ++ def initialize(cls): ++ pass +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/watchdog.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/watchdog.py +new file mode 100644 +index 000000000..4193dee09 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/sonic_platform/watchdog.py +@@ -0,0 +1,199 @@ ++""" ++Module contains an implementation of SONiC Platform Base API and ++provides access to hardware watchdog ++""" ++ ++import os ++import fcntl ++import array ++ ++from sonic_platform_base.watchdog_base import WatchdogBase ++from sonic_py_common import logger ++ ++""" ioctl constants """ ++IO_READ = 0x80000000 ++IO_SIZE_INT = 0x00040000 ++IO_READ_WRITE = 0xC0000000 ++IO_TYPE_WATCHDOG = ord('W') << 8 ++ ++WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG ++WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG ++ ++""" Watchdog ioctl commands """ ++WDIOC_SETOPTIONS = 4 | WDR_INT ++WDIOC_KEEPALIVE = 5 | WDR_INT ++WDIOC_SETTIMEOUT = 6 | WDWR_INT ++WDIOC_GETTIMEOUT = 7 | WDR_INT ++WDIOC_GETTIMELEFT = 10 | WDR_INT ++ ++""" Watchdog status constants """ ++WDIOS_DISABLECARD = 0x0001 ++WDIOS_ENABLECARD = 0x0002 ++ ++""" watchdog sysfs """ ++WD_SYSFS_PATH = "/sys/class/watchdog/{}/" ++WD_DEV_PATH = "/dev/{}" ++ ++WD_COMMON_ERROR = -1 ++ ++sonic_logger = logger.Logger() ++ ++ ++class WatchdogImplBase(WatchdogBase): ++ """ ++ Base class that implements common logic for interacting ++ with watchdog using ioctl commands ++ """ ++ ++ def __init__(self, wd_device_path): ++ """ ++ Open a watchdog handle ++ @param wd_device_path Path to watchdog device ++ """ ++ ++ self.watchdog_path = WD_DEV_PATH.format(wd_device_path) ++ self.watchdog_sysfs_path = WD_SYSFS_PATH.format(wd_device_path) ++ ++ # Opening a watchdog descriptor starts ++ # watchdog timer; by default it should be stopped ++ #self._disablewatchdog() ++ ++ self.timeout = self._gettimeout() ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def disarm(self): ++ """ ++ Disarm the hardware watchdog ++ ++ Returns: ++ A boolean, True if watchdog is disarmed successfully, False ++ if not ++ """ ++ sonic_logger.log_info(" Debug disarm watchdog ") ++ ++ try: ++ self._disablewatchdog() ++ except IOError: ++ return False ++ ++ return True ++ ++ def _disablewatchdog(self): ++ """ ++ Turn off the watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('h', [WDIOS_DISABLECARD]) ++ fcntl.ioctl(watchdog, WDIOC_SETOPTIONS, req, False) ++ os.close(watchdog) ++ ++ def _settimeout(self, seconds): ++ """ ++ Set watchdog timer timeout ++ @param seconds - timeout in seconds ++ @return is the actual set timeout ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('I', [seconds]) ++ fcntl.ioctl(watchdog, WDIOC_SETTIMEOUT, req, True) ++ os.close(watchdog) ++ ++ return int(req[0]) ++ ++ def _gettimeout(self): ++ """ ++ Get watchdog timeout ++ @return watchdog timeout ++ """ ++ ++ timeout_path = self.watchdog_sysfs_path + "timeout" ++ timeout = self.__read_txt_file(timeout_path) ++ return int(timeout) ++ ++ def _gettimeleft(self): ++ """ ++ Get time left before watchdog timer expires ++ @return time left in seconds ++ """ ++ ++ timeleft_path = self.watchdog_sysfs_path + "timeleft" ++ timeleft = self.__read_txt_file(timeleft_path) ++ return int(timeleft) ++ ++ ++ def arm(self, seconds): ++ """ ++ Implements arm WatchdogBase API ++ """ ++ sonic_logger.log_info(" Debug arm watchdog4 ") ++ ret = WD_COMMON_ERROR ++ if seconds < 0: ++ return ret ++ ++ try: ++ if self.timeout != seconds: ++ self.timeout = self._settimeout(seconds) ++ if self.is_armed(): ++ self._keepalive() ++ else: ++ sonic_logger.log_info(" Debug arm watchdog5 ") ++ self._enablewatchdog() ++ self._keepalive() ++ ret = self.timeout ++ except IOError: ++ pass ++ ++ return ret ++ ++ def _enablewatchdog(self): ++ """ ++ Turn on the watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('h', [WDIOS_ENABLECARD]) ++ fcntl.ioctl(watchdog, WDIOC_SETOPTIONS, req, False) ++ os.close(watchdog) ++ ++ def _keepalive(self): ++ """ ++ Keep alive watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ fcntl.ioctl(watchdog, WDIOC_KEEPALIVE) ++ os.close(watchdog) ++ ++ def is_armed(self): ++ """ ++ Implements is_armed WatchdogBase API ++ """ ++ state_path = self.watchdog_sysfs_path + "state" ++ state = self.__read_txt_file(state_path) ++ return state == "active" ++ ++ def get_remaining_time(self): ++ """ ++ Implements get_remaining_time WatchdogBase API ++ """ ++ ++ timeleft = WD_COMMON_ERROR ++ ++ if self.is_armed(): ++ try: ++ timeleft = self._gettimeleft() ++ except IOError: ++ pass ++ ++ return timeleft ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/get-base-mac.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/get-base-mac.py +new file mode 100644 +index 000000000..fe271d04a +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/get-base-mac.py +@@ -0,0 +1,20 @@ ++#!/usr/bin/env python ++ ++def main(): ++ try: ++ import sonic_platform.platform ++ import sonic_platform.chassis ++ except ImportError, e: ++ raise ImportError (str(e) + "- required module not found") ++ ++ chassis = sonic_platform.platform.Platform().get_chassis() ++ if chassis is None: ++ print "DEBUG chassis was None " ++ ++ base_mac = chassis.get_base_mac() ++ print base_mac ++ ++ return ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/phytool b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/phytool +new file mode 100755 +index 0000000000000000000000000000000000000000..2a34c41e6fd4ae17ab3132328282c419236b9383 +GIT binary patch +literal 24440 +zcmeHv3wRXAm2ORs5O@$mNCIIXp#=sDfgWJ-FlNo@fdw(fM98u4nyjX!8A)S}X2i@0 +zBtzoi;m5u4cTGp)k!%3Pb`mt3yXM<~12&t;IGZ?ek|hQ^B=KV;jF)V@2@cq3Z1C)V +z>LIlTQ-V%-XXnrUDnSktOT(fb}7~hCX$3<>8 +z4cByBlW|SKMJX3oIXOrQ0Inzhfno5XVes9MucIzG{S3hMd35A3Hx|Vj-gu+H$Q%zlCQ%$|$^|6-La9yJj +zWJYZu7$&lCph;vtR^Q+Whp2%6!RZMG{ec=^pw0+;1AgG{Kx>%QlLY>6h}GBm0wIrJ +zZ}l-F)Drai!}UZ8X66mlg?-FhUqhOO175$|(*{mKQ&UsdX4KSs{f5u`poi55T0DNC +zcwKV~TBrV!^1*OTv*AVae#uCEX4K!H(Ol#8Z1S0is3d^0AHnWtmE2a?#9w#XZHZ3WP>caRpI(kUZ28Tl1I>M +z1N3U&VV8^1Nm@vd&dYs?!XpyDkc7KvkwNND!jI+({KB0=F(qfc+)wl;;Y|`}a$lq9 +z+ax|F3EwX9j3j)H#3v`=B@)+@@MRLuOTt%4yf_JeccJLlk|g|Ni93_;Bs@pr +zYm@M2q@4Sb@E(b~lJH+hyfF#?t;AcB@OFu}CE<@qJd%WWNc^!Ryi4K-?;bk7`aEHu +zSQ6efSK#N9aT#34$bEzwcU7L8ggX}qIeHTQ`XqtpCE=%O6NglsgnySdMo3GN@Rd@& +zGYNlO%3qm;KSmoyq_s(S+8lvLlJGOMp+uT|?@+sC(?$|$NfN$;Hl|32q}^8J&_?rVE2xY}3_+aZB?~UM{v1DP!L9v0W5H=(tWwN^tGzSTowwj>-%a=h3r_oKmHI8X+Mn|} +z*v|8|%Ef`Gtc$_L|qI;sWrU$R_-C +zWjy1=Qd8HazcyXBzp5@?_cy5P6Lq{?i?Vhbr{(2(lxJAV51?FTDf>~bwUmP>Z?lv) +zqWq+#{28f|%G)gE-6%h4DSsX1 +z6PEIRl>02@CsEe^YOwupqddb>j-p&D>K4B^U0OdYQ +z`2@<^?St+A808t3^3PB%vy^{{a;+#|-TWN)gNy5I-5nVB_wU!bKd`g>_wBZ*>yMT3 +z%XRi{8*|2ci&)&oBCkY1!}=@ZlYw>NF-o?JnV0P>x>a+=OKt4PrCMgbmC80euCeM6 +z_~Loyu_tDq9Q`)(o{tkHo!glCULujRHI-;0RTtNlcE5jrS@#9B +zf4Q!_`|9Q&A7t>s@1q`(_GIqyF=ou36WvYxDQw|e4z|I-W1tf7V*Y1;V7HkwaKGIF +zo$ZsNUC3Q*`D>TZCu|@~BBXz;60)3e26=4nXmcH8U4RZT(C^V$XD?_YR}*xkJ;~D2 +z%>$@U?n_TRaU^EX&R6;>U1=V1Jx>Zfec+8~&@-KF__q%e)x+uM{3x+dgWhE0u5@QS +zAAF<->C^$85KA^(8hv2Oo6wWXKQH80gDz$hc8Fb0Tx0XdrNohM!UoVanyhPy#@WqdnqS$Cl_z61G=)0OcXp-Ue1 +zmu!5#GVa89PlFt?iHaXx@EPXP&2J*lMZTP|KlEVywt^@3Ol8~v4~;#IIq@aa=Q8&4 +zj4KbFDoxw^mE0?(9WQ_$&m=CCU8#)Ma$aqKm)g9#`3J(k$FlhM(59=_b*mHhija=4 +zSH_Va=53@n!@irHaf9X{v;C|TeR>XbYP_#*{wLlCt1T{) +zkCP2Bmq&}aaEQfnyH5T)nv7guIwNE8l99;pC+%dFyX8&)HKUD;2U* +zAuAQKQll?lSJtrsn|4Ak8Y>x#qGa0$`pDzZViAX2na*REr?U8EyO!U>`WKaA%xM0^ +z?6&*^knhT5$3md#(E1mjMNH7N$SV{NVs?ARkueQpcen=iv1gp^7^C)n_y@O>jANIl +zk`Mhv+JDe*sE-%XudR?r{e0i9ML&RUR{z2Lk5V7|Y>`(;?{>6v8GV6#*fA$c{ndq@ +z(b!CikIq{S`1Yw8tbLcA9aixqW}g_H1Uj~iW%kTw?F@X_BWEu^kJxEr)k+piVP+cW +zdLb(pvbHj|Fe^JNKU6kh!5`2snitf6^0lqf*FbZ4I(TA<1698Vjq*9sZ{>IYI54(Z +zm=mFAM`0e=qhfq*=t~yHSd0GtDq_0E;=0BT69zqBc^eq)8t=jUQP^9+;Q#MMfX5IM +z@xXY3YWM2q7v)|iQuUG4Igb45=I?PG&YrcIw5IKa{e|6au)CIT`%`6{*1&jEN;e;a +z1~G?wpR$>KFWStH<}!#$?M^Ib@t9_Hj^$m(st +z`hu9LW8K3uhQqHx=NSBk!B)=EtmNWbcXW$!of!Sdu9@-Wv|gdlsP98=qu6nL6vldL +z^!woL-HvfD2My{!q;&!JZvg)gYv2IAGnLc-9np6PdWvb}$3*`t;2}F(_-l-rkWchE +z(HDU;tWmKB=P~AF6JiaBHKSM0(X+8;IwvgXfu<$?g-QD^Mo;Jc|5#schk;+vFaE_cJ?c0zaU!KfHkUJJXq& +z19>=eWp}1B6YGeu$#JqtcJvWRn~Qx>XC`Ph5wB>yr}}!-N9?eH#>RdyX;OX+{_q;+ +z-LtSg{Cr?8KdI!pMsvB<;G-DD_1+?|CfU~3j}q0LQg|a0Dt=)P7H_KP{%9`6v0n^{V-#1_zVVV=|K87Ham?lX#6xy5 +zkK|g|i?uH?6S3?pGq0enAHp|!F?Vw@cd-X(@?q|rg&ks}%e(t#I^#z`lf15Nh2N&2 +zZ?x{woaQ=akzOj!493?E%x_w2u^#Ysnf8O$*vj>UPQ9=J?GF)OuDdt<`4zDrNY*8n +z;t}e|Kgn0NVbA7-99oyj=V||Rt$u@Xkm5hZ{>0s^o$Hk&qb+gc62HNPYVeP%o +zGxH+$MsgkDdt}v~*e4?nxzHxs`#t1xd3;|a;;eNqM19iIoZT$Ld8}`|y_L5*f_L)6%%^7Fv`nTb{@;2Jl5Oc~7jS{iPc>{bREB{Hf +zf%S)`e@Q|10RZ4YoRqb+r_{2KI1>Q-@bkKhclxp#CiMr1qifA*t&j_R&O6>XbkoJ`?3E#w+ +zM9+0F^Xzs;V{(X9J5-!GnT>MiKa4VIKGs5hpPV;+h#d>jey_b^4&CDygF9`AvC}Kq +zhFr$(%sqsC0?CRv%(+B|IpYGqj`i6IpZX(oB3%dPiSQ?7Z;EqS@JF)AS=f`y+UYP6 +z_b24=cC!UGZ>;%C*x1k}&||Pe%r(}GlFd^hRTDvHXqf`vGS=k&34A=qvjpBb*4!`Y +zZ{T>gz`r}z+$(WA$0rKBXRL`>&gEZ49}I1hz)z1gAD8%Lj^_xxf2{ckaPp7$fcIhz +z<$6v_GrNEr+GIgjl4fp^{QtuFrwZJaW^R;tFUO||d~cfBBJtmG{4)aod7Alv#9!t3 +zX9dp2nQn>yGsmY3JbRq^HxmCT$NA5chgk7A^FH9Dw-~1r2Va0cQ9PT@vV!z1Yq+tZ +zF`~WR7r?tKEmHNWwhQ~UDM9w7NYxQ7BK+d~x;b0oCdcJ?^`x7+#J|FEIbN}JbBe?t=J<`$PUFpN +z;5Z-VKLmV0@3rI2LZXN7kv$&L+WySi#?d;**Yq;?II}Dx@^wDujpI#v)OS;e*g=j8d +zpHK0V&huqXX8sBDUadhCTkhfGIXJi2O=H%Pu6QA2A?Wa!AGB$_-u|(5w>s3 +zFlm26@^y~Ox$#(r`HaM;a9qxfLm6f_aPr-3;MTEvk?8q2ZTvI!Q;k*fIDPz~g|97> +zw{N7&xp5`~@lmaZFCM)3VIt?qmu*v73j6%uTkNgusA3tn-@6&uYiH$`q+yO=Ja!@O +zA30HE_F3D5jlTvx4Ncm`H^FR`{fvQbAm%(h!3;?Jw;Y$gdUAs4mH26nOFObmvko}f +z<(Jm>iZjhG0e3B0eX8q0SN|Ssoh#Gah&p5T%2Qop|D`V5r|}+c0da{Fm%VbL1k{e6>!} +zS%LN(Pg(XHSW6FwemV0iwPnuulY@JX!F62E;y(N^+NZVI+8)g>@)z27(0&fj+)k=z +zwr^wK;gS1}i}F1EZR{W3!L!;_>^(+d&yhOK*)5)v*vxa-cZ|ZmzBAD-bFkjtMfVc$CwdeRz8^ECDy+OOqA +zp9d|C<9gKnQLXKWE#f)AkL9^x@EMQTUoid*pcQS&(5)-3pUNV~h;fbalHY9m3AjZ8kN<2sJLqA>Ur<0ze_w#4Z +zL!Rfxab}|DOiz5A$kEnpuUgKuCYm;O}ISRTST3HmMH#5R;64wSJ2U#C6YS=mn)jpuvA_w#nNq2!gZH2xcc +zC{HoT|H@dZ`7Ux@%_s6jI?GBs(Y%_@pAR1&csA7uAM1Q_F4jb?o5#UzbInd|;>+}V +z2>BIQ!G{G+LKkn6n48tUu%?64iW8 +zOC7Fm{t=%K#7BCl-{REoaP+RrJt3pPvs9lI(t{qut?R4rE-$TKb@!U0suh(ET_jX) +z3VOqyA(i^F;)3F~dZgPebo||-0lNE1$``MxUUf%l`3lFTM!Xv2aHt0LrGKUKilSvL +zcmZikOJn=(`WC%n#TSZ}l~z<#5wK +zagBQl524Y$u7eJ({v;P2q?Ar7-BCGC`GN)TzVecV4!Rrg9P$l-Lx80NUiX){5xk(d +zsCeluMe{8VBD_dcwHZal~~eHx?6V#y&FBj +zkREDn;Z_&J4Ery2dp3IOJTAT5XS9YqIyxdp#8DpzHXC7#)`(aB$6i^)ibCz7qB@@u +z3KjW1;i6d~a@|l(XpM+yOeC}XvqDQ}`RR5j2gxkEYh6`d +zaa-~HIaa}SMvGDF^?AcyPl(MgE-t7o;aNTZw-Nsq&}{+T6&HjT@DjgiWc5CyA;dgw +z;R3w!8g30S!|!P*KzKnE4SQJ7(~Rj-P;a#Q!m^4Q!waeS`-dj>fKglP337H70a<;k +z&&L`KU;XveFX!qP4^bZh4sR9v0)duVyfG|V@%VWoErCs*V1XN9k$FP_p8<`yeqf;& +zbXi@%=ktaTZ41IcSg6J0akE+Of>|MMZj6l>i?!>>YD1fCp&4D^@v~+GeY&S1EpVgP +zbzz2)WZ^b}yJ4ijrh>X~(8p%Y6azUZxtt`I4DAr&J=AW5%fL9^hUS)nkRRP+8+`^e +zZT0&-J{C3_3cU3NwSjOW^E6P9FK7<9@jf!%F7}99uOCBd_-IK|B+w+_4)NK*2h2l8 +z9#G~Qmuud*WQk`{G2TU$cegGcxLYXi<}Xoqw=7(sCdJy7|3hzX#bSkJ$)KpNBN8s< +z!Lh~g2C>epxpU3k_pZs~zCDLbw{(`6rIahBs7LVs5a*ud#;(c1ii_vzZf}Uj*UgIO +z&(mu$Gn=rw!aL_-y)=S;UO)|I>L$D{O-0V-@we;ulI3nCtHLa8C|#Zj1mHeQ$tsuUaeb!Aupib%jvNehT(J&Q-Cllr!K(@Qq#?Uuq5u +zkSC~z+gm(3)e}prAD#Esdu1nE{gB##0(DZ|f|Hy-xDmK*s{Jy6FZ17Jb-+_D#4jq^9P^koY#e0c_3waOn$B}QrL+0biGu}@m +zGVpTgPUIExCDRP3LCN-D6-#ORtZi!AbpCGnWMJ#xfE{?Pc;9>;?%RMZlbDX&iR)=# +zE0MF(bbVjSetTJmw&u+@PVv`I@tm5uah(JWR2@ipxZ8s3IPjx{mZq=W=h%NkS;v^p +z(Pg_*caLg(^Nm+uJ9QdTbW|V2wG!j87P+OJwW=K*@Xv9DL9-gUh30NWL;7F9^$pOx +zEofTyrSBhC){)jZwtSak_YEuejCtVAH-0VKC3+p>x)$TzFX#t#tRNjL_oM`d(ys;m +zWcb4lL0`Ntb^oZcj+9P&#V&2P?H-5fR4INSB|DNo`9Qy#{Gl}cq;21n{Wq5H$=;h) +zwrkSviFbBP?#%gG=GQ0uZHD&3n{WK?H^2S$8L6H4+piw*x1CKS_FD8SCmTY)FQPFr +z;7zDI54!W9>$1>sTd&%cdcUO8QI`S#bm2#lYxIXOl0`Hnpy>gP91GsZ6&)#eDLYep +z_kreJ&^(6wA!ECGS8A1PkN6{?+kqd6ry&QOYhT*_v1J{O&Kt^hjoCfAVo&PcQ7#xw +z^}2NI1D{ZW2x|K@Wc8!%7TjC>pp%=QIsxMo-4)O|@q_SbqAL^rS3$O0xhu6^>R61b +zn=m%-f-XXIrRjrXTE0uGq7fA`?~r%gM)!ed3FiCb7M@D-gTEGbr1rOfrVBI&F*Zui +ziVm&Qrnvi9))b1g#VCqY?K?Cgx+O?Q>96 +z=(%d(4kRQ$B?a>aJS{>G(Z5|9cUx`UU(bkI2uJEhN@W2dmtxlI +zh*>nx6)hJEyYZPI$AaeBW1yXfxOSXq%Y+|PkRPlhKiHG%8k}Z~{N^a>0s5W7Z<6M5 +z<(@HnM}I9TkktqK6eoH;N43 +z`4S9MWqFLu>19ev>N^|LM3H~fiEh>Nf;M`7f%N{zi2&s;JinoY#|k{<$v=Wu-vq$l +zaPZ_189OBPRe$47&uuA5Hxvc@E7@3=`a5@7b5yoZ&uJ;Czq!v5MHZ7CS9qKJ*nsM1 +zqwI);`M0!)Rp}wcF#HV??;q6VtRKsAo@7kOvQ&rR?@&4Y8QBot`Qqi9mB3FaKa?RF +z`u{!O$saD_IivLNztp_y`yXBOX6Pp*_1zDQcY?^&_deA3J=FI+)b~5o_c|V*B!sH( +zaj5Tad_q%0s?>KmhJYw2J(BT}@~2~g5&M5Sb{?*k5&I8knNJ5FvHz!I=TB;dwlM#< +z#zB1-YB>GW_o0TX|9>7Y3^mf%35{A-i1)la!4_8N$2(AkrDdxM@Ztt5Z1A@hHX5Nu +zR_Jc`huWJ(jxQJT8hVkCzFKH4)Sxct@fpM*?^^Ia736#IZy0Z1u|j;1(2Kf&+Xx%1 +z(9>AMUj(XYbc0uw1V@b#3>xi%L){Y>H30!!9i!P>2NePkECkkuLjN@*L;HH#;;Vh} +z5_zL?b?#8D$>V@3^6$mc-d*w2dnuGuuJh91Kk8hfkXg8)vxwqX=M|NomxSuPqRs_M +zPA=*{z}{W)tMiS@)ww8{Uy5aOaYHsx{ObIp@`LhVL+2y9Rqd+J +z8BfXfyA3E}!+`$kJfiY7l27Tc+EMvR)YDlUTKx)&GOQt_+v +zm&(=oOSP}~RsRjiUxu8LI?t*6s1!{6w8c*5ZvsX(QRmOS@;sz+b#4R+Piov%xgIxG +z{^WDig(QPZ@%$YmlCdF)U!5;hzC#_vi5N-oixOj-aAR#>o!?cSOrNa(mn6Tke~COF +zseHXUh|30(`5#W=PyXJv`o6YgA9yaH%J}=BA@hIlVo{^=YBlhZL5-i{--jD|5lfx_ +z)$gIy)B8%4lz%FIHLfqC&f30u{?R2Tu4|a~m7J4F{EWZ&0&p!Zq{)g<6tA(z +mYru&_^?&kxqQS}c35J!DPi0B!4AEWDP_FoYX9aPe%>VBN4lDuy + +literal 0 +HcmV?d00001 + +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/psu_detect.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/psu_detect.py +new file mode 100755 +index 000000000..a0caf8d12 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/psu_detect.py +@@ -0,0 +1,56 @@ ++import sonic_platform ++import time ++import subprocess ++import os ++ ++class psu_monitor(object): ++ def __init__(self): ++ self.pl = sonic_platform.platform.Platform() ++ self.cha = self.pl.get_chassis() ++ self.pre_sta = [True] * 2 ++ for i in range(0, 2): ++ psu = self.cha.get_psu(i) ++ self.pre_sta[i] = psu.get_presence() ++ if not self.pre_sta[i]: ++ self.remove_device(i) ++ ++ ++ def remove_device(self, index): ++ psu = self.cha.get_psu(index) ++ path="/sys/bus/i2c/devices/i2c-3/delete_device" ++ cmd="echo 0x" + psu.i2c_addr + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+psu.i2c_addr ++ if os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ ++ def probe_device(self, index): ++ psu = self.cha.get_psu(index) ++ path="/sys/bus/i2c/devices/i2c-3/new_device" ++ cmd="echo wistron_psu 0x" + psu.i2c_addr + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+psu.i2c_addr ++ if not os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ ++ def update_psu(self): ++ #fan status detect ++ for i in range(0, 2): ++ psu = self.cha.get_psu(i) ++ pres = psu.get_presence() ++ ++ if pres and not self.pre_sta[i]: ++ self.probe_device(i) ++ elif not pres and self.pre_sta[i]: ++ self.remove_device(i) ++ ++ self.pre_sta[i] = pres ++ ++def main(): ++ monitor = psu_monitor() ++ ++ # Loop forever: ++ while True: ++ time.sleep(1) ++ monitor.update_psu() ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/rst_button.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/rst_button.py +new file mode 100644 +index 000000000..3f47e8776 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/rst_button.py +@@ -0,0 +1,66 @@ ++import subprocess ++import time ++from sonic_py_common import device_info ++ ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++class rst_button_monitor(object): ++ def __init__(self): ++ self.intr_path = "{}/rst_button_10s".format(CPLD_SYSFS_DIR) ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def check_intr(self): ++ val=self.__read_txt_file(self.intr_path) ++ if val is not None: ++ return int(val, 10)==1 ++ else: ++ return True ++ ++ def restore_default(self): ++ version_info = device_info.get_sonic_version_info() ++ subprocess.run(["rm", "/etc/sonic/config_db.json"]) ++ time.sleep(0.5) ++ image_ver=version_info['build_version'] ++ path="/host/image-{}/platform/firsttime".format(image_ver) ++ cmd="touch {}".format(path) ++ subprocess.run(cmd.split()) ++ time.sleep(0.5) ++ subprocess.run(["sync"]) ++ time.sleep(0.5) ++ subprocess.run(["sync"]) ++ time.sleep(0.5) ++ cmd = ["passwd", "admin"] ++ try: ++ p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE) ++ p.stdin.write("YourPaSsWoRd\n".encode('utf-8')) ++ p.stdin.flush() ++ p.stdin.write("YourPaSsWoRd\n".encode('utf-8')) ++ p.stdin.flush() ++ except Exception as e: ++ print("restore_default failed: {}".format(e)) ++ ++def main(): ++ monitor = rst_button_monitor() ++ cont=True ++ ++ # Loop forever: ++ while cont: ++ time.sleep(1) ++ cont=monitor.check_intr() ++ ++ monitor.restore_default() ++ time.sleep(2) ++ ++ subprocess.run(["reboot"]) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sensor_conf.sh b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sensor_conf.sh +new file mode 100755 +index 000000000..15b972eae +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sensor_conf.sh +@@ -0,0 +1,13 @@ ++#!/bin/bash ++ ++direction=$(decode-syseeprom -p) ++dev_path=/usr/share/sonic/device/arm64-wistron_es1227_54ts-r0/ ++ ++if [ $direction == "ES-1227-54TS-O" ]; then ++ cp $dev_path/sensors_afo.conf $dev_path/sensors.conf ++ cp $dev_path/platform_afo.json $dev_path/platform.json ++fi ++if [ $direction == "ES-1227-54TS-I" ]; then ++ cp $dev_path/sensors_afi.conf $dev_path/sensors.conf ++ cp $dev_path/platform_afi.json $dev_path/platform.json ++fi +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sysled_health.py b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sysled_health.py +new file mode 100755 +index 000000000..b303dbcff +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/sysled_health.py +@@ -0,0 +1,14 @@ ++import sonic_platform ++import time ++ ++def main(): ++ ++ pl=sonic_platform.platform.Platform() ++ cha=pl.get_chassis() ++ # Loop forever: ++ while True: ++ time.sleep(5) ++ cha.set_status_led("green") ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/updateCPLD b/platform/marvell-prestera/sonic-platform-wistron/es1227_54ts/utils/updateCPLD +new file mode 100755 +index 0000000000000000000000000000000000000000..5d9f81e6a5bb85f10d06a363a220717c4f1f3c64 +GIT binary patch +literal 23328 +zcmeHv3wRvWmFBH3y&tw7wq?fzm5_~vL$~AywqzT-CE?e^!9q5K4cTqAx=T_It!~i| +zBgLMLFqsJfl5ww{fy{z&F#9DYGhfI|c4E(vARgJU!_E#Ngk^VuZHbx0vq?4vzJL{M +zdjE6lp6=@E?%>QOn{U34D^;C)&OPVcd(ORe>(=R8_37<dkF|bo^z0RDGmH%B1rkkc8LOdWrpD+7FjT4xf>uy?Yz{~pcn^LeWm=e +zRJEU>GFNnlL&KfnpgSCjBq!Z|e=IPzVZA3F^{lb%CjG>_^ZFZQP1N6&GH0C{0hZxt +zQM5&XbvPC(oaC!jo|>>22l=)MM-7f8IO=f}OH?n_N8_ZJPuOSNo?4rd1;{VO(X43H +zPD<1UqLXf^({hCL4$*twyyr52lIbRtP}`lU4TNHJYEv=#-V$_bZ!!LVQ-V(ZF2+xN +zQjGrD67*dq=ybUh(=$+lehPF0hcjIRLNPrZCFs*7=$lK>zf^)gRe~NXL8q}>tet%& +z=;0D{6ZA%mv}e0|k+a6U%;0(p(Dk)J#3y2*NMb~cL?_IMh$mu^!1#oiFk`W3OiUyb +zaS=29;czq{{KL^$f;bYEPXwVwgrb2&SR~_N +z)0_|^x5q*W$w{^NeAEtKJmHTeeB=I5M2y5tQ|#QcyRYB3*0W|KI7Y{#5yjy{(_JP0 +zN|i`!ah=hh5Ij%am--W2b}n(;Di-NZ%Rd?}X8SzAexu2kuFGsv{&ay(dO20u=<;G# +z1r0Vj%_W?c+UPuwP?=$)+wV^uHoAQ->ax*!9wI&6Hag!+i0-w~d0r&?E*qWZMNR`Y +zx_y4T*+!=^%W23)xBGLj8|Jp93|H$*t%m+XK2Ub9(dC_Qa0yu^@e1Hq*zg+QeKvdn@L?O?1pKfK +zUjqDL8~!2SPucLxfzR3SD}cMST>V!9zru#E2Ht1GJ-~-;_*&qHZTJS@58Lofz@M_= +zTY=Bn@IK%!SFZjYz^}03zX!a}hF=eS*oF@RKWxKq0{*ZK{{---Ed0Y_`i0AJ{G%=& +zoz=bbbL}GaBlMpT=@*2Uc~exKcvJkB!*A-qb>KR1{nb0)ECXH!ybO5R&+dHlFEW|? +zzKdfTeJjrGoc9Xx&2MKiE!6+ix1gUBhMu|uunlmV5I;GAt_4lCe +zYtm?&A*Kh1`t+W+YQ6Ip4?ZQw=8w?Eiw7T&EiaEn>d5D^P==gk-9>g +zenErmA3#TXoA->E`0ze)$a{2lp?BU8;vUQ{^XV2bPrQBL1Mdr8AYSN6Z}y(iE)z{@ +z)CpUA2x4wcrBRR6RVEtKsEhKgTf}XjzmVBa{kR5ZVYc@UoLb}y^<}mRJaogX*=a7FMvv}$%(7g52P4FY8g6To_$;E?b +zEPs%msOXt%fj^!QJ(-UH-ijlN_O^J>_{qj7+Wo-7+rpJ%fBI>WIt<&%S8J&(pru?c +z3-=KIx=6XoEPOTL+H@0SdNSX`@f?o7hkv5p9M9dk6kl`poT?mS-%X{jH*XZd0e^*L-3 +z)GuV`6KKz6qM7(_J)fb+kwxTl_JKiml<>hD&}sL<&j`2q;Gcj`SE7x-2_Kxad@y~9 +zK6npx=lMXmQvU%o8V|VN<@?|x@Q0{tB7VQk2Lg3nJor5|PHkgmxi}-oOlNMayhOIM +zpDOal%2!JHVL9skRbzq6?PK9De?31u?)1Y6S1M4-51r(P2I+^P`P^8@_rqW3t{wOx +zvkGGfeZ$v9m~B0Y@%|MYU&HZrjC-~vfN?*HF--m0s>c1Tz`6WRHSRwP+EMVVQatwn +zf7-I$OJm>`)Z3pw?(fLA^)WoYjoN-qo+^&?{byaL +zU)FGq$^NwLH55Lp8>@%JkwM(IYUp|%viV^q&ky<6a|YKkjV~U@e~o(6l||-n9;c<| +zZ!Z6TxMu$zb=&5y$AnRqI-vZ3weF%cuG91rS`R^SsA^yOZ#dtuFa0g#pXlwG{hQvN +zxo`FMyso=e&*|FgSzWA__tojL)YqXa|C)CAg6<18U)&DfHXQ+;@9li&AJG+ib--&xYY(RaFrm<$J0k2#mHPiaV+e7__HQatGW880z#imBI +zd$t8@s=eO7*oJlD=P-7sY0ZLlBdxVwht7xf=@;6t){t!(sz_~uenVJm8LUmPzI$5D +zSEbvu@)Fu~N3puGhRN2Qu1GD19*mbJIrdO@Yn6E8^JE+4U(w$9d=VW_mD_YoSEk56 +z#oC|ItG|Eopvc`*u&$%J(%W2TGMjO1#L=S7r}e5->xK2FEO?EA8x-8AV7G!j3T{$x +zvx4hRWm=(cx$6wAQ)XMIU%<8TD6Qwda{>K_b!2Ouxb0rpHjREyqyCpPj4@i%8uZNI +zo&Pkghgu-t(szdX_-^t8<`v?7j(NQn@0W?N>Uxap8lrJXV+=Z`Nr&svlaS-_H;cMS{u#`zCn3Z53~*}m +z>}IQeaiS`9is}O{WxHS(*=^UKw)FdmuM&My**g#3H|~HBPAGrfjXKcJgK79V-3r~| +z%jC1fO(aA8*rH^rp$~2K1%JPa;#UI +z3<~oC5>2ZT`(JM_PtB?8MKh|UFME|AsC}|c=ywmz8LBRSIog0WQoZ#qE6?qf*EQO@ +zh1#vt_{-VK?cPi62A%B6v{&}bzFvm4e0k~-k|Ep6#0^<}&~*i#rD*($&%{r8%fu<- +zbv0Pe3zw4&1_8du8@smw{aR>B?-~?-Je*Ts_OY1AKY``V=+_4RBQ@o|P(l((OBY +zviFsAb!r*ahw&!Yv?ukc%vba&swe$(F+W6O;%mU6H~p@9mU&mheWo%ceZ8&k%v~gp +zG09`_$;;3uq!0c4ur=4Nrm=hkd_0anNpqY{#=l%X|6%P{n|hV(K>d7A|E|N%CmnWv +z8~6;_2Ro;!y~@r^Cu}WYm*jgNy9OP0-LWKRm+P1E9wP1fgw3ui9d@-XhK$XYf9J5} +z3l3ZECR?g3TQa{PI}C>%Pc|rDpQue8rus3))6KXRFlTR~>kRkE!|M5X#L?bi;DW}~ +zop?U@ERK6bk3l~FV>~M~_acViJvG-XQr@D_is_X_VH0mzK4Fy +z(bQHRU-o`D4;da`&p2%UGR<2X<+a_IhMjz!&w{p1h+F9y+TKqc4!c(nj%$FgEd%&W +z?Qgc9{)+0b+1y)3He1(`Ygul*eFuCJM;TpLJEg7Gd@+mp(3(f;Qnlbi07b?HXdO=R +zfd&N;^OZPa#S$XMEFnFQ5FcXN5+W8Zp-Vx&4-C=$6XWK+U!u)u1Lop2l7{>&(dd43 +zOk4A1;-mW!?sajrhwA5f;sn+o+54DLpLz#!cKj^|{&S`G;z92ztUpo|lj9iKTl=(A +z$1r~$dun6q7q_@heG&Qp`0&QmG1ubf-p1PUoq&Go9jqD7<34-rz5b(zpevz?Z#LuJ +zL-wBhRQ&v$zVy*}1=bgO%cE(137$u`z4VZ)`6q3e%>K9b^`830Eq$ln3G|=h7#PV} +zZLng?_PDYp;ISg9=Ek^x)ZApOj2m10vC-tX8A)udsWFT#!^!wo(1O9(R>OUhvB?0@ +zFoL1@MA$!N1d_2BSdAT>A2$w|v3MvN@f3({83~0=U&KFdZe{tAP;C5mf6O$J6QePI +z(DWGFZ+%YPQ+R`^Q2P28{(X9yda91FkmwMkF~tY{p9R*_9a` +zsC%8eYjWept4N?TXddW9f4Wx&W&7PXNr0ae6UMd1${^KEDP{rr&`H@nT{6L6JdlF^ +zgx?59F_wamGq6#>jC-sEB{kb42{UH&MbGvF*dH>)aMV} +zIvR^6Bf%P@f5WD|J9dzcoC?{3ntk+BB)smAha#g!|BjvHr~ZLG*C|HTPQ^D7i(+_> +zkC)`Fxp4vwH;s5Q5P(ldlHu@_#~28k{K^DN*wzzcwsFb~V5eQHpYOwQOEyIys|L)45a@8jemi>vo{XWFb{ckV-@TDKTNP;w0ZidWHA!F}z68|85;DHZ3 +z@PP+D@W2Ni_`n0dIS3eu8+5<@)S%hXWqm5}#0X(`-V&K; +zX+R0T)yQ;CmDBoz5|{IRe$wS7viQY&*nxo5p?e7k-ZS^ratr6Zas#TIpF2)VZbbhS +zT&mz=1sU+3y|ZecAT9AIb*K!jJ1OzrJKh6!w!)i7Kdo@KL#|`NQ7yT0dko*pSoYkn +z_%jM;|6&;>?Hy9(O8mD5cz^o)RnVpS`(GM#+O@O4f0NOH-R8#rXfzxc!`4(|BpNdk +zV|Z+H5Ady6*quaC2y|!yjkEd&$(czDcyJKe94dRBYuA(xJ>}q

yNKTzW$19v!1zJ;z(BC +z*~`7i3-K9wE<9}k$t7Yi$VMXsP}e)-P7SN2JW=ISOZGhxwu4G&Za9QPo2J^z +zXmb|0zl3w$H*h^r@h5P&?#4-LsYNJRRO{2KV!f;!yPHMXI#9*sI9y^k&Q;nSL_pf7 +zR9H2<2CPin0(zBJ3#;n>TopSVaS<%8s`40$^)KM$dbwpgNM-9Kz4A1X$|}E2psIYF +zKttI}P*@%Y105BjvWlV}RkRhpTAsc@IXa0NtJRfN$ADB;{VC2at?DOGQ+p04tz)4d +zq}n+s)K**hgG9gD%D+u?kIa|90!BKhzB$0U+CL@Eu7%$x4gZ7kYh=FuZz=E7#+2vE +zP)VjpqcI^ +zTBC+sEm0aUx4YI0eZi*M&9yzXyPLNybK$n3uMoAhTWfWU^s+0(ZVJRmMK@LySAz;F +zr79)204kQ)v}VQH#Jp~NE3>y*g>ke +z`E!RgFd*P`_hH1Tm!|sQw#6WdMr{pbmQdriEQ>7Q1{QT81rT+y2In&E-39eRLn21} +zdpw;8q6N)~c&B=U2mxh^=Xv&73zKRW&$s#-t*yPitzBPYeDtF?w7c+jfYvTGf4G=t +z5sHKoo&bsv4#T0#K*c3BAP`H0a`p4Prf=2S+S;y=^@?g2Pt*F}2`xwE$y)!Ppi0*3 +zVWuvgMGFe*?o5nNbOuLYbCJ?e1YQk?Whj3%5MXE91vz~JO!xin#L` +z7QW-@S1VfKsO;oH`CI6-cr4I4N-x!P2I5J2UC!v;XRP(CTZ{FFZ}(pOv=9tM=%h?(uLakqDb^`~nm5M}Yf>L)V5UHmoY6ltxD+5eHR9+YuXwuEZE|0l4u>P$UW@5`{v<E{d7`_%&qrE({#eXEWxYZq +z;-OEOzJxF%2k7mi5tQc@+eWI?l8nSdqY?b%V5yUDE5Wf+Fkc>S!>>gC7^o95v!Gu5 +z=oa{0dwgJb|F7$Jcnbz)%_g%1OgSK=cY@L6aF`hKEhbmwxt<8c`;0E8{Ipr2ni$~h +zM3ywdSzdyaiMOUPUE>XxtZ}eV<5)3`g9REjYI-ZUAIX<7iT5vodpI#$4Zjeu}73}|fdY$M}{>-P>XP>9? +z=?et+TRwfE;K!zXdPDZT@qButFjjc&B$?Oo<|@Z^?1egho#c2*-@Soao5dN%r$U#QDxgnSxdy8Lyl7@gLVg-Mss +zAjRmdg+x$vVHD7@4#acn8yRQ8A4)>u_@{@WV*J&lNED8f(|9r}#&78_94B?qQ;eUU +z)QZu$UY=iMvvK-7_+4lZ(-)}%i@$LETlB*5OwYKb>#Y?$4{^P$hvy@v*Ol-Cx4%Qp +zi_G5wermsyzD&_?cJN#NY!Ne#aeKAmKjPr;16{+L$j>W&m?@K`r||l^LGl;UCzXDV +z<8u2gJ%!irXQZA&I**6D9P_tDZxrht^MggtwV&%f3H_z}t6n_g@B`O-e~EhUchpNS +zNB%1P`~<@7;r4s4^fF1pQsaU7?{e@zA^p}UoODuFtUZ4RetPrYIZwVO^%TyNKUVzC +z`SzERUN~>pV@08f!gm;4pnxA%-pdTy~!ob%#ob&T1z~5l| +zJ^^bRE1~C*q}Pj=o4k^h<{e7+D*B1VUWw1hvk=EYFZTU|{|q|S`?BM@`-Y^qWWSf7 +z)QHncf7L>-Bw5i)A>2fF70y4;meBvA)WceH@W&v&IJdq8eXs=GEJ2?Fy`f0|{*mOb7x$`m?ot*1utYnLg5TiA+2F%U&p$MKB~|WG +zLGCX>Z*&#TpEHX8oD3~uFO-x*6j0I?Vgs*|9(*l^*FQjI`l-^>;L!6<2|ZQi)Gvi; +zxun+%o@e-J<0B>b|2wYVV&ijb3I0#3c5-}+Td)`W#q@k!(VumU|A5qAFNT(Qr3$%M +z2e~mtf45?_?^f}g}`kiCB#}vIzU8l#C)X5Th{t9&JUuQc*CC1N6(&H*z +zCp=X`|BI5IyT3f3+Vj6k@QdF<$VSHGiiFvs!@r*k<#Zw%5NV!IurbBStkO6Zu%9>_OqDV3PKh!bvP91M1Vj=ZEb->8Och*V0jZ#gy}BXn-;DVZ<34;02b)t70trTa +zqv7bVKkN%4ycPHPlanG49iIrB*rn^~UbAsSaVC3Q3cIgkQ}`?nc31m?$?@?ih}bZD +zgv(-0${nY)WtBEkqj9#Fme03iu=iuzecP|U&gUzP(fF?WSJ(G`Y;sqZc2(J+``2L~~!;cAyW +zOv(E~l5+<+%7gK!Z_FPFB2<^#$8LSiDZh^V_;7A7y!;GQ9xLoDVJ1aKWthwJ7X3ZH?p>Q?*e)kmZ9B;{a8(n}2pMMiH;PDp=XZ@c=?R35X>xBp}P +zYS7E?R^^pq^6@3$A#>9DR8?M~@WiLa6aHa9eD_MiG0q_-Y{n*pM^4MVeY@QW|ETaF +zGVU4k$H#;xI2D1g1rsr=ga@x=Q-}{`2yOdGK;>(I|A`ChhI2Lp9@p6N>kqQ;Gc~wha@fe<>L(?$N#z&fy(VkJsxC9?Z{Q) +zVEO$nFEG3;qzHz@awlE~GUXa%ur$cZb3Borrzt&Vf$aXHDuuHi`rYzv?A_t|J9Mw) +z=)ii0(h3U{$Sbm-aC0pVmgo57fRevi70?gyWINZt6nRShIEaMekSghLU%-Uy;QqGUQ8^=lJPq +zCEukOl{p3W-=^gI6d%V~&nkJ|&qeY}a5(*U5H#|MV$a578>&G>;&_#XS#9M!!2>w# +z@*KDAQu0R}4sTGx4DWEr^Ll?qZD{*5M+3P1N{ygR8ut1*4jfjYN3MtYdE7FN_xPne +z`=6herj0Fr~*?|DS`7ofh&M +zAQq0B@b^lc{ERa^0~z{09h=E8yC|Ts!}1*W=I_C#RsZw&Vma=Y +z{|Z@RVR?>^zuXBT67yMDVf{ZqfnA>C=x3Gu^DL+!*U#`3hdjq~PIp-XrRrz3bI6b` +zZa+WQJ$s4rKZY!|U$G-+C6>RD2?{EAN*N-Z!@)GgB7s2@Gg5=2&}k0^+#M`Zu1igP +z#~kC&$y*D8lST@jSufRyvv)~l~12}lx^8JsdS%-;I +fApLt1h&TAgVWC<36^a;9ary64Wk|c<$Nv8dA~k3V + +literal 0 +HcmV?d00001 + +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/Makefile b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/Makefile +new file mode 100755 +index 000000000..70f03cb6c +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/Makefile +@@ -0,0 +1,17 @@ ++ifneq ($(KERNELRELEASE),) ++obj-m:= wistron_cpld.o wistron_max31790.o wistron_psu.o ++else ++ifeq (,$(KERNEL_SRC)) ++#$(error KERNEL_SRC is not defined) ++KVERSION=3.16.0-8-amd64 ++KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/ ++KERNELDIR:=$(KERNEL_DIR) ++else ++KERNELDIR:=$(KERNEL_SRC) ++endif ++PWD:=$(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++clean: ++ rm -rf *.o *.mod.o *.mod.o *.ko .*cmd *.mod.c .tmp_versions Module.markers Module.symvers modules.order *.mod ++endif +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/pmbus.h b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/pmbus.h +new file mode 100644 +index 000000000..10fb17879 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/pmbus.h +@@ -0,0 +1,511 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * pmbus.h - Common defines and structures for PMBus devices ++ * ++ * Copyright (c) 2010, 2011 Ericsson AB. ++ * Copyright (c) 2012 Guenter Roeck ++ */ ++ ++#ifndef PMBUS_H ++#define PMBUS_H ++ ++#include ++#include ++ ++/* ++ * Registers ++ */ ++enum pmbus_regs { ++ PMBUS_PAGE = 0x00, ++ PMBUS_OPERATION = 0x01, ++ PMBUS_ON_OFF_CONFIG = 0x02, ++ PMBUS_CLEAR_FAULTS = 0x03, ++ PMBUS_PHASE = 0x04, ++ ++ PMBUS_WRITE_PROTECT = 0x10, ++ ++ PMBUS_CAPABILITY = 0x19, ++ PMBUS_QUERY = 0x1A, ++ ++ PMBUS_VOUT_MODE = 0x20, ++ PMBUS_VOUT_COMMAND = 0x21, ++ PMBUS_VOUT_TRIM = 0x22, ++ PMBUS_VOUT_CAL_OFFSET = 0x23, ++ PMBUS_VOUT_MAX = 0x24, ++ PMBUS_VOUT_MARGIN_HIGH = 0x25, ++ PMBUS_VOUT_MARGIN_LOW = 0x26, ++ PMBUS_VOUT_TRANSITION_RATE = 0x27, ++ PMBUS_VOUT_DROOP = 0x28, ++ PMBUS_VOUT_SCALE_LOOP = 0x29, ++ PMBUS_VOUT_SCALE_MONITOR = 0x2A, ++ ++ PMBUS_COEFFICIENTS = 0x30, ++ PMBUS_POUT_MAX = 0x31, ++ ++ PMBUS_FAN_CONFIG_12 = 0x3A, ++ PMBUS_FAN_COMMAND_1 = 0x3B, ++ PMBUS_FAN_COMMAND_2 = 0x3C, ++ PMBUS_FAN_CONFIG_34 = 0x3D, ++ PMBUS_FAN_COMMAND_3 = 0x3E, ++ PMBUS_FAN_COMMAND_4 = 0x3F, ++ ++ PMBUS_VOUT_OV_FAULT_LIMIT = 0x40, ++ PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41, ++ PMBUS_VOUT_OV_WARN_LIMIT = 0x42, ++ PMBUS_VOUT_UV_WARN_LIMIT = 0x43, ++ PMBUS_VOUT_UV_FAULT_LIMIT = 0x44, ++ PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45, ++ PMBUS_IOUT_OC_FAULT_LIMIT = 0x46, ++ PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47, ++ PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48, ++ PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49, ++ PMBUS_IOUT_OC_WARN_LIMIT = 0x4A, ++ PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B, ++ PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C, ++ ++ PMBUS_OT_FAULT_LIMIT = 0x4F, ++ PMBUS_OT_FAULT_RESPONSE = 0x50, ++ PMBUS_OT_WARN_LIMIT = 0x51, ++ PMBUS_UT_WARN_LIMIT = 0x52, ++ PMBUS_UT_FAULT_LIMIT = 0x53, ++ PMBUS_UT_FAULT_RESPONSE = 0x54, ++ PMBUS_VIN_OV_FAULT_LIMIT = 0x55, ++ PMBUS_VIN_OV_FAULT_RESPONSE = 0x56, ++ PMBUS_VIN_OV_WARN_LIMIT = 0x57, ++ PMBUS_VIN_UV_WARN_LIMIT = 0x58, ++ PMBUS_VIN_UV_FAULT_LIMIT = 0x59, ++ ++ PMBUS_IIN_OC_FAULT_LIMIT = 0x5B, ++ PMBUS_IIN_OC_WARN_LIMIT = 0x5D, ++ ++ PMBUS_POUT_OP_FAULT_LIMIT = 0x68, ++ PMBUS_POUT_OP_WARN_LIMIT = 0x6A, ++ PMBUS_PIN_OP_WARN_LIMIT = 0x6B, ++ ++ PMBUS_STATUS_BYTE = 0x78, ++ PMBUS_STATUS_WORD = 0x79, ++ PMBUS_STATUS_VOUT = 0x7A, ++ PMBUS_STATUS_IOUT = 0x7B, ++ PMBUS_STATUS_INPUT = 0x7C, ++ PMBUS_STATUS_TEMPERATURE = 0x7D, ++ PMBUS_STATUS_CML = 0x7E, ++ PMBUS_STATUS_OTHER = 0x7F, ++ PMBUS_STATUS_MFR_SPECIFIC = 0x80, ++ PMBUS_STATUS_FAN_12 = 0x81, ++ PMBUS_STATUS_FAN_34 = 0x82, ++ ++ PMBUS_READ_VIN = 0x88, ++ PMBUS_READ_IIN = 0x89, ++ PMBUS_READ_VCAP = 0x8A, ++ PMBUS_READ_VOUT = 0x8B, ++ PMBUS_READ_IOUT = 0x8C, ++ PMBUS_READ_TEMPERATURE_1 = 0x8D, ++ PMBUS_READ_TEMPERATURE_2 = 0x8E, ++ PMBUS_READ_TEMPERATURE_3 = 0x8F, ++ PMBUS_READ_FAN_SPEED_1 = 0x90, ++ PMBUS_READ_FAN_SPEED_2 = 0x91, ++ PMBUS_READ_FAN_SPEED_3 = 0x92, ++ PMBUS_READ_FAN_SPEED_4 = 0x93, ++ PMBUS_READ_DUTY_CYCLE = 0x94, ++ PMBUS_READ_FREQUENCY = 0x95, ++ PMBUS_READ_POUT = 0x96, ++ PMBUS_READ_PIN = 0x97, ++ ++ PMBUS_REVISION = 0x98, ++ PMBUS_MFR_ID = 0x99, ++ PMBUS_MFR_MODEL = 0x9A, ++ PMBUS_MFR_REVISION = 0x9B, ++ PMBUS_MFR_LOCATION = 0x9C, ++ PMBUS_MFR_DATE = 0x9D, ++ PMBUS_MFR_SERIAL = 0x9E, ++ ++ PMBUS_MFR_VIN_MIN = 0xA0, ++ PMBUS_MFR_VIN_MAX = 0xA1, ++ PMBUS_MFR_IIN_MAX = 0xA2, ++ PMBUS_MFR_PIN_MAX = 0xA3, ++ PMBUS_MFR_VOUT_MIN = 0xA4, ++ PMBUS_MFR_VOUT_MAX = 0xA5, ++ PMBUS_MFR_IOUT_MAX = 0xA6, ++ PMBUS_MFR_POUT_MAX = 0xA7, ++ ++ PMBUS_IC_DEVICE_ID = 0xAD, ++ PMBUS_IC_DEVICE_REV = 0xAE, ++ ++ PMBUS_MFR_MAX_TEMP_1 = 0xC0, ++ PMBUS_MFR_MAX_TEMP_2 = 0xC1, ++ PMBUS_MFR_MAX_TEMP_3 = 0xC2, ++ ++/* ++ * Virtual registers. ++ * Useful to support attributes which are not supported by standard PMBus ++ * registers but exist as manufacturer specific registers on individual chips. ++ * Must be mapped to real registers in device specific code. ++ * ++ * Semantics: ++ * Virtual registers are all word size. ++ * READ registers are read-only; writes are either ignored or return an error. ++ * RESET registers are read/write. Reading reset registers returns zero ++ * (used for detection), writing any value causes the associated history to be ++ * reset. ++ * Virtual registers have to be handled in device specific driver code. Chip ++ * driver code returns non-negative register values if a virtual register is ++ * supported, or a negative error code if not. The chip driver may return ++ * -ENODATA or any other error code in this case, though an error code other ++ * than -ENODATA is handled more efficiently and thus preferred. Either case, ++ * the calling PMBus core code will abort if the chip driver returns an error ++ * code when reading or writing virtual registers. ++ */ ++ PMBUS_VIRT_BASE = 0x100, ++ PMBUS_VIRT_READ_TEMP_AVG, ++ PMBUS_VIRT_READ_TEMP_MIN, ++ PMBUS_VIRT_READ_TEMP_MAX, ++ PMBUS_VIRT_RESET_TEMP_HISTORY, ++ PMBUS_VIRT_READ_VIN_AVG, ++ PMBUS_VIRT_READ_VIN_MIN, ++ PMBUS_VIRT_READ_VIN_MAX, ++ PMBUS_VIRT_RESET_VIN_HISTORY, ++ PMBUS_VIRT_READ_IIN_AVG, ++ PMBUS_VIRT_READ_IIN_MIN, ++ PMBUS_VIRT_READ_IIN_MAX, ++ PMBUS_VIRT_RESET_IIN_HISTORY, ++ PMBUS_VIRT_READ_PIN_AVG, ++ PMBUS_VIRT_READ_PIN_MIN, ++ PMBUS_VIRT_READ_PIN_MAX, ++ PMBUS_VIRT_RESET_PIN_HISTORY, ++ PMBUS_VIRT_READ_POUT_AVG, ++ PMBUS_VIRT_READ_POUT_MIN, ++ PMBUS_VIRT_READ_POUT_MAX, ++ PMBUS_VIRT_RESET_POUT_HISTORY, ++ PMBUS_VIRT_READ_VOUT_AVG, ++ PMBUS_VIRT_READ_VOUT_MIN, ++ PMBUS_VIRT_READ_VOUT_MAX, ++ PMBUS_VIRT_RESET_VOUT_HISTORY, ++ PMBUS_VIRT_READ_IOUT_AVG, ++ PMBUS_VIRT_READ_IOUT_MIN, ++ PMBUS_VIRT_READ_IOUT_MAX, ++ PMBUS_VIRT_RESET_IOUT_HISTORY, ++ PMBUS_VIRT_READ_TEMP2_AVG, ++ PMBUS_VIRT_READ_TEMP2_MIN, ++ PMBUS_VIRT_READ_TEMP2_MAX, ++ PMBUS_VIRT_RESET_TEMP2_HISTORY, ++ ++ PMBUS_VIRT_READ_VMON, ++ PMBUS_VIRT_VMON_UV_WARN_LIMIT, ++ PMBUS_VIRT_VMON_OV_WARN_LIMIT, ++ PMBUS_VIRT_VMON_UV_FAULT_LIMIT, ++ PMBUS_VIRT_VMON_OV_FAULT_LIMIT, ++ PMBUS_VIRT_STATUS_VMON, ++ ++ /* ++ * RPM and PWM Fan control ++ * ++ * Drivers wanting to expose PWM control must define the behaviour of ++ * PMBUS_VIRT_PWM_[1-4] and PMBUS_VIRT_PWM_ENABLE_[1-4] in the ++ * {read,write}_word_data callback. ++ * ++ * pmbus core provides a default implementation for ++ * PMBUS_VIRT_FAN_TARGET_[1-4]. ++ * ++ * TARGET, PWM and PWM_ENABLE members must be defined sequentially; ++ * pmbus core uses the difference between the provided register and ++ * it's _1 counterpart to calculate the FAN/PWM ID. ++ */ ++ PMBUS_VIRT_FAN_TARGET_1, ++ PMBUS_VIRT_FAN_TARGET_2, ++ PMBUS_VIRT_FAN_TARGET_3, ++ PMBUS_VIRT_FAN_TARGET_4, ++ PMBUS_VIRT_PWM_1, ++ PMBUS_VIRT_PWM_2, ++ PMBUS_VIRT_PWM_3, ++ PMBUS_VIRT_PWM_4, ++ PMBUS_VIRT_PWM_ENABLE_1, ++ PMBUS_VIRT_PWM_ENABLE_2, ++ PMBUS_VIRT_PWM_ENABLE_3, ++ PMBUS_VIRT_PWM_ENABLE_4, ++ ++ /* Samples for average ++ * ++ * Drivers wanting to expose functionality for changing the number of ++ * samples used for average values should implement support in ++ * {read,write}_word_data callback for either PMBUS_VIRT_SAMPLES if it ++ * applies to all types of measurements, or any number of specific ++ * PMBUS_VIRT_*_SAMPLES registers to allow for individual control. ++ */ ++ PMBUS_VIRT_SAMPLES, ++ PMBUS_VIRT_IN_SAMPLES, ++ PMBUS_VIRT_CURR_SAMPLES, ++ PMBUS_VIRT_POWER_SAMPLES, ++ PMBUS_VIRT_TEMP_SAMPLES, ++}; ++ ++/* ++ * OPERATION ++ */ ++#define PB_OPERATION_CONTROL_ON BIT(7) ++ ++/* ++ * WRITE_PROTECT ++ */ ++#define PB_WP_ALL BIT(7) /* all but WRITE_PROTECT */ ++#define PB_WP_OP BIT(6) /* all but WP, OPERATION, PAGE */ ++#define PB_WP_VOUT BIT(5) /* all but WP, OPERATION, PAGE, VOUT, ON_OFF */ ++ ++#define PB_WP_ANY (PB_WP_ALL | PB_WP_OP | PB_WP_VOUT) ++ ++/* ++ * CAPABILITY ++ */ ++#define PB_CAPABILITY_SMBALERT BIT(4) ++#define PB_CAPABILITY_ERROR_CHECK BIT(7) ++ ++/* ++ * VOUT_MODE ++ */ ++#define PB_VOUT_MODE_MODE_MASK 0xe0 ++#define PB_VOUT_MODE_PARAM_MASK 0x1f ++ ++#define PB_VOUT_MODE_LINEAR 0x00 ++#define PB_VOUT_MODE_VID 0x20 ++#define PB_VOUT_MODE_DIRECT 0x40 ++ ++/* ++ * Fan configuration ++ */ ++#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1)) ++#define PB_FAN_2_RPM BIT(2) ++#define PB_FAN_2_INSTALLED BIT(3) ++#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5)) ++#define PB_FAN_1_RPM BIT(6) ++#define PB_FAN_1_INSTALLED BIT(7) ++ ++enum pmbus_fan_mode { percent = 0, rpm }; ++ ++/* ++ * STATUS_BYTE, STATUS_WORD (lower) ++ */ ++#define PB_STATUS_NONE_ABOVE BIT(0) ++#define PB_STATUS_CML BIT(1) ++#define PB_STATUS_TEMPERATURE BIT(2) ++#define PB_STATUS_VIN_UV BIT(3) ++#define PB_STATUS_IOUT_OC BIT(4) ++#define PB_STATUS_VOUT_OV BIT(5) ++#define PB_STATUS_OFF BIT(6) ++#define PB_STATUS_BUSY BIT(7) ++ ++/* ++ * STATUS_WORD (upper) ++ */ ++#define PB_STATUS_UNKNOWN BIT(8) ++#define PB_STATUS_OTHER BIT(9) ++#define PB_STATUS_FANS BIT(10) ++#define PB_STATUS_POWER_GOOD_N BIT(11) ++#define PB_STATUS_WORD_MFR BIT(12) ++#define PB_STATUS_INPUT BIT(13) ++#define PB_STATUS_IOUT_POUT BIT(14) ++#define PB_STATUS_VOUT BIT(15) ++ ++/* ++ * STATUS_IOUT ++ */ ++#define PB_POUT_OP_WARNING BIT(0) ++#define PB_POUT_OP_FAULT BIT(1) ++#define PB_POWER_LIMITING BIT(2) ++#define PB_CURRENT_SHARE_FAULT BIT(3) ++#define PB_IOUT_UC_FAULT BIT(4) ++#define PB_IOUT_OC_WARNING BIT(5) ++#define PB_IOUT_OC_LV_FAULT BIT(6) ++#define PB_IOUT_OC_FAULT BIT(7) ++ ++/* ++ * STATUS_VOUT, STATUS_INPUT ++ */ ++#define PB_VOLTAGE_VIN_OFF BIT(3) ++#define PB_VOLTAGE_UV_FAULT BIT(4) ++#define PB_VOLTAGE_UV_WARNING BIT(5) ++#define PB_VOLTAGE_OV_WARNING BIT(6) ++#define PB_VOLTAGE_OV_FAULT BIT(7) ++ ++/* ++ * STATUS_INPUT ++ */ ++#define PB_PIN_OP_WARNING BIT(0) ++#define PB_IIN_OC_WARNING BIT(1) ++#define PB_IIN_OC_FAULT BIT(2) ++ ++/* ++ * STATUS_TEMPERATURE ++ */ ++#define PB_TEMP_UT_FAULT BIT(4) ++#define PB_TEMP_UT_WARNING BIT(5) ++#define PB_TEMP_OT_WARNING BIT(6) ++#define PB_TEMP_OT_FAULT BIT(7) ++ ++/* ++ * STATUS_FAN ++ */ ++#define PB_FAN_AIRFLOW_WARNING BIT(0) ++#define PB_FAN_AIRFLOW_FAULT BIT(1) ++#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2) ++#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3) ++#define PB_FAN_FAN2_WARNING BIT(4) ++#define PB_FAN_FAN1_WARNING BIT(5) ++#define PB_FAN_FAN2_FAULT BIT(6) ++#define PB_FAN_FAN1_FAULT BIT(7) ++ ++/* ++ * CML_FAULT_STATUS ++ */ ++#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0) ++#define PB_CML_FAULT_OTHER_COMM BIT(1) ++#define PB_CML_FAULT_PROCESSOR BIT(3) ++#define PB_CML_FAULT_MEMORY BIT(4) ++#define PB_CML_FAULT_PACKET_ERROR BIT(5) ++#define PB_CML_FAULT_INVALID_DATA BIT(6) ++#define PB_CML_FAULT_INVALID_COMMAND BIT(7) ++ ++enum pmbus_sensor_classes { ++ PSC_VOLTAGE_IN = 0, ++ PSC_VOLTAGE_OUT, ++ PSC_CURRENT_IN, ++ PSC_CURRENT_OUT, ++ PSC_POWER, ++ PSC_TEMPERATURE, ++ PSC_FAN, ++ PSC_PWM, ++ PSC_NUM_CLASSES /* Number of power sensor classes */ ++}; ++ ++#define PMBUS_PAGES 32 /* Per PMBus specification */ ++#define PMBUS_PHASES 10 /* Maximum number of phases per page */ ++ ++/* Functionality bit mask */ ++#define PMBUS_HAVE_VIN BIT(0) ++#define PMBUS_HAVE_VCAP BIT(1) ++#define PMBUS_HAVE_VOUT BIT(2) ++#define PMBUS_HAVE_IIN BIT(3) ++#define PMBUS_HAVE_IOUT BIT(4) ++#define PMBUS_HAVE_PIN BIT(5) ++#define PMBUS_HAVE_POUT BIT(6) ++#define PMBUS_HAVE_FAN12 BIT(7) ++#define PMBUS_HAVE_FAN34 BIT(8) ++#define PMBUS_HAVE_TEMP BIT(9) ++#define PMBUS_HAVE_TEMP2 BIT(10) ++#define PMBUS_HAVE_TEMP3 BIT(11) ++#define PMBUS_HAVE_STATUS_VOUT BIT(12) ++#define PMBUS_HAVE_STATUS_IOUT BIT(13) ++#define PMBUS_HAVE_STATUS_INPUT BIT(14) ++#define PMBUS_HAVE_STATUS_TEMP BIT(15) ++#define PMBUS_HAVE_STATUS_FAN12 BIT(16) ++#define PMBUS_HAVE_STATUS_FAN34 BIT(17) ++#define PMBUS_HAVE_VMON BIT(18) ++#define PMBUS_HAVE_STATUS_VMON BIT(19) ++#define PMBUS_HAVE_PWM12 BIT(20) ++#define PMBUS_HAVE_PWM34 BIT(21) ++#define PMBUS_HAVE_SAMPLES BIT(22) ++ ++#define PMBUS_PHASE_VIRTUAL BIT(30) /* Phases on this page are virtual */ ++#define PMBUS_PAGE_VIRTUAL BIT(31) /* Page is virtual */ ++ ++enum pmbus_data_format { linear = 0, ieee754, direct, vid }; ++enum vrm_version { vr11 = 0, vr12, vr13, imvp9, amd625mv }; ++ ++struct pmbus_driver_info { ++ int pages; /* Total number of pages */ ++ u8 phases[PMBUS_PAGES]; /* Number of phases per page */ ++ enum pmbus_data_format format[PSC_NUM_CLASSES]; ++ enum vrm_version vrm_version[PMBUS_PAGES]; /* vrm version per page */ ++ /* ++ * Support one set of coefficients for each sensor type ++ * Used for chips providing data in direct mode. ++ */ ++ int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ ++ int b[PSC_NUM_CLASSES]; /* offset */ ++ int R[PSC_NUM_CLASSES]; /* exponent */ ++ ++ u32 func[PMBUS_PAGES]; /* Functionality, per page */ ++ u32 pfunc[PMBUS_PHASES];/* Functionality, per phase */ ++ /* ++ * The following functions map manufacturing specific register values ++ * to PMBus standard register values. Specify only if mapping is ++ * necessary. ++ * Functions return the register value (read) or zero (write) if ++ * successful. A return value of -ENODATA indicates that there is no ++ * manufacturer specific register, but that a standard PMBus register ++ * may exist. Any other negative return value indicates that the ++ * register does not exist, and that no attempt should be made to read ++ * the standard register. ++ */ ++ int (*read_byte_data)(struct i2c_client *client, int page, int reg); ++ int (*read_word_data)(struct i2c_client *client, int page, int phase, ++ int reg); ++ int (*write_byte_data)(struct i2c_client *client, int page, int reg, ++ u8 byte); ++ int (*write_word_data)(struct i2c_client *client, int page, int reg, ++ u16 word); ++ int (*write_byte)(struct i2c_client *client, int page, u8 value); ++ /* ++ * The identify function determines supported PMBus functionality. ++ * This function is only necessary if a chip driver supports multiple ++ * chips, and the chip functionality is not pre-determined. ++ */ ++ int (*identify)(struct i2c_client *client, ++ struct pmbus_driver_info *info); ++ ++ /* Regulator functionality, if supported by this chip driver. */ ++ int num_regulators; ++ const struct regulator_desc *reg_desc; ++ ++ /* custom attributes */ ++ const struct attribute_group **groups; ++}; ++ ++/* Regulator ops */ ++ ++extern const struct regulator_ops pmbus_regulator_ops; ++ ++/* Macros for filling in array of struct regulator_desc */ ++#define PMBUS_REGULATOR_STEP(_name, _id, _voltages, _step) \ ++ [_id] = { \ ++ .name = (_name # _id), \ ++ .id = (_id), \ ++ .of_match = of_match_ptr(_name # _id), \ ++ .regulators_node = of_match_ptr("regulators"), \ ++ .ops = &pmbus_regulator_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE, \ ++ .n_voltages = _voltages, \ ++ .uV_step = _step, \ ++ } ++ ++#define PMBUS_REGULATOR(_name, _id) PMBUS_REGULATOR_STEP(_name, _id, 0, 0) ++ ++/* Function declarations */ ++ ++void pmbus_clear_cache(struct i2c_client *client); ++void pmbus_set_update(struct i2c_client *client, u8 reg, bool update); ++int pmbus_set_page(struct i2c_client *client, int page, int phase); ++int pmbus_read_word_data(struct i2c_client *client, int page, int phase, ++ u8 reg); ++int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, ++ u16 word); ++int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); ++int pmbus_write_byte(struct i2c_client *client, int page, u8 value); ++int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 value); ++int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg, ++ u8 mask, u8 value); ++void pmbus_clear_faults(struct i2c_client *client); ++bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); ++bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); ++int pmbus_do_probe(struct i2c_client *client, struct pmbus_driver_info *info); ++const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client ++ *client); ++int pmbus_get_fan_rate_device(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode); ++int pmbus_get_fan_rate_cached(struct i2c_client *client, int page, int id, ++ enum pmbus_fan_mode mode); ++int pmbus_update_fan(struct i2c_client *client, int page, int id, ++ u8 config, u8 mask, u16 command); ++struct dentry *pmbus_get_debugfs_dir(struct i2c_client *client); ++ ++#endif /* PMBUS_H */ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.c b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.c +new file mode 100755 +index 000000000..a55c6a0b3 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.c +@@ -0,0 +1,2154 @@ ++/* ++ * A hwmon driver for the wistron_switch_cpld ++ * ++ */ ++ ++/* ---------------------------------------------------------------------------- ++ * Include files ++ * ---------------------------------------------------------------------------- ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* --------------------------------------------------------------------------- ++ * Constant ++ * ---------------------------------------------------------------------------- ++ */ ++#include "wistron_cpld.h" ++ ++static LIST_HEAD(cpld_client_list); ++static struct mutex list_lock; ++ ++struct cpld_client_node { ++ struct i2c_client *client; ++ struct list_head list; ++}; ++ ++/* ---------------------------------------------------------------------------- ++ * ++ * Module attribute functions ++ * ---------------------------------------------------------------------------- ++ */ ++/* ++static ssize_t cpld_show_board_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, ver = 0, ver2 = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0xf0) >> 4; ++ ver2 = (val & 0xf); ++ return sprintf(buf, "%s %s\n", (ver == 0) ? "EVT" : (ver == 1) ? "DVT" : "PVT", (ver2 == 0) ? "with CPU" : "without CPU" ); ++} ++*/ ++ ++static ssize_t cpld_show_board_id(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, ver = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0x7); ++ ++ return sprintf(buf, "%d\n", ver); ++} ++ ++static ssize_t cpld_show_fan_direction(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, ver = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0x4) >> 2; ++ ++ return sprintf(buf, "%d\n", ver); ++} ++ ++static ssize_t cpld_show_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, mjr_ver = 0, mnr_ver = 0; ++ unsigned char command = CPLD_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ mjr_ver = (val & 0xf0) >> 4; ++ mnr_ver = (val & 0xf) ; ++ ++ return sprintf(buf, "%d.%d\n", mjr_ver, mnr_ver); ++} ++ ++static ssize_t cpld_show_build_date(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, b_year = 0, b_month = 0, b_day = 0; ++ unsigned char command = CPLD_BUILD_YEAR_REG; ++ unsigned char command2 = CPLD_BUILD_DATE_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ b_year = (val & 0xfe) >> 1; ++ b_month = ((val & 0x1) << 3) + ((val2 & 0xe0) >> 5); ++ b_day = val2 & 0x1f; ++ return sprintf(buf, "20%02d %02d %02d\n", b_year, b_month, b_day); ++} ++ ++static ssize_t cpld_read_psu_status(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0; ++ unsigned char command = CPLD_PSU_CHECK_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & (1 << bit)) >> bit; ++ //0 : present ++ //1 : not present ++ //0 : power on ++ //1 : power off ++ if ( (bit == PSU2_PRESENT) || (bit == PSU1_PRESENT) || (bit == PSU2_ON) || (bit == PSU1_ON) ) ++ res = (res) ? 0 : 1; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t cpld_write_psu_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_PSU_CHECK_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask << bit); ++ ++ val |= (~(res) << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t cpld_show_power_ctrl(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, i = 0; ++ unsigned char command = CPLD_POWER_CTL1_REG; ++ unsigned char command2 = CPLD_POWER_CTL2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_ctrl_str1[i], ((val & (1 << i)) >> i) ? "Enable" : "Disable"); ++ } ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_ctrl_str2[i], ((val2 & (1 << i)) >> i) ? "Enable" : "Disable"); ++ } ++ ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t cpld_show_power_good(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, i = 0; ++ unsigned char command = CPLD_POWER_GOOD_REG; ++ unsigned char command2 = CPLD_POWER_GOOD2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ mutex_unlock(&list_lock); ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_good_str1[i], ((val & (1 << i)) >> i) ? "OK" : "Failed"); ++ } ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_good_str2[i], ((val2 & (1 << i)) >> i) ? "OK" : "Failed"); ++ } ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t port_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT1) || (sda->index == PORT2)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT3) || (sda->index == PORT4)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT5) || (sda->index == PORT6)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT7) || (sda->index == PORT8)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT9) || (sda->index == PORT10)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT11) || (sda->index == PORT12)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT13) || (sda->index == PORT14)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT15) || (sda->index == PORT16)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT17) || (sda->index == PORT18)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT19) || (sda->index == PORT20)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT21) || (sda->index == PORT22)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT23) || (sda->index == PORT24)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT25) || (sda->index == PORT26)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT27) || (sda->index == PORT28)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT29) || (sda->index == PORT30)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT31) || (sda->index == PORT32)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT33) || (sda->index == PORT34)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT35) || (sda->index == PORT36)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT37) || (sda->index == PORT38)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT39) || (sda->index == PORT40)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT41) || (sda->index == PORT42)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT43) || (sda->index == PORT44)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT45) || (sda->index == PORT46)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT47) || (sda->index == PORT48)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT49) || (sda->index == PORT50)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT51) || (sda->index == PORT52)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT53) || (sda->index == PORT54)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 2) * 4; ++ mask = (0x7) << bit; ++ } else{ ++ bit = ((sda->index + 1) % 2) * 4; ++ mask = (0x7) << bit; ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT1) || (sda->index == PORT2)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT3) || (sda->index == PORT4)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT5) || (sda->index == PORT6)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT7) || (sda->index == PORT8)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT9) || (sda->index == PORT10)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT11) || (sda->index == PORT12)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT13) || (sda->index == PORT14)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT15) || (sda->index == PORT16)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT17) || (sda->index == PORT18)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT19) || (sda->index == PORT20)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT21) || (sda->index == PORT22)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT23) || (sda->index == PORT24)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT25) || (sda->index == PORT26)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT27) || (sda->index == PORT28)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT29) || (sda->index == PORT30)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT31) || (sda->index == PORT32)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT33) || (sda->index == PORT34)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT35) || (sda->index == PORT36)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT37) || (sda->index == PORT38)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT39) || (sda->index == PORT40)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT41) || (sda->index == PORT42)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT43) || (sda->index == PORT44)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT45) || (sda->index == PORT46)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT47) || (sda->index == PORT48)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT49) || (sda->index == PORT50)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT51) || (sda->index == PORT52)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT53) || (sda->index == PORT54)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ if (res < 0 || res > 4) ++ return -EINVAL; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 2) * 4; ++ mask = (0x7) << bit; ++ } else{ ++ bit = ((sda->index + 1) % 2) * 4; ++ mask = (0x7) << bit; ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++/* ++static ssize_t port_led_act_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT0) || (sda->index == PORT1)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT2) || (sda->index == PORT3)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT4) || (sda->index == PORT5)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT6) || (sda->index == PORT7)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT8) || (sda->index == PORT9)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT10) || (sda->index == PORT11)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT12) || (sda->index == PORT13)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT14) || (sda->index == PORT15)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT16) || (sda->index == PORT17)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT18) || (sda->index == PORT19)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT20) || (sda->index == PORT21)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT22) || (sda->index == PORT23)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT24) || (sda->index == PORT25)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT26) || (sda->index == PORT27)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT28) || (sda->index == PORT29)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT30) || (sda->index == PORT31)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT32) || (sda->index == PORT33)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT34) || (sda->index == PORT35)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT36) || (sda->index == PORT37)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT38) || (sda->index == PORT39)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT40) || (sda->index == PORT41)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT42) || (sda->index == PORT43)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT44) || (sda->index == PORT45)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT46) || (sda->index == PORT47)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT48) || (sda->index == PORT49)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT50) || (sda->index == PORT51)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT52) || (sda->index == PORT53)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ bit = (((sda->index) % 2) * 4) + 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_act_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT0) || (sda->index == PORT1)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT2) || (sda->index == PORT3)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT4) || (sda->index == PORT5)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT6) || (sda->index == PORT7)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT8) || (sda->index == PORT9)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT10) || (sda->index == PORT11)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT12) || (sda->index == PORT13)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT14) || (sda->index == PORT15)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT16) || (sda->index == PORT17)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT18) || (sda->index == PORT19)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT20) || (sda->index == PORT21)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT22) || (sda->index == PORT23)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT24) || (sda->index == PORT25)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT26) || (sda->index == PORT27)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT28) || (sda->index == PORT29)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT30) || (sda->index == PORT31)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT32) || (sda->index == PORT33)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT34) || (sda->index == PORT35)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT36) || (sda->index == PORT37)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT38) || (sda->index == PORT39)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT40) || (sda->index == PORT41)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT42) || (sda->index == PORT43)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT44) || (sda->index == PORT45)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT46) || (sda->index == PORT47)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT48) || (sda->index == PORT49)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT50) || (sda->index == PORT51)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT52) || (sda->index == PORT53)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (sda->index < PORT48){ ++ if (res < 0 || res > 3) ++ return -EINVAL; ++ }else{ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ } ++ ++ bit = (((sda->index) % 2) * 4) + 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++*/ ++static ssize_t port_poe_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if (sda->index < PORT5) ++ command = CPLD_POE_PRT_LED_CTL1_REG; ++ else if (sda->index < PORT9) ++ command = CPLD_POE_PRT_LED_CTL2_REG; ++ else if (sda->index < PORT13) ++ command = CPLD_POE_PRT_LED_CTL3_REG; ++ else if (sda->index < PORT17) ++ command = CPLD_POE_PRT_LED_CTL4_REG; ++ else if (sda->index < PORT21) ++ command = CPLD_POE_PRT_LED_CTL5_REG; ++ else if (sda->index < PORT25) ++ command = CPLD_POE_PRT_LED_CTL6_REG; ++ else if (sda->index < PORT29) ++ command = CPLD_POE_PRT_LED_CTL7_REG; ++ else if (sda->index < PORT33) ++ command = CPLD_POE_PRT_LED_CTL8_REG; ++ else if (sda->index < PORT37) ++ command = CPLD_POE_PRT_LED_CTL9_REG; ++ else if (sda->index < PORT41) ++ command = CPLD_POE_PRT_LED_CTL10_REG; ++ else if (sda->index < PORT45) ++ command = CPLD_POE_PRT_LED_CTL11_REG; ++ else if (sda->index < PORT49) ++ command = CPLD_POE_PRT_LED_CTL12_REG; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 4) * 2; ++ mask = (0x3) << bit; ++ } else { ++ switch( (sda->index) % 4 ){ ++ case 0: ++ bit = 2; ++ mask = (0x3) << bit; ++ break; ++ case 1: ++ bit = 0; ++ mask = (0x3) << bit; ++ break; ++ case 2: ++ bit = 6; ++ mask = (0x3) << bit; ++ break; ++ case 3: ++ bit = 4; ++ mask = (0x3) << bit; ++ break; ++ } ++ } ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_poe_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if (sda->index < PORT5) ++ command = CPLD_POE_PRT_LED_CTL1_REG; ++ else if (sda->index < PORT9) ++ command = CPLD_POE_PRT_LED_CTL2_REG; ++ else if (sda->index < PORT13) ++ command = CPLD_POE_PRT_LED_CTL3_REG; ++ else if (sda->index < PORT17) ++ command = CPLD_POE_PRT_LED_CTL4_REG; ++ else if (sda->index < PORT21) ++ command = CPLD_POE_PRT_LED_CTL5_REG; ++ else if (sda->index < PORT25) ++ command = CPLD_POE_PRT_LED_CTL6_REG; ++ else if (sda->index < PORT29) ++ command = CPLD_POE_PRT_LED_CTL7_REG; ++ else if (sda->index < PORT33) ++ command = CPLD_POE_PRT_LED_CTL8_REG; ++ else if (sda->index < PORT37) ++ command = CPLD_POE_PRT_LED_CTL9_REG; ++ else if (sda->index < PORT41) ++ command = CPLD_POE_PRT_LED_CTL10_REG; ++ else if (sda->index < PORT45) ++ command = CPLD_POE_PRT_LED_CTL11_REG; ++ else if (sda->index < PORT49) ++ command = CPLD_POE_PRT_LED_CTL12_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 4) * 2; ++ mask = (0x3) << bit; ++ } else { ++ switch( (sda->index) % 4 ){ ++ case 0: ++ bit = 2; ++ mask = (0x3) << bit; ++ break; ++ case 1: ++ bit = 0; ++ mask = (0x3) << bit; ++ break; ++ case 2: ++ bit = 6; ++ mask = (0x3) << bit; ++ break; ++ case 3: ++ bit = 4; ++ mask = (0x3) << bit; ++ break; ++ } ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t fan_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_FAN_LED_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index * 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t fan_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_FAN_LED_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ ++ bit = sda->index * 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t sys_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_SYS_LED_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t sys_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_SYS_LED_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 3) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t rst_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index > RST_MAC_JTAG){ ++ command = CPLD_RESET_CTL2_REG; ++ bit = (sda->index - 8); ++ } else { ++ command = CPLD_RESET_CTL1_REG; ++ bit = sda->index; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++/* ++static ssize_t rst_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ if (sda->index > RST_MAC_JTAG){ ++ command = CPLD_RESET_CTL2_REG; ++ bit = (sda->index - 8); ++ } else { ++ command = CPLD_RESET_CTL1_REG; ++ bit = sda->index; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t int_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index < INT_OOB_IOIEXP){ ++ command = CPLD_INT_CTL1_REG; ++ bit = sda->index; ++ } else if (sda->index < DEV_INIT_DONE){ ++ command = CPLD_INT_CTL2_REG; ++ bit = sda->index - 8; ++ } else if (sda->index < MB_SYSTEM_INT){ ++ command = CPLD_INT_CTL3_REG; ++ bit = sda->index - 16; ++ } else { ++ command = CPLD_INT_CTL4_REG; ++ bit = sda->index - 19; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t int_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ if (sda->index < INT_OOB_IOIEXP){ ++ command = CPLD_INT_CTL1_REG; ++ bit = sda->index; ++ } else if (sda->index < DEV_INIT_DONE){ ++ command = CPLD_INT_CTL2_REG; ++ bit = sda->index - 8; ++ } else if (sda->index < MB_SYSTEM_INT){ ++ command = CPLD_INT_CTL3_REG; ++ bit = sda->index - 16; ++ } else { ++ command = CPLD_INT_CTL4_REG; ++ bit = sda->index - 19; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++*/ ++static ssize_t fan_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index < PWRGD_VR_P12V_FAN3){ ++ command = CPLD_FAN_CTL1_REG; ++ bit = sda->index; ++ } else { ++ command = CPLD_FAN_CTL2_REG; ++ bit = sda->index - PWRGD_VR_P12V_FAN3; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ // fan present bit is active low ++ if ( (sda->index == CNFAN1_PRESENT) || (sda->index == CNFAN2_PRESENT) || (sda->index == CNFAN3_PRESENT) ) ++ res = (res) ? 0 : 1; ++ ++ // fan enable bit is active low ++ //if ( (sda->index == FM_FAN1_EN) || (sda->index == FM_FAN2_EN) || (sda->index == FM_FAN3_EN) ) ++ // res = (res) ? 0 : 1; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t fan_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ command = CPLD_FAN_CTL1_REG; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t port_led_auto_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_PORT_LED_MANUAL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ mutex_lock(&list_lock); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_auto_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_PORT_LED_MANUAL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t poe_enable_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_MSCI_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t poe_enable_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_MSCI_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t msci_ctl2_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_MSCI_CTL2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t msci_ctl2_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_MSCI_CTL2_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_enable_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ unsigned char command = CPLD_WATCHDOG_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t watchdog_enable_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_refresh(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 1, bit = 1, mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_timer_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 2, mask = (0x7) << bit; ++ unsigned char command = CPLD_WATCHDOG_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t watchdog_timer_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 0, bit = 2, mask = (0x7) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < WATCHDOG_180S || res > WATCHDOG_300S) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t power_down_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ unsigned char command = CPLD_SYS_POWER_DOWN_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t power_down_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_SYS_POWER_DOWN_REG; ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++//static SENSOR_DEVICE_ATTR(board_rev, S_IRUGO, cpld_show_board_version, NULL, 0); ++static SENSOR_DEVICE_ATTR(board_id, S_IRUGO, cpld_show_board_id, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan_direction, S_IRUGO, cpld_show_fan_direction, NULL, 0); ++static SENSOR_DEVICE_ATTR(cpld_rev, S_IRUGO, cpld_show_version, NULL, 0); ++static SENSOR_DEVICE_ATTR(build_date, S_IRUGO, cpld_show_build_date, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(psu2_on, S_IRUGO | S_IWUSR, cpld_read_psu_status, cpld_write_psu_status, PSU2_ON); ++static SENSOR_DEVICE_ATTR(psu1_on, S_IRUGO | S_IWUSR, cpld_read_psu_status, cpld_write_psu_status, PSU1_ON); ++static SENSOR_DEVICE_ATTR(psu2_ac_ok, S_IRUGO, cpld_read_psu_status, NULL, PSU2_AC_OK); ++static SENSOR_DEVICE_ATTR(psu1_ac_ok, S_IRUGO, cpld_read_psu_status, NULL, PSU1_AC_OK); ++static SENSOR_DEVICE_ATTR(psu2_present, S_IRUGO, cpld_read_psu_status, NULL, PSU2_PRESENT); ++static SENSOR_DEVICE_ATTR(psu1_present, S_IRUGO, cpld_read_psu_status, NULL, PSU1_PRESENT); ++static SENSOR_DEVICE_ATTR(psu2_power_good, S_IRUGO, cpld_read_psu_status, NULL, PSU2_PWRGD); ++static SENSOR_DEVICE_ATTR(psu1_power_good, S_IRUGO, cpld_read_psu_status, NULL, PSU1_PWRGD); ++ ++ ++static SENSOR_DEVICE_ATTR(power_ctrl, S_IRUGO, cpld_show_power_ctrl, NULL, 0); ++static SENSOR_DEVICE_ATTR(power_good, S_IRUGO, cpld_show_power_good, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(fan_full_speed, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FAN_FULL_SPEED); ++static SENSOR_DEVICE_ATTR(fm_fan3_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN3_EN); ++static SENSOR_DEVICE_ATTR(fm_fan2_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN2_EN); ++static SENSOR_DEVICE_ATTR(fm_fan1_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN1_EN); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan3, S_IRUGO , fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN3); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan2, S_IRUGO, fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN2); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan1, S_IRUGO, fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN1); ++static SENSOR_DEVICE_ATTR(cnfan3_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN3_PRESENT); ++static SENSOR_DEVICE_ATTR(cnfan2_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN2_PRESENT); ++static SENSOR_DEVICE_ATTR(cnfan1_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN1_PRESENT); ++ ++static SENSOR_DEVICE_ATTR(port1_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT48); ++static SENSOR_DEVICE_ATTR(port49_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT49); ++static SENSOR_DEVICE_ATTR(port50_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT50); ++static SENSOR_DEVICE_ATTR(port51_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT51); ++static SENSOR_DEVICE_ATTR(port52_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT52); ++static SENSOR_DEVICE_ATTR(port53_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT53); ++static SENSOR_DEVICE_ATTR(port54_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT54); ++/* ++static SENSOR_DEVICE_ATTR(port0_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT0); ++static SENSOR_DEVICE_ATTR(port1_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT48); ++static SENSOR_DEVICE_ATTR(port49_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT49); ++static SENSOR_DEVICE_ATTR(port50_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT50); ++static SENSOR_DEVICE_ATTR(port51_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT51); ++static SENSOR_DEVICE_ATTR(port52_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT52); ++static SENSOR_DEVICE_ATTR(port53_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT53); ++*/ ++ ++static SENSOR_DEVICE_ATTR(port1_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT48); ++ ++static SENSOR_DEVICE_ATTR(fan1_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN1); ++static SENSOR_DEVICE_ATTR(fan2_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN2); ++static SENSOR_DEVICE_ATTR(fan3_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN3); ++ ++static SENSOR_DEVICE_ATTR(loc_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, LOC_LED); ++static SENSOR_DEVICE_ATTR(psu_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, PSU_LED); ++static SENSOR_DEVICE_ATTR(sys_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, SYS_LED); ++static SENSOR_DEVICE_ATTR(fan_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, FAN_LED); ++ ++static SENSOR_DEVICE_ATTR(port_led_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_PORT_LED_EN); ++static SENSOR_DEVICE_ATTR(sysled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_SYS_LED_EN); ++static SENSOR_DEVICE_ATTR(psuled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_PSU_LED_EN); ++static SENSOR_DEVICE_ATTR(fanled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_FAN_LED_EN); ++static SENSOR_DEVICE_ATTR(locled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_LOC_LED_EN); ++ ++static SENSOR_DEVICE_ATTR(poe_en_ctrl, S_IRUGO | S_IWUSR, poe_enable_read, poe_enable_write, 0); ++ ++static SENSOR_DEVICE_ATTR(psu_vsense, S_IRUGO | S_IWUSR, msci_ctl2_read, msci_ctl2_write, PSU_VSENSE); ++static SENSOR_DEVICE_ATTR(psu_pwrgd, S_IRUGO, msci_ctl2_read, NULL, PSU_PWRGD); ++static SENSOR_DEVICE_ATTR(rst_button_10s, S_IRUGO, rst_ctrl_read, NULL, RST_BUTTON_10S); ++ ++static SENSOR_DEVICE_ATTR(watchdog_timer, S_IRUGO | S_IWUSR, watchdog_timer_read, watchdog_timer_write, 0); ++static SENSOR_DEVICE_ATTR(watchdog_kick, S_IWUSR, NULL, watchdog_refresh, 0); ++static SENSOR_DEVICE_ATTR(watchdog_en, S_IRUGO | S_IWUSR, watchdog_enable_read, watchdog_enable_write, 0); ++ ++ ++static SENSOR_DEVICE_ATTR(system_power_down, S_IRUGO | S_IWUSR, power_down_read, power_down_write, 0); ++/* ++static SENSOR_DEVICE_ATTR(rst_mb_ioiexp, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MB_IOIEXP); ++static SENSOR_DEVICE_ATTR(rst_phy0_5, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_PHY0_5); ++static SENSOR_DEVICE_ATTR(rst_poe_ctr, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_POE_CTR); ++static SENSOR_DEVICE_ATTR(cpld_sysrst_mac_rst, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, CPLD_SYSRST_MAC_RST); ++static SENSOR_DEVICE_ATTR(rst_cpu_sysrst_out, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_CPU_SYSRST_OUT); ++static SENSOR_DEVICE_ATTR(rst_gphy_rst, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_GPHY_RST); ++static SENSOR_DEVICE_ATTR(rst_i2c_mux, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_I2C_MUX); ++static SENSOR_DEVICE_ATTR(rst_mac_jtag, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MAC_JTAG); ++static SENSOR_DEVICE_ATTR(rst_button_cpld_cpu, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_BUTTON_CPLD_CPU); ++static SENSOR_DEVICE_ATTR(rst_button, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_BUTTON); ++static SENSOR_DEVICE_ATTR(rst_cpld_i2c_mux, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_CPLD_I2C_MUX); ++static SENSOR_DEVICE_ATTR(rst_mac_sys, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MAC_SYS); ++ ++static SENSOR_DEVICE_ATTR(int_phy0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY0); ++static SENSOR_DEVICE_ATTR(int_phy1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY1); ++static SENSOR_DEVICE_ATTR(int_phy2, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY2); ++static SENSOR_DEVICE_ATTR(int_phy3, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY3); ++static SENSOR_DEVICE_ATTR(int_phy4_0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY4_0); ++static SENSOR_DEVICE_ATTR(int_phy4_1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY4_1); ++static SENSOR_DEVICE_ATTR(int_phy5_0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY5_0); ++static SENSOR_DEVICE_ATTR(int_phy5_1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY5_1); ++static SENSOR_DEVICE_ATTR(int_oob_ioiexp, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_OOB_IOIEXP); ++static SENSOR_DEVICE_ATTR(int_mb_ioiexp, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_MB_IOIEXP); ++static SENSOR_DEVICE_ATTR(usb_ocp_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, USB_OCP_ALERT); ++static SENSOR_DEVICE_ATTR(temp_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, TEMP_ALERT); ++static SENSOR_DEVICE_ATTR(rtc_irq, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, RTC_IRQ); ++static SENSOR_DEVICE_ATTR(psu2_int_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, PSU2_INT_ALERT); ++static SENSOR_DEVICE_ATTR(psu1_int_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, PSU1_INT_ALERT); ++static SENSOR_DEVICE_ATTR(int_pd69210, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PD69210); ++static SENSOR_DEVICE_ATTR(dev_init_done, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, DEV_INIT_DONE); ++static SENSOR_DEVICE_ATTR(fan_ctl_fail, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, FAN_CTL_FAIL); ++static SENSOR_DEVICE_ATTR(memhot, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MEMHOT); ++static SENSOR_DEVICE_ATTR(mb_system_int, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MB_SYSTEM_INT); ++static SENSOR_DEVICE_ATTR(mb_mod_pre_int, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MB_MOD_PRE_INT); ++*/ ++static struct attribute *wistron_switch_cpld_attributes[] = { ++// &sensor_dev_attr_board_rev.dev_attr.attr, ++ &sensor_dev_attr_board_id.dev_attr.attr, ++ &sensor_dev_attr_fan_direction.dev_attr.attr, ++ &sensor_dev_attr_cpld_rev.dev_attr.attr, ++ &sensor_dev_attr_build_date.dev_attr.attr, ++ ++ &sensor_dev_attr_psu2_on.dev_attr.attr, ++ &sensor_dev_attr_psu1_on.dev_attr.attr, ++ &sensor_dev_attr_psu2_ac_ok.dev_attr.attr, ++ &sensor_dev_attr_psu1_ac_ok.dev_attr.attr, ++ &sensor_dev_attr_psu2_present.dev_attr.attr, ++ &sensor_dev_attr_psu1_present.dev_attr.attr, ++ &sensor_dev_attr_psu2_power_good.dev_attr.attr, ++ &sensor_dev_attr_psu1_power_good.dev_attr.attr, ++ ++ &sensor_dev_attr_power_ctrl.dev_attr.attr, ++ &sensor_dev_attr_power_good.dev_attr.attr, ++ ++ &sensor_dev_attr_fan_full_speed.dev_attr.attr, ++ &sensor_dev_attr_fm_fan3_en.dev_attr.attr, ++ &sensor_dev_attr_fm_fan2_en.dev_attr.attr, ++ &sensor_dev_attr_fm_fan1_en.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan3.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan2.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan1.dev_attr.attr, ++ &sensor_dev_attr_cnfan3_present.dev_attr.attr, ++ &sensor_dev_attr_cnfan2_present.dev_attr.attr, ++ &sensor_dev_attr_cnfan1_present.dev_attr.attr, ++ ++ &sensor_dev_attr_port1_led.dev_attr.attr, ++ &sensor_dev_attr_port2_led.dev_attr.attr, ++ &sensor_dev_attr_port3_led.dev_attr.attr, ++ &sensor_dev_attr_port4_led.dev_attr.attr, ++ &sensor_dev_attr_port5_led.dev_attr.attr, ++ &sensor_dev_attr_port6_led.dev_attr.attr, ++ &sensor_dev_attr_port7_led.dev_attr.attr, ++ &sensor_dev_attr_port8_led.dev_attr.attr, ++ &sensor_dev_attr_port9_led.dev_attr.attr, ++ &sensor_dev_attr_port10_led.dev_attr.attr, ++ &sensor_dev_attr_port11_led.dev_attr.attr, ++ &sensor_dev_attr_port12_led.dev_attr.attr, ++ &sensor_dev_attr_port13_led.dev_attr.attr, ++ &sensor_dev_attr_port14_led.dev_attr.attr, ++ &sensor_dev_attr_port15_led.dev_attr.attr, ++ &sensor_dev_attr_port16_led.dev_attr.attr, ++ &sensor_dev_attr_port17_led.dev_attr.attr, ++ &sensor_dev_attr_port18_led.dev_attr.attr, ++ &sensor_dev_attr_port19_led.dev_attr.attr, ++ &sensor_dev_attr_port20_led.dev_attr.attr, ++ &sensor_dev_attr_port21_led.dev_attr.attr, ++ &sensor_dev_attr_port22_led.dev_attr.attr, ++ &sensor_dev_attr_port23_led.dev_attr.attr, ++ &sensor_dev_attr_port24_led.dev_attr.attr, ++ &sensor_dev_attr_port25_led.dev_attr.attr, ++ &sensor_dev_attr_port26_led.dev_attr.attr, ++ &sensor_dev_attr_port27_led.dev_attr.attr, ++ &sensor_dev_attr_port28_led.dev_attr.attr, ++ &sensor_dev_attr_port29_led.dev_attr.attr, ++ &sensor_dev_attr_port30_led.dev_attr.attr, ++ &sensor_dev_attr_port31_led.dev_attr.attr, ++ &sensor_dev_attr_port32_led.dev_attr.attr, ++ &sensor_dev_attr_port33_led.dev_attr.attr, ++ &sensor_dev_attr_port34_led.dev_attr.attr, ++ &sensor_dev_attr_port35_led.dev_attr.attr, ++ &sensor_dev_attr_port36_led.dev_attr.attr, ++ &sensor_dev_attr_port37_led.dev_attr.attr, ++ &sensor_dev_attr_port38_led.dev_attr.attr, ++ &sensor_dev_attr_port39_led.dev_attr.attr, ++ &sensor_dev_attr_port40_led.dev_attr.attr, ++ &sensor_dev_attr_port41_led.dev_attr.attr, ++ &sensor_dev_attr_port42_led.dev_attr.attr, ++ &sensor_dev_attr_port43_led.dev_attr.attr, ++ &sensor_dev_attr_port44_led.dev_attr.attr, ++ &sensor_dev_attr_port45_led.dev_attr.attr, ++ &sensor_dev_attr_port46_led.dev_attr.attr, ++ &sensor_dev_attr_port47_led.dev_attr.attr, ++ &sensor_dev_attr_port48_led.dev_attr.attr, ++ &sensor_dev_attr_port49_led.dev_attr.attr, ++ &sensor_dev_attr_port50_led.dev_attr.attr, ++ &sensor_dev_attr_port51_led.dev_attr.attr, ++ &sensor_dev_attr_port52_led.dev_attr.attr, ++ &sensor_dev_attr_port53_led.dev_attr.attr, ++ &sensor_dev_attr_port54_led.dev_attr.attr, ++/* ++ &sensor_dev_attr_port0_act_led.dev_attr.attr, ++ &sensor_dev_attr_port1_act_led.dev_attr.attr, ++ &sensor_dev_attr_port2_act_led.dev_attr.attr, ++ &sensor_dev_attr_port3_act_led.dev_attr.attr, ++ &sensor_dev_attr_port4_act_led.dev_attr.attr, ++ &sensor_dev_attr_port5_act_led.dev_attr.attr, ++ &sensor_dev_attr_port6_act_led.dev_attr.attr, ++ &sensor_dev_attr_port7_act_led.dev_attr.attr, ++ &sensor_dev_attr_port8_act_led.dev_attr.attr, ++ &sensor_dev_attr_port9_act_led.dev_attr.attr, ++ &sensor_dev_attr_port10_act_led.dev_attr.attr, ++ &sensor_dev_attr_port11_act_led.dev_attr.attr, ++ &sensor_dev_attr_port12_act_led.dev_attr.attr, ++ &sensor_dev_attr_port13_act_led.dev_attr.attr, ++ &sensor_dev_attr_port14_act_led.dev_attr.attr, ++ &sensor_dev_attr_port15_act_led.dev_attr.attr, ++ &sensor_dev_attr_port16_act_led.dev_attr.attr, ++ &sensor_dev_attr_port17_act_led.dev_attr.attr, ++ &sensor_dev_attr_port18_act_led.dev_attr.attr, ++ &sensor_dev_attr_port19_act_led.dev_attr.attr, ++ &sensor_dev_attr_port20_act_led.dev_attr.attr, ++ &sensor_dev_attr_port21_act_led.dev_attr.attr, ++ &sensor_dev_attr_port22_act_led.dev_attr.attr, ++ &sensor_dev_attr_port23_act_led.dev_attr.attr, ++ &sensor_dev_attr_port24_act_led.dev_attr.attr, ++ &sensor_dev_attr_port25_act_led.dev_attr.attr, ++ &sensor_dev_attr_port26_act_led.dev_attr.attr, ++ &sensor_dev_attr_port27_act_led.dev_attr.attr, ++ &sensor_dev_attr_port28_act_led.dev_attr.attr, ++ &sensor_dev_attr_port29_act_led.dev_attr.attr, ++ &sensor_dev_attr_port30_act_led.dev_attr.attr, ++ &sensor_dev_attr_port31_act_led.dev_attr.attr, ++ &sensor_dev_attr_port32_act_led.dev_attr.attr, ++ &sensor_dev_attr_port33_act_led.dev_attr.attr, ++ &sensor_dev_attr_port34_act_led.dev_attr.attr, ++ &sensor_dev_attr_port35_act_led.dev_attr.attr, ++ &sensor_dev_attr_port36_act_led.dev_attr.attr, ++ &sensor_dev_attr_port37_act_led.dev_attr.attr, ++ &sensor_dev_attr_port38_act_led.dev_attr.attr, ++ &sensor_dev_attr_port39_act_led.dev_attr.attr, ++ &sensor_dev_attr_port40_act_led.dev_attr.attr, ++ &sensor_dev_attr_port41_act_led.dev_attr.attr, ++ &sensor_dev_attr_port42_act_led.dev_attr.attr, ++ &sensor_dev_attr_port43_act_led.dev_attr.attr, ++ &sensor_dev_attr_port44_act_led.dev_attr.attr, ++ &sensor_dev_attr_port45_act_led.dev_attr.attr, ++ &sensor_dev_attr_port46_act_led.dev_attr.attr, ++ &sensor_dev_attr_port47_act_led.dev_attr.attr, ++ &sensor_dev_attr_port48_act_led.dev_attr.attr, ++ &sensor_dev_attr_port49_act_led.dev_attr.attr, ++ &sensor_dev_attr_port50_act_led.dev_attr.attr, ++ &sensor_dev_attr_port51_act_led.dev_attr.attr, ++ &sensor_dev_attr_port52_act_led.dev_attr.attr, ++ &sensor_dev_attr_port53_act_led.dev_attr.attr, ++*/ ++ ++ &sensor_dev_attr_port1_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port2_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port3_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port4_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port5_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port6_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port7_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port8_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port9_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port10_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port11_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port12_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port13_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port14_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port15_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port16_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port17_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port18_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port19_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port20_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port21_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port22_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port23_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port24_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port25_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port26_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port27_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port28_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port29_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port30_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port31_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port32_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port33_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port34_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port35_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port36_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port37_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port38_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port39_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port40_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port41_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port42_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port43_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port44_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port45_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port46_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port47_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port48_poe_led.dev_attr.attr, ++ ++ &sensor_dev_attr_fan1_led.dev_attr.attr, ++ &sensor_dev_attr_fan2_led.dev_attr.attr, ++ &sensor_dev_attr_fan3_led.dev_attr.attr, ++ ++ &sensor_dev_attr_loc_led.dev_attr.attr, ++ &sensor_dev_attr_psu_led.dev_attr.attr, ++ &sensor_dev_attr_sys_led.dev_attr.attr, ++ &sensor_dev_attr_fan_led.dev_attr.attr, ++ ++ &sensor_dev_attr_port_led_auto.dev_attr.attr, ++ &sensor_dev_attr_sysled_auto.dev_attr.attr, ++ &sensor_dev_attr_fanled_auto.dev_attr.attr, ++ &sensor_dev_attr_psuled_auto.dev_attr.attr, ++ &sensor_dev_attr_locled_auto.dev_attr.attr, ++ ++ &sensor_dev_attr_poe_en_ctrl.dev_attr.attr, ++ ++ &sensor_dev_attr_psu_vsense.dev_attr.attr, ++ &sensor_dev_attr_psu_pwrgd.dev_attr.attr, ++ &sensor_dev_attr_rst_button_10s.dev_attr.attr, ++ ++ &sensor_dev_attr_watchdog_timer.dev_attr.attr, ++ &sensor_dev_attr_watchdog_kick.dev_attr.attr, ++ &sensor_dev_attr_watchdog_en.dev_attr.attr, ++ ++ &sensor_dev_attr_system_power_down.dev_attr.attr, ++/* ++ &sensor_dev_attr_rst_mb_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_rst_phy0_5.dev_attr.attr, ++ &sensor_dev_attr_rst_poe_ctr.dev_attr.attr, ++ &sensor_dev_attr_cpld_sysrst_mac_rst.dev_attr.attr, ++ &sensor_dev_attr_rst_cpu_sysrst_out.dev_attr.attr, ++ &sensor_dev_attr_rst_gphy_rst.dev_attr.attr, ++ &sensor_dev_attr_rst_i2c_mux.dev_attr.attr, ++ &sensor_dev_attr_rst_mac_jtag.dev_attr.attr, ++ &sensor_dev_attr_rst_button_cpld_cpu.dev_attr.attr, ++ &sensor_dev_attr_rst_button.dev_attr.attr, ++ &sensor_dev_attr_rst_cpld_i2c_mux.dev_attr.attr, ++ &sensor_dev_attr_rst_mac_sys.dev_attr.attr, ++ ++ &sensor_dev_attr_int_phy0.dev_attr.attr, ++ &sensor_dev_attr_int_phy1.dev_attr.attr, ++ &sensor_dev_attr_int_phy2.dev_attr.attr, ++ &sensor_dev_attr_int_phy3.dev_attr.attr, ++ &sensor_dev_attr_int_phy4_0.dev_attr.attr, ++ &sensor_dev_attr_int_phy4_1.dev_attr.attr, ++ &sensor_dev_attr_int_phy5_0.dev_attr.attr, ++ &sensor_dev_attr_int_phy5_1.dev_attr.attr, ++ &sensor_dev_attr_int_oob_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_int_mb_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_usb_ocp_alert.dev_attr.attr, ++ &sensor_dev_attr_temp_alert.dev_attr.attr, ++ &sensor_dev_attr_rtc_irq.dev_attr.attr, ++ &sensor_dev_attr_psu2_int_alert.dev_attr.attr, ++ &sensor_dev_attr_psu1_int_alert.dev_attr.attr, ++ &sensor_dev_attr_int_pd69210.dev_attr.attr, ++ &sensor_dev_attr_dev_init_done.dev_attr.attr, ++ &sensor_dev_attr_fan_ctl_fail.dev_attr.attr, ++ &sensor_dev_attr_memhot.dev_attr.attr, ++ &sensor_dev_attr_mb_system_int.dev_attr.attr, ++ &sensor_dev_attr_mb_mod_pre_int.dev_attr.attr, ++*/ ++ NULL ++}; ++ ++static const struct attribute_group wistron_switch_cpld_group = { ++ .attrs = wistron_switch_cpld_attributes, ++}; ++ ++ ++/* ---------------------------------------------------------------------------- ++ * Module probe/remove functions ++ * ---------------------------------------------------------------------------- ++ */ ++static int _add_client(struct i2c_client *client) ++{ ++ struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); ++ if (!node) { ++ dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); ++ return -ENOMEM; ++ } ++ ++ node->client = client; ++ ++ mutex_lock(&list_lock); ++ list_add(&node->list, &cpld_client_list); ++ mutex_unlock(&list_lock); ++ ++ return 0; ++} ++ ++static int _remove_client(struct i2c_client *client) ++{ ++ struct list_head *list_node = NULL; ++ struct cpld_client_node *cpld_node = NULL; ++ int found = 0; ++ ++ mutex_lock(&list_lock); ++ ++ list_for_each(list_node, &cpld_client_list) { ++ cpld_node = list_entry(list_node, struct cpld_client_node, list); ++ ++ if (cpld_node->client == client) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (found) { ++ list_del(list_node); ++ kfree(cpld_node); ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ return 0; ++} ++ ++/* Probe I2C driver */ ++static int wistron_i2c_cpld_probe(struct i2c_client *client, ++ const struct i2c_device_id *dev_id) ++{ ++ int status; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); ++ status = -EIO; ++ goto exit; ++ } ++ ++ status = _add_client(client); ++ if (status < 0) { ++ dev_err(&client->dev, "Failed to add client\n"); ++ goto exit; ++ } ++ ++ status = sysfs_create_group(&client->dev.kobj, &wistron_switch_cpld_group); ++ ++ if (status) { ++ goto exit; ++ } ++ ++ dev_info(&client->dev, "chip found\n"); ++ ++ return 0; ++ ++exit: ++ return status; ++} ++ ++static void wistron_i2c_cpld_remove(struct i2c_client *client) ++{ ++ _remove_client(client); ++ ++ sysfs_remove_group(&client->dev.kobj, &wistron_switch_cpld_group); ++ ++} ++ ++/* ---------------------------------------------------------------------------- ++ * Module main functions ++ * ---------------------------------------------------------------------------- ++ */ ++static const struct i2c_device_id wistron_i2c_cpld_id[] = { ++ {"wistron_cpld", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, wistron_i2c_cpld_id); ++ ++static struct i2c_driver wistron_i2c_cpld_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "wistron_cpld", ++ }, ++ .probe = wistron_i2c_cpld_probe, ++ .remove = wistron_i2c_cpld_remove, ++ .id_table = wistron_i2c_cpld_id, ++}; ++ ++static int __init wistron_i2c_cpld_init(void) ++{ ++ mutex_init(&list_lock); ++ ++ return i2c_add_driver(&wistron_i2c_cpld_driver); ++} ++ ++static void __exit wistron_i2c_cpld_exit(void) ++{ ++ i2c_del_driver(&wistron_i2c_cpld_driver); ++} ++ ++ ++MODULE_AUTHOR("Wistron"); ++MODULE_DESCRIPTION("SONiC platform driver for Wistron CPLD"); ++MODULE_LICENSE("GPL"); ++ ++module_init(wistron_i2c_cpld_init); ++module_exit(wistron_i2c_cpld_exit); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.h b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.h +new file mode 100755 +index 000000000..db3475da4 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_cpld.h +@@ -0,0 +1,298 @@ ++ ++/*************************************************************************** ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ ***************************************************************************/ ++ ++ ++#ifndef _WISTRON_SWITCH_CPLD_H ++#define _WISTRON_SWITCH_CPLD_H ++ ++//#define CPLD_REVISION_REG 0x0 ++#define CPLD_HW_REVISION_REG 0x1 ++#define CPLD_REVISION_REG 0x2 ++#define CPLD_BUILD_YEAR_REG 0x3 ++#define CPLD_BUILD_DATE_REG 0x4 ++#define CPLD_RW_TEST_REG 0x5 ++#define CPLD_PSU_CHECK_REG 0x6 ++ ++#define CPLD_POWER_CTL1_REG 0x7 ++#define CPLD_POWER_CTL2_REG 0x8 ++ ++#define CPLD_POWER_GOOD_REG 0x9 ++#define CPLD_POWER_GOOD2_REG 0xA ++ ++#define CPLD_FAN_CTL1_REG 0xB ++#define CPLD_FAN_CTL2_REG 0xC ++ ++ ++#define CPLD_1G_LED_CTL1_REG 0xD ++#define CPLD_1G_LED_CTL2_REG 0xE ++#define CPLD_1G_LED_CTL3_REG 0xF ++#define CPLD_1G_LED_CTL4_REG 0x10 ++#define CPLD_1G_LED_CTL5_REG 0x11 ++#define CPLD_1G_LED_CTL6_REG 0x12 ++#define CPLD_1G_LED_CTL7_REG 0x13 ++#define CPLD_1G_LED_CTL8_REG 0x14 ++#define CPLD_1G_LED_CTL9_REG 0x15 ++#define CPLD_1G_LED_CTL10_REG 0x16 ++#define CPLD_1G_LED_CTL11_REG 0x17 ++#define CPLD_1G_LED_CTL12_REG 0x18 ++#define CPLD_1G_LED_CTL13_REG 0x19 ++#define CPLD_1G_LED_CTL14_REG 0x1A ++#define CPLD_1G_LED_CTL15_REG 0x1B ++#define CPLD_1G_LED_CTL16_REG 0x1C ++ ++#define CPLD_2_5G_LED_CTL1_REG 0x1D ++#define CPLD_2_5G_LED_CTL2_REG 0x1E ++#define CPLD_2_5G_LED_CTL3_REG 0x1F ++#define CPLD_2_5G_LED_CTL4_REG 0x20 ++#define CPLD_2_5G_LED_CTL5_REG 0x21 ++#define CPLD_2_5G_LED_CTL6_REG 0x22 ++#define CPLD_2_5G_LED_CTL7_REG 0x23 ++#define CPLD_2_5G_LED_CTL8_REG 0x24 ++ ++#define CPLD_POE_PRT_LED_CTL1_REG 0x25 ++#define CPLD_POE_PRT_LED_CTL2_REG 0x26 ++#define CPLD_POE_PRT_LED_CTL3_REG 0x27 ++#define CPLD_POE_PRT_LED_CTL4_REG 0x28 ++#define CPLD_POE_PRT_LED_CTL5_REG 0x29 ++#define CPLD_POE_PRT_LED_CTL6_REG 0x2A ++#define CPLD_POE_PRT_LED_CTL7_REG 0x2B ++#define CPLD_POE_PRT_LED_CTL8_REG 0x2C ++#define CPLD_POE_PRT_LED_CTL9_REG 0x2D ++#define CPLD_POE_PRT_LED_CTL10_REG 0x2E ++#define CPLD_POE_PRT_LED_CTL11_REG 0x2F ++#define CPLD_POE_PRT_LED_CTL12_REG 0x30 ++ ++#define CPLD_SFP_LED_CTL1_REG 0x31 ++#define CPLD_SFP_LED_CTL2_REG 0x32 ++#define CPLD_SFP_LED_CTL3_REG 0x33 ++ ++ ++#define CPLD_FAN_LED_CTL_REG 0x34 ++#define CPLD_SYS_LED_CTL_REG 0x35 ++ ++#define CPLD_RESET_CTL1_REG 0x36 ++#define CPLD_RESET_CTL2_REG 0x37 ++ ++#define CPLD_INT_CTL1_REG 0x38 ++#define CPLD_INT_CTL2_REG 0x39 ++#define CPLD_INT_CTL3_REG 0x3A ++#define CPLD_INT_CTL4_REG 0x3B ++#define CPLD_MSCI_CTL_REG 0x3C ++#define CPLD_PORT_LED_MANUAL_REG 0x3D ++#define CPLD_RESET_CTL3_REG 0x3E ++#define CPLD_MSCI_CTL2_REG 0x3F ++#define CPLD_WATCHDOG_REG 0x40 ++#define CPLD_SYS_POWER_DOWN_REG 0x41 ++ ++static char* power_ctrl_str1[] = { ++ "P1V2_OOB_EN", // 0 ++ "P1V5_EN", ++ "P1V8_CPU_EN", ++ "P1V8", ++ "P2V5_CPU_DDR4_EN", ++ "P2V5_EN", ++ "P3V3_EN", ++ "P5V0_EN", // 7 ++}; ++ ++static char* power_ctrl_str2[] = { ++ "PHY_P0V8_EN", // 0 ++ "P0V8_MAC_EN", ++ "P0V85_CPU_AP_VDD_EN", ++ "P1V15_EN", ++ "P0V6_CPU_DDR4_VTT_EN", ++ "P0V6_EN", ++ "P1V2_CPU_DDR4_EN", ++ "P1V2_EN", // 7 ++}; ++ ++static char* power_good_str1[] = { ++ "PWRGD_VR_P1V2_OOB", // 0 ++ "PWRGD_P1V5", ++ "PWRGD_P1V8_CPU", ++ "PWRGD_P1V8", ++ "PWRGD_P2V5_CPU_DDR4", ++ "PWRGD_P2V5", ++ "PWRGD_P3V3", ++ "PWRGD_P5V0", // 7 ++}; ++ ++static char* power_good_str2[] = { ++ "PWRGD_PHY_P0V8", // 0 ++ "PWRGD_VR_MAC_P0V8", ++ "PWRGD_P0V85_CPU_AP_VDD", ++ "PWRGD_P1V15", ++ "PWRGD_VR_P0V6_CPU_DDR4_VTT", ++ "PWRGD_VR_P0V6", ++ "PWRGD_P1V2_CPU_DDR4", ++ "PWRGD_P1V2", ++}; ++ ++enum psu_status_bit { ++ PSU2_ON = 0, ++ PSU1_ON, ++ PSU2_AC_OK, ++ PSU1_AC_OK, ++ PSU2_PRESENT, ++ PSU1_PRESENT, ++ PSU2_PWRGD, ++ PSU1_PWRGD, ++}; ++ ++enum fan_control_bit { ++ FAN_FULL_SPEED = 0, ++ FM_FAN3_EN = 1, ++ FM_FAN2_EN = 2, ++ FM_FAN1_EN = 3, ++ FM_FAN3_TYPE = 4, ++ FM_FAN2_TYPE = 5, ++ FM_FAN1_TYPE = 6, ++ PWRGD_VR_P12V_FAN3 = 7, ++ PWRGD_VR_P12V_FAN2 = 8, ++ PWRGD_VR_P12V_FAN1 = 9, ++ CNFAN3_PRESENT = 10, ++ CNFAN2_PRESENT = 11, ++ CNFAN1_PRESENT = 12, ++}; ++ ++enum fan_id { ++ FAN3 = 0, ++ FAN2, ++ FAN1, ++}; ++ ++enum port_id { ++ PORT1 = 0, ++ PORT2, ++ PORT3, ++ PORT4, ++ PORT5, ++ PORT6, ++ PORT7, ++ PORT8, ++ PORT9, ++ PORT10, ++ PORT11, ++ PORT12, ++ PORT13, ++ PORT14, ++ PORT15, ++ PORT16, ++ PORT17, ++ PORT18, ++ PORT19, ++ PORT20, ++ PORT21, ++ PORT22, ++ PORT23, ++ PORT24, ++ PORT25, ++ PORT26, ++ PORT27, ++ PORT28, ++ PORT29, ++ PORT30, ++ PORT31, ++ PORT32, ++ PORT33, ++ PORT34, ++ PORT35, ++ PORT36, ++ PORT37, ++ PORT38, ++ PORT39, ++ PORT40, ++ PORT41, ++ PORT42, ++ PORT43, ++ PORT44, ++ PORT45, ++ PORT46, ++ PORT47, ++ PORT48, ++ PORT49, ++ PORT50, ++ PORT51, ++ PORT52, ++ PORT53, ++ PORT54, ++}; ++ ++enum led_status_shift_bit { ++ LOC_LED = 0, ++ PSU_LED = 2, ++ SYS_LED = 4, ++ FAN_LED = 6, ++}; ++ ++enum rst_shift_bit { ++ RST_MB_IOIEXP = 0, ++ RST_PHY0_5 = 1, ++ RST_POE_CTR = 2, ++ CPLD_SYSRST_MAC_RST = 3, ++ RST_CPU_SYSRST_OUT = 4, ++ RST_GPHY_RST = 5, ++ RST_I2C_MUX = 6, ++ RST_MAC_JTAG = 7, ++ RST_BUTTON_CPLD_CPU = 8, ++ RST_BUTTON = 9, ++ RST_CPLD_I2C_MUX = 10, ++ RST_BUTTON_10S = 1, ++}; ++ ++enum int_shift_bit { ++ INT_PHY0 = 0, ++ INT_PHY1 = 1, ++ INT_PHY2 = 2, ++ INT_PHY3 = 3, ++ INT_PHY4_0 = 4, ++ INT_PHY4_1 = 5, ++ INT_PHY5_0 = 6, ++ INT_PHY5_1 = 7, ++ ++ INT_OOB_IOIEXP = 8, ++ INT_MB_IOIEXP = 9, ++ USB_OCP_ALERT = 10, ++ TEMP_ALERT = 11, ++ RTC_IRQ = 12, ++ PSU2_INT_ALERT = 13, ++ PSU1_INT_ALERT = 14, ++ INT_PD69210 = 15, ++ ++ DEV_INIT_DONE = 16, ++ FAN_CTL_FAIL = 17, ++ MEMHOT = 18, ++ ++ MB_SYSTEM_INT = 19, ++ MB_MOD_PRE_INT = 20, ++}; ++ ++enum msci_ctl2_shift_bit { ++ PSU_VSENSE = 0, ++ PSU_PWRGD = 1, ++}; ++ ++enum sysled_en_shift_bit { ++ FRONT_PORT_LED_EN = 0, ++ FRONT_SYS_LED_EN = 1, ++ FRONT_PSU_LED_EN = 2, ++ FRONT_FAN_LED_EN = 3, ++ FRONT_LOC_LED_EN = 4, ++}; ++ ++enum watchdog_timer_def { ++ WATCHDOG_180S = 0, ++ WATCHDOG_210S = 1, ++ WATCHDOG_240S = 2, ++ WATCHDOG_270S = 3, ++ WATCHDOG_300S = 4, ++}; ++ ++#endif /* _WISTRON_SWITCH_CPLD_H */ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_max31790.c b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_max31790.c +new file mode 100755 +index 000000000..78a0daadf +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_max31790.c +@@ -0,0 +1,604 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * max31790.c - Part of lm_sensors, Linux kernel modules for hardware ++ * monitoring. ++ * ++ * (C) 2015 by Il Han ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MAX31790 registers */ ++#define MAX31790_REG_GLOBAL_CONFIG 0x00 ++#define MAX31790_REG_FAN_CONFIG(ch) (0x02 + (ch)) ++#define MAX31790_REG_FAN_DYNAMICS(ch) (0x08 + (ch)) ++#define MAX31790_REG_FAN_FAULT_STATUS2 0x10 ++#define MAX31790_REG_FAN_FAULT_STATUS1 0x11 ++#define MAX31790_REG_TACH_COUNT(ch) (0x18 + (ch) * 2) ++#define MAX31790_REG_PWM_DUTY_CYCLE(ch) (0x30 + (ch) * 2) ++#define MAX31790_REG_PWMOUT(ch) (0x40 + (ch) * 2) ++#define MAX31790_REG_TARGET_COUNT(ch) (0x50 + (ch) * 2) ++ ++/* Fan Config register bits */ ++#define MAX31790_FAN_CFG_RPM_MODE 0x80 ++#define MAX31790_FAN_CFG_CTRL_MON 0x10 ++#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08 ++#define MAX31790_FAN_CFG_TACH_INPUT 0x01 ++ ++/* Fan Dynamics register bits */ ++#define MAX31790_FAN_DYN_SR_SHIFT 5 ++#define MAX31790_FAN_DYN_SR_MASK 0xE0 ++#define SR_FROM_REG(reg) (((reg) & MAX31790_FAN_DYN_SR_MASK) \ ++ >> MAX31790_FAN_DYN_SR_SHIFT) ++ ++#define FAN_RPM_MIN 120 ++#define FAN_RPM_MAX 7864320 ++ ++#define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \ ++ ((60 * (sr) * 8192) / ((reg) >> 4)) : \ ++ FAN_RPM_MAX) ++#define RPM_TO_REG(rpm, sr) ((60 * (sr) * 8192) / ((rpm) * 2)) ++ ++#define NR_CHANNEL 6 ++ ++#define MAX31790_REG_FREQ_CONFIG 0x01 ++#define MAX31790_REG_FAIL_MASK2 0x12 ++#define MAX31790_REG_FAIL_MASK1 0x13 ++#define MAX31790_REG_FAIL_CTRL 0x14 ++static char *platform; ++module_param(platform, charp, 0000); ++MODULE_PARM_DESC(platform, "platform name (support ES-1227)."); ++ ++enum { ++ PLATFORM_ES1227 = 1, ++ PLATFORM_LAST, ++}; ++ ++struct max31790_init_data { ++ u8 freq; ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++#if 0 ++ u8 fail_mask[2]; ++ u8 fail_ctrl; ++#endif ++}; ++ ++struct max31790_init_data platform_init_data[PLATFORM_LAST - 1] = ++{ ++ { ++ .freq = 0xbb, ++ .fan_config = {0x68, 0x79, 0x68, 0x68, 0x79, 0x79}, ++ .fan_dynamics = {0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c}, ++#if 0 ++ .fail_mask = {0x3d, 0x20}, ++ .fail_ctrl = 0x45, ++#endif ++ }, ++}; ++/* ++ * Client data (each client gets its own) ++ */ ++struct max31790_data { ++ struct i2c_client *client; ++ struct mutex update_lock; ++ bool valid; /* zero until following fields are valid */ ++ unsigned long last_updated; /* in jiffies */ ++ ++ /* register values */ ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++ u16 fault_status; ++ u16 tach[NR_CHANNEL * 2]; ++ u16 pwm[NR_CHANNEL]; ++ u16 target_count[NR_CHANNEL]; ++}; ++ ++static struct max31790_data *max31790_update_device(struct device *dev) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ struct max31790_data *ret = data; ++ int i; ++ int rv; ++ ++ mutex_lock(&data->update_lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS1); ++ if (rv < 0) ++ goto abort; ++ data->fault_status = rv & 0x3F; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS2); ++ if (rv < 0) ++ goto abort; ++ data->fault_status |= (rv & 0x3F) << 6; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(NR_CHANNEL ++ + i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[NR_CHANNEL + i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_PWMOUT(i)); ++ if (rv < 0) ++ goto abort; ++ data->pwm[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->target_count[i] = rv; ++ } ++ ++ data->last_updated = jiffies; ++ data->valid = true; ++ } ++ goto done; ++ ++abort: ++ data->valid = false; ++ ret = ERR_PTR(rv); ++ ++done: ++ mutex_unlock(&data->update_lock); ++ ++ return ret; ++} ++ ++static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; ++ ++static u8 get_tach_period(u8 fan_dynamics) ++{ ++ return tach_period[SR_FROM_REG(fan_dynamics)]; ++} ++ ++static u8 bits_for_tach_period(int rpm) ++{ ++ u8 bits; ++ ++ if (rpm < 500) ++ bits = 0x0; ++ else if (rpm < 1000) ++ bits = 0x1; ++ else if (rpm < 2000) ++ bits = 0x2; ++ else if (rpm < 4000) ++ bits = 0x3; ++ else if (rpm < 8000) ++ bits = 0x4; ++ else ++ bits = 0x5; ++ ++ return bits; ++} ++ ++static int max31790_read_fan(struct device *dev, u32 attr, int channel, ++ long *val) ++{ ++ struct max31790_data *data = max31790_update_device(dev); ++ int sr, rpm; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]); ++ rpm = RPM_FROM_REG(data->tach[channel], sr); ++ *val = rpm; ++ return 0; ++ case hwmon_fan_target: ++ sr = get_tach_period(data->fan_dynamics[channel]); ++ rpm = RPM_FROM_REG(data->target_count[channel], sr); ++ *val = rpm; ++ return 0; ++ case hwmon_fan_fault: ++ *val = !!(data->fault_status & (1 << channel)); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write_fan(struct device *dev, u32 attr, int channel, ++ long val) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ int target_count; ++ int err = 0; ++ u8 bits; ++ int sr; ++ ++ mutex_lock(&data->update_lock); ++ ++ switch (attr) { ++ case hwmon_fan_target: ++ val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX); ++ bits = bits_for_tach_period(val); ++ data->fan_dynamics[channel] = ++ ((data->fan_dynamics[channel] & ++ ~MAX31790_FAN_DYN_SR_MASK) | ++ (bits << MAX31790_FAN_DYN_SR_SHIFT)); ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(channel), ++ data->fan_dynamics[channel]); ++ if (err < 0) ++ break; ++ ++ sr = get_tach_period(data->fan_dynamics[channel]); ++ target_count = RPM_TO_REG(val, sr); ++ target_count = clamp_val(target_count, 0x1, 0x7FF); ++ ++ data->target_count[channel] = target_count << 5; ++ ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(channel), ++ data->target_count[channel]); ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return err; ++} ++ ++static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) ++{ ++ const struct max31790_data *data = _data; ++ u8 fan_config = data->fan_config[channel % NR_CHANNEL]; ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ case hwmon_fan_fault: ++ if (channel < NR_CHANNEL || ++ (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0444; ++ return 0; ++ case hwmon_fan_target: ++ if (channel < NR_CHANNEL && ++ !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0644; ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int max31790_read_pwm(struct device *dev, u32 attr, int channel, ++ long *val) ++{ ++ struct max31790_data *data = max31790_update_device(dev); ++ u8 fan_config; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ fan_config = data->fan_config[channel]; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ *val = data->pwm[channel] >> 8; ++ return 0; ++ case hwmon_pwm_enable: ++ if (fan_config & MAX31790_FAN_CFG_CTRL_MON) ++ *val = 0; ++ else if (fan_config & MAX31790_FAN_CFG_RPM_MODE) ++ *val = 2; ++ else ++ *val = 1; ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write_pwm(struct device *dev, u32 attr, int channel, ++ long val) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ u8 fan_config; ++ int err = 0; ++ int i = 0; ++ ++ mutex_lock(&data->update_lock); ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ if (val < 0 || val > 255) { ++ err = -EINVAL; ++ break; ++ } ++ data->pwm[channel] = val << 8; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_PWMOUT(i), ++ data->pwm[channel]); ++ } ++ break; ++ case hwmon_pwm_enable: ++ fan_config = data->fan_config[channel]; ++ if (val == 0) { ++ fan_config |= MAX31790_FAN_CFG_CTRL_MON; ++ /* ++ * Disable RPM mode; otherwise disabling fan speed ++ * monitoring is not possible. ++ */ ++ fan_config &= ~MAX31790_FAN_CFG_RPM_MODE; ++ } else if (val == 1) { ++ fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE); ++ } else if (val == 2) { ++ fan_config &= ~MAX31790_FAN_CFG_CTRL_MON; ++ /* ++ * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its ++ * own if MAX31790_FAN_CFG_RPM_MODE is set. ++ * Do it here as well to reflect the actual register ++ * value in the cache. ++ */ ++ fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN); ++ } else { ++ err = -EINVAL; ++ break; ++ } ++ if (fan_config != data->fan_config[channel]) { ++ err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel), ++ fan_config); ++ if (!err) ++ data->fan_config[channel] = fan_config; ++ } ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return err; ++} ++ ++static umode_t max31790_pwm_is_visible(const void *_data, u32 attr, int channel) ++{ ++ const struct max31790_data *data = _data; ++ u8 fan_config = data->fan_config[channel]; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ case hwmon_pwm_enable: ++ if (!(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0644; ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int max31790_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_read_fan(dev, attr, channel, val); ++ case hwmon_pwm: ++ return max31790_read_pwm(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_write_fan(dev, attr, channel, val); ++ case hwmon_pwm: ++ return max31790_write_pwm(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static umode_t max31790_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_fan_is_visible(data, attr, channel); ++ case hwmon_pwm: ++ return max31790_pwm_is_visible(data, attr, channel); ++ default: ++ return 0; ++ } ++} ++ ++static const struct hwmon_channel_info *max31790_info[] = { ++ HWMON_CHANNEL_INFO(fan, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT), ++ HWMON_CHANNEL_INFO(pwm, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE), ++ NULL ++}; ++ ++static const struct hwmon_ops max31790_hwmon_ops = { ++ .is_visible = max31790_is_visible, ++ .read = max31790_read, ++ .write = max31790_write, ++}; ++ ++static const struct hwmon_chip_info max31790_chip_info = { ++ .ops = &max31790_hwmon_ops, ++ .info = max31790_info, ++}; ++ ++static int max31790_init_setup(struct i2c_client *client, ++ int platform_id) ++{ ++ int i, rv; ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FREQ_CONFIG, ++ platform_init_data[platform_id - 1].freq); ++ if (rv < 0) ++ return rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i), ++ platform_init_data[platform_id - 1].fan_config[i]); ++ if (rv < 0) ++ return rv; ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i), ++ platform_init_data[platform_id - 1].fan_dynamics[i]); ++ if (rv < 0) ++ return rv; ++ } ++ ++#if 0 ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_MASK2, ++ platform_init_data[platform_id - 1].fail_mask[0]); ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_MASK1, ++ platform_init_data[platform_id - 1].fail_mask[1]); ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_CTRL, ++ platform_init_data[platform_id - 1].fail_ctrl); ++#endif ++ return 0; ++} ++ ++static int max31790_init_client(struct i2c_client *client, ++ struct max31790_data *data) ++{ ++ int i, rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_config[i] = rv; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_dynamics[i] = rv; ++ } ++ ++ return 0; ++} ++ ++static int max31790_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct device *dev = &client->dev; ++ struct max31790_data *data; ++ struct device *hwmon_dev; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) ++ return -ENODEV; ++ ++ data = devm_kzalloc(dev, sizeof(struct max31790_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ mutex_init(&data->update_lock); ++ ++ /* ++ * Initialize the max31790 chip ++ */ ++ if (id->driver_data != 0) { ++ err = max31790_init_setup(client, id->driver_data); ++ } else { ++ if (!strcmp(platform, "1227")) ++ err = max31790_init_setup(client, PLATFORM_ES1227); ++ } ++ ++ if (err) ++ return err; ++ ++ err = max31790_init_client(client, data); ++ if (err) ++ return err; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ++ data, ++ &max31790_chip_info, ++ NULL); ++ ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static const struct i2c_device_id max31790_id[] = { ++ { "max31790", 0 }, ++ { "1227_max31790", PLATFORM_ES1227}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max31790_id); ++ ++static struct i2c_driver max31790_driver = { ++ .class = I2C_CLASS_HWMON, ++ .probe = max31790_probe, ++ .driver = { ++ .name = "wistron_max31790", ++ }, ++ .id_table = max31790_id, ++}; ++ ++module_i2c_driver(max31790_driver); ++ ++MODULE_AUTHOR("Il Han "); ++MODULE_DESCRIPTION("MAX31790 sensor driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_psu.c b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_psu.c +new file mode 100755 +index 000000000..d873fe3aa +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/modules/wistron_psu.c +@@ -0,0 +1,248 @@ ++/* ++ * Wistron Generic PMBUS driver ++ * ++ * ++ * Based on pmbus_core driver and ltc2978 driver ++ * ++ * Author: ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "pmbus.h" ++ ++static int pmbus_read_block_data(struct i2c_client *client, u8 command, u8 *data) ++{ ++ int result = 0; ++ int retry_count = 3; ++ ++ while (retry_count) { ++ retry_count--; ++ ++ result = i2c_smbus_read_i2c_block_data(client, command, I2C_SMBUS_BLOCK_MAX, data); ++ ++ if (result < 0) { ++ msleep(10); ++ continue; ++ } ++ ++ result = 0; ++ break; ++ } ++ ++ return result; ++} ++ ++/* ---------------------------------------------------------------------------- ++ * export function for specified use ++ * ---------------------------------------------------------------------------- ++ */ ++ ++static ssize_t wistron_psu_get_vendor(struct device *dev, struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_ID, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer ID\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++ ++} ++ ++static ssize_t wistron_psu_get_model(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer Model\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static ssize_t wistron_psu_get_version(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_REVISION, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer Revision\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static ssize_t wistron_psu_get_location(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_LOCATION, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacture Location\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static ssize_t wistron_psu_get_serial(struct device *dev, ++ struct device_attribute *da, char *buf) ++{ ++ int ret, len; ++ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1], *str; ++ struct i2c_client *client = container_of(dev, struct i2c_client, dev); ++ ++ ret = pmbus_read_block_data(client, PMBUS_MFR_SERIAL, block_buffer); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "Failed to read Manufacturer Serial\n"); ++ return ret; ++ } ++ len = block_buffer[0]; ++ block_buffer[(len+1)] = '\0'; ++ str = &(block_buffer[1]); ++ ++ return snprintf(buf, PAGE_SIZE, "%s\n", str); ++} ++ ++static DEVICE_ATTR(mfr_id, S_IRUGO, wistron_psu_get_vendor, NULL); ++static DEVICE_ATTR(mfr_model, S_IRUGO, wistron_psu_get_model, NULL); ++static DEVICE_ATTR(mfr_revision, S_IRUGO, wistron_psu_get_version, NULL); ++static DEVICE_ATTR(mfr_location, S_IRUGO, wistron_psu_get_location, NULL); ++static DEVICE_ATTR(mfr_serial, S_IRUGO, wistron_psu_get_serial, NULL); ++ ++static struct attribute *wistron_pmbus_attributes[] = { ++ &dev_attr_mfr_id.attr, ++ &dev_attr_mfr_model.attr, ++ &dev_attr_mfr_revision.attr, ++ &dev_attr_mfr_location.attr, ++ &dev_attr_mfr_serial.attr, ++ NULL ++}; ++ ++static const struct attribute_group wistron_pmbus_group = { ++ .attrs = wistron_pmbus_attributes, ++}; ++ ++static const struct i2c_device_id pmbus_id[] = { ++ {"wistron_psu", 0}, ++ {} ++}; ++MODULE_DEVICE_TABLE(i2c, pmbus_id); ++ ++struct pmbus_driver_info wistron_psu_info = { ++ .pages = 1, ++ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | ++ PMBUS_HAVE_PIN | PMBUS_HAVE_STATUS_INPUT | ++ PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | ++ PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | ++ PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP | ++ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ++ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ++ PMBUS_HAVE_POUT, ++}; ++ ++static int pmbus_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct device *dev = &client->dev; ++ int ret; ++ ++ dev_info(dev, "wistron-psu pmbus_probe\n"); ++ ++ if (!i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_WORD_DATA)) ++ return -ENODEV; ++ ++ /* Register sysfs hooks */ ++ ret = sysfs_create_group(&client->dev.kobj, &wistron_pmbus_group); ++ if (ret) { ++ dev_err(dev, "Failed to create sysfs entries\n"); ++ goto exit; ++ } ++ ++ return pmbus_do_probe(client, &wistron_psu_info); ++ ++exit: ++ return ret; ++} ++ ++static struct i2c_driver pmbus_driver = { ++ .driver = { ++ .name = "wistron-psu", ++ }, ++ .probe = pmbus_probe, ++ .id_table = pmbus_id, ++}; ++ ++static int __init pmbus_driver_init(void) ++{ ++ return i2c_add_driver(&pmbus_driver); ++} ++ ++static void __exit pmbus_driver_exit(void) ++{ ++ i2c_del_driver(&pmbus_driver); ++} ++ ++module_init(pmbus_driver_init); ++module_exit(pmbus_driver_exit); ++ ++MODULE_AUTHOR("Wistron"); ++MODULE_VERSION("1.0"); ++MODULE_DESCRIPTION("SONiC platform driver for Wistron PSU"); ++MODULE_LICENSE("GPL"); ++MODULE_IMPORT_NS(PMBUS); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/entropy.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/entropy.py +new file mode 100644 +index 000000000..338e2ad9b +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/entropy.py +@@ -0,0 +1,19 @@ ++#!/usr/bin/python ++import fcntl, struct ++import time ++from os import path ++ ++RNDADDENTROPY=0x40085203 ++ ++def avail(): ++ with open("/proc/sys/kernel/random/entropy_avail", mode='r') as avail: ++ return int(avail.read()) ++ ++if path.exists("/proc/sys/kernel/random/entropy_avail"): ++ while 1: ++ while avail() < 2048: ++ with open('/dev/urandom', 'rb') as urnd, open("/dev/random", mode='wb') as rnd: ++ d = urnd.read(512) ++ t = struct.pack('ii', 4 * len(d), len(d)) + d ++ fcntl.ioctl(rnd, RNDADDENTROPY, t) ++ time.sleep(30) +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts-init.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts-init.sh +new file mode 100755 +index 000000000..8a4a58946 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts-init.sh +@@ -0,0 +1,72 @@ ++#!/bin/bash ++ ++# Platform init script ++ ++# Load required kernel-mode drivers ++load_kernel_drivers() { ++ # Remove modules loaded during Linux init ++ # FIX-ME: This will be removed in the future when Linux init no longer loads these ++ rmmod i2c_dev ++ rmmod i2c_mv64xxx ++ ++ # Carefully control the load order here to ensure consistent i2c bus numbering ++ modprobe i2c_mv64xxx ++ modprobe i2c_dev ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_cpld.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_max31790.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_psu.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/mvcpss.ko ++ modprobe optoe ++ modprobe jc42 ++} ++ ++# - Main entry ++ ++# Install kernel drivers required for i2c bus access ++load_kernel_drivers ++#entropy setting ++#python /etc/entropy.py ++ echo wistron_cpld 0x33 > /sys/bus/i2c/devices/i2c-0/new_device ++ echo 1227_max31790 0x2f > /sys/bus/i2c/devices/i2c-2/new_device ++ ++ echo jc42 0x1b > /sys/bus/i2c/devices/i2c-0/new_device ++ echo wistron_psu 0x58 > /sys/bus/i2c/devices/i2c-3/new_device ++ echo wistron_psu 0x59 > /sys/bus/i2c/devices/i2c-3/new_device ++ ++ tca_detect=$(i2cget -f -y 5 0x22 0x40 1>/dev/null 2>/dev/null; echo $?) ++ if [ $tca_detect -eq 0 ]; then ++ i2cset -y 5 0x22 0x54 0x22 ++ i2cset -y 5 0x22 0x55 0x22 ++ i2cset -y 5 0x22 0x56 0x22 ++ echo pcal6524 0x22 > /sys/bus/i2c/devices/i2c-5/new_device ++ else ++ echo tca6424 0x22 > /sys/bus/i2c/devices/i2c-5/new_device ++ fi ++ ++ local i ++ for i in {4..9}; ++ do ++ echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device ++ done ++ local j ++ for j in {472..495}; ++ do ++ echo $j > /sys/class/gpio/export ++ done ++ local k ++ for k in $(seq 473 4 493); do ++ echo out > /sys/class/gpio/gpio$k/direction ++ done ++ ++ for i in {0..2}; ++ do ++ echo 85000 > /sys/class/hwmon/hwmon$i/temp1_max ++ echo 80000 > /sys/class/hwmon/hwmon$i/temp1_max_hyst ++ done ++ ++ echo 80000 > /sys/class/hwmon/hwmon4/temp1_max ++ echo 85000 > /sys/class/hwmon/hwmon4/temp1_crit ++ ++ echo 1 > /sys/bus/i2c/devices/0-0033/port_led_auto ++ ++exit 0 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts_plt_setup.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts_plt_setup.sh +new file mode 100755 +index 000000000..e4f019f5a +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/es2227_54ts_plt_setup.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++ ++fw_uboot_env_cfg() ++{ ++ echo "Setting up U-Boot environment..." ++ MACH_FILE="/host/machine.conf" ++ PLATFORM=`sed -n 's/onie_platform=\(.*\)/\1/p' $MACH_FILE` ++} ++ ++es2227_54ts_profile() ++{ ++ MAC_ADDR=$(fw_printenv -n ethaddr) ++ find /usr/share/sonic/device/*es2227_54ts* -name profile.ini | xargs sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" ++ echo "es2227_54ts: Updating switch mac address ${MAC_ADDR}" ++} ++ ++update_modulelist() ++{ ++ MODULE_FILE="/etc/modules-load.d/marvell.conf" ++ ++ echo "# Module list to load during the boot" > $MODULE_FILE ++ echo "mvcpss" >> $MODULE_FILE ++ echo "psample" >> $MODULE_FILE ++} ++ ++main() ++{ ++ fw_uboot_env_cfg ++ es2227_54ts_profile ++ update_modulelist ++} ++ ++main $@ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/fw_env.config b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/fw_env.config +new file mode 100644 +index 000000000..ea22bf4a3 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/scripts/fw_env.config +@@ -0,0 +1 @@ ++/dev/mtd1 0x0 0x10000 0x10000 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-init.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-init.service +new file mode 100644 +index 000000000..96b592804 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-init.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts Service ++Before=pmon.service ++After=sysinit.target ++DefaultDependencies=no ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/es2227_54ts-init.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-oob-led.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-oob-led.service +new file mode 100644 +index 000000000..2cc457560 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-oob-led.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es2227_54ts OOB LED Service ++After=pmon.service es2227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/usr/bin/sleep 20 ++ExecStart=/usr/local/bin/es2227_54ts-oob-led.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-psu-monitor.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-psu-monitor.service +new file mode 100644 +index 000000000..0621b2073 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-psu-monitor.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts psu monitor Service ++After=pmon.service es2227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/psu_detect.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-rst_button.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-rst_button.service +new file mode 100644 +index 000000000..5a269be55 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-rst_button.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es2227_54ts Reset Button Service ++After=pmon.service es2227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/usr/bin/sleep 20 ++ExecStart=/usr/bin/python3 /usr/local/bin/rst_button.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sensor_conf.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sensor_conf.service +new file mode 100644 +index 000000000..57988a699 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sensor_conf.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es2227_54ts sensor conf Service ++After=pmon.service es2227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/bin/sleep 60 ++ExecStart=/bin/bash /usr/local/bin/sensor_conf.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=60s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sysled.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sysled.service +new file mode 100644 +index 000000000..1811104b1 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/service/es2227_54ts-sysled.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts system LED Service ++After=pmon.service es2227_54ts-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/sysled_health.py ++Restart=on-failure ++RestartSec=5 ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/setup.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/setup.py +new file mode 100644 +index 000000000..7675f61d2 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/setup.py +@@ -0,0 +1,32 @@ ++from setuptools import setup ++ ++ ++setup( ++ name='sonic-platform', ++ version='1.0', ++ description='SONiC platform API implementation on Wistron Platforms', ++ license='Apache 2.0', ++ author='SONiC Team', ++ author_email='linuxnetdev@microsoft.com', ++ url='https://github.com/Azure/sonic-buildimage', ++ maintainer='ChihPei Chang', ++ maintainer_email='ChihPei_Chang@wistron.com', ++ packages=[ ++ 'sonic_platform', ++ ], ++ package_dir={'sonic_platform': 'sonic_platform'}, ++ classifiers=[ ++ 'Development Status :: 3 - Alpha', ++ 'Environment :: Plugins', ++ 'Intended Audience :: Developers', ++ 'Intended Audience :: Information Technology', ++ 'Intended Audience :: System Administrators', ++ 'License :: OSI Approved :: Apache Software License', ++ 'Natural Language :: English', ++ 'Operating System :: POSIX :: Linux', ++ 'Programming Language :: Python :: 2.7', ++ 'Topic :: Utilities', ++ ], ++ keywords='sonic SONiC platform PLATFORM', ++) ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/__init__.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/__init__.py +new file mode 100644 +index 000000000..4bfefa0fb +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/__init__.py +@@ -0,0 +1,3 @@ ++__all__ = ["platform", "chassis"] ++from sonic_platform import * ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/chassis.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/chassis.py +new file mode 100644 +index 000000000..2a08dbda2 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/chassis.py +@@ -0,0 +1,464 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Chassis information which are available in the platform ++# ++############################################################################# ++try: ++ import sys ++ import os ++ import time ++ import subprocess ++ from sonic_platform_base.chassis_base import ChassisBase ++ from sonic_platform.fan import Fan ++ from sonic_platform.psu import Psu ++ from sonic_platform.component import Component ++ from sonic_platform.thermal import Thermal ++ from sonic_platform.sfp import Sfp ++ from sonic_platform.eeprom import Tlv ++ from sonic_platform.fan_drawer import FanDrawer ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++NUM_FANTRAY = 2 ++NUM_PSU = 2 ++NUM_THERMAL = 14 ++COPPER_PORT_START = 1 ++COPPER_PORT_END = 48 ++SFP_BASE = 49 ++NUM_SFP = 6 ++NUM_COMPONENT = 3 ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" ++PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" ++REBOOT_CAUSE_FILE = "reboot-cause.txt" ++PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" ++HOST_CHK_CMD = "docker > /dev/null 2>&1" ++GET_HWSKU_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.hwsku" ++GET_PLATFORM_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.platform" ++GET_HOST_HWSKU_CMD = 'grep ^onie_machine= /host/machine.conf | cut -f2 -d"="' ++GET_HOST_PLATFORM_CMD = 'grep ^onie_platform /host/machine.conf | cut -f2 -d"="' ++ ++class Chassis(ChassisBase): ++ """Platform-specific Chassis class""" ++ ++ def __init__(self): ++ super(Chassis, self).__init__() ++ ++ # Initialize SKU name and Platform name ++ self.sku_name = self._get_sku_name() ++ self.platform_name = self._get_platform_name() ++ self.name = self.sku_name ++ self.COPPER_PORT_START = COPPER_PORT_START ++ self.COPPER_PORT_END = COPPER_PORT_END ++ ++ ++ for fan_index in range(0, NUM_FANTRAY): ++ fandrawer = FanDrawer(fan_index) ++ self._fan_drawer_list.append(fandrawer) ++ self._fan_list.extend(fandrawer._fan_list) ++ ++ for index in range(0, NUM_PSU): ++ psu = Psu(index) ++ self._psu_list.append(psu) ++ ++ for index in range(0, NUM_THERMAL): ++ thermal = Thermal(index) ++ self._thermal_list.append(thermal) ++ ++ # for non-sfp ports create dummy objects for copper / non-sfp ports ++ for index in range(self.COPPER_PORT_START, self.COPPER_PORT_END+1): ++ port=index-1 ++ sfp_node = Sfp(index, 'COPPER') ++ self._sfp_list.append(sfp_node) ++ ++ for index in range(SFP_BASE, SFP_BASE + NUM_SFP): ++ sfp_module = Sfp(index, 'SFP') ++ self._sfp_list.append(sfp_module) ++ ++ from sonic_platform.component import Component ++ for index in range(0, NUM_COMPONENT): ++ component = Component(index) ++ self._component_list.append(component) ++ ++ self._eeprom = Tlv() ++ self._transceiver_presence = [0] * (SFP_BASE + NUM_SFP - 1) ++ ++ def __is_host(self): ++ return os.system(HOST_CHK_CMD) == 0 ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def get_base_mac(self): ++ """ ++ Retrieves the base MAC address for the chassis ++ Returns: ++ A string containing the MAC address in the format ++ 'XX:XX:XX:XX:XX:XX' ++ """ ++ return self._eeprom.get_mac() ++ ++ def get_serial(self): ++ """ ++ Retrieves the hardware serial number for the chassis ++ Returns: ++ A string containing the hardware serial number for this chassis. ++ """ ++ return self._eeprom.get_serial() ++ ++ def get_system_eeprom_info(self): ++ """ ++ Retrieves the full content of system EEPROM information for the chassis ++ Returns: ++ A dictionary where keys are the type code defined in ++ OCP ONIE TlvInfo EEPROM format and values are their corresponding ++ values. ++ """ ++ return self._eeprom.get_eeprom() ++ ++ def get_firmware_version(self, component_name): ++ """ ++ Retrieves platform-specific hardware/firmware versions for chassis ++ componenets such as BIOS, CPLD, FPGA, etc. ++ Args: ++ type: A string, component name ++ ++ Returns: ++ A string containing platform-specific component versions ++ """ ++ self.component = Component(component_name) ++ if component_name not in self._component_name_list: ++ return None ++ return self.component.get_firmware_version() ++ ++ def install_component_firmware(self, component_name, image_path): ++ """ ++ Install firmware to module ++ Args: ++ type: A string, component name. ++ image_path: A string, path to firmware image. ++ ++ Returns: ++ A boolean, True if install successfully, False if not ++ """ ++ self.component = Component(component_name) ++ if component_name not in self._component_name_list: ++ return False ++ return self.component.upgrade_firmware(image_path) ++ ++ def get_reboot_cause(self): ++ """ ++ Retrieves the cause of the previous reboot ++ ++ Returns: ++ A tuple (string, string) where the first element is a string ++ containing the cause of the previous reboot. This string must be ++ one of the predefined strings in this class. If the first string ++ is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used ++ to pass a description of the reboot cause. ++ """ ++ ++ reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host( ++ ) else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE ++ sw_reboot_cause = self.__read_txt_file( ++ reboot_cause_path) or "Unknown" ++ ++ if sw_reboot_cause != "Unknown": ++ reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE ++ description = sw_reboot_cause ++ else: ++ reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER ++ description = 'Unknown reason' ++ ++ return (reboot_cause, description) ++ ++ def _get_sku_name(self): ++ if self.__is_host(): ++ p = subprocess.Popen(GET_HOST_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) ++ else: ++ p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) ++ out, err = p.communicate() ++ return out.decode().rstrip('\n') ++ ++ def _get_platform_name(self): ++ if self.__is_host(): ++ p = subprocess.Popen(GET_HOST_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) ++ else: ++ p = subprocess.Popen(GET_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) ++ out, err = p.communicate() ++ return out.decode().rstrip('\n') ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return self.name ++ ++ def get_sfp(self, index): ++ sfp = None ++ try: ++ sfp = self._sfp_list[index - 1] ++ except IndexError: ++ sys.stderr.write("SFP index {} out of range (1-{})\n".format(index, len(self._sfp_list))) ++ ++ return sfp ++ ++ def _get_sfp_presence(self): ++ port_pres = {} ++ for port in range(0, SFP_BASE + NUM_SFP - 1): ++ sfp = self._sfp_list[port] ++ port_pres[port] = sfp.get_presence() ++ ++ return port_pres ++ ++ def get_change_event(self, timeout=0): ++ port_dict = {} ++ ret_dict = {'sfp': port_dict} ++ forever = False ++ change_event = False ++ ++ if timeout == 0: ++ forever = True ++ elif timeout > 0: ++ timeout = timeout / float(1000) ++ else: ++ return False, ret_dict #Incorrect timeout ++ ++ while True: ++ if forever: ++ timer = 1 ++ else: ++ timer = min(timeout, 1) ++ start_time = time.time() ++ ++ time.sleep(timer) ++ cur_presence = self._get_sfp_presence() ++ for port in range(0, SFP_BASE + NUM_SFP - 1): ++ if cur_presence[port] != self._transceiver_presence[port]: ++ change_event = True ++ if cur_presence[port] == 1: ++ port_dict[port + 1] = '1' ++ else: ++ port_dict[port + 1] = '0' ++ ++ self._transceiver_presence = cur_presence ++ if change_event == True: ++ break ++ ++ if not forever: ++ elapsed_time = time.time() - start_time ++ timeout = round(timeout - elapsed_time, 3) ++ if timeout <= 0: ++ break ++ ++ return True, ret_dict ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._eeprom.get_model() ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ ++ return '0' ++ ++ def get_watchdog(self): ++ """ ++ Retrieves hardware watchdog device on this chassis ++ ++ Returns: ++ An object derived from WatchdogBase representing the hardware ++ watchdog device ++ """ ++ try: ++ if self._watchdog is None: ++ from sonic_platform.watchdog import WatchdogImplBase ++ watchdog_device = "watchdog1" ++ self._watchdog = WatchdogImplBase(watchdog_device) ++ except Exception as e: ++ sonic_logger.log_warning(" Fail to load watchdog {}".format(repr(e))) ++ ++ return self._watchdog ++ ++ def initizalize_system_led(self): ++ self.system_led = "" ++ return True ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the system LED ++ ++ Args: ++ color: A string representing the color with which to set the ++ system LED ++ ++ Returns: ++ bool: True if system LED state is set successfully, False if not ++ """ ++ ++ self.system_led = color ++ ++ sysled_path="{}/sys_led".format(CPLD_SYSFS_DIR) ++ psuled_path="{}/psu_led".format(CPLD_SYSFS_DIR) ++ fanled_path="{}/fan_led".format(CPLD_SYSFS_DIR) ++ watchdog_update_path="{}/watchdog_kick".format(CPLD_SYSFS_DIR) ++ ++ #if color == "red": ++ # val = 2 ++ #elif color == "green_blinking": ++ # val = 3 ++ #elif color == "green": ++ # val = 1 ++ ++ color=int(self.__read_txt_file(sysled_path)) ++ if color is None: ++ return True ++ if color != 1 and color != 2: ++ self.__write_txt_file(sysled_path, str(1)) ++ self.__write_txt_file(watchdog_update_path, str(1)) ++ ++ fan_sta = True ++ psu_sta = True ++ ++ #clear fault before we update the fan statue led ++ for fan_index in range(0, NUM_FANTRAY): ++ sta=self._fan_drawer_list[fan_index].get_status() ++ if not sta: ++ self._fan_drawer_list[fan_index]._fan_list[0].try_clear_fault() ++ ++ for fan_index in range(0, NUM_FANTRAY): ++ sta=self._fan_drawer_list[fan_index].get_status() ++ prs=self._fan_drawer_list[fan_index].get_presence() ++ fan_sta = fan_sta & sta ++ if sta and prs: ++ val=1 ++ else: ++ val=2 ++ led_path="{}/fan{}_led".format(CPLD_SYSFS_DIR, fan_index+1) ++ self.__write_txt_file(led_path, str(val)) ++ ++ if fan_sta: ++ val = 1 ++ else: ++ val = 2 ++ self.__write_txt_file(fanled_path, str(val)) ++ ++ for index in range(0, NUM_PSU): ++ sta=self._psu_list[index].get_status() ++ psu_sta = psu_sta & sta ++ if psu_sta: ++ val = 1 ++ else: ++ val = 2 ++ self.__write_txt_file(psuled_path, str(val)) ++ ++ return True ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the system LED ++ ++ Returns: ++ A string, one of the valid LED color strings which could be vendor ++ specified. ++ """ ++ return self.system_led ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ return None ++ ++ def get_port_or_cage_type(self, index): ++ """ ++ Retrieves sfp port or cage type corresponding to physical port ++ ++ Args: ++ index: An integer (>=0), the index of the sfp to retrieve. ++ The index should correspond to the physical port in a chassis. ++ For example:- ++ 1 for Ethernet0, 2 for Ethernet4 and so on for one platform. ++ 0 for Ethernet0, 1 for Ethernet4 and so on for another platform. ++ ++ Returns: ++ The masks of all types of port or cage that can be supported on the port ++ Types are defined in sfp_base.py ++ Eg. ++ Both SFP and SFP+ are supported on the port, the return value should be 0x0a ++ which is 0x02 | 0x08 ++ """ ++ index = index - 1 ++ if index < COPPER_PORT_END: ++ from sonic_platform_base.sfp_base import SfpBase ++ return SfpBase.SFP_PORT_TYPE_BIT_RJ45 ++ raise NotImplementedError ++ ++ def power_down(self): ++ power_down_path="{}/system_power_down".format(CPLD_SYSFS_DIR) ++ self.__write_txt_file(power_down_path, str(0)) ++ ++ def set_sysled_red(self): ++ sysled_path="{}/sys_led".format(CPLD_SYSFS_DIR) ++ self.__write_txt_file(sysled_path, str(2)) ++ ++ def get_thermal_manager(self): ++ from .thermal_manager import ThermalManager ++ return ThermalManager ++ ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the Chassis ++ Returns: ++ bool: True if Chassis is present, False if not ++ """ ++ return True ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/component.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/component.py +new file mode 100644 +index 000000000..c2760be45 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/component.py +@@ -0,0 +1,186 @@ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in ++# the platform ++# ++######################################################################## ++ ++try: ++ import sys ++ import subprocess ++ from sonic_platform_base.component_base import ComponentBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++if sys.version_info[0] < 3: ++ import commands as cmd ++else: ++ import subprocess as cmd ++ ++ ++class Component(ComponentBase): ++ """platform-specific Component class""" ++ ++ CHASSIS_COMPONENTS = [ ++ ["U-Boot", "Performs initialization during booting"], ++ ["ONIE-VERSION", "ONIE - Open Network Install Environment"], ++ ["CPLD", "CPLD firmware"], ++ ] ++ ++ def __init__(self, component_index): ++ self.index = component_index ++ self.name = self.CHASSIS_COMPONENTS[self.index][0] ++ self.description = self.CHASSIS_COMPONENTS[self.index][1] ++ ++ def _get_command_result(self, cmdline): ++ try: ++ proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ stdout = proc.communicate()[0] ++ proc.wait() ++ result = stdout.rstrip('\n') ++ except OSError: ++ result = None ++ ++ return result ++ ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the component ++ ++ Returns: ++ A string containing the name of the component ++ """ ++ return self.name ++ ++ def get_description(self): ++ """ ++ Retrieves the description of the component ++ ++ Returns: ++ A string containing the description of the component ++ """ ++ return self.description ++ ++ def get_firmware_version(self): ++ """ ++ Retrieves the firmware version of the component ++ ++ Returns: ++ A string containing the firmware version of the component ++ """ ++ ++ if self.index == 0: ++ cmdstatus, uboot_version = cmd.getstatusoutput('grep --null-data ^U-Boot /dev/mtd0 | tail -n 1 | cut -d" " -f2') ++ return uboot_version ++ ++ if self.index == 1: ++ cmdstatus, onie_version = cmd.getstatusoutput('grep ^onie_version /host/machine.conf | cut -f2 -d"="') ++ return onie_version ++ ++ if self.index == 2: ++ cmdstatus, cpld_ver = cmd.getstatusoutput('cat /sys/bus/i2c/devices/0-0033/cpld_rev') ++ return cpld_ver ++ ++ def install_firmware(self, image_path): ++ """ ++ Installs firmware to the component ++ ++ Args: ++ image_path: A string, path to firmware image ++ ++ Returns: ++ A boolean, True if install was successful, False if not ++ """ ++ return False ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if FAN is present, False if not ++ """ ++ return True ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return 'N/A' ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return 'N/A' ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False ++ ++ def get_available_firmware_version(self, image_path): ++ """ ++ Retrieves the available firmware version of the component ++ Note: the firmware version will be read from image ++ Args: ++ image_path: A string, path to firmware image ++ Returns: ++ A string containing the available firmware version of the component ++ """ ++ return "N/A" ++ ++ def get_firmware_update_notification(self, image_path): ++ """ ++ Retrieves a notification on what should be done in order to complete ++ the component firmware update ++ Args: ++ image_path: A string, path to firmware image ++ Returns: ++ A string containing the component firmware update notification if required. ++ By default 'None' value will be used, which indicates that no actions are required ++ """ ++ return "None" ++ ++ def update_firmware(self, image_path): ++ """ ++ Updates firmware of the component ++ This API performs firmware update: it assumes firmware installation and loading in a single call. ++ In case platform component requires some extra steps (apart from calling Low Level Utility) ++ to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API ++ Args: ++ image_path: A string, path to firmware image ++ Raises: ++ RuntimeError: update failed ++ """ ++ return False +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/eeprom.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/eeprom.py +new file mode 100644 +index 000000000..ae9fe3513 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/eeprom.py +@@ -0,0 +1,120 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# Platform and model specific eeprom subclass, inherits from the base class, ++# and provides the followings: ++# - the eeprom format definition ++# - specific encoder/decoder if there is special need ++############################################################################# ++ ++try: ++ import glob ++ import os ++ import sys ++ import imp ++ import re ++ from array import array ++ from io import StringIO ++ from sonic_platform_base.sonic_eeprom import eeprom_dts ++ from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' ++CACHE_FILE = 'syseeprom_cache' ++ ++ ++class Tlv(eeprom_tlvinfo.TlvInfoDecoder): ++ ++ EEPROM_DECODE_HEADLINES = 6 ++ ++ def __init__(self): ++ self._eeprom_path = "/sys/bus/i2c/devices/0-0055/eeprom" ++ super(Tlv, self).__init__(self._eeprom_path, 0, '', True) ++ self._eeprom = self._load_eeprom() ++ ++ def __parse_output(self, decode_output): ++ decode_output.replace('\0', '') ++ lines = decode_output.split('\n') ++ lines = lines[self.EEPROM_DECODE_HEADLINES:] ++ _eeprom_info_dict = dict() ++ ++ for line in lines: ++ try: ++ match = re.search( ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+[\s]+[\S]+)', line) ++ if match is not None and match.group(1) == '0x25': ++ idx = match.group(1) ++ value = match.group(3).rstrip('\0') ++ _eeprom_info_dict[idx] = value ++ else: ++ match = re.search( ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) ++ if match is not None: ++ idx = match.group(1) ++ value = match.group(3).rstrip('\0') ++ _eeprom_info_dict[idx] = value ++ ++ except BaseException: ++ pass ++ return _eeprom_info_dict ++ ++ def _load_eeprom(self): ++ original_stdout = sys.stdout ++ sys.stdout = StringIO() ++ try: ++ self.read_eeprom_db() ++ except Exception: ++ decode_output = sys.stdout.getvalue() ++ sys.stdout = original_stdout ++ return self.__parse_output(decode_output) ++ ++ status = self.check_status() ++ if status < 'ok': ++ return False ++ ++ if not os.path.exists(CACHE_ROOT): ++ try: ++ os.makedirs(CACHE_ROOT) ++ except: ++ pass ++ ++ # ++ # only the eeprom classes that inherit from eeprom_base ++ # support caching. Others will work normally ++ # ++ try: ++ self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) ++ except: ++ pass ++ ++ e = self.read_eeprom() ++ if e is None: ++ return 0 ++ ++ try: ++ self.update_cache(e) ++ except: ++ pass ++ ++ self.decode_eeprom(e) ++ decode_output = sys.stdout.getvalue() ++ sys.stdout = original_stdout ++ ++ (is_valid, valid_crc) = self.is_checksum_valid(e) ++ if not is_valid: ++ return False ++ ++ return self.__parse_output(decode_output) ++ ++ def get_eeprom(self): ++ return self._eeprom ++ ++ def get_serial(self): ++ return self._eeprom.get('0x23', "Undefined.") ++ ++ def get_mac(self): ++ return self._eeprom.get('0x24', "Undefined.") ++ ++ def get_model(self): ++ return self._eeprom.get('0x21', "Undefined.") +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan.py +new file mode 100644 +index 000000000..42445fdd4 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan.py +@@ -0,0 +1,366 @@ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the fan status which are available in the platform ++# ++############################################################################# ++ ++ ++import os.path ++import time ++ ++try: ++ from sonic_platform.eeprom import Tlv ++ from sonic_platform_base.fan_base import FanBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++PSU_FAN_MAX_RPM = 18000 ++SPEED_TOLERANCE = 15 ++SYSFS_PATH = "/sys/bus/i2c/devices/{0}-00{1}" ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++HWMON_PATH = "/sys/bus/i2c/devices/{0}-00{1}/hwmon" ++PSU_HWMON_I2C_MAPPING = { ++ 0: { ++ "num": 3, ++ "addr": "59" ++ }, ++ 1: { ++ "num": 3, ++ "addr": "58" ++ }, ++} ++ ++FAN_HWMON_I2C_MAPPING = { ++ 0: { ++ "num": 2, ++ "addr": "2f" ++ }, ++} ++ ++#FAN_PCA9539_I2C_MAPPING = { ++# 0: { ++# "num": 9, ++# "addr": "74" ++# }, ++# 1: { ++# "num": 9, ++# "addr": "76" ++# }, ++#} ++ ++# 3 fan sku not exist now ++#FAN_ROTOR_MAPPING = { ++# 0: 1, ++# 1: 8, ++# 2: 4 ++#} ++ ++#FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"] ++ ++FAN_ROTOR_MAPPING = { ++ 0: 4, ++ 1: 8 ++} ++ ++FAN_NAME_LIST = ["FAN-1", "FAN-2"] ++ ++class Fan(FanBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): ++ self.fan_index = fan_index ++ self.fan_tray_index = fan_tray_index ++ self.is_psu_fan = is_psu_fan ++ self.pwm_conv=[] ++ ++ if self.is_psu_fan: ++ self.psu_index = psu_index ++ self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] ++ self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] ++ hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++ self.psu_i2c_num, self.psu_i2c_addr)) ++ self.psu_hwmon_path = os.path.join(HWMON_PATH.format(self.psu_i2c_num, self.psu_i2c_addr), hwmon_dir) ++ ++ self.psu_status_path = CPLD_SYSFS_DIR ++ else: ++ self.fan_i2c_num = FAN_HWMON_I2C_MAPPING[0]['num'] ++ self.fan_i2c_addr = FAN_HWMON_I2C_MAPPING[0]['addr'] ++ hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++ self.fan_i2c_num, self.fan_i2c_addr)) ++ self.fan_hwmon_path = os.path.join(HWMON_PATH.format(self.fan_i2c_num, self.fan_i2c_addr), hwmon_dir) ++ ++ self.fan_status_path = CPLD_SYSFS_DIR ++ ++# self.an_fan_i2c_num = FAN_HWMON_I2C_MAPPING[1]['num'] ++# self.an_fan_i2c_addr = FAN_HWMON_I2C_MAPPING[1]['addr'] ++# hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++# self.fan_i2c_num, self.fan_i2c_addr)) ++# self.an_fan_hwmon_path = os.path.join(HWMON_PATH.format(self.fan_i2c_num, self.fan_i2c_addr), hwmon_dir) ++ ++# self.fan_sts_i2c_num = FAN_PCA9539_I2C_MAPPING[0 if fan_tray_index < 3 else 1]['num'] ++# self.fan_sts_i2c_addr = FAN_PCA9539_I2C_MAPPING[0 if fan_tray_index < 3 else 1]['addr'] ++# self.fan_status_path = SYSFS_PATH.format(self.fan_sts_i2c_num, self.fan_sts_i2c_addr) ++ ++ ++ self._eeprom = Tlv() ++ ++ for i in range(0, 101): ++ self.pwm_conv.append(int(i * 255 / 100)) ++ ++ FanBase.__init__(self) ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ 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 = 0 ++ if self.is_psu_fan: ++ if self.get_presence(): ++ path_pre=SYSFS_PATH.format(self.psu_i2c_num, self.psu_i2c_addr) ++ psu_fan_path= "{}/{}".format(path_pre, 'mfr_model') ++ model=self.__read_txt_file(psu_fan_path) ++ if model is None: ++ direction = 0 ++ direction = 0 if 'WNA' in model else 1 ++ elif self.get_presence(): ++ part=self._eeprom.get_model() ++ direction = 0 if 'ES-2227-54TS-O' in part else 1 ++ ++ return self.FAN_DIRECTION_EXHAUST if int(direction) == 0 else self.FAN_DIRECTION_INTAKE ++ ++ def get_speed(self): ++ """ ++ Retrieves the speed of fan as a percentage of full speed ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ ++ """ ++ speed = 0 ++ if self.is_psu_fan: ++ psu_fan_path= "{}/{}".format(self.psu_hwmon_path, 'fan1_input') ++ rpm=self.__read_txt_file(psu_fan_path) ++ if rpm is None: ++ return 0 ++ speed = int(int(rpm) * 100 / PSU_FAN_MAX_RPM) ++ elif self.get_presence(): ++ path= "{}/pwm1".format(self.fan_hwmon_path) ++ pwm=self.__read_txt_file(path) ++ if pwm is None: ++ return 0 ++ elif int(pwm) == 77: ++ pwm = 76 ++ speed = self.pwm_conv.index(int(pwm)) ++ ++ return int(speed) ++ ++ def get_target_speed(self): ++ """ ++ Retrieves the target (expected) speed of the fan ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ ++ Note: ++ speed_pc = pwm_target/255*100 ++ ++ 0 : when PWM mode is use ++ pwm : when pwm mode is not use ++ """ ++ return self.get_speed() ++ ++ def get_speed_tolerance(self): ++ """ ++ Retrieves the speed tolerance of the fan ++ Returns: ++ An integer, the percentage of variance from target speed which is ++ considered tolerable ++ """ ++ return SPEED_TOLERANCE ++ ++ def set_speed(self, speed): ++ """ ++ Sets the fan speed ++ Args: ++ speed: An integer, the percentage of full fan speed to set fan to, ++ in the range 0 (off) to 100 (full speed) ++ Returns: ++ A boolean, True if speed is set successfully, False if not ++ ++ """ ++ ++ if not self.is_psu_fan and self.get_presence(): ++ pwm = int((speed * 255) / 100) ++ speed_path = "{}/{}".format(self.fan_hwmon_path, 'pwm1') ++ self.__write_txt_file(speed_path, str(pwm)) ++# speed_path = "{}/{}".format(self.an_fan_hwmon_path, 'pwm1') ++# self.__write_txt_file(speed_path, int(speed)) ++ ++ return True ++ ++ return False ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the fan module status LED ++ Args: ++ color: A string representing the color with which to set the ++ fan module status LED ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ if color is self.STATUS_LED_COLOR_GREEN: ++ val = 1 ++ else: ++ val = 2 ++ ++ led_path="{}/fan{}_led".format(self.fan_status_path, self.fan_tray_index+1) ++ self.__write_txt_file(led_path, str(val)) ++ ++ return True ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ status=self.get_presence() ++ if status is None: ++ return self.STATUS_LED_COLOR_OFF ++ ++ return { ++ 1: self.STATUS_LED_COLOR_GREEN, ++ 0: self.STATUS_LED_COLOR_RED ++ }.get(status, self.STATUS_LED_COLOR_OFF) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ fan_name = FAN_NAME_LIST[self.fan_tray_index + self.fan_index] \ ++ if not self.is_psu_fan \ ++ else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) ++ ++ return fan_name ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if FAN is present, False if not ++ """ ++ ++ ++ if self.is_psu_fan: ++ present_path="{}/psu{}_present".format(self.psu_status_path, self.psu_index+1) ++ else: ++ present_path="{}/cnfan{}_present".format(self.fan_status_path, self.fan_tray_index+1) ++ ++ val=self.__read_txt_file(present_path) ++ if val is not None: ++ return int(val, 10)==1 ++ else: ++ return False ++ ++ def try_clear_fault(self): ++ path= "{}/pwm1".format(self.fan_hwmon_path) ++ speed=self.__read_txt_file(path) ++ ++ self.__write_txt_file(path, str(speed)) ++ time.sleep(2) ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ if self.is_psu_fan: ++ psu_fan_path= "{}/{}".format(self.psu_hwmon_path, 'fan1_fault') ++ val=self.__read_txt_file(psu_fan_path) ++ if val is not None: ++ return int(val, 10)==0 ++ else: ++ return False ++ else: ++ path= "{}/fan{}_fault".format(self.fan_hwmon_path, FAN_ROTOR_MAPPING[self.fan_tray_index + self.fan_index]) ++ val=self.__read_txt_file(path) ++ if val is not None: ++ return int(val, 10)==0 ++ else: ++ return False ++ ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ ++ return "N/A" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "N/A" ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return (self.fan_tray_index+1) \ ++ if not self.is_psu_fan else (self.psu_index+1) ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return True if not self.is_psu_fan else False ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan_drawer.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan_drawer.py +new file mode 100644 +index 000000000..0f9f7c31b +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/fan_drawer.py +@@ -0,0 +1,108 @@ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Fan-Drawers' information available in the platform. ++# ++######################################################################## ++ ++try: ++ from sonic_platform_base.fan_drawer_base import FanDrawerBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++FANS_PER_FANTRAY = 1 ++MAX_FAN_WATT = 7.2 ++ ++class FanDrawer(FanDrawerBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, fantray_index): ++ ++ FanDrawerBase.__init__(self) ++ # FanTray is 0-based in platforms ++ self.fantrayindex = fantray_index ++ self.__initialize_fan_drawer() ++ ++ ++ def __initialize_fan_drawer(self): ++ from sonic_platform.fan import Fan ++ for i in range(FANS_PER_FANTRAY): ++ self._fan_list.append(Fan(self.fantrayindex, i)) ++ ++ def get_name(self): ++ """ ++ Retrieves the fan drawer name ++ Returns: ++ string: The name of the device ++ """ ++ return "FanTray{}".format(self.fantrayindex+1) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ return self._fan_list[0].get_presence() ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._fan_list[0].get_model() ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return self._fan_list[0].get_serial() ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return self._fan_list[0].get_status() ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan drawer LED ++ ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ return self._fan_list[0].get_status_led() ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return (self.fantrayindex+1) ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return True ++ ++ def get_maximum_consumed_power(self): ++ """ ++ Retrives the maximum power drawn by Fan Drawer ++ Returns: ++ A float, with value of the maximum consumable power of the ++ component. ++ """ ++ return MAX_FAN_WATT +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/pcie.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/pcie.py +new file mode 100644 +index 000000000..273767cfb +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/pcie.py +@@ -0,0 +1,47 @@ ++######################################################################## ++# Copyright (C) 2021, mrvl CORPORATION & AFFILIATES. All rights reserved. ++# Module contains a platform specific implementation of SONiC Platform ++# Base PCIe class ++######################################################################## ++import os ++import re ++ ++try: ++ from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++SYSFS_PCI_DEVICE_PATH = '/sys/bus/pci/devices/' ++ ++class Pcie(PcieUtil): ++ def get_pcie_check(self): ++ self.load_config_file() ++ for item_conf in self.confInfo: ++ id_conf = item_conf["id"] ++ dev_conf = item_conf["dev"] ++ fn_conf = item_conf["fn"] ++ bus_conf = self._device_id_to_bus_map.get(str(id_conf)) ++ if bus_conf and self.check_pcie_sysfs(bus=int(bus_conf, base=16), device=int(dev_conf, base=16), ++ func=int(fn_conf, base=16)): ++ item_conf["result"] = "Passed" ++ else: ++ item_conf["result"] = "Failed" ++ return self.confInfo ++ ++ def _create_device_id_to_bus_map(self): ++ self._device_id_to_bus_map = {} ++ self.load_config_file() ++ device_folders = os.listdir(SYSFS_PCI_DEVICE_PATH) ++ for folder in device_folders: ++ pattern_for_device_folder = re.search('....:(..):..\..', folder) ++ if pattern_for_device_folder: ++ bus = pattern_for_device_folder.group(1) ++ with open(os.path.join(SYSFS_PCI_DEVICE_PATH, folder, 'device'), 'r') as device_file: ++ # The 'device' file contain an hex repesantaion of the id key in the yaml file. ++ # We will strip the new line character, and remove the 0x prefix that is not needed. ++ device_id = device_file.read().strip().replace('0x', '') ++ self._device_id_to_bus_map[device_id] = bus ++ ++ def __init__(self, platform_path): ++ PcieUtil.__init__(self, platform_path) ++ self._create_device_id_to_bus_map() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/platform.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/platform.py +new file mode 100644 +index 000000000..0b67a68b8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/platform.py +@@ -0,0 +1,22 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the platform information ++# ++############################################################################# ++ ++try: ++ from sonic_platform_base.platform_base import PlatformBase ++ from sonic_platform.chassis import Chassis ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Platform(PlatformBase): ++ ++ def __init__(self): ++ PlatformBase.__init__(self) ++ self._chassis = Chassis() ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/psu.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/psu.py +new file mode 100755 +index 000000000..928fae682 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/psu.py +@@ -0,0 +1,359 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# psuutil.py ++# Platform-specific PSU status interface for SONiC ++############################################################################# ++ ++import os.path ++import sonic_platform ++ ++try: ++ from sonic_platform_base.psu_base import PsuBase ++ from sonic_platform.fan import Fan ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++PSU_NAME_LIST = ["PSU-1", "PSU-2"] ++ ++PSU_HWMON_PATH = "/sys/bus/i2c/devices/{0}-00{1}/hwmon" ++PSU_SYSFS_PATH = "/sys/bus/i2c/devices/{0}-00{1}" ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++PSU_I2C_MAPPING = { ++ 0: { ++ "bus": 3, ++ "addr": "59" ++ }, ++ 1: { ++ "bus": 3, ++ "addr": "58" ++ }, ++} ++ ++ ++class Psu(PsuBase): ++ """Platform-specific Psu class""" ++ ++ def __init__(self, psu_index): ++ self.PSU_TEMP_MAX = 68000 ++ self.PSU_OUTPUT_POWER_MAX = 420000000 ++ self.PSU_OUTPUT_VOLTAGE_MIN = 40000 ++ self.PSU_OUTPUT_VOLTAGE_MAX = 62000 ++ self.index = psu_index ++ PsuBase.__init__(self) ++ self.i2c_num = PSU_I2C_MAPPING[self.index]["bus"] ++ self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] ++ self.hwmon_path = PSU_HWMON_PATH.format(self.i2c_num, self.i2c_addr) ++ self.sysfs_path = PSU_SYSFS_PATH.format(self.i2c_num, str( ++ int(self.i2c_addr))) ++ self.__initialize_fan() ++ ++ def __initialize_fan(self): ++ from sonic_platform.fan import Fan ++ for fan_index in range(0, 1): ++ fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) ++ self._fan_list.append(fan) ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def get_fan(self, index): ++ """ ++ Retrieves object representing the fan module contained in this PSU ++ Returns: ++ An object dervied from FanBase representing the fan module ++ contained in this PSU ++ """ ++ return self._fan_list[index] ++ ++ def get_powergood_status(self): ++ """ ++ Retrieves the powergood status of PSU ++ Returns: ++ A boolean, True if PSU has stablized its output voltages and passed all ++ its internal self-tests, False if not. ++ """ ++ return self.get_status() ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the PSU status LED ++ Args: ++ color: A string representing the color with which to set the PSU status LED ++ Note: Only support green and off ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ # Hardware not supported ++ return False ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the PSU status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ if self.get_presence(): ++ if self.get_powergood_status(): ++ return self.STATUS_LED_COLOR_GREEN ++ else: ++ return self.STATUS_LED_COLOR_RED ++ else: ++ return None ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return PSU_NAME_LIST[self.index] ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the PSU ++ Returns: ++ bool: True if PSU is present, False if not ++ """ ++ attr_file = 'psu{}_present'.format(self.index + 1) ++ attr_path = CPLD_SYSFS_DIR + '/' + attr_file ++ status = 0 ++ try: ++ with open(attr_path, 'r') as psu_prs: ++ status = int(psu_prs.read()) ++ except IOError: ++ return False ++ ++ return status == 1 ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ attr_file = 'psu{}_power_good'.format(self.index + 1) ++ attr_path = CPLD_SYSFS_DIR + '/' + attr_file ++ status = 0 ++ if self.get_presence(): ++ try: ++ with open(attr_path, 'r') as power_status: ++ status = int(power_status.read()) ++ except IOError: ++ return False ++ ++ return status == 1 ++ ++ def get_model(self): ++ """ ++ Retrieves the model name of the PSU ++ Returns: ++ model name ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "mfr_model") ++ if os.path.exists(file_path): ++ model = self.__read_txt_file(file_path) ++ return model ++ ++ return None ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the PSU ++ Returns: ++ model serial ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "mfr_serial") ++ if os.path.exists(file_path): ++ serial = self.__read_txt_file(file_path) ++ return serial ++ ++ return None ++ ++ def get_revision(self): ++ """ ++ Retrieves the hw rev of the PSU ++ Returns: ++ model rev ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "mfr_revision") ++ if os.path.exists(file_path): ++ rev = self.__read_txt_file(file_path) ++ return rev ++ ++ return None ++ ++ def get_voltage(self): ++ """ ++ Retrieves current PSU voltage output ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 12.1 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "in2_input") ++ voltage = self.__read_txt_file(file_path) ++ if not voltage: ++ return None ++ return float(voltage) / 1000 ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from PSU ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "temp1_input") ++ temp = self.__read_txt_file(file_path) ++ if not temp: ++ return None ++ return float(temp) / 1000 ++ ++ def get_current(self): ++ """ ++ Retrieves present electric current supplied by PSU ++ Returns: ++ A float number, the electric current in amperes, e.g 15.4 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "curr2_input") ++ current = self.__read_txt_file(file_path) ++ if not current: ++ return None ++ return float(current) / 1000 ++ ++ def get_power(self): ++ """ ++ Retrieves current energy supplied by PSU ++ Returns: ++ A float number, the power in watts, e.g. 302.6 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "power2_input") ++ power = self.__read_txt_file(file_path) ++ if not power: ++ return None ++ return float(power) / 1000000 ++ ++ def get_voltage_vin(self): ++ """ ++ Retrieves current PSU voltage output ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 220.0 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "in1_input") ++ voltage = self.__read_txt_file(file_path) ++ if not voltage: ++ return None ++ return float(voltage) / 1000 ++ ++ def get_temperature_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of PSU ++ Returns: ++ A float number, the high threshold temperature of PSU in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ return float(self.PSU_TEMP_MAX/1000) ++ ++ def get_voltage_high_threshold(self): ++ """ ++ Retrieves the high threshold PSU voltage output ++ Returns: ++ A float number, the high threshold output voltage in volts, ++ e.g. 12.1 ++ """ ++ return float(self.PSU_OUTPUT_VOLTAGE_MAX/1000) ++ ++ def get_voltage_low_threshold(self): ++ """ ++ Retrieves the low threshold PSU voltage output ++ Returns: ++ A float number, the low threshold output voltage in volts, ++ e.g. 12.1 ++ """ ++ return float(self.PSU_OUTPUT_VOLTAGE_MIN/1000) ++ ++ def get_maximum_supplied_power(self): ++ """ ++ Retrieves the maximum supplied power by PSU ++ Returns: ++ A float number, the maximum power output in Watts. ++ e.g. 1200.1 ++ """ ++ return float(self.PSU_OUTPUT_POWER_MAX/(1000 * 1000)) ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.index + 1 ++ ++ def is_replaceable(self): ++ return True ++ ++ def get_num_fans(self): ++ """ ++ Retrieves the number of fan modules available on this PSU ++ ++ Returns: ++ An integer, the number of fan modules available on this PSU ++ """ ++ return len(self._fan_list) ++ ++ def get_all_fans(self): ++ """ ++ Retrieves all fan modules available on this PSU ++ ++ Returns: ++ A list of objects derived from FanBase representing all fan ++ modules available on this PSU ++ """ ++ return self._fan_list +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/sfp.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/sfp.py +new file mode 100644 +index 000000000..be5468308 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/sfp.py +@@ -0,0 +1,379 @@ ++import os ++import time ++import sys ++import subprocess ++from ctypes import create_string_buffer ++ ++try: ++ from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase ++ from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper ++ from sonic_py_common import logger ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++if sys.version_info[0] < 3: ++ import commands as cmd ++else: ++ import subprocess as cmd ++ ++COPPER_TYPE = "COPPER" ++SFP_TYPE = "SFP" ++ ++SYSLOG_IDENTIFIER = "xcvrd" ++sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) ++ ++class Sfp(SfpOptoeBase): ++ """Platform-specific Sfp class""" ++ ++ # Paths ++ EEPROM_PATH = "/sys/bus/i2c/devices/{0}-0050/eeprom" ++ GPIO_PATH = "/sys/class/gpio/gpio{0}/value" ++ ++ PORT_EEPROM_I2C_MAPPING = { ++ 49: 5, ++ 50: 4, ++ 51: 7, ++ 52: 6, ++ 53: 9, ++ 54: 8, ++ } ++ ++ PORT_PRESENT_GPIO_MAPPING = { ++ 50: 472, ++ 49: 476, ++ 52: 480, ++ 51: 484, ++ 54: 488, ++ 53: 492, ++ } ++ ++ PORT_TX_DISABLE_GPIO_MAPPING = { ++ 50: 473, ++ 49: 477, ++ 52: 481, ++ 51: 485, ++ 54: 489, ++ 53: 493, ++ } ++ ++ PORT_RX_LOS_GPIO_MAPPING = { ++ 50: 474, ++ 49: 478, ++ 52: 482, ++ 51: 486, ++ 54: 490, ++ 53: 494, ++ } ++ ++ PORT_TX_FAULT_GPIO_MAPPING = { ++ 50: 475, ++ 49: 479, ++ 52: 483, ++ 51: 487, ++ 54: 491, ++ 53: 495, ++ } ++ ++ port_to_i2c_mapping = 0 ++ ++ def __init__(self, index, sfp_type): ++ SfpOptoeBase.__init__(self) ++ # Init index ++ self.index = index ++ self.port_num = index ++ self.sfp_type = sfp_type ++ #self.eeprom_path = eeprom_path ++ #self.port_to_i2c_mapping = port_i2c_map ++ self.port_to_eeprom_mapping = {} ++ ++ if self.sfp_type == COPPER_TYPE: ++ self.port_to_eeprom_mapping[index] = 'N/A' ++ else: ++ self.port_to_eeprom_mapping[index] = self.EEPROM_PATH.format(self.PORT_EEPROM_I2C_MAPPING[self.index]) ++ ++ def get_eeprom_path(self): ++ return self.port_to_eeprom_mapping[self.port_num] ++ ++ def __read_eeprom_specific_bytes(self, offset, num_bytes): ++ sysfsfile_eeprom = None ++ eeprom_raw = [] ++ for i in range(0, num_bytes): ++ eeprom_raw.append("0x00") ++ ++ sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] ++ try: ++ sysfsfile_eeprom = open( ++ sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) ++ sysfsfile_eeprom.seek(offset) ++ raw = sysfsfile_eeprom.read(num_bytes) ++ for n in range(0, num_bytes): ++ if sys.version_info[0] >= 3: ++ eeprom_raw[n] = hex(raw[n])[2:].zfill(2) ++ else: ++ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) ++ except Exception: ++ pass ++ finally: ++ if sysfsfile_eeprom: ++ sysfsfile_eeprom.close() ++ ++ return eeprom_raw ++ ++ def get_reset_status(self): ++ """ ++ Retrieves the reset status of SFP ++ Returns: ++ A Boolean, True if reset enabled, False if disabled ++ """ ++ return False # SFP port doesn't support this feature ++ ++ ++ def get_rx_los(self): ++ """ ++ Retrieves the RX LOS (lost-of-signal) status of SFP ++ Returns: ++ A Boolean, True if SFP has RX LOS, False if not. ++ Note : RX LOS status is latched until a call to get_rx_los or a reset. ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_RX_LOS_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp rx los cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return True ++ else: ++ return False ++ ++ def get_tx_fault(self): ++ """ ++ Retrieves the TX fault status of SFP ++ ++ Returns: ++ A list of boolean values, representing the TX fault status ++ of each available channel, value is True if SFP channel ++ has TX fault, False if not. ++ E.g., for a tranceiver with four channels: [False, False, True, False] ++ Note : TX fault status is lached until a call to get_tx_fault or a reset. ++ """ ++ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_TX_FAULT_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp tx fault cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return True ++ else: ++ return False ++ ++ ++ def get_tx_disable(self): ++ """ ++ Retrieves the tx_disable status of this SFP ++ Returns: ++ A list of boolean values, representing the TX disable status ++ of each available channel, value is True if SFP channel ++ is TX disabled, False if not. ++ E.g., for a tranceiver with four channels: [False, False, True, False] ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return None ++ else: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_TX_DISABLE_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp present cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return [True] ++ else: ++ return [False] ++ ++ ++ def get_tx_disable_channel(self): ++ """ ++ Retrieves the TX disabled channels in this SFP ++ Returns: ++ A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent ++ TX channels which have been disabled in this SFP. ++ As an example, a returned value of 0x5 indicates that channel 0 ++ and channel 2 have been disabled. ++ """ ++ tx_disable_list = self.get_tx_disable() ++ if tx_disable_list is None: ++ return 0 ++ tx_disabled = 0 ++ for i in range(len(tx_disable_list)): ++ if tx_disable_list[i]: ++ tx_disabled |= 1 << i ++ return tx_disabled ++ ++ def get_lpmode(self): ++ """ ++ Retrieves the lpmode (low power mode) status of this SFP ++ Returns: ++ A Boolean, True if lpmode is enabled, False if disabled ++ """ ++ # SFP doesn't support this feature ++ return False ++ ++ def get_power_set(self): ++ ++ # SFP doesn't support this feature ++ return False ++ ++ def get_power_override(self): ++ """ ++ Retrieves the power-override status of this SFP ++ Returns: ++ A Boolean, True if power-override is enabled, False if disabled ++ """ ++ return False # SFP doesn't support this feature ++ ++ def reset(self): ++ """ ++ Reset SFP and return all user module settings to their default srate. ++ Returns: ++ A boolean, True if successful, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def tx_disable(self, tx_disable): ++ """ ++ Disable SFP TX for all channels ++ Args: ++ tx_disable : A Boolean, True to enable tx_disable mode, False to disable ++ tx_disable mode. ++ Returns: ++ A boolean, True if tx_disable is set successfully, False if not ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ gpiopin = self.GPIO_PATH.format(self.PORT_TX_DISABLE_GPIO_MAPPING[self.index]) ++ cmdstatus, value = cmd.getstatusoutput('echo {} > {}'.format(tx_disable, gpiopin)) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp tx_disable cmdstatus get failed") ++ return False ++ return True ++ ++ def tx_disable_channel(self, channel, disable): ++ """ ++ Sets the tx_disable for specified SFP channels ++ Args: ++ channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, ++ e.g. 0x5 for channel 0 and channel 2. ++ disable : A boolean, True to disable TX channels specified in channel, ++ False to enable ++ Returns: ++ A boolean, True if successful, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def set_lpmode(self, lpmode): ++ """ ++ Sets the lpmode (low power mode) of SFP ++ Args: ++ lpmode: A Boolean, True to enable lpmode, False to disable it ++ Note : lpmode can be overridden by set_power_override ++ Returns: ++ A boolean, True if lpmode is set successfully, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def set_power_override(self, power_override, power_set): ++ """ ++ Sets SFP power level using power_override and power_set ++ Args: ++ power_override : ++ A Boolean, True to override set_lpmode and use power_set ++ to control SFP power, False to disable SFP power control ++ through power_override/power_set and use set_lpmode ++ to control SFP power. ++ power_set : ++ Only valid when power_override is True. ++ A Boolean, True to set SFP to low power mode, False to set ++ SFP to high power mode. ++ Returns: ++ A boolean, True if power-override and power_set are set successfully, ++ False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return "Ethernet" + str(self.index - 1) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_PRESENT_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp present cmdstatus get failed") ++ return False ++ if int(value) == 0: ++ return True ++ else: ++ return False ++ ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return self.get_presence() ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.port_num ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ if self.sfp_type == "SFP": ++ return True ++ else: ++ return False ++ ++ def get_error_description(self): ++ """ ++ Retrives the error descriptions of the SFP module ++ Returns: ++ String that represents the current error descriptions of vendor specific errors ++ In case there are multiple errors, they should be joined by '|', ++ like: "Bad EEPROM|Unsupported cable" ++ """ ++ if not self.get_presence(): ++ err_descr = self.SFP_STATUS_UNPLUGGED ++ else: ++ err_descr = self.SFP_STATUS_OK ++ ++ return err_descr +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal.py +new file mode 100644 +index 000000000..a92ed271c +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal.py +@@ -0,0 +1,303 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# 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.sfp import Sfp ++ from sonic_platform.fan import Fan ++ from sonic_platform_base.thermal_base import ThermalBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Thermal(ThermalBase): ++ """Platform-specific Thermal class""" ++ ++ THERMAL_NAME_LIST = [] ++ SYSFS_THERMAL_DIR = ["/sys/bus/i2c/devices/2-004a/hwmon/", ++ "/sys/bus/i2c/devices/2-0049/hwmon/", ++ "/sys/bus/i2c/devices/2-004b/hwmon/", ++ "/sys/bus/i2c/devices/3-0059/hwmon/", ++ "/sys/bus/i2c/devices/3-0058/hwmon/", ++ "/sys/devices/virtual/thermal/thermal_zone1/", ++ "/sys/bus/i2c/devices/0-001b/hwmon/"] ++ ++ def __init__(self, thermal_index): ++ self.index = thermal_index ++ self.fan = Fan(0, 0) ++ self.direction = self.fan.get_direction() ++ if thermal_index >= 8: ++ self.sfp_module = Sfp(49 + (thermal_index - 8), 'SFP') ++ ++ # Add thermal name ++ if self.direction == "exhaust": ++ self.THERMAL_NAME_LIST.append("XFMR Ambient") ++ self.THERMAL_NAME_LIST.append("DDR Ambient") ++ self.THERMAL_NAME_LIST.append("System Ambient") ++ else: ++ self.THERMAL_NAME_LIST.append("System Ambient") ++ self.THERMAL_NAME_LIST.append("FAN Ambient") ++ self.THERMAL_NAME_LIST.append("CPU Ambient") ++ ++ self.THERMAL_NAME_LIST.append("PSU 1 Temp") ++ self.THERMAL_NAME_LIST.append("PSU 2 Temp") ++ self.THERMAL_NAME_LIST.append("CPU Temp") ++ self.THERMAL_NAME_LIST.append("Dimm Temp") ++ self.THERMAL_NAME_LIST.append("MAC Temp") ++ ++ self.THERMAL_NAME_LIST.append("XCVR 1 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 2 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 3 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 4 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 5 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 6 Temp") ++ ThermalBase.__init__(self) ++ self.minimum_thermal = 150.0 ++ self.maximum_thermal = 0.0 ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return "" ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def __get_temp(self, temp_file): ++ hwmon_dir = self.__search_hwmon_dir_name(self.SYSFS_THERMAL_DIR[self.index]) ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], hwmon_dir, temp_file) ++ raw_temp = self.__read_txt_file(temp_file_path) ++ temp = float(raw_temp)/1000 ++ return "{:.3f}".format(temp) ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from thermal ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 5 or self.index == 6: ++ temp_file = "temp1_input" ++ if self.get_presence(): ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ temp_file = "temp" ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], temp_file) ++ raw_temp = self.__read_txt_file(temp_file_path) ++ temp = float(raw_temp)/1000 ++ return float("{:.3f}".format(temp)) ++ elif self.index == 7: ++ from swsscommon.swsscommon import DBConnector ++ temp = 0 ++ try: ++ stateDB = DBConnector('STATE_DB', 0, True, '') ++ temp = int(stateDB.hget('ASIC_TEMPERATURE_INFO', 'temperature_0')) ++ except Exception as E: ++ print("get_temperature (MAC) failed, cause by {}".format(E)) ++ return float("{:.3f}".format(temp)) ++ else: ++ if self.get_presence(): ++ return float("{:.3f}".format(self.sfp_module.get_temperature())) ++ ++ def get_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of thermal ++ Returns: ++ A float number, the high threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 3 or self.index == 6: ++ return float("{:.3f}".format(80)) ++ elif self.index < 5: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ return float("{:.3f}".format(90)) ++ elif self.index == 7: ++ return float("{:.3f}".format(100)) ++ else: ++ return float("{:.3f}".format(68)) ++ ++ def get_caution2_threshold(self): ++ """ ++ Retrieves the T-caution2 threshold temperature of thermal ++ Returns: ++ A float number, the high threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 3 or self.index == 6: ++ return float("{:.3f}".format(82)) ++ elif self.index < 5: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) + 2 ++ elif self.index == 5: ++ return float("{:.3f}".format(92)) ++ elif self.index == 7: ++ return float("{:.3f}".format(105)) ++ else: ++ return float("{:.3f}".format(69)) ++ ++ def get_high_critical_threshold(self): ++ """ ++ Retrieves the high critical threshold temperature of thermal ++ :return: A float number, the high critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ ++ if self.index < 3: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) ++ elif self.index < 5: ++ temp_file = "temp1_crit" ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ return float("{:.3f}".format(95)) ++ elif self.index == 6: ++ return float("{:.3f}".format(85)) ++ elif self.index == 7: ++ return float("{:.3f}".format(108)) ++ else: ++ return float("{:.3f}".format(70)) ++ ++ ++ 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 ++ """ ++ if self.index < 5 or self.index == 6: ++ temp_file = "temp1_input" ++ hwmon_dir = self.__search_hwmon_dir_name(self.SYSFS_THERMAL_DIR[self.index]) ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], hwmon_dir, temp_file) ++ return os.path.isfile(temp_file_path) ++ elif self.index == 5: ++ temp_file = "temp" ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], temp_file) ++ return os.path.isfile(temp_file_path) ++ elif self.index > 7: ++ return self.sfp_module.get_presence() ++ return True ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ if self.index > 6 and self.index < 8: ++ return True ++ if not self.get_presence(): ++ return False ++ ++ return True ++ ++ def get_low_threshold(self): ++ """ ++ Retrieves the low threshold temperature of thermal ++ :return: A float number, the low threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ # work temperatur is 0~40, hyst is 2 ++ return 2.0 ++ ++ def get_low_critical_threshold(self): ++ """ ++ Retrieves the low critical threshold temperature of thermal ++ :return: A float number, the low critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ # work temperatur is 0~40 ++ return 0.0 ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return "None" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "None" ++ ++ def is_replaceable(self): ++ """ ++ Retrieves whether thermal module is replaceable ++ Returns: ++ A boolean value, True if replaceable, False if not ++ """ ++ return False ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return self.index + 1 ++ ++ def get_minimum_recorded(self): ++ """ ++ Retrieves the minimum recorded temperature of thermal ++ Returns: ++ A float number, the minimum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ tmp = self.get_temperature() ++ if tmp is None: ++ return self.minimum_thermal ++ if tmp < self.minimum_thermal: ++ self.minimum_thermal = tmp ++ return self.minimum_thermal ++ ++ def get_maximum_recorded(self): ++ """ ++ Retrieves the maximum recorded temperature of thermal ++ Returns: ++ A float number, the maximum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ tmp = self.get_temperature() ++ if tmp is None: ++ return self.maximum_thermal ++ if tmp > self.maximum_thermal: ++ self.maximum_thermal = tmp ++ return self.maximum_thermal +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_actions.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_actions.py +new file mode 100755 +index 000000000..2f024d052 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_actions.py +@@ -0,0 +1,240 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++import math ++import time ++import sonic_platform.platform ++try: ++ from sonic_platform.thermal import Thermal ++except Exception as e: ++ print(e) ++ ++from sonic_py_common import daemon_base, logger ++ ++sonic_logger = logger.Logger('thermal_actions') ++ ++SENSORS_NUM = 5 ++ ++TEMP_INFO = [] ++ ++SENSOR_INDEX = { ++ 0: 0, ++ 1: 1, ++ 2: 2, ++ 3: 5, ++ 4: 7 ++} ++ ++COFF_KA = { ++ 'exhaust': { ++ 0: 2.62, ++ 1: 2.15, ++ 2: 2.23, ++ 3: 2.51, ++ 4: 1.6 ++ }, ++ 'intake': { ++ 0: 2.5, ++ 1: 1.8, ++ 2: 1.9, ++ 3: 1.5, ++ 4: 1.1 ++ } ++} ++ ++COFF_KB = { ++ 'exhaust': { ++ 0: 110, ++ 1: 72, ++ 2: 78, ++ 3: 126, ++ 4: 60 ++ }, ++ 'intake': { ++ 0: 100, ++ 1: 44, ++ 2: 52, ++ 3: 35, ++ 4: 10 ++ } ++} ++ ++class SetFanSpeedAction(ThermalPolicyActionBase): ++ """ ++ Base thermal action class to set speed for fans ++ """ ++ # JSON field definition ++ JSON_FIELD_SPEED = 'speed' ++ ++ def __init__(self): ++ """ ++ Constructor of SetFanSpeedAction ++ """ ++ self.default_speed = 50 ++ self.high_temp_speed = 100 ++ self.speed = self.default_speed ++ self.chassis = sonic_platform.platform.Platform().get_chassis() ++ self.direction = self.chassis.get_fan(0).get_direction() ++ ++ ++ def load_from_json(self, json_obj): ++ """ ++ Construct SetFanSpeedAction via JSON. JSON example: ++ { ++ "type": "fan.all.set_speed" ++ "speed": "100" ++ } ++ :param json_obj: A JSON object representing a SetFanSpeedAction action. ++ :return: ++ """ ++ if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj: ++ speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) ++ if speed < 0 or speed > 100: ++ raise ValueError( ++ 'SetFanSpeedAction invalid speed value {} in JSON policy file, valid value should be [0, 100]'. ++ format(speed)) ++ self.speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) ++ # else: ++ # raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. ++ # format(SetFanSpeedAction.JSON_FIELD_SPEED)) ++ ++ def get_chassis(self): ++ return self.chassis ++ ++ def get_direction(self): ++ return self.direction ++ ++ @classmethod ++ def set_all_fan_speed(cls, thermal_info_dict, speed): ++ from .thermal_infos import FanInfo ++ if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): ++ fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME] ++ for fan in fan_info_obj.get_presence_fans(): ++ fan.set_speed(int(speed)) ++ ++ @classmethod ++ def calc_fan_speed(cls, index, temp): ++ direction = cls().get_direction() ++ fan_speed = int((temp * COFF_KA[direction][index] - COFF_KB[direction][index])) ++ ++ if fan_speed < 30: ++ fan_speed = 30 ++ elif fan_speed > 100: ++ fan_speed = 100 ++ ++ return fan_speed ++ ++ @classmethod ++ def power_down(cls): ++ chassis = cls().get_chassis() ++ chassis.power_down() ++ ++ @classmethod ++ def get_temp(cls, thermal_info_dict): ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ return thermal_info_obj.get_temp_list() ++ ++@thermal_json_object('fan.all.set_speed') ++class SetAllFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) ++ ++ ++@thermal_json_object('fan.new.set_speed') ++class SetNewFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.default_speed) ++ time.sleep(8) ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) ++ ++ ++@thermal_json_object('switch.shutdown') ++class SwitchPolicyAction(ThermalPolicyActionBase): ++ """ ++ Base class for thermal action. Once all thermal conditions in a thermal policy are matched, ++ all predefined thermal action will be executed. ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Take action when thermal condition matches. For example, adjust speed of fan or shut ++ down the switch. ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ temp_info = thermal_info_obj.get_temp_dict() ++ for key in temp_info: ++ sonic_logger.log_warning( ++ "Temp is over high critical threshold, system shutdown {} temperature is {}".format(key, temp_info[key])) ++ import os ++ os.system('sync') ++ SetFanSpeedAction.power_down() ++ # import os ++ # os.system('reboot') ++ ++ ++@thermal_json_object('fan.set_speed') ++class SetAllFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ temp_info = thermal_info_obj.get_temp_dict() ++ temp_list = [] ++ for key in temp_info: ++ temp_list.append(temp_info[key]) ++ speed = 0 ++ for i in range(0, SENSORS_NUM): ++ if SetFanSpeedAction.calc_fan_speed(i, temp_list[SENSOR_INDEX[i]]) > speed: ++ speed = SetFanSpeedAction.calc_fan_speed(i, temp_list[SENSOR_INDEX[i]]) ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, speed) ++ ++@thermal_json_object('high_threshold.control') ++class ThermalOverHighThresholdAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_conditions.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_conditions.py +new file mode 100755 +index 000000000..66f92c720 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_conditions.py +@@ -0,0 +1,110 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++ ++ ++class ThermalCondition(ThermalPolicyConditionBase): ++ def get_thermal_info(self, thermal_info_dict): ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ++ ThermalInfo): ++ return thermal_info_dict[ThermalInfo.INFO_NAME] ++ else: ++ return None ++ ++ ++@thermal_json_object('thermal.over.high_threshold') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ if thermal_info_obj: ++ return thermal_info_obj.is_over_high_threshold() ++ else: ++ return False ++ ++ ++@thermal_json_object('thermal.over.high_critical_threshold') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ return thermal_info_obj.is_over_high_critical_threshold() if thermal_info_obj else False ++ ++ ++@thermal_json_object('thermal.over.threshold_after_cool_down') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ return thermal_info_obj.is_warm_up_and_over_high_threshold() if thermal_info_obj else False ++ ++ ++class FanCondition(ThermalPolicyConditionBase): ++ old_presence = True ++ interval_cnt = 0 ++ ++ def get_fan_info(self, thermal_info_dict): ++ from .thermal_infos import FanInfo ++ if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): ++ return thermal_info_dict[FanInfo.INFO_NAME] ++ else: ++ return None ++ ++ ++@thermal_json_object('fan.any.absence') ++class AnyFanAbsenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if len(fan_info_obj.get_absence_fans()) > 0: ++ self.old_presence = False ++ result = len(fan_info_obj.get_absence_fans()) == 1 if fan_info_obj else False ++ return result ++ ++ ++@thermal_json_object('fan.all.absence') ++class AllFanAbsenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if len(fan_info_obj.get_absence_fans()) > 0: ++ self.old_presence = False ++ return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False ++ ++ ++@thermal_json_object('fan.any.new') ++class AllFanNewCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ # Update status ++ self.all_presence = True ++ if len(fan_info_obj.get_absence_fans()) == 0: ++ self.all_presence = True ++ else: ++ self.all_presence = False ++ if self.all_presence == True and self.old_presence == False: ++ self.new_fan_insert = True ++ else: ++ self.new_fan_insert = False ++ self.old_presence = self.all_presence ++ return self.new_fan_insert if fan_info_obj else False ++ ++ ++@thermal_json_object('fan.all.presence') ++class AllFanPresenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if not self.old_presence and len(fan_info_obj.get_absence_fans()) == 0: ++ self.old_presence = True ++ return False ++ elif not self.old_presence and len(fan_info_obj.get_absence_fans()) != 0: ++ self.old_presence = False ++ return False ++ else: ++ if len(fan_info_obj.get_absence_fans()) != 0: ++ self.old_presence = False ++ return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False ++ ++ ++class PsuCondition(ThermalPolicyConditionBase): ++ def get_psu_info(self, thermal_info_dict): ++ from .thermal_infos import PsuInfo ++ if PsuInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[PsuInfo.INFO_NAME], PsuInfo): ++ return thermal_info_dict[PsuInfo.INFO_NAME] ++ else: ++ return None +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_infos.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_infos.py +new file mode 100755 +index 000000000..72dbfa546 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_infos.py +@@ -0,0 +1,210 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++ ++ ++@thermal_json_object('fan_info') ++class FanInfo(ThermalPolicyInfoBase): ++ """ ++ Fan information needed by thermal policy ++ """ ++ ++ # Fan information name ++ INFO_NAME = 'fan_info' ++ ++ def __init__(self): ++ self._absence_fans = set() ++ self._presence_fans = set() ++ self._fault_fans = set() ++ self._status_changed = False ++ ++ def collect(self, chassis): ++ """ ++ Collect absence and presence fans. ++ :param chassis: The chassis object ++ :return: ++ """ ++ self._status_changed = False ++ for fan in chassis.get_all_fans(): ++ status = fan.get_status() ++ if fan.get_presence() and fan not in self._presence_fans: ++ self._presence_fans.add(fan) ++ self._status_changed = True ++ if fan in self._absence_fans: ++ self._absence_fans.remove(fan) ++ elif not fan.get_presence() and fan not in self._absence_fans: ++ self._absence_fans.add(fan) ++ self._status_changed = True ++ if fan in self._presence_fans: ++ self._presence_fans.remove(fan) ++ ++ if not status and fan not in self._fault_fans: ++ self._fault_fans.add(fan) ++ self._status_changed = True ++ elif status and fan in self._fault_fans: ++ self._fault_fans.remove(fan) ++ self._status_changed = True ++ ++ def get_absence_fans(self): ++ """ ++ Retrieves absence fans ++ :return: A set of absence fans ++ """ ++ return self._absence_fans ++ ++ def get_presence_fans(self): ++ """ ++ Retrieves presence fans ++ :return: A set of presence fans ++ """ ++ return self._presence_fans ++ ++ def get_fault_fans(self): ++ """ ++ Retrieves fault fans ++ :return: A set of fault fans ++ """ ++ return self._fault_fans ++ ++ def is_status_changed(self): ++ """ ++ Retrieves if the status of fan information changed ++ :return: True if status changed else False ++ """ ++ return self._status_changed ++ ++ ++@thermal_json_object('thermal_info') ++class ThermalInfo(ThermalPolicyInfoBase): ++ """ ++ Thermal information needed by thermal policy ++ """ ++ ++ # Fan information name ++ INFO_NAME = 'thermal_info' ++ ++ def __init__(self): ++ self._state = ["N/A"] * 15 ++ self._enter_warm_up_state = [False] * 15 ++ self.init = False ++ self.normal_thres = False ++ self.high_thres = False ++ self.critical_high_thres = False ++ self.warm_up_thres = False ++ self._temp_dict = {} ++ ++ def collect(self, chassis): ++ """ ++ Collect thermal sensor temperature change status ++ :param chassis: The chassis object ++ :return: ++ """ ++ # self._cool_down_and_below_low_threshold = False ++ ++ # Calculate average temp within the device ++ num_of_thermals = chassis.get_num_thermals() ++ ++ # Initial the to default ++ self.normal_thres = False ++ self.high_thres = False ++ self.critical_high_thres = False ++ self.warm_up_thres = False ++ ++ # Collect the information ++ for index in range(num_of_thermals): ++ if not chassis.get_thermal(index).get_presence(): ++ continue ++ ++ # Store the temperature in the DB ++ name = chassis.get_thermal(index).get_name() ++ temp = chassis.get_thermal(index).get_temperature() ++ self._temp_dict[name] = temp ++ ++ # Get the threshold ++ normal_temp = chassis.get_thermal(index).get_high_threshold() ++ high_temp = chassis.get_thermal(index).get_caution2_threshold() ++ critical_high_temp = chassis.get_thermal(index).get_high_critical_threshold() ++ ++ # Check if the temperature is over the threshold ++ if temp < normal_temp: ++ self._state[index] = "n/a" ++ elif normal_temp <= temp < high_temp: ++ self._state[index] = "normal" ++ elif high_temp <= temp < critical_high_temp: ++ if self._state[index] == "high": ++ self._enter_warm_up_state[index] = True ++ self._state[index] = "high" ++ elif temp >= critical_high_temp: ++ self._state[index] = "critical" ++ ++ # Check the system status ++ if self._state[index] == "critical": ++ self.critical_high_thres = True ++ elif self._state[index] == "high": ++ self.high_thres = True ++ elif self._state[index] == "normal": ++ self.normal_thres = True ++ ++ if self._enter_warm_up_state[index]: ++ self.warm_up_thres = True ++ ++ def get_temp_dict(self): ++ return self._temp_dict ++ ++ def is_over_high_threshold(self): ++ """ ++ Retrieves if the temperature is over high threshold ++ :return: True if the temperature is over high threshold else False ++ """ ++ if self.high_thres and not self.critical_high_thres: ++ return True ++ return False ++ ++ def is_warm_up_and_over_high_threshold(self): ++ """ ++ Retrieves if the temperature is warm up and over high threshold ++ :return: True if the temperature is warm up and over high threshold else False ++ """ ++ ++ return self.warm_up_thres ++ ++ def is_over_high_critical_threshold(self): ++ """ ++ Retrieves if the temperature is over high critical threshold ++ :return: True if the temperature is over high critical threshold else False ++ """ ++ return self.critical_high_thres ++ ++ def is_over_normal_threshold(self): ++ """ ++ Retrieves if the temperature is over high critical threshold ++ :return: True if the temperature is over high critical threshold else False ++ """ ++ if self.normal_thres and not self.critical_high_thres and not self.high_thres: ++ return True ++ return False ++ ++ ++@thermal_json_object('chassis_info') ++class ChassisInfo(ThermalPolicyInfoBase): ++ """ ++ Chassis information needed by thermal policy ++ """ ++ INFO_NAME = 'chassis_info' ++ ++ def __init__(self): ++ self._chassis = None ++ ++ def collect(self, chassis): ++ """ ++ Collect platform chassis. ++ :param chassis: The chassis object ++ :return: ++ """ ++ self._chassis = chassis ++ ++ def get_chassis(self): ++ """ ++ Retrieves platform chassis object ++ :return: A platform chassis object. ++ """ ++ return self._chassis +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_manager.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_manager.py +new file mode 100755 +index 000000000..3fe0942bd +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/thermal_manager.py +@@ -0,0 +1,10 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase ++from .thermal_actions import * ++from .thermal_conditions import * ++from .thermal_infos import * ++ ++ ++class ThermalManager(ThermalManagerBase): ++ @classmethod ++ def initialize(cls): ++ pass +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/watchdog.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/watchdog.py +new file mode 100644 +index 000000000..4193dee09 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/sonic_platform/watchdog.py +@@ -0,0 +1,199 @@ ++""" ++Module contains an implementation of SONiC Platform Base API and ++provides access to hardware watchdog ++""" ++ ++import os ++import fcntl ++import array ++ ++from sonic_platform_base.watchdog_base import WatchdogBase ++from sonic_py_common import logger ++ ++""" ioctl constants """ ++IO_READ = 0x80000000 ++IO_SIZE_INT = 0x00040000 ++IO_READ_WRITE = 0xC0000000 ++IO_TYPE_WATCHDOG = ord('W') << 8 ++ ++WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG ++WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG ++ ++""" Watchdog ioctl commands """ ++WDIOC_SETOPTIONS = 4 | WDR_INT ++WDIOC_KEEPALIVE = 5 | WDR_INT ++WDIOC_SETTIMEOUT = 6 | WDWR_INT ++WDIOC_GETTIMEOUT = 7 | WDR_INT ++WDIOC_GETTIMELEFT = 10 | WDR_INT ++ ++""" Watchdog status constants """ ++WDIOS_DISABLECARD = 0x0001 ++WDIOS_ENABLECARD = 0x0002 ++ ++""" watchdog sysfs """ ++WD_SYSFS_PATH = "/sys/class/watchdog/{}/" ++WD_DEV_PATH = "/dev/{}" ++ ++WD_COMMON_ERROR = -1 ++ ++sonic_logger = logger.Logger() ++ ++ ++class WatchdogImplBase(WatchdogBase): ++ """ ++ Base class that implements common logic for interacting ++ with watchdog using ioctl commands ++ """ ++ ++ def __init__(self, wd_device_path): ++ """ ++ Open a watchdog handle ++ @param wd_device_path Path to watchdog device ++ """ ++ ++ self.watchdog_path = WD_DEV_PATH.format(wd_device_path) ++ self.watchdog_sysfs_path = WD_SYSFS_PATH.format(wd_device_path) ++ ++ # Opening a watchdog descriptor starts ++ # watchdog timer; by default it should be stopped ++ #self._disablewatchdog() ++ ++ self.timeout = self._gettimeout() ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def disarm(self): ++ """ ++ Disarm the hardware watchdog ++ ++ Returns: ++ A boolean, True if watchdog is disarmed successfully, False ++ if not ++ """ ++ sonic_logger.log_info(" Debug disarm watchdog ") ++ ++ try: ++ self._disablewatchdog() ++ except IOError: ++ return False ++ ++ return True ++ ++ def _disablewatchdog(self): ++ """ ++ Turn off the watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('h', [WDIOS_DISABLECARD]) ++ fcntl.ioctl(watchdog, WDIOC_SETOPTIONS, req, False) ++ os.close(watchdog) ++ ++ def _settimeout(self, seconds): ++ """ ++ Set watchdog timer timeout ++ @param seconds - timeout in seconds ++ @return is the actual set timeout ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('I', [seconds]) ++ fcntl.ioctl(watchdog, WDIOC_SETTIMEOUT, req, True) ++ os.close(watchdog) ++ ++ return int(req[0]) ++ ++ def _gettimeout(self): ++ """ ++ Get watchdog timeout ++ @return watchdog timeout ++ """ ++ ++ timeout_path = self.watchdog_sysfs_path + "timeout" ++ timeout = self.__read_txt_file(timeout_path) ++ return int(timeout) ++ ++ def _gettimeleft(self): ++ """ ++ Get time left before watchdog timer expires ++ @return time left in seconds ++ """ ++ ++ timeleft_path = self.watchdog_sysfs_path + "timeleft" ++ timeleft = self.__read_txt_file(timeleft_path) ++ return int(timeleft) ++ ++ ++ def arm(self, seconds): ++ """ ++ Implements arm WatchdogBase API ++ """ ++ sonic_logger.log_info(" Debug arm watchdog4 ") ++ ret = WD_COMMON_ERROR ++ if seconds < 0: ++ return ret ++ ++ try: ++ if self.timeout != seconds: ++ self.timeout = self._settimeout(seconds) ++ if self.is_armed(): ++ self._keepalive() ++ else: ++ sonic_logger.log_info(" Debug arm watchdog5 ") ++ self._enablewatchdog() ++ self._keepalive() ++ ret = self.timeout ++ except IOError: ++ pass ++ ++ return ret ++ ++ def _enablewatchdog(self): ++ """ ++ Turn on the watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('h', [WDIOS_ENABLECARD]) ++ fcntl.ioctl(watchdog, WDIOC_SETOPTIONS, req, False) ++ os.close(watchdog) ++ ++ def _keepalive(self): ++ """ ++ Keep alive watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ fcntl.ioctl(watchdog, WDIOC_KEEPALIVE) ++ os.close(watchdog) ++ ++ def is_armed(self): ++ """ ++ Implements is_armed WatchdogBase API ++ """ ++ state_path = self.watchdog_sysfs_path + "state" ++ state = self.__read_txt_file(state_path) ++ return state == "active" ++ ++ def get_remaining_time(self): ++ """ ++ Implements get_remaining_time WatchdogBase API ++ """ ++ ++ timeleft = WD_COMMON_ERROR ++ ++ if self.is_armed(): ++ try: ++ timeleft = self._gettimeleft() ++ except IOError: ++ pass ++ ++ return timeleft ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/es2227_54ts-oob-led.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/es2227_54ts-oob-led.sh +new file mode 100755 +index 000000000..975fb275f +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/es2227_54ts-oob-led.sh +@@ -0,0 +1,103 @@ ++#!/bin/bash ++ ++COPPER_TYPE=0 ++FIBER_TYPE=1 ++ ++currMediaType=0 ++ ++RET=-1 ++ ++set_led() ++{ ++ if [ $1 -eq $COPPER_TYPE ]; then ++ a=0; b=1 ++ else ++ a=1; b=0 ++ fi ++ ++ echo $a > /sys/class/gpio/gpio498/value; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 1; fi ++ ++ echo $b > /sys/class/gpio/gpio499/value; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 2; fi ++} ++ ++init() ++{ ++ # init oob port led ++ phytool write eth0/0/22 3; ++ phytool write eth0/0/17 0x44a5; ++ phytool write eth0/0/22 3; ++ phytool write eth0/0/16 0x0240; ++ phytool write eth0/0/22 0 ++ ++ # set rj port sgmii amplitude ++ phytool write eth0/0/22 2; ++ phytool write eth0/0/26 0x8004; ++ phytool write eth0/0/22 0 ++ ++ echo 496 > /sys/class/gpio/export ++ echo out > /sys/class/gpio/gpio496/direction ++ for k in $(seq 498 499); do ++ echo $k > /sys/class/gpio/export ++ echo out > /sys/class/gpio/gpio$k/direction ++ done ++ ++ # default set sfp txdisable to off ++ echo 0 > /sys/class/gpio/gpio496/value ++ ++ # default set to copper port mode ++ currMediaType=$COPPER_TYPE ++ set_led $COPPER_TYPE ++ ++ # Disable fiber Auto-Negotiation ++ phytool write eth0/0/22 1; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 3; fi ++ ethtool -s eth0 autoneg off speed 1000 duplex full; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 4; fi ++ #echo "Disable fiber Auto-Negotiation" ++ ++ # Set auto select mode - Prefer fiber medium ++ phytool write eth0/0/22 2; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 5; fi ++ phytool write eth0/0/16 0x508; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 6; fi ++ #echo "Set auto select mode - Prefer fiber medium" ++ ++ # Enable auto medium register selection ++ phytool write eth0/0/22 0x8000; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 7; fi ++ #echo "Enable auto medium register selection" ++} ++ ++do_task() ++{ ++ while true; do ++ regVal=`phytool read eth0/0/22`; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 8; fi ++ ++ type=$((regVal & 0x1)) ++ ++ if [ $type -ne $currMediaType ]; then ++ if [ $type -eq $COPPER_TYPE ]; then ++ set_led $COPPER_TYPE ++ #echo "set led to copper mode" ++ else ++ set_led $FIBER_TYPE ++ #echo "set led to fiber mode" ++ fi ++ ++ currMediaType=$type ++ fi ++ ++ sleep 2 ++ done ++} ++ ++main() ++{ ++ init ++ do_task ++} ++ ++main +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/get-base-mac.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/get-base-mac.py +new file mode 100644 +index 000000000..fe271d04a +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/get-base-mac.py +@@ -0,0 +1,20 @@ ++#!/usr/bin/env python ++ ++def main(): ++ try: ++ import sonic_platform.platform ++ import sonic_platform.chassis ++ except ImportError, e: ++ raise ImportError (str(e) + "- required module not found") ++ ++ chassis = sonic_platform.platform.Platform().get_chassis() ++ if chassis is None: ++ print "DEBUG chassis was None " ++ ++ base_mac = chassis.get_base_mac() ++ print base_mac ++ ++ return ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/phytool b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/phytool +new file mode 100755 +index 0000000000000000000000000000000000000000..2a34c41e6fd4ae17ab3132328282c419236b9383 +GIT binary patch +literal 24440 +zcmeHv3wRXAm2ORs5O@$mNCIIXp#=sDfgWJ-FlNo@fdw(fM98u4nyjX!8A)S}X2i@0 +zBtzoi;m5u4cTGp)k!%3Pb`mt3yXM<~12&t;IGZ?ek|hQ^B=KV;jF)V@2@cq3Z1C)V +z>LIlTQ-V%-XXnrUDnSktOT(fb}7~hCX$3<>8 +z4cByBlW|SKMJX3oIXOrQ0Inzhfno5XVes9MucIzG{S3hMd35A3Hx|Vj-gu+H$Q%zlCQ%$|$^|6-La9yJj +zWJYZu7$&lCph;vtR^Q+Whp2%6!RZMG{ec=^pw0+;1AgG{Kx>%QlLY>6h}GBm0wIrJ +zZ}l-F)Drai!}UZ8X66mlg?-FhUqhOO175$|(*{mKQ&UsdX4KSs{f5u`poi55T0DNC +zcwKV~TBrV!^1*OTv*AVae#uCEX4K!H(Ol#8Z1S0is3d^0AHnWtmE2a?#9w#XZHZ3WP>caRpI(kUZ28Tl1I>M +z1N3U&VV8^1Nm@vd&dYs?!XpyDkc7KvkwNND!jI+({KB0=F(qfc+)wl;;Y|`}a$lq9 +z+ax|F3EwX9j3j)H#3v`=B@)+@@MRLuOTt%4yf_JeccJLlk|g|Ni93_;Bs@pr +zYm@M2q@4Sb@E(b~lJH+hyfF#?t;AcB@OFu}CE<@qJd%WWNc^!Ryi4K-?;bk7`aEHu +zSQ6efSK#N9aT#34$bEzwcU7L8ggX}qIeHTQ`XqtpCE=%O6NglsgnySdMo3GN@Rd@& +zGYNlO%3qm;KSmoyq_s(S+8lvLlJGOMp+uT|?@+sC(?$|$NfN$;Hl|32q}^8J&_?rVE2xY}3_+aZB?~UM{v1DP!L9v0W5H=(tWwN^tGzSTowwj>-%a=h3r_oKmHI8X+Mn|} +z*v|8|%Ef`Gtc$_L|qI;sWrU$R_-C +zWjy1=Qd8HazcyXBzp5@?_cy5P6Lq{?i?Vhbr{(2(lxJAV51?FTDf>~bwUmP>Z?lv) +zqWq+#{28f|%G)gE-6%h4DSsX1 +z6PEIRl>02@CsEe^YOwupqddb>j-p&D>K4B^U0OdYQ +z`2@<^?St+A808t3^3PB%vy^{{a;+#|-TWN)gNy5I-5nVB_wU!bKd`g>_wBZ*>yMT3 +z%XRi{8*|2ci&)&oBCkY1!}=@ZlYw>NF-o?JnV0P>x>a+=OKt4PrCMgbmC80euCeM6 +z_~Loyu_tDq9Q`)(o{tkHo!glCULujRHI-;0RTtNlcE5jrS@#9B +zf4Q!_`|9Q&A7t>s@1q`(_GIqyF=ou36WvYxDQw|e4z|I-W1tf7V*Y1;V7HkwaKGIF +zo$ZsNUC3Q*`D>TZCu|@~BBXz;60)3e26=4nXmcH8U4RZT(C^V$XD?_YR}*xkJ;~D2 +z%>$@U?n_TRaU^EX&R6;>U1=V1Jx>Zfec+8~&@-KF__q%e)x+uM{3x+dgWhE0u5@QS +zAAF<->C^$85KA^(8hv2Oo6wWXKQH80gDz$hc8Fb0Tx0XdrNohM!UoVanyhPy#@WqdnqS$Cl_z61G=)0OcXp-Ue1 +zmu!5#GVa89PlFt?iHaXx@EPXP&2J*lMZTP|KlEVywt^@3Ol8~v4~;#IIq@aa=Q8&4 +zj4KbFDoxw^mE0?(9WQ_$&m=CCU8#)Ma$aqKm)g9#`3J(k$FlhM(59=_b*mHhija=4 +zSH_Va=53@n!@irHaf9X{v;C|TeR>XbYP_#*{wLlCt1T{) +zkCP2Bmq&}aaEQfnyH5T)nv7guIwNE8l99;pC+%dFyX8&)HKUD;2U* +zAuAQKQll?lSJtrsn|4Ak8Y>x#qGa0$`pDzZViAX2na*REr?U8EyO!U>`WKaA%xM0^ +z?6&*^knhT5$3md#(E1mjMNH7N$SV{NVs?ARkueQpcen=iv1gp^7^C)n_y@O>jANIl +zk`Mhv+JDe*sE-%XudR?r{e0i9ML&RUR{z2Lk5V7|Y>`(;?{>6v8GV6#*fA$c{ndq@ +z(b!CikIq{S`1Yw8tbLcA9aixqW}g_H1Uj~iW%kTw?F@X_BWEu^kJxEr)k+piVP+cW +zdLb(pvbHj|Fe^JNKU6kh!5`2snitf6^0lqf*FbZ4I(TA<1698Vjq*9sZ{>IYI54(Z +zm=mFAM`0e=qhfq*=t~yHSd0GtDq_0E;=0BT69zqBc^eq)8t=jUQP^9+;Q#MMfX5IM +z@xXY3YWM2q7v)|iQuUG4Igb45=I?PG&YrcIw5IKa{e|6au)CIT`%`6{*1&jEN;e;a +z1~G?wpR$>KFWStH<}!#$?M^Ib@t9_Hj^$m(st +z`hu9LW8K3uhQqHx=NSBk!B)=EtmNWbcXW$!of!Sdu9@-Wv|gdlsP98=qu6nL6vldL +z^!woL-HvfD2My{!q;&!JZvg)gYv2IAGnLc-9np6PdWvb}$3*`t;2}F(_-l-rkWchE +z(HDU;tWmKB=P~AF6JiaBHKSM0(X+8;IwvgXfu<$?g-QD^Mo;Jc|5#schk;+vFaE_cJ?c0zaU!KfHkUJJXq& +z19>=eWp}1B6YGeu$#JqtcJvWRn~Qx>XC`Ph5wB>yr}}!-N9?eH#>RdyX;OX+{_q;+ +z-LtSg{Cr?8KdI!pMsvB<;G-DD_1+?|CfU~3j}q0LQg|a0Dt=)P7H_KP{%9`6v0n^{V-#1_zVVV=|K87Ham?lX#6xy5 +zkK|g|i?uH?6S3?pGq0enAHp|!F?Vw@cd-X(@?q|rg&ks}%e(t#I^#z`lf15Nh2N&2 +zZ?x{woaQ=akzOj!493?E%x_w2u^#Ysnf8O$*vj>UPQ9=J?GF)OuDdt<`4zDrNY*8n +z;t}e|Kgn0NVbA7-99oyj=V||Rt$u@Xkm5hZ{>0s^o$Hk&qb+gc62HNPYVeP%o +zGxH+$MsgkDdt}v~*e4?nxzHxs`#t1xd3;|a;;eNqM19iIoZT$Ld8}`|y_L5*f_L)6%%^7Fv`nTb{@;2Jl5Oc~7jS{iPc>{bREB{Hf +zf%S)`e@Q|10RZ4YoRqb+r_{2KI1>Q-@bkKhclxp#CiMr1qifA*t&j_R&O6>XbkoJ`?3E#w+ +zM9+0F^Xzs;V{(X9J5-!GnT>MiKa4VIKGs5hpPV;+h#d>jey_b^4&CDygF9`AvC}Kq +zhFr$(%sqsC0?CRv%(+B|IpYGqj`i6IpZX(oB3%dPiSQ?7Z;EqS@JF)AS=f`y+UYP6 +z_b24=cC!UGZ>;%C*x1k}&||Pe%r(}GlFd^hRTDvHXqf`vGS=k&34A=qvjpBb*4!`Y +zZ{T>gz`r}z+$(WA$0rKBXRL`>&gEZ49}I1hz)z1gAD8%Lj^_xxf2{ckaPp7$fcIhz +z<$6v_GrNEr+GIgjl4fp^{QtuFrwZJaW^R;tFUO||d~cfBBJtmG{4)aod7Alv#9!t3 +zX9dp2nQn>yGsmY3JbRq^HxmCT$NA5chgk7A^FH9Dw-~1r2Va0cQ9PT@vV!z1Yq+tZ +zF`~WR7r?tKEmHNWwhQ~UDM9w7NYxQ7BK+d~x;b0oCdcJ?^`x7+#J|FEIbN}JbBe?t=J<`$PUFpN +z;5Z-VKLmV0@3rI2LZXN7kv$&L+WySi#?d;**Yq;?II}Dx@^wDujpI#v)OS;e*g=j8d +zpHK0V&huqXX8sBDUadhCTkhfGIXJi2O=H%Pu6QA2A?Wa!AGB$_-u|(5w>s3 +zFlm26@^y~Ox$#(r`HaM;a9qxfLm6f_aPr-3;MTEvk?8q2ZTvI!Q;k*fIDPz~g|97> +zw{N7&xp5`~@lmaZFCM)3VIt?qmu*v73j6%uTkNgusA3tn-@6&uYiH$`q+yO=Ja!@O +zA30HE_F3D5jlTvx4Ncm`H^FR`{fvQbAm%(h!3;?Jw;Y$gdUAs4mH26nOFObmvko}f +z<(Jm>iZjhG0e3B0eX8q0SN|Ssoh#Gah&p5T%2Qop|D`V5r|}+c0da{Fm%VbL1k{e6>!} +zS%LN(Pg(XHSW6FwemV0iwPnuulY@JX!F62E;y(N^+NZVI+8)g>@)z27(0&fj+)k=z +zwr^wK;gS1}i}F1EZR{W3!L!;_>^(+d&yhOK*)5)v*vxa-cZ|ZmzBAD-bFkjtMfVc$CwdeRz8^ECDy+OOqA +zp9d|C<9gKnQLXKWE#f)AkL9^x@EMQTUoid*pcQS&(5)-3pUNV~h;fbalHY9m3AjZ8kN<2sJLqA>Ur<0ze_w#4Z +zL!Rfxab}|DOiz5A$kEnpuUgKuCYm;O}ISRTST3HmMH#5R;64wSJ2U#C6YS=mn)jpuvA_w#nNq2!gZH2xcc +zC{HoT|H@dZ`7Ux@%_s6jI?GBs(Y%_@pAR1&csA7uAM1Q_F4jb?o5#UzbInd|;>+}V +z2>BIQ!G{G+LKkn6n48tUu%?64iW8 +zOC7Fm{t=%K#7BCl-{REoaP+RrJt3pPvs9lI(t{qut?R4rE-$TKb@!U0suh(ET_jX) +z3VOqyA(i^F;)3F~dZgPebo||-0lNE1$``MxUUf%l`3lFTM!Xv2aHt0LrGKUKilSvL +zcmZikOJn=(`WC%n#TSZ}l~z<#5wK +zagBQl524Y$u7eJ({v;P2q?Ar7-BCGC`GN)TzVecV4!Rrg9P$l-Lx80NUiX){5xk(d +zsCeluMe{8VBD_dcwHZal~~eHx?6V#y&FBj +zkREDn;Z_&J4Ery2dp3IOJTAT5XS9YqIyxdp#8DpzHXC7#)`(aB$6i^)ibCz7qB@@u +z3KjW1;i6d~a@|l(XpM+yOeC}XvqDQ}`RR5j2gxkEYh6`d +zaa-~HIaa}SMvGDF^?AcyPl(MgE-t7o;aNTZw-Nsq&}{+T6&HjT@DjgiWc5CyA;dgw +z;R3w!8g30S!|!P*KzKnE4SQJ7(~Rj-P;a#Q!m^4Q!waeS`-dj>fKglP337H70a<;k +z&&L`KU;XveFX!qP4^bZh4sR9v0)duVyfG|V@%VWoErCs*V1XN9k$FP_p8<`yeqf;& +zbXi@%=ktaTZ41IcSg6J0akE+Of>|MMZj6l>i?!>>YD1fCp&4D^@v~+GeY&S1EpVgP +zbzz2)WZ^b}yJ4ijrh>X~(8p%Y6azUZxtt`I4DAr&J=AW5%fL9^hUS)nkRRP+8+`^e +zZT0&-J{C3_3cU3NwSjOW^E6P9FK7<9@jf!%F7}99uOCBd_-IK|B+w+_4)NK*2h2l8 +z9#G~Qmuud*WQk`{G2TU$cegGcxLYXi<}Xoqw=7(sCdJy7|3hzX#bSkJ$)KpNBN8s< +z!Lh~g2C>epxpU3k_pZs~zCDLbw{(`6rIahBs7LVs5a*ud#;(c1ii_vzZf}Uj*UgIO +z&(mu$Gn=rw!aL_-y)=S;UO)|I>L$D{O-0V-@we;ulI3nCtHLa8C|#Zj1mHeQ$tsuUaeb!Aupib%jvNehT(J&Q-Cllr!K(@Qq#?Uuq5u +zkSC~z+gm(3)e}prAD#Esdu1nE{gB##0(DZ|f|Hy-xDmK*s{Jy6FZ17Jb-+_D#4jq^9P^koY#e0c_3waOn$B}QrL+0biGu}@m +zGVpTgPUIExCDRP3LCN-D6-#ORtZi!AbpCGnWMJ#xfE{?Pc;9>;?%RMZlbDX&iR)=# +zE0MF(bbVjSetTJmw&u+@PVv`I@tm5uah(JWR2@ipxZ8s3IPjx{mZq=W=h%NkS;v^p +z(Pg_*caLg(^Nm+uJ9QdTbW|V2wG!j87P+OJwW=K*@Xv9DL9-gUh30NWL;7F9^$pOx +zEofTyrSBhC){)jZwtSak_YEuejCtVAH-0VKC3+p>x)$TzFX#t#tRNjL_oM`d(ys;m +zWcb4lL0`Ntb^oZcj+9P&#V&2P?H-5fR4INSB|DNo`9Qy#{Gl}cq;21n{Wq5H$=;h) +zwrkSviFbBP?#%gG=GQ0uZHD&3n{WK?H^2S$8L6H4+piw*x1CKS_FD8SCmTY)FQPFr +z;7zDI54!W9>$1>sTd&%cdcUO8QI`S#bm2#lYxIXOl0`Hnpy>gP91GsZ6&)#eDLYep +z_kreJ&^(6wA!ECGS8A1PkN6{?+kqd6ry&QOYhT*_v1J{O&Kt^hjoCfAVo&PcQ7#xw +z^}2NI1D{ZW2x|K@Wc8!%7TjC>pp%=QIsxMo-4)O|@q_SbqAL^rS3$O0xhu6^>R61b +zn=m%-f-XXIrRjrXTE0uGq7fA`?~r%gM)!ed3FiCb7M@D-gTEGbr1rOfrVBI&F*Zui +ziVm&Qrnvi9))b1g#VCqY?K?Cgx+O?Q>96 +z=(%d(4kRQ$B?a>aJS{>G(Z5|9cUx`UU(bkI2uJEhN@W2dmtxlI +zh*>nx6)hJEyYZPI$AaeBW1yXfxOSXq%Y+|PkRPlhKiHG%8k}Z~{N^a>0s5W7Z<6M5 +z<(@HnM}I9TkktqK6eoH;N43 +z`4S9MWqFLu>19ev>N^|LM3H~fiEh>Nf;M`7f%N{zi2&s;JinoY#|k{<$v=Wu-vq$l +zaPZ_189OBPRe$47&uuA5Hxvc@E7@3=`a5@7b5yoZ&uJ;Czq!v5MHZ7CS9qKJ*nsM1 +zqwI);`M0!)Rp}wcF#HV??;q6VtRKsAo@7kOvQ&rR?@&4Y8QBot`Qqi9mB3FaKa?RF +z`u{!O$saD_IivLNztp_y`yXBOX6Pp*_1zDQcY?^&_deA3J=FI+)b~5o_c|V*B!sH( +zaj5Tad_q%0s?>KmhJYw2J(BT}@~2~g5&M5Sb{?*k5&I8knNJ5FvHz!I=TB;dwlM#< +z#zB1-YB>GW_o0TX|9>7Y3^mf%35{A-i1)la!4_8N$2(AkrDdxM@Ztt5Z1A@hHX5Nu +zR_Jc`huWJ(jxQJT8hVkCzFKH4)Sxct@fpM*?^^Ia736#IZy0Z1u|j;1(2Kf&+Xx%1 +z(9>AMUj(XYbc0uw1V@b#3>xi%L){Y>H30!!9i!P>2NePkECkkuLjN@*L;HH#;;Vh} +z5_zL?b?#8D$>V@3^6$mc-d*w2dnuGuuJh91Kk8hfkXg8)vxwqX=M|NomxSuPqRs_M +zPA=*{z}{W)tMiS@)ww8{Uy5aOaYHsx{ObIp@`LhVL+2y9Rqd+J +z8BfXfyA3E}!+`$kJfiY7l27Tc+EMvR)YDlUTKx)&GOQt_+v +zm&(=oOSP}~RsRjiUxu8LI?t*6s1!{6w8c*5ZvsX(QRmOS@;sz+b#4R+Piov%xgIxG +z{^WDig(QPZ@%$YmlCdF)U!5;hzC#_vi5N-oixOj-aAR#>o!?cSOrNa(mn6Tke~COF +zseHXUh|30(`5#W=PyXJv`o6YgA9yaH%J}=BA@hIlVo{^=YBlhZL5-i{--jD|5lfx_ +z)$gIy)B8%4lz%FIHLfqC&f30u{?R2Tu4|a~m7J4F{EWZ&0&p!Zq{)g<6tA(z +mYru&_^?&kxqQS}c35J!DPi0B!4AEWDP_FoYX9aPe%>VBN4lDuy + +literal 0 +HcmV?d00001 + +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/psu_detect.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/psu_detect.py +new file mode 100755 +index 000000000..a0caf8d12 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/psu_detect.py +@@ -0,0 +1,56 @@ ++import sonic_platform ++import time ++import subprocess ++import os ++ ++class psu_monitor(object): ++ def __init__(self): ++ self.pl = sonic_platform.platform.Platform() ++ self.cha = self.pl.get_chassis() ++ self.pre_sta = [True] * 2 ++ for i in range(0, 2): ++ psu = self.cha.get_psu(i) ++ self.pre_sta[i] = psu.get_presence() ++ if not self.pre_sta[i]: ++ self.remove_device(i) ++ ++ ++ def remove_device(self, index): ++ psu = self.cha.get_psu(index) ++ path="/sys/bus/i2c/devices/i2c-3/delete_device" ++ cmd="echo 0x" + psu.i2c_addr + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+psu.i2c_addr ++ if os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ ++ def probe_device(self, index): ++ psu = self.cha.get_psu(index) ++ path="/sys/bus/i2c/devices/i2c-3/new_device" ++ cmd="echo wistron_psu 0x" + psu.i2c_addr + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+psu.i2c_addr ++ if not os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ ++ def update_psu(self): ++ #fan status detect ++ for i in range(0, 2): ++ psu = self.cha.get_psu(i) ++ pres = psu.get_presence() ++ ++ if pres and not self.pre_sta[i]: ++ self.probe_device(i) ++ elif not pres and self.pre_sta[i]: ++ self.remove_device(i) ++ ++ self.pre_sta[i] = pres ++ ++def main(): ++ monitor = psu_monitor() ++ ++ # Loop forever: ++ while True: ++ time.sleep(1) ++ monitor.update_psu() ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/rst_button.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/rst_button.py +new file mode 100644 +index 000000000..3f47e8776 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/rst_button.py +@@ -0,0 +1,66 @@ ++import subprocess ++import time ++from sonic_py_common import device_info ++ ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++class rst_button_monitor(object): ++ def __init__(self): ++ self.intr_path = "{}/rst_button_10s".format(CPLD_SYSFS_DIR) ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def check_intr(self): ++ val=self.__read_txt_file(self.intr_path) ++ if val is not None: ++ return int(val, 10)==1 ++ else: ++ return True ++ ++ def restore_default(self): ++ version_info = device_info.get_sonic_version_info() ++ subprocess.run(["rm", "/etc/sonic/config_db.json"]) ++ time.sleep(0.5) ++ image_ver=version_info['build_version'] ++ path="/host/image-{}/platform/firsttime".format(image_ver) ++ cmd="touch {}".format(path) ++ subprocess.run(cmd.split()) ++ time.sleep(0.5) ++ subprocess.run(["sync"]) ++ time.sleep(0.5) ++ subprocess.run(["sync"]) ++ time.sleep(0.5) ++ cmd = ["passwd", "admin"] ++ try: ++ p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE) ++ p.stdin.write("YourPaSsWoRd\n".encode('utf-8')) ++ p.stdin.flush() ++ p.stdin.write("YourPaSsWoRd\n".encode('utf-8')) ++ p.stdin.flush() ++ except Exception as e: ++ print("restore_default failed: {}".format(e)) ++ ++def main(): ++ monitor = rst_button_monitor() ++ cont=True ++ ++ # Loop forever: ++ while cont: ++ time.sleep(1) ++ cont=monitor.check_intr() ++ ++ monitor.restore_default() ++ time.sleep(2) ++ ++ subprocess.run(["reboot"]) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sensor_conf.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sensor_conf.sh +new file mode 100755 +index 000000000..2480f35b8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sensor_conf.sh +@@ -0,0 +1,13 @@ ++#!/bin/bash ++ ++direction=$(decode-syseeprom -p) ++dev_path=/usr/share/sonic/device/arm64-wistron_es2227_54ts-r0/ ++ ++if [ $direction == "ES-2227-54TS-O" ]; then ++ cp $dev_path/sensors_afo.conf $dev_path/sensors.conf ++ cp $dev_path/platform_afo.json $dev_path/platform.json ++fi ++if [ $direction == "ES-2227-54TS-I" ]; then ++ cp $dev_path/sensors_afi.conf $dev_path/sensors.conf ++ cp $dev_path/platform_afi.json $dev_path/platform.json ++fi +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sysled_health.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sysled_health.py +new file mode 100755 +index 000000000..b303dbcff +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/sysled_health.py +@@ -0,0 +1,14 @@ ++import sonic_platform ++import time ++ ++def main(): ++ ++ pl=sonic_platform.platform.Platform() ++ cha=pl.get_chassis() ++ # Loop forever: ++ while True: ++ time.sleep(5) ++ cha.set_status_led("green") ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/updateCPLD b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts/utils/updateCPLD +new file mode 100755 +index 0000000000000000000000000000000000000000..5d9f81e6a5bb85f10d06a363a220717c4f1f3c64 +GIT binary patch +literal 23328 +zcmeHv3wRvWmFBH3y&tw7wq?fzm5_~vL$~AywqzT-CE?e^!9q5K4cTqAx=T_It!~i| +zBgLMLFqsJfl5ww{fy{z&F#9DYGhfI|c4E(vARgJU!_E#Ngk^VuZHbx0vq?4vzJL{M +zdjE6lp6=@E?%>QOn{U34D^;C)&OPVcd(ORe>(=R8_37<dkF|bo^z0RDGmH%B1rkkc8LOdWrpD+7FjT4xf>uy?Yz{~pcn^LeWm=e +zRJEU>GFNnlL&KfnpgSCjBq!Z|e=IPzVZA3F^{lb%CjG>_^ZFZQP1N6&GH0C{0hZxt +zQM5&XbvPC(oaC!jo|>>22l=)MM-7f8IO=f}OH?n_N8_ZJPuOSNo?4rd1;{VO(X43H +zPD<1UqLXf^({hCL4$*twyyr52lIbRtP}`lU4TNHJYEv=#-V$_bZ!!LVQ-V(ZF2+xN +zQjGrD67*dq=ybUh(=$+lehPF0hcjIRLNPrZCFs*7=$lK>zf^)gRe~NXL8q}>tet%& +z=;0D{6ZA%mv}e0|k+a6U%;0(p(Dk)J#3y2*NMb~cL?_IMh$mu^!1#oiFk`W3OiUyb +zaS=29;czq{{KL^$f;bYEPXwVwgrb2&SR~_N +z)0_|^x5q*W$w{^NeAEtKJmHTeeB=I5M2y5tQ|#QcyRYB3*0W|KI7Y{#5yjy{(_JP0 +zN|i`!ah=hh5Ij%am--W2b}n(;Di-NZ%Rd?}X8SzAexu2kuFGsv{&ay(dO20u=<;G# +z1r0Vj%_W?c+UPuwP?=$)+wV^uHoAQ->ax*!9wI&6Hag!+i0-w~d0r&?E*qWZMNR`Y +zx_y4T*+!=^%W23)xBGLj8|Jp93|H$*t%m+XK2Ub9(dC_Qa0yu^@e1Hq*zg+QeKvdn@L?O?1pKfK +zUjqDL8~!2SPucLxfzR3SD}cMST>V!9zru#E2Ht1GJ-~-;_*&qHZTJS@58Lofz@M_= +zTY=Bn@IK%!SFZjYz^}03zX!a}hF=eS*oF@RKWxKq0{*ZK{{---Ed0Y_`i0AJ{G%=& +zoz=bbbL}GaBlMpT=@*2Uc~exKcvJkB!*A-qb>KR1{nb0)ECXH!ybO5R&+dHlFEW|? +zzKdfTeJjrGoc9Xx&2MKiE!6+ix1gUBhMu|uunlmV5I;GAt_4lCe +zYtm?&A*Kh1`t+W+YQ6Ip4?ZQw=8w?Eiw7T&EiaEn>d5D^P==gk-9>g +zenErmA3#TXoA->E`0ze)$a{2lp?BU8;vUQ{^XV2bPrQBL1Mdr8AYSN6Z}y(iE)z{@ +z)CpUA2x4wcrBRR6RVEtKsEhKgTf}XjzmVBa{kR5ZVYc@UoLb}y^<}mRJaogX*=a7FMvv}$%(7g52P4FY8g6To_$;E?b +zEPs%msOXt%fj^!QJ(-UH-ijlN_O^J>_{qj7+Wo-7+rpJ%fBI>WIt<&%S8J&(pru?c +z3-=KIx=6XoEPOTL+H@0SdNSX`@f?o7hkv5p9M9dk6kl`poT?mS-%X{jH*XZd0e^*L-3 +z)GuV`6KKz6qM7(_J)fb+kwxTl_JKiml<>hD&}sL<&j`2q;Gcj`SE7x-2_Kxad@y~9 +zK6npx=lMXmQvU%o8V|VN<@?|x@Q0{tB7VQk2Lg3nJor5|PHkgmxi}-oOlNMayhOIM +zpDOal%2!JHVL9skRbzq6?PK9De?31u?)1Y6S1M4-51r(P2I+^P`P^8@_rqW3t{wOx +zvkGGfeZ$v9m~B0Y@%|MYU&HZrjC-~vfN?*HF--m0s>c1Tz`6WRHSRwP+EMVVQatwn +zf7-I$OJm>`)Z3pw?(fLA^)WoYjoN-qo+^&?{byaL +zU)FGq$^NwLH55Lp8>@%JkwM(IYUp|%viV^q&ky<6a|YKkjV~U@e~o(6l||-n9;c<| +zZ!Z6TxMu$zb=&5y$AnRqI-vZ3weF%cuG91rS`R^SsA^yOZ#dtuFa0g#pXlwG{hQvN +zxo`FMyso=e&*|FgSzWA__tojL)YqXa|C)CAg6<18U)&DfHXQ+;@9li&AJG+ib--&xYY(RaFrm<$J0k2#mHPiaV+e7__HQatGW880z#imBI +zd$t8@s=eO7*oJlD=P-7sY0ZLlBdxVwht7xf=@;6t){t!(sz_~uenVJm8LUmPzI$5D +zSEbvu@)Fu~N3puGhRN2Qu1GD19*mbJIrdO@Yn6E8^JE+4U(w$9d=VW_mD_YoSEk56 +z#oC|ItG|Eopvc`*u&$%J(%W2TGMjO1#L=S7r}e5->xK2FEO?EA8x-8AV7G!j3T{$x +zvx4hRWm=(cx$6wAQ)XMIU%<8TD6Qwda{>K_b!2Ouxb0rpHjREyqyCpPj4@i%8uZNI +zo&Pkghgu-t(szdX_-^t8<`v?7j(NQn@0W?N>Uxap8lrJXV+=Z`Nr&svlaS-_H;cMS{u#`zCn3Z53~*}m +z>}IQeaiS`9is}O{WxHS(*=^UKw)FdmuM&My**g#3H|~HBPAGrfjXKcJgK79V-3r~| +z%jC1fO(aA8*rH^rp$~2K1%JPa;#UI +z3<~oC5>2ZT`(JM_PtB?8MKh|UFME|AsC}|c=ywmz8LBRSIog0WQoZ#qE6?qf*EQO@ +zh1#vt_{-VK?cPi62A%B6v{&}bzFvm4e0k~-k|Ep6#0^<}&~*i#rD*($&%{r8%fu<- +zbv0Pe3zw4&1_8du8@smw{aR>B?-~?-Je*Ts_OY1AKY``V=+_4RBQ@o|P(l((OBY +zviFsAb!r*ahw&!Yv?ukc%vba&swe$(F+W6O;%mU6H~p@9mU&mheWo%ceZ8&k%v~gp +zG09`_$;;3uq!0c4ur=4Nrm=hkd_0anNpqY{#=l%X|6%P{n|hV(K>d7A|E|N%CmnWv +z8~6;_2Ro;!y~@r^Cu}WYm*jgNy9OP0-LWKRm+P1E9wP1fgw3ui9d@-XhK$XYf9J5} +z3l3ZECR?g3TQa{PI}C>%Pc|rDpQue8rus3))6KXRFlTR~>kRkE!|M5X#L?bi;DW}~ +zop?U@ERK6bk3l~FV>~M~_acViJvG-XQr@D_is_X_VH0mzK4Fy +z(bQHRU-o`D4;da`&p2%UGR<2X<+a_IhMjz!&w{p1h+F9y+TKqc4!c(nj%$FgEd%&W +z?Qgc9{)+0b+1y)3He1(`Ygul*eFuCJM;TpLJEg7Gd@+mp(3(f;Qnlbi07b?HXdO=R +zfd&N;^OZPa#S$XMEFnFQ5FcXN5+W8Zp-Vx&4-C=$6XWK+U!u)u1Lop2l7{>&(dd43 +zOk4A1;-mW!?sajrhwA5f;sn+o+54DLpLz#!cKj^|{&S`G;z92ztUpo|lj9iKTl=(A +z$1r~$dun6q7q_@heG&Qp`0&QmG1ubf-p1PUoq&Go9jqD7<34-rz5b(zpevz?Z#LuJ +zL-wBhRQ&v$zVy*}1=bgO%cE(137$u`z4VZ)`6q3e%>K9b^`830Eq$ln3G|=h7#PV} +zZLng?_PDYp;ISg9=Ek^x)ZApOj2m10vC-tX8A)udsWFT#!^!wo(1O9(R>OUhvB?0@ +zFoL1@MA$!N1d_2BSdAT>A2$w|v3MvN@f3({83~0=U&KFdZe{tAP;C5mf6O$J6QePI +z(DWGFZ+%YPQ+R`^Q2P28{(X9yda91FkmwMkF~tY{p9R*_9a` +zsC%8eYjWept4N?TXddW9f4Wx&W&7PXNr0ae6UMd1${^KEDP{rr&`H@nT{6L6JdlF^ +zgx?59F_wamGq6#>jC-sEB{kb42{UH&MbGvF*dH>)aMV} +zIvR^6Bf%P@f5WD|J9dzcoC?{3ntk+BB)smAha#g!|BjvHr~ZLG*C|HTPQ^D7i(+_> +zkC)`Fxp4vwH;s5Q5P(ldlHu@_#~28k{K^DN*wzzcwsFb~V5eQHpYOwQOEyIys|L)45a@8jemi>vo{XWFb{ckV-@TDKTNP;w0ZidWHA!F}z68|85;DHZ3 +z@PP+D@W2Ni_`n0dIS3eu8+5<@)S%hXWqm5}#0X(`-V&K; +zX+R0T)yQ;CmDBoz5|{IRe$wS7viQY&*nxo5p?e7k-ZS^ratr6Zas#TIpF2)VZbbhS +zT&mz=1sU+3y|ZecAT9AIb*K!jJ1OzrJKh6!w!)i7Kdo@KL#|`NQ7yT0dko*pSoYkn +z_%jM;|6&;>?Hy9(O8mD5cz^o)RnVpS`(GM#+O@O4f0NOH-R8#rXfzxc!`4(|BpNdk +zV|Z+H5Ady6*quaC2y|!yjkEd&$(czDcyJKe94dRBYuA(xJ>}q

yNKTzW$19v!1zJ;z(BC +z*~`7i3-K9wE<9}k$t7Yi$VMXsP}e)-P7SN2JW=ISOZGhxwu4G&Za9QPo2J^z +zXmb|0zl3w$H*h^r@h5P&?#4-LsYNJRRO{2KV!f;!yPHMXI#9*sI9y^k&Q;nSL_pf7 +zR9H2<2CPin0(zBJ3#;n>TopSVaS<%8s`40$^)KM$dbwpgNM-9Kz4A1X$|}E2psIYF +zKttI}P*@%Y105BjvWlV}RkRhpTAsc@IXa0NtJRfN$ADB;{VC2at?DOGQ+p04tz)4d +zq}n+s)K**hgG9gD%D+u?kIa|90!BKhzB$0U+CL@Eu7%$x4gZ7kYh=FuZz=E7#+2vE +zP)VjpqcI^ +zTBC+sEm0aUx4YI0eZi*M&9yzXyPLNybK$n3uMoAhTWfWU^s+0(ZVJRmMK@LySAz;F +zr79)204kQ)v}VQH#Jp~NE3>y*g>ke +z`E!RgFd*P`_hH1Tm!|sQw#6WdMr{pbmQdriEQ>7Q1{QT81rT+y2In&E-39eRLn21} +zdpw;8q6N)~c&B=U2mxh^=Xv&73zKRW&$s#-t*yPitzBPYeDtF?w7c+jfYvTGf4G=t +z5sHKoo&bsv4#T0#K*c3BAP`H0a`p4Prf=2S+S;y=^@?g2Pt*F}2`xwE$y)!Ppi0*3 +zVWuvgMGFe*?o5nNbOuLYbCJ?e1YQk?Whj3%5MXE91vz~JO!xin#L` +z7QW-@S1VfKsO;oH`CI6-cr4I4N-x!P2I5J2UC!v;XRP(CTZ{FFZ}(pOv=9tM=%h?(uLakqDb^`~nm5M}Yf>L)V5UHmoY6ltxD+5eHR9+YuXwuEZE|0l4u>P$UW@5`{v<E{d7`_%&qrE({#eXEWxYZq +z;-OEOzJxF%2k7mi5tQc@+eWI?l8nSdqY?b%V5yUDE5Wf+Fkc>S!>>gC7^o95v!Gu5 +z=oa{0dwgJb|F7$Jcnbz)%_g%1OgSK=cY@L6aF`hKEhbmwxt<8c`;0E8{Ipr2ni$~h +zM3ywdSzdyaiMOUPUE>XxtZ}eV<5)3`g9REjYI-ZUAIX<7iT5vodpI#$4Zjeu}73}|fdY$M}{>-P>XP>9? +z=?et+TRwfE;K!zXdPDZT@qButFjjc&B$?Oo<|@Z^?1egho#c2*-@Soao5dN%r$U#QDxgnSxdy8Lyl7@gLVg-Mss +zAjRmdg+x$vVHD7@4#acn8yRQ8A4)>u_@{@WV*J&lNED8f(|9r}#&78_94B?qQ;eUU +z)QZu$UY=iMvvK-7_+4lZ(-)}%i@$LETlB*5OwYKb>#Y?$4{^P$hvy@v*Ol-Cx4%Qp +zi_G5wermsyzD&_?cJN#NY!Ne#aeKAmKjPr;16{+L$j>W&m?@K`r||l^LGl;UCzXDV +z<8u2gJ%!irXQZA&I**6D9P_tDZxrht^MggtwV&%f3H_z}t6n_g@B`O-e~EhUchpNS +zNB%1P`~<@7;r4s4^fF1pQsaU7?{e@zA^p}UoODuFtUZ4RetPrYIZwVO^%TyNKUVzC +z`SzERUN~>pV@08f!gm;4pnxA%-pdTy~!ob%#ob&T1z~5l| +zJ^^bRE1~C*q}Pj=o4k^h<{e7+D*B1VUWw1hvk=EYFZTU|{|q|S`?BM@`-Y^qWWSf7 +z)QHncf7L>-Bw5i)A>2fF70y4;meBvA)WceH@W&v&IJdq8eXs=GEJ2?Fy`f0|{*mOb7x$`m?ot*1utYnLg5TiA+2F%U&p$MKB~|WG +zLGCX>Z*&#TpEHX8oD3~uFO-x*6j0I?Vgs*|9(*l^*FQjI`l-^>;L!6<2|ZQi)Gvi; +zxun+%o@e-J<0B>b|2wYVV&ijb3I0#3c5-}+Td)`W#q@k!(VumU|A5qAFNT(Qr3$%M +z2e~mtf45?_?^f}g}`kiCB#}vIzU8l#C)X5Th{t9&JUuQc*CC1N6(&H*z +zCp=X`|BI5IyT3f3+Vj6k@QdF<$VSHGiiFvs!@r*k<#Zw%5NV!IurbBStkO6Zu%9>_OqDV3PKh!bvP91M1Vj=ZEb->8Och*V0jZ#gy}BXn-;DVZ<34;02b)t70trTa +zqv7bVKkN%4ycPHPlanG49iIrB*rn^~UbAsSaVC3Q3cIgkQ}`?nc31m?$?@?ih}bZD +zgv(-0${nY)WtBEkqj9#Fme03iu=iuzecP|U&gUzP(fF?WSJ(G`Y;sqZc2(J+``2L~~!;cAyW +zOv(E~l5+<+%7gK!Z_FPFB2<^#$8LSiDZh^V_;7A7y!;GQ9xLoDVJ1aKWthwJ7X3ZH?p>Q?*e)kmZ9B;{a8(n}2pMMiH;PDp=XZ@c=?R35X>xBp}P +zYS7E?R^^pq^6@3$A#>9DR8?M~@WiLa6aHa9eD_MiG0q_-Y{n*pM^4MVeY@QW|ETaF +zGVU4k$H#;xI2D1g1rsr=ga@x=Q-}{`2yOdGK;>(I|A`ChhI2Lp9@p6N>kqQ;Gc~wha@fe<>L(?$N#z&fy(VkJsxC9?Z{Q) +zVEO$nFEG3;qzHz@awlE~GUXa%ur$cZb3Borrzt&Vf$aXHDuuHi`rYzv?A_t|J9Mw) +z=)ii0(h3U{$Sbm-aC0pVmgo57fRevi70?gyWINZt6nRShIEaMekSghLU%-Uy;QqGUQ8^=lJPq +zCEukOl{p3W-=^gI6d%V~&nkJ|&qeY}a5(*U5H#|MV$a578>&G>;&_#XS#9M!!2>w# +z@*KDAQu0R}4sTGx4DWEr^Ll?qZD{*5M+3P1N{ygR8ut1*4jfjYN3MtYdE7FN_xPne +z`=6herj0Fr~*?|DS`7ofh&M +zAQq0B@b^lc{ERa^0~z{09h=E8yC|Ts!}1*W=I_C#RsZw&Vma=Y +z{|Z@RVR?>^zuXBT67yMDVf{ZqfnA>C=x3Gu^DL+!*U#`3hdjq~PIp-XrRrz3bI6b` +zZa+WQJ$s4rKZY!|U$G-+C6>RD2?{EAN*N-Z!@)GgB7s2@Gg5=2&}k0^+#M`Zu1igP +z#~kC&$y*D8lST@jSufRyvv)~l~12}lx^8JsdS%-;I +fApLt1h&TAgVWC<36^a;9ary64Wk|c<$Nv8dA~k3V + +literal 0 +HcmV?d00001 + +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/Makefile b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/Makefile +new file mode 100755 +index 000000000..6f8def9d8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/Makefile +@@ -0,0 +1,17 @@ ++ifneq ($(KERNELRELEASE),) ++obj-m:= wistron_cpld.o wistron_max31790.o wistron_eeprom.o ++else ++ifeq (,$(KERNEL_SRC)) ++#$(error KERNEL_SRC is not defined) ++KVERSION=3.16.0-8-amd64 ++KERNEL_DIR = /usr/src/linux-headers-$(KVERSION)/ ++KERNELDIR:=$(KERNEL_DIR) ++else ++KERNELDIR:=$(KERNEL_SRC) ++endif ++PWD:=$(shell pwd) ++default: ++ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ++clean: ++ rm -rf *.o *.mod.o *.mod.o *.ko .*cmd *.mod.c .tmp_versions Module.markers Module.symvers modules.order *.mod ++endif +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.c b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.c +new file mode 100755 +index 000000000..0b40f81a3 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.c +@@ -0,0 +1,2156 @@ ++/* ++ * A hwmon driver for the wistron_switch_cpld ++ * ++ */ ++ ++/* ---------------------------------------------------------------------------- ++ * Include files ++ * ---------------------------------------------------------------------------- ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* --------------------------------------------------------------------------- ++ * Constant ++ * ---------------------------------------------------------------------------- ++ */ ++#include "wistron_cpld.h" ++ ++static LIST_HEAD(cpld_client_list); ++static struct mutex list_lock; ++ ++struct cpld_client_node { ++ struct i2c_client *client; ++ struct list_head list; ++}; ++ ++/* ---------------------------------------------------------------------------- ++ * ++ * Module attribute functions ++ * ---------------------------------------------------------------------------- ++ */ ++/* ++static ssize_t cpld_show_board_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, ver = 0, ver2 = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0xf0) >> 4; ++ ver2 = (val & 0xf); ++ return sprintf(buf, "%s %s\n", (ver == 0) ? "EVT" : (ver == 1) ? "DVT" : "PVT", (ver2 == 0) ? "with CPU" : "without CPU" ); ++} ++*/ ++ ++static ssize_t cpld_show_board_id(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, ver = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0x7); ++ ++ return sprintf(buf, "%d\n", ver); ++} ++ ++static ssize_t cpld_show_fan_direction(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, ver = 0; ++ unsigned char command = CPLD_HW_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ ver = (val & 0x4) >> 2; ++ ++ return sprintf(buf, "%d\n", ver); ++} ++ ++static ssize_t cpld_show_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, mjr_ver = 0, mnr_ver = 0; ++ unsigned char command = CPLD_REVISION_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ mjr_ver = (val & 0xf0) >> 4; ++ mnr_ver = (val & 0xf) ; ++ ++ return sprintf(buf, "%d.%d\n", mjr_ver, mnr_ver); ++} ++ ++static ssize_t cpld_show_build_date(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, b_year = 0, b_month = 0, b_day = 0; ++ unsigned char command = CPLD_BUILD_YEAR_REG; ++ unsigned char command2 = CPLD_BUILD_DATE_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ b_year = (val & 0xfe) >> 1; ++ b_month = ((val & 0x1) << 3) + ((val2 & 0xe0) >> 5); ++ b_day = val2 & 0x1f; ++ return sprintf(buf, "20%02d %02d %02d\n", b_year, b_month, b_day); ++} ++ ++static ssize_t cpld_read_psu_status(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0; ++ unsigned char command = CPLD_PSU_CHECK_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & (1 << bit)) >> bit; ++ //0 : present ++ //1 : not present ++ //0 : power on ++ //1 : power off ++ if ( (bit == PSU2_PRESENT) || (bit == PSU1_PRESENT) || (bit == PSU2_ON) || (bit == PSU1_ON) ) ++ res = (res) ? 0 : 1; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t cpld_write_psu_status(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_PSU_CHECK_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask << bit); ++ ++ val |= (~(res) << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t cpld_show_power_ctrl(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, i = 0; ++ unsigned char command = CPLD_POWER_CTL1_REG; ++ unsigned char command2 = CPLD_POWER_CTL2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_ctrl_str1[i], ((val & (1 << i)) >> i) ? "Enable" : "Disable"); ++ } ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_ctrl_str2[i], ((val2 & (1 << i)) >> i) ? "Enable" : "Disable"); ++ } ++ ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t cpld_show_power_good(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, val2 = 0, i = 0; ++ unsigned char command = CPLD_POWER_GOOD_REG; ++ unsigned char command2 = CPLD_POWER_GOOD2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val2 = i2c_smbus_read_byte_data(client, command2); ++ if (val2 < 0) { ++ mutex_unlock(&list_lock); ++ return val2; ++ } ++ mutex_unlock(&list_lock); ++ ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_good_str1[i], ((val & (1 << i)) >> i) ? "OK" : "Failed"); ++ } ++ for (i = 0; i < 8; i++) { ++ sprintf(buf + strlen(buf), "%s: %s\n", power_good_str2[i], ((val2 & (1 << i)) >> i) ? "OK" : "Failed"); ++ } ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t port_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT1) || (sda->index == PORT2)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT3) || (sda->index == PORT4)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT5) || (sda->index == PORT6)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT7) || (sda->index == PORT8)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT9) || (sda->index == PORT10)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT11) || (sda->index == PORT12)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT13) || (sda->index == PORT14)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT15) || (sda->index == PORT16)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT17) || (sda->index == PORT18)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT19) || (sda->index == PORT20)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT21) || (sda->index == PORT22)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT23) || (sda->index == PORT24)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT25) || (sda->index == PORT26)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT27) || (sda->index == PORT28)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT29) || (sda->index == PORT30)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT31) || (sda->index == PORT32)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT33) || (sda->index == PORT34)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT35) || (sda->index == PORT36)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT37) || (sda->index == PORT38)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT39) || (sda->index == PORT40)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT41) || (sda->index == PORT42)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT43) || (sda->index == PORT44)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT45) || (sda->index == PORT46)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT47) || (sda->index == PORT48)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT49) || (sda->index == PORT50)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT51) || (sda->index == PORT52)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT53) || (sda->index == PORT54)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 2) * 4; ++ mask = (0x7) << bit; ++ } else{ ++ bit = ((sda->index + 1) % 2) * 4; ++ mask = (0x7) << bit; ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT1) || (sda->index == PORT2)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT3) || (sda->index == PORT4)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT5) || (sda->index == PORT6)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT7) || (sda->index == PORT8)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT9) || (sda->index == PORT10)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT11) || (sda->index == PORT12)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT13) || (sda->index == PORT14)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT15) || (sda->index == PORT16)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT17) || (sda->index == PORT18)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT19) || (sda->index == PORT20)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT21) || (sda->index == PORT22)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT23) || (sda->index == PORT24)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT25) || (sda->index == PORT26)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT27) || (sda->index == PORT28)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT29) || (sda->index == PORT30)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT31) || (sda->index == PORT32)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT33) || (sda->index == PORT34)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT35) || (sda->index == PORT36)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT37) || (sda->index == PORT38)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT39) || (sda->index == PORT40)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT41) || (sda->index == PORT42)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT43) || (sda->index == PORT44)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT45) || (sda->index == PORT46)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT47) || (sda->index == PORT48)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT49) || (sda->index == PORT50)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT51) || (sda->index == PORT52)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT53) || (sda->index == PORT54)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ if (res < 0 || res > 4) ++ return -EINVAL; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 2) * 4; ++ mask = (0x7) << bit; ++ } else{ ++ bit = ((sda->index + 1) % 2) * 4; ++ mask = (0x7) << bit; ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++/* ++static ssize_t port_led_act_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT0) || (sda->index == PORT1)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT2) || (sda->index == PORT3)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT4) || (sda->index == PORT5)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT6) || (sda->index == PORT7)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT8) || (sda->index == PORT9)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT10) || (sda->index == PORT11)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT12) || (sda->index == PORT13)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT14) || (sda->index == PORT15)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT16) || (sda->index == PORT17)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT18) || (sda->index == PORT19)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT20) || (sda->index == PORT21)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT22) || (sda->index == PORT23)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT24) || (sda->index == PORT25)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT26) || (sda->index == PORT27)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT28) || (sda->index == PORT29)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT30) || (sda->index == PORT31)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT32) || (sda->index == PORT33)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT34) || (sda->index == PORT35)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT36) || (sda->index == PORT37)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT38) || (sda->index == PORT39)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT40) || (sda->index == PORT41)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT42) || (sda->index == PORT43)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT44) || (sda->index == PORT45)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT46) || (sda->index == PORT47)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT48) || (sda->index == PORT49)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT50) || (sda->index == PORT51)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT52) || (sda->index == PORT53)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ bit = (((sda->index) % 2) * 4) + 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_act_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if ((sda->index == PORT0) || (sda->index == PORT1)) ++ command = CPLD_1G_LED_CTL1_REG; ++ else if ((sda->index == PORT2) || (sda->index == PORT3)) ++ command = CPLD_1G_LED_CTL2_REG; ++ else if ((sda->index == PORT4) || (sda->index == PORT5)) ++ command = CPLD_1G_LED_CTL3_REG; ++ else if ((sda->index == PORT6) || (sda->index == PORT7)) ++ command = CPLD_1G_LED_CTL4_REG; ++ else if ((sda->index == PORT8) || (sda->index == PORT9)) ++ command = CPLD_1G_LED_CTL5_REG; ++ else if ((sda->index == PORT10) || (sda->index == PORT11)) ++ command = CPLD_1G_LED_CTL6_REG; ++ else if ((sda->index == PORT12) || (sda->index == PORT13)) ++ command = CPLD_1G_LED_CTL7_REG; ++ else if ((sda->index == PORT14) || (sda->index == PORT15)) ++ command = CPLD_1G_LED_CTL8_REG; ++ else if ((sda->index == PORT16) || (sda->index == PORT17)) ++ command = CPLD_1G_LED_CTL9_REG; ++ else if ((sda->index == PORT18) || (sda->index == PORT19)) ++ command = CPLD_1G_LED_CTL10_REG; ++ else if ((sda->index == PORT20) || (sda->index == PORT21)) ++ command = CPLD_1G_LED_CTL11_REG; ++ else if ((sda->index == PORT22) || (sda->index == PORT23)) ++ command = CPLD_1G_LED_CTL12_REG; ++ else if ((sda->index == PORT24) || (sda->index == PORT25)) ++ command = CPLD_1G_LED_CTL13_REG; ++ else if ((sda->index == PORT26) || (sda->index == PORT27)) ++ command = CPLD_1G_LED_CTL14_REG; ++ else if ((sda->index == PORT28) || (sda->index == PORT29)) ++ command = CPLD_1G_LED_CTL15_REG; ++ else if ((sda->index == PORT30) || (sda->index == PORT31)) ++ command = CPLD_1G_LED_CTL16_REG; ++ else if ((sda->index == PORT32) || (sda->index == PORT33)) ++ command = CPLD_2_5G_LED_CTL1_REG; ++ else if ((sda->index == PORT34) || (sda->index == PORT35)) ++ command = CPLD_2_5G_LED_CTL2_REG; ++ else if ((sda->index == PORT36) || (sda->index == PORT37)) ++ command = CPLD_2_5G_LED_CTL3_REG; ++ else if ((sda->index == PORT38) || (sda->index == PORT39)) ++ command = CPLD_2_5G_LED_CTL4_REG; ++ else if ((sda->index == PORT40) || (sda->index == PORT41)) ++ command = CPLD_2_5G_LED_CTL5_REG; ++ else if ((sda->index == PORT42) || (sda->index == PORT43)) ++ command = CPLD_2_5G_LED_CTL6_REG; ++ else if ((sda->index == PORT44) || (sda->index == PORT45)) ++ command = CPLD_2_5G_LED_CTL7_REG; ++ else if ((sda->index == PORT46) || (sda->index == PORT47)) ++ command = CPLD_2_5G_LED_CTL8_REG; ++ else if ((sda->index == PORT48) || (sda->index == PORT49)) ++ command = CPLD_SFP_LED_CTL1_REG; ++ else if ((sda->index == PORT50) || (sda->index == PORT51)) ++ command = CPLD_SFP_LED_CTL2_REG; ++ else if ((sda->index == PORT52) || (sda->index == PORT53)) ++ command = CPLD_SFP_LED_CTL3_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (sda->index < PORT48){ ++ if (res < 0 || res > 3) ++ return -EINVAL; ++ }else{ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ } ++ ++ bit = (((sda->index) % 2) * 4) + 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++*/ ++static ssize_t port_poe_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ ++ if (sda->index < PORT5) ++ command = CPLD_POE_PRT_LED_CTL1_REG; ++ else if (sda->index < PORT9) ++ command = CPLD_POE_PRT_LED_CTL2_REG; ++ else if (sda->index < PORT13) ++ command = CPLD_POE_PRT_LED_CTL3_REG; ++ else if (sda->index < PORT17) ++ command = CPLD_POE_PRT_LED_CTL4_REG; ++ else if (sda->index < PORT21) ++ command = CPLD_POE_PRT_LED_CTL5_REG; ++ else if (sda->index < PORT25) ++ command = CPLD_POE_PRT_LED_CTL6_REG; ++ else if (sda->index < PORT29) ++ command = CPLD_POE_PRT_LED_CTL7_REG; ++ else if (sda->index < PORT33) ++ command = CPLD_POE_PRT_LED_CTL8_REG; ++ else if (sda->index < PORT37) ++ command = CPLD_POE_PRT_LED_CTL9_REG; ++ else if (sda->index < PORT41) ++ command = CPLD_POE_PRT_LED_CTL10_REG; ++ else if (sda->index < PORT45) ++ command = CPLD_POE_PRT_LED_CTL11_REG; ++ else if (sda->index < PORT49) ++ command = CPLD_POE_PRT_LED_CTL12_REG; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 4) * 2; ++ mask = (0x3) << bit; ++ } else { ++ switch( (sda->index) % 4 ){ ++ case 0: ++ bit = 2; ++ mask = (0x3) << bit; ++ break; ++ case 1: ++ bit = 0; ++ mask = (0x3) << bit; ++ break; ++ case 2: ++ bit = 6; ++ mask = (0x3) << bit; ++ break; ++ case 3: ++ bit = 4; ++ mask = (0x3) << bit; ++ break; ++ } ++ } ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_poe_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ ++ if (sda->index < PORT5) ++ command = CPLD_POE_PRT_LED_CTL1_REG; ++ else if (sda->index < PORT9) ++ command = CPLD_POE_PRT_LED_CTL2_REG; ++ else if (sda->index < PORT13) ++ command = CPLD_POE_PRT_LED_CTL3_REG; ++ else if (sda->index < PORT17) ++ command = CPLD_POE_PRT_LED_CTL4_REG; ++ else if (sda->index < PORT21) ++ command = CPLD_POE_PRT_LED_CTL5_REG; ++ else if (sda->index < PORT25) ++ command = CPLD_POE_PRT_LED_CTL6_REG; ++ else if (sda->index < PORT29) ++ command = CPLD_POE_PRT_LED_CTL7_REG; ++ else if (sda->index < PORT33) ++ command = CPLD_POE_PRT_LED_CTL8_REG; ++ else if (sda->index < PORT37) ++ command = CPLD_POE_PRT_LED_CTL9_REG; ++ else if (sda->index < PORT41) ++ command = CPLD_POE_PRT_LED_CTL10_REG; ++ else if (sda->index < PORT45) ++ command = CPLD_POE_PRT_LED_CTL11_REG; ++ else if (sda->index < PORT49) ++ command = CPLD_POE_PRT_LED_CTL12_REG; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ ++ if (sda->index < PORT33) { ++ bit = ((sda->index) % 4) * 2; ++ mask = (0x3) << bit; ++ } else { ++ switch( (sda->index) % 4 ){ ++ case 0: ++ bit = 2; ++ mask = (0x3) << bit; ++ break; ++ case 1: ++ bit = 0; ++ mask = (0x3) << bit; ++ break; ++ case 2: ++ bit = 6; ++ mask = (0x3) << bit; ++ break; ++ case 3: ++ bit = 4; ++ mask = (0x3) << bit; ++ break; ++ } ++ } ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t fan_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_FAN_LED_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index * 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t fan_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_FAN_LED_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 2) ++ return -EINVAL; ++ ++ bit = sda->index * 2; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t sys_led_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_SYS_LED_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t sys_led_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_SYS_LED_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 3) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x3) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t rst_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index > RST_MAC_JTAG){ ++ command = CPLD_RESET_CTL2_REG; ++ bit = (sda->index - 8); ++ } else { ++ command = CPLD_RESET_CTL1_REG; ++ bit = sda->index; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++/* ++static ssize_t rst_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ if (sda->index > RST_MAC_JTAG){ ++ command = CPLD_RESET_CTL2_REG; ++ bit = (sda->index - 8); ++ } else { ++ command = CPLD_RESET_CTL1_REG; ++ bit = sda->index; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t int_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index < INT_OOB_IOIEXP){ ++ command = CPLD_INT_CTL1_REG; ++ bit = sda->index; ++ } else if (sda->index < DEV_INIT_DONE){ ++ command = CPLD_INT_CTL2_REG; ++ bit = sda->index - 8; ++ } else if (sda->index < MB_SYSTEM_INT){ ++ command = CPLD_INT_CTL3_REG; ++ bit = sda->index - 16; ++ } else { ++ command = CPLD_INT_CTL4_REG; ++ bit = sda->index - 19; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t int_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ if (sda->index < INT_OOB_IOIEXP){ ++ command = CPLD_INT_CTL1_REG; ++ bit = sda->index; ++ } else if (sda->index < DEV_INIT_DONE){ ++ command = CPLD_INT_CTL2_REG; ++ bit = sda->index - 8; ++ } else if (sda->index < MB_SYSTEM_INT){ ++ command = CPLD_INT_CTL3_REG; ++ bit = sda->index - 16; ++ } else { ++ command = CPLD_INT_CTL4_REG; ++ bit = sda->index - 19; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++*/ ++static ssize_t fan_ctrl_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = 0; ++ if (sda->index < PWRGD_VR_P12V_FAN3){ ++ command = CPLD_FAN_CTL1_REG; ++ bit = sda->index; ++ } else { ++ command = CPLD_FAN_CTL2_REG; ++ bit = sda->index - PWRGD_VR_P12V_FAN3; ++ } ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ // fan present bit is active low ++ if ( (sda->index == CNFAN1_PRESENT) || (sda->index == CNFAN2_PRESENT) || (sda->index == CNFAN3_PRESENT) ) ++ res = (res) ? 0 : 1; ++ ++ // fan enable bit is active low ++ //if ( (sda->index == FM_FAN1_EN) || (sda->index == FM_FAN2_EN) || (sda->index == FM_FAN3_EN) ) ++ // res = (res) ? 0 : 1; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t fan_ctrl_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = 0; ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ command = CPLD_FAN_CTL1_REG; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t port_led_auto_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_PORT_LED_MANUAL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ mutex_lock(&list_lock); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t port_led_auto_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_PORT_LED_MANUAL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t poe_enable_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_MSCI_CTL_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t poe_enable_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_MSCI_CTL_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t msci_ctl2_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = 0; ++ unsigned char command = CPLD_MSCI_CTL2_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t msci_ctl2_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); ++ unsigned char command = CPLD_MSCI_CTL2_REG; ++ int val = 0, res = 0, bit = 0, mask = 0; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ bit = sda->index; ++ mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_enable_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ unsigned char command = CPLD_WATCHDOG_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t watchdog_enable_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_refresh(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 1, bit = 1, mask = (0x1) << bit; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t watchdog_timer_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 2, mask = (0x7) << bit; ++ unsigned char command = CPLD_WATCHDOG_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t watchdog_timer_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_WATCHDOG_REG; ++ int val = 0, res = 0, bit = 2, mask = (0x7) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < WATCHDOG_180S || res > WATCHDOG_300S) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++static ssize_t power_down_read(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ unsigned char command = CPLD_SYS_POWER_DOWN_REG; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ res = (val & mask) >> bit; ++ ++ return sprintf(buf, "%d\n", res); ++} ++ ++static ssize_t power_down_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ unsigned char command = CPLD_SYS_POWER_DOWN_REG; ++ int val = 0, res = 0, bit = 0, mask = (0x1) << bit; ++ ++ val = kstrtoint(buf, 10, &res); ++ if (val) ++ return val; ++ ++ if (res < 0 || res > 1) ++ return -EINVAL; ++ ++ mutex_lock(&list_lock); ++ ++ val = i2c_smbus_read_byte_data(client, command); ++ if (val < 0) { ++ mutex_unlock(&list_lock); ++ return val; ++ } ++ ++ val &= ~(mask); ++ ++ val |= (res << bit); ++ ++ i2c_smbus_write_byte_data(client, command, val); ++ ++ mutex_unlock(&list_lock); ++ ++ return count; ++} ++ ++//static SENSOR_DEVICE_ATTR(board_rev, S_IRUGO, cpld_show_board_version, NULL, 0); ++static SENSOR_DEVICE_ATTR(board_id, S_IRUGO, cpld_show_board_id, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan_direction, S_IRUGO, cpld_show_fan_direction, NULL, 0); ++static SENSOR_DEVICE_ATTR(cpld_rev, S_IRUGO, cpld_show_version, NULL, 0); ++static SENSOR_DEVICE_ATTR(build_date, S_IRUGO, cpld_show_build_date, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(psu2_on, S_IRUGO | S_IWUSR, cpld_read_psu_status, cpld_write_psu_status, PSU2_ON); ++static SENSOR_DEVICE_ATTR(psu1_on, S_IRUGO | S_IWUSR, cpld_read_psu_status, cpld_write_psu_status, PSU1_ON); ++static SENSOR_DEVICE_ATTR(psu2_ac_ok, S_IRUGO, cpld_read_psu_status, NULL, PSU2_AC_OK); ++static SENSOR_DEVICE_ATTR(psu1_ac_ok, S_IRUGO, cpld_read_psu_status, NULL, PSU1_AC_OK); ++static SENSOR_DEVICE_ATTR(psu2_present, S_IRUGO, cpld_read_psu_status, NULL, PSU2_PRESENT); ++static SENSOR_DEVICE_ATTR(psu1_present, S_IRUGO, cpld_read_psu_status, NULL, PSU1_PRESENT); ++static SENSOR_DEVICE_ATTR(psu2_power_good, S_IRUGO, cpld_read_psu_status, NULL, PSU2_PWRGD); ++static SENSOR_DEVICE_ATTR(psu1_power_good, S_IRUGO, cpld_read_psu_status, NULL, PSU1_PWRGD); ++ ++ ++static SENSOR_DEVICE_ATTR(power_ctrl, S_IRUGO, cpld_show_power_ctrl, NULL, 0); ++static SENSOR_DEVICE_ATTR(power_good, S_IRUGO, cpld_show_power_good, NULL, 0); ++ ++static SENSOR_DEVICE_ATTR(fan_full_speed, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FAN_FULL_SPEED); ++static SENSOR_DEVICE_ATTR(fm_fan3_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN3_EN); ++static SENSOR_DEVICE_ATTR(fm_fan2_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN2_EN); ++static SENSOR_DEVICE_ATTR(fm_fan1_en, S_IRUGO | S_IWUSR, fan_ctrl_read, fan_ctrl_write, FM_FAN1_EN); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan3, S_IRUGO , fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN3); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan2, S_IRUGO, fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN2); ++static SENSOR_DEVICE_ATTR(pwrgd_vr_p12v_fan1, S_IRUGO, fan_ctrl_read, NULL, PWRGD_VR_P12V_FAN1); ++static SENSOR_DEVICE_ATTR(cnfan3_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN3_PRESENT); ++static SENSOR_DEVICE_ATTR(cnfan2_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN2_PRESENT); ++static SENSOR_DEVICE_ATTR(cnfan1_present, S_IRUGO, fan_ctrl_read, NULL, CNFAN1_PRESENT); ++ ++static SENSOR_DEVICE_ATTR(port1_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT48); ++static SENSOR_DEVICE_ATTR(port49_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT49); ++static SENSOR_DEVICE_ATTR(port50_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT50); ++static SENSOR_DEVICE_ATTR(port51_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT51); ++static SENSOR_DEVICE_ATTR(port52_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT52); ++static SENSOR_DEVICE_ATTR(port53_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT53); ++static SENSOR_DEVICE_ATTR(port54_led, S_IRUGO | S_IWUSR, port_led_read, port_led_write, PORT54); ++/* ++static SENSOR_DEVICE_ATTR(port0_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT0); ++static SENSOR_DEVICE_ATTR(port1_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT48); ++static SENSOR_DEVICE_ATTR(port49_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT49); ++static SENSOR_DEVICE_ATTR(port50_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT50); ++static SENSOR_DEVICE_ATTR(port51_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT51); ++static SENSOR_DEVICE_ATTR(port52_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT52); ++static SENSOR_DEVICE_ATTR(port53_act_led, S_IRUGO | S_IWUSR, port_led_act_read, port_led_act_write, PORT53); ++*/ ++ ++static SENSOR_DEVICE_ATTR(port1_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT1); ++static SENSOR_DEVICE_ATTR(port2_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT2); ++static SENSOR_DEVICE_ATTR(port3_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT3); ++static SENSOR_DEVICE_ATTR(port4_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT4); ++static SENSOR_DEVICE_ATTR(port5_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT5); ++static SENSOR_DEVICE_ATTR(port6_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT6); ++static SENSOR_DEVICE_ATTR(port7_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT7); ++static SENSOR_DEVICE_ATTR(port8_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT8); ++static SENSOR_DEVICE_ATTR(port9_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT9); ++static SENSOR_DEVICE_ATTR(port10_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT10); ++static SENSOR_DEVICE_ATTR(port11_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT11); ++static SENSOR_DEVICE_ATTR(port12_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT12); ++static SENSOR_DEVICE_ATTR(port13_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT13); ++static SENSOR_DEVICE_ATTR(port14_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT14); ++static SENSOR_DEVICE_ATTR(port15_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT15); ++static SENSOR_DEVICE_ATTR(port16_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT16); ++static SENSOR_DEVICE_ATTR(port17_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT17); ++static SENSOR_DEVICE_ATTR(port18_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT18); ++static SENSOR_DEVICE_ATTR(port19_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT19); ++static SENSOR_DEVICE_ATTR(port20_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT20); ++static SENSOR_DEVICE_ATTR(port21_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT21); ++static SENSOR_DEVICE_ATTR(port22_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT22); ++static SENSOR_DEVICE_ATTR(port23_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT23); ++static SENSOR_DEVICE_ATTR(port24_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT24); ++static SENSOR_DEVICE_ATTR(port25_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT25); ++static SENSOR_DEVICE_ATTR(port26_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT26); ++static SENSOR_DEVICE_ATTR(port27_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT27); ++static SENSOR_DEVICE_ATTR(port28_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT28); ++static SENSOR_DEVICE_ATTR(port29_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT29); ++static SENSOR_DEVICE_ATTR(port30_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT30); ++static SENSOR_DEVICE_ATTR(port31_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT31); ++static SENSOR_DEVICE_ATTR(port32_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT32); ++static SENSOR_DEVICE_ATTR(port33_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT33); ++static SENSOR_DEVICE_ATTR(port34_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT34); ++static SENSOR_DEVICE_ATTR(port35_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT35); ++static SENSOR_DEVICE_ATTR(port36_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT36); ++static SENSOR_DEVICE_ATTR(port37_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT37); ++static SENSOR_DEVICE_ATTR(port38_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT38); ++static SENSOR_DEVICE_ATTR(port39_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT39); ++static SENSOR_DEVICE_ATTR(port40_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT40); ++static SENSOR_DEVICE_ATTR(port41_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT41); ++static SENSOR_DEVICE_ATTR(port42_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT42); ++static SENSOR_DEVICE_ATTR(port43_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT43); ++static SENSOR_DEVICE_ATTR(port44_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT44); ++static SENSOR_DEVICE_ATTR(port45_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT45); ++static SENSOR_DEVICE_ATTR(port46_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT46); ++static SENSOR_DEVICE_ATTR(port47_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT47); ++static SENSOR_DEVICE_ATTR(port48_poe_led, S_IRUGO | S_IWUSR, port_poe_led_read, port_poe_led_write, PORT48); ++ ++static SENSOR_DEVICE_ATTR(fan1_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN1); ++static SENSOR_DEVICE_ATTR(fan2_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN2); ++static SENSOR_DEVICE_ATTR(fan3_led, S_IRUGO | S_IWUSR, fan_led_read, fan_led_write, FAN3); ++ ++static SENSOR_DEVICE_ATTR(loc_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, LOC_LED); ++static SENSOR_DEVICE_ATTR(psu_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, PSU_LED); ++static SENSOR_DEVICE_ATTR(sys_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, SYS_LED); ++static SENSOR_DEVICE_ATTR(fan_led, S_IRUGO | S_IWUSR, sys_led_read, sys_led_write, FAN_LED); ++ ++static SENSOR_DEVICE_ATTR(port_led_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_PORT_LED_EN); ++static SENSOR_DEVICE_ATTR(sysled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_SYS_LED_EN); ++static SENSOR_DEVICE_ATTR(psuled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_PSU_LED_EN); ++static SENSOR_DEVICE_ATTR(fanled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_FAN_LED_EN); ++static SENSOR_DEVICE_ATTR(locled_auto, S_IRUGO | S_IWUSR, port_led_auto_read, port_led_auto_write, FRONT_LOC_LED_EN); ++ ++static SENSOR_DEVICE_ATTR(poe_en_ctrl, S_IRUGO | S_IWUSR, poe_enable_read, poe_enable_write, 0); ++ ++static SENSOR_DEVICE_ATTR(psu_budget_mode, S_IRUGO | S_IWUSR, msci_ctl2_read, msci_ctl2_write, PSU_BUDGET_MODE); ++static SENSOR_DEVICE_ATTR(psu_vsense, S_IRUGO | S_IWUSR, msci_ctl2_read, msci_ctl2_write, PSU_VSENSE); ++static SENSOR_DEVICE_ATTR(psu_pwrgd, S_IRUGO, msci_ctl2_read, NULL, PSU_PWRGD); ++static SENSOR_DEVICE_ATTR(rst_button_10s, S_IRUGO, rst_ctrl_read, NULL, RST_BUTTON_10S); ++ ++static SENSOR_DEVICE_ATTR(watchdog_timer, S_IRUGO | S_IWUSR, watchdog_timer_read, watchdog_timer_write, 0); ++static SENSOR_DEVICE_ATTR(watchdog_kick, S_IWUSR, NULL, watchdog_refresh, 0); ++static SENSOR_DEVICE_ATTR(watchdog_en, S_IRUGO | S_IWUSR, watchdog_enable_read, watchdog_enable_write, 0); ++ ++ ++static SENSOR_DEVICE_ATTR(system_power_down, S_IRUGO | S_IWUSR, power_down_read, power_down_write, 0); ++/* ++static SENSOR_DEVICE_ATTR(rst_mb_ioiexp, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MB_IOIEXP); ++static SENSOR_DEVICE_ATTR(rst_phy0_5, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_PHY0_5); ++static SENSOR_DEVICE_ATTR(rst_poe_ctr, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_POE_CTR); ++static SENSOR_DEVICE_ATTR(cpld_sysrst_mac_rst, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, CPLD_SYSRST_MAC_RST); ++static SENSOR_DEVICE_ATTR(rst_cpu_sysrst_out, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_CPU_SYSRST_OUT); ++static SENSOR_DEVICE_ATTR(rst_gphy_rst, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_GPHY_RST); ++static SENSOR_DEVICE_ATTR(rst_i2c_mux, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_I2C_MUX); ++static SENSOR_DEVICE_ATTR(rst_mac_jtag, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MAC_JTAG); ++static SENSOR_DEVICE_ATTR(rst_button_cpld_cpu, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_BUTTON_CPLD_CPU); ++static SENSOR_DEVICE_ATTR(rst_button, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_BUTTON); ++static SENSOR_DEVICE_ATTR(rst_cpld_i2c_mux, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_CPLD_I2C_MUX); ++static SENSOR_DEVICE_ATTR(rst_mac_sys, S_IRUGO | S_IWUSR, rst_ctrl_read, rst_ctrl_write, RST_MAC_SYS); ++ ++static SENSOR_DEVICE_ATTR(int_phy0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY0); ++static SENSOR_DEVICE_ATTR(int_phy1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY1); ++static SENSOR_DEVICE_ATTR(int_phy2, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY2); ++static SENSOR_DEVICE_ATTR(int_phy3, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY3); ++static SENSOR_DEVICE_ATTR(int_phy4_0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY4_0); ++static SENSOR_DEVICE_ATTR(int_phy4_1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY4_1); ++static SENSOR_DEVICE_ATTR(int_phy5_0, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY5_0); ++static SENSOR_DEVICE_ATTR(int_phy5_1, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PHY5_1); ++static SENSOR_DEVICE_ATTR(int_oob_ioiexp, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_OOB_IOIEXP); ++static SENSOR_DEVICE_ATTR(int_mb_ioiexp, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_MB_IOIEXP); ++static SENSOR_DEVICE_ATTR(usb_ocp_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, USB_OCP_ALERT); ++static SENSOR_DEVICE_ATTR(temp_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, TEMP_ALERT); ++static SENSOR_DEVICE_ATTR(rtc_irq, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, RTC_IRQ); ++static SENSOR_DEVICE_ATTR(psu2_int_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, PSU2_INT_ALERT); ++static SENSOR_DEVICE_ATTR(psu1_int_alert, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, PSU1_INT_ALERT); ++static SENSOR_DEVICE_ATTR(int_pd69210, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, INT_PD69210); ++static SENSOR_DEVICE_ATTR(dev_init_done, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, DEV_INIT_DONE); ++static SENSOR_DEVICE_ATTR(fan_ctl_fail, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, FAN_CTL_FAIL); ++static SENSOR_DEVICE_ATTR(memhot, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MEMHOT); ++static SENSOR_DEVICE_ATTR(mb_system_int, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MB_SYSTEM_INT); ++static SENSOR_DEVICE_ATTR(mb_mod_pre_int, S_IRUGO | S_IWUSR, int_ctrl_read, int_ctrl_write, MB_MOD_PRE_INT); ++*/ ++static struct attribute *wistron_switch_cpld_attributes[] = { ++// &sensor_dev_attr_board_rev.dev_attr.attr, ++ &sensor_dev_attr_board_id.dev_attr.attr, ++ &sensor_dev_attr_fan_direction.dev_attr.attr, ++ &sensor_dev_attr_cpld_rev.dev_attr.attr, ++ &sensor_dev_attr_build_date.dev_attr.attr, ++ ++ &sensor_dev_attr_psu2_on.dev_attr.attr, ++ &sensor_dev_attr_psu1_on.dev_attr.attr, ++ &sensor_dev_attr_psu2_ac_ok.dev_attr.attr, ++ &sensor_dev_attr_psu1_ac_ok.dev_attr.attr, ++ &sensor_dev_attr_psu2_present.dev_attr.attr, ++ &sensor_dev_attr_psu1_present.dev_attr.attr, ++ &sensor_dev_attr_psu2_power_good.dev_attr.attr, ++ &sensor_dev_attr_psu1_power_good.dev_attr.attr, ++ ++ &sensor_dev_attr_power_ctrl.dev_attr.attr, ++ &sensor_dev_attr_power_good.dev_attr.attr, ++ ++ &sensor_dev_attr_fan_full_speed.dev_attr.attr, ++ &sensor_dev_attr_fm_fan3_en.dev_attr.attr, ++ &sensor_dev_attr_fm_fan2_en.dev_attr.attr, ++ &sensor_dev_attr_fm_fan1_en.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan3.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan2.dev_attr.attr, ++ &sensor_dev_attr_pwrgd_vr_p12v_fan1.dev_attr.attr, ++ &sensor_dev_attr_cnfan3_present.dev_attr.attr, ++ &sensor_dev_attr_cnfan2_present.dev_attr.attr, ++ &sensor_dev_attr_cnfan1_present.dev_attr.attr, ++ ++ &sensor_dev_attr_port1_led.dev_attr.attr, ++ &sensor_dev_attr_port2_led.dev_attr.attr, ++ &sensor_dev_attr_port3_led.dev_attr.attr, ++ &sensor_dev_attr_port4_led.dev_attr.attr, ++ &sensor_dev_attr_port5_led.dev_attr.attr, ++ &sensor_dev_attr_port6_led.dev_attr.attr, ++ &sensor_dev_attr_port7_led.dev_attr.attr, ++ &sensor_dev_attr_port8_led.dev_attr.attr, ++ &sensor_dev_attr_port9_led.dev_attr.attr, ++ &sensor_dev_attr_port10_led.dev_attr.attr, ++ &sensor_dev_attr_port11_led.dev_attr.attr, ++ &sensor_dev_attr_port12_led.dev_attr.attr, ++ &sensor_dev_attr_port13_led.dev_attr.attr, ++ &sensor_dev_attr_port14_led.dev_attr.attr, ++ &sensor_dev_attr_port15_led.dev_attr.attr, ++ &sensor_dev_attr_port16_led.dev_attr.attr, ++ &sensor_dev_attr_port17_led.dev_attr.attr, ++ &sensor_dev_attr_port18_led.dev_attr.attr, ++ &sensor_dev_attr_port19_led.dev_attr.attr, ++ &sensor_dev_attr_port20_led.dev_attr.attr, ++ &sensor_dev_attr_port21_led.dev_attr.attr, ++ &sensor_dev_attr_port22_led.dev_attr.attr, ++ &sensor_dev_attr_port23_led.dev_attr.attr, ++ &sensor_dev_attr_port24_led.dev_attr.attr, ++ &sensor_dev_attr_port25_led.dev_attr.attr, ++ &sensor_dev_attr_port26_led.dev_attr.attr, ++ &sensor_dev_attr_port27_led.dev_attr.attr, ++ &sensor_dev_attr_port28_led.dev_attr.attr, ++ &sensor_dev_attr_port29_led.dev_attr.attr, ++ &sensor_dev_attr_port30_led.dev_attr.attr, ++ &sensor_dev_attr_port31_led.dev_attr.attr, ++ &sensor_dev_attr_port32_led.dev_attr.attr, ++ &sensor_dev_attr_port33_led.dev_attr.attr, ++ &sensor_dev_attr_port34_led.dev_attr.attr, ++ &sensor_dev_attr_port35_led.dev_attr.attr, ++ &sensor_dev_attr_port36_led.dev_attr.attr, ++ &sensor_dev_attr_port37_led.dev_attr.attr, ++ &sensor_dev_attr_port38_led.dev_attr.attr, ++ &sensor_dev_attr_port39_led.dev_attr.attr, ++ &sensor_dev_attr_port40_led.dev_attr.attr, ++ &sensor_dev_attr_port41_led.dev_attr.attr, ++ &sensor_dev_attr_port42_led.dev_attr.attr, ++ &sensor_dev_attr_port43_led.dev_attr.attr, ++ &sensor_dev_attr_port44_led.dev_attr.attr, ++ &sensor_dev_attr_port45_led.dev_attr.attr, ++ &sensor_dev_attr_port46_led.dev_attr.attr, ++ &sensor_dev_attr_port47_led.dev_attr.attr, ++ &sensor_dev_attr_port48_led.dev_attr.attr, ++ &sensor_dev_attr_port49_led.dev_attr.attr, ++ &sensor_dev_attr_port50_led.dev_attr.attr, ++ &sensor_dev_attr_port51_led.dev_attr.attr, ++ &sensor_dev_attr_port52_led.dev_attr.attr, ++ &sensor_dev_attr_port53_led.dev_attr.attr, ++ &sensor_dev_attr_port54_led.dev_attr.attr, ++/* ++ &sensor_dev_attr_port0_act_led.dev_attr.attr, ++ &sensor_dev_attr_port1_act_led.dev_attr.attr, ++ &sensor_dev_attr_port2_act_led.dev_attr.attr, ++ &sensor_dev_attr_port3_act_led.dev_attr.attr, ++ &sensor_dev_attr_port4_act_led.dev_attr.attr, ++ &sensor_dev_attr_port5_act_led.dev_attr.attr, ++ &sensor_dev_attr_port6_act_led.dev_attr.attr, ++ &sensor_dev_attr_port7_act_led.dev_attr.attr, ++ &sensor_dev_attr_port8_act_led.dev_attr.attr, ++ &sensor_dev_attr_port9_act_led.dev_attr.attr, ++ &sensor_dev_attr_port10_act_led.dev_attr.attr, ++ &sensor_dev_attr_port11_act_led.dev_attr.attr, ++ &sensor_dev_attr_port12_act_led.dev_attr.attr, ++ &sensor_dev_attr_port13_act_led.dev_attr.attr, ++ &sensor_dev_attr_port14_act_led.dev_attr.attr, ++ &sensor_dev_attr_port15_act_led.dev_attr.attr, ++ &sensor_dev_attr_port16_act_led.dev_attr.attr, ++ &sensor_dev_attr_port17_act_led.dev_attr.attr, ++ &sensor_dev_attr_port18_act_led.dev_attr.attr, ++ &sensor_dev_attr_port19_act_led.dev_attr.attr, ++ &sensor_dev_attr_port20_act_led.dev_attr.attr, ++ &sensor_dev_attr_port21_act_led.dev_attr.attr, ++ &sensor_dev_attr_port22_act_led.dev_attr.attr, ++ &sensor_dev_attr_port23_act_led.dev_attr.attr, ++ &sensor_dev_attr_port24_act_led.dev_attr.attr, ++ &sensor_dev_attr_port25_act_led.dev_attr.attr, ++ &sensor_dev_attr_port26_act_led.dev_attr.attr, ++ &sensor_dev_attr_port27_act_led.dev_attr.attr, ++ &sensor_dev_attr_port28_act_led.dev_attr.attr, ++ &sensor_dev_attr_port29_act_led.dev_attr.attr, ++ &sensor_dev_attr_port30_act_led.dev_attr.attr, ++ &sensor_dev_attr_port31_act_led.dev_attr.attr, ++ &sensor_dev_attr_port32_act_led.dev_attr.attr, ++ &sensor_dev_attr_port33_act_led.dev_attr.attr, ++ &sensor_dev_attr_port34_act_led.dev_attr.attr, ++ &sensor_dev_attr_port35_act_led.dev_attr.attr, ++ &sensor_dev_attr_port36_act_led.dev_attr.attr, ++ &sensor_dev_attr_port37_act_led.dev_attr.attr, ++ &sensor_dev_attr_port38_act_led.dev_attr.attr, ++ &sensor_dev_attr_port39_act_led.dev_attr.attr, ++ &sensor_dev_attr_port40_act_led.dev_attr.attr, ++ &sensor_dev_attr_port41_act_led.dev_attr.attr, ++ &sensor_dev_attr_port42_act_led.dev_attr.attr, ++ &sensor_dev_attr_port43_act_led.dev_attr.attr, ++ &sensor_dev_attr_port44_act_led.dev_attr.attr, ++ &sensor_dev_attr_port45_act_led.dev_attr.attr, ++ &sensor_dev_attr_port46_act_led.dev_attr.attr, ++ &sensor_dev_attr_port47_act_led.dev_attr.attr, ++ &sensor_dev_attr_port48_act_led.dev_attr.attr, ++ &sensor_dev_attr_port49_act_led.dev_attr.attr, ++ &sensor_dev_attr_port50_act_led.dev_attr.attr, ++ &sensor_dev_attr_port51_act_led.dev_attr.attr, ++ &sensor_dev_attr_port52_act_led.dev_attr.attr, ++ &sensor_dev_attr_port53_act_led.dev_attr.attr, ++*/ ++ ++ &sensor_dev_attr_port1_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port2_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port3_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port4_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port5_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port6_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port7_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port8_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port9_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port10_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port11_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port12_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port13_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port14_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port15_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port16_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port17_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port18_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port19_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port20_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port21_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port22_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port23_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port24_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port25_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port26_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port27_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port28_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port29_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port30_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port31_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port32_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port33_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port34_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port35_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port36_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port37_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port38_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port39_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port40_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port41_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port42_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port43_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port44_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port45_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port46_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port47_poe_led.dev_attr.attr, ++ &sensor_dev_attr_port48_poe_led.dev_attr.attr, ++ ++ &sensor_dev_attr_fan1_led.dev_attr.attr, ++ &sensor_dev_attr_fan2_led.dev_attr.attr, ++ &sensor_dev_attr_fan3_led.dev_attr.attr, ++ ++ &sensor_dev_attr_loc_led.dev_attr.attr, ++ &sensor_dev_attr_psu_led.dev_attr.attr, ++ &sensor_dev_attr_sys_led.dev_attr.attr, ++ &sensor_dev_attr_fan_led.dev_attr.attr, ++ ++ &sensor_dev_attr_port_led_auto.dev_attr.attr, ++ &sensor_dev_attr_sysled_auto.dev_attr.attr, ++ &sensor_dev_attr_fanled_auto.dev_attr.attr, ++ &sensor_dev_attr_psuled_auto.dev_attr.attr, ++ &sensor_dev_attr_locled_auto.dev_attr.attr, ++ ++ &sensor_dev_attr_poe_en_ctrl.dev_attr.attr, ++ ++ &sensor_dev_attr_psu_budget_mode.dev_attr.attr, ++ &sensor_dev_attr_psu_vsense.dev_attr.attr, ++ &sensor_dev_attr_psu_pwrgd.dev_attr.attr, ++ &sensor_dev_attr_rst_button_10s.dev_attr.attr, ++ ++ &sensor_dev_attr_watchdog_timer.dev_attr.attr, ++ &sensor_dev_attr_watchdog_kick.dev_attr.attr, ++ &sensor_dev_attr_watchdog_en.dev_attr.attr, ++ ++ &sensor_dev_attr_system_power_down.dev_attr.attr, ++/* ++ &sensor_dev_attr_rst_mb_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_rst_phy0_5.dev_attr.attr, ++ &sensor_dev_attr_rst_poe_ctr.dev_attr.attr, ++ &sensor_dev_attr_cpld_sysrst_mac_rst.dev_attr.attr, ++ &sensor_dev_attr_rst_cpu_sysrst_out.dev_attr.attr, ++ &sensor_dev_attr_rst_gphy_rst.dev_attr.attr, ++ &sensor_dev_attr_rst_i2c_mux.dev_attr.attr, ++ &sensor_dev_attr_rst_mac_jtag.dev_attr.attr, ++ &sensor_dev_attr_rst_button_cpld_cpu.dev_attr.attr, ++ &sensor_dev_attr_rst_button.dev_attr.attr, ++ &sensor_dev_attr_rst_cpld_i2c_mux.dev_attr.attr, ++ &sensor_dev_attr_rst_mac_sys.dev_attr.attr, ++ ++ &sensor_dev_attr_int_phy0.dev_attr.attr, ++ &sensor_dev_attr_int_phy1.dev_attr.attr, ++ &sensor_dev_attr_int_phy2.dev_attr.attr, ++ &sensor_dev_attr_int_phy3.dev_attr.attr, ++ &sensor_dev_attr_int_phy4_0.dev_attr.attr, ++ &sensor_dev_attr_int_phy4_1.dev_attr.attr, ++ &sensor_dev_attr_int_phy5_0.dev_attr.attr, ++ &sensor_dev_attr_int_phy5_1.dev_attr.attr, ++ &sensor_dev_attr_int_oob_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_int_mb_ioiexp.dev_attr.attr, ++ &sensor_dev_attr_usb_ocp_alert.dev_attr.attr, ++ &sensor_dev_attr_temp_alert.dev_attr.attr, ++ &sensor_dev_attr_rtc_irq.dev_attr.attr, ++ &sensor_dev_attr_psu2_int_alert.dev_attr.attr, ++ &sensor_dev_attr_psu1_int_alert.dev_attr.attr, ++ &sensor_dev_attr_int_pd69210.dev_attr.attr, ++ &sensor_dev_attr_dev_init_done.dev_attr.attr, ++ &sensor_dev_attr_fan_ctl_fail.dev_attr.attr, ++ &sensor_dev_attr_memhot.dev_attr.attr, ++ &sensor_dev_attr_mb_system_int.dev_attr.attr, ++ &sensor_dev_attr_mb_mod_pre_int.dev_attr.attr, ++*/ ++ NULL ++}; ++ ++static const struct attribute_group wistron_switch_cpld_group = { ++ .attrs = wistron_switch_cpld_attributes, ++}; ++ ++ ++/* ---------------------------------------------------------------------------- ++ * Module probe/remove functions ++ * ---------------------------------------------------------------------------- ++ */ ++static int _add_client(struct i2c_client *client) ++{ ++ struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); ++ if (!node) { ++ dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); ++ return -ENOMEM; ++ } ++ ++ node->client = client; ++ ++ mutex_lock(&list_lock); ++ list_add(&node->list, &cpld_client_list); ++ mutex_unlock(&list_lock); ++ ++ return 0; ++} ++ ++static int _remove_client(struct i2c_client *client) ++{ ++ struct list_head *list_node = NULL; ++ struct cpld_client_node *cpld_node = NULL; ++ int found = 0; ++ ++ mutex_lock(&list_lock); ++ ++ list_for_each(list_node, &cpld_client_list) { ++ cpld_node = list_entry(list_node, struct cpld_client_node, list); ++ ++ if (cpld_node->client == client) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (found) { ++ list_del(list_node); ++ kfree(cpld_node); ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ return 0; ++} ++ ++/* Probe I2C driver */ ++static int wistron_i2c_cpld_probe(struct i2c_client *client, ++ const struct i2c_device_id *dev_id) ++{ ++ int status; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); ++ status = -EIO; ++ goto exit; ++ } ++ ++ status = _add_client(client); ++ if (status < 0) { ++ dev_err(&client->dev, "Failed to add client\n"); ++ goto exit; ++ } ++ ++ status = sysfs_create_group(&client->dev.kobj, &wistron_switch_cpld_group); ++ ++ if (status) { ++ goto exit; ++ } ++ ++ dev_info(&client->dev, "chip found\n"); ++ ++ return 0; ++ ++exit: ++ return status; ++} ++ ++static void wistron_i2c_cpld_remove(struct i2c_client *client) ++{ ++ _remove_client(client); ++ ++ sysfs_remove_group(&client->dev.kobj, &wistron_switch_cpld_group); ++ ++} ++ ++/* ---------------------------------------------------------------------------- ++ * Module main functions ++ * ---------------------------------------------------------------------------- ++ */ ++static const struct i2c_device_id wistron_i2c_cpld_id[] = { ++ {"wistron_cpld", 0}, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(i2c, wistron_i2c_cpld_id); ++ ++static struct i2c_driver wistron_i2c_cpld_driver = { ++ .class = I2C_CLASS_HWMON, ++ .driver = { ++ .name = "wistron_cpld", ++ }, ++ .probe = wistron_i2c_cpld_probe, ++ .remove = wistron_i2c_cpld_remove, ++ .id_table = wistron_i2c_cpld_id, ++}; ++ ++static int __init wistron_i2c_cpld_init(void) ++{ ++ mutex_init(&list_lock); ++ ++ return i2c_add_driver(&wistron_i2c_cpld_driver); ++} ++ ++static void __exit wistron_i2c_cpld_exit(void) ++{ ++ i2c_del_driver(&wistron_i2c_cpld_driver); ++} ++ ++ ++MODULE_AUTHOR("Wistron"); ++MODULE_DESCRIPTION("SONiC platform driver for Wistron CPLD"); ++MODULE_LICENSE("GPL"); ++ ++module_init(wistron_i2c_cpld_init); ++module_exit(wistron_i2c_cpld_exit); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.h b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.h +new file mode 100755 +index 000000000..aad74bd48 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_cpld.h +@@ -0,0 +1,299 @@ ++ ++/*************************************************************************** ++ * * ++ * This program is free software; you can redistribute it and/or modify * ++ * it under the terms of the GNU General Public License as published by * ++ * the Free Software Foundation; either version 2 of the License, or * ++ * (at your option) any later version. * ++ * * ++ ***************************************************************************/ ++ ++ ++#ifndef _WISTRON_SWITCH_CPLD_H ++#define _WISTRON_SWITCH_CPLD_H ++ ++//#define CPLD_REVISION_REG 0x0 ++#define CPLD_HW_REVISION_REG 0x1 ++#define CPLD_REVISION_REG 0x2 ++#define CPLD_BUILD_YEAR_REG 0x3 ++#define CPLD_BUILD_DATE_REG 0x4 ++#define CPLD_RW_TEST_REG 0x5 ++#define CPLD_PSU_CHECK_REG 0x6 ++ ++#define CPLD_POWER_CTL1_REG 0x7 ++#define CPLD_POWER_CTL2_REG 0x8 ++ ++#define CPLD_POWER_GOOD_REG 0x9 ++#define CPLD_POWER_GOOD2_REG 0xA ++ ++#define CPLD_FAN_CTL1_REG 0xB ++#define CPLD_FAN_CTL2_REG 0xC ++ ++ ++#define CPLD_1G_LED_CTL1_REG 0xD ++#define CPLD_1G_LED_CTL2_REG 0xE ++#define CPLD_1G_LED_CTL3_REG 0xF ++#define CPLD_1G_LED_CTL4_REG 0x10 ++#define CPLD_1G_LED_CTL5_REG 0x11 ++#define CPLD_1G_LED_CTL6_REG 0x12 ++#define CPLD_1G_LED_CTL7_REG 0x13 ++#define CPLD_1G_LED_CTL8_REG 0x14 ++#define CPLD_1G_LED_CTL9_REG 0x15 ++#define CPLD_1G_LED_CTL10_REG 0x16 ++#define CPLD_1G_LED_CTL11_REG 0x17 ++#define CPLD_1G_LED_CTL12_REG 0x18 ++#define CPLD_1G_LED_CTL13_REG 0x19 ++#define CPLD_1G_LED_CTL14_REG 0x1A ++#define CPLD_1G_LED_CTL15_REG 0x1B ++#define CPLD_1G_LED_CTL16_REG 0x1C ++ ++#define CPLD_2_5G_LED_CTL1_REG 0x1D ++#define CPLD_2_5G_LED_CTL2_REG 0x1E ++#define CPLD_2_5G_LED_CTL3_REG 0x1F ++#define CPLD_2_5G_LED_CTL4_REG 0x20 ++#define CPLD_2_5G_LED_CTL5_REG 0x21 ++#define CPLD_2_5G_LED_CTL6_REG 0x22 ++#define CPLD_2_5G_LED_CTL7_REG 0x23 ++#define CPLD_2_5G_LED_CTL8_REG 0x24 ++ ++#define CPLD_POE_PRT_LED_CTL1_REG 0x25 ++#define CPLD_POE_PRT_LED_CTL2_REG 0x26 ++#define CPLD_POE_PRT_LED_CTL3_REG 0x27 ++#define CPLD_POE_PRT_LED_CTL4_REG 0x28 ++#define CPLD_POE_PRT_LED_CTL5_REG 0x29 ++#define CPLD_POE_PRT_LED_CTL6_REG 0x2A ++#define CPLD_POE_PRT_LED_CTL7_REG 0x2B ++#define CPLD_POE_PRT_LED_CTL8_REG 0x2C ++#define CPLD_POE_PRT_LED_CTL9_REG 0x2D ++#define CPLD_POE_PRT_LED_CTL10_REG 0x2E ++#define CPLD_POE_PRT_LED_CTL11_REG 0x2F ++#define CPLD_POE_PRT_LED_CTL12_REG 0x30 ++ ++#define CPLD_SFP_LED_CTL1_REG 0x31 ++#define CPLD_SFP_LED_CTL2_REG 0x32 ++#define CPLD_SFP_LED_CTL3_REG 0x33 ++ ++ ++#define CPLD_FAN_LED_CTL_REG 0x34 ++#define CPLD_SYS_LED_CTL_REG 0x35 ++ ++#define CPLD_RESET_CTL1_REG 0x36 ++#define CPLD_RESET_CTL2_REG 0x37 ++ ++#define CPLD_INT_CTL1_REG 0x38 ++#define CPLD_INT_CTL2_REG 0x39 ++#define CPLD_INT_CTL3_REG 0x3A ++#define CPLD_INT_CTL4_REG 0x3B ++#define CPLD_MSCI_CTL_REG 0x3C ++#define CPLD_PORT_LED_MANUAL_REG 0x3D ++#define CPLD_RESET_CTL3_REG 0x3E ++#define CPLD_MSCI_CTL2_REG 0x3F ++#define CPLD_WATCHDOG_REG 0x40 ++#define CPLD_SYS_POWER_DOWN_REG 0x41 ++ ++static char* power_ctrl_str1[] = { ++ "P1V2_OOB_EN", // 0 ++ "P1V5_EN", ++ "P1V8_CPU_EN", ++ "P1V8", ++ "P2V5_CPU_DDR4_EN", ++ "P2V5_EN", ++ "P3V3_EN", ++ "P5V0_EN", // 7 ++}; ++ ++static char* power_ctrl_str2[] = { ++ "PHY_P0V8_EN", // 0 ++ "P0V8_MAC_EN", ++ "P0V85_CPU_AP_VDD_EN", ++ "P1V15_EN", ++ "P0V6_CPU_DDR4_VTT_EN", ++ "P0V6_EN", ++ "P1V2_CPU_DDR4_EN", ++ "P1V2_EN", // 7 ++}; ++ ++static char* power_good_str1[] = { ++ "PWRGD_VR_P1V2_OOB", // 0 ++ "PWRGD_P1V5", ++ "PWRGD_P1V8_CPU", ++ "PWRGD_P1V8", ++ "PWRGD_P2V5_CPU_DDR4", ++ "PWRGD_P2V5", ++ "PWRGD_P3V3", ++ "PWRGD_P5V0", // 7 ++}; ++ ++static char* power_good_str2[] = { ++ "PWRGD_PHY_P0V8", // 0 ++ "PWRGD_VR_MAC_P0V8", ++ "PWRGD_P0V85_CPU_AP_VDD", ++ "PWRGD_P1V15", ++ "PWRGD_VR_P0V6_CPU_DDR4_VTT", ++ "PWRGD_VR_P0V6", ++ "PWRGD_P1V2_CPU_DDR4", ++ "PWRGD_P1V2", ++}; ++ ++enum psu_status_bit { ++ PSU2_ON = 0, ++ PSU1_ON, ++ PSU2_AC_OK, ++ PSU1_AC_OK, ++ PSU2_PRESENT, ++ PSU1_PRESENT, ++ PSU2_PWRGD, ++ PSU1_PWRGD, ++}; ++ ++enum fan_control_bit { ++ FAN_FULL_SPEED = 0, ++ FM_FAN3_EN = 1, ++ FM_FAN2_EN = 2, ++ FM_FAN1_EN = 3, ++ FM_FAN3_TYPE = 4, ++ FM_FAN2_TYPE = 5, ++ FM_FAN1_TYPE = 6, ++ PWRGD_VR_P12V_FAN3 = 7, ++ PWRGD_VR_P12V_FAN2 = 8, ++ PWRGD_VR_P12V_FAN1 = 9, ++ CNFAN3_PRESENT = 10, ++ CNFAN2_PRESENT = 11, ++ CNFAN1_PRESENT = 12, ++}; ++ ++enum fan_id { ++ FAN3 = 0, ++ FAN2, ++ FAN1, ++}; ++ ++enum port_id { ++ PORT1 = 0, ++ PORT2, ++ PORT3, ++ PORT4, ++ PORT5, ++ PORT6, ++ PORT7, ++ PORT8, ++ PORT9, ++ PORT10, ++ PORT11, ++ PORT12, ++ PORT13, ++ PORT14, ++ PORT15, ++ PORT16, ++ PORT17, ++ PORT18, ++ PORT19, ++ PORT20, ++ PORT21, ++ PORT22, ++ PORT23, ++ PORT24, ++ PORT25, ++ PORT26, ++ PORT27, ++ PORT28, ++ PORT29, ++ PORT30, ++ PORT31, ++ PORT32, ++ PORT33, ++ PORT34, ++ PORT35, ++ PORT36, ++ PORT37, ++ PORT38, ++ PORT39, ++ PORT40, ++ PORT41, ++ PORT42, ++ PORT43, ++ PORT44, ++ PORT45, ++ PORT46, ++ PORT47, ++ PORT48, ++ PORT49, ++ PORT50, ++ PORT51, ++ PORT52, ++ PORT53, ++ PORT54, ++}; ++ ++enum led_status_shift_bit { ++ LOC_LED = 0, ++ PSU_LED = 2, ++ SYS_LED = 4, ++ FAN_LED = 6, ++}; ++ ++enum rst_shift_bit { ++ RST_MB_IOIEXP = 0, ++ RST_PHY0_5 = 1, ++ RST_POE_CTR = 2, ++ CPLD_SYSRST_MAC_RST = 3, ++ RST_CPU_SYSRST_OUT = 4, ++ RST_GPHY_RST = 5, ++ RST_I2C_MUX = 6, ++ RST_MAC_JTAG = 7, ++ RST_BUTTON_CPLD_CPU = 8, ++ RST_BUTTON = 9, ++ RST_CPLD_I2C_MUX = 10, ++ RST_BUTTON_10S = 1, ++}; ++ ++enum int_shift_bit { ++ INT_PHY0 = 0, ++ INT_PHY1 = 1, ++ INT_PHY2 = 2, ++ INT_PHY3 = 3, ++ INT_PHY4_0 = 4, ++ INT_PHY4_1 = 5, ++ INT_PHY5_0 = 6, ++ INT_PHY5_1 = 7, ++ ++ INT_OOB_IOIEXP = 8, ++ INT_MB_IOIEXP = 9, ++ USB_OCP_ALERT = 10, ++ TEMP_ALERT = 11, ++ RTC_IRQ = 12, ++ PSU2_INT_ALERT = 13, ++ PSU1_INT_ALERT = 14, ++ INT_PD69210 = 15, ++ ++ DEV_INIT_DONE = 16, ++ FAN_CTL_FAIL = 17, ++ MEMHOT = 18, ++ ++ MB_SYSTEM_INT = 19, ++ MB_MOD_PRE_INT = 20, ++}; ++ ++enum msci_ctl2_shift_bit { ++ PSU_VSENSE = 0, ++ PSU_PWRGD = 1, ++ PSU_BUDGET_MODE = 2, ++}; ++ ++enum sysled_en_shift_bit { ++ FRONT_PORT_LED_EN = 0, ++ FRONT_SYS_LED_EN = 1, ++ FRONT_PSU_LED_EN = 2, ++ FRONT_FAN_LED_EN = 3, ++ FRONT_LOC_LED_EN = 4, ++}; ++ ++enum watchdog_timer_def { ++ WATCHDOG_180S = 0, ++ WATCHDOG_210S = 1, ++ WATCHDOG_240S = 2, ++ WATCHDOG_270S = 3, ++ WATCHDOG_300S = 4, ++}; ++ ++#endif /* _WISTRON_SWITCH_CPLD_H */ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_eeprom.c b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_eeprom.c +new file mode 100755 +index 000000000..4d20c3c53 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_eeprom.c +@@ -0,0 +1,281 @@ ++/* ++ * Copyright (C) 1998, 1999 Frodo Looijaard and ++ * Philip Edelbrock ++ * Copyright (C) 2003 Greg Kroah-Hartman ++ * Copyright (C) 2003 IBM Corp. ++ * Copyright (C) 2004 Jean Delvare ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Size of EEPROM in bytes */ ++#define EEPROM_SIZE 256 ++ ++#define VENDOR_NAME_LEN 8 ++#define VENDOR_NAME_START_BYTE 0xC ++ ++#define FSP_PRODUCT_NAME_LEN 8 ++#define FSP_PRODUCT_OPTION_NAME_LEN 11 ++#define FSP_SERIAL_NUMBER_LEN 19 ++#define FSP_HW_REVISION_LEN 3 ++ ++#define FSP_PRODUCT_NAME_START_BYTE 0x20 ++#define FSP_PRODUCT_OPTION_NAME_START_BYTE 0x29 ++#define FSP_SERIAL_NUMBER_START_BYTE 0x35 ++#define FSP_HW_REVISION_START_BYTE 0x57 ++ ++ ++#define GOS_PRODUCT_NAME_LEN 13 ++#define GOS_SERIAL_NUMBER_LEN 19 ++#define GOS_HW_REVISION_LEN 3 ++ ++#define GOS_PRODUCT_NAME_START_BYTE 0x15 ++#define GOS_SERIAL_NUMBER_START_BYTE 0x3d ++#define GOS_HW_REVISION_START_BYTE 0x39 ++ ++#define GOS_STRING "GOSPOWER" ++ ++enum psu_vendor { ++ PSU_FSP = 0, ++ PSU_GOS, ++}; ++ ++/* Each client has this additional data */ ++struct eeprom_data { ++ struct mutex update_lock; ++ u8 valid; /* bitfield, bit!=0 if slice is valid */ ++ unsigned long last_updated[8]; /* In jiffies, 8 slices */ ++ u8 data[EEPROM_SIZE]; /* Register values */ ++ u8 vendor_code; ++}; ++ ++static ssize_t get_vendor_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct eeprom_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ for (i = VENDOR_NAME_START_BYTE ; i < (VENDOR_NAME_START_BYTE + VENDOR_NAME_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ sprintf(buf + strlen(buf), "\n"); ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t get_product_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct eeprom_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ if (data->vendor_code == PSU_FSP) { ++ for (i = FSP_PRODUCT_NAME_START_BYTE ; i < (FSP_PRODUCT_NAME_START_BYTE + FSP_PRODUCT_NAME_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ for (i = FSP_PRODUCT_OPTION_NAME_START_BYTE ; i < (FSP_PRODUCT_OPTION_NAME_START_BYTE + FSP_PRODUCT_OPTION_NAME_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ } else { ++ for (i = GOS_PRODUCT_NAME_START_BYTE ; i < (GOS_PRODUCT_NAME_START_BYTE + GOS_PRODUCT_NAME_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ } ++ sprintf(buf + strlen(buf), "\n"); ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t get_serial_number(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct eeprom_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ if (data->vendor_code == PSU_FSP) { ++ for (i = FSP_SERIAL_NUMBER_START_BYTE ; i < (FSP_SERIAL_NUMBER_START_BYTE + FSP_SERIAL_NUMBER_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ } else { ++ for (i = GOS_SERIAL_NUMBER_START_BYTE ; i < (GOS_SERIAL_NUMBER_START_BYTE + GOS_SERIAL_NUMBER_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ } ++ ++ sprintf(buf + strlen(buf), "\n"); ++ return (ssize_t)strlen(buf);; ++} ++ ++static ssize_t get_hw_revision(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct eeprom_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ if (data->vendor_code == PSU_FSP) { ++ for (i = FSP_HW_REVISION_START_BYTE ; i < (FSP_HW_REVISION_START_BYTE + FSP_HW_REVISION_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ } else { ++ for (i = GOS_HW_REVISION_START_BYTE ; i < (GOS_HW_REVISION_START_BYTE + GOS_HW_REVISION_LEN) ; i++) ++ sprintf(buf + strlen(buf), "%c", data->data[i]); ++ } ++ ++ sprintf(buf + strlen(buf), "\n"); ++ return (ssize_t)strlen(buf);; ++} ++ ++static DEVICE_ATTR(vendor_name, S_IRUGO, get_vendor_name, NULL); ++static DEVICE_ATTR(product_name, S_IRUGO, get_product_name, NULL); ++static DEVICE_ATTR(serial_number, S_IRUGO, get_serial_number, NULL); ++static DEVICE_ATTR(hw_revision, S_IRUGO, get_hw_revision, NULL); ++ ++static struct attribute *_i2c_eeprom_attr[] = { ++ &dev_attr_vendor_name.attr, ++ &dev_attr_product_name.attr, ++ &dev_attr_serial_number.attr, ++ &dev_attr_hw_revision.attr, ++ NULL ++}; ++ ++static const struct attribute_group _i2c_eeprom_attr_grp = { ++ .attrs = _i2c_eeprom_attr, ++}; ++ ++static void eeprom_update_client(struct i2c_client *client, u8 slice) ++{ ++ struct eeprom_data *data = i2c_get_clientdata(client); ++ int i; ++ ++ mutex_lock(&data->update_lock); ++ ++ if (!(data->valid & (1 << slice)) || ++ time_after(jiffies, data->last_updated[slice] + 300 * HZ)) { ++ dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice); ++ ++ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ for (i = slice << 5; i < (slice + 1) << 5; i += 24) ++ if (i2c_smbus_read_i2c_block_data(client, i, ++ 24, data->data + i) ++ != 24) ++ goto exit; ++ } else { ++ for (i = slice << 5; i < (slice + 1) << 5; i += 2) { ++ int word = i2c_smbus_read_word_data(client, i); ++ if (word < 0) ++ goto exit; ++ data->data[i] = word & 0xff; ++ data->data[i + 1] = word >> 8; ++ } ++ } ++ data->last_updated[slice] = jiffies; ++ data->valid |= (1 << slice); ++ } ++exit: ++ mutex_unlock(&data->update_lock); ++} ++ ++static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *bin_attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(kobj_to_dev(kobj)); ++ struct eeprom_data *data = i2c_get_clientdata(client); ++ u8 slice; ++ ++ /* Only refresh slices which contain requested bytes */ ++ for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++) ++ eeprom_update_client(client, slice); ++ ++ memcpy(buf, &data->data[off], count); ++ ++ return count; ++} ++ ++ ++static struct bin_attribute eeprom_attr = { ++ .attr = { ++ .name = "eeprom", ++ .mode = S_IRUGO, ++ }, ++ .size = EEPROM_SIZE, ++ .read = eeprom_read, ++}; ++ ++static int eeprom_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct eeprom_data *data; ++ int err; ++ u8 slice; ++ ++ if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { ++ err = -ENOMEM; ++ goto exit; ++ } ++ ++ memset(data->data, 0xff, EEPROM_SIZE); ++ i2c_set_clientdata(client, data); ++ mutex_init(&data->update_lock); ++ ++ /* create the sysfs eeprom file */ ++ err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); ++ if (err) { ++ goto exit_kfree; ++ } ++ ++ /* perform dummy read eeprom*/ ++ for (slice = 0 >> 5; slice <= (EEPROM_SIZE - 1) >> 5; slice++) ++ eeprom_update_client(client, slice); ++ ++ data->vendor_code = PSU_FSP; ++ ++ if (data->data[VENDOR_NAME_START_BYTE] == 0x47) ++ data->vendor_code = PSU_GOS; ++ ++ err = sysfs_create_group(&client->dev.kobj, &_i2c_eeprom_attr_grp); ++ if (err) { ++ dev_dbg(&client->dev, "Exit, failed to create sysfs, rc = 0x%x", err); ++ goto exit_kfree; ++ } ++ return 0; ++ ++exit_kfree: ++ kfree(data); ++exit: ++ return err; ++} ++ ++static void eeprom_remove(struct i2c_client *client) ++{ ++ sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr); ++ kfree(i2c_get_clientdata(client)); ++ ++} ++ ++static const struct i2c_device_id eeprom_id[] = { ++ { "wistron_eeprom", 0 }, ++ { } ++}; ++ ++static struct i2c_driver eeprom_driver = { ++ .driver = { ++ .name = "wistron_eeprom", ++ }, ++ .probe = eeprom_probe, ++ .remove = eeprom_remove, ++ .id_table = eeprom_id, ++}; ++ ++module_i2c_driver(eeprom_driver); ++ ++MODULE_AUTHOR("switchsupport@wistron.com"); ++MODULE_DESCRIPTION ("SONiC platform driver for PSU EEPROM"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_max31790.c b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_max31790.c +new file mode 100755 +index 000000000..abf9c0a63 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/modules/wistron_max31790.c +@@ -0,0 +1,604 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * max31790.c - Part of lm_sensors, Linux kernel modules for hardware ++ * monitoring. ++ * ++ * (C) 2015 by Il Han ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MAX31790 registers */ ++#define MAX31790_REG_GLOBAL_CONFIG 0x00 ++#define MAX31790_REG_FAN_CONFIG(ch) (0x02 + (ch)) ++#define MAX31790_REG_FAN_DYNAMICS(ch) (0x08 + (ch)) ++#define MAX31790_REG_FAN_FAULT_STATUS2 0x10 ++#define MAX31790_REG_FAN_FAULT_STATUS1 0x11 ++#define MAX31790_REG_TACH_COUNT(ch) (0x18 + (ch) * 2) ++#define MAX31790_REG_PWM_DUTY_CYCLE(ch) (0x30 + (ch) * 2) ++#define MAX31790_REG_PWMOUT(ch) (0x40 + (ch) * 2) ++#define MAX31790_REG_TARGET_COUNT(ch) (0x50 + (ch) * 2) ++ ++/* Fan Config register bits */ ++#define MAX31790_FAN_CFG_RPM_MODE 0x80 ++#define MAX31790_FAN_CFG_CTRL_MON 0x10 ++#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08 ++#define MAX31790_FAN_CFG_TACH_INPUT 0x01 ++ ++/* Fan Dynamics register bits */ ++#define MAX31790_FAN_DYN_SR_SHIFT 5 ++#define MAX31790_FAN_DYN_SR_MASK 0xE0 ++#define SR_FROM_REG(reg) (((reg) & MAX31790_FAN_DYN_SR_MASK) \ ++ >> MAX31790_FAN_DYN_SR_SHIFT) ++ ++#define FAN_RPM_MIN 120 ++#define FAN_RPM_MAX 7864320 ++ ++#define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \ ++ ((60 * (sr) * 8192) / ((reg) >> 4)) : \ ++ FAN_RPM_MAX) ++#define RPM_TO_REG(rpm, sr) ((60 * (sr) * 8192) / ((rpm) * 2)) ++ ++#define NR_CHANNEL 6 ++ ++#define MAX31790_REG_FREQ_CONFIG 0x01 ++#define MAX31790_REG_FAIL_MASK2 0x12 ++#define MAX31790_REG_FAIL_MASK1 0x13 ++#define MAX31790_REG_FAIL_CTRL 0x14 ++static char *platform; ++module_param(platform, charp, 0000); ++MODULE_PARM_DESC(platform, "platform name (support ES-2227)."); ++ ++enum { ++ PLATFORM_ES2227 = 1, ++ PLATFORM_LAST, ++}; ++ ++struct max31790_init_data { ++ u8 freq; ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++#if 0 ++ u8 fail_mask[2]; ++ u8 fail_ctrl; ++#endif ++}; ++ ++struct max31790_init_data platform_init_data[PLATFORM_LAST - 1] = ++{ ++ { ++ .freq = 0xbb, ++ .fan_config = {0x68, 0x79, 0x68, 0x68, 0x79, 0x79}, ++ .fan_dynamics = {0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c}, ++#if 0 ++ .fail_mask = {0x3d, 0x20}, ++ .fail_ctrl = 0x45, ++#endif ++ }, ++}; ++/* ++ * Client data (each client gets its own) ++ */ ++struct max31790_data { ++ struct i2c_client *client; ++ struct mutex update_lock; ++ bool valid; /* zero until following fields are valid */ ++ unsigned long last_updated; /* in jiffies */ ++ ++ /* register values */ ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++ u16 fault_status; ++ u16 tach[NR_CHANNEL * 2]; ++ u16 pwm[NR_CHANNEL]; ++ u16 target_count[NR_CHANNEL]; ++}; ++ ++static struct max31790_data *max31790_update_device(struct device *dev) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ struct max31790_data *ret = data; ++ int i; ++ int rv; ++ ++ mutex_lock(&data->update_lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS1); ++ if (rv < 0) ++ goto abort; ++ data->fault_status = rv & 0x3F; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS2); ++ if (rv < 0) ++ goto abort; ++ data->fault_status |= (rv & 0x3F) << 6; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(NR_CHANNEL ++ + i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[NR_CHANNEL + i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_PWMOUT(i)); ++ if (rv < 0) ++ goto abort; ++ data->pwm[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->target_count[i] = rv; ++ } ++ ++ data->last_updated = jiffies; ++ data->valid = true; ++ } ++ goto done; ++ ++abort: ++ data->valid = false; ++ ret = ERR_PTR(rv); ++ ++done: ++ mutex_unlock(&data->update_lock); ++ ++ return ret; ++} ++ ++static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; ++ ++static u8 get_tach_period(u8 fan_dynamics) ++{ ++ return tach_period[SR_FROM_REG(fan_dynamics)]; ++} ++ ++static u8 bits_for_tach_period(int rpm) ++{ ++ u8 bits; ++ ++ if (rpm < 500) ++ bits = 0x0; ++ else if (rpm < 1000) ++ bits = 0x1; ++ else if (rpm < 2000) ++ bits = 0x2; ++ else if (rpm < 4000) ++ bits = 0x3; ++ else if (rpm < 8000) ++ bits = 0x4; ++ else ++ bits = 0x5; ++ ++ return bits; ++} ++ ++static int max31790_read_fan(struct device *dev, u32 attr, int channel, ++ long *val) ++{ ++ struct max31790_data *data = max31790_update_device(dev); ++ int sr, rpm; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]); ++ rpm = RPM_FROM_REG(data->tach[channel], sr); ++ *val = rpm; ++ return 0; ++ case hwmon_fan_target: ++ sr = get_tach_period(data->fan_dynamics[channel]); ++ rpm = RPM_FROM_REG(data->target_count[channel], sr); ++ *val = rpm; ++ return 0; ++ case hwmon_fan_fault: ++ *val = !!(data->fault_status & (1 << channel)); ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write_fan(struct device *dev, u32 attr, int channel, ++ long val) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ int target_count; ++ int err = 0; ++ u8 bits; ++ int sr; ++ ++ mutex_lock(&data->update_lock); ++ ++ switch (attr) { ++ case hwmon_fan_target: ++ val = clamp_val(val, FAN_RPM_MIN, FAN_RPM_MAX); ++ bits = bits_for_tach_period(val); ++ data->fan_dynamics[channel] = ++ ((data->fan_dynamics[channel] & ++ ~MAX31790_FAN_DYN_SR_MASK) | ++ (bits << MAX31790_FAN_DYN_SR_SHIFT)); ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(channel), ++ data->fan_dynamics[channel]); ++ if (err < 0) ++ break; ++ ++ sr = get_tach_period(data->fan_dynamics[channel]); ++ target_count = RPM_TO_REG(val, sr); ++ target_count = clamp_val(target_count, 0x1, 0x7FF); ++ ++ data->target_count[channel] = target_count << 5; ++ ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(channel), ++ data->target_count[channel]); ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return err; ++} ++ ++static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel) ++{ ++ const struct max31790_data *data = _data; ++ u8 fan_config = data->fan_config[channel % NR_CHANNEL]; ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ case hwmon_fan_fault: ++ if (channel < NR_CHANNEL || ++ (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0444; ++ return 0; ++ case hwmon_fan_target: ++ if (channel < NR_CHANNEL && ++ !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0644; ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int max31790_read_pwm(struct device *dev, u32 attr, int channel, ++ long *val) ++{ ++ struct max31790_data *data = max31790_update_device(dev); ++ u8 fan_config; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ fan_config = data->fan_config[channel]; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ *val = data->pwm[channel] >> 8; ++ return 0; ++ case hwmon_pwm_enable: ++ if (fan_config & MAX31790_FAN_CFG_CTRL_MON) ++ *val = 0; ++ else if (fan_config & MAX31790_FAN_CFG_RPM_MODE) ++ *val = 2; ++ else ++ *val = 1; ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write_pwm(struct device *dev, u32 attr, int channel, ++ long val) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ u8 fan_config; ++ int err = 0; ++ int i = 0; ++ ++ mutex_lock(&data->update_lock); ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ if (val < 0 || val > 255) { ++ err = -EINVAL; ++ break; ++ } ++ data->pwm[channel] = val << 8; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_PWMOUT(i), ++ data->pwm[channel]); ++ } ++ break; ++ case hwmon_pwm_enable: ++ fan_config = data->fan_config[channel]; ++ if (val == 0) { ++ fan_config |= MAX31790_FAN_CFG_CTRL_MON; ++ /* ++ * Disable RPM mode; otherwise disabling fan speed ++ * monitoring is not possible. ++ */ ++ fan_config &= ~MAX31790_FAN_CFG_RPM_MODE; ++ } else if (val == 1) { ++ fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON | MAX31790_FAN_CFG_RPM_MODE); ++ } else if (val == 2) { ++ fan_config &= ~MAX31790_FAN_CFG_CTRL_MON; ++ /* ++ * The chip sets MAX31790_FAN_CFG_TACH_INPUT_EN on its ++ * own if MAX31790_FAN_CFG_RPM_MODE is set. ++ * Do it here as well to reflect the actual register ++ * value in the cache. ++ */ ++ fan_config |= (MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_TACH_INPUT_EN); ++ } else { ++ err = -EINVAL; ++ break; ++ } ++ if (fan_config != data->fan_config[channel]) { ++ err = i2c_smbus_write_byte_data(client, MAX31790_REG_FAN_CONFIG(channel), ++ fan_config); ++ if (!err) ++ data->fan_config[channel] = fan_config; ++ } ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return err; ++} ++ ++static umode_t max31790_pwm_is_visible(const void *_data, u32 attr, int channel) ++{ ++ const struct max31790_data *data = _data; ++ u8 fan_config = data->fan_config[channel]; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ case hwmon_pwm_enable: ++ if (!(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0644; ++ return 0; ++ default: ++ return 0; ++ } ++} ++ ++static int max31790_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_read_fan(dev, attr, channel, val); ++ case hwmon_pwm: ++ return max31790_read_pwm(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int max31790_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_write_fan(dev, attr, channel, val); ++ case hwmon_pwm: ++ return max31790_write_pwm(dev, attr, channel, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static umode_t max31790_is_visible(const void *data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ switch (type) { ++ case hwmon_fan: ++ return max31790_fan_is_visible(data, attr, channel); ++ case hwmon_pwm: ++ return max31790_pwm_is_visible(data, attr, channel); ++ default: ++ return 0; ++ } ++} ++ ++static const struct hwmon_channel_info *max31790_info[] = { ++ HWMON_CHANNEL_INFO(fan, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT), ++ HWMON_CHANNEL_INFO(pwm, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE, ++ HWMON_PWM_INPUT | HWMON_PWM_ENABLE), ++ NULL ++}; ++ ++static const struct hwmon_ops max31790_hwmon_ops = { ++ .is_visible = max31790_is_visible, ++ .read = max31790_read, ++ .write = max31790_write, ++}; ++ ++static const struct hwmon_chip_info max31790_chip_info = { ++ .ops = &max31790_hwmon_ops, ++ .info = max31790_info, ++}; ++ ++static int max31790_init_setup(struct i2c_client *client, ++ int platform_id) ++{ ++ int i, rv; ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FREQ_CONFIG, ++ platform_init_data[platform_id - 1].freq); ++ if (rv < 0) ++ return rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i), ++ platform_init_data[platform_id - 1].fan_config[i]); ++ if (rv < 0) ++ return rv; ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i), ++ platform_init_data[platform_id - 1].fan_dynamics[i]); ++ if (rv < 0) ++ return rv; ++ } ++ ++#if 0 ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_MASK2, ++ platform_init_data[platform_id - 1].fail_mask[0]); ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_MASK1, ++ platform_init_data[platform_id - 1].fail_mask[1]); ++ ++ rv = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAIL_CTRL, ++ platform_init_data[platform_id - 1].fail_ctrl); ++#endif ++ return 0; ++} ++ ++static int max31790_init_client(struct i2c_client *client, ++ struct max31790_data *data) ++{ ++ int i, rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_config[i] = rv; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_dynamics[i] = rv; ++ } ++ ++ return 0; ++} ++ ++static int max31790_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct device *dev = &client->dev; ++ struct max31790_data *data; ++ struct device *hwmon_dev; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) ++ return -ENODEV; ++ ++ data = devm_kzalloc(dev, sizeof(struct max31790_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ mutex_init(&data->update_lock); ++ ++ /* ++ * Initialize the max31790 chip ++ */ ++ if (id->driver_data != 0) { ++ err = max31790_init_setup(client, id->driver_data); ++ } else { ++ if (!strcmp(platform, "2227")) ++ err = max31790_init_setup(client, PLATFORM_ES2227); ++ } ++ ++ if (err) ++ return err; ++ ++ err = max31790_init_client(client, data); ++ if (err) ++ return err; ++ ++ hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, ++ data, ++ &max31790_chip_info, ++ NULL); ++ ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static const struct i2c_device_id max31790_id[] = { ++ { "max31790", 0 }, ++ { "2227_max31790", PLATFORM_ES2227}, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max31790_id); ++ ++static struct i2c_driver max31790_driver = { ++ .class = I2C_CLASS_HWMON, ++ .probe = max31790_probe, ++ .driver = { ++ .name = "wistron_max31790", ++ }, ++ .id_table = max31790_id, ++}; ++ ++module_i2c_driver(max31790_driver); ++ ++MODULE_AUTHOR("Il Han "); ++MODULE_DESCRIPTION("MAX31790 sensor driver"); ++MODULE_LICENSE("GPL"); +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/entropy.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/entropy.py +new file mode 100644 +index 000000000..338e2ad9b +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/entropy.py +@@ -0,0 +1,19 @@ ++#!/usr/bin/python ++import fcntl, struct ++import time ++from os import path ++ ++RNDADDENTROPY=0x40085203 ++ ++def avail(): ++ with open("/proc/sys/kernel/random/entropy_avail", mode='r') as avail: ++ return int(avail.read()) ++ ++if path.exists("/proc/sys/kernel/random/entropy_avail"): ++ while 1: ++ while avail() < 2048: ++ with open('/dev/urandom', 'rb') as urnd, open("/dev/random", mode='wb') as rnd: ++ d = urnd.read(512) ++ t = struct.pack('ii', 4 * len(d), len(d)) + d ++ fcntl.ioctl(rnd, RNDADDENTROPY, t) ++ time.sleep(30) +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p-init.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p-init.sh +new file mode 100755 +index 000000000..5742307e5 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p-init.sh +@@ -0,0 +1,76 @@ ++#!/bin/bash ++ ++# Platform init script ++ ++# Load required kernel-mode drivers ++load_kernel_drivers() { ++ # Remove modules loaded during Linux init ++ # FIX-ME: This will be removed in the future when Linux init no longer loads these ++ rmmod i2c_dev ++ rmmod i2c_mv64xxx ++ ++ # Carefully control the load order here to ensure consistent i2c bus numbering ++ modprobe i2c_mv64xxx ++ modprobe i2c_dev ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_cpld.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_max31790.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/wistron_eeprom.ko ++ insmod /usr/lib/modules/$(uname -r)/kernel/extra/mvcpss.ko ++ modprobe optoe ++ modprobe jc42 ++} ++ ++# - Main entry ++ ++# Install kernel drivers required for i2c bus access ++load_kernel_drivers ++#entropy setting ++#python /etc/entropy.py ++ echo wistron_cpld 0x33 > /sys/bus/i2c/devices/i2c-0/new_device ++ echo 2227_max31790 0x2f > /sys/bus/i2c/devices/i2c-2/new_device ++ echo wistron_eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device ++ echo wistron_eeprom 0x51 > /sys/bus/i2c/devices/i2c-3/new_device ++ ++ echo jc42 0x1b > /sys/bus/i2c/devices/i2c-0/new_device ++ echo pmbus 0x58 > /sys/bus/i2c/devices/i2c-3/new_device ++ echo pmbus 0x59 > /sys/bus/i2c/devices/i2c-3/new_device ++ ++ tca_detect=$(i2cget -f -y 5 0x22 0x40 1>/dev/null 2>/dev/null; echo $?) ++ if [ $tca_detect -eq 0 ]; then ++ i2cset -y 5 0x22 0x54 0x22 ++ i2cset -y 5 0x22 0x55 0x22 ++ i2cset -y 5 0x22 0x56 0x22 ++ echo pcal6524 0x22 > /sys/bus/i2c/devices/i2c-5/new_device ++ else ++ echo tca6424 0x22 > /sys/bus/i2c/devices/i2c-5/new_device ++ fi ++ ++ local i ++ for i in {4..9}; ++ do ++ echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device ++ done ++ local j ++ for j in {472..495}; ++ do ++ echo $j > /sys/class/gpio/export ++ done ++ local k ++ for k in $(seq 473 4 493); do ++ echo out > /sys/class/gpio/gpio$k/direction ++ done ++ ++ for i in {0..2}; ++ do ++ echo 85000 > /sys/class/hwmon/hwmon$i/temp1_max ++ echo 80000 > /sys/class/hwmon/hwmon$i/temp1_max_hyst ++ done ++ ++ echo 80000 > /sys/class/hwmon/hwmon4/temp1_max ++ echo 85000 > /sys/class/hwmon/hwmon4/temp1_crit ++ ++ echo 1 > /sys/bus/i2c/devices/0-0033/port_led_auto ++ ++ sh /usr/local/bin/poe_init.sh ++ ++exit 0 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p_plt_setup.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p_plt_setup.sh +new file mode 100755 +index 000000000..e4f019f5a +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/es2227_54ts_p_plt_setup.sh +@@ -0,0 +1,33 @@ ++#!/bin/bash ++ ++fw_uboot_env_cfg() ++{ ++ echo "Setting up U-Boot environment..." ++ MACH_FILE="/host/machine.conf" ++ PLATFORM=`sed -n 's/onie_platform=\(.*\)/\1/p' $MACH_FILE` ++} ++ ++es2227_54ts_profile() ++{ ++ MAC_ADDR=$(fw_printenv -n ethaddr) ++ find /usr/share/sonic/device/*es2227_54ts* -name profile.ini | xargs sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" ++ echo "es2227_54ts: Updating switch mac address ${MAC_ADDR}" ++} ++ ++update_modulelist() ++{ ++ MODULE_FILE="/etc/modules-load.d/marvell.conf" ++ ++ echo "# Module list to load during the boot" > $MODULE_FILE ++ echo "mvcpss" >> $MODULE_FILE ++ echo "psample" >> $MODULE_FILE ++} ++ ++main() ++{ ++ fw_uboot_env_cfg ++ es2227_54ts_profile ++ update_modulelist ++} ++ ++main $@ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/fw_env.config b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/fw_env.config +new file mode 100644 +index 000000000..ea22bf4a3 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/scripts/fw_env.config +@@ -0,0 +1 @@ ++/dev/mtd1 0x0 0x10000 0x10000 +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-init.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-init.service +new file mode 100644 +index 000000000..b1669d1df +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-init.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts_p Service ++Before=pmon.service ++After=sysinit.target ++DefaultDependencies=no ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/local/bin/es2227_54ts_p-init.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-led-monitor.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-led-monitor.service +new file mode 100644 +index 000000000..9ebebd48f +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-led-monitor.service +@@ -0,0 +1,14 @@ ++[Unit] ++Description=Platform es2227_54ts_p PoE LED Service ++Before=pmon.service ++After=es2227_54ts_p-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/local/bin/es2227_54ts_p_led.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-oob-led.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-oob-led.service +new file mode 100644 +index 000000000..7808ee7ef +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-oob-led.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es2227_54ts_p OOB LED Service ++After=pmon.service es2227_54ts_p-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/usr/bin/sleep 20 ++ExecStart=/usr/local/bin/es2227_54ts_p-oob-led.sh ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-poe_lldp.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-poe_lldp.service +new file mode 100644 +index 000000000..93db39c42 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-poe_lldp.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts_p system LED Service ++After=pmon.service es2227_54ts_p-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/poe_cfg_lldp.py ++Restart=on-failure ++RestartSec=5 ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-psu-monitor.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-psu-monitor.service +new file mode 100644 +index 000000000..08e17ae27 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-psu-monitor.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts_p psu monitor Service ++After=pmon.service es2227_54ts_p-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/psu_detect.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-rst_button.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-rst_button.service +new file mode 100644 +index 000000000..8845e59c7 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-rst_button.service +@@ -0,0 +1,16 @@ ++[Unit] ++Description=Platform es2227_54ts_p Reset Button Service ++After=pmon.service es2227_54ts_p-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStartPre=/usr/bin/sleep 20 ++ExecStart=/usr/bin/python3 /usr/local/bin/rst_button.py ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++Restart=on-failure ++RestartSec=5s ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-sysled.service b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-sysled.service +new file mode 100644 +index 000000000..a7eceacab +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/service/es2227_54ts_p-sysled.service +@@ -0,0 +1,15 @@ ++[Unit] ++Description=Platform es2227_54ts_p system LED Service ++After=pmon.service es2227_54ts_p-init.service ++DefaultDependencies=no ++ ++[Service] ++ExecStart=/usr/bin/python3 /usr/local/bin/sysled_health.py ++Restart=on-failure ++RestartSec=5 ++KillSignal=SIGKILL ++SuccessExitStatus=SIGKILL ++#StandardOutput=tty ++ ++[Install] ++WantedBy=multi-user.target +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/setup.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/setup.py +new file mode 100644 +index 000000000..7675f61d2 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/setup.py +@@ -0,0 +1,32 @@ ++from setuptools import setup ++ ++ ++setup( ++ name='sonic-platform', ++ version='1.0', ++ description='SONiC platform API implementation on Wistron Platforms', ++ license='Apache 2.0', ++ author='SONiC Team', ++ author_email='linuxnetdev@microsoft.com', ++ url='https://github.com/Azure/sonic-buildimage', ++ maintainer='ChihPei Chang', ++ maintainer_email='ChihPei_Chang@wistron.com', ++ packages=[ ++ 'sonic_platform', ++ ], ++ package_dir={'sonic_platform': 'sonic_platform'}, ++ classifiers=[ ++ 'Development Status :: 3 - Alpha', ++ 'Environment :: Plugins', ++ 'Intended Audience :: Developers', ++ 'Intended Audience :: Information Technology', ++ 'Intended Audience :: System Administrators', ++ 'License :: OSI Approved :: Apache Software License', ++ 'Natural Language :: English', ++ 'Operating System :: POSIX :: Linux', ++ 'Programming Language :: Python :: 2.7', ++ 'Topic :: Utilities', ++ ], ++ keywords='sonic SONiC platform PLATFORM', ++) ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/__init__.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/__init__.py +new file mode 100644 +index 000000000..4bfefa0fb +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/__init__.py +@@ -0,0 +1,3 @@ ++__all__ = ["platform", "chassis"] ++from sonic_platform import * ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/chassis.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/chassis.py +new file mode 100755 +index 000000000..e4c8a6b4a +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/chassis.py +@@ -0,0 +1,463 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Chassis information which are available in the platform ++# ++############################################################################# ++try: ++ import sys ++ import os ++ import time ++ import subprocess ++ from sonic_platform_base.chassis_base import ChassisBase ++ from sonic_platform.fan import Fan ++ from sonic_platform.psu import Psu ++ from sonic_platform.component import Component ++ from sonic_platform.thermal import Thermal ++ from sonic_platform.sfp import Sfp ++ from sonic_platform.eeprom import Tlv ++ from sonic_platform.fan_drawer import FanDrawer ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++NUM_FANTRAY = 2 ++NUM_PSU = 2 ++NUM_THERMAL = 15 ++COPPER_PORT_START = 1 ++COPPER_PORT_END = 48 ++SFP_BASE = 49 ++NUM_SFP = 6 ++NUM_COMPONENT = 4 ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" ++PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" ++REBOOT_CAUSE_FILE = "reboot-cause.txt" ++PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" ++HOST_CHK_CMD = "docker > /dev/null 2>&1" ++GET_HWSKU_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.hwsku" ++GET_PLATFORM_CMD = "sonic-cfggen -d -v DEVICE_METADATA.localhost.platform" ++GET_HOST_HWSKU_CMD = 'grep ^onie_machine= /host/machine.conf | cut -f2 -d"="' ++GET_HOST_PLATFORM_CMD = 'grep ^onie_platform /host/machine.conf | cut -f2 -d"="' ++ ++class Chassis(ChassisBase): ++ """Platform-specific Chassis class""" ++ ++ def __init__(self): ++ super(Chassis, self).__init__() ++ ++ # Initialize SKU name and Platform name ++ self.sku_name = self._get_sku_name() ++ self.platform_name = self._get_platform_name() ++ self.name = self.sku_name ++ self.COPPER_PORT_START = COPPER_PORT_START ++ self.COPPER_PORT_END = COPPER_PORT_END ++ ++ ++ for fan_index in range(0, NUM_FANTRAY): ++ fandrawer = FanDrawer(fan_index) ++ self._fan_drawer_list.append(fandrawer) ++ self._fan_list.extend(fandrawer._fan_list) ++ ++ for index in range(0, NUM_PSU): ++ psu = Psu(index) ++ self._psu_list.append(psu) ++ ++ for index in range(0, NUM_THERMAL): ++ thermal = Thermal(index) ++ self._thermal_list.append(thermal) ++ ++ # for non-sfp ports create dummy objects for copper / non-sfp ports ++ for index in range(self.COPPER_PORT_START, self.COPPER_PORT_END+1): ++ port=index-1 ++ sfp_node = Sfp(index, 'COPPER') ++ self._sfp_list.append(sfp_node) ++ ++ for index in range(SFP_BASE, SFP_BASE + NUM_SFP): ++ sfp_module = Sfp(index, 'SFP') ++ self._sfp_list.append(sfp_module) ++ ++ from sonic_platform.component import Component ++ for index in range(0, NUM_COMPONENT): ++ component = Component(index) ++ self._component_list.append(component) ++ ++ self._eeprom = Tlv() ++ self._transceiver_presence = [0] * (SFP_BASE + NUM_SFP - 1) ++ ++ def __is_host(self): ++ return os.system(HOST_CHK_CMD) == 0 ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def get_base_mac(self): ++ """ ++ Retrieves the base MAC address for the chassis ++ Returns: ++ A string containing the MAC address in the format ++ 'XX:XX:XX:XX:XX:XX' ++ """ ++ return self._eeprom.get_mac() ++ ++ def get_serial(self): ++ """ ++ Retrieves the hardware serial number for the chassis ++ Returns: ++ A string containing the hardware serial number for this chassis. ++ """ ++ return self._eeprom.get_serial() ++ ++ def get_system_eeprom_info(self): ++ """ ++ Retrieves the full content of system EEPROM information for the chassis ++ Returns: ++ A dictionary where keys are the type code defined in ++ OCP ONIE TlvInfo EEPROM format and values are their corresponding ++ values. ++ """ ++ return self._eeprom.get_eeprom() ++ ++ def get_firmware_version(self, component_name): ++ """ ++ Retrieves platform-specific hardware/firmware versions for chassis ++ componenets such as BIOS, CPLD, FPGA, etc. ++ Args: ++ type: A string, component name ++ ++ Returns: ++ A string containing platform-specific component versions ++ """ ++ self.component = Component(component_name) ++ if component_name not in self._component_name_list: ++ return None ++ return self.component.get_firmware_version() ++ ++ def install_component_firmware(self, component_name, image_path): ++ """ ++ Install firmware to module ++ Args: ++ type: A string, component name. ++ image_path: A string, path to firmware image. ++ ++ Returns: ++ A boolean, True if install successfully, False if not ++ """ ++ self.component = Component(component_name) ++ if component_name not in self._component_name_list: ++ return False ++ return self.component.upgrade_firmware(image_path) ++ ++ def get_reboot_cause(self): ++ """ ++ Retrieves the cause of the previous reboot ++ ++ Returns: ++ A tuple (string, string) where the first element is a string ++ containing the cause of the previous reboot. This string must be ++ one of the predefined strings in this class. If the first string ++ is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used ++ to pass a description of the reboot cause. ++ """ ++ ++ reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host( ++ ) else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE ++ sw_reboot_cause = self.__read_txt_file( ++ reboot_cause_path) or "Unknown" ++ ++ if sw_reboot_cause != "Unknown": ++ reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE ++ description = sw_reboot_cause ++ else: ++ reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER ++ description = 'Unknown reason' ++ ++ return (reboot_cause, description) ++ ++ def _get_sku_name(self): ++ if self.__is_host(): ++ p = subprocess.Popen(GET_HOST_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) ++ else: ++ p = subprocess.Popen(GET_HWSKU_CMD, shell=True, stdout=subprocess.PIPE) ++ out, err = p.communicate() ++ return out.decode().rstrip('\n') ++ ++ def _get_platform_name(self): ++ if self.__is_host(): ++ p = subprocess.Popen(GET_HOST_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) ++ else: ++ p = subprocess.Popen(GET_PLATFORM_CMD, shell=True, stdout=subprocess.PIPE) ++ out, err = p.communicate() ++ return out.decode().rstrip('\n') ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return self.name ++ ++ def get_sfp(self, index): ++ sfp = None ++ try: ++ sfp = self._sfp_list[index - 1] ++ except IndexError: ++ sys.stderr.write("SFP index {} out of range (1-{})\n".format(index, len(self._sfp_list))) ++ ++ return sfp ++ ++ def _get_sfp_presence(self): ++ port_pres = {} ++ for port in range(0, SFP_BASE + NUM_SFP - 1): ++ sfp = self._sfp_list[port] ++ port_pres[port] = sfp.get_presence() ++ ++ return port_pres ++ ++ def get_change_event(self, timeout=0): ++ port_dict = {} ++ ret_dict = {'sfp': port_dict} ++ forever = False ++ change_event = False ++ ++ if timeout == 0: ++ forever = True ++ elif timeout > 0: ++ timeout = timeout / float(1000) ++ else: ++ return False, ret_dict #Incorrect timeout ++ ++ while True: ++ if forever: ++ timer = 1 ++ else: ++ timer = min(timeout, 1) ++ start_time = time.time() ++ ++ time.sleep(timer) ++ cur_presence = self._get_sfp_presence() ++ for port in range(0, SFP_BASE + NUM_SFP - 1): ++ if cur_presence[port] != self._transceiver_presence[port]: ++ change_event = True ++ if cur_presence[port] == 1: ++ port_dict[port + 1] = '1' ++ else: ++ port_dict[port + 1] = '0' ++ ++ self._transceiver_presence = cur_presence ++ if change_event == True: ++ break ++ ++ if not forever: ++ elapsed_time = time.time() - start_time ++ timeout = round(timeout - elapsed_time, 3) ++ if timeout <= 0: ++ break ++ ++ return True, ret_dict ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._eeprom.get_model() ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ ++ return '0' ++ ++ def get_watchdog(self): ++ """ ++ Retrieves hardware watchdog device on this chassis ++ ++ Returns: ++ An object derived from WatchdogBase representing the hardware ++ watchdog device ++ """ ++ try: ++ if self._watchdog is None: ++ from sonic_platform.watchdog import WatchdogImplBase ++ watchdog_device = "watchdog1" ++ self._watchdog = WatchdogImplBase(watchdog_device) ++ except Exception as e: ++ sonic_logger.log_warning(" Fail to load watchdog {}".format(repr(e))) ++ ++ return self._watchdog ++ ++ def initizalize_system_led(self): ++ self.system_led = "" ++ return True ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the system LED ++ ++ Args: ++ color: A string representing the color with which to set the ++ system LED ++ ++ Returns: ++ bool: True if system LED state is set successfully, False if not ++ """ ++ ++ self.system_led = color ++ ++ sysled_path="{}/sys_led".format(CPLD_SYSFS_DIR) ++ psuled_path="{}/psu_led".format(CPLD_SYSFS_DIR) ++ fanled_path="{}/fan_led".format(CPLD_SYSFS_DIR) ++ watchdog_update_path="{}/watchdog_kick".format(CPLD_SYSFS_DIR) ++ ++ #if color == "red": ++ # val = 2 ++ #elif color == "green_blinking": ++ # val = 3 ++ #elif color == "green": ++ # val = 1 ++ ++ color=int(self.__read_txt_file(sysled_path)) ++ if color is None: ++ return True ++ if color != 1 and color != 2: ++ self.__write_txt_file(sysled_path, str(1)) ++ self.__write_txt_file(watchdog_update_path, str(1)) ++ ++ fan_sta = True ++ psu_sta = True ++ ++ #clear fault before we update the fan statue led ++ for fan_index in range(0, NUM_FANTRAY): ++ sta=self._fan_drawer_list[fan_index].get_status() ++ if not sta: ++ self._fan_drawer_list[fan_index]._fan_list[0].try_clear_fault() ++ ++ for fan_index in range(0, NUM_FANTRAY): ++ sta=self._fan_drawer_list[fan_index].get_status() ++ prs=self._fan_drawer_list[fan_index].get_presence() ++ fan_sta = fan_sta & sta ++ if sta and prs: ++ val=1 ++ else: ++ val=2 ++ led_path="{}/fan{}_led".format(CPLD_SYSFS_DIR, fan_index+1) ++ self.__write_txt_file(led_path, str(val)) ++ ++ if fan_sta: ++ val = 1 ++ else: ++ val = 2 ++ self.__write_txt_file(fanled_path, str(val)) ++ ++ for index in range(0, NUM_PSU): ++ sta=self._psu_list[index].get_status() ++ psu_sta = psu_sta & sta ++ if psu_sta: ++ val = 1 ++ else: ++ val = 2 ++ self.__write_txt_file(psuled_path, str(val)) ++ ++ return True ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the system LED ++ ++ Returns: ++ A string, one of the valid LED color strings which could be vendor ++ specified. ++ """ ++ return self.system_led ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ return None ++ ++ def get_port_or_cage_type(self, index): ++ """ ++ Retrieves sfp port or cage type corresponding to physical port ++ ++ Args: ++ index: An integer (>=0), the index of the sfp to retrieve. ++ The index should correspond to the physical port in a chassis. ++ For example:- ++ 1 for Ethernet0, 2 for Ethernet4 and so on for one platform. ++ 0 for Ethernet0, 1 for Ethernet4 and so on for another platform. ++ ++ Returns: ++ The masks of all types of port or cage that can be supported on the port ++ Types are defined in sfp_base.py ++ Eg. ++ Both SFP and SFP+ are supported on the port, the return value should be 0x0a ++ which is 0x02 | 0x08 ++ """ ++ index = index - 1 ++ if index < COPPER_PORT_END: ++ from sonic_platform_base.sfp_base import SfpBase ++ return SfpBase.SFP_PORT_TYPE_BIT_RJ45 ++ raise NotImplementedError ++ ++ def power_down(self): ++ power_down_path="{}/system_power_down".format(CPLD_SYSFS_DIR) ++ self.__write_txt_file(power_down_path, str(0)) ++ ++ def set_sysled_red(self): ++ sysled_path="{}/sys_led".format(CPLD_SYSFS_DIR) ++ self.__write_txt_file(sysled_path, str(2)) ++ ++ def get_thermal_manager(self): ++ from .thermal_manager import ThermalManager ++ return ThermalManager ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the Chassis ++ Returns: ++ bool: True if Chassis is present, False if not ++ """ ++ return True ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/component.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/component.py +new file mode 100644 +index 000000000..3ee2c1c80 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/component.py +@@ -0,0 +1,194 @@ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in ++# the platform ++# ++######################################################################## ++ ++try: ++ import sys ++ import subprocess ++ from sonic_platform_base.component_base import ComponentBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++if sys.version_info[0] < 3: ++ import commands as cmd ++else: ++ import subprocess as cmd ++ ++ ++class Component(ComponentBase): ++ """platform-specific Component class""" ++ ++ CHASSIS_COMPONENTS = [ ++ ["U-Boot", "Performs initialization during booting"], ++ ["ONIE-VERSION", "ONIE - Open Network Install Environment"], ++ ["CPLD", "CPLD firmware"], ++ ["PoE", "Power over Ethernet controller firmware"], ++ ] ++ ++ def __init__(self, component_index): ++ self.index = component_index ++ self.name = self.CHASSIS_COMPONENTS[self.index][0] ++ self.description = self.CHASSIS_COMPONENTS[self.index][1] ++ ++ def _get_command_result(self, cmdline): ++ try: ++ proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ stdout = proc.communicate()[0] ++ proc.wait() ++ result = stdout.rstrip('\n') ++ except OSError: ++ result = None ++ ++ return result ++ ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the component ++ ++ Returns: ++ A string containing the name of the component ++ """ ++ return self.name ++ ++ def get_description(self): ++ """ ++ Retrieves the description of the component ++ ++ Returns: ++ A string containing the description of the component ++ """ ++ return self.description ++ ++ def get_firmware_version(self): ++ """ ++ Retrieves the firmware version of the component ++ ++ Returns: ++ A string containing the firmware version of the component ++ """ ++ ++ if self.index == 0: ++ cmdstatus, uboot_version = cmd.getstatusoutput('grep --null-data ^U-Boot /dev/mtd0 | tail -n 1 | cut -d" " -f2') ++ return uboot_version ++ ++ if self.index == 1: ++ cmdstatus, onie_version = cmd.getstatusoutput('grep ^onie_version /host/machine.conf | cut -f2 -d"="') ++ return onie_version ++ ++ if self.index == 2: ++ cmdstatus, cpld_ver = cmd.getstatusoutput('cat /sys/bus/i2c/devices/0-0033/cpld_rev') ++ return cpld_ver ++ ++ if self.index == 3: ++ cmdstatus, poe_min = cmd.getstatusoutput('poetool system get_sw_ver | grep swMinorVerNum') ++ cmdstatus, poe_maj = cmd.getstatusoutput('poetool system get_sw_ver | grep swMajorNum') ++ poe_ver = poe_maj.split(" ")[-1] + "." + poe_min.split(" ")[-1] ++ return poe_ver ++ ++ ++ def install_firmware(self, image_path): ++ """ ++ Installs firmware to the component ++ ++ Args: ++ image_path: A string, path to firmware image ++ ++ Returns: ++ A boolean, True if install was successful, False if not ++ """ ++ return False ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if FAN is present, False if not ++ """ ++ return True ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return 'N/A' ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return 'N/A' ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False ++ ++ def get_available_firmware_version(self, image_path): ++ """ ++ Retrieves the available firmware version of the component ++ Note: the firmware version will be read from image ++ Args: ++ image_path: A string, path to firmware image ++ Returns: ++ A string containing the available firmware version of the component ++ """ ++ return "N/A" ++ ++ def get_firmware_update_notification(self, image_path): ++ """ ++ Retrieves a notification on what should be done in order to complete ++ the component firmware update ++ Args: ++ image_path: A string, path to firmware image ++ Returns: ++ A string containing the component firmware update notification if required. ++ By default 'None' value will be used, which indicates that no actions are required ++ """ ++ return "None" ++ ++ def update_firmware(self, image_path): ++ """ ++ Updates firmware of the component ++ This API performs firmware update: it assumes firmware installation and loading in a single call. ++ In case platform component requires some extra steps (apart from calling Low Level Utility) ++ to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API ++ Args: ++ image_path: A string, path to firmware image ++ Raises: ++ RuntimeError: update failed ++ """ ++ return False +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/eeprom.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/eeprom.py +new file mode 100644 +index 000000000..ae9fe3513 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/eeprom.py +@@ -0,0 +1,120 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# Platform and model specific eeprom subclass, inherits from the base class, ++# and provides the followings: ++# - the eeprom format definition ++# - specific encoder/decoder if there is special need ++############################################################################# ++ ++try: ++ import glob ++ import os ++ import sys ++ import imp ++ import re ++ from array import array ++ from io import StringIO ++ from sonic_platform_base.sonic_eeprom import eeprom_dts ++ from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' ++CACHE_FILE = 'syseeprom_cache' ++ ++ ++class Tlv(eeprom_tlvinfo.TlvInfoDecoder): ++ ++ EEPROM_DECODE_HEADLINES = 6 ++ ++ def __init__(self): ++ self._eeprom_path = "/sys/bus/i2c/devices/0-0055/eeprom" ++ super(Tlv, self).__init__(self._eeprom_path, 0, '', True) ++ self._eeprom = self._load_eeprom() ++ ++ def __parse_output(self, decode_output): ++ decode_output.replace('\0', '') ++ lines = decode_output.split('\n') ++ lines = lines[self.EEPROM_DECODE_HEADLINES:] ++ _eeprom_info_dict = dict() ++ ++ for line in lines: ++ try: ++ match = re.search( ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+[\s]+[\S]+)', line) ++ if match is not None and match.group(1) == '0x25': ++ idx = match.group(1) ++ value = match.group(3).rstrip('\0') ++ _eeprom_info_dict[idx] = value ++ else: ++ match = re.search( ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) ++ if match is not None: ++ idx = match.group(1) ++ value = match.group(3).rstrip('\0') ++ _eeprom_info_dict[idx] = value ++ ++ except BaseException: ++ pass ++ return _eeprom_info_dict ++ ++ def _load_eeprom(self): ++ original_stdout = sys.stdout ++ sys.stdout = StringIO() ++ try: ++ self.read_eeprom_db() ++ except Exception: ++ decode_output = sys.stdout.getvalue() ++ sys.stdout = original_stdout ++ return self.__parse_output(decode_output) ++ ++ status = self.check_status() ++ if status < 'ok': ++ return False ++ ++ if not os.path.exists(CACHE_ROOT): ++ try: ++ os.makedirs(CACHE_ROOT) ++ except: ++ pass ++ ++ # ++ # only the eeprom classes that inherit from eeprom_base ++ # support caching. Others will work normally ++ # ++ try: ++ self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) ++ except: ++ pass ++ ++ e = self.read_eeprom() ++ if e is None: ++ return 0 ++ ++ try: ++ self.update_cache(e) ++ except: ++ pass ++ ++ self.decode_eeprom(e) ++ decode_output = sys.stdout.getvalue() ++ sys.stdout = original_stdout ++ ++ (is_valid, valid_crc) = self.is_checksum_valid(e) ++ if not is_valid: ++ return False ++ ++ return self.__parse_output(decode_output) ++ ++ def get_eeprom(self): ++ return self._eeprom ++ ++ def get_serial(self): ++ return self._eeprom.get('0x23', "Undefined.") ++ ++ def get_mac(self): ++ return self._eeprom.get('0x24', "Undefined.") ++ ++ def get_model(self): ++ return self._eeprom.get('0x21', "Undefined.") +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan.py +new file mode 100644 +index 000000000..51fd551ff +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan.py +@@ -0,0 +1,353 @@ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the fan status which are available in the platform ++# ++############################################################################# ++ ++ ++import os.path ++import time ++ ++try: ++ from sonic_platform_base.fan_base import FanBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++PSU_FAN_MAX_RPM = 26000 ++SPEED_TOLERANCE = 15 ++SYSFS_PATH = "/sys/bus/i2c/devices/{0}-00{1}" ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++HWMON_PATH = "/sys/bus/i2c/devices/{0}-00{1}/hwmon" ++PSU_HWMON_I2C_MAPPING = { ++ 0: { ++ "num": 3, ++ "addr": "59" ++ }, ++ 1: { ++ "num": 3, ++ "addr": "58" ++ }, ++} ++ ++FAN_HWMON_I2C_MAPPING = { ++ 0: { ++ "num": 2, ++ "addr": "2f" ++ }, ++} ++ ++#FAN_PCA9539_I2C_MAPPING = { ++# 0: { ++# "num": 9, ++# "addr": "74" ++# }, ++# 1: { ++# "num": 9, ++# "addr": "76" ++# }, ++#} ++ ++# 3 fan sku not exist now ++#FAN_ROTOR_MAPPING = { ++# 0: 1, ++# 1: 8, ++# 2: 4 ++#} ++ ++#FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"] ++ ++FAN_ROTOR_MAPPING = { ++ 0: 4, ++ 1: 8 ++} ++ ++FAN_NAME_LIST = ["FAN-1", "FAN-2"] ++ ++class Fan(FanBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): ++ self.fan_index = fan_index ++ self.fan_tray_index = fan_tray_index ++ self.is_psu_fan = is_psu_fan ++ self.pwm_conv=[] ++ ++ if self.is_psu_fan: ++ self.psu_index = psu_index ++ self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] ++ self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] ++ hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++ self.psu_i2c_num, self.psu_i2c_addr)) ++ self.psu_hwmon_path = os.path.join(HWMON_PATH.format(self.psu_i2c_num, self.psu_i2c_addr), hwmon_dir) ++ ++ self.psu_status_path = CPLD_SYSFS_DIR ++ else: ++ self.fan_i2c_num = FAN_HWMON_I2C_MAPPING[0]['num'] ++ self.fan_i2c_addr = FAN_HWMON_I2C_MAPPING[0]['addr'] ++ hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++ self.fan_i2c_num, self.fan_i2c_addr)) ++ self.fan_hwmon_path = os.path.join(HWMON_PATH.format(self.fan_i2c_num, self.fan_i2c_addr), hwmon_dir) ++ ++ self.fan_status_path = CPLD_SYSFS_DIR ++ ++# self.an_fan_i2c_num = FAN_HWMON_I2C_MAPPING[1]['num'] ++# self.an_fan_i2c_addr = FAN_HWMON_I2C_MAPPING[1]['addr'] ++# hwmon_dir = self.__search_hwmon_dir_name(HWMON_PATH.format( ++# self.fan_i2c_num, self.fan_i2c_addr)) ++# self.an_fan_hwmon_path = os.path.join(HWMON_PATH.format(self.fan_i2c_num, self.fan_i2c_addr), hwmon_dir) ++ ++# self.fan_sts_i2c_num = FAN_PCA9539_I2C_MAPPING[0 if fan_tray_index < 3 else 1]['num'] ++# self.fan_sts_i2c_addr = FAN_PCA9539_I2C_MAPPING[0 if fan_tray_index < 3 else 1]['addr'] ++# self.fan_status_path = SYSFS_PATH.format(self.fan_sts_i2c_num, self.fan_sts_i2c_addr) ++ ++ for i in range(0, 101): ++ self.pwm_conv.append(int(i * 255 / 100)) ++ ++ FanBase.__init__(self) ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ 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) ++ ++ """ ++ speed = 0 ++ if self.is_psu_fan: ++ psu_fan_path= "{}/{}".format(self.psu_hwmon_path, 'fan1_input') ++ rpm=self.__read_txt_file(psu_fan_path) ++ if rpm is None: ++ return 0 ++ speed = int(int(rpm) * 100 / PSU_FAN_MAX_RPM) ++ elif self.get_presence(): ++ #path= "{}/fan{}_input".format(self.fan_hwmon_path, FAN_ROTOR_MAPPING[self.fan_tray_index + self.fan_index]) ++ path= "{}/pwm1".format(self.fan_hwmon_path) ++ pwm=self.__read_txt_file(path) ++ if pwm is None: ++ return 0 ++ elif int(pwm) == 77: ++ pwm = 76 ++ ++ speed = self.pwm_conv.index(int(pwm)) ++ ++ return int(speed) ++ ++ def get_target_speed(self): ++ """ ++ Retrieves the target (expected) speed of the fan ++ Returns: ++ An integer, the percentage of full fan speed, in the range 0 (off) ++ to 100 (full speed) ++ ++ Note: ++ speed_pc = pwm_target/255*100 ++ ++ 0 : when PWM mode is use ++ pwm : when pwm mode is not use ++ """ ++ return self.get_speed() ++ ++ def get_speed_tolerance(self): ++ """ ++ Retrieves the speed tolerance of the fan ++ Returns: ++ An integer, the percentage of variance from target speed which is ++ considered tolerable ++ """ ++ return SPEED_TOLERANCE ++ ++ def set_speed(self, speed): ++ """ ++ Sets the fan speed ++ Args: ++ speed: An integer, the percentage of full fan speed to set fan to, ++ in the range 0 (off) to 100 (full speed) ++ Returns: ++ A boolean, True if speed is set successfully, False if not ++ ++ """ ++ ++ if not self.is_psu_fan and self.get_presence(): ++ pwm = int((speed * 255) / 100) ++ speed_path = "{}/{}".format(self.fan_hwmon_path, 'pwm1') ++ self.__write_txt_file(speed_path, str(pwm)) ++# speed_path = "{}/{}".format(self.an_fan_hwmon_path, 'pwm1') ++# self.__write_txt_file(speed_path, int(speed)) ++ ++ return True ++ ++ return False ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the fan module status LED ++ Args: ++ color: A string representing the color with which to set the ++ fan module status LED ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ if color is self.STATUS_LED_COLOR_GREEN: ++ val = 1 ++ else: ++ val = 2 ++ ++ led_path="{}/fan{}_led".format(self.fan_status_path, self.fan_tray_index+1) ++ self.__write_txt_file(led_path, str(val)) ++ ++ return True ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ status=self.get_presence() ++ if status is None: ++ return self.STATUS_LED_COLOR_OFF ++ ++ return { ++ 1: self.STATUS_LED_COLOR_GREEN, ++ 0: self.STATUS_LED_COLOR_RED ++ }.get(status, self.STATUS_LED_COLOR_OFF) ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ fan_name = FAN_NAME_LIST[self.fan_tray_index + self.fan_index] \ ++ if not self.is_psu_fan \ ++ else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) ++ ++ return fan_name ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the FAN ++ Returns: ++ bool: True if FAN is present, False if not ++ """ ++ ++ ++ if self.is_psu_fan: ++ present_path="{}/psu{}_present".format(self.psu_status_path, self.psu_index+1) ++ else: ++ present_path="{}/cnfan{}_present".format(self.fan_status_path, self.fan_tray_index+1) ++ ++ val=self.__read_txt_file(present_path) ++ if val is not None: ++ return int(val, 10)==1 ++ else: ++ return False ++ ++ def try_clear_fault(self): ++ path= "{}/pwm1".format(self.fan_hwmon_path) ++ speed=self.__read_txt_file(path) ++ ++ self.__write_txt_file(path, str(speed)) ++ time.sleep(2) ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ if self.is_psu_fan: ++ psu_fan_path= "{}/{}".format(self.psu_hwmon_path, 'fan1_fault') ++ val=self.__read_txt_file(psu_fan_path) ++ if val is not None: ++ return int(val, 10)==0 ++ else: ++ return False ++ else: ++ path= "{}/fan{}_fault".format(self.fan_hwmon_path, FAN_ROTOR_MAPPING[self.fan_tray_index + self.fan_index]) ++ val=self.__read_txt_file(path) ++ if val is not None: ++ return int(val, 10)==0 ++ else: ++ return False ++ ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ ++ return "N/A" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "N/A" ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return (self.fan_tray_index+1) \ ++ if not self.is_psu_fan else (self.psu_index+1) ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return True if not self.is_psu_fan else False ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan_drawer.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan_drawer.py +new file mode 100644 +index 000000000..0f9f7c31b +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/fan_drawer.py +@@ -0,0 +1,108 @@ ++######################################################################## ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the Fan-Drawers' information available in the platform. ++# ++######################################################################## ++ ++try: ++ from sonic_platform_base.fan_drawer_base import FanDrawerBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++FANS_PER_FANTRAY = 1 ++MAX_FAN_WATT = 7.2 ++ ++class FanDrawer(FanDrawerBase): ++ """Platform-specific Fan class""" ++ ++ def __init__(self, fantray_index): ++ ++ FanDrawerBase.__init__(self) ++ # FanTray is 0-based in platforms ++ self.fantrayindex = fantray_index ++ self.__initialize_fan_drawer() ++ ++ ++ def __initialize_fan_drawer(self): ++ from sonic_platform.fan import Fan ++ for i in range(FANS_PER_FANTRAY): ++ self._fan_list.append(Fan(self.fantrayindex, i)) ++ ++ def get_name(self): ++ """ ++ Retrieves the fan drawer name ++ Returns: ++ string: The name of the device ++ """ ++ return "FanTray{}".format(self.fantrayindex+1) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ return self._fan_list[0].get_presence() ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._fan_list[0].get_model() ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return self._fan_list[0].get_serial() ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return self._fan_list[0].get_status() ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan drawer LED ++ ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ return self._fan_list[0].get_status_led() ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return (self.fantrayindex+1) ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return True ++ ++ def get_maximum_consumed_power(self): ++ """ ++ Retrives the maximum power drawn by Fan Drawer ++ Returns: ++ A float, with value of the maximum consumable power of the ++ component. ++ """ ++ return MAX_FAN_WATT +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/pcie.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/pcie.py +new file mode 100644 +index 000000000..273767cfb +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/pcie.py +@@ -0,0 +1,47 @@ ++######################################################################## ++# Copyright (C) 2021, mrvl CORPORATION & AFFILIATES. All rights reserved. ++# Module contains a platform specific implementation of SONiC Platform ++# Base PCIe class ++######################################################################## ++import os ++import re ++ ++try: ++ from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++SYSFS_PCI_DEVICE_PATH = '/sys/bus/pci/devices/' ++ ++class Pcie(PcieUtil): ++ def get_pcie_check(self): ++ self.load_config_file() ++ for item_conf in self.confInfo: ++ id_conf = item_conf["id"] ++ dev_conf = item_conf["dev"] ++ fn_conf = item_conf["fn"] ++ bus_conf = self._device_id_to_bus_map.get(str(id_conf)) ++ if bus_conf and self.check_pcie_sysfs(bus=int(bus_conf, base=16), device=int(dev_conf, base=16), ++ func=int(fn_conf, base=16)): ++ item_conf["result"] = "Passed" ++ else: ++ item_conf["result"] = "Failed" ++ return self.confInfo ++ ++ def _create_device_id_to_bus_map(self): ++ self._device_id_to_bus_map = {} ++ self.load_config_file() ++ device_folders = os.listdir(SYSFS_PCI_DEVICE_PATH) ++ for folder in device_folders: ++ pattern_for_device_folder = re.search('....:(..):..\..', folder) ++ if pattern_for_device_folder: ++ bus = pattern_for_device_folder.group(1) ++ with open(os.path.join(SYSFS_PCI_DEVICE_PATH, folder, 'device'), 'r') as device_file: ++ # The 'device' file contain an hex repesantaion of the id key in the yaml file. ++ # We will strip the new line character, and remove the 0x prefix that is not needed. ++ device_id = device_file.read().strip().replace('0x', '') ++ self._device_id_to_bus_map[device_id] = bus ++ ++ def __init__(self, platform_path): ++ PcieUtil.__init__(self, platform_path) ++ self._create_device_id_to_bus_map() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/platform.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/platform.py +new file mode 100644 +index 000000000..0b67a68b8 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/platform.py +@@ -0,0 +1,22 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the platform information ++# ++############################################################################# ++ ++try: ++ from sonic_platform_base.platform_base import PlatformBase ++ from sonic_platform.chassis import Chassis ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Platform(PlatformBase): ++ ++ def __init__(self): ++ PlatformBase.__init__(self) ++ self._chassis = Chassis() ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/psu.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/psu.py +new file mode 100644 +index 000000000..80274cd93 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/psu.py +@@ -0,0 +1,359 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# psuutil.py ++# Platform-specific PSU status interface for SONiC ++############################################################################# ++ ++import os.path ++import sonic_platform ++ ++try: ++ from sonic_platform_base.psu_base import PsuBase ++ from sonic_platform.fan import Fan ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++PSU_NAME_LIST = ["PSU-1", "PSU-2"] ++ ++PSU_HWMON_PATH = "/sys/bus/i2c/devices/{0}-00{1}/hwmon" ++PSU_SYSFS_PATH = "/sys/bus/i2c/devices/{0}-00{1}" ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++PSU_I2C_MAPPING = { ++ 0: { ++ "bus": 3, ++ "addr": "59" ++ }, ++ 1: { ++ "bus": 3, ++ "addr": "58" ++ }, ++} ++ ++ ++class Psu(PsuBase): ++ """Platform-specific Psu class""" ++ ++ def __init__(self, psu_index): ++ self.PSU_TEMP_MAX = 70000 ++ self.PSU_OUTPUT_POWER_MAX = 1920000000 ++ self.PSU_OUTPUT_VOLTAGE_MIN = 40000 ++ self.PSU_OUTPUT_VOLTAGE_MAX = 62000 ++ self.index = psu_index ++ PsuBase.__init__(self) ++ self.i2c_num = PSU_I2C_MAPPING[self.index]["bus"] ++ self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] ++ self.hwmon_path = PSU_HWMON_PATH.format(self.i2c_num, self.i2c_addr) ++ self.sysfs_path = PSU_SYSFS_PATH.format(self.i2c_num, str( ++ int(self.i2c_addr) - 8)) # eeprom addr always be mcu addr - 8 ++ self.__initialize_fan() ++ ++ def __initialize_fan(self): ++ from sonic_platform.fan import Fan ++ for fan_index in range(0, 1): ++ fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) ++ self._fan_list.append(fan) ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def get_fan(self, index): ++ """ ++ Retrieves object representing the fan module contained in this PSU ++ Returns: ++ An object dervied from FanBase representing the fan module ++ contained in this PSU ++ """ ++ return self._fan_list[index] ++ ++ def get_powergood_status(self): ++ """ ++ Retrieves the powergood status of PSU ++ Returns: ++ A boolean, True if PSU has stablized its output voltages and passed all ++ its internal self-tests, False if not. ++ """ ++ return self.get_status() ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the PSU status LED ++ Args: ++ color: A string representing the color with which to set the PSU status LED ++ Note: Only support green and off ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ # Hardware not supported ++ return False ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the PSU status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ if self.get_presence(): ++ if self.get_powergood_status(): ++ return self.STATUS_LED_COLOR_GREEN ++ else: ++ return self.STATUS_LED_COLOR_RED ++ else: ++ return None ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return PSU_NAME_LIST[self.index] ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the PSU ++ Returns: ++ bool: True if PSU is present, False if not ++ """ ++ attr_file = 'psu{}_present'.format(self.index + 1) ++ attr_path = CPLD_SYSFS_DIR + '/' + attr_file ++ status = 0 ++ try: ++ with open(attr_path, 'r') as psu_prs: ++ status = int(psu_prs.read()) ++ except IOError: ++ return False ++ ++ return status == 1 ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ attr_file = 'psu{}_power_good'.format(self.index + 1) ++ attr_path = CPLD_SYSFS_DIR + '/' + attr_file ++ status = 0 ++ if self.get_presence(): ++ try: ++ with open(attr_path, 'r') as power_status: ++ status = int(power_status.read()) ++ except IOError: ++ return False ++ ++ return status == 1 ++ ++ def get_model(self): ++ """ ++ Retrieves the model name of the PSU ++ Returns: ++ model name ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "product_name") ++ if os.path.exists(file_path): ++ model = self.__read_txt_file(file_path) ++ return model ++ ++ return None ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the PSU ++ Returns: ++ model serial ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "serial_number") ++ if os.path.exists(file_path): ++ serial = self.__read_txt_file(file_path) ++ return serial ++ ++ return None ++ ++ def get_revision(self): ++ """ ++ Retrieves the hw rev of the PSU ++ Returns: ++ model rev ++ """ ++ if self.get_presence(): ++ file_path = os.path.join(self.sysfs_path, "hw_revision") ++ if os.path.exists(file_path): ++ rev = self.__read_txt_file(file_path) ++ return rev ++ ++ return None ++ ++ def get_voltage(self): ++ """ ++ Retrieves current PSU voltage output ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 12.1 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "in2_input") ++ voltage = self.__read_txt_file(file_path) ++ if not voltage: ++ return None ++ return float(voltage) / 1000 ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from PSU ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "temp1_input") ++ temp = self.__read_txt_file(file_path) ++ if not temp: ++ return None ++ return float(temp) / 1000 ++ ++ def get_current(self): ++ """ ++ Retrieves present electric current supplied by PSU ++ Returns: ++ A float number, the electric current in amperes, e.g 15.4 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "curr2_input") ++ current = self.__read_txt_file(file_path) ++ if not current: ++ return None ++ return float(current) / 1000 ++ ++ def get_power(self): ++ """ ++ Retrieves current energy supplied by PSU ++ Returns: ++ A float number, the power in watts, e.g. 302.6 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "power2_input") ++ power = self.__read_txt_file(file_path) ++ if not power: ++ return None ++ return float(power) / 1000000 ++ ++ def get_voltage_vin(self): ++ """ ++ Retrieves current PSU voltage output ++ Returns: ++ A float number, the output voltage in volts, ++ e.g. 220.0 ++ """ ++ hwmon_dir = self.__search_hwmon_dir_name(self.hwmon_path) ++ if hwmon_dir == '': ++ return None ++ ++ file_path = os.path.join(self.hwmon_path, hwmon_dir, ++ "in1_input") ++ voltage = self.__read_txt_file(file_path) ++ if not voltage: ++ return None ++ return float(voltage) / 1000 ++ ++ def get_temperature_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of PSU ++ Returns: ++ A float number, the high threshold temperature of PSU in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ return float(self.PSU_TEMP_MAX/1000) ++ ++ def get_voltage_high_threshold(self): ++ """ ++ Retrieves the high threshold PSU voltage output ++ Returns: ++ A float number, the high threshold output voltage in volts, ++ e.g. 12.1 ++ """ ++ return float(self.PSU_OUTPUT_VOLTAGE_MAX/1000) ++ ++ def get_voltage_low_threshold(self): ++ """ ++ Retrieves the low threshold PSU voltage output ++ Returns: ++ A float number, the low threshold output voltage in volts, ++ e.g. 12.1 ++ """ ++ return float(self.PSU_OUTPUT_VOLTAGE_MIN/1000) ++ ++ def get_maximum_supplied_power(self): ++ """ ++ Retrieves the maximum supplied power by PSU ++ Returns: ++ A float number, the maximum power output in Watts. ++ e.g. 1200.1 ++ """ ++ return float(self.PSU_OUTPUT_POWER_MAX/(1000 * 1000)) ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.index + 1 ++ ++ def is_replaceable(self): ++ return True ++ ++ def get_num_fans(self): ++ """ ++ Retrieves the number of fan modules available on this PSU ++ ++ Returns: ++ An integer, the number of fan modules available on this PSU ++ """ ++ return len(self._fan_list) ++ ++ def get_all_fans(self): ++ """ ++ Retrieves all fan modules available on this PSU ++ ++ Returns: ++ A list of objects derived from FanBase representing all fan ++ modules available on this PSU ++ """ ++ return self._fan_list +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/sfp.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/sfp.py +new file mode 100644 +index 000000000..be5468308 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/sfp.py +@@ -0,0 +1,379 @@ ++import os ++import time ++import sys ++import subprocess ++from ctypes import create_string_buffer ++ ++try: ++ from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase ++ from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper ++ from sonic_py_common import logger ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++if sys.version_info[0] < 3: ++ import commands as cmd ++else: ++ import subprocess as cmd ++ ++COPPER_TYPE = "COPPER" ++SFP_TYPE = "SFP" ++ ++SYSLOG_IDENTIFIER = "xcvrd" ++sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) ++ ++class Sfp(SfpOptoeBase): ++ """Platform-specific Sfp class""" ++ ++ # Paths ++ EEPROM_PATH = "/sys/bus/i2c/devices/{0}-0050/eeprom" ++ GPIO_PATH = "/sys/class/gpio/gpio{0}/value" ++ ++ PORT_EEPROM_I2C_MAPPING = { ++ 49: 5, ++ 50: 4, ++ 51: 7, ++ 52: 6, ++ 53: 9, ++ 54: 8, ++ } ++ ++ PORT_PRESENT_GPIO_MAPPING = { ++ 50: 472, ++ 49: 476, ++ 52: 480, ++ 51: 484, ++ 54: 488, ++ 53: 492, ++ } ++ ++ PORT_TX_DISABLE_GPIO_MAPPING = { ++ 50: 473, ++ 49: 477, ++ 52: 481, ++ 51: 485, ++ 54: 489, ++ 53: 493, ++ } ++ ++ PORT_RX_LOS_GPIO_MAPPING = { ++ 50: 474, ++ 49: 478, ++ 52: 482, ++ 51: 486, ++ 54: 490, ++ 53: 494, ++ } ++ ++ PORT_TX_FAULT_GPIO_MAPPING = { ++ 50: 475, ++ 49: 479, ++ 52: 483, ++ 51: 487, ++ 54: 491, ++ 53: 495, ++ } ++ ++ port_to_i2c_mapping = 0 ++ ++ def __init__(self, index, sfp_type): ++ SfpOptoeBase.__init__(self) ++ # Init index ++ self.index = index ++ self.port_num = index ++ self.sfp_type = sfp_type ++ #self.eeprom_path = eeprom_path ++ #self.port_to_i2c_mapping = port_i2c_map ++ self.port_to_eeprom_mapping = {} ++ ++ if self.sfp_type == COPPER_TYPE: ++ self.port_to_eeprom_mapping[index] = 'N/A' ++ else: ++ self.port_to_eeprom_mapping[index] = self.EEPROM_PATH.format(self.PORT_EEPROM_I2C_MAPPING[self.index]) ++ ++ def get_eeprom_path(self): ++ return self.port_to_eeprom_mapping[self.port_num] ++ ++ def __read_eeprom_specific_bytes(self, offset, num_bytes): ++ sysfsfile_eeprom = None ++ eeprom_raw = [] ++ for i in range(0, num_bytes): ++ eeprom_raw.append("0x00") ++ ++ sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] ++ try: ++ sysfsfile_eeprom = open( ++ sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) ++ sysfsfile_eeprom.seek(offset) ++ raw = sysfsfile_eeprom.read(num_bytes) ++ for n in range(0, num_bytes): ++ if sys.version_info[0] >= 3: ++ eeprom_raw[n] = hex(raw[n])[2:].zfill(2) ++ else: ++ eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) ++ except Exception: ++ pass ++ finally: ++ if sysfsfile_eeprom: ++ sysfsfile_eeprom.close() ++ ++ return eeprom_raw ++ ++ def get_reset_status(self): ++ """ ++ Retrieves the reset status of SFP ++ Returns: ++ A Boolean, True if reset enabled, False if disabled ++ """ ++ return False # SFP port doesn't support this feature ++ ++ ++ def get_rx_los(self): ++ """ ++ Retrieves the RX LOS (lost-of-signal) status of SFP ++ Returns: ++ A Boolean, True if SFP has RX LOS, False if not. ++ Note : RX LOS status is latched until a call to get_rx_los or a reset. ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_RX_LOS_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp rx los cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return True ++ else: ++ return False ++ ++ def get_tx_fault(self): ++ """ ++ Retrieves the TX fault status of SFP ++ ++ Returns: ++ A list of boolean values, representing the TX fault status ++ of each available channel, value is True if SFP channel ++ has TX fault, False if not. ++ E.g., for a tranceiver with four channels: [False, False, True, False] ++ Note : TX fault status is lached until a call to get_tx_fault or a reset. ++ """ ++ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_TX_FAULT_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp tx fault cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return True ++ else: ++ return False ++ ++ ++ def get_tx_disable(self): ++ """ ++ Retrieves the tx_disable status of this SFP ++ Returns: ++ A list of boolean values, representing the TX disable status ++ of each available channel, value is True if SFP channel ++ is TX disabled, False if not. ++ E.g., for a tranceiver with four channels: [False, False, True, False] ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return None ++ else: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_TX_DISABLE_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp present cmdstatus get failed") ++ return False ++ if int(value) == 1: ++ return [True] ++ else: ++ return [False] ++ ++ ++ def get_tx_disable_channel(self): ++ """ ++ Retrieves the TX disabled channels in this SFP ++ Returns: ++ A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent ++ TX channels which have been disabled in this SFP. ++ As an example, a returned value of 0x5 indicates that channel 0 ++ and channel 2 have been disabled. ++ """ ++ tx_disable_list = self.get_tx_disable() ++ if tx_disable_list is None: ++ return 0 ++ tx_disabled = 0 ++ for i in range(len(tx_disable_list)): ++ if tx_disable_list[i]: ++ tx_disabled |= 1 << i ++ return tx_disabled ++ ++ def get_lpmode(self): ++ """ ++ Retrieves the lpmode (low power mode) status of this SFP ++ Returns: ++ A Boolean, True if lpmode is enabled, False if disabled ++ """ ++ # SFP doesn't support this feature ++ return False ++ ++ def get_power_set(self): ++ ++ # SFP doesn't support this feature ++ return False ++ ++ def get_power_override(self): ++ """ ++ Retrieves the power-override status of this SFP ++ Returns: ++ A Boolean, True if power-override is enabled, False if disabled ++ """ ++ return False # SFP doesn't support this feature ++ ++ def reset(self): ++ """ ++ Reset SFP and return all user module settings to their default srate. ++ Returns: ++ A boolean, True if successful, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def tx_disable(self, tx_disable): ++ """ ++ Disable SFP TX for all channels ++ Args: ++ tx_disable : A Boolean, True to enable tx_disable mode, False to disable ++ tx_disable mode. ++ Returns: ++ A boolean, True if tx_disable is set successfully, False if not ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ gpiopin = self.GPIO_PATH.format(self.PORT_TX_DISABLE_GPIO_MAPPING[self.index]) ++ cmdstatus, value = cmd.getstatusoutput('echo {} > {}'.format(tx_disable, gpiopin)) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp tx_disable cmdstatus get failed") ++ return False ++ return True ++ ++ def tx_disable_channel(self, channel, disable): ++ """ ++ Sets the tx_disable for specified SFP channels ++ Args: ++ channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, ++ e.g. 0x5 for channel 0 and channel 2. ++ disable : A boolean, True to disable TX channels specified in channel, ++ False to enable ++ Returns: ++ A boolean, True if successful, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def set_lpmode(self, lpmode): ++ """ ++ Sets the lpmode (low power mode) of SFP ++ Args: ++ lpmode: A Boolean, True to enable lpmode, False to disable it ++ Note : lpmode can be overridden by set_power_override ++ Returns: ++ A boolean, True if lpmode is set successfully, False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def set_power_override(self, power_override, power_set): ++ """ ++ Sets SFP power level using power_override and power_set ++ Args: ++ power_override : ++ A Boolean, True to override set_lpmode and use power_set ++ to control SFP power, False to disable SFP power control ++ through power_override/power_set and use set_lpmode ++ to control SFP power. ++ power_set : ++ Only valid when power_override is True. ++ A Boolean, True to set SFP to low power mode, False to set ++ SFP to high power mode. ++ Returns: ++ A boolean, True if power-override and power_set are set successfully, ++ False if not ++ """ ++ ++ return False # SFP doesn't support this feature ++ ++ def get_name(self): ++ """ ++ Retrieves the name of the device ++ Returns: ++ string: The name of the device ++ """ ++ return "Ethernet" + str(self.index - 1) ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ if self.sfp_type == COPPER_TYPE: ++ return False ++ if self.sfp_type == SFP_TYPE: ++ cmdstatus, value = cmd.getstatusoutput('cat {}'.format(self.GPIO_PATH.format(self.PORT_PRESENT_GPIO_MAPPING[self.index]))) ++ if cmdstatus: ++ sonic_logger.log_warning("sfp present cmdstatus get failed") ++ return False ++ if int(value) == 0: ++ return True ++ else: ++ return False ++ ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return self.get_presence() ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.port_num ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ if self.sfp_type == "SFP": ++ return True ++ else: ++ return False ++ ++ def get_error_description(self): ++ """ ++ Retrives the error descriptions of the SFP module ++ Returns: ++ String that represents the current error descriptions of vendor specific errors ++ In case there are multiple errors, they should be joined by '|', ++ like: "Bad EEPROM|Unsupported cable" ++ """ ++ if not self.get_presence(): ++ err_descr = self.SFP_STATUS_UNPLUGGED ++ else: ++ err_descr = self.SFP_STATUS_OK ++ ++ return err_descr +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal.py +new file mode 100755 +index 000000000..836d9381c +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal.py +@@ -0,0 +1,305 @@ ++#!/usr/bin/env python ++ ++############################################################################# ++# ++# 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.sfp import Sfp ++ from sonic_platform_base.thermal_base import ThermalBase ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Thermal(ThermalBase): ++ """Platform-specific Thermal class""" ++ ++ THERMAL_NAME_LIST = [] ++ SYSFS_THERMAL_DIR = ["/sys/bus/i2c/devices/2-004a/hwmon/", ++ "/sys/bus/i2c/devices/2-0049/hwmon/", ++ "/sys/bus/i2c/devices/2-004b/hwmon/", ++ "/sys/bus/i2c/devices/3-0059/hwmon/", ++ "/sys/bus/i2c/devices/3-0058/hwmon/", ++ "/sys/devices/virtual/thermal/thermal_zone1/", ++ "/sys/bus/i2c/devices/0-001b/hwmon/"] ++ ++ def __init__(self, thermal_index): ++ self.index = thermal_index ++ if thermal_index >= 9: ++ self.sfp_module = Sfp(49 + (thermal_index - 9), 'SFP') ++ ++ # Add thermal name ++ self.THERMAL_NAME_LIST.append("XFMR Ambient") ++ self.THERMAL_NAME_LIST.append("DDR Ambient") ++ self.THERMAL_NAME_LIST.append("System Ambient") ++ self.THERMAL_NAME_LIST.append("PSU 1 Temp") ++ self.THERMAL_NAME_LIST.append("PSU 2 Temp") ++ self.THERMAL_NAME_LIST.append("CPU Temp") ++ self.THERMAL_NAME_LIST.append("Dimm Temp") ++ self.THERMAL_NAME_LIST.append("PoE Temp") ++ self.THERMAL_NAME_LIST.append("MAC Temp") ++ ++ self.THERMAL_NAME_LIST.append("XCVR 1 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 2 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 3 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 4 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 5 Temp") ++ self.THERMAL_NAME_LIST.append("XCVR 6 Temp") ++ ThermalBase.__init__(self) ++ self.minimum_thermal = 150.0 ++ self.maximum_thermal = 0.0 ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return "" ++ ++ def __search_hwmon_dir_name(self, directory): ++ try: ++ dirs = os.listdir(directory) ++ for file in dirs: ++ if file.startswith("hwmon"): ++ return file ++ except: ++ pass ++ return '' ++ ++ def __get_temp(self, temp_file): ++ hwmon_dir = self.__search_hwmon_dir_name(self.SYSFS_THERMAL_DIR[self.index]) ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], hwmon_dir, temp_file) ++ raw_temp = self.__read_txt_file(temp_file_path) ++ temp = float(raw_temp)/1000 ++ return "{:.3f}".format(temp) ++ ++ def get_temperature(self): ++ """ ++ Retrieves current temperature reading from thermal ++ Returns: ++ A float number of current temperature in Celsius up to nearest thousandth ++ of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 5 or self.index == 6: ++ temp_file = "temp1_input" ++ if self.get_presence(): ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ temp_file = "temp" ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], temp_file) ++ raw_temp = self.__read_txt_file(temp_file_path) ++ temp = float(raw_temp)/1000 ++ return float("{:.3f}".format(temp)) ++ elif self.index == 7: ++ raw_temp = self.__read_txt_file("/poe_temp") ++ temp = float(raw_temp) ++ return float("{:.3f}".format(temp)) ++ elif self.index == 8: ++ from swsscommon.swsscommon import DBConnector ++ temp = 0 ++ try: ++ stateDB = DBConnector('STATE_DB', 0, True, '') ++ temp = int(stateDB.hget('ASIC_TEMPERATURE_INFO', 'temperature_0')) ++ except Exception as E: ++ print("get_temperature (MAC) failed, cause by {}".format(E)) ++ return float("{:.3f}".format(temp)) ++ else: ++ if self.get_presence(): ++ return float("{:.3f}".format(self.sfp_module.get_temperature())) ++ ++ def get_high_threshold(self): ++ """ ++ Retrieves the high threshold temperature of thermal ++ Returns: ++ A float number, the high threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 3 or self.index == 6: ++ return float("{:.3f}".format(80)) ++ elif self.index < 5: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ return float("{:.3f}".format(90)) ++ elif self.index == 7: ++ return float("{:.3f}".format(110)) ++ elif self.index == 8: ++ return float("{:.3f}".format(100)) ++ else: ++ return float("{:.3f}".format(68)) ++ ++ def get_caution2_threshold(self): ++ """ ++ Retrieves the T-caution2 threshold temperature of thermal ++ Returns: ++ A float number, the high threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.index < 3 or self.index == 6: ++ return float("{:.3f}".format(82)) ++ elif self.index < 5: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) + 2 ++ elif self.index == 5: ++ return float("{:.3f}".format(92)) ++ elif self.index == 7: ++ return float("{:.3f}".format(115)) ++ elif self.index == 8: ++ return float("{:.3f}".format(105)) ++ else: ++ return float("{:.3f}".format(69)) ++ ++ def get_high_critical_threshold(self): ++ """ ++ Retrieves the high critical threshold temperature of thermal ++ :return: A float number, the high critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ ++ if self.index < 3: ++ temp_file = "temp1_max" ++ return float(self.__get_temp(temp_file)) ++ elif self.index < 5: ++ temp_file = "temp1_crit" ++ return float(self.__get_temp(temp_file)) ++ elif self.index == 5: ++ return float("{:.3f}".format(95)) ++ elif self.index == 6: ++ return float("{:.3f}".format(85)) ++ elif self.index == 7: ++ return float("{:.3f}".format(120)) ++ elif self.index == 8: ++ return float("{:.3f}".format(108)) ++ else: ++ return float("{:.3f}".format(70)) ++ ++ 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 ++ """ ++ if self.index < 5 or self.index == 6: ++ temp_file = "temp1_input" ++ hwmon_dir = self.__search_hwmon_dir_name(self.SYSFS_THERMAL_DIR[self.index]) ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], hwmon_dir, temp_file) ++ return os.path.isfile(temp_file_path) ++ elif self.index == 5: ++ temp_file = "temp" ++ temp_file_path = os.path.join(self.SYSFS_THERMAL_DIR[self.index], temp_file) ++ return os.path.isfile(temp_file_path) ++ elif self.index > 8: ++ return self.sfp_module.get_presence() ++ ++ return True ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ if self.index > 6 and self.index < 9: ++ return True ++ if not self.get_presence(): ++ return False ++ ++ return True ++ ++ def get_low_threshold(self): ++ """ ++ Retrieves the low threshold temperature of thermal ++ :return: A float number, the low threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ # work temperatur is 0~40, hyst is 2 ++ return 2.0 ++ ++ def get_low_critical_threshold(self): ++ """ ++ Retrieves the low critical threshold temperature of thermal ++ :return: A float number, the low critical threshold temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ # work temperatur is 0~40 ++ return 0.0 ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return "None" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "None" ++ ++ def is_replaceable(self): ++ """ ++ Retrieves whether thermal module is replaceable ++ Returns: ++ A boolean value, True if replaceable, False if not ++ """ ++ return False ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return self.index + 1 ++ ++ def get_minimum_recorded(self): ++ """ ++ Retrieves the minimum recorded temperature of thermal ++ Returns: ++ A float number, the minimum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ tmp = self.get_temperature() ++ if tmp is None: ++ return self.minimum_thermal ++ if tmp < self.minimum_thermal: ++ self.minimum_thermal = tmp ++ return self.minimum_thermal ++ ++ def get_maximum_recorded(self): ++ """ ++ Retrieves the maximum recorded temperature of thermal ++ Returns: ++ A float number, the maximum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ tmp = self.get_temperature() ++ if tmp is None: ++ return self.maximum_thermal ++ if tmp > self.maximum_thermal: ++ self.maximum_thermal = tmp ++ return self.maximum_thermal +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_actions.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_actions.py +new file mode 100755 +index 000000000..89f7d3ac7 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_actions.py +@@ -0,0 +1,218 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++import math ++import time ++import sonic_platform.platform ++try: ++ from sonic_platform.thermal import Thermal ++except Exception as e: ++ print(e) ++ ++from sonic_py_common import daemon_base, logger ++ ++sonic_logger = logger.Logger('thermal_actions') ++ ++SENSORS_NUM = 5 ++ ++TEMP_INFO = [] ++ ++SENSOR_INDEX = { ++ 0: 0, ++ 1: 1, ++ 2: 2, ++ 3: 5, ++ 4: 8 ++} ++ ++COFF_KA = { ++ 0: 2.62, ++ 1: 2.15, ++ 2: 2.23, ++ 3: 2.51, ++ 4: 1.6 ++} ++ ++COFF_KB = { ++ 0: 110, ++ 1: 72, ++ 2: 78, ++ 3: 126, ++ 4: 60 ++} ++ ++ ++class SetFanSpeedAction(ThermalPolicyActionBase): ++ """ ++ Base thermal action class to set speed for fans ++ """ ++ # JSON field definition ++ JSON_FIELD_SPEED = 'speed' ++ ++ def __init__(self): ++ """ ++ Constructor of SetFanSpeedAction ++ """ ++ self.default_speed = 50 ++ self.high_temp_speed = 100 ++ self.speed = self.default_speed ++ self.chassis = sonic_platform.platform.Platform().get_chassis() ++ ++ ++ def load_from_json(self, json_obj): ++ """ ++ Construct SetFanSpeedAction via JSON. JSON example: ++ { ++ "type": "fan.all.set_speed" ++ "speed": "100" ++ } ++ :param json_obj: A JSON object representing a SetFanSpeedAction action. ++ :return: ++ """ ++ if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj: ++ speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) ++ if speed < 0 or speed > 100: ++ raise ValueError( ++ 'SetFanSpeedAction invalid speed value {} in JSON policy file, valid value should be [0, 100]'. ++ format(speed)) ++ self.speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) ++ # else: ++ # raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. ++ # format(SetFanSpeedAction.JSON_FIELD_SPEED)) ++ ++ def get_chassis(self): ++ return self.chassis ++ ++ @classmethod ++ def set_all_fan_speed(cls, thermal_info_dict, speed): ++ from .thermal_infos import FanInfo ++ if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): ++ fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME] ++ for fan in fan_info_obj.get_presence_fans(): ++ fan.set_speed(int(speed)) ++ ++ @classmethod ++ def calc_fan_speed(cls, index, temp): ++ fan_speed = int((temp * COFF_KA[index] - COFF_KB[index])) ++ ++ if fan_speed < 30: ++ fan_speed = 30 ++ elif fan_speed > 100: ++ fan_speed = 100 ++ ++ return fan_speed ++ ++ @classmethod ++ def power_down(cls): ++ chassis = cls().get_chassis() ++ chassis.power_down() ++ ++ @classmethod ++ def get_temp(cls, thermal_info_dict): ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ return thermal_info_obj.get_temp_list() ++ ++@thermal_json_object('fan.all.set_speed') ++class SetAllFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) ++ ++ ++@thermal_json_object('fan.new.set_speed') ++class SetNewFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.default_speed) ++ time.sleep(8) ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) ++ ++ ++@thermal_json_object('switch.shutdown') ++class SwitchPolicyAction(ThermalPolicyActionBase): ++ """ ++ Base class for thermal action. Once all thermal conditions in a thermal policy are matched, ++ all predefined thermal action will be executed. ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Take action when thermal condition matches. For example, adjust speed of fan or shut ++ down the switch. ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ temp_info = thermal_info_obj.get_temp_dict() ++ for key in temp_info: ++ sonic_logger.log_warning( ++ "Temp is over high critical threshold, system shutdown {} temperature is {}".format(key, temp_info[key])) ++ import os ++ os.system('sync') ++ SetFanSpeedAction.power_down() ++ # import os ++ # os.system('reboot') ++ ++ ++@thermal_json_object('fan.set_speed') ++class SetAllFanSpeedAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and \ ++ isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): ++ ++ thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] ++ temp_info = thermal_info_obj.get_temp_dict() ++ temp_list = [] ++ for key in temp_info: ++ temp_list.append(temp_info[key]) ++ speed = 0 ++ for i in range(0, SENSORS_NUM): ++ if SetFanSpeedAction.calc_fan_speed(i, temp_list[SENSOR_INDEX[i]]) > speed: ++ speed = SetFanSpeedAction.calc_fan_speed(i, temp_list[SENSOR_INDEX[i]]) ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, speed) ++ ++@thermal_json_object('high_threshold.control') ++class ThermalOverHighThresholdAction(SetFanSpeedAction): ++ """ ++ Action to set speed for all fans ++ """ ++ ++ def execute(self, thermal_info_dict): ++ """ ++ Set speed for all fans ++ :param thermal_info_dict: A dictionary stores all thermal information. ++ :return: ++ """ ++ SetFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.high_temp_speed) +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_conditions.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_conditions.py +new file mode 100755 +index 000000000..66f92c720 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_conditions.py +@@ -0,0 +1,110 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++ ++ ++class ThermalCondition(ThermalPolicyConditionBase): ++ def get_thermal_info(self, thermal_info_dict): ++ from .thermal_infos import ThermalInfo ++ if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ++ ThermalInfo): ++ return thermal_info_dict[ThermalInfo.INFO_NAME] ++ else: ++ return None ++ ++ ++@thermal_json_object('thermal.over.high_threshold') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ if thermal_info_obj: ++ return thermal_info_obj.is_over_high_threshold() ++ else: ++ return False ++ ++ ++@thermal_json_object('thermal.over.high_critical_threshold') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ return thermal_info_obj.is_over_high_critical_threshold() if thermal_info_obj else False ++ ++ ++@thermal_json_object('thermal.over.threshold_after_cool_down') ++class ThermalOverHighCriticalCondition(ThermalCondition): ++ def is_match(self, thermal_info_dict): ++ thermal_info_obj = self.get_thermal_info(thermal_info_dict) ++ return thermal_info_obj.is_warm_up_and_over_high_threshold() if thermal_info_obj else False ++ ++ ++class FanCondition(ThermalPolicyConditionBase): ++ old_presence = True ++ interval_cnt = 0 ++ ++ def get_fan_info(self, thermal_info_dict): ++ from .thermal_infos import FanInfo ++ if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): ++ return thermal_info_dict[FanInfo.INFO_NAME] ++ else: ++ return None ++ ++ ++@thermal_json_object('fan.any.absence') ++class AnyFanAbsenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if len(fan_info_obj.get_absence_fans()) > 0: ++ self.old_presence = False ++ result = len(fan_info_obj.get_absence_fans()) == 1 if fan_info_obj else False ++ return result ++ ++ ++@thermal_json_object('fan.all.absence') ++class AllFanAbsenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if len(fan_info_obj.get_absence_fans()) > 0: ++ self.old_presence = False ++ return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False ++ ++ ++@thermal_json_object('fan.any.new') ++class AllFanNewCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ # Update status ++ self.all_presence = True ++ if len(fan_info_obj.get_absence_fans()) == 0: ++ self.all_presence = True ++ else: ++ self.all_presence = False ++ if self.all_presence == True and self.old_presence == False: ++ self.new_fan_insert = True ++ else: ++ self.new_fan_insert = False ++ self.old_presence = self.all_presence ++ return self.new_fan_insert if fan_info_obj else False ++ ++ ++@thermal_json_object('fan.all.presence') ++class AllFanPresenceCondition(FanCondition): ++ def is_match(self, thermal_info_dict): ++ fan_info_obj = self.get_fan_info(thermal_info_dict) ++ if not self.old_presence and len(fan_info_obj.get_absence_fans()) == 0: ++ self.old_presence = True ++ return False ++ elif not self.old_presence and len(fan_info_obj.get_absence_fans()) != 0: ++ self.old_presence = False ++ return False ++ else: ++ if len(fan_info_obj.get_absence_fans()) != 0: ++ self.old_presence = False ++ return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False ++ ++ ++class PsuCondition(ThermalPolicyConditionBase): ++ def get_psu_info(self, thermal_info_dict): ++ from .thermal_infos import PsuInfo ++ if PsuInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[PsuInfo.INFO_NAME], PsuInfo): ++ return thermal_info_dict[PsuInfo.INFO_NAME] ++ else: ++ return None +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_infos.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_infos.py +new file mode 100755 +index 000000000..94d7f3dfd +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_infos.py +@@ -0,0 +1,210 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase ++from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object ++ ++ ++@thermal_json_object('fan_info') ++class FanInfo(ThermalPolicyInfoBase): ++ """ ++ Fan information needed by thermal policy ++ """ ++ ++ # Fan information name ++ INFO_NAME = 'fan_info' ++ ++ def __init__(self): ++ self._absence_fans = set() ++ self._presence_fans = set() ++ self._fault_fans = set() ++ self._status_changed = False ++ ++ def collect(self, chassis): ++ """ ++ Collect absence and presence fans. ++ :param chassis: The chassis object ++ :return: ++ """ ++ self._status_changed = False ++ for fan in chassis.get_all_fans(): ++ status = fan.get_status() ++ if fan.get_presence() and fan not in self._presence_fans: ++ self._presence_fans.add(fan) ++ self._status_changed = True ++ if fan in self._absence_fans: ++ self._absence_fans.remove(fan) ++ elif not fan.get_presence() and fan not in self._absence_fans: ++ self._absence_fans.add(fan) ++ self._status_changed = True ++ if fan in self._presence_fans: ++ self._presence_fans.remove(fan) ++ ++ if not status and fan not in self._fault_fans: ++ self._fault_fans.add(fan) ++ self._status_changed = True ++ elif status and fan in self._fault_fans: ++ self._fault_fans.remove(fan) ++ self._status_changed = True ++ ++ def get_absence_fans(self): ++ """ ++ Retrieves absence fans ++ :return: A set of absence fans ++ """ ++ return self._absence_fans ++ ++ def get_presence_fans(self): ++ """ ++ Retrieves presence fans ++ :return: A set of presence fans ++ """ ++ return self._presence_fans ++ ++ def get_fault_fans(self): ++ """ ++ Retrieves fault fans ++ :return: A set of fault fans ++ """ ++ return self._fault_fans ++ ++ def is_status_changed(self): ++ """ ++ Retrieves if the status of fan information changed ++ :return: True if status changed else False ++ """ ++ return self._status_changed ++ ++ ++@thermal_json_object('thermal_info') ++class ThermalInfo(ThermalPolicyInfoBase): ++ """ ++ Thermal information needed by thermal policy ++ """ ++ ++ # Fan information name ++ INFO_NAME = 'thermal_info' ++ ++ def __init__(self): ++ self._state = ["N/A"] * 16 ++ self._enter_warm_up_state = [False] * 16 ++ self.init = False ++ self.normal_thres = False ++ self.high_thres = False ++ self.critical_high_thres = False ++ self.warm_up_thres = False ++ self._temp_dict = {} ++ ++ def collect(self, chassis): ++ """ ++ Collect thermal sensor temperature change status ++ :param chassis: The chassis object ++ :return: ++ """ ++ # self._cool_down_and_below_low_threshold = False ++ ++ # Calculate average temp within the device ++ num_of_thermals = chassis.get_num_thermals() ++ ++ # Initial the to default ++ self.normal_thres = False ++ self.high_thres = False ++ self.critical_high_thres = False ++ self.warm_up_thres = False ++ ++ # Collect the information ++ for index in range(num_of_thermals): ++ if not chassis.get_thermal(index).get_presence(): ++ continue ++ ++ # Store the temperature in the DB ++ name = chassis.get_thermal(index).get_name() ++ temp = chassis.get_thermal(index).get_temperature() ++ self._temp_dict[name] = temp ++ ++ # Get the threshold ++ normal_temp = chassis.get_thermal(index).get_high_threshold() ++ high_temp = chassis.get_thermal(index).get_caution2_threshold() ++ critical_high_temp = chassis.get_thermal(index).get_high_critical_threshold() ++ ++ # Check if the temperature is over the threshold ++ if temp < normal_temp: ++ self._state[index] = "n/a" ++ elif normal_temp <= temp < high_temp: ++ self._state[index] = "normal" ++ elif high_temp <= temp < critical_high_temp: ++ if self._state[index] == "high": ++ self._enter_warm_up_state[index] = True ++ self._state[index] = "high" ++ elif temp >= critical_high_temp: ++ self._state[index] = "critical" ++ ++ # Check the system status ++ if self._state[index] == "critical": ++ self.critical_high_thres = True ++ elif self._state[index] == "high": ++ self.high_thres = True ++ elif self._state[index] == "normal": ++ self.normal_thres = True ++ ++ if self._enter_warm_up_state[index]: ++ self.warm_up_thres = True ++ ++ def get_temp_dict(self): ++ return self._temp_dict ++ ++ def is_over_high_threshold(self): ++ """ ++ Retrieves if the temperature is over high threshold ++ :return: True if the temperature is over high threshold else False ++ """ ++ if self.high_thres and not self.critical_high_thres: ++ return True ++ return False ++ ++ def is_warm_up_and_over_high_threshold(self): ++ """ ++ Retrieves if the temperature is warm up and over high threshold ++ :return: True if the temperature is warm up and over high threshold else False ++ """ ++ ++ return self.warm_up_thres ++ ++ def is_over_high_critical_threshold(self): ++ """ ++ Retrieves if the temperature is over high critical threshold ++ :return: True if the temperature is over high critical threshold else False ++ """ ++ return self.critical_high_thres ++ ++ def is_over_normal_threshold(self): ++ """ ++ Retrieves if the temperature is over high critical threshold ++ :return: True if the temperature is over high critical threshold else False ++ """ ++ if self.normal_thres and not self.critical_high_thres and not self.high_thres: ++ return True ++ return False ++ ++ ++@thermal_json_object('chassis_info') ++class ChassisInfo(ThermalPolicyInfoBase): ++ """ ++ Chassis information needed by thermal policy ++ """ ++ INFO_NAME = 'chassis_info' ++ ++ def __init__(self): ++ self._chassis = None ++ ++ def collect(self, chassis): ++ """ ++ Collect platform chassis. ++ :param chassis: The chassis object ++ :return: ++ """ ++ self._chassis = chassis ++ ++ def get_chassis(self): ++ """ ++ Retrieves platform chassis object ++ :return: A platform chassis object. ++ """ ++ return self._chassis +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_manager.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_manager.py +new file mode 100755 +index 000000000..3fe0942bd +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/thermal_manager.py +@@ -0,0 +1,10 @@ ++from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase ++from .thermal_actions import * ++from .thermal_conditions import * ++from .thermal_infos import * ++ ++ ++class ThermalManager(ThermalManagerBase): ++ @classmethod ++ def initialize(cls): ++ pass +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/watchdog.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/watchdog.py +new file mode 100644 +index 000000000..4193dee09 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/sonic_platform/watchdog.py +@@ -0,0 +1,199 @@ ++""" ++Module contains an implementation of SONiC Platform Base API and ++provides access to hardware watchdog ++""" ++ ++import os ++import fcntl ++import array ++ ++from sonic_platform_base.watchdog_base import WatchdogBase ++from sonic_py_common import logger ++ ++""" ioctl constants """ ++IO_READ = 0x80000000 ++IO_SIZE_INT = 0x00040000 ++IO_READ_WRITE = 0xC0000000 ++IO_TYPE_WATCHDOG = ord('W') << 8 ++ ++WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG ++WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG ++ ++""" Watchdog ioctl commands """ ++WDIOC_SETOPTIONS = 4 | WDR_INT ++WDIOC_KEEPALIVE = 5 | WDR_INT ++WDIOC_SETTIMEOUT = 6 | WDWR_INT ++WDIOC_GETTIMEOUT = 7 | WDR_INT ++WDIOC_GETTIMELEFT = 10 | WDR_INT ++ ++""" Watchdog status constants """ ++WDIOS_DISABLECARD = 0x0001 ++WDIOS_ENABLECARD = 0x0002 ++ ++""" watchdog sysfs """ ++WD_SYSFS_PATH = "/sys/class/watchdog/{}/" ++WD_DEV_PATH = "/dev/{}" ++ ++WD_COMMON_ERROR = -1 ++ ++sonic_logger = logger.Logger() ++ ++ ++class WatchdogImplBase(WatchdogBase): ++ """ ++ Base class that implements common logic for interacting ++ with watchdog using ioctl commands ++ """ ++ ++ def __init__(self, wd_device_path): ++ """ ++ Open a watchdog handle ++ @param wd_device_path Path to watchdog device ++ """ ++ ++ self.watchdog_path = WD_DEV_PATH.format(wd_device_path) ++ self.watchdog_sysfs_path = WD_SYSFS_PATH.format(wd_device_path) ++ ++ # Opening a watchdog descriptor starts ++ # watchdog timer; by default it should be stopped ++ #self._disablewatchdog() ++ ++ self.timeout = self._gettimeout() ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def disarm(self): ++ """ ++ Disarm the hardware watchdog ++ ++ Returns: ++ A boolean, True if watchdog is disarmed successfully, False ++ if not ++ """ ++ sonic_logger.log_info(" Debug disarm watchdog ") ++ ++ try: ++ self._disablewatchdog() ++ except IOError: ++ return False ++ ++ return True ++ ++ def _disablewatchdog(self): ++ """ ++ Turn off the watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('h', [WDIOS_DISABLECARD]) ++ fcntl.ioctl(watchdog, WDIOC_SETOPTIONS, req, False) ++ os.close(watchdog) ++ ++ def _settimeout(self, seconds): ++ """ ++ Set watchdog timer timeout ++ @param seconds - timeout in seconds ++ @return is the actual set timeout ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('I', [seconds]) ++ fcntl.ioctl(watchdog, WDIOC_SETTIMEOUT, req, True) ++ os.close(watchdog) ++ ++ return int(req[0]) ++ ++ def _gettimeout(self): ++ """ ++ Get watchdog timeout ++ @return watchdog timeout ++ """ ++ ++ timeout_path = self.watchdog_sysfs_path + "timeout" ++ timeout = self.__read_txt_file(timeout_path) ++ return int(timeout) ++ ++ def _gettimeleft(self): ++ """ ++ Get time left before watchdog timer expires ++ @return time left in seconds ++ """ ++ ++ timeleft_path = self.watchdog_sysfs_path + "timeleft" ++ timeleft = self.__read_txt_file(timeleft_path) ++ return int(timeleft) ++ ++ ++ def arm(self, seconds): ++ """ ++ Implements arm WatchdogBase API ++ """ ++ sonic_logger.log_info(" Debug arm watchdog4 ") ++ ret = WD_COMMON_ERROR ++ if seconds < 0: ++ return ret ++ ++ try: ++ if self.timeout != seconds: ++ self.timeout = self._settimeout(seconds) ++ if self.is_armed(): ++ self._keepalive() ++ else: ++ sonic_logger.log_info(" Debug arm watchdog5 ") ++ self._enablewatchdog() ++ self._keepalive() ++ ret = self.timeout ++ except IOError: ++ pass ++ ++ return ret ++ ++ def _enablewatchdog(self): ++ """ ++ Turn on the watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ req = array.array('h', [WDIOS_ENABLECARD]) ++ fcntl.ioctl(watchdog, WDIOC_SETOPTIONS, req, False) ++ os.close(watchdog) ++ ++ def _keepalive(self): ++ """ ++ Keep alive watchdog timer ++ """ ++ ++ watchdog = os.open(self.watchdog_path, os.O_WRONLY) ++ fcntl.ioctl(watchdog, WDIOC_KEEPALIVE) ++ os.close(watchdog) ++ ++ def is_armed(self): ++ """ ++ Implements is_armed WatchdogBase API ++ """ ++ state_path = self.watchdog_sysfs_path + "state" ++ state = self.__read_txt_file(state_path) ++ return state == "active" ++ ++ def get_remaining_time(self): ++ """ ++ Implements get_remaining_time WatchdogBase API ++ """ ++ ++ timeleft = WD_COMMON_ERROR ++ ++ if self.is_armed(): ++ try: ++ timeleft = self._gettimeleft() ++ except IOError: ++ pass ++ ++ return timeleft ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p-oob-led.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p-oob-led.sh +new file mode 100755 +index 000000000..975fb275f +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p-oob-led.sh +@@ -0,0 +1,103 @@ ++#!/bin/bash ++ ++COPPER_TYPE=0 ++FIBER_TYPE=1 ++ ++currMediaType=0 ++ ++RET=-1 ++ ++set_led() ++{ ++ if [ $1 -eq $COPPER_TYPE ]; then ++ a=0; b=1 ++ else ++ a=1; b=0 ++ fi ++ ++ echo $a > /sys/class/gpio/gpio498/value; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 1; fi ++ ++ echo $b > /sys/class/gpio/gpio499/value; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 2; fi ++} ++ ++init() ++{ ++ # init oob port led ++ phytool write eth0/0/22 3; ++ phytool write eth0/0/17 0x44a5; ++ phytool write eth0/0/22 3; ++ phytool write eth0/0/16 0x0240; ++ phytool write eth0/0/22 0 ++ ++ # set rj port sgmii amplitude ++ phytool write eth0/0/22 2; ++ phytool write eth0/0/26 0x8004; ++ phytool write eth0/0/22 0 ++ ++ echo 496 > /sys/class/gpio/export ++ echo out > /sys/class/gpio/gpio496/direction ++ for k in $(seq 498 499); do ++ echo $k > /sys/class/gpio/export ++ echo out > /sys/class/gpio/gpio$k/direction ++ done ++ ++ # default set sfp txdisable to off ++ echo 0 > /sys/class/gpio/gpio496/value ++ ++ # default set to copper port mode ++ currMediaType=$COPPER_TYPE ++ set_led $COPPER_TYPE ++ ++ # Disable fiber Auto-Negotiation ++ phytool write eth0/0/22 1; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 3; fi ++ ethtool -s eth0 autoneg off speed 1000 duplex full; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 4; fi ++ #echo "Disable fiber Auto-Negotiation" ++ ++ # Set auto select mode - Prefer fiber medium ++ phytool write eth0/0/22 2; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 5; fi ++ phytool write eth0/0/16 0x508; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 6; fi ++ #echo "Set auto select mode - Prefer fiber medium" ++ ++ # Enable auto medium register selection ++ phytool write eth0/0/22 0x8000; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 7; fi ++ #echo "Enable auto medium register selection" ++} ++ ++do_task() ++{ ++ while true; do ++ regVal=`phytool read eth0/0/22`; RET=`echo $?` ++ if [ $RET -ne 0 ]; then exit 8; fi ++ ++ type=$((regVal & 0x1)) ++ ++ if [ $type -ne $currMediaType ]; then ++ if [ $type -eq $COPPER_TYPE ]; then ++ set_led $COPPER_TYPE ++ #echo "set led to copper mode" ++ else ++ set_led $FIBER_TYPE ++ #echo "set led to fiber mode" ++ fi ++ ++ currMediaType=$type ++ fi ++ ++ sleep 2 ++ done ++} ++ ++main() ++{ ++ init ++ do_task ++} ++ ++main +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p_led.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p_led.py +new file mode 100755 +index 000000000..c474c25cf +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/es2227_54ts_p_led.py +@@ -0,0 +1,103 @@ ++#!/usr/bin/env python ++# ++# Copyright (C) 2023 Wistron Corporation ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++try: ++ import sys ++ import subprocess ++ import os ++ import time ++except ImportError as e: ++ raise ImportError('%s - required module not found' % str(e)) ++ ++# Deafults ++VERSION = '1.0' ++NUM_POE_PORT = 48 ++POE_PORT_FAILED_STATUS_CMD = "poetool port get_port_status {0}" ++POE_ALL_PORT_POWER_STATUS_CMD = "poetool port get_all_ports_power_state" ++POE_PORT_STATUS_GROUP = [1,2,3,4,5,6] ++POE_LED_BLINKING = 2 ++POE_LED_ENABLE = 1 ++POE_LED_DISABLE = 0 ++ ++LED_STATE = [0] * 48 ++ ++#need to define all failed value and then parse it ++#POE_PORT_FAILED_STATUS_CODE = [0x7, 0x8, 0xc, 0x11, 0x12, 0x1c, 0x1e, 0x1f, 0x20, 0x21, 0x24, 0x25, 0x26, 0x36, 0x43, 0x44, 0x45, 0xa0, 0xa7] ++POE_PORT_FAILED_STATUS_CODE = [0x7, 0x8, 0xc, 0x11, 0x12, 0x1e, 0x1f, 0x20, 0x21, 0x24, 0x25, 0x26, 0x36, 0x43, 0x44, 0x45, 0xa0, 0xa7] ++ ++class poe_led_monitor(object): ++ def __init__(self): ++ for port in range(0, NUM_POE_PORT): ++ self.set_led(port, POE_LED_DISABLE) ++ LED_STATE[port] = POE_LED_DISABLE ++ ++ def update_port_led(self): ++ poestatus = subprocess.getoutput(POE_ALL_PORT_POWER_STATUS_CMD) ++ power_status = [] ++ ++ for i in POE_PORT_STATUS_GROUP: ++ power_status.append(hex(int(poestatus.split("\n\n")[i].split(" ")[1]))) ++ ++ for port in range(0, NUM_POE_PORT): ++ if ( int(power_status[(port // 8)],base=16) & (0x1 << (port - (8 * (port // 8)))) ): ++ st = POE_LED_ENABLE ++ else: ++ st = POE_LED_DISABLE ++ ++ if LED_STATE[port] != st: ++ self.set_led(port, st) ++ LED_STATE[port] = st ++ ++ def chk_port_fault(self, start_port, num_port): ++ for port in range(start_port, start_port + num_port): ++ poefailedstatus = subprocess.getoutput(POE_PORT_FAILED_STATUS_CMD.format(port)) ++ failed_code = poefailedstatus.split("\n\n")[1].split(" ")[1] ++ if int(failed_code) in POE_PORT_FAILED_STATUS_CODE: ++ if LED_STATE[port] != POE_LED_BLINKING: ++ self.set_led(port, POE_LED_BLINKING) ++ LED_STATE[port] = POE_LED_BLINKING ++ ++ def __write_txt_file(self, file_path, data): ++ try: ++ with open(file_path, 'w') as fd: ++ fd.write(data) ++ except IOError: ++ pass ++ return None ++ ++ def set_led(self, port, state): ++ path= "/sys/bus/i2c/devices/0-0033/port{}_poe_led".format(port+1) ++ self.__write_txt_file(path, str(state)) ++ ++def main(): ++ monitor = poe_led_monitor() ++ port_cnt = 0 ++ ++ # Loop forever: ++ while True: ++ time.sleep(1.5) ++ monitor.update_port_led() ++ monitor.chk_port_fault(port_cnt, 8) ++ port_cnt += 8 ++ if port_cnt == 48: ++ port_cnt = 0 ++ ++ #workaround for poe temperature ++ os.system("poetool device get_dev_status 0 | grep temperature | awk '{printf $2}' > /tmp/poe_temp; docker cp /tmp/poe_temp pmon:/") ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/get-base-mac.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/get-base-mac.py +new file mode 100644 +index 000000000..fe271d04a +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/get-base-mac.py +@@ -0,0 +1,20 @@ ++#!/usr/bin/env python ++ ++def main(): ++ try: ++ import sonic_platform.platform ++ import sonic_platform.chassis ++ except ImportError, e: ++ raise ImportError (str(e) + "- required module not found") ++ ++ chassis = sonic_platform.platform.Platform().get_chassis() ++ if chassis is None: ++ print "DEBUG chassis was None " ++ ++ base_mac = chassis.get_base_mac() ++ print base_mac ++ ++ return ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/phytool b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/phytool +new file mode 100755 +index 0000000000000000000000000000000000000000..2a34c41e6fd4ae17ab3132328282c419236b9383 +GIT binary patch +literal 24440 +zcmeHv3wRXAm2ORs5O@$mNCIIXp#=sDfgWJ-FlNo@fdw(fM98u4nyjX!8A)S}X2i@0 +zBtzoi;m5u4cTGp)k!%3Pb`mt3yXM<~12&t;IGZ?ek|hQ^B=KV;jF)V@2@cq3Z1C)V +z>LIlTQ-V%-XXnrUDnSktOT(fb}7~hCX$3<>8 +z4cByBlW|SKMJX3oIXOrQ0Inzhfno5XVes9MucIzG{S3hMd35A3Hx|Vj-gu+H$Q%zlCQ%$|$^|6-La9yJj +zWJYZu7$&lCph;vtR^Q+Whp2%6!RZMG{ec=^pw0+;1AgG{Kx>%QlLY>6h}GBm0wIrJ +zZ}l-F)Drai!}UZ8X66mlg?-FhUqhOO175$|(*{mKQ&UsdX4KSs{f5u`poi55T0DNC +zcwKV~TBrV!^1*OTv*AVae#uCEX4K!H(Ol#8Z1S0is3d^0AHnWtmE2a?#9w#XZHZ3WP>caRpI(kUZ28Tl1I>M +z1N3U&VV8^1Nm@vd&dYs?!XpyDkc7KvkwNND!jI+({KB0=F(qfc+)wl;;Y|`}a$lq9 +z+ax|F3EwX9j3j)H#3v`=B@)+@@MRLuOTt%4yf_JeccJLlk|g|Ni93_;Bs@pr +zYm@M2q@4Sb@E(b~lJH+hyfF#?t;AcB@OFu}CE<@qJd%WWNc^!Ryi4K-?;bk7`aEHu +zSQ6efSK#N9aT#34$bEzwcU7L8ggX}qIeHTQ`XqtpCE=%O6NglsgnySdMo3GN@Rd@& +zGYNlO%3qm;KSmoyq_s(S+8lvLlJGOMp+uT|?@+sC(?$|$NfN$;Hl|32q}^8J&_?rVE2xY}3_+aZB?~UM{v1DP!L9v0W5H=(tWwN^tGzSTowwj>-%a=h3r_oKmHI8X+Mn|} +z*v|8|%Ef`Gtc$_L|qI;sWrU$R_-C +zWjy1=Qd8HazcyXBzp5@?_cy5P6Lq{?i?Vhbr{(2(lxJAV51?FTDf>~bwUmP>Z?lv) +zqWq+#{28f|%G)gE-6%h4DSsX1 +z6PEIRl>02@CsEe^YOwupqddb>j-p&D>K4B^U0OdYQ +z`2@<^?St+A808t3^3PB%vy^{{a;+#|-TWN)gNy5I-5nVB_wU!bKd`g>_wBZ*>yMT3 +z%XRi{8*|2ci&)&oBCkY1!}=@ZlYw>NF-o?JnV0P>x>a+=OKt4PrCMgbmC80euCeM6 +z_~Loyu_tDq9Q`)(o{tkHo!glCULujRHI-;0RTtNlcE5jrS@#9B +zf4Q!_`|9Q&A7t>s@1q`(_GIqyF=ou36WvYxDQw|e4z|I-W1tf7V*Y1;V7HkwaKGIF +zo$ZsNUC3Q*`D>TZCu|@~BBXz;60)3e26=4nXmcH8U4RZT(C^V$XD?_YR}*xkJ;~D2 +z%>$@U?n_TRaU^EX&R6;>U1=V1Jx>Zfec+8~&@-KF__q%e)x+uM{3x+dgWhE0u5@QS +zAAF<->C^$85KA^(8hv2Oo6wWXKQH80gDz$hc8Fb0Tx0XdrNohM!UoVanyhPy#@WqdnqS$Cl_z61G=)0OcXp-Ue1 +zmu!5#GVa89PlFt?iHaXx@EPXP&2J*lMZTP|KlEVywt^@3Ol8~v4~;#IIq@aa=Q8&4 +zj4KbFDoxw^mE0?(9WQ_$&m=CCU8#)Ma$aqKm)g9#`3J(k$FlhM(59=_b*mHhija=4 +zSH_Va=53@n!@irHaf9X{v;C|TeR>XbYP_#*{wLlCt1T{) +zkCP2Bmq&}aaEQfnyH5T)nv7guIwNE8l99;pC+%dFyX8&)HKUD;2U* +zAuAQKQll?lSJtrsn|4Ak8Y>x#qGa0$`pDzZViAX2na*REr?U8EyO!U>`WKaA%xM0^ +z?6&*^knhT5$3md#(E1mjMNH7N$SV{NVs?ARkueQpcen=iv1gp^7^C)n_y@O>jANIl +zk`Mhv+JDe*sE-%XudR?r{e0i9ML&RUR{z2Lk5V7|Y>`(;?{>6v8GV6#*fA$c{ndq@ +z(b!CikIq{S`1Yw8tbLcA9aixqW}g_H1Uj~iW%kTw?F@X_BWEu^kJxEr)k+piVP+cW +zdLb(pvbHj|Fe^JNKU6kh!5`2snitf6^0lqf*FbZ4I(TA<1698Vjq*9sZ{>IYI54(Z +zm=mFAM`0e=qhfq*=t~yHSd0GtDq_0E;=0BT69zqBc^eq)8t=jUQP^9+;Q#MMfX5IM +z@xXY3YWM2q7v)|iQuUG4Igb45=I?PG&YrcIw5IKa{e|6au)CIT`%`6{*1&jEN;e;a +z1~G?wpR$>KFWStH<}!#$?M^Ib@t9_Hj^$m(st +z`hu9LW8K3uhQqHx=NSBk!B)=EtmNWbcXW$!of!Sdu9@-Wv|gdlsP98=qu6nL6vldL +z^!woL-HvfD2My{!q;&!JZvg)gYv2IAGnLc-9np6PdWvb}$3*`t;2}F(_-l-rkWchE +z(HDU;tWmKB=P~AF6JiaBHKSM0(X+8;IwvgXfu<$?g-QD^Mo;Jc|5#schk;+vFaE_cJ?c0zaU!KfHkUJJXq& +z19>=eWp}1B6YGeu$#JqtcJvWRn~Qx>XC`Ph5wB>yr}}!-N9?eH#>RdyX;OX+{_q;+ +z-LtSg{Cr?8KdI!pMsvB<;G-DD_1+?|CfU~3j}q0LQg|a0Dt=)P7H_KP{%9`6v0n^{V-#1_zVVV=|K87Ham?lX#6xy5 +zkK|g|i?uH?6S3?pGq0enAHp|!F?Vw@cd-X(@?q|rg&ks}%e(t#I^#z`lf15Nh2N&2 +zZ?x{woaQ=akzOj!493?E%x_w2u^#Ysnf8O$*vj>UPQ9=J?GF)OuDdt<`4zDrNY*8n +z;t}e|Kgn0NVbA7-99oyj=V||Rt$u@Xkm5hZ{>0s^o$Hk&qb+gc62HNPYVeP%o +zGxH+$MsgkDdt}v~*e4?nxzHxs`#t1xd3;|a;;eNqM19iIoZT$Ld8}`|y_L5*f_L)6%%^7Fv`nTb{@;2Jl5Oc~7jS{iPc>{bREB{Hf +zf%S)`e@Q|10RZ4YoRqb+r_{2KI1>Q-@bkKhclxp#CiMr1qifA*t&j_R&O6>XbkoJ`?3E#w+ +zM9+0F^Xzs;V{(X9J5-!GnT>MiKa4VIKGs5hpPV;+h#d>jey_b^4&CDygF9`AvC}Kq +zhFr$(%sqsC0?CRv%(+B|IpYGqj`i6IpZX(oB3%dPiSQ?7Z;EqS@JF)AS=f`y+UYP6 +z_b24=cC!UGZ>;%C*x1k}&||Pe%r(}GlFd^hRTDvHXqf`vGS=k&34A=qvjpBb*4!`Y +zZ{T>gz`r}z+$(WA$0rKBXRL`>&gEZ49}I1hz)z1gAD8%Lj^_xxf2{ckaPp7$fcIhz +z<$6v_GrNEr+GIgjl4fp^{QtuFrwZJaW^R;tFUO||d~cfBBJtmG{4)aod7Alv#9!t3 +zX9dp2nQn>yGsmY3JbRq^HxmCT$NA5chgk7A^FH9Dw-~1r2Va0cQ9PT@vV!z1Yq+tZ +zF`~WR7r?tKEmHNWwhQ~UDM9w7NYxQ7BK+d~x;b0oCdcJ?^`x7+#J|FEIbN}JbBe?t=J<`$PUFpN +z;5Z-VKLmV0@3rI2LZXN7kv$&L+WySi#?d;**Yq;?II}Dx@^wDujpI#v)OS;e*g=j8d +zpHK0V&huqXX8sBDUadhCTkhfGIXJi2O=H%Pu6QA2A?Wa!AGB$_-u|(5w>s3 +zFlm26@^y~Ox$#(r`HaM;a9qxfLm6f_aPr-3;MTEvk?8q2ZTvI!Q;k*fIDPz~g|97> +zw{N7&xp5`~@lmaZFCM)3VIt?qmu*v73j6%uTkNgusA3tn-@6&uYiH$`q+yO=Ja!@O +zA30HE_F3D5jlTvx4Ncm`H^FR`{fvQbAm%(h!3;?Jw;Y$gdUAs4mH26nOFObmvko}f +z<(Jm>iZjhG0e3B0eX8q0SN|Ssoh#Gah&p5T%2Qop|D`V5r|}+c0da{Fm%VbL1k{e6>!} +zS%LN(Pg(XHSW6FwemV0iwPnuulY@JX!F62E;y(N^+NZVI+8)g>@)z27(0&fj+)k=z +zwr^wK;gS1}i}F1EZR{W3!L!;_>^(+d&yhOK*)5)v*vxa-cZ|ZmzBAD-bFkjtMfVc$CwdeRz8^ECDy+OOqA +zp9d|C<9gKnQLXKWE#f)AkL9^x@EMQTUoid*pcQS&(5)-3pUNV~h;fbalHY9m3AjZ8kN<2sJLqA>Ur<0ze_w#4Z +zL!Rfxab}|DOiz5A$kEnpuUgKuCYm;O}ISRTST3HmMH#5R;64wSJ2U#C6YS=mn)jpuvA_w#nNq2!gZH2xcc +zC{HoT|H@dZ`7Ux@%_s6jI?GBs(Y%_@pAR1&csA7uAM1Q_F4jb?o5#UzbInd|;>+}V +z2>BIQ!G{G+LKkn6n48tUu%?64iW8 +zOC7Fm{t=%K#7BCl-{REoaP+RrJt3pPvs9lI(t{qut?R4rE-$TKb@!U0suh(ET_jX) +z3VOqyA(i^F;)3F~dZgPebo||-0lNE1$``MxUUf%l`3lFTM!Xv2aHt0LrGKUKilSvL +zcmZikOJn=(`WC%n#TSZ}l~z<#5wK +zagBQl524Y$u7eJ({v;P2q?Ar7-BCGC`GN)TzVecV4!Rrg9P$l-Lx80NUiX){5xk(d +zsCeluMe{8VBD_dcwHZal~~eHx?6V#y&FBj +zkREDn;Z_&J4Ery2dp3IOJTAT5XS9YqIyxdp#8DpzHXC7#)`(aB$6i^)ibCz7qB@@u +z3KjW1;i6d~a@|l(XpM+yOeC}XvqDQ}`RR5j2gxkEYh6`d +zaa-~HIaa}SMvGDF^?AcyPl(MgE-t7o;aNTZw-Nsq&}{+T6&HjT@DjgiWc5CyA;dgw +z;R3w!8g30S!|!P*KzKnE4SQJ7(~Rj-P;a#Q!m^4Q!waeS`-dj>fKglP337H70a<;k +z&&L`KU;XveFX!qP4^bZh4sR9v0)duVyfG|V@%VWoErCs*V1XN9k$FP_p8<`yeqf;& +zbXi@%=ktaTZ41IcSg6J0akE+Of>|MMZj6l>i?!>>YD1fCp&4D^@v~+GeY&S1EpVgP +zbzz2)WZ^b}yJ4ijrh>X~(8p%Y6azUZxtt`I4DAr&J=AW5%fL9^hUS)nkRRP+8+`^e +zZT0&-J{C3_3cU3NwSjOW^E6P9FK7<9@jf!%F7}99uOCBd_-IK|B+w+_4)NK*2h2l8 +z9#G~Qmuud*WQk`{G2TU$cegGcxLYXi<}Xoqw=7(sCdJy7|3hzX#bSkJ$)KpNBN8s< +z!Lh~g2C>epxpU3k_pZs~zCDLbw{(`6rIahBs7LVs5a*ud#;(c1ii_vzZf}Uj*UgIO +z&(mu$Gn=rw!aL_-y)=S;UO)|I>L$D{O-0V-@we;ulI3nCtHLa8C|#Zj1mHeQ$tsuUaeb!Aupib%jvNehT(J&Q-Cllr!K(@Qq#?Uuq5u +zkSC~z+gm(3)e}prAD#Esdu1nE{gB##0(DZ|f|Hy-xDmK*s{Jy6FZ17Jb-+_D#4jq^9P^koY#e0c_3waOn$B}QrL+0biGu}@m +zGVpTgPUIExCDRP3LCN-D6-#ORtZi!AbpCGnWMJ#xfE{?Pc;9>;?%RMZlbDX&iR)=# +zE0MF(bbVjSetTJmw&u+@PVv`I@tm5uah(JWR2@ipxZ8s3IPjx{mZq=W=h%NkS;v^p +z(Pg_*caLg(^Nm+uJ9QdTbW|V2wG!j87P+OJwW=K*@Xv9DL9-gUh30NWL;7F9^$pOx +zEofTyrSBhC){)jZwtSak_YEuejCtVAH-0VKC3+p>x)$TzFX#t#tRNjL_oM`d(ys;m +zWcb4lL0`Ntb^oZcj+9P&#V&2P?H-5fR4INSB|DNo`9Qy#{Gl}cq;21n{Wq5H$=;h) +zwrkSviFbBP?#%gG=GQ0uZHD&3n{WK?H^2S$8L6H4+piw*x1CKS_FD8SCmTY)FQPFr +z;7zDI54!W9>$1>sTd&%cdcUO8QI`S#bm2#lYxIXOl0`Hnpy>gP91GsZ6&)#eDLYep +z_kreJ&^(6wA!ECGS8A1PkN6{?+kqd6ry&QOYhT*_v1J{O&Kt^hjoCfAVo&PcQ7#xw +z^}2NI1D{ZW2x|K@Wc8!%7TjC>pp%=QIsxMo-4)O|@q_SbqAL^rS3$O0xhu6^>R61b +zn=m%-f-XXIrRjrXTE0uGq7fA`?~r%gM)!ed3FiCb7M@D-gTEGbr1rOfrVBI&F*Zui +ziVm&Qrnvi9))b1g#VCqY?K?Cgx+O?Q>96 +z=(%d(4kRQ$B?a>aJS{>G(Z5|9cUx`UU(bkI2uJEhN@W2dmtxlI +zh*>nx6)hJEyYZPI$AaeBW1yXfxOSXq%Y+|PkRPlhKiHG%8k}Z~{N^a>0s5W7Z<6M5 +z<(@HnM}I9TkktqK6eoH;N43 +z`4S9MWqFLu>19ev>N^|LM3H~fiEh>Nf;M`7f%N{zi2&s;JinoY#|k{<$v=Wu-vq$l +zaPZ_189OBPRe$47&uuA5Hxvc@E7@3=`a5@7b5yoZ&uJ;Czq!v5MHZ7CS9qKJ*nsM1 +zqwI);`M0!)Rp}wcF#HV??;q6VtRKsAo@7kOvQ&rR?@&4Y8QBot`Qqi9mB3FaKa?RF +z`u{!O$saD_IivLNztp_y`yXBOX6Pp*_1zDQcY?^&_deA3J=FI+)b~5o_c|V*B!sH( +zaj5Tad_q%0s?>KmhJYw2J(BT}@~2~g5&M5Sb{?*k5&I8knNJ5FvHz!I=TB;dwlM#< +z#zB1-YB>GW_o0TX|9>7Y3^mf%35{A-i1)la!4_8N$2(AkrDdxM@Ztt5Z1A@hHX5Nu +zR_Jc`huWJ(jxQJT8hVkCzFKH4)Sxct@fpM*?^^Ia736#IZy0Z1u|j;1(2Kf&+Xx%1 +z(9>AMUj(XYbc0uw1V@b#3>xi%L){Y>H30!!9i!P>2NePkECkkuLjN@*L;HH#;;Vh} +z5_zL?b?#8D$>V@3^6$mc-d*w2dnuGuuJh91Kk8hfkXg8)vxwqX=M|NomxSuPqRs_M +zPA=*{z}{W)tMiS@)ww8{Uy5aOaYHsx{ObIp@`LhVL+2y9Rqd+J +z8BfXfyA3E}!+`$kJfiY7l27Tc+EMvR)YDlUTKx)&GOQt_+v +zm&(=oOSP}~RsRjiUxu8LI?t*6s1!{6w8c*5ZvsX(QRmOS@;sz+b#4R+Piov%xgIxG +z{^WDig(QPZ@%$YmlCdF)U!5;hzC#_vi5N-oixOj-aAR#>o!?cSOrNa(mn6Tke~COF +zseHXUh|30(`5#W=PyXJv`o6YgA9yaH%J}=BA@hIlVo{^=YBlhZL5-i{--jD|5lfx_ +z)$gIy)B8%4lz%FIHLfqC&f30u{?R2Tu4|a~m7J4F{EWZ&0&p!Zq{)g<6tA(z +mYru&_^?&kxqQS}c35J!DPi0B!4AEWDP_FoYX9aPe%>VBN4lDuy + +literal 0 +HcmV?d00001 + +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_init.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_init.py +new file mode 100755 +index 000000000..f783e8849 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_init.py +@@ -0,0 +1,370 @@ ++#!/usr/bin/env python ++ ++import os ++import subprocess # James ++import json ++import time ++import sonic_platform ++from sonic_py_common import logger ++from swsscommon.swsscommon import ConfigDBConnector ++import utilities_common.cli as clicommon ++ ++SYSLOG_IDENTIFIER = "poecfg" ++log = logger.Logger(SYSLOG_IDENTIFIER) ++ ++ ++def get_priority_value(priority): # James ++ priority_mapping = { ++ "critical": "1", ++ "high": "2", ++ "low": "3", ++ "0xff": "0xff" # 0xff means don't change the setting ++ } ++ return priority_mapping.get(priority, None) ++ ++ ++def parse_keyword(keyword, string): # James ++ if string: ++ # Parse the value of keyword from the string ++ index = string.find(keyword) ++ if index != -1: ++ start_index = index + len(keyword) ++ end_index = string.find("\n", start_index) ++ result = string[start_index:end_index].strip() ++ # click.echo("result: {}\n".format(result)) ++ else: ++ log.log_error("Unable to find the result in the output.") ++ return None ++ ++ # click.echo("string: {}\n".format(string.strip())) ++ return result ++ else: ++ return None ++ ++ ++def run_command(command): # James ++ try: ++ output = subprocess.check_output(command.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # command, shell=True, stderr=subprocess.DEVNULL, universal_newlines=True) ++ # return output.strip() ++ except subprocess.CalledProcessError as e: ++ print("Command failed:") ++ print(e.output) ++ return None, None ++ ++ if output: ++ # Parse the value of "result" from the output ++ keyword = "result " ++ index = output.find(keyword) ++ if index != -1: ++ start_index = index + len(keyword) ++ end_index = output.find("\n", start_index) ++ result = output[start_index:end_index].strip() ++ # click.echo("result: {}\n".format(result)) ++ else: ++ log.log_error("Unable to find the result in the output.") ++ return None, None ++ ++ # click.echo("output: {}\n".format(output.strip())) ++ return result, output.strip() ++ ++ ++def run_lldpcli_config_port_command(interface, enabled): ++ # lldpcli configure port Etherent40 dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority low requested 28000 allocated 15000 ++ ++ cmd = "lldpcli configure port %s dot3 power pse supported %s powerpairs signal class class-4" % ( ++ interface, enabled) ++ # print(cmd) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ return result.strip() ++ except subprocess.CalledProcessError as e: ++ log.log_error("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++ ++def run_lldpcli_show_port_command(interface): ++ # lldpcli configure port Etherent40 dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority low requested 28000 allocated 15000 ++ ++ cmd = "lldpcli show in port %s de" % (interface) ++ # print(cmd) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ return result.strip() ++ except subprocess.CalledProcessError as e: ++ log.log_error("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++ ++def power(): ++ ++ VOLTAGE_110V_MIN = 90 ++ VOLTAGE_110V_MAX = 132 ++ VOLTAGE_220V_MIN = 180 ++ VOLTAGE_220V_MAX = 264 ++ VOLTAGE_110_1_VALUE = 810 # 110V for one bank ++ VOLTAGE_110_2_VALUE = 1810 # 110V for two banks ++ VOLTAGE_220_1_VALUE = 1410 # 220V for one bank ++ VOLTAGE_220_2_VALUE = 2400 # 220V for two banks ++ ++ POWER_BANK_1 = 0X1 ++ POWER_BANK_2 = 0X2 ++ POWER_BANK_3 = 0X3 ++ ++ platform_chassis = None ++ try: ++ platform_chassis = sonic_platform.platform.Platform().get_chassis() ++ except Exception as e: ++ log.log_error( ++ "Failed to instantiate Chassis due to {}".format(repr(e))) ++ ++ if not platform_chassis: ++ log.log_error("no platform_chassis") ++ return False ++ ++ psu_list = platform_chassis.get_all_psus() ++ psu_count = 0 # Count PSU number when two PSUs are existing, need to set bank 3 ++ psu_110v_count = 0 # Check if any 110V PSU in the system. If any 110V PSU, then the power value of bank 3 follows 110V's value ++ ++ for psu in psu_list: ++ if psu.get_presence(): ++ try: ++ name = psu.get_name() ++ voltage = psu.get_voltage_vin() ++ # log.log_error("{}- voltage: {}".format(psu, voltage)) ++ # print("name: {} voltage: {}".format(name, voltage)) ++ ++ # Decide voltage ++ if (voltage >= VOLTAGE_110V_MIN and voltage <= VOLTAGE_110V_MAX): ++ voltage_value = VOLTAGE_110_1_VALUE ++ psu_110v_count = 1 ++ elif (voltage >= VOLTAGE_220V_MIN and voltage <= VOLTAGE_220V_MAX): ++ voltage_value = VOLTAGE_220_1_VALUE ++ else: ++ log.log_error( ++ "poe_cfg_init.py - wrong voltage: {}".format(voltage)) ++ continue ++ ++ except: ++ log.log_error( ++ "poe_cfg_init.py(Exception) - {}- voltage: {}".format(name, voltage)) ++ pass ++ ++ if (psu_110v_count != 0): ++ voltage_value_1 = VOLTAGE_110_1_VALUE ++ voltage_value_2 = VOLTAGE_110_2_VALUE ++ else: ++ voltage_value_1 = VOLTAGE_220_1_VALUE ++ voltage_value_2 = VOLTAGE_220_2_VALUE ++ ++ cmd = "poetool mgmt set_power_banks 1 %s 570 440 0xa" % ( ++ voltage_value_1) ++ log.log_error(cmd) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ cmd = "poetool mgmt set_power_banks 2 %s 570 440 0xa" % ( ++ voltage_value_1) ++ log.log_error(cmd) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ cmd = "poetool mgmt set_power_banks 3 %s 570 440 0xa" % ( ++ voltage_value_2) ++ log.log_error(cmd) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ ++def main(): ++ # PoE global configuration ++ # preemptive priority ++ tmp_file = "/etc/sonic/poe_preemptive_priority_tmp" ++ cfg_file = "/etc/sonic/poe_preemptive_priority" ++ ++ if os.path.exists(cfg_file): ++ value = 0 ++ if not os.path.exists(tmp_file): ++ with open(tmp_file, 'w') as new_file: ++ new_file.write("poe_preemptive_priority_tmp") ++ else: ++ value = 1 ++ if os.path.exists(tmp_file): ++ # Delete the the file if it exists ++ os.remove(tmp_file) ++ ++ IGNORANCE_MASK = '0' ++ cmd = "sudo poetool system set_idv_mask %s %s" % (IGNORANCE_MASK, value) ++ # print(cmd) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ # redundant mode ++ tmp_file = "/etc/sonic/poe_redundant_tmp" ++ cfg_file = "/etc/sonic/poe_redundant" ++ ++ if os.path.exists(cfg_file): ++ value = 0 ++ if not os.path.exists(tmp_file): ++ with open(tmp_file, 'w') as new_file: ++ new_file.write("poe_redundant_tmp") ++ else: ++ value = 1 ++ if os.path.exists(tmp_file): ++ # Delete the the file if it exists ++ os.remove(tmp_file) ++ ++ FILE_PATH = "/sys/bus/i2c/devices/0-0033/psu_budget_mode" ++ if not os.path.exists(FILE_PATH): ++ log.log_error("FILE_PATH is not exsiting " + FILE_PATH) ++ ++ cmd = "sudo echo %s >> %s" % (value, FILE_PATH) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ except subprocess.CalledProcessError as e: ++ log.log_error("Error running run_power_redundant_cmd command:" + e) ++ ++ # PoE port configuration ++ CONFIG_DB_FILE = '/etc/sonic/config_db.json' ++ with open(CONFIG_DB_FILE) as json_file: ++ # Load the contents of the file ++ data = json.load(json_file) ++ ++ port_dict = data['PORT'] ++ # config_db = ConfigDBConnector() ++ # config_db.connect() ++ # port_dict = config_db.get_table('PORT') ++ # print(port_dict) ++ # command = "poeutil port-priority Ethernet0 low" ++ ++ for key in port_dict: ++ if port_dict[key]["poe_pri"] == "NA": ++ continue # Skips the non-poe ports ++ ++ # command = "poeutil port-priority %s %s" % ( ++ # key, port_dict[key]["poe_pri"]) ++ # clicommon.run_command(command) ++ # command = "poeutil power-inline %s %s %s" % ( ++ # key, port_dict[key]["poe_status"], port_dict[key]["poe_maxpower"]) ++ # clicommon.run_command(command) ++ ++ port_num = port_dict[key]["lanes"] ++ power_mode = port_dict[key]["poe_status"] ++ max_power = int(float(port_dict[key]["poe_maxpower"]) * 10) ++ ++ pure_power_mode = "enable" if (power_mode == "enableDynamic" or ++ power_mode == "enableStatic" or ++ power_mode == "enable") else "disable" ++ ++ pure_power_calculation = "static" if (power_mode == "enableStatic" or ++ power_mode == "disableStatic") else "disable" ++ ++ if pure_power_calculation == "static": ++ cfg2 = 1 ++ else: ++ cfg2 = 0 ++ ++ if (int(port_num) <= 31): # AT port, oper_mode is 9 ++ oper_mode = "9" ++ else: ++ oper_mode = "0" # BT port, oper_mode is 0 ++ add_power = 0 ++ ++ if (pure_power_mode == "enable" and int(max_power) != 0): ++ cfg1 = 1 ++ oper_mode = 0x31 # According to 3.3.12 Set BT Port Reserve Power Request ++ elif (pure_power_mode == "enable"): ++ cfg1 = 1 ++ elif (pure_power_mode == "disable"): ++ cfg1 = 0 ++ ++ pri = get_priority_value(port_dict[key]["poe_pri"]) ++ ++ cmd = "poetool port set_port_params %s %s %s %s %s %s" % ( ++ port_num, cfg1, cfg2, oper_mode, add_power, pri) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ if (pure_power_mode == "enable" and int(max_power) != 0): ++ reserve_power = max_power ++ pse_type = 1 ++ cmd = "poetool port set_port_reserve_power %s %s %s" % ( ++ port_num, reserve_power, pse_type) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ # print("cmd: ") ++ # print(cmd) ++ # print("result: ") ++ # print(result) ++ ++ # print(key, port_dict[key]["poe_pri"]) ++ ++ # Save setting and rest to make poe priority work properly ++ time.sleep(1) ++ cmd = "poetool system save_setting" ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ time.sleep(2) ++ cmd = "poetool system reset" ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ while True: ++ key = "Ethernet0" ++ result = run_lldpcli_show_port_command(key) ++ # print(result) ++ match = parse_keyword(key, result) ++ ++ if match is not None: ++ # print("Function returned:", result) ++ time.sleep(2) ++ break ++ else: ++ # print("Function returned None. Retrying in 5 seconds...") ++ time.sleep(5) ++ ++ for key in port_dict: ++ if port_dict[key]["poe_pri"] == "NA": ++ continue # Skips the non-poe ports ++ ++ state = port_dict[key]["poe_tlv"] ++ # print(state) ++ if (state == 'enable'): ++ enabled = 'enabled' ++ else: ++ enabled = '' ++ ++ while True: ++ result = run_lldpcli_config_port_command(key, enabled) ++ # print(result) ++ if result is not None: ++ # print("Function returned:", result) ++ break ++ else: ++ # print("Function returned None. Retrying in 5 seconds...") ++ time.sleep(5) ++ ++ ++if __name__ == '__main__': ++ # power() ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_lldp.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_lldp.py +new file mode 100755 +index 000000000..44bff37d4 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_cfg_lldp.py +@@ -0,0 +1,691 @@ ++#!/usr/bin/env python ++ ++import os ++import subprocess ++import json ++import time ++from swsscommon.swsscommon import ConfigDBConnector ++from sonic_py_common import logger ++ ++SYSLOG_IDENTIFIER = "poelldp" ++log = logger.Logger(SYSLOG_IDENTIFIER) ++ ++# Global dictionary to store power data for each port ++port_power_data = {} ++allocated_values = {} ++requested_values = {} ++lldp_power_sm = {} ++ ++# PoE configuration - Customziation ++# key is logical interface name ++# value 1 is the PoE physical port ++# value 2 is the PoE type(NA/AT/BT) ++poe_config_dict = { ++ "Ethernet0": ["0", "AT"], ++ "Ethernet1": ["1", "AT"], ++ "Ethernet2": ["2", "AT"], ++ "Ethernet3": ["3", "AT"], ++ "Ethernet4": ["4", "AT"], ++ "Ethernet5": ["5", "AT"], ++ "Ethernet6": ["6", "AT"], ++ "Ethernet7": ["7", "AT"], ++ "Ethernet8": ["8", "AT"], ++ "Ethernet9": ["9", "AT"], ++ "Ethernet10": ["10", "AT"], ++ "Ethernet11": ["11", "AT"], ++ "Ethernet12": ["12", "AT"], ++ "Ethernet13": ["13", "AT"], ++ "Ethernet14": ["14", "AT"], ++ "Ethernet15": ["15", "AT"], ++ "Ethernet16": ["16", "AT"], ++ "Ethernet17": ["17", "AT"], ++ "Ethernet18": ["18", "AT"], ++ "Ethernet19": ["19", "AT"], ++ "Ethernet20": ["20", "AT"], ++ "Ethernet21": ["21", "AT"], ++ "Ethernet22": ["22", "AT"], ++ "Ethernet23": ["23", "AT"], ++ "Ethernet24": ["24", "AT"], ++ "Ethernet25": ["25", "AT"], ++ "Ethernet26": ["26", "AT"], ++ "Ethernet27": ["27", "AT"], ++ "Ethernet28": ["28", "AT"], ++ "Ethernet29": ["29", "AT"], ++ "Ethernet30": ["30", "AT"], ++ "Ethernet31": ["31", "AT"], ++ "Ethernet32": ["32", "BT"], ++ "Ethernet33": ["33", "BT"], ++ "Ethernet34": ["34", "BT"], ++ "Ethernet35": ["35", "BT"], ++ "Ethernet36": ["36", "BT"], ++ "Ethernet37": ["37", "BT"], ++ "Ethernet38": ["38", "BT"], ++ "Ethernet39": ["39", "BT"], ++ "Ethernet40": ["40", "BT"], ++ "Ethernet41": ["41", "BT"], ++ "Ethernet42": ["42", "BT"], ++ "Ethernet43": ["43", "BT"], ++ "Ethernet44": ["44", "BT"], ++ "Ethernet45": ["45", "BT"], ++ "Ethernet46": ["46", "BT"], ++ "Ethernet47": ["47", "BT"], ++ "Ethernet48": ["48", "NA"], ++ "Ethernet49": ["49", "NA"], ++ "Ethernet50": ["50", "NA"], ++ "Ethernet51": ["51", "NA"], ++ "Ethernet52": ["52", "NA"], ++ "Ethernet53": ["53", "NA"], ++} ++ ++ ++def run_lldpcli_neighbor_command(): ++ try: ++ result = subprocess.run(['lldpcli', '-f', 'json', 'show', ++ 'ne', 'de'], capture_output=True, text=True, check=True) ++ return result.stdout ++ except subprocess.CalledProcessError as e: ++ print("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++ ++def run_lldpcli_config_port_command(interface, pri, req, alloc): ++ # lldpcli configure port Etherent40 dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority low requested 28000 allocated 15000 ++ ++ cmd = "lldpcli configure port %s dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority %s requested %s allocated %s" % ( ++ interface, pri, req, alloc) ++ # print(cmd) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ return result.strip() ++ except subprocess.CalledProcessError as e: ++ print("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++ ++def run_command(command): ++ try: ++ output = subprocess.check_output(command.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ except subprocess.CalledProcessError as e: ++ print("Command failed:") ++ print(e.output) ++ return None, None ++ ++ if output: ++ # Parse the value of "result" from the output ++ keyword = "result " ++ index = output.find(keyword) ++ if index != -1: ++ start_index = index + len(keyword) ++ end_index = output.find("\n", start_index) ++ result = output[start_index:end_index].strip() ++ # click.echo("result: {}\n".format(result)) ++ else: ++ print("Unable to find the result in the output.") ++ return None, None ++ ++ # click.echo("output: {}\n".format(output.strip())) ++ return result, output.strip() ++ ++ ++def run_port_lldp_pd_req_cmd(port_name, single, dual_a, dual_b, auto_class, cable_len, l2cfg): ++ ++ # Here is the command to set port params ++ # poetool port set_lldp_pd_req ++ ++ port_num = poe_config_dict[port_name][0] ++ ++ cmd = "sudo poetool port set_lldp_pd_req %s %s %s %s %s %s %s" % ( ++ port_num, single, dual_a, dual_b, auto_class, cable_len, l2cfg) ++ # print(cmd) ++ result, output_str = run_command(cmd) ++ # click.echo("result: {}\n".format(result)) ++ return result, output_str ++ ++ ++def run_port_port_status_cmd(port_name): ++ ++ # Here is the command to get port poe status ++ # admin@sonic:/usr/local/bin$ sudo poetool port get_lldp_pse_data 2 ++ # Code 69 get_lldp_pse_data, result 0 ++ # pseAllocatedPwrSingleOrAltA 255 ++ # pseAllocatedPwrAltB 0 ++ # pseMaxPwr 300 ++ # assignedClassPrimary 4 ++ # assignedClassSecondary 12 ++ # layer2Execution 0 ++ # layer2Usage 1 ++ # ieeeBTPwrBitsExt1514 1 ++ # ieeeBTPwrBitsExt1110 1 ++ # cableLength 10 ++ # layer2_cfg 1 ++ ++ port_num = poe_config_dict[port_name][0] ++ ++ cmd = "sudo poetool port get_lldp_pse_data %s" % (port_num) ++ # print(cmd) ++ result, output_str = run_command(cmd) ++ # click.echo("result: {}\n".format(result)) ++ return result, output_str ++ ++ ++def parse_keyword(keyword, string): # James ++ if string: ++ # Parse the value of keyword from the string ++ index = string.find(keyword) ++ if index != -1: ++ start_index = index + len(keyword) ++ end_index = string.find("\n", start_index) ++ result = string[start_index:end_index].strip() ++ # click.echo("result: {}\n".format(result)) ++ else: ++ print("Unable to find the result in the output.") ++ return None ++ ++ # click.echo("string: {}\n".format(string.strip())) ++ return result ++ else: ++ return None ++ ++def get_priority_value(priority): # James ++ priority_mapping = { ++ "critical": "1", ++ "high": "2", ++ "low": "3", ++ "0xff": "0xff" # 0xff means don't change the setting ++ } ++ return priority_mapping.get(priority, None) ++ ++def run_lldpcli_show_port_command(interface): ++ # lldpcli configure port Etherent40 dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority low requested 28000 allocated 15000 ++ ++ cmd = "lldpcli show in port %s de" % (interface) ++ # print(cmd) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ return result.strip() ++ except subprocess.CalledProcessError as e: ++ log.log_error("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++def run_lldpcli_init_port_command(interface, enabled): ++ # lldpcli configure port Etherent40 dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority low requested 28000 allocated 15000 ++ ++ cmd = "lldpcli configure port %s dot3 power pse supported %s powerpairs signal class class-4" % ( ++ interface, enabled) ++ # print(cmd) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ return result.strip() ++ except subprocess.CalledProcessError as e: ++ log.log_error("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++def poe_cfg(): ++ # PoE global configuration ++ # preemptive priority ++ tmp_file = "/etc/sonic/poe_preemptive_priority_tmp" ++ cfg_file = "/etc/sonic/poe_preemptive_priority" ++ ++ if os.path.exists(cfg_file): ++ value = 0 ++ if not os.path.exists(tmp_file): ++ with open(tmp_file, 'w') as new_file: ++ new_file.write("poe_preemptive_priority_tmp") ++ else: ++ value = 1 ++ if os.path.exists(tmp_file): ++ # Delete the the file if it exists ++ os.remove(tmp_file) ++ ++ IGNORANCE_MASK = '0' ++ cmd = "sudo poetool system set_idv_mask %s %s" % (IGNORANCE_MASK, value) ++ # print(cmd) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ # redundant mode ++ tmp_file = "/etc/sonic/poe_redundant_tmp" ++ cfg_file = "/etc/sonic/poe_redundant" ++ ++ if os.path.exists(cfg_file): ++ value = 0 ++ if not os.path.exists(tmp_file): ++ with open(tmp_file, 'w') as new_file: ++ new_file.write("poe_redundant_tmp") ++ else: ++ value = 1 ++ if os.path.exists(tmp_file): ++ # Delete the the file if it exists ++ os.remove(tmp_file) ++ ++ FILE_PATH = "/sys/bus/i2c/devices/0-0033/psu_budget_mode" ++ if not os.path.exists(FILE_PATH): ++ log.log_error("FILE_PATH is not exsiting " + FILE_PATH) ++ ++ cmd = "sudo echo %s >> %s" % (value, FILE_PATH) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ except subprocess.CalledProcessError as e: ++ log.log_error("Error running run_power_redundant_cmd command:" + e) ++ ++ # PoE port configuration# Wait for the file to be ready ++ CONFIG_DB_FILE = '/etc/sonic/config_db.json' ++ while not os.path.exists(CONFIG_DB_FILE): ++ print(f"Waiting for {CONFIG_DB_FILE} to be ready...") ++ time.sleep(3) # Sleep for 3 second before checking again ++ ++ with open(CONFIG_DB_FILE) as json_file: ++ # Load the contents of the file ++ data = json.load(json_file) ++ ++ port_dict = data['PORT'] ++ # config_db = ConfigDBConnector() ++ # config_db.connect() ++ # port_dict = config_db.get_table('PORT') ++ # print(port_dict) ++ # command = "poeutil port-priority Ethernet0 low" ++ ++ # Check if poe cfg not in the config_db ++ poe_in_config_db = False ++ for key in port_dict: ++ if "poe_pri" in port_dict[key]: ++ poe_in_config_db = True ++ break ++ else: ++ break ++ ++ if poe_in_config_db == False: ++ # If poe cfg not in the config_db yet ++ # 1. Use the default poe cfg json file ++ # 2. Add the default poe cfg to redis DB ++ ++ # Use the default poe cfg json file ++ CONFIG_POE_DB_FILE = '/usr/share/sonic/device/arm64-wistron_es2227_54ts_p-r0/wistron_es2227_54ts_p/poe_default_cfg.json' ++ with open(CONFIG_POE_DB_FILE) as json_file: ++ # Load the contents of the file ++ data = json.load(json_file) ++ port_dict = data['PORT'] ++ ++ # Add the default poe cfg to redis DB ++ config_db = ConfigDBConnector() ++ config_db.connect() ++ for key in port_dict: ++ config_db.mod_entry("PORT", key, {'poe_pri': port_dict[key]["poe_pri"]}) ++ config_db.mod_entry("PORT", key, {'poe_tlv': port_dict[key]["poe_tlv"]}) ++ config_db.mod_entry("PORT", key, {'poe_status': port_dict[key]["poe_status"]}) ++ config_db.mod_entry("PORT", key, {'poe_maxpower': port_dict[key]["poe_maxpower"]}) ++ ++ for key in port_dict: ++ if port_dict[key]["poe_pri"] == "NA": ++ continue # Skips the non-poe ports ++ ++ # command = "poeutil port-priority %s %s" % ( ++ # key, port_dict[key]["poe_pri"]) ++ # clicommon.run_command(command) ++ # command = "poeutil power-inline %s %s %s" % ( ++ # key, port_dict[key]["poe_status"], port_dict[key]["poe_maxpower"]) ++ # clicommon.run_command(command) ++ ++ port_num = port_dict[key]["lanes"] ++ power_mode = port_dict[key]["poe_status"] ++ max_power = int(float(port_dict[key]["poe_maxpower"]) * 10) ++ ++ pure_power_mode = "enable" if (power_mode == "enableDynamic" or ++ power_mode == "enableStatic" or ++ power_mode == "enable") else "disable" ++ ++ pure_power_calculation = "static" if (power_mode == "enableStatic" or ++ power_mode == "disableStatic") else "disable" ++ ++ if pure_power_calculation == "static": ++ cfg2 = 1 ++ else: ++ cfg2 = 0 ++ ++ if (int(port_num) <= 31): # AT port, oper_mode is 9 ++ oper_mode = "9" ++ else: ++ oper_mode = "0" # BT port, oper_mode is 0 ++ add_power = 0 ++ ++ if (pure_power_mode == "enable" and int(max_power) != 0): ++ cfg1 = 1 ++ oper_mode = 0x31 # According to 3.3.12 Set BT Port Reserve Power Request ++ elif (pure_power_mode == "enable"): ++ cfg1 = 1 ++ elif (pure_power_mode == "disable"): ++ cfg1 = 0 ++ ++ pri = get_priority_value(port_dict[key]["poe_pri"]) ++ ++ cmd = "poetool port set_port_params %s %s %s %s %s %s" % ( ++ port_num, cfg1, cfg2, oper_mode, add_power, pri) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ if (pure_power_mode == "enable" and int(max_power) != 0): ++ reserve_power = max_power ++ pse_type = 1 ++ cmd = "poetool port set_port_reserve_power %s %s %s" % ( ++ port_num, reserve_power, pse_type) ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ # print("cmd: ") ++ # print(cmd) ++ # print("result: ") ++ # print(result) ++ ++ # print(key, port_dict[key]["poe_pri"]) ++ ++ # Save setting and rest to make poe priority work properly ++ time.sleep(1) ++ cmd = "poetool system save_setting" ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ time.sleep(2) ++ cmd = "poetool system reset" ++ result, output_str = run_command(cmd) ++ if (result == None or int(result) != 0): ++ result, output_str = run_command(cmd) ++ log.log_error("try it again: " + result) ++ ++ while True: ++ key = "Ethernet0" ++ result = run_lldpcli_show_port_command(key) ++ # print(result) ++ match = parse_keyword(key, result) ++ ++ if match is not None: ++ # print("Function returned:", result) ++ time.sleep(2) ++ break ++ else: ++ # print("Function returned None. Retrying in 5 seconds...") ++ time.sleep(5) ++ ++ for key in port_dict: ++ if port_dict[key]["poe_pri"] == "NA": ++ continue # Skips the non-poe ports ++ ++ state = port_dict[key]["poe_tlv"] ++ # print(state) ++ if (state == 'enable'): ++ enabled = 'enabled' ++ else: ++ enabled = '' ++ ++ while True: ++ result = run_lldpcli_init_port_command(key, enabled) ++ # print(result) ++ if result is not None: ++ # print("Function returned:", result) ++ break ++ else: ++ # print("Function returned None. Retrying in 5 seconds...") ++ time.sleep(5) ++ ++def parse_lldpcli_output(output): ++ try: ++ # open DB ++ config_db = ConfigDBConnector() ++ config_db.connect() ++ port_dict = config_db.get_table('PORT') ++ ++ lldp_data = json.loads(output) ++ interfaces = lldp_data['lldp']['interface'] ++ ++ # print("lldp_debug: {}".format(lldp_debug)) ++ ++ # Store dictionary keys in a list ++ key_list = list(lldp_power_sm.keys()) ++ ++ for key in key_list: ++ if (lldp_debug != "0"): ++ print("key: {} value: {}".format(key, lldp_power_sm[key])) ++ is_found = 0 ++ for interface in interfaces: ++ # print("interface: {}".format(interface))a ++ if key in interface: ++ # print("xxxx") ++ is_found = 1 ++ break ++ # reset all parameters ++ if (is_found == 0): ++ del lldp_power_sm[key] ++ if key in allocated_values: ++ del allocated_values[key] ++ if key in requested_values: ++ del requested_values[key] ++ if (lldp_debug != "0"): ++ print("reset intf: {}".format(key)) ++ ++ for interface in interfaces: ++ if (lldp_debug != "0"): ++ # print(interface) ++ pass ++ for intf in interface: ++ if (lldp_debug != "0"): ++ print(intf) ++ if intf not in poe_config_dict: ++ if (lldp_debug != "0"): ++ print("intf not in poe_config_dict") ++ pass ++ elif intf == "eth0": ++ if (lldp_debug != "0"): ++ print("intf == eth0") ++ pass ++ elif port_dict[intf]["poe_status"] != "enableDynamic" and port_dict[intf]["poe_status"] != "enableStatic": ++ if (lldp_debug != "0"): ++ print("port_dict[intf][poe_status] is noe eanble") ++ pass # Skip the poe-disabled ports ++ elif port_dict[intf]["poe_tlv"] != "enable": ++ if (lldp_debug != "0"): ++ print("port_dict[intf][poe_tlv] is noe eanble") ++ pass # Skip the poe_tlv-disabled ports ++ elif port_dict[intf]["poe_maxpower"] != "0" and port_dict[intf]["poe_maxpower"] != "0.0": ++ if (lldp_debug != "0"): ++ print("port_dict[intf][poe_maxpower] is noe zero") ++ pass # Skip the static-power ports ++ else: ++ if 'port' not in interface[intf]: ++ if (lldp_debug != "0"): ++ print("port not in interface[intf]") ++ pass ++ ++ port_power_data[intf] = { ++ 'supported': False, ++ 'enabled': False, ++ 'device-type': '', ++ 'paircontrol': False, ++ 'pairs': '', ++ 'class': '', ++ 'power-type': '', ++ 'source': '', ++ 'priority': '', ++ 'requested': '0', ++ 'allocated': '' ++ } ++ elif 'power' not in interface[intf]['port']: ++ if (lldp_debug != "0"): ++ print("power not in interface[intf]") ++ pass ++ ++ port_power_data[intf] = { ++ 'supported': False, ++ 'enabled': False, ++ 'device-type': '', ++ 'paircontrol': False, ++ 'pairs': '', ++ 'class': '', ++ 'power-type': '', ++ 'source': '', ++ 'priority': '', ++ 'requested': '0', ++ 'allocated': '' ++ } ++ else: ++ # print(interface) ++ port_data = interface[intf]['port']['power'] ++ # print("port_data: {}", port_data) ++ port_power_data[intf] = { ++ 'supported': port_data.get('supported', False), ++ 'enabled': port_data.get('enabled', False), ++ 'device-type': port_data.get('device-type', ''), ++ 'paircontrol': port_data.get('paircontrol', False), ++ 'pairs': port_data.get('pairs', ''), ++ 'class': port_data.get('class', ''), ++ 'power-type': port_data.get('power-type', ''), ++ 'source': port_data.get('source', ''), ++ 'priority': port_data.get('priority', ''), ++ 'requested': port_data.get('requested', '0'), ++ 'allocated': port_data.get('allocated', '') ++ } ++ ++ if (port_power_data[intf]['requested'] == '0'): ++ # no requested power, nothing to do ++ if (lldp_debug != "0"): ++ print("power reuqest is zero") ++ pass ++ ++ # Check the poe attribute in lldp-med ++ if 'lldp-med' not in interface[intf]: ++ if (lldp_debug != "0"): ++ print("lldp-med not in interface[intf]") ++ continue ++ elif 'poe' not in interface[intf]['lldp-med']: ++ if (lldp_debug != "0"): ++ print("lldp-med not in interface[intf]") ++ continue ++ else: ++ lldp_med_poe = interface[intf]['lldp-med']['poe'] ++ ++ port_power_data[intf]['device-type'] = lldp_med_poe['device-type'] ++ port_power_data[intf]['requested'] = lldp_med_poe['power'] ++ ++ port_name = intf ++ single = int( ++ int(port_power_data[intf]['requested'])/100) ++ ++ if port_power_data[intf]['device-type'] != 'PD': ++ if (lldp_debug != "0"): ++ print("not a PD") ++ pass # Support PD only as the switch is a PSE ++ elif intf in allocated_values and allocated_values[intf] == port_power_data[intf]['requested']: ++ if (lldp_debug != "0"): ++ print(" Bingo: {}", intf) ++ pass # The request has been handled ++ # log.log_error(" Bingo: {}", intf) ++ elif intf in requested_values and requested_values[intf] == port_power_data[intf]['requested'] and lldp_power_sm[intf] == 0: ++ if (lldp_debug != "0"): ++ print(" Bingo2: {}".format(intf)) ++ pass # The request has been handled ++ # log.log_error(" Bingo2: {}", intf) ++ else: ++ # 1. call poetool to requst power ++ requested_values[intf] = port_power_data[intf]['requested'] ++ if (intf not in lldp_power_sm or lldp_power_sm[intf] == 0): ++ # print("0xffff") ++ lldp_power_sm[intf] = 1 ++ port_name = intf ++ # the requested power in lldpd is milliwatt(0.001w) and in poetool is 0.1w ++ single = int( ++ int(port_power_data[intf]['requested'])/100) ++ dual_a = 0 ++ dual_b = 0 ++ auto_class = 0 ++ cable_len = 0 ++ l2cfg = 0xff ++ ++ result, output_str = run_port_lldp_pd_req_cmd( ++ port_name, single, dual_a, dual_b, auto_class, cable_len, l2cfg) ++ ++ if result is None or int(result) != 0: ++ print("run_port_lldp_pd_req_cmd fails") ++ continue ++ else: ++ pass ++ ++ # 2. call poetool to cofirm alloacted power ++ if (lldp_power_sm[intf] == 1): ++ lldp_power_sm[intf] = 2 ++ pass ++ else: ++ result, output_str = run_port_port_status_cmd( ++ port_name) ++ # print(result) ++ # print(output_str) ++ if (result == None): ++ print(port_name) ++ result, output_str = run_port_port_status_cmd( ++ port_name) ++ print("try again: ") ++ print(result) ++ continue ++ ++ keyword = "pseAllocatedPwrSingleOrAltA" ++ allocated_power = parse_keyword( ++ keyword, output_str) ++ # print(allocated_power) ++ keyword = "layer2Execution" ++ layer2Execution = parse_keyword( ++ keyword, output_str) ++ # print(layer2Execution) ++ keyword = "layer2Usage" ++ layer2Usage = parse_keyword(keyword, output_str) ++ # print(layer2Usage) ++ ++ # print(single) ++ ++ if (layer2Usage == '1' or layer2Usage == '2' or layer2Usage == '3' or layer2Usage == '4'): ++ # print("xxx") ++ # 3. update allocated power to lldpd ++ port_pri = port_dict[intf]["poe_pri"] ++ run_lldpcli_config_port_command( ++ intf, port_pri, int(single) * 100, int(allocated_power) * 100) ++ # 4. Save allocated value to the global variable ++ allocated_values[intf] = allocated_power ++ lldp_power_sm[intf] = 0 ++ pass ++ else: ++ # print("yyy") ++ pass ++ ++ except (KeyError, json.JSONDecodeError) as e: ++ print("Error parsing lldpcli output:", e) ++ ++ ++if __name__ == "__main__": ++ import sys ++ ++ if len(sys.argv) > 1: ++ lldp_debug = sys.argv[1] ++ else: ++ lldp_debug = "0" ++ ++ poe_cfg() ++ ++ while True: ++ # log.log_error("while True") ++ lldpcli_output = run_lldpcli_neighbor_command() ++ if lldpcli_output: ++ # log.log_error("parse_lldpcli_output") ++ parse_lldpcli_output(lldpcli_output) ++ if (lldp_debug != "0"): ++ # print(port_power_data) ++ print(allocated_values) ++ print("=============") ++ time.sleep(2) ++ # log.log_error("time sleep") +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_init.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_init.sh +new file mode 100755 +index 000000000..cadecf1dc +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_init.sh +@@ -0,0 +1,77 @@ ++#!/bin/sh ++ ++echo 1 > /sys/bus/i2c/devices/0-0033/poe_en_ctrl ++ ++# Set temporary matrix ++#poetool port set_temp_matrix 0 33 255 ++#poetool port set_temp_matrix 1 38 255 ++#poetool port set_temp_matrix 2 34 255 ++#poetool port set_temp_matrix 3 37 255 ++#poetool port set_temp_matrix 4 35 255 ++#poetool port set_temp_matrix 5 36 255 ++#poetool port set_temp_matrix 6 39 255 ++#poetool port set_temp_matrix 7 32 255 ++#poetool port set_temp_matrix 8 47 255 ++#poetool port set_temp_matrix 9 40 255 ++#poetool port set_temp_matrix 10 44 255 ++#poetool port set_temp_matrix 11 43 255 ++#poetool port set_temp_matrix 12 45 255 ++#poetool port set_temp_matrix 13 42 255 ++#poetool port set_temp_matrix 14 46 255 ++#poetool port set_temp_matrix 15 41 255 ++#poetool port set_temp_matrix 16 49 255 ++#poetool port set_temp_matrix 17 54 255 ++#poetool port set_temp_matrix 18 50 255 ++#poetool port set_temp_matrix 19 53 255 ++#poetool port set_temp_matrix 20 52 255 ++#poetool port set_temp_matrix 21 51 255 ++#poetool port set_temp_matrix 22 48 255 ++#poetool port set_temp_matrix 23 55 255 ++#poetool port set_temp_matrix 24 63 255 ++#poetool port set_temp_matrix 25 56 255 ++#poetool port set_temp_matrix 26 60 255 ++#poetool port set_temp_matrix 27 59 255 ++#poetool port set_temp_matrix 28 61 255 ++#poetool port set_temp_matrix 29 58 255 ++#poetool port set_temp_matrix 30 62 255 ++#poetool port set_temp_matrix 31 57 255 ++#poetool port set_temp_matrix 32 5 2 ++#poetool port set_temp_matrix 33 4 3 ++#poetool port set_temp_matrix 34 7 0 ++#poetool port set_temp_matrix 35 6 1 ++#poetool port set_temp_matrix 36 9 14 ++#poetool port set_temp_matrix 37 8 15 ++#poetool port set_temp_matrix 38 11 12 ++#poetool port set_temp_matrix 39 10 13 ++#poetool port set_temp_matrix 40 21 18 ++#poetool port set_temp_matrix 41 20 19 ++#poetool port set_temp_matrix 42 23 16 ++#poetool port set_temp_matrix 43 22 17 ++#poetool port set_temp_matrix 44 25 30 ++#poetool port set_temp_matrix 45 24 31 ++#poetool port set_temp_matrix 46 27 28 ++#poetool port set_temp_matrix 47 26 29 ++# ++## PSUx2 = {power bank 3}; PSUx1 = {power bank 1/2} ++## For 220v PSUx2 ++##poe_main 0x09 3 2185 570 440 ++## For 220v PSUx1 ++##poe_main 0x09 1 1410 570 440 ++##poe_main 0x09 2 1410 570 440 ++# ++## For 110v PSUx2 ++#poetool mgmt set_power_banks 3 1810 570 440 0xa ++## For 110v PSUx1 ++#poetool mgmt set_power_banks 1 810 570 440 0xa ++#poetool mgmt set_power_banks 2 810 570 440 0xa ++# ++## Program global matrix ++#poetool port program_global_matrix ++## Save system settings ++#poetool system save_setting ++ ++# PoE power bank setting ++poe_power.sh ++# reload PoE configuration ++#poe_cfg_init.py ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_lldp.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_lldp.py +new file mode 100755 +index 000000000..6af5feb2e +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_lldp.py +@@ -0,0 +1,440 @@ ++#!/usr/bin/env python ++ ++ ++import subprocess ++import json ++import time ++from swsscommon.swsscommon import ConfigDBConnector ++from sonic_py_common import logger ++ ++SYSLOG_IDENTIFIER = "poelldp" ++log = logger.Logger(SYSLOG_IDENTIFIER) ++ ++# Global dictionary to store power data for each port ++port_power_data = {} ++allocated_values = {} ++requested_values = {} ++lldp_power_sm = {} ++ ++# PoE configuration - Customziation ++# key is logical interface name ++# value 1 is the PoE physical port ++# value 2 is the PoE type(NA/AT/BT) ++poe_config_dict = { ++ "Ethernet0": ["0", "AT"], ++ "Ethernet1": ["1", "AT"], ++ "Ethernet2": ["2", "AT"], ++ "Ethernet3": ["3", "AT"], ++ "Ethernet4": ["4", "AT"], ++ "Ethernet5": ["5", "AT"], ++ "Ethernet6": ["6", "AT"], ++ "Ethernet7": ["7", "AT"], ++ "Ethernet8": ["8", "AT"], ++ "Ethernet9": ["9", "AT"], ++ "Ethernet10": ["10", "AT"], ++ "Ethernet11": ["11", "AT"], ++ "Ethernet12": ["12", "AT"], ++ "Ethernet13": ["13", "AT"], ++ "Ethernet14": ["14", "AT"], ++ "Ethernet15": ["15", "AT"], ++ "Ethernet16": ["16", "AT"], ++ "Ethernet17": ["17", "AT"], ++ "Ethernet18": ["18", "AT"], ++ "Ethernet19": ["19", "AT"], ++ "Ethernet20": ["20", "AT"], ++ "Ethernet21": ["21", "AT"], ++ "Ethernet22": ["22", "AT"], ++ "Ethernet23": ["23", "AT"], ++ "Ethernet24": ["24", "AT"], ++ "Ethernet25": ["25", "AT"], ++ "Ethernet26": ["26", "AT"], ++ "Ethernet27": ["27", "AT"], ++ "Ethernet28": ["28", "AT"], ++ "Ethernet29": ["29", "AT"], ++ "Ethernet30": ["30", "AT"], ++ "Ethernet31": ["31", "AT"], ++ "Ethernet32": ["32", "BT"], ++ "Ethernet33": ["33", "BT"], ++ "Ethernet34": ["34", "BT"], ++ "Ethernet35": ["35", "BT"], ++ "Ethernet36": ["36", "BT"], ++ "Ethernet37": ["37", "BT"], ++ "Ethernet38": ["38", "BT"], ++ "Ethernet39": ["39", "BT"], ++ "Ethernet40": ["40", "BT"], ++ "Ethernet41": ["41", "BT"], ++ "Ethernet42": ["42", "BT"], ++ "Ethernet43": ["43", "BT"], ++ "Ethernet44": ["44", "BT"], ++ "Ethernet45": ["45", "BT"], ++ "Ethernet46": ["46", "BT"], ++ "Ethernet47": ["47", "BT"], ++ "Ethernet48": ["48", "NA"], ++ "Ethernet49": ["49", "NA"], ++ "Ethernet50": ["50", "NA"], ++ "Ethernet51": ["51", "NA"], ++ "Ethernet52": ["52", "NA"], ++ "Ethernet53": ["53", "NA"], ++} ++ ++ ++def run_lldpcli_neighbor_command(): ++ try: ++ result = subprocess.run(['lldpcli', '-f', 'json', 'show', ++ 'ne', 'de'], capture_output=True, text=True, check=True) ++ return result.stdout ++ except subprocess.CalledProcessError as e: ++ print("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++ ++def run_lldpcli_config_port_command(interface, pri, req, alloc): ++ # lldpcli configure port Etherent40 dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority low requested 28000 allocated 15000 ++ ++ cmd = "lldpcli configure port %s dot3 power pse supported enabled powerpairs signal class class-4 type 2 source primary priority %s requested %s allocated %s" % ( ++ interface, pri, req, alloc) ++ # print(cmd) ++ try: ++ result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ # print(result.strip()) ++ return result.strip() ++ except subprocess.CalledProcessError as e: ++ print("Error running run_lldpcli_neighbor_command command:", e) ++ return None ++ ++ ++def run_command(command): ++ try: ++ output = subprocess.check_output(command.split(), stderr=subprocess.STDOUT, universal_newlines=True) ++ except subprocess.CalledProcessError as e: ++ print("Command failed:") ++ print(e.output) ++ return None, None ++ ++ if output: ++ # Parse the value of "result" from the output ++ keyword = "result " ++ index = output.find(keyword) ++ if index != -1: ++ start_index = index + len(keyword) ++ end_index = output.find("\n", start_index) ++ result = output[start_index:end_index].strip() ++ # click.echo("result: {}\n".format(result)) ++ else: ++ print("Unable to find the result in the output.") ++ return None, None ++ ++ # click.echo("output: {}\n".format(output.strip())) ++ return result, output.strip() ++ ++ ++def run_port_lldp_pd_req_cmd(port_name, single, dual_a, dual_b, auto_class, cable_len, l2cfg): ++ ++ # Here is the command to set port params ++ # poetool port set_lldp_pd_req ++ ++ port_num = poe_config_dict[port_name][0] ++ ++ cmd = "sudo poetool port set_lldp_pd_req %s %s %s %s %s %s %s" % ( ++ port_num, single, dual_a, dual_b, auto_class, cable_len, l2cfg) ++ # print(cmd) ++ result, output_str = run_command(cmd) ++ # click.echo("result: {}\n".format(result)) ++ return result, output_str ++ ++ ++def run_port_port_status_cmd(port_name): ++ ++ # Here is the command to get port poe status ++ # admin@sonic:/usr/local/bin$ sudo poetool port get_lldp_pse_data 2 ++ # Code 69 get_lldp_pse_data, result 0 ++ # pseAllocatedPwrSingleOrAltA 255 ++ # pseAllocatedPwrAltB 0 ++ # pseMaxPwr 300 ++ # assignedClassPrimary 4 ++ # assignedClassSecondary 12 ++ # layer2Execution 0 ++ # layer2Usage 1 ++ # ieeeBTPwrBitsExt1514 1 ++ # ieeeBTPwrBitsExt1110 1 ++ # cableLength 10 ++ # layer2_cfg 1 ++ ++ port_num = poe_config_dict[port_name][0] ++ ++ cmd = "sudo poetool port get_lldp_pse_data %s" % (port_num) ++ # print(cmd) ++ result, output_str = run_command(cmd) ++ # click.echo("result: {}\n".format(result)) ++ return result, output_str ++ ++ ++def parse_keyword(keyword, string): # James ++ if string: ++ # Parse the value of keyword from the string ++ index = string.find(keyword) ++ if index != -1: ++ start_index = index + len(keyword) ++ end_index = string.find("\n", start_index) ++ result = string[start_index:end_index].strip() ++ # click.echo("result: {}\n".format(result)) ++ else: ++ print("Unable to find the result in the output.") ++ return None ++ ++ # click.echo("string: {}\n".format(string.strip())) ++ return result ++ else: ++ return None ++ ++ ++def parse_lldpcli_output(output): ++ try: ++ # open DB ++ config_db = ConfigDBConnector() ++ config_db.connect() ++ port_dict = config_db.get_table('PORT') ++ ++ lldp_data = json.loads(output) ++ interfaces = lldp_data['lldp']['interface'] ++ ++ # print("lldp_debug: {}".format(lldp_debug)) ++ ++ # Store dictionary keys in a list ++ key_list = list(lldp_power_sm.keys()) ++ ++ for key in key_list: ++ if (lldp_debug != "0"): ++ print("key: {} value: {}".format(key, lldp_power_sm[key])) ++ is_found = 0 ++ for interface in interfaces: ++ # print("interface: {}".format(interface))a ++ if key in interface: ++ # print("xxxx") ++ is_found = 1 ++ break ++ # reset all parameters ++ if (is_found == 0): ++ del lldp_power_sm[key] ++ if key in allocated_values: ++ del allocated_values[key] ++ if key in requested_values: ++ del requested_values[key] ++ if (lldp_debug != "0"): ++ print("reset intf: {}".format(key)) ++ ++ for interface in interfaces: ++ if (lldp_debug != "0"): ++ # print(interface) ++ pass ++ for intf in interface: ++ if (lldp_debug != "0"): ++ print(intf) ++ if intf not in poe_config_dict: ++ if (lldp_debug != "0"): ++ print("intf not in poe_config_dict") ++ pass ++ elif intf == "eth0": ++ if (lldp_debug != "0"): ++ print("intf == eth0") ++ pass ++ elif port_dict[intf]["poe_status"] != "enableDynamic" and port_dict[intf]["poe_status"] != "enableStatic": ++ if (lldp_debug != "0"): ++ print("port_dict[intf][poe_status] is noe eanble") ++ pass # Skip the poe-disabled ports ++ elif port_dict[intf]["poe_tlv"] != "enable": ++ if (lldp_debug != "0"): ++ print("port_dict[intf][poe_tlv] is noe eanble") ++ pass # Skip the poe_tlv-disabled ports ++ elif port_dict[intf]["poe_maxpower"] != "0" and port_dict[intf]["poe_maxpower"] != "0.0": ++ if (lldp_debug != "0"): ++ print("port_dict[intf][poe_maxpower] is noe zero") ++ pass # Skip the static-power ports ++ else: ++ if 'port' not in interface[intf]: ++ if (lldp_debug != "0"): ++ print("port not in interface[intf]") ++ pass ++ ++ port_power_data[intf] = { ++ 'supported': False, ++ 'enabled': False, ++ 'device-type': '', ++ 'paircontrol': False, ++ 'pairs': '', ++ 'class': '', ++ 'power-type': '', ++ 'source': '', ++ 'priority': '', ++ 'requested': '0', ++ 'allocated': '' ++ } ++ elif 'power' not in interface[intf]['port']: ++ if (lldp_debug != "0"): ++ print("power not in interface[intf]") ++ pass ++ ++ port_power_data[intf] = { ++ 'supported': False, ++ 'enabled': False, ++ 'device-type': '', ++ 'paircontrol': False, ++ 'pairs': '', ++ 'class': '', ++ 'power-type': '', ++ 'source': '', ++ 'priority': '', ++ 'requested': '0', ++ 'allocated': '' ++ } ++ else: ++ # print(interface) ++ port_data = interface[intf]['port']['power'] ++ # print("port_data: {}", port_data) ++ port_power_data[intf] = { ++ 'supported': port_data.get('supported', False), ++ 'enabled': port_data.get('enabled', False), ++ 'device-type': port_data.get('device-type', ''), ++ 'paircontrol': port_data.get('paircontrol', False), ++ 'pairs': port_data.get('pairs', ''), ++ 'class': port_data.get('class', ''), ++ 'power-type': port_data.get('power-type', ''), ++ 'source': port_data.get('source', ''), ++ 'priority': port_data.get('priority', ''), ++ 'requested': port_data.get('requested', '0'), ++ 'allocated': port_data.get('allocated', '') ++ } ++ ++ if (port_power_data[intf]['requested'] == '0'): ++ # no requested power, nothing to do ++ if (lldp_debug != "0"): ++ print("power reuqest is zero") ++ pass ++ ++ # Check the poe attribute in lldp-med ++ if 'lldp-med' not in interface[intf]: ++ if (lldp_debug != "0"): ++ print("lldp-med not in interface[intf]") ++ continue ++ elif 'poe' not in interface[intf]['lldp-med']: ++ if (lldp_debug != "0"): ++ print("lldp-med not in interface[intf]") ++ continue ++ else: ++ lldp_med_poe = interface[intf]['lldp-med']['poe'] ++ ++ port_power_data[intf]['device-type'] = lldp_med_poe['device-type'] ++ port_power_data[intf]['requested'] = lldp_med_poe['power'] ++ ++ port_name = intf ++ single = int( ++ int(port_power_data[intf]['requested'])/100) ++ ++ if port_power_data[intf]['device-type'] != 'PD': ++ if (lldp_debug != "0"): ++ print("not a PD") ++ pass # Support PD only as the switch is a PSE ++ elif intf in allocated_values and allocated_values[intf] == port_power_data[intf]['requested']: ++ if (lldp_debug != "0"): ++ print(" Bingo: {}", intf) ++ pass # The request has been handled ++ # log.log_error(" Bingo: {}", intf) ++ elif intf in requested_values and requested_values[intf] == port_power_data[intf]['requested'] and lldp_power_sm[intf] == 0: ++ if (lldp_debug != "0"): ++ print(" Bingo2: {}".format(intf)) ++ pass # The request has been handled ++ # log.log_error(" Bingo2: {}", intf) ++ else: ++ # 1. call poetool to requst power ++ requested_values[intf] = port_power_data[intf]['requested'] ++ if (intf not in lldp_power_sm or lldp_power_sm[intf] == 0): ++ # print("0xffff") ++ lldp_power_sm[intf] = 1 ++ port_name = intf ++ # the requested power in lldpd is milliwatt(0.001w) and in poetool is 0.1w ++ single = int( ++ int(port_power_data[intf]['requested'])/100) ++ dual_a = 0 ++ dual_b = 0 ++ auto_class = 0 ++ cable_len = 0 ++ l2cfg = 0xff ++ ++ result, output_str = run_port_lldp_pd_req_cmd( ++ port_name, single, dual_a, dual_b, auto_class, cable_len, l2cfg) ++ ++ if result is None or int(result) != 0: ++ print("run_port_lldp_pd_req_cmd fails") ++ continue ++ else: ++ pass ++ ++ # 2. call poetool to cofirm alloacted power ++ if (lldp_power_sm[intf] == 1): ++ lldp_power_sm[intf] = 2 ++ pass ++ else: ++ result, output_str = run_port_port_status_cmd( ++ port_name) ++ # print(result) ++ # print(output_str) ++ if (result == None): ++ print(port_name) ++ result, output_str = run_port_port_status_cmd( ++ port_name) ++ print("try again: ") ++ print(result) ++ continue ++ ++ keyword = "pseAllocatedPwrSingleOrAltA" ++ allocated_power = parse_keyword( ++ keyword, output_str) ++ # print(allocated_power) ++ keyword = "layer2Execution" ++ layer2Execution = parse_keyword( ++ keyword, output_str) ++ # print(layer2Execution) ++ keyword = "layer2Usage" ++ layer2Usage = parse_keyword(keyword, output_str) ++ # print(layer2Usage) ++ ++ # print(single) ++ ++ if (layer2Usage == '1' or layer2Usage == '2' or layer2Usage == '3' or layer2Usage == '4'): ++ # print("xxx") ++ # 3. update allocated power to lldpd ++ port_pri = port_dict[intf]["poe_pri"] ++ run_lldpcli_config_port_command( ++ intf, port_pri, int(single) * 100, int(allocated_power) * 100) ++ # 4. Save allocated value to the global variable ++ allocated_values[intf] = allocated_power ++ lldp_power_sm[intf] = 0 ++ pass ++ else: ++ # print("yyy") ++ pass ++ ++ except (KeyError, json.JSONDecodeError) as e: ++ print("Error parsing lldpcli output:", e) ++ ++ ++if __name__ == "__main__": ++ import sys ++ ++ if len(sys.argv) > 1: ++ lldp_debug = sys.argv[1] ++ else: ++ lldp_debug = "0" ++ ++ while True: ++ # log.log_error("while True") ++ lldpcli_output = run_lldpcli_neighbor_command() ++ if lldpcli_output: ++ # log.log_error("parse_lldpcli_output") ++ parse_lldpcli_output(lldpcli_output) ++ if (lldp_debug != "0"): ++ # print(port_power_data) ++ print(allocated_values) ++ print("=============") ++ time.sleep(2) ++ # log.log_error("time sleep") +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_power.sh b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_power.sh +new file mode 100755 +index 000000000..cbfb4ec86 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poe_power.sh +@@ -0,0 +1,107 @@ ++#!/bin/bash ++ ++directories=( ++ # When both PSUs are plugged PSU1 is hwmon5 and PSU2 is hwmon4 ++ # If only one PSU is plugged, it is hwmon4 ++ "/sys/bus/i2c/devices/3-0059/hwmon/hwmon5" ++ "/sys/bus/i2c/devices/3-0059/hwmon/hwmon4" ++ "/sys/bus/i2c/devices/3-0058/hwmon/hwmon4" ++) ++ ++# PSU corresponding parameters ++VOLTAGE_110V_MIN=90 ++VOLTAGE_110V_MIN_MW=90000 ++VOLTAGE_110V_MAX=132 ++VOLTAGE_220V_MIN=180 ++VOLTAGE_220V_MAX=264 ++VOLTAGE_110_1_VALUE=810 # 110V for one bank ++VOLTAGE_110_2_VALUE=1810 # 110V for two banks ++VOLTAGE_220_1_VALUE=1410 # 220V for one bank ++VOLTAGE_220_2_VALUE=2400 # 220V for two banks ++ ++# Initialize variables for minimum value and its corresponding parameter ++min_value="" ++min_param="" ++ ++# List of parameters to extract ++parameters=("in1_input") ++ ++# Read and find the minimum parameter value from each directory ++for directory in "${directories[@]}"; do ++ # echo "directory $directory" ++ for param in "${parameters[@]}"; do ++ # echo "param $param" ++ file_path="$directory/$param" ++ if [ -e "$file_path" ]; then ++ value=$(<"$file_path") ++ ++ # Skip iteration if value is less than 110V requirement ++ if [ "$value" -lt "$VOLTAGE_110V_MIN_MW" ]; then ++ continue ++ fi ++ ++ # echo "Found value: $value for parameter: $param in directory: $directory" ++ if [ -z "$min_value" ] || [ "$value" -lt "$min_value" ]; then ++ # echo "Updating minimum value to: $value for parameter: $param" ++ min_value="$value" ++ min_param="$param" ++ fi ++ fi ++ done ++done ++ ++ ++# Decide the boardID ++# 3 : EVT ++# 1 : DVT ++BOARD_ID_EVT=3 ++BOARD_ID_DVT=1 ++ ++xboard_id="$BOARD_ID_EVT" ++file_path="/sys/bus/i2c/devices/0-0033/board_id" ++ ++# Check if the file exists ++if [ -f "$file_path" ]; then ++ # Read the content of the file and assign it to xboard_id ++ xboard_id=$(cat "$file_path") ++fi ++# echo "xboard_id: $xboard_id" ++ ++# Define the variables for 110V/220V ++PSU_VSENSE_110V=0 ++PSU_VSENSE_220V=1 ++ ++#value_watts=$(awk "BEGIN {print $min_value / 1000}") ++value_watts=$(printf "%.0f" $(awk "BEGIN {print $min_value / 1000}")) ++vsense_file_path="/sys/bus/i2c/devices/0-0033/psu_vsense" ++if [ "$value_watts" -ge "$VOLTAGE_220V_MIN" ] && [ "$value_watts" -le "$VOLTAGE_220V_MAX" ]; then ++ # echo "220V" ++ if [ "$xboard_id" -eq "$BOARD_ID_EVT" ]; then ++ # echo "EVT" ++ # For 110v PSUx2 ++ poetool mgmt set_power_banks 3 2400 570 440 0xa ++ # For 110v PSUx1 ++ poetool mgmt set_power_banks 1 1410 570 440 0xa ++ poetool mgmt set_power_banks 2 1410 570 440 0xa ++ else ++ value_to_write=$PSU_VSENSE_220V ++ echo "$value_to_write" > "$vsense_file_path" ++ # echo "Value written to $vsense_file_path: $value_to_write" ++ fi ++else ++ # echo "110V" ++ if [ "$xboard_id" -eq "$BOARD_ID_EVT" ]; then ++ # echo "EVT" ++ # For 110v PSUx2 ++ poetool mgmt set_power_banks 3 1810 570 440 0xa ++ # For 110v PSUx1 ++ poetool mgmt set_power_banks 1 810 570 440 0xa ++ poetool mgmt set_power_banks 2 810 570 440 0xa ++ else ++ value_to_write=$PSU_VSENSE_110V ++ echo "$value_to_write" > "$vsense_file_path" ++ # echo "Value written to $vsense_file_path: $value_to_write" ++ fi ++ ++fi ++ +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poetool b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/poetool +new file mode 100755 +index 0000000000000000000000000000000000000000..e81fbcea75844521ee31612fd0954c2826c9959f +GIT binary patch +literal 1338224 +zcmdqK3w)Htxj#PdCP26-fkZ(;vk52&C>0{ +z+FIL;+G49M3APGUYrOQ-9BtizR(iB;#7k}MWjEdxEs9p6(EPsNxx733W;a~^?cw+j +zpXHr-X6BiBF7wPYmv`Q)KQ;4$kmm{emm_{I7>ku?NW>&GEhsc0AtGX;=!yS_h!W8q +z&|Lf?CN=onZ&2H3p2?SkC(BI?X+ZEf$mFw6+d@9OnY2ug2Y;k<+NV&|=>OT)`t3Ts +ze!H&NJ`)A`3SIp${j}wni{%=J`&r&(t)R&Dft4w|Nsaqw)=;ccnj9$L*%;ig0T(R!V +zs;br1OU@mC)|!=PovrDnwot|upSwhSec0MDIX#}gy>##`=ib}?`0LxBx^Ot#%{CAp +z^YD-Pd#I3xGtJg#z=!q75xqszDV?+Ch!cfqG6FHlJyB`@&RNBREbz}FZ>IbMvgH3W +zs>_srYnJ@iWXb;m7?BCjx3c8#hjxZD&~-EFEy(~M2RO?F{|;oqe?Ky2YR`%+`M;ip +z-b=E;CuM=>XMz7NOTE`;fgj8QFUo@db6NQR*DUa#Wr6=93;qz`nfU*5mUf<#1^?@!M``N&{ctqne^w^S=zZOOM8BhCI1Im;Qy7S{nur| +z|9loa-_6qg`C0JPWvTafS>O+6skbN#ydn#p{aM<%B}@K!S@LhlQtw4s;00OW1GDhw +z2U*~kXKByNS@OS?rQRJ`;GfIFhmW)1e>h8f=)Yvr=kH{Jp9wr+{DObWvb5)`$e0QL +zs4V#($Wrg-EO;Kv0{>zb{N-8T0)D}&wM$kns#-{IV2r5z^xV%@E?l&F(c-0R)-GB- +z_p{TNuUxTcZqM*1?9wsO@Xo$0D76i=`0iWMpw +z=(=Lff-}!PYmA|*a`ELWS5&T9TeW&^WhKc*awQR=c~>s2UQ~J2(zQz}uUxvYa@Ep> +zHhuA;wKf?e@e4vby8Vlg>v8dq7hrh4g8i%>DjZ&lUO%PW_zfK)H5 +zs$OKXfC30-d8b;HWK7XDs3{|*Ypz&u`O>wW%BmK-G+$03oGVtXyo%LU>loTzy{c9$ +zS_c_krdqlRdI0_+VFgoGU9olzlmjxWURGJXWLf29RZEu>TD_!dwYYrE;?>nxLLZhd +zs$MIq7OY&oR)8gx9uTZuxtx#XP?XCTT@C`o+G_k?wRWv4iHxFp?b6Gkv}+fxykadg +zvC7M|>=c44mW#`kM8twGEn2;j$QP|Zg=^706q4$-%f-@_{2y&uvtpsRV$JeJi&mk@ +z8XMb;YA;)U#hNAJvQ?1O+RKo5r3tEJAcar92-y%)t*fl8URPCl+0qqN%a?v>5n8kY +z6@Ux6yefp|RbS3}$V{Wtmsc%aA;@@<+0A$PxcG{y)eA+%%ui37UOD!xvnTk$v8Beq +zg+vJcJ^$xFVSXB#YoIoj=`b$_s-HQkH0OTA;-;nNWQxv#O!#wCb=c-$KHVbb^YHIk +zWZ;}6jNc~tT}-FCi32QzKc+84#WwxxDm_>9FcUDQW61E+b@`mM@~cgG;?wCNKi$ql +za}2)ghcK5Ax0?B;g+~m0;=SYo=rj5AFJSFLL;~==aXo6x3cy8+hDQVNfjcyORREr6 +z@~;cPha33y0eIeSji){cH~4Q2z?)1v8v^i&2LD3=_=N@@55W7FdUplj*PHyU0eJnV +zG~Zqb!1E2BL;ya}z+Vr*uV1g&FZKuEyG*@#X5MM#W#jn)_~4Nm&%gkDjFE3R0H0{! +z!vpZ45sha|0KU%TpBRA0to{VxTW4xK7Y5*QlYdqKzRSQb4Zv?*q47im@VpAm|0Mx< +zzJad_z^}hj<5?Gg&ocRA0r;f`zBK^9`yP#_DFEMN;131hYaiA5;{o`TUupQR06g}h +zhPMXb!{65M7Xt8lI_mgK1mIh5)bQ5>@J9@MZvei0lg__C0N;9>hKu{s?Z%S3G(0Z| +zzgxre1Muj38ouinx_?`Jo_LLxV`~5&G4K}x@JkIm5rD5U@Ye(I>kWKw0N!BW`vdS@ +z1}=V?-p;)So)>`UU8~!lAApAqd|&`R(ZIt2_$&h-9)L#;d`tiyGw_K4c!PmQ0`P|n +z{K5cymx0d;z!L_3X#oDZfky-I{RX}y0M9e)krx{K=3(6FV^oTdOC9)e4t$9NKi+}I +z9QdgYe5(UL-GMhb@L>*ouLHl(fxmvY*7FeBX@+o>y4Qi5p;N*4JMgsi<$F?i;1KwK +zc@EsJSu!!-f!noU!UsC=o&=b`umkU9fp`vg;JqFA7zgh1d7=aF>*S9(aJ%Nq_a&4fe!q72Y!+R +zuXo@lJMdc__#g+~;J^nv@U0HqT}p0p;6+aUha7m=fyW(qu>;@bz)Ku>s{=Q#o=Sbe +zfe&@^Cmi@`4*Yco?)Ia-4t%(if4>7i!-0#Rru2V=1J85d#${2d`3`)PlYgKCKhuGS +z9r#%ee7FN2?ZC%4@G%a2q60tMfkzzpSOmB%H2VU>Mr#SFi9r#oS-r&H`bKqMYc$oula^MjM +z{*VJNci?dcKFxvea^TY)c&h_H-+{m2z(3`{6At_W2mZPP=UTJ<+v~tTZGm|1ci^9K +z;KGbA97kq2@H_`@Tx6A+@4!Fn61!-;7Ze1Q|c3Gt0i{JV&6apK=ce1{YNA>wULd<){Cb5ix+ +ziFk<<-;Ve+C;n5!7dY|z5#Q*<{|oUgPW-;NY(!;;w4V}O~j`;@plkk;KbiU +ze4`WpJK|gXczwT*5Z~d%|ABa$6Ax9O{)x8!`hMLJFLC0%5TEA6k4Jog6Yr1sMkjtE +z;#-{f$%yZ8;-@0s=EO@750$3sKOONBCq4r4X-@ns#1}a6v50SU;^!j1#feWse1{W1 +z5Ail9J`M5Eq*VPEAYS6cKZE!*C;mCa7dY|Rh;MY_|AzP$C;oZFcR2C?M7+(3FF-sr +zIaU8ffHYi_(mswCE{D0_?Hmh;l#g!c$*X7h58IPseh-{{1@i})5DKSjiLpNiirIbwSsY_C&|#-DS{+ +zrATL8n9mg^0QaVd{^S{WQQL{OqRzB!_Gx?UpH3U*K54YA&rVw@X~W!5(NJ_C=iN?p +z4fg4ROBs+^2D+AZqAR73)EkfKhR=zSq8TnxVPa&YS>%d~8BdIiH7AiTEW`~;pB@r5 +zG0FmYs6%)EqXXg2d0JGS81YD3Uf~{{${W-pt9z<%82t%@#>5cO+;)eMsJGQioFWrB +zq3tEmP3UcV@v6u}-YW4>q&xDB7PYY+cvg$jSRXtmh}vYekO`E%wm3HXCD@3z(UIEZ +zkVtcnvEr7*Fwi$F(hQwT>3s$s4(!B3?XOJ&4(qR3AC7Gl;Zx;Elu_Z>sdBgt$4`}~ +z*>Jc>me_E#NEX>}yhskV;Ye7XWWx<%d7=%AVp(9r(PEiz!?6;1oDC;RWG@?z4Us); +zSPYfx{P1a#^4IM=P5$Gc2}e(tAKS1PCif#uJDic$$S}Fr=1mNfZ`*KexO}s#a^eix +zX7k3+kbkw|*a-QjF3XLS&)U54k@9I94xcH1Ys2C!`J@epN6TF{92p}Yx8a5{a)%9v +z&z6tcaKqX15gQg`WwQ-8jFtao!;x|F0UM5wlT9`p9WU>(;rMvD-G(FQ$h&MfagO|v +z4ad%vjW#SM$R8q{mCvyW^1C)~c%r=7hDE8Yx8Yc+ys;}B;YsqVHg9~A+-SqVadlVa +zVw2@nHg9B#eBFj)Q{^i*EY3^GGhAlnxmQGmT#_C4UJ>(TRO8qyA|d%7HXO~7pSNL= +zE9Z5EqajybWb;P5$(epQM}E3fx%>2(RV11_jmKA+F^hi4Qx)xraTv3TVCQm0O|hrP +z~B`>wf!y<`?PSXzH%ZQuirGQ1^7y{e4sS +zqF~)IUH5NI-HqLitn#$no$q2xc2t7by+Ce`qwtpkyxhkDZfGY +zyF7V^h39I2LctSx@&^_kj+C?P)&W8_qoMNX|}IW~lPU43|R+J`z4)oFU&iqp&TZ3|E7 +zHQL=zzGmSrALIRG(!yOnivIFN3wQY#=`WwNaF>s<{_=Mg9(Co{U;f&{7dmiJAa`2$ +zV2AIK0{IIIk2rj9D3Ct~{CLCnKZMfkNvkIc72l^J5Bo<8_^!tGd~FB6fN~r!o6?Fe +zx;~LQF+ZT|@j^M)!qas91UbsW({%j=c{<=p)ENY@y* +z?Kh_FZ=;;*ZxsPvfd@B{2ZUFoXnxd`!+RYmnlA#)@NJZ?U!-aN3(JBh#SWcG$3Lq* +z0y;N?2A{ukP}iKm7#KfMeiwO^eMNtGD98&jKH^DIUI|*DWT!=9Jb;1XVQrauZu*%VgDo5`>7cIp0=JfR0ZN=s0xpCiXkPlM|rhlZ}oeZ<>z7PF$ZYAIh-}NvmTB!&lS# +z7S=k}YTEN8=^)R^|LNerwV~6Ej!~BwhK@bK`jEH9m8YXi3tV{~LWb9aPk$vo@N#>Q +zmr>2j0>jG|%S$uYz2CI`cJh)w%eVj!!JBf`R=~$OykH-*ykOYy;)ezw`eBL}lfet* +zQT=VQ=EZe}{-i^{Ygfc^_Xo6q+$)K!+!d*xThPnKoOL%6HAVvsDga93}mgXB2C +zzhQWKNsy=UK}tV=xnJvN6?i(w&{Lf2jEPSFd}pL%8>k->4zGXqWBVoq`{!WU+rr)c +z85u0QS-4AQY_RM=TNNIc&ctBZZsBhKjGQ9(S-9)tG@K&ew(v2oy*O3AX5oV!zdCZN +zOaea9@DXS93MV0qzRP{85n&H&RM`7!yQ=g4OBwO0y`|ro{TIE)uH@Nps+@;(6&6Ku +zt_?R7$%}0`9G0K6;dofiKsf7KYNS|Bw|NuAGGfE=5;@g|v1UH0D;y0&y<|fBb-uC$JA3%0GTs=suJw +zpYe~C&3^#4ZIsY{#lr|+8d846D$|}y(lIh+^OMN0Y`lQ)fcz?)D@tduO~~hUGxh=D +zMr$7sesu)w1II7o3fg;&TV_oca_lbqKz7x{2Y6YKj}gtsO@@ycYcwB?y`N*+eKz?> +z9tM48@a1vfcYWqMj(4OTe4tM?&ESAOq-ckYSM+N8UfS2tTkOzV=g_F0ncbjd8ziVa`Hz +zl_s2vFv==8{IA8V3uUSt{VcZr7vP~I(9hwZ?`p&I`9Yq?G|wOSyXJYZT{|+qtTZ&> +z9ATm2H*Fhyuny~^hRwVQeB4St0-l5)20HY*k@eRiCLiSTT(*41e^Y!kc8&dcm1)B$ +zmye^-pUJz?hL5ys3}cSZ@rS&tb9m?bZh${<#^KwtKY%a3?6|+?%vn@ljgOJ7$fI-v +zI!zzqpk6DnK7<;l+AxO+o=-W8xRnp_>!1&TK6kdf0O_iZ=-G0*A08_sHY~=;sWu!N +zCnwo(WW1bU!`RmyZ^Myu<=HkIKUcDTZEq&Xkv1HkAcxyKrS!BbB +z$#Sp_N2kb>Y&bDRo@m1jQ)Ph-N6wS^Hk>Gv$03~6S3uwErt@NL*OMU|4u@pN2gbij +zgyaDmj^@gCgtOvHbd&GeybayuJ2nh_Z*^5J+C#o%^G2|DW5X!-=dQ|yd&=i*-gr;B +z+lH~9@H-oB=p&!9;qYq=n>XBFZn0sM+uT*TM1Q%-=8YA|TWlERWLM=Ph4Sk*Z=z6s&4y9#ny$(`SgZN>SSJvMJ-tbD_UQRl0j%H5TH +z4)TOZpM!9{_7HQB=ZPPF4s5XYfz2G`D|)<}-6IcvLvMH8X`J$pcA0YJ*aua0n0=o6 +z%sAQJ17r1*7^k1X??wD>#(2Fcux|3Cko&;L1mMY=FgQ%ZG=-2h#hn=ELua1GH2*^!oD~z*ipuy|;oE#TWXok3z2>RXnou +z8|*ueliy|@!rk?r#5nnN!r2z^YEF<>;qi)Bg@#ui&e&`-?QV41UFFE>{KIQ^J?Eic +z1YVAptb2TV-A!Ih*Zsjh-3Nnm5{Ad8TRGj(Sx!TUoA4Vl%js`s&+G(OP7fG4J)q@u +zxuLhkq1TmD-VxAy7I{tmrJQ~aIsH6MPEC~4Y0N`-N=}%Ej*~@zUuk&tM)x$G#@fd@ +zN>1Aiuaa2r=lH|AJe*&({mGTnA5VAs6Weny+QYVG?^{Y{2T=#sV%_zA%zMv~A6mHE +z?)W+KT?d- +z=EQZzHY0DEZN{8yV^{gCZQd#5x~}rY%-jrP!iui)HJE%D6Bc%rFK+U|mVG{3KF~#; +zHF6yIdCIn_un48b0n9^#ibX7uYd=88k|?t4(j!M#(7R)XQUMUqCeMI +zR34laP_PZTa|F()`|v)1V?6QW`H%s}6yli$ys)u;+Cb6#WzvT>lso-E?HO>d8SsH_ +zKRAT$p9ekq4)MWW-b9GtW;WZo;q1%=6I(#{ie-HyfVcta-lD@VqfgKk9V^JRd_oSe|bJ&o_1M +zN5hzh@YGo$jE56tv4y+q%#o>bkcAI*c{^2}VBv+%IyTmH`dauHCx63vvZsZ+{SN2t +zb1dBLcVe`1O1nvio*t**(NOguDGBUMBCi@KnFRI+>7n +zTX-K|My(NR*ub|)bZZ5`faNSnKU)A0Q>l%4gDR$_gB8T_M_0Xf1?IiK|ao?I4bPOLQk +z5%Q+_NAN$Co@L7yP5Cpb4`s>+{Jx)J=B}KBsd=pRQ&vW5i}H`xdvKi7V&9Q@<{6q! +zaCPZA=o06v*J)i!qO1yY{hxjY;avYGebB!a$0qyh|A2>%K*xrI=T{rKycayPD?&;x +z59~E#P+&i9prPSqlvDH7#Q|A>$4Tk~;fpi(sU8N$GprkJSM!srO`p12^I@c+w>U5J +z81$D;GYVjjX%_7Hsp>$w)5@+;6sLh|<(p0aP~BRTSE3m@Pg?jy2aflG9=Gr*4m_4CAGPqX(`Q9D*=*q#`uVYcH&s$zs{Jz^czmk7$HIp@ +zc%t3pT^2sdfycYaMhj2*Ip9Ngc^lyGQLgCAi-J0XwR8HSrz4N*8z-5*92PYK{`@^S +zLy;_sG-JHS8Tsz=dgSAIs5#Uj?jN~xp~b3?*P@SeKd-r?I-p3mDi_O>XV`KHQx0>%4{SRF_2GG3+VBw5Q8VI1gdk +zS;G5>T7PcHIOc(B-pKG6QJO>>Rlf0}v^)8Wda4|oq~2pNbGycpL))aNdC%<$wE0xx +zD~mMaMfmi2K&+?gPqUGS{i(dK=}%@Jz_X6*Ke(4)+u-?uJ_6l~QKp2?&uoL+3=Z7? +znXAmJYdlg(0hX`qpM(puTnO+)}Pzq9iffPL%2H+i1m^i +zEIiM*Rq!u*%PTEBmw;I)&8hoFWPyWoN3_;9eDIOc>&-*AdjH~`9U4PyFRq3Prsvez_a`C +zMh9X>ej%#^^E&H52kRw#US=IwX>h#Db1}C6EHgT=OzQyc71LU>=)lXxhp+R!*dANY +zO6b7KfDVY`rN=ykr|H1)@?-Ep!P9i0ul&HmQ#zn{{x`rcFuZLJo;iy3RlNO@;(aTCr +z`yGbfVuxPWHl23_^ezM~zFt;CFRPVasxeEgQAG0PeB`;`@Z_{0Ph$E#w^!dbeRY80 +ziCOo3($F)2JfW|{b4u0txxUVH=vPI6R~XZeXPtm2r$^K~Az{9Ig}iC{1)t$Jq#;|r +zXlktA*;T%n$p>GlxvP8)CLi?w-mdb+O+Lu{$Jz3MF6w_3eFn4ctKOl&S)QWX`|5qc +zY8_VZP+&YKT=^Rq&ly(lP;kzLFy~n-4Zk1e`5(>_+r7x1-puNiNANIT$;8%tZ-)`Ryz1~NB +zum_isr|z0%TzY}r-VcLs0l*|K_dKK+T#XUjJ2L3`ENvOjb_ +zTbAf2??t+{b^YbtHr&u(ZnI%gDDSl4SfRYbhH);Z0pTp?Dc~2KAaAvK!zaq`*l>J+ +zyvc^~p3b-Z@JaHUHjMWmzHYqLmBXDjt8Cs_k-S`o +z>v3zY{9>naoz9#qetVqnRS1m9>dd*mdt(^%rU?2RICCC#?%w!3@x%6k?`h{fzNgPC +z&;C_#oQZ_h*gMmddNK^}{Pi;HBnVeoy+?RM5&Aj%7Q$+sWjfl$aBwdMeUE1v +z*go!+Z$=$F3vTl%-N5;z?^(F3_ldB)*}`4_3}={bwD8p0BXpuzUT5K{wMXom6w5jb +zPpv0I79~oayGbkB8B6C&y%#M}eCdv|%6{1S(m>7IFPQV+t2zFDKG*j2s;lMlW@k8JHTV`__;dlyX+HA@iY +z`B?GJ#@S^;EK}nr#uzm($2b(mRiZ^}^*aywhF_&^t8&+(?&ZUp$=TQm(tVhy4gzI-2Ya`ri+X&1m4A~_ZqY= +zT!TDH7XstaK68#ky^F_n<+8wd1pePg{u7SzPT^qxx&;1Abv +zCushBOdLq7bLjQ`Q^3D_1oS=vTKsw@qyJ7$>zDQHPY*B;;i-OEFA^p49t%(P%X$$V +zBJZ;B)VvA#hsZ_?cjwOGq4G8hPxV*SJ5+uL@I9mz{qpu#&boL!aTAX7^J%(h=82y* +zI3~Ngi1(e8E{@c?c&XvJ*E=;vxVpISl*8|PCy@_U=SM>}qXRsLt^U>`zeahY9M_U}D*g!G+g0yHhD-8xhACe)2)2pokad#w +zlxGnUHfF{E@!*Twmk;sMU?jgI)d4ySP9eZ4^r&VdO3+~BM_E;G(&49-6wAMe0acp@WYPn4y9dxxzDd`k8cbMG+t +z8nd+VQG?I+n_})`ffp@V@;?yB-^lw4jNBC8!y{E+{=pmIHEj}X4P^Fi3uLC-I#T`x +zX<@W=A)XyWM0*E(K#ng_eV1c%DQOtOexb&2jHPCbiDQiycyLF2A$2Do&m{6CCdas* +zr0%V>c|$y#1UhV5GAA?wYuKfnpcufYn)f0pIDwhx+kBseWp%iF7q*#)W! +z_@-AQ_T#=yq)kT}+jt+J#lqiwC4Ygs$chVef5 +z9?uk(!CXt8=ngr2Ri0PAn$vfys3Ll +zO`D5g`(OjvZs>Kho!2}C9)@|>U_{7W#%|q*`i7uw8^=RdSTk09#QTU3Kt8taw0?tk +z5*v_4dbXe}+qM>Mq274#SylPiS#pyqA8G%x$qS=U=<{G$tXb^+@-xZa`kq(bRTy<_ +ztsp+|kTSRJy&dhXV||&+HhFmGgJbu*sE=in^q(=Gqdda!m2vm}#i}g(vQszw>Fp>t +z;=9x}@M=j{btFzwb-Zwtb*MdJ)PXztv(te)14zfCM_I=cJlldg&h4rW%*|QHokv;6 +z2%L{%9jA0v2j1~#9XB3j9lTeTb?^>fs{@0e1Jt)`fs@ZyUt=EJ?_utT#vL?ItA73n +z@92g;W6eF>6Z-yGDP9MUl-e{8>xedN$6XsQXF1riv^eaUjTdvh3O3EgRer1^`f=J~ +ztRLEV3-e<>W#iuQh!0K0u`lbV74zPyQK`5pi#^Sb-ss1Dg}Q^9c)V7;Bi|Qe&64QE +zB===|V=NI~?*#I}HtBH%`57)6BWf<^oyp9zAy2J2`fb4;Dd8L&eAq;RyEby311}}- +zHs9Cxl>NL*d>`&I?to9l-_4Z!=vZ?Sb`X6_-_v}HsEO15IdHG1*jv1-R2GBxxC?m% +z`Z;NBW&5KTyGoXXCko^d$OFHrRA4+*Z80#)?+Q~F()@d!nYRdIQw;W@=uciv7O +z1av`Xn%(ws54=S4>WFA4{};3kJitC7e8+i_+Qb}D8*FDA?i=cg*E!&I+Z|o!5qX{E +zaXe@_QW>l93_dgEtL~Le3kUQFa-m!k$Wt^?)cj^o$6S`**JJvA>f^!n_t63uih-$U)zK+vnVz-IV3i(f +za>cf2ZaJRbHth50`{auv?PFo9*lt@-a)O>y6pIi(FCE(r{hE6!?AO8d&nSO`whMRG +z*LD=)HyV8&Kk97TXd|Nre5Zi^9{RkP0-tga)`r;UQ3kwHeFtqVWte^b)9CZ6Zj=)^ +z+r%}%0~mPOIN7;GW^5rL<*2liV93dcjhfxY%3 +z+z}Q<-{PZjNxU&Z`_dhY5d +zg>M=4k6Xq-^4W+DmypigPqGhl_v*41YI>4?4v43C^w3N4)rRiN@x+}%vIIH|pKf~?&kK~li!uXH2KwmXT?f@(=(nH` +z1Xv^Jg3Z?W*$;q+yhzIjd+gJ1%U`?;Cl=&>8`ODdhP{2|Zqt|Vbq)OFC$ +zHD*gE@1^7U&T{mBAIAKEHM%&k4^Eip!mtNU81cq{7vG3X!z;d^{E7k>FKl7~?BfVN +z>05vgwQL*pFi{j&;bjOn0H5NefxQWs@}kdPaxxz +zf0A0aQF0#%xsTNSrxE)Zs*RX`U=2q3$I1^vnEDq3PD=yqekz^1i2ma14a!@6Cp{LY +zg2C3bSl%%oc|6xs-*XV}*Uc{DIVX$@wE5&mlyo3G0Q6mt{&j-OThj-8`Ph14yINQd +z^RHs?z{B^M1fJAE@`V0?+Dq)M! +zCve81w&+@%5ubuF0?$34!E*!roC*55obgqlX{>(k`81vjk$;SSE@%8wjI$&4bI*l% +z&V){c^>aDn=c9a~e(tHjbGYUa_wuR`ckPDKNsQfAX4G*Ziu#kU5sYJs7Vb%5FVxRt +z&T}O6UZ}Q{=sOBJeXQV|?hU +zFiid-+!tZL4W{o#(00F#*eA5<9?}!o8-!d_I%wNXINpc#^RnH91=~$nu-$|mM!TVt +zdqr%tJP|TaVo%xDrECaz>!Ba{?Z(^*=}oF1LDxmDc^4P+9i^8x4R%EcCr#6!$|>G6 +zzotRM$a}&x4H`dqFYvyvH(2ynX?pD>m4^3&{WQIfqSNrsM_S!{M;P+*>^d_HnnZqd_O_ +zpVc#!o>Kr=f7n&qS9F_HT5gICrn@{;>D|)PT^_3R?&;|+ADNDGePTn80`;`AU_A~$ +zJ?aW!QBmr*oBbo-=r7Y2I%&`k`Uky6D==8tGz);YXP8eU=ooYG^gYxs4t +zy|%w%UnY%@?929jd!{-46?1;oR@Ek^@m>7Buzzmd#uh&9){V6lTes>%*q26~%8r)X +zdwPMV4mOiIu){5j{kgQV*o$IWA4Z-M7VLk71^XXi!Tv`W_pMNWqth18(6QNVOHryV +zYRn1hK6&TpzLF8vgwWnvzrC~#gazA17}~~mc<$I@c=Bbp9fMNsQ2ZRE>PYc~br9z8 +z1lFx{Uxj|T?M+}kF*zqv+wi^b&5nJqd3AV0!)@X~^qJ6xoH^Vp5j@{2LcPVhqB&uH +z(ir{OqfKUApeIvVfwJVoQQ-tXh%<3V{p{$}?S6a2hHi6McM|X_z`YHPw-uwEC4kpq +z54U`ShwW}Jy?u_26|k{I@W;2&mqObcHIJJ)=eBZU9;N4+wq^_W=m!vn^?3^uc>lJO +z9Yh~>d8>4R#u#BgujNh;i5SF +zE1Wstb7m2q4`F@vME!i~R6KvA*ISF4kPr8tyzALqr{Z;NjJywWrGI$?n4+)Vvoew^yBCgF|@;vhmjtXd+cl(g52Z4tM*J`ugdLxod{Q% +zu?O{~#vaFpAGY13UFI1X+GPj7>8qs|y7&Wj8M@P7+1O70L8!nV_h@h3v5jLQ^dc?Y +z^${Q^We>ESZdT)-(=OYGOWbxjcA9ki_QY-1;r0n_hZH}G?VVHPw;880+m6SL?J(z| +zgLA!r?bwqrwquG{(|~tlitt=MAI~vfO=7lw?)f~PL%o{VEd5;0_(0_691hPt|Bh$A +zR}-J4pUWA~MSO&Q?zt4t1F$(m^m94m?<0P)e(srv=N{-G&V%x~obd$o5Z}_{bI-rw +z`INC;FQ6Rs_kO;U2VN+Dy&^C+RwzA6^=I%qK^VqHmZ@`iX?3g7#Wy{GZ+ZrNgc*Fv +z4ESzz@##6K>gUQh_YGH^ONtNd8PoO+aRX#GZ}xqXK=-o3Ah>8^im?YqY5+jliTB+RkL{^WV8txfowJC}0j>(&+p=jx=(%8+TUeKayu +z<4bDJUa#i=Ota%#YVNMnNOOu08W!+7m2bpyg=)-KdDOT|*ce5#E{AcKb0wvdOw(hx +z&QBQ=23;XPS{xZy(XU6};d`P?Q+7hn>os1>56+#no@<=66@+P7Xc%a9=I6RRXjC-l +zxpysOr1OGKl~?;E8b(<%-_R6Y9&}g1hC49Q!+fKJmal!U7wu1)etVTmkDe>*_E>sG +zr_;kV$+UjRbS-0D4(ZBgB3$=h4X1qV`U}%snJ~@Do@wJ#G^ja;TMlPTEN@hrTW*Sz +zM*Rrt4E?rX-(h{>l+Fluorq}{Iyjl;);H5hOZVS3&D6C_^$mCGgWT9o<`aDea(#nq +z;krEJm$Ce)KzY|Lvdyq*)X{QR-bQ~vc6|#ypVxIk-ktbGSqIy%=lZ^W25gkZmB~iw +zb%0d4!?sWu@m+8t>uC3O>3SPjor@q%7&HOcRr!tb)1*L +zCSTx|)qebu@u}!2`NVQTK3QAEG{@$vd8X9`rs;85x080s)lH_mwiD?}HwlMsvTrv! +ze6aI|%>KLmzQEzl{SW-v`0r7#CVC3|WIUIjhUcX?&&|CRJogO6^L+U4m|GUjf?tol +z;1YKn`K0PdQEC+u@*=oo4vSV|rtJhAS +z2+V)A4rQ{{X8vp2df2v_<$`)0q$kr@%5qNsSN$O{^@zgk=ei0yhE2e +z+;M{Cjz&*d&e4;=+NW*<$JHPoSdMo%!Tx#n{WgT{7?Rok>Gcbqf9Sk_t@rzR7Uze5 +zg55Lw{l)q9cn_rsYr@59P1wU($r9|#cpHiereRH(@8J|fZa9xQBZN5DwG%i`hW+Ix +zo)=HzTo=Y&J=SC2UBxjM=Q|bV%ul^KhdsKt~x0B-uq*t=*(f8yCp4V##1ixA)=aH(|DKGil8W;)ji>tM@m`?021>hX?y?&+)b +z5OFRe8qqJ>(8n#oZV(!lqd0t;o@TM`7il~ +zm|KN!VHM-f^6;h6hY-#W?+RntvgmnRj_ro-_2Zdp547;CIM&V7onzz!`5VER*D`%h +zyvd#u&s2tIvn}oBoVh9=O`S9EvOM0y8R6F12EU{P_5K)rH5cJK@Z_1IMm(eZ##j7o +z`Dfeodr#-j%a0 +zLpkqA@x?F4wz+w*$D!!@1@APZ&T(%Zb6ypOPfdM}L7$=X?Fhfyf^d}Y{)(}(?M1w| +zgthZ~Sr+NG-*|d$8}C1>Jq^5zHCE1mEone|ex&*5x5v@FtaLd1>$04YuX;a)I&0~) +zI&0fV9u&jhR&>P2$};HPmtFdKR-L?X>BqbzNdFc?|4Nocx}qQa>O_BHtn6**Uw9Ps +zoBsO$iFW90m*qR@h0z^L7t*r{gTBl;42t~R_ER)@WM)lVbiWFGqI1xG>S|7CsN2>K}Zd{^$6 +z3wDw_=1)PnpJU`6Itrc~Q@L|4NV((5IVKAq`T&TIbkQBVBQqu +z$=*NczVHi_{iNAF&L1)E^6sV-FEFNm2E4f5Ia_G4>dk9jI~Vaih^U!@)d+%&dKp@g$MsnkLhQtZw*X73cCL<+lr9!Z@am=fOlLv +z>B4}{x-i1%!iQLAInsV{OmzXYC|$tQwH4(j8(G6vY{cEmad-WwAOlYdI`ia}7qqRo +z|0sBJto6j)C!=hI&kOqh;04bC9;u9vH9be#-W}NQ;<)LS3;MAo*tch%(xc!<$^T*B +z-nNbRm~hS-B7JD@!S%oDbPmw+2V+C2vJ+g_iQ~PAv#_p%=gjeV^4uTy0PuWj9G*Du +z7apviGa0`d?@ZwQAD>V0{f!25wg%?|!?aO`5s*D;Zh!^X1X8x?o`}5}`th3F|A?c%HKCaFeFr2IJz2Axb8u~EF +z{Mc+oBmC7b;LhrqE^iLu*IC{?`g?7c&N~X;*nWJ>_(Pu#{9#|Lf{j)*!7iNyUf_Ia +zN>2{q&skn&-dx +zx40+zm*~@~zj6)h5dNO!)!BwuO)Pr|nvJdW`_!@08=qJ7?_ir0uNcO9m7N!qTi)PX +zk=KDYSGl}7g#TlC^XBuqPc8if@utn{FMS`|rv|3_)cN4W_)j1`b(V&Pb7TQ%=sb?u +zJ)NAV53UbwJ9rKH0PTg*X*HIaz9n{HPhqX7$=fRCmSb!w4o~c~r=aFl>_>}%gXP?{ +z(8Vdg(CSL1(Ur6KjkhE0NA#5sRpy^GSiWtKfcJ{>E2eI><O~=W*nVJ5~HJ4-9&U+aS%zJ%0BNJpk_&dwx?~D|GeICw8 +z(>3sVtXyMwIPH_DYoN#KTAib7zrmfe$GNu7iFD!ajW6Q +z;!h$kK#%2xuNUCOd$^Z=tjmkZ8F(?dGcPVNycl{Eyf~(P4YZIC%04rUbprM^u3wj1 +z9l^fZ-Qdd}t}ogCg7*VEjcF4)^QEuhi~6R@5sq8OyuW}Rt0O)ypd(Ac3)}^f;sxFf +z?8FPai-&Paoh!8C`%_PA+i@GqBAxH1;=HcD69aJ%=j1<8V>@ZE^D~Bx?kL*K8j}j+ +zeFbHwnFnLOvd;`-51(^0l?QwHN(TuCU(|TSa2Phc0C(y37R^X+Zp+CVQDyZqK0$Ve +zEYz8JtCu|E$*?IAbbG-yTRxj&(UW}DHaUXu?_0wtFI;Q8S +zJGu|9f5bnNZS@R%N$myV{htK){`ely8F=FTp9J^*_#V)3Jo)}lfqpJ$+`bny6YuNi +ziMeKv>J!1sHoH!Ggf?k`Id@_CXXTKU`L8=$wT*b^ +zDD?7Jj3YiD+2`yy!m#!8bzju}8^iF~l>f#s`gZ!-ObBZ;-iS8nbQSol?dBwT9Q0b* +zTg%Hs?|~^^t}?t-_Vx(ne60Go&(A@cpK2_2`GK+c*Z8i%qNC7{V@^{Z-iPQs_iqZ! +z{p)Q%a{8KI&dgK%JZ(7hz;hi~15EX`L+=ANajy9K?{r_oMQvP{Q1A2jIy^x0pX1h# +zFc-T6_ConYctS7LdmW1*htBr)F>~(X{*x=#i>Vq$owZ7QDpg#CpS?g=~=hb(D)t8B8 +z58u(3PI?&$$-~x_QMg0d(G}_>?z(B_7>j<>tm1_xj(aLp9P9ro9q(8(F3=`1N~pVE +z<9L^u`h79l>-Q6#_4UudrrhAgLh9Um2;-vP9;C6~s_%j2_bO%C&|D{d7QR#D +z<~bkjA%4*9<2QL!9k{bV;aJ-R4&GD1de(K3XNk(wjQLCI-9^afHy?B;p030^*r&nR +z9?Q>$Q4T*jkF@;6e9Q8)(cZ@r;O8&B06#fDpNzKRjPOg~XA-s!cVTZA`>%cm?^xcz +zZ#YG1_YUMVGhYsPOTJ{vNB$(SN95(_tNVX)h8{-VLX#KYwLK)>K6$mOtW-H%QL)%sS{7}vH_)eaR1CPKRM%2*+?wR-b9fwXBo)=RWY4gEHHFj`q +z$MU-@#qVP5m4f$b>~ZyXL6F~EC&M}t_u|rM0H49{Ct0uJcPy`2<-=ZGm-(*M`Esys +zm&QK_pD&kiNhxvWj6aOLLrva^hmm)<$vfpR@{Tfj!vT3`YVW{)wW_`NX279oGkHfH +zM&6-1ZwP(7OWxj+r|ziCq!+j|Kc!=_P)!5x@v}O1dq{nU#g7lheQmA|_VH?3@Qs0# +z4(hwK!+`m9#k}k~$n|ThgB2+qOlIlxEh5n8xfg)7a_sk}>x}L5&_Q2k#Dr3n7h_+V +z3^L`-HF+^dIb_~z2h}RP+3bnihJ1rJn>}&!7Mi@n52L*UO0pBN;Anv +z=>p`DX3HNDHOKANwtSdd4s8v?PFh>u$Zua*+rqUME7#E}x%%(#BcE$qW(4KRbu_H` +zg!mm0XG?DXGj`_aRoljv;5A)uG>wl}}4tR$?!~F%RJ6$X;v>oG^01f!A$vE_9wgdG1 +zhO|D4I|wF==4!}pPEW+kkZ!(v9c5oe7|+5s+}+=T^U4Y*-lM+?ZAm@~nmEU42+3mj +z^4_{CeA|uRa4UP>{bq3zcPVbinLQU)&ig@k3b~cv+{3qI?RPorXkW%*Jj49~#R&U# +z#Bws$F*Zw^$Dz#%XCIA6e1z|I^GQqI`U4} +zc?InRfzr*|%a&K;{5VbG$#W&6DH%rFk*5FL*+yvH6CZO&| +zNGtV%e20$^Wg5ch3+j8ETc5_kzx}S4r4!%#>WTce4$kYzgDSL7nD-=($9GfgH@#G!v)>6;3z!a@Tsqb&FeTtR?75>_`2i^2xn7jJ)q5Ndv^wYQ&j(b1YH+>lM1J>x`z<5en +z8eWW>gpqG-KfmeX;{aZJ$CwWTUg6y30=d*G+Q56{nVa}u`lbu#bsf0lCGA@!=r6Q) +zu$SsvB~zgPuoJaK58{3+-f@j*pD>P^P4PJ +zk95#hbc?6%o&B53BkCQ$p@eUE_&lOKsEe>uKFr9k1@_2?!5`(CJMF9wivR{4OOxgK +zfE9Y_vb+$m@%qjNzwAuF@SPOZ2f%}0Q}6J6!aN@jwi|WVVeadf$NCTN_)X%w9zKk; +zpzd-PMp{sJBkth!^HH}@x97sBTd1ST|V)44=~ao8gm{QPjxhKM$u) +z$RCL`aD3x?bgBE0vVC`xI_|+PN8l?R$#*yX +zz5zXh&Gf&!>BBL1B|LmY-`&*rTqzuO%^CgzY@Yu1T_yZNJ66IMnQ8kT#$|!^1o~$v +ztNX2m<-ulH854&2?56G*b75oExNpZ?jOzoy!$hUPdv^M}Y69yDKYR(i9HPhj5ctHl +z>2IiowwLsYY{Q!Lwvs;OczSqF!!v~EbUbsmC2-%B8Vm8HzhvoZgD(>Fm!ADK>QR2Q +zmf6Aesc(G!H@`_2xZ}$1hwkew@a=T`^7LIYu+60jz5cJphG<{d_6NP1r?Bp##)dxn +zIg|0NUQL*HkK_3i$A}+c48Xb~pEDV6z@8~=D4$Oe&+XVNg{|asCgU7Scvm@|PaTh^ +zGnPakn;P=dw2MBBXYRqmJCXJ7zKPNrZi*VUiq%d;KwoD^xPsTG8I9*O1g5ofhWl`Bc1lK>2e;;5L=WYil=K^8y&c2ts +zuXm(9<-b0v_K5E5CT=;nzQy?X+NZVt>~~b!4wKgG?T*uTQ3fy|_OM4701pjYpLCfY|8hYYQ}+;T1OQ_Q>$ +z`qA~=u?l@>&>pl8bB!3rglpKg`DpumGgm?1VfgoM+u(oEe;|!v!l8#)Gskz^AR~P9 +zSKXlr7^C&&2YHKc;~W~{<*4s)>8S!e5eH`uak_JO(u+C#JeP)B +z%=Zy%HqQPq7x^pEhDt|H2-6;^IXcFqB*rYRMSO+d=yc|^#en)g+mJtk +z@o6e}6X&}~D8s!QhQ06<$@?|$M4q}HvE3>?JXOAlxDB@qsN=r4$}f* +z{Dr;H^-q!ASjS63;@r}9uGzx3Rl4bkNzm7BBkm_p9s6Q=$~72ki)inFfA+bo%lM%@ +ze{mf1;NDe1KLT*kcJ1sfj@-%9;LL#F9s_9MI;i+^ +zY1yp9e%S4l7y6OF$#}sc?#^@+O0G0&r?tr^*`vbNQ0IS;#2Y1i&x5-$41>ex-4p +zC$C1i4r^Nt-{VI2#oh~>;fJVxNd7kk@Wu5ysNc@>&`#QYUk1_h{Q|sd&Ba)baR@l+2Xx=Qt_S!&0DK>y>x|P5BK&tFd&T>3 +znGBOR%mdz3p!5>^Me{VXucC17s%U@ZG59GMLv8%iz?Z}t4DG@33|qf2aju#(xHQnld+6&Ct}}&& +z{1$L2JP%g17oab!MtSlLeSZY=csTEr$SK$!1DvuL1s`ZGyY5V}r-qz;@zeqcMQ1-KG;3vQ8Y@H3c@_y1_bOL$$ccR(FXZT?8T@=I@ +z=_Y?@@hSdke2RudH@OLE)Th+kCUs5${#-M7k@D}1U!-i%6s(<~&Cn6ek8pRnAGj#L +z$>0^9yLs1Dl6%SUy-Of>^tJZlRgwMPDzTq=EI +zDYHDZvlEUf-D~dod&k@;(v94j$oIC?Y^H2Le{QbcjXRG=Wd2&0} +zrc!-J=jq4*OX{(|iQfSk278k#W7dnEahl^>8^<)-J)Yyi9BH*GW7m<*z6iz<$i9_p +zFlruM6r)Yu&N6E49P0%)lMeW%*8jBnlk#WmT*&u@e0(L)L4^zJ#aw%cX}$4Z=16}+`6B3W6?M$?p*Z-G@~JfcsQ-#CQ6}ePC=*p>?0UN{WAopZA%8;` +z`CrVCKh{P5XAY6S2;cEOxc-nuy~sCApV`}7VIy_ +zTFliV_pJo_bEW9^*0fw9%R4&e7K5)V&_>FQ;S*7Y^8$_`KSLX!2kng^uBCWyklieaV~w+ljXVZ4uqXIf*6H+T{UJAOty528GI1$_O}cxB+_nD@Exdrf_B;<**Lw7kta0_6)_ +z??d)g;B}ZbPxMq{UmM0wws!*Bm=NMYwjVy%>?eSug|sJB{^q&hMIxsVHr10;kQU1W +z@37{O+$ZFITL9QeA;gq2~Pqyc@Y7;^p%(!$+!Uf`bn0pdG>x2mav?qf3hSuR+_B7|RxbU-)hku8fK8u0ww6$iek` +z9Qy!1@N>}DXHiE3^%r%-z-!VI%N6IaKRyZ>6z%WPehc6md%*9wEjBv_oZFFyV_P^^ +zJV?4eD2TLw7O+Tr$9S~0sS544I?FbVMVdex{s^9vSJRk|cro<41bY3fkyV{j?mfVe +zr~j{Q8OYI=VSOz3E0b12egS6j#Q`UMV^FV_@1xruL%ra`Z1(9o@Qd@VY2aricq!mF +z3;{0{Z{dTpA6|<*8(T|msN5j7g>?HJAL|#}P6w_YSSutxWfy?|eXbFL_b=nVi&r+& +zKf#_YZ3TP<)V(_i9=74z65nFGAp0uFKDjwkS{D+{lo@TSXx)4={q{83A)l6=w)G#i +zSh^nBHWYZLh2pzyJ19@usB3_)3jKzBI0rg2G*952Ht3<53vEGPjKMCwvQtRX@inyd +zeEisEwvlaJNV@T!4c9iquv1as106RZ&rLiVum9?`3~{_>036WcY>X{&-I1^9R@elHqwi&b*iNm+DAQISRNK*7FZN_EKNF@8}r7r}^&2cJ`;GEgb`F +zyd3dGh#y>k_qJW&&ztxT3;C6o#P~2QHubIPx$+Ij@GXo{c^>9qhL1&_Scdg-xg2~< +zT$8))MlaI-c756Ic}@}?f!BH#z@@-*@o^oI(ucYt$dyjQMRoI2JEi_+=n_aVf$ +zz+M%Dmto*4Zs;k0fpUBwgD?TRTr7IYhX5lU?xj?sZ;?kF&#^8u;!K?F;Mk2Zar-5? +z;$rsUap1$xLIpRp!?u+IPwDjDkek@s7K)S>H}sPGk@pVxamk#492-YG8Y*~e?eU^N +z*L&K&xMt!SjHkCDee-$P`@}ez%sENr`z~P2=a#EOI`grQaLjIpovcGY=NN8nH0xmf +zgcV16OTsbNh1^r)75h8K>}w$pL)-Qkc#8QI`_ +zqhNbm&Iv00=ZMo6cqL~5-T^;h1jqiD3p`2PI}!50_sK@Yy#43yM14gMd1r@VkK2$| +z4I4f!KXx+lt9rt{}PPu+oz=Yr1mWx0^0*!~gyT*zZ{NYvc?57BSU{kNRF=CYIf +zuL*hmqF;&Jd;{v(k9-Yz;=xk1pW^`Kx-X}2#7T&Q2Pu9&dKD>+4;Ud$MqKK5cxcVcn)@qr<@jmF2Zxso&=uvze7%>zc}7oQZDUSOa3S) +zcf`jdVGmK)AdKtaA!s>4(J~OUKv!pfyjV1^MBTAo@GEZiFxH6rY4H(qNF+8J&OkeO +zy*;O1tQ&~EjzdvCajVBp|naIfF(heVq`{SDxj_Ad`hUW_moRKWX5Nf&7mH{`#X<&cE2kyE!qws5uYiy$|8JIP+P8UoOs-ZT`Ec +z`P%WKUqzniN1tLC_H-YMUwiVjK8Qo+S3rhQ^n)b&5%&IT!0)*w$P2r>>`mC(E!`uf +zQT!M$hMt#uVtlk$q_hz2DiZ&Xy?X((qPX+_-{;JQ0h)0@R78Y>f`Xy~qG1e?xp7mJ +z5%97JyD*mnOc-XyxyWGHh)NRor%7M|K?8^hCdQb=T}>7fHo;30vuhH(MU#*O5Cx+f +zP1J~yc>bSnb@!P*!$6YV?EiUwzvn$ZQggbhtE*mBU0q$>Gm}`Nvd`83tM69ZXdacV +zm*&#JSmEXo!ThJz^3l94q5BWpC!w(@zK>bicAFEL!$7SUMfpV6af`n(b}UO9^o8Jf +z@pQxgf^>GiWb%6JcVv6+9kKA7S$&hvnM$22FAhuC+~sMrGq2$)(<24mgq!m2nEj0M +zf7ILBI@wDuxnF%TZ{@1lHxJ#~TIWA9xVFr@qI^X~-^qu2T|0b5;`moIkGE@C`4HU; +zJaE(C$%lt&dtP>X&7@%a@D&BePnJ=G(%0-rSUX&6>FeY@Tz_BH;=ZhQv2we9Kdd}= +zoK~Fm`#*iG?90(SPW5xY$0qZtS6ZOI=V9~3eJ|#(v9-QD&D&l&;Fa!wHNUh`eZj`X +zvOi@m*z}eie319e?lZUg?W(dZoY8_S3cPj|wXl +z9#Uw>8K-WlV+eX2>X!YK&d!;s?Ij}a_`O<@4X^pN|drwNZ +zd({13$uG6%{~u7D_MTLpGcUheeb)JCeyC$Po8!ad7OGE +z?*6O2<#wDes-L{9;})u)oTB4-3GaeO)KB+(y{fcUePp3VFg``6}oX3j1s{jtiYd-t<;YHV@y(=*F+=BIl#_S!g* +z?bG4>L*;O7x9_|urF#c>YaUg9+oNk!#gMXpK2PQRFZHR-R^GfmIp_DAy6$~X<+W>^ +z)=;j!M{AMqwH18Xwd3TV9rqpQkG@PlmmAH^7U&+u<}bqs4VyDq{bSD(wPlIc!<)T_ +zmnR2b`c7W{eHZALqa1!QvF5E83)W12)4TQs9pe_A$D@XM13cU3%|vOh0U=k_qlb5AvOnfPOltDl)n9XqV(WhU=DYbbpuJ_#TFZS&> +z+S>h#VY}~JQugp;HrA`{HC8=+j^0y$Pwg1Yi}LTYescXVJ=;*b+8Wak)iI@hV8^mH +zw!UD;yDmB8(v<4#>2F>qlxCQB;u2e{wfmNGYiG6b^FzG>L)7;6GY@uev~PfZe~6ic +z?fDDq?d|bw>)F1Y%{rAgmwDPdI(cZjM)HenO=aBlvJL(s&ypvphSnn-c +zpNRT{^0?sh>JK&+**IkH2-;dpWN2+{{l?-yD2u)76Se9S(b|*7`(T{Zy-vI@Y|1;a +z?+wWzOKuC>EuNp9b7kt^d(_7IS;hWV&%Mb+U+d%Z)vkNxx39VE;U8(=y1c}#I>u9z +zwY^sDT@kkTca_IZmDlF9QJY#D+$Rs$t{M;XG`F$eN#1=7dQoGujYDqy39kkFw03D@ +zy6!{nvoYPqb{l^(U(t0>W98T6wjdmPx{u4lH6Mz`o#wi|SpJ`h#ck}LhOY^yr58B$H=IOH%!M&in +z_f6bq{msUy{Tg%j>GyXOglmiUglmgiPx9v8t^ICDCfr(Bsq!g(CUtA7Z`s2;kM|~A +za9r8Ly5G6>9R2*no)4D2`^P#xJ5*b|tKX%hbMANL$Lo1;ue%2SI_drH6z{IV*3b8R +zO7D!Hr0tWvclT<|!TdLt<_uIcD|dL`;k9pF3>abcg@JG)OUZEUsQJeUYnDtAMg28 +z*~9sR%C7hHvn>Zy#|HINJy&}7pyt&3bZ$SQbGvTX%BK(9>^=O-qGaj8CCO5&^8wZQ +zTRSov4%}?d=LhQ?w>604?>i9s9FRr69QM4Uu~f&my!L7x$J;sS)^_c;Det7dgXDad +z&P!iECvDf8@2Ky+qcwqT3O&VH-3AqTQFFynWe?ljUt`kTy!@)stMvYT +z#ftn>QbmcrW%<(b^7`uMfgT<<&%5@kYS#t&d6~C0Zl;d&9-gCo7HC|JKF`u;8y`NY +z(2Z>xBcrj++JB|CtNsH%u5h!;o4Gl6es6P?w{%}yAI?|q`i<_9)K6YMFSzz=yuPnY +z$E#gkcKs;zg?f!=pOVohbk?}YEJ~EV +zyd+WjQnSYGHeI`yB}yw*j&Brt{lm2-t=|N5ptqM4lzv8TR<}JGgQ7JhHxD{5cOIlM +zNAsW)ve#(q!>XIRKHL1q)(~z|zj))@nGI1swnl5${72-a`)S +z>ON?)-YbWTz~?=o8Rnti&D7=5ZY +z;FWNmuXE$tbCl)+tGwPxLK{6@Cl`0a{k_N!lvEYaF$;)Gj2>6eXOr7`SNJLhk| +zN827aDqHsJG?>?}S?yjQ7?g%I0ss+bg=T +zT<>62zA=AdO)Akhp?>433>7;5clBJ&)&cDt`l;%^SNB+t>fR!{E?PUp$C2p%%KGA? +z-NvFfyrQ7<3AK0-;O-EU2ov4H5%*eoyZv~Urkc$%!;omOl-d) +zIq=mR6&E-JYxreq3wIu9e({pZ^0KbQz5E+zuadKkanX5U=R#nUbZukzpD#a{-0s>& +za}GNE@;R)+gM8Ra)T*uEg#ZqMr7{+ojR?cGDS|H(nRtzo(yN_V%dee3=* +zrE96}cd^>kV;R5LVRZMFX+-tq}@vu81GZl&>6*8|;O +z1@GhN+O6wEGMHP%+M%E7VB_n}`Z?8AWk;4hy5F?5zEx2KYhTm6XPfP}GT6_a>slT1 +zQo-k!_4$d1yS1x+#>M6*-P_fk`^U$`gDUfPRiAqme(AE6v!^QGxQ$&$-MzEQ`?8## +zc(-S#8X0tV>ZxwOQ&~5wtk!-ueidHYwVrI}YE)i3SM6E5jUm==tZiO;Ft|=GQXe^> +zHtnT0-KO$%UmwtMk0{H^$Vcm>H*|K*r)?ed-*k*%F0JP_I*!e;?K!FIJ6bQz*KusF +z{+jwijqWvU&GfXsD`%gs`@nr?CQ47!y3>niCrWS7ef-|@5~bzZeunN(`e_U~ps~)@ +zS5NoyZ@uUG`t7Uq?$`~<{3YoU&(`+mzNIzTJ$b#dbL5w`_S$T9(mAm}{q<(uLugL= +zbiIDhM~&vjBU1T&AHP1e{hsR=Y`-VvUGZJLp?ZtzTklQ3aMj!s$6K7IW7HMdal9on +z)prtV(|1&_JzB%v=gzO-J*MGm^WeSC@VP{{HC(qYtnyh~Sh;3|<=U!wvgK*(C})MP +zHYYq?+iae?Pw!&xYxCCJqxoI*KBGO)$=B~Yc=2`3`}Om%Q9EbnZ7+Ijtc`%P~k +zO6_@;ov&WWjf3r;p;mcD_Y5|^WbYaD%qqHPcw6~f|IA;ieKq&ZmNo2;c3rXYaliVd +z+9dmY<1&qrRV}B^DOkB`_9yhrX`z)*ecH~aZAFg{c8)rS)CaCu<@FzLp!iWaxKs}Sa0^R=Vj4c*vc6_Co?BkUfnCI{hqe+ +z*!|y2Yx6qoS<_Q0%T~>Y&F#f^G#}P;rqAnsWq2yDZ+Wuw!r>E7os(4EhNry#H>rN* +zMUM==F?&CgYkPMz9%$ZV&jTad;c7R_!}cGpzjqkr@w)1>A#^wMsfWG(Y5o6wJ!iWi +z)&^gA;O4=1>GLNP7mW|w9#}Q_`}+CZwEj28RSHM{m)1|rUu{(*)94vgd~AC~?f0_U +z;3drm_SbpK52$TcTYDUBo*!$2MwQiFM>U>QXssb`|B#I*8Y4bo_HHcEI}++Ado-5V +zxjaSf^|r=@J?95&7J7%|zC$|CZq|CmOBzr1YYZ8p{Phk@e|z3w&-V9e9l_e`O^q}5 +zd}g7_Y2(A2dd`xtHA1aj)DA8C=b!#t^sY$mGstq+mtxN#?OfM85z+G+d(Lg|30@f0 +zOZ~s9I@YJczHfcr`jokrs~^X&ueMGxTIWDQ?>JYiNSv}a^C@@!RC$TMH>n+~=3f5H +z6tzjb4eUB-bAs`zkF{NQ`@PXQ8nYjvJZ!GjS7o*5UftK6t?%12H)k)`yX_nepL?ap +z+L}wA8{jb?*Cx-W9)oE$`YVbPf8Xt}PXM_G{|^6?(q) +zgMnWE@9Daumc5gdP`rCbN7tXb-S`&H@7(n#w@*g>(bko9Z#38Tw>d+Ft~vI- +zwY#mWJ*qV|d)_iwmbTs2Y^**{D>Q>u+V0LzjgP;MjUQ&K^K;jy)f*B@^sV|8n3hMp!G@{Z|yw8w6(oKat_ +zjoCaB*|>2gSigPT+~-t0yf2&s?XA@Lq&~J^=R%?EtuOvY?GyDg`+G0-D&Ji?PqQAu +zy3{UvMrm{JlwAkZ=j=LQWjUxi+WCK-`qJYX@4wei?+feNu}ANM*Q&p{Yl8Ze&1*J< +zec^5O8@nc0|F=G2&H&xE=W4-#}5%czc)-lc3#ua=2$kTeFy&vp8 +zhd&D)ye}O7OlNq0ud6-FJu9|x^&1sutyz~m;Xmz}udT1!d#d)F;Jt6CKF6(lb%9LQ +zy7|}GC*4$^s!3JPnvx1OrIx1K+G-Z1Q+3Ttm)2OM{%>h*XlhTjrrTPY +zo7&Q;hJ~qy_SE8CF6rdv}B8(Nnxt7%Pp=c%^mwYM*yGtNryd8t%&bC$9) +zAZ)uxBWKF^(ynZlF8JKu+?t-hu%=Goa@*>*x7A#ip0A|s4NZ$Io%`I;mTs+G-kwfP +zs;X(Px!7$_x6fC@TvyYcp5Itgn{G@^nrXqsVLpo#AGGQGw)UF#4z-rc-?pc(OE%xpJ!^=CC)}~vP?UbgP+Qzh1NDfx+9@B;STRB^rm!(_hH#F5Z)YY^% +zG&jv}OxLF-&0XG-R&KMJQX?%`xG)N<(v3CCFYeQoe^2{c_K|m8V@+Gz{F?gu2A6xw +zvewk3O53J<%fqeJRtDDyUHKk;KbL#9er?O~ +z+{9sbvGS)<)^$=1ZK<)HW5=e>Q80B%c=&F|Gs&Eum2*tnNBMO>?h!l1x?^yB*FD1m +zj0*~&zc1*%a_g(Cy7iP)w-WSx{O&vb)!j5GXS{Q#&P&BRw?5`{Zk^ih%lW2KV=qcA +zt!Z77t{;<9Cr`JwcC@rxg`1k&)qk7PtvXrjQ_B{on^NtI(H4;FEu%1> +zaTldJntIIXFUlp%Cti=Rpke;C8oyQ6*)}Alnp^D~8;i2Xw|JG|s--mzO{u9h9gWez +z<@S$*^q6l|Lz@Q6rgWX1B`IBKTCCl_W2B+NZARIeV+%WUFF +zM;Ts&cIk>d;v{um!Ek(0%Ff-i8=A+YY#^y`XtQzJ>XCCE=Zx5YuADiEX~x|R$b2>cXhTNDaVmp +z59@M06zSOYILc08J%Xcn-r{s)i+vwW`YN02)2Wg5sgZ4CY$B)u)jsv<7p2#>oXKF$ +zBv6TRuIl!=`_(qg$V!(pi3_*awRFsJlfdyQ9k}bb;pDR_?Z(xvsMeaL)xiuPxM)X( +zZMtr$8?>X(3pL`^musBAF0HGA2I#ijdb#*8rhK8s#){_V_A6VmiQFJKrL&=}n}^lI +z#f6j97LCxAHeH=!v(B;eKM+_XRHgA2djD58Hs%KoDjdq`B&F=cVs3DyL?#`1LO$(dDB=xnkgX1sn+Q*esH%Im1 +z3F@x4VYHnOL4S$eTxf@`ew4dC)(&>n6T7;g#uH`dPL7ygkMY)joNkY?!TA|ob*@KbdJzo-navwRwdY;>+9vkJNTPn4y-AQSqE|$^ur8S)z)w`mi?XDk3 +zH%ltP;$>H9-et4Rpe8M?&Gj91x{(Y&w=Ju#X|G$XL|xmg;BCt;YiMe2?P+_>N1MAP +zR{EA2jf`zJn&;+I+tJWiAKT<+|4lWGbFPkU)c(PBH0WLNdm3H8j8GBtgG1=Pa&be8 +zcGjKc+&R;`-A`J&;HJJSomI!KgHb-M=|%3Q)NZ8RqJg_jw;Y3XMriruq)T5HB*-ae +zlw(-3qg)@uN_9)zb2Y;2dQiizSxLnh-3_>DzWRfP1l>5frGW7IE{9C`^ayr`R3PBYjVPrSLZ^PAQ#tf~6SdTH-q01M$%{|nEtyOQX$D`n_tz2S&_ +zY;8aVPqjBkZ4l*oZmPDXEp2y3n!1FCS=f+ntk>kw&AX~xuj$J1=*`%(zg7LuIz|4L +z*w$KHw~o528$Sgao;<<0W1pjyuR3+LIq7zF?q~!FK$IqT;0T?xJ(w?r$@Mw7n1%zT +zK2No&Pn6rzs`Pcy_m)L;{$EvB(->T*f*s@CH5zkW`nJo{i*(C4SKT?DPkY`S#uB?C9p)KS2EsK}WZ$BcRpaOPYv^Hzab?N*?jm@<+jp5P4>Sgm$ +z7A~)at<6j4YvEM$&Ti$(=4Z#PX>4@q+ro>dbq9B!8rCZ)mmAYn9~CmJnZCPBV|?Y* +zY2&PBT_4AXA9V-cYAN(leKA<_Q^MAU=GKPx=-{O<8}(W*i$ +zMSOpEE$u441Blnp=2oq83htP)nFM>->{OB28mOw(ZE3e++Pxe{$tQli#>V=V`7QOj +zrd-=qAbnRgJAJJ?#2npgYDG7`sj8!<(e$|t%m^_ciC +zJ?WKCD&+=<;7UE=16pTjUSz|B4xmyrxeI!Mhu%v>rx;;CtB)3Rx>o@f^*eYx_)@~=2*{=ve>UweSqxY>2S=ZXyWzR^7}O2#S~2rd=1M>U0UP4nM}0gcmm~T0ADDHD4{@sUAJ{m*DzvOy914(!<5% +zC_X*ID6zhJDo5`4o>QD2(}&lsoP_er8Ar0^?&%_TlyYRRcd?w0nr}97w#OZ{e!+Dz +zmZ?%6Jzu*Q?Ya!OOmoYd?efQRi{*cm^x1L;2mABaV{5wB_ISFZ_TxEIf=3%&3)kaP +zK}}-qZ{><#A9H|W<&t9wk))#pdS>;fXyB)zE#$`9TX~Yp*Y`pJ&j+=nX +z&*m3y%^^6^$Jx^iozC^m?s=US8&fsW48+#^6_vBit}rg2*xV$@X>4ctn3UV9p~9vt +zTJ+cTNefJNU+TVzZc4)|q07h3YJwd8rh|^k8EbDlC3ELXu@+Z3jyQjF6K7l87<>m`qtwS9N_W-CRj4j}=|{C_Sfq6^dys96b-X%ZgvpX?x{ +zXUX<_t+cdMW68PWQp@y!Fy~C~mR_@kzbd^Z6n|BE%{%_8^m_Ju?DRdgb9CPkKPOes +zBgPTezER>>+ge|>^EGyJ60Ub2v1s7g{NL6aqBWB6b4B*^Q5F&0Jml!}Uw6EtE*7YK +zcBZ#=J$4E{yT?tz3W|#l9y3KtD()0?+k?kTM{W-uD;>E#c$}28-Fz&sXn`v`uL{;= +zU3uoX2Yiu)JG|Q-O}^tXmRGoaeDzZME*=}yH;Q+c$SJMawR+3h_K(&;;(KbjQ49D} +zn_H{H1B8*;sdHGXW{sHf3@@8gS*Zt$Sv-QiFT-kATldi>t4jYDILT-C`V`Fpn +z$wyHCaQ7onZL@bx>H%D%J;tf7n$zCeQD?6LMKM8zA}`n1w2ao>J14#eZ!I`kmpE#J<;EYGK{h_#Sh05Q +zw%N0Zp)2cUK|?RqQ|Wk(vhj2Dm_ltD#hG7h-s4@_l|)s=3i^X=v)UWm-o~YrS^1wb}4^?npWL28Yd! +zZ__#17`$+u-A|X+aE!52`G`CJSUtO!zk9u-d5=Tsp7?K4S=CA9PNfV^6SnY`F0GRq +zXzmKDOV=eEOz$onYwxEytKey=o2Rzfy=nIetJ}X@V<;0%ZLd?aWT&>Nw#CgIjrF=! +z(!k!XrLffbK?2dDZ;euO}Am7}WW8~Xt&w{(>o7+WV`DQ!DMX9;&HqF+|?C#s{ +z&cgc|yCbid>wdbSy*2Ib>T23jygqa<3M`j9lP9v$6C#o9l()OGdWW43?y#6kN< +z_cN}G1WCI0znoli?r)E=Q`e-r`^o1TyHY>B(XljmlP4T}v`ks&x<`0Q*IZZA&}d^} +ze4~vE;mH}D`R=pzzi`8Kc9&>ps{QClY+&ow|J}Ib_6<%_Pw#icJ4d&@_46FLUF3-P +zMbQ`#9<;5wqqWXGzKWN^^JXv2o#J-2OKdPuJ$q~nZ8xV5_fBtRM{8@>#on%?Jybg! +z7sH<-i9J$PzmLX;D00%mhTvx$beQ10whh5c&AQR<{v#)P5Ym`Vjk>x)t4im#jVn#5 +z+uHI&y0bmqWN*NXwtN&}fv4%ECLcE2Y;3NnkAA3UxHm&f6g5lqwq8wbb4Pn>VoJ~* +zy0^E5i>P4ksY^$bdx=}aMWbdqX?s((MYsJDaHmF)|CGz;&hERyS_0`nu>gn}~e$qyz(z88#4Aj(MuXkHw +zeH|IE{+o^cYs(R4s(ibheqQg9=ZqWQrasly&&`R>Q@_)jmi8l5?rW+$tktj1jV9+c +z+biCRuW4CqFV=U(*VJ9x(V$VXE6y^gYN&UMj&3)DuhU9QsCKU2NVC@_Q+jXG-7};# +z-wA%EK!cbiZq-8u{d|@^fpD`&_1CWV9Y)#@{)GPZ&1zy>_tErSKg(4=Tv@p<%f;@$ +z!}s)UplnL(WYF{V;VGrazVG02^SqID(SL4t&-T~iXlrVbUeHS|Yi-tIk-IguVYe;i +zU4GSNy1i?yupeQvENpMvb9VVHmM$|4-|G{p|~H +zrheJ~m0@^m7(Sw~w|?Bs;wCFx6@LE%g#+_~?UyM0Z20}tVR)j_>-fv`U!AgdU+%L$ +zMO&is1)=8!%e-zT-7+oRuBoU72HgT>pRI?p>FVmMr_BEI$%6Xl9zQ6Nwpkf+j~|sH +zDC;E(N((&i(+dAR{N9s=Z5yZXmhk&xIoP%uGGsGFHe0`*BUz`bf=%5JbAJ!T)f=2p-;alvuDqeNTr_8sb9MO +zulYm0#tiKmbX)cRBhuB{lB7qlqvwDiHPzc!5>-x(dKk41D9L_a~)+?w6Vc||3i +zY0n^2*#zOc!^(`o9l$>6X6rFU+@lx+C(P +z-I;O)(~JCR{XC^!GIK+ay~r6J(sdipCDICd;BQOr(GKypI5*YanOc%|4Up1{_FW&M +zidW8@HD|`<(^7Mz<2u09sHJU->e?H_W9kYTrOTG@DCxp-)ipNT8*-j^S@_elZ4K9_ +z9iMt}vzEeT^L7IVPph4UP)0u+~b=y~ff+5>`mtEr1zq +z$-Qd#o~y>)V27?!w$@!2PnbQfZI2zddiJa;%V*A&74xg6R9rdDKIrR8_x|^yCRL+8 +z=w#~C+CEnonYM*GUYlENbUoeDXSeIRrI~_O1N7ELm{!fIz8|!J_4Sm}Pn|J!R_f~6 +zGv-cFzWRA8O+7BM6mB%I(?{RimrFN$N_kaoGOyywnU~I=b>-Y{n}hAai|1XLDxYlm +z8k(XKx +zFm&zH4_H{sPtBf}+NYyMleXneb%BsQf(d@;EH_<8t!{;nmaw9uafvRo4K^ckS!-YW +za@#cniF!$}HNL$Iz~W|U@>koj&|1{q_FovhrQmrs47tt}W^lE;qHA`q`r6YldlfYJ +zY49LHSG?=_M~Uy65ro-#bE;>g^wWZN$6?*eo2pweTO71Tu$j58qAp^temqGNRc}U< +zOae@oMTKfQ-CZt%9Q7jvtu?dNXDy8~3buOQU8}a}zl+O)us95VJ309L(=2PqtN*ZY}?3iG$VpSeciZiSr+ +zTkd{8vr%D6zszF0!U+mru+Lw3KXXXoH3|py(s2|{RCvoa?XU1jg`EoX@6rAW7bx7W +zaGSyx6z*1dNa3o7wZHy|>az+bDjf7J?XR#}VW+~a3O6d;uW-AJ?*dXeudX4 +z+^?`x;gIiZe}$_QZdbTN;R_1K{y_UHT&!@Aew*`%gW6x=N`==bJgBf!Vd@p_ukad$ +z+ZC4lPWvmIuJDk;b#K3)8RF}+{%FM{3*UV|vq0gdKWcx4WB&AhW}U+P_tlOH?^pPw +z!dvvmUtd!=&&y3hQ3J)&IWU3V&R=8N9_t8w|7KJ7HW!(2FoTu;!i&wZuVQOh6 +zb4cL|{bJogCGu=lJ_^USDIbN^3R@KJ(jV|yr*OZ*hZK6(WirnyTzS3rSNO!ow10o) +zw<437sIXDtH42~9FURgwxcY`nW}}7r17$mGyTaWH8&}Ce;kHl6VSviOKWHS0|MPB~@$z--F+;M9rvs2+7g?kjfrO-QG{q43)CZ%w?!ZL-M6fRJBP~l32 +zsZVQvg>x0|RJcmv9)%An)L+i@4k}D3eBrYyx5DjfR9}Tf|E&5dT&-}o!UbzHnW7W4 +zeVy7};bMi=3R@J`D_p6tQ{ifbx7qgf+F#*zg-<*V@C`!bm~?DJRDPJ{JXVVT0Q_iKNJdlar#xbmw?Z`;47{1om~ +zIPetpv#%??!d(g*6|Vdj`PlY*B_MIuW-pp?z7mwXekWv%UPzp@~!cVQ!n) +zyk|GOpBd|7gLGr`{Ttd=7H&%^wC{&(d_OZ?p;um<+MK^7uVQWT@?ZV(8J&stM-p_8 +ztN+WCCf_!MU#h0JLjRA^_T9Fvym;*9!Yu_Izxt)y&*C@f|ASreWt)q(^oqytQ2e$# +zG=?eE{w}^fw!h^&?@o +zvtseP6+ct)M?3yu#n&r-UTps>WBU)$J?PeB`$nTBB=Am0o +z%{!QHhZv$wD->VbFDj+ZBJb`t4Tyu4CkXSn=M!9zFjd +zxE +z{_*~?N$~?U*Em}I4#kgA{L%8?t@wGz*#EHN+m8`HL?`TR$B3V#_-)6CpQrd8$B18{ +z_-7S=wDNCKeEzrJ&n%AlTod!%q4=4KKbp^O#n&Gr{;=X#93%fBnwvg;jQuAmez)S= +zW99outbFqnKX%8_%eTVjzKY+GQU>Z@d7H;?8JBlXQPjUSDSrR%qo1EU6rcL#(S3F+ +zezD?@=5tu_D~}OBME!oF;%%i>!#`%=&OTb1T1e!AjqolyI?Y%bo?uVSsA +zcbsyttAmXJE0v~2^U;U&z0$ZbdP!)Q(x$D7&;O0?57bwq_~duO1lnX{vwokNx5s{Y +za(Esl=M;N`v|WEE#~Y$Q)VbQubLG9ZF!}lDxOTs=`i<cPaiM&EtFWvUBDqfFa3YWoAaf6?}piOnTjj?4RK()P6SE>Qfae9dEmK2W{6 +z&z9bK{ahCc+F$WiMVf!={zLnRW9)CU`)^hJ{^K=|QD0Sju>Zxu{#KTqihq2N<~RC2 +zUM{;Y+o|niOa}?JP?#8rA^g}FB+f8RB2wT_+5$e%_nX-A@A~nU;au*2>N`x(u|s>IbcvH +zH}A;%yDpP;if^AOGu=}uk3EUaL$;if*DudXZ}ogg@vE;nvd&Lx`)%5uAM|%;l?*RP +z))ucRzU9NZHwsMLapQf<*FEF{-80QpS{>K*?JEK@cib_GzfJL5gZPq#s*#naO4|p{ +z%N)_C=4pHC?={y9+TQi$yc4?GZiV9K)#x59%r82})@l1|+V02Ot~@A+)#D+>zfh}t +zlVCrW@6@oIw(Z$4er4d`>RF+ae^WRqwLI*8c|y9&u>0I@kow~&#ar6QB0L?ulr~LN +z{0PObjE!x1LxZ~6F1Fu1rCHgK$xILG;pUIY>aKdMQ2f2R7rn-I2E!FVr48-{6WQUjm0mF#oPM9;#S@N#`|12$+0@DRQ$>|-LC}uyS9qv@F{KE +zs`!cRy1$9-Z*6&1tc;H<&590IB`4D5uoGURK`Vcs&` +zLk98goKH4(#g9<@Tb=6PvHYjS@~=|-A;m{yQ1`x6ulUy#pNj1t^;bLosxW>+5bumH +zjpe^h@!oR%QpzCSwd0&v{NswBp!k`w{iE~N^53uc1&R;n0WSaeJTqSqor({S@BHG& +zAEEf$6hAh|-^GVRsq?E+{H9~X*DL=1qr}@WS1Ep{;$MsTSFSI*y;tShKI?i<*-*H# +zAl>IzzkL3M=YIOkv&CMyx~*q**`fV9wZ>xiIXZt_yQ=@L>$O~|gOug#3+Fs{_4>jo +zeV(i6TlrkodK2ni|89M+ +zdhbkb9<}AnOV*w-FDisK+rGB$^^o?hvUK_?)Bj_%?Vz^pvJIhk<@&&N8P5Z_htKDqftbJwn_+4$Lrn$Xf#)f>?(p?R0 +z?YvF++_rPyU0|FlgWEu5V|= +zz76A*kM;9LL!3YVPyPUxm5NDwtk5vvB(53arhx +zX}`r<1MJlIa(^Iy>gK6irc|u0nxkD@&(XC=QBNw}cBNa_J>7?M)4ip1qqLT|x_i36 +z>q<9PaklojTIn7L((THx*nG*B85L`%ubWo6e(LR0rfjIXN_#vXwN|^*Rcjw#>yvK< +zbzE6czPWnKtctalueH%O{uv3()BYdH_q5_Nz+fCQ(w9Km%sYO?w|eK +zNfxgxu(a!E-hSzZOE%7kcCk$A`nc5PeJh^(>GLmCS|;U|iMLY6eL}~*?Vq&%+QV_} +zm@aw6ozw1^KDFz>F@62?+oxT!amt3NQ|_p` +z!cNIc)x&}zw0KXxC9xD6rfyWc?KQ>HOt&4%@31mjA4m<el{N23rr`rnD=MEQ7UmPIn~SGq>6-{0Fk +zzmMdmYf-w_l&(EW=f<+iwN+PirJJC*jY>CZqvkxpaig(kLsi%ClPuFN*}+Hq4AK9) +zwBNitvU4pr*NNs@V-){J7$1&lJM*iuV{p~_s`<(>x?%@?S$}`m+pYYv^@{56dR5?Q +z`A%25d3s*4OW&*i?bNv+jqS>}=7@YdmHx2O=k}{9YpYxj4DvOHtxC7*a~juzd?N=N +zgR5)|p1z@KqwC?Zk-^&c1?@LN&rP!Bj{1QWCF}=we%nIHHl^EsWd3f9pRu88Zk&0p +z(oN7lqc-aqNz^vw?z&*bsj`C2+E7*hyav{2tl5=sTP=D+m8Gog^SlOe`)7*#?)mZ! +zRg;wOZOV7z7R||me0QqvMuyYZS6%zujPSgWt_?lwUDHi{PTz#rKkYyLu54d@L)Xd6 +zw_H}ScILHRbyiaEEj!LuJ&ZwJk;&3J*WNjxk^hB9B-1I9lfA@ +z+Jk(;>vC>iE>T>)J!8@{Df`~OEbP>_5wUI77Po0zO55V&q3(6o6;!UzzddithUCVC +zru|Vv2l?#OK8@NZ-!kS40R#|0;Qv{HTTTzERu+bKskE=|;m?B2+3oeVMyRhSU2C_` +z&)R*6zWgBY9?<&*_GL>?_BC*7u%|9J?rZgZK?e4EgMAeRfv49a+}Fl1-sWWX6~*h( +zM6-R~7#`o2!0oGA>#_D_>ofMXJ&X@GdjrA?oUQ%XmoDM%OVik#udo{4uKR-w!fZTy +zPt3js27#x?Anr@kB=_}#=7shZZMXM>>?w@jo;pc0@FxYzJzl#<(eAKqy|J5MwwJ>b|Zt!{1_k(cdFM@E?e+A*{LqT}&r-N`u +z7&dMQw|_1O7k?=X-Hoc&VSXQcE;%y@`4<5M5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** +z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 +z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ +z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL +zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ +z0R#|0009ILKmY**5I_I{1Q0*~0R#~Ezg-{`ekH<+OuRYxt}G0%3B#5!yd?~`hT#)o +z_(m8OtqS%}h2g|7tPaBkVYo63w}#>NFnl5m_k`iWFgz57MV|=rpH^9UQEJqcwH;0E +z9jVfDC!9O>oN*oQ)3}e1AA9cD3FnR*9c=f;sA@@9y(0JTZKnryJ^bMy?EY_%{=rF} +z7o@-C<3WmvH+D}Md=AooZ)KEzXC~Obc)+pJKeaYWKWacwrNccZ56eIIj%@nlgY=8X +z_q@Z`Rq}inRg}1Vvgak9nc#W7e9!Bt;>kqOUB}5M+3PdI73BBYc7cMTUUylLD7;&7 +zdFyn%dx(5F7@Rrma@ezSeQ{8W8^cYn)S1;5jkzo5y=a>p4u*r~4Ic`22+VCWz# +zao%^;9STlA@q_xlZ?Aj{3WxRkmTKuAcd|bCd1G}z{}mlC>3`SC36eLv2bF^d-_m3db%P?d!L~1z2e{f +zgFakT)LS2t#gARB4+E=x6X4-O-GAW#N;z`<6SoD3RIqp`qPgv*X;ty-P +z|Ls9m=k^P&&V#JQ{E?%r&Oa`(I)B#O{JyGBp_g}?b}n3&cdB;lcc{Y3_py@C=tFUn +z+Msa7Kr510+-!;evDgZm^zz>Fwig%oM+=JRJEX?NOA1cECi0D24 +zkaZUIGRt*qp6zj5Z*}P~=@*LMvZT+QW=RK2F5%_%QFP%K^PaP$)x)z%w-*n~Q=;i- +zTIH51jdHz0(S_gEH%e-3VXpsPe3d1=ZJ;H6Tt`m&KRnR{?opp8^70NVY2l;Evu(Gn +zI&!$%Ka#b!^Uow5?)+r&AeG6# +zU8j`iZ_xpI`~LCPL)M(@c?13DGyt9KpQP=l_&*cOF#q<6o|p1R>EE;bdv%!c{(0&$ +z=lfq*|19(GIKlI#`t#KrXZXE)dEP94nR;Ed|LKvQH^fT|}WTJScrA_I~_WV|rGU4@qTk(YjiR2hd{1eqROnh>pc)2A$ +zsMFW;7poddyi4(gLlViqv&5fJOqh6BqWFuJ_zJ~){$V@Qy#Ak5eBo({lhFpUdg +z;*p8sXDsp6!z}UL!(HN(jX9$d$pcJ<-l+J(^ApK_iYb|LdN%Q8iQ-L`xQ`q(MkuRgn*?(Oyeq4m^;MDoj)?N2nIg;j1$6i?KN;9snNJb#5Mp72xZDM>#q{yhIdZOQis +zYKHHrTRdjzri}R +zU#(7D#Nc!J7)2g<(%(8l0nH=Z!UudWP +zR};x!SSHu1ykXV8o+zH%TbZbED*V;b=;iNKfs6cN?dbcLDwF>HlWMd9{#P~94)(vN +z98U4CI>YmZ_*eJyyrKRtRn1}k->U^u{&wwqn*Sf;Ja2^mTcsT7Uo*z@&hS5^15EJG +zR%gDze{-VeUFe^$96sRxQ7I?+dyn_L5BV!3Q0{+3dsX^(sEw-p(^aV{{;U&iRJ&-T +z=S}nTRi5d7>sTA%Rw(C7{2!?wUh2Q3E9y-DRc%@6|4>bHqyMrR;wJwq>JK;j^HsuC +zeuW@E;SW{%Px^h-l%Mi%Qq^zq&r+@b$v;~o?rQ%O<-EpUtG=<-&)1eO`JFoMy%cd0Ky$# +zNfbYAJHFyh^KaT9=AT$jQ8uM+hD|0*@*@%{moZJ__In&1R~sA`t- +z3luxt|NHUQd@rBrd8hlIRg;bI@6uIlq`yiX@(llFb$~PdW$N2w{g<@8+8?4c8L$5e +zm8j59CVy?kd%ml9#mVAtTJe73`u4Zf3JL#f+CAz2qg3+zztixZ@4uuiI{RL*OioB9 +zKdwDW-qkfMtm8?^;(j_S{J{e8{HyG8?|)YHO8OsDSIP5-DD!;(Aq_GG{y(U33;mJm +zB)$Cps&$dq|BuS4aCkELm}Psuu)}OmPZpP1w#Vzt@ce&KNfQ2xqm`}Ke}YmKo|#Mz +zR(#37s|CVcMkkAx+b&lWTjHsTNct~IAkXikJ>>8mZ7MuBnY_$)tk)12?l?AC{6*XG +z*D9pvSLhtkD4kY(;rYqrCoS;>>ONuO3zEgpSmL=Vu;*W?c2wdE6<;_pnS9U^uU4lH +z6JL}pK1*%ypCEb9e^kws@XvO_7pO<&`3JN)-+w{pW`WY7Df9fxWSj4oD7L`=iB6D0um2?N +zU3hsi`2p=$;we>_RdurXYnIh7C9H8q160DV(b1FsPjyYn^ZF;0w(!bi@+RBydeMeE +zUY#sHU^|}Ws`f2s{u}+P@vXnx@niZ>I4_y}wo(mf(aD`CtWB2mS2sF7t-}=7C69OW +zQLlfq4WaePVMDEp6}@HYH>+DD3Ku0y$}Rn8&sN0ZZ2C=#ENn=ga=A-CLjMjpLxn9V +zY)qDX&(i1VJTF|DJk_SG-tniU^ru!D#!I?5sf3MwipDhMhf3ISA9Hg^=FOf-r*Dk>@}Mq*4vgNg|z +zCZcgoTrd(Pkt7Z^Gx?WRj1B5Rds5=^-f_Nyw+c!sZ?Pi +z{qqN!N*8Wsg)DSRXr(IbWfd=SYGuM?<$FS*zu2jJS!|d}8`h!*GX8l^t}k+4uu#qZ +z`A$~ySa^y)yTqyBRL(0jpf&p!#5N2fbzyA7W;*Fb#s({YE!}XbQ!|{U8L$zCW#~GK +z{&FYxAL==YR<6)iT7}6YL9Nu3UFgbkyI50B;Q)Are~G5t!b$8gFV&P+7=@12zf4n! +z!f%+V%bkex$e{2ZeB8gnsg_AyVIF!||4OHhv%y^9U6%AJr>=Nrn} +z3LAQYy4tDZLZjNs7htx(+9`Ua_zhZMd-x3MqKAKtle-&Xg{P?XS|{Sf%_{t$AE>oX +zz8zo2-TDii9ti$V_0;f`Cg+H*?e(dB} +z3sK=Q3~l}mx=y+jhV%t>qf^0oRCVDF^tt{zr-arPt^9VF=HKMhJuKFy@g4Su){K9P +zllz3$I%xm?txgXvV64Jn@Gbu~rw7+4USS+ME&q0>8+XGI-P11XB_#Ckb($t1ogaAk4oAR}z`x(gT|`-%*_a-18o6?@ +z3X7J;|~|C8iD7Y-cw&pNsN&@B{l{lV}%N3m9|!XH>4 +zzjrcXU11!(=Q&L!3gwL3p(*rVi`fpIcWMrS6hHVECEttjCE>s5P1%L3dw_aHQ%<3oMfj?wT&?FdO`(MDfl&XCPW}C&XFR^c$LpDcH;`lM8N~8^ +z(<$e4*eYDWDt*gQrhFd*tH0Cfx<^uPX6ii{3q36BataMqr+&wzw({>I(%&=o +z%l)0QcCrEfQ}bJe3kQPwKvQ<%Iy%OOv1Beb{C^qAg}JohBTadQzp`FFcB(mV4+_H> +z_lb_n6rN_3e7Cpy_&+9 +z+6q?xOQ&iGRRmu%^=kOE?SF%^X;1yFNp0n?MkMw?y3Q7U8WxVk*j4mhH&>5NRcrHH +zsVnr)%tykNl64A~W1isqZY38IUf~yP%}LD}6e_!c3fu}=2NYV-1NkXeJUCallHEjF +zbCwkj#~|t}O_djpr`KiNG<`kNxhv6e)diXC-(WJ&Ck&Uq4t=S{| +zoNtAjFe17BP&e0r=3N-ZobK<2Y%iDxaEu)0$_Q&0&LMSxE4=}9KY)b(aJPI2yM=)J +z8{sV@SpTEk+;Q!)4%GaZLEnr>{~))1w(t+fcUXdQa{NQw+>gmG+D03Gt!<2^;B6Te +z=~%btosxPkQy+@2B_S)LK3S3@2%RtMEMi>SVW^ +z%UG|FZUl9T8*w=m6fWeC@iT4>)Sl#T6QfHI|hQl=NS=Vu}d?jpB3&CV{^MgD<*kI```0;W +zjdM`IveN&NPVE&AVQpQfsYKy$s=i*^>=&Ly`T9TBaY5nNjJrWose&2?>PAhabq>~P +zN?G~Mbhw+`ZYQ(%30|f}7+BDn+T7f&v`BJrtLC=~_xDEJZLZApoWhhdK;5q6&|hK} +zh`E~E{eF=(8{c6A!fby7{HxF6@KC$U&ffsU>F$UknGeRZ}H}iLB2jG?gvfK%1Y`RB7Q=*5^~Yc5?;s-EBH9 +z)V}+)rV54qIrIOO<}52*%`W2CnyM%)=E%I=?ati*^dEO|A@z(~HvxI@gC)$@D;P_1 +z{%_sf)6AEY!?RklRhUF;f9K{|`cC0pQoq-fSLj8zc}`P)VGF%thug@-eNb4#*7Uq9 +z>xN9>Xx8BiZdZ<4*d%=!KmH%wJ}-z3+)NDb#-i2sUvhJwwA=8qvBAo3K&1bQ+xr{g +zf0g{ZFoCW1|LEo(MAu$;zaJR>q;qT)o?%tL9^3pZmAw($ET#CSw#(P0_?D)U1(z*m +zr`v-&4ng6tMo@3NMcF7Q?BrbJ&u$;C^>c;WS>ErseYk)x(|O&cr9?Wff6;mEV&&g~ +zq5ivWzsETQ1s=Y`b1;n9{%$w-Hf@*k{%d<)&qk#GH@D9}grA!d;asc{1AmX3+aGO3 +z*T~;>ek@%h|A_M{HS*6muTlpen7mr~Ga<(R&>b*_EiU+&l5Mmf$N$L9olD7L$;X=C +zD%9@>wof#L@!eum`_yf|L{d+{ceo8r-S$6ob9c9={@kRt@=viJ_`+>|Sol|we-dWJ +zw!hcSy+(eK|7AP>L`3>ux&7Z2{w?Gmhu%8ne+}!<8)@tQ7h88N#ebtq%`VJfd;3;X +zPGJ=LZp)Kdkz1HZ%GQ)uIG&WFsYKxnQm&@_vIXZ4v3yTc$-?EV@r0(Z1|7?x!}l65 +zfh~TphxW~u{9_Gyce{NlPi9}})_M%vV9!|Vl|w=GYOjOK +z*&#M~kzd4b!0tFKN?U63a!m-+dU_i@R=$pHso9H$3V#OQ;khGeS6?r8JNdqu&?K>ug^ +zL%rM|s8!G5+pR1|q(987-zoeLlfT%VRu1=a``3eC>TJY5R*u}q%2BbEQcDNMR!Z&; +z(wwlX4nqAFuW<}y`oX)@b1LdM@DG7+P>RU!ZsI6BPE#0L +zXVO&;^?KeWk|*H1{98C;vd$^}sRZ3+q2GVEk7d0c3=9s09odaXLG$3`d_-8;`%uln +z&=k3X>;SL@`wNlFZpQE!3=<;C-hmbw93Vt7+aJ@&V7L&C+0W4agAqau$SMjLDa5es +zHYf{53DJ^W4JQs-gczT_iAoO^VoLT3_)>6)5Yw{1f!hRQDvm?a8QFPQ*97CrP69C} +zyN(u)7poU!Z-wIqhY7Jb`|DvKCa9~xuq68unn!SWh$(@!GP~_S5J!|A2I7+J$C&#C +zlLH>hUz$C18i*rHXF>F;>~AUH_>v!kZEd!Qu_rjO@*Kph%ckKU!SpT{fLNbx+aJV9 +zV$R0w-9->5r|v+S&DqmE5T~Sn4q{7o>aieZh;7@lJYEh?4OT$FcFX-6iYJxq@+c~% +zq7H*o(44JozLxm +z2=s`cT%lZ<-MN;1V61t3x8Qs&zRi?b@t;Moj}D~K!t`zf48t75(0$Pbi!A%lpq9r8 +z-BvBp$zOyreu^W|F70!I68f#vx}Z1;9g4j;D7g!fPV1Dqd8eIY+2;mXHYlfcTJf$E +z5r1Bwba_weQG#^#1woE93J;%Nr=sV#2L|>OQzB^6^0C`$vdrs6NvZvH=jh-q$vFBa +zXlS~?E=pGF0$XDW?4o2(U0^Fsfh|i)fw`?4SLhO3o|F=ETeqxe=)=VL?A1Tk!I*~E +zEjS-_cx|$V69DAYYM8!2N55*y;%#shpTqp!zBgI&4D#i+-nOFd?3qg#P^|;jBj8Mw +z$i2y)I^fO~MGous#$@I(Nz%5W_(QtI#$<&KxOIj2=zYmRXKC|_y2WQNfO{pS(A?HX +zR%m~FJlU1g1XQBcFlV8*ZK|UX5R7E9f0q`vKS<6F0>jkXn44oyI3#1NSJM*6~)u?xQr<5IvSy7hq;t6t7Dq +zOj+K#tav|0eLIyf?drB=#mzdPUYF(iWyNy`3P&FuaObk(J&^YKEdNKjQk0rWu-_LDb1;IJfoM)J#n1;!OE{Zo| +z!Khtsy4i2U4uQtSJvsZ$gz3FaExZ-0e%;jWTXF5~G`8$X^xy`c+q!qT)vyt>B7XQL +zC_g`KS8e;o7mZ-YH*WK)k(2hTxryes?pa>^-zb=({33VB+}4jF_=8ilz`)hN3;M-* +z>K_YkTc!ux{(d}oEGvFVLH+$Y?XmFs!&qAV{eC(CUf;qod4O+njdD4XGo}H47d=Fw +zT#nNLJ#>IEe_(9>4pS}zedF~nn*1E$_vL1o+qw(p_nD>5-eJn+ckSk%8Jlke&y58? +zYve5So4KLow!XN$xC+VaMSg$oSh=mQL-2spwBUHS>DE6km+QYH_{Xu}?MCpeeqZh$ +zxvkrl7yp8KvTySTa(l>aeHMb(oUR3X#^N>Yg15wiH!Q1La4rVpEpdUHEIbx#+G@(? +zvAAru8P(hUKHM%s%Y~+A;fVa~)IZi=+cmurYchi0j0JBoa^Cg(aN`IKb$RhRP8{Cz +z2XJQyeFOyWG$Y=2(=lF$!ArM;uVTUI7}Iq7|Hcjg7b(>Nm1feitXQT4>dmBOS+R=_ +zXl{3rS{<<8J}&ZgZ0%-K3}45^@Q5+LG}**`DRex`t!}TMrSl)pTC}Bo;u(u6g1+&L +zWuuX?U$Qs%j?l*}FP4o$R)!|~adQZL%yLW}oFalw^Xvs?C?94D8Iyod(1Y01Jp1d3 +zI?PO5I6pXwsit`Lb`#Yp)p?8>DfKLpXyK8nzM&^_6HNRu1*5a +z$Ftq&*_WB9P6D5%yVrR35EEqvSz7oab(O<-E{gH#BycHLF(okm`%!!A5tZ=lHQ$dq +zVFaT7=h{=hAN6z^QJ=eZ_4lKWqJ{r-?H%K_8J#TrB!j5;T>E+x)ycwh_ea!Qu08$x +zQKxfe@sew2zAtbl1#WTe;83kAZkbpb+}s;cjw_S49xXb0H;SAeyX~)N8G6#@xLx!- +zI$jz$Zo|Gy1DwrsE!D9!NVsM()za`{iwLxGrc1bOFxu0n>_4kq)48`{e!d8^xGFa? +zU9O&J<2YL@-eM;3)voC-x0(rXgImM*5oC@Q9ikQOHi|xPS2QYCgvA9HuLs6*<8{C| +zx0){|aFQk??xAjxFCNGwZO9lcHl8BPN4XRqh+zL**Yy8bfbg~m0!;J2ZH3O^S+U|< +zwBmWOVyqlwMS`sKv +zPNJkWRuV58+T1F>L4bK+-NMt(uQ&?T;OM +zt%>U7w_WM&dmMY3iR$FHb1|8*-*N1+?+bjo2~n>(_Vxp{t`31U*VQ2^XNz-IH|yw) +zs3U&tHeMLe&Y81~b8cF$R}?whIOqE1dPNc1#yPhx*DH#GZB`T?FK-x$A&j3b`p4=z +z6tydrIodYf`OD=}tYd8Bj31cw!6duLcOu32`k+Pg6N{NiF$1u=wP$`u%&D=MJx0u2 +zyPB^`im!PX#Q2HZ3O9f2WH;eLyN)kN%93)(0L`_^_{D=%b``?xYwRLlEtF-zPE5@C +znP#|NX_s}cUF2(ftnP++Xe9i^-hDVanc@%XA?w$%;g2oX&irfJw9dzu>rv*{b`RZL +zO$lv}v$o4DskYn3yLX$szGOG>6+BshJd1Y3&u0B&Euv=0#d~&dzFa3W|IPd9=&ude +z+vNIyv*Nw6eUC4%J8$MZ2ACO~G3U$JoY##xU&iL_H0F3tE#JJ;OM%@eAAVldKh{vV +zu-4So+1C@QoOlvyWcP5o@g+MhI;@6|VKP6Dn2LCsf@K~(A{M-5 +zdEI<$ag1op?fNY@6iN@%=q6Q>=#V +zXg2)pl5fk}15+^l#m?IdryF0!(`$^K!*zU_vG^z?(-xl}TO1eq`LW5S(3ivpZ8ruj +zi4A(z7<8#q&DZg`ys;V@M`}&gM$-fBnr@CY8Ns*2g0~qtcR5vjF^{Vmz0tJ6spFe> +zvYP2O8>Pih+;`TUcN+Ghwm8*%p-xsERmcc02l8dx!mEqmJ3Df6&7< +za@XA6Zm%;j9mX|2f|g@%wP$=kW-mr>`%Zf?Iv##L&_9sYbZZ~P+$_E63=@kUUp{tQ +z?>Pvvuael!G5~ZmOS^3x<~Yq9SXN6v>a@=8(}1qXUL$X@IjzU`*@!;J{$cWF%$U)Q +z^?9DTU7J5a$Qgb14gz_7Ij=LaW9ofV1bS)mE-0@y%C2uW<$5UVyLA9Lx{?F(nq@7j-1Y}aut{6XtDq9)dHc?A>n +zWmK$V%Dy^|?4*P9|K6KjBpD<+;_Jj6I`}G{)-lNBV@}`c=&$TSeHevNq0g)6$n7DS +zyCfsDoO!Uaa5c~R3+y*nmivvy@ffCrt1!*yXV}I1cUBjO`F~$oj;|^2b2ZsB*O5<# +zD9>C+mgf>o>7ARq9EWgTO>V_+d^MTRUZ<u`6XV6|1&Zf=iNl0g +zta#p+n4nGr!xF{wzJxjNQ#|iWnDaix^S;F7U_E{=RXp!Y99ha^qg9IMeTm~segFY$ +z70>$;CsyLpuC-3_ye~1m%WpueS3K`aoFwLKRCgCaoSb4kY*sw)OPrFv6~q?B^S;Ck +zv2B~;d0*nxU+Nr`N=M<#SG8;63y8XecpF17;s$#5n1{H?J7M44-CB$M2SBC +zW%JKX!c~y1~f_$m$9MAufS4&8a=YPr7^6d46LwU2J`=G%q +zh4Tb6^UFjV%Q;JT7~&eaww2qJhPU0G?SY^i@586oXXrjT-iJ@!k*90#dmrB8xl>x- +zhxdx;8`JteymvFhyNTf*@5ZO~-T1t|iKFUDx}(HGxf>tK-S|-M#)on@K0F7`=7lS} +zq3A-n8z0Ku_)zY~hjKSQl)Lev+>HhsxB9G=u=IhvJI+gm_f9#Bk~`kEQJB1t!ow7X423URkm%Ub}6YL)XP(iJ-H*Q;Bz +z=Yc7d`}Lu|U+?jLy;|?GunQgc>(yP^JIE^c>qC9N-sAmxb&q=qSv&66t1a0bWR?5% +zp}t@59a#_7Upfzxwc~!hdLrxkV3qszq1>+z<$isr@7H@@+er2+=XEAqkE|Kz+n#M< +zGPz$L%KiFK?$?KMzdqFW>%BXWK>gk+1#6+>e!bd}eTIqUetjtS>qEI;AIkmuQ0~`< +za=$*5`}LvRuMg#ZeJJ7CezF+V0e!bf5yu<_@_v_XB+4>|BlvE>Ap}t@5@qWGf2VgqD +z+Ht>LeUP0*)`yE^)%WW?-mh05Iep36alc-DnmwPaa=$**_v=00uUDTt)5zL!zh3<( +z%ge^0+^-My{d$l0>(y7zrDW~6U$4H-K2KJ;UmxoG^&aont8bm3Afl|}e!ar|`Y*{V +z_v=G_zrLLJ>lNhOVw}k(}_sWViT9{>5)bPit*oJt^t9X?^fmPOVe_!GL{uPuj_xD46f4`jf_Z9B% +zQ*&9z{e6Y|`#&SI+}{uN{rz&@-&eT5e;t`S?(Zwy-`_=MxxXLYQ4e#h@*<{j3itQ7 +zk-6jkzQX?(Zwy-ycq9xxXLk`}^g*zprqAzbj(O +z-W%6mfcx3m)nvZ&a2DWIh;YIIC>1YUgODI}$FKlvbE*PK;0wtKr)pa#@oSPIkdLG-4`h#d-QKq#mIp`ZqY +zqcDq0gn}9n3Ti+or~#p%287QSk)u#h1HxMr##XDGr~wM70ko#912sSaHQ+p|6V!lE +zPy<3i4G8Bo(M&-N2n97D6x4uFPy@o196GIXq6R3S2J``0_J^oF7eEd8CB+JAKq#mI +zVX+%?FQ@_G&oE8!LX8?wPSgMe)PPGVqysfT0W~0k^`W2!gn}9nF2Z2%gn}9n3Ti+o +zr~#p%284nd5DIEQxDpPNw#tbbpnw|iEQSB#uyzYCv$GQ^yb<+khc&1lntg_0S +zj(h-H;Cylkwm>M@0-<0Fgc@6*oY(>i*aDPQ_UV*%@jtS&_cP((Nvy_u##70Oa01UN +z|2MeQ4YqR`le`4QropbWvuyt1Xs}sf*Rf3E!qc2^Kg?=etNdl~s#|U6Q6~ILhm+lI +zXRG1E;bF)M1|2w-9X<{vPWU?Vi-hljS8cGJkD0Io06_r&fxE_`03d_{fDj4*LMQ+T +z;hYxMk_JF1Cjf#1074T|lyv|gC;%YbSpp#_XUh)-03j3rgirtw!if-)4+Q`r6aa)! +z01!d}KnMi@Art_FPyi4@0YC@^03j3rgirtwLIFSs1ppxw0EAEg5W=qpVpA&=0EBR< +zV_64>0)P+-0757L2%!KVgaUvNda!4FxNv}F9To}zLMQ+Tp#UI+|LlV%90~wJC;$lI +z13qTfp#UI+hoH7E4+Q`rOox_rWhej$p#UI+0)P+-0757L2%!KVgc<;$oB#-Fm+hRx +z0_*@lPyj%9iv=hE2%!KVgb%??z&EMNIsgz901!N+2?YQl6aa)!01!d}KnMi@A=Cf}<-B{X0D!QALOK8t6aWxT +zq>!!$!AC;@KnMi@Art_Fuo`aTg#v&O3IIab6Hby0^O!6KRyhF>6aWzNkWn_6s|^o* +zi=_a7a1F%@0757L2%!c*C?^1d0sz7sCg}h`Pyj&qEt3cULMQ+Tp#UI+8UUf37xEMU +z5N=_@4gdrN0EEw&Pyi4@4S-Ni00ad9gjdPDU;lQ)0Dw@R1G4}igc<;$oB#+400=f> +z$~piL6aWyGkXZl_LIFSs1ppxw0EF;;WYr4=03j3rgirtwLJfdWP5=Z20EB)NI|5z2 +zDI5SG{F-7n_h6X|0757L2%!KVgaUvN<`A0*H2^|60T2`b5H6>v4gdrN0EDk8N&pZ- +z0YC_6_GSao00`v-Ku`ccc##P^01y-a5V$283IIYV00^M~AcPtKp_~8+3IGTxa8(Kb +zf&u`-DWD<(ASeJJ$RfllpU-|C00{FC=LfvvTqytu3IGV#lAizw3IGU(p8yC700?cu +zOa03av;AQaGZL+}P%LXqZ0D=Ml0%Zje0T2`b5J;t>iM5~r +zfIuo85dc8}0D+W>2!NmffWR4T#wsTOf&u_S5lnt?Cv6Y_1O)(ui)aG@5EK9qnA(a6 +zfS>??z`3>;5dc8}0D*BqL;wT@00dI0hyVx*00^Wo#1a5O0RUl@=;?*;N&!Gn06-Xv +zzAGXCf&u`7)??z*%=DA^?H{00O7$x#(S%Gyo7d%`S_s??a1^ZegKL-*0YFdyK=?OvLI4B>00ho_t%v{!3IGUKi+uz@Pyj&SL^p^C +zfS>??z?p0&A^?H{00O6~xrhJ=3IGV4i=Adu=35dc8}0D)7& +z>WBac3IGVSwrG_T06_r&0gVOLPJ?}w0)U_ZfN&7PA_5>N03dLMX+;D;Pyj&SBGQWp +zfS>??z_lUzI07Ij03b{fSw6li1pq+-0AY2zEC3*Mk_7;SPO<=iU}O;hK>+|^oya7uh +zPyj$+ty&QQ5U?)Jh;=AgmS1BPm$`5EK9q{z=IM +zKu`cc5KAHgASeJJkg}tz(Gw~FAdqsRW)>j;5JJb10 +z1ptJm3g{sKf&u^nXZBV^00ad91e2No2nqlQL&50>-!QcRAYk2{JH900w5>=AdugRE@ZC*00dHYL;wT@00b?W00;^I2qHP+4ScNFh4LZ-AYfy( +znoE!%BF=yU00KEP5djbs01#+x)+#3ef&u`-7-+|JCR!u_2nqlQ=h7kqASeJJFtrsm +zvt$8)Knjae0w5>=AY3A;C*ZqswTBo50ED~SQv(1&Qd{K&Ku`cccv$#XkzW816aWx7 +z!f0)H$wF)6L6rgk0&R670w5>=AaG6OMcgx006-vT5D@@D0RVxEl}tnc1O)&DdT=fx +z0D=Ml0y)bf0w5>=Ado7Lj;GfF0D+v5&K&>{7*`z;06_r&fmBUI00ad91X8uANhnfz +z*V%$Rl#kFv?N!JE3X$15uK|w=Xb8_TTSP-pKts?jLPP=uGz6V3;u$EQAy6=!n`j6M +zXb7)~tZVUIDQE}^Xb3*qkCp{A1T9Na-b6wD5Pqcjfl6tibMW?sW2xIRXqlw0z|B*N9X--L8v-|1k1jJq3lV +z8r)YbuBy8Uw1??aDPD2J5RJM)h%P`KqZOTtLZR +zfIm?E+#I*)q9e%A-|fn!o)!IOG^hbOA1JlYDSDvWM`26V4_;wvo)@_as16el7V$=y +z0;&Vc36mQR{6KXeWk*DHP(XDsWk^&91yqOQL{=W(m4fP^fa-8zyDXqOh%Bp|s16FK +z4p$2QN#qw)2L)7zE#wz%Ky}c%MH^5ZL^sgW=o&zEct%qHkf{aLK>^ia4^xZfKy@(M +zi0Yt#>hQVnKSzE+bx=Tc=!J}EZ9sMCqz$MJMjKHb6i^)ogVPWG%ha!-yZ04P9om?h +zs16FK4mvea9TZRTsWEJpkX8g6g1v>QID=i1%U@P#wr`MMQN_Ky~2S+>40npn&SYHDVB5*bEA&4qW(U +zBBDAdpgM2`my3w%pn&Q?DPd+VZ{NN$l@C9;UE1)_|X}1BW +z4q^j5irE9I!%4zF7~hqH5Y$8AO(x##jfm=?fa<`-zp)vp4oq!q2C73Rn}O=k$!4HB +zbg~(!4xMZUs)N`Z5!FEf)qxA2>WHWg3aAd`EL!CQX&+D>{wMa$qJ5K4Hnsw)LlN^N +zU8X>FF!`Ctf&;2UU&H|_2H%x}>Y#w?z#GImKR|Wplpmlv=sMt?ZUs~a$_k>d*!2R{ +zfmABuy+s972lgoGh^P(=NUBl1eu84T^^gm?f^ +z+#%*Ms8S#v(1+(fqIu#XfOueH@Xw?TfOz;?_+KW!Ks+cwJY0++OJ@fV4>~)9cu;_N +zU}`TS#DfCF1F1wrhzA9T2WG&J2=Sl*@xZtsBE*9N!~>~RM2H6khzC+>ogF|tkWyCp +z!}PwJT*ra-a^gLJ=ynSTKVVQL{?N{V_wXj3basIEz{FO>cgq#<9%zCS@s$|`ya&di +zZ$sWNHFdkcFS72SEWvwFzlLME^!-set#ObrbJF0q;R{>ox?u2U3ZMcn=DA52P^NBi@4o-opyfQ-kkH!Fy1^ +zd$^N&q{@KzVC?z}$6??-JS6;=lV9*26!0D{EP`KJ6!0E&l@aej0q=p^A6`Vf2L-$b +z?qdWI@g5ZL9w<2z5${0(?}1cFM7#$Dya!U*hx17LNi2ya#T6pl7)oIZ@BJ&d>2%PVfg1b=M<9 +ze!!s0S8NWD0Dn+u4Z2VO{y;TWMDPa%@CRM^1b0PqK~!73;Cg97-& +zc;Tze|{=iL=OhoVp1@H&%bL1j|KPZ4daPy)}=M~@&loIK@0{nqg7pt7$ +z4+`K99wvZ(a0G1^@COC(hX#b{@&@<=`B6Uve^3B_7$W>>d{@pr5cVj5KU_?HsS$ub +z=)6je0Q^DcRcZv_4?3?>2LOMdWHbkYKPZ4dTqBZ)Q?h_RD1bjaMaj|}0RAABLJu6~G@pYEKRD2a}Jd5UBwE@U`&2Onw1>Pym0Z>ke%q +zAK(v$e9b{6SlHEyV-;L9B}i{-6Nramje8OR6=_xz#lq!DZn4ZORe%Nz@h;Dun-zhiukS+@COC(hqtJe +zKmrQj4_Yh19~8hJv{r&YD1bkZ@*+Y9D1bkZ@*~0uD1blEh9DwLfCBgf3E>sIC*;160WAr}_?>rSKn%?@9rGPym1UJNYG#0Dqu1 +zD-ufp{-Es=O91|$?Gj4>{y@ooMDPa%@CQ=Kh~N(j;19-1f+{t0RHe6^+>G({6Xs>_=5uYgVrOHD1bj`Jp_MH0DmBb +zo@EwYX&0cP0`dEyXt`!kVkr{9$=m1RNZ?B$fLd5 +zAt0AJRddIJJjSaV1M+LP>a4>+9_!UkWo%G2oq~_^>Su%8T2eKfewstR+g)J +z8Z0li^w%^k7FyxoOrX`#m^R1!oR!e%nC8TiR>w4}^|B7S{8m(in(bAzA`Gi5 +z#8x|*#>6i{*34UUDv*dv={i=;*(92Uu&rAByNuM^;Hk?XeWpROUU$o}cvIKOPO|Y1z(0rxk2Z&XT@pZQPs@#dC3zctre#|3?*)#ZzQgYLnj}G&?P4H+0GK5 +zh$XsK&uXUqT`KvYh+J=qtk;ETR`zexY1Tr^f2F{zm8=MS?6%+b!C7KITKwDeXx0y3 +z%WvfS%fCx2CIR9@(;;IJ|NFFm9FpKRLX*w%elDh48u5-T`e8X*h +zYDMprM(bw?;HOCtC0|`GwsU}j0o%< +z$j5FQ1rdGkqz6CQk)%Ic>{6X%?Ox5gQnzMk{W+3oM_Z~Ljqj>Y`AV}vnS8DX6TN9; +zI?#sUmGuqZ;bHtkar{!4`W790vDUl5=q(z7cH3U+eHbGRSo)EGUh(hqWB*=?o{QRg +zZKva&qy^3XkCu?Zyn!FP?NStrBs?WfxS;8AHiVh6>(6N_ITG}#X}yu!dPdXV89ytI +zpVxbvks3R?uDr8iCs=G*{m-6&B!_Dwwtk_NZ`409;#C;Yw1iS8r}frv>(a(qz)zW+ +zE|W<>>vERQl-PuetX}^(9Nhm-N&BDisg^Vy4UZqYZEXLzTK=6H!S){)&*v%A{1@xy +z{zb|(|0PuLMJm!2w6y6GmfC+(d91XNc%jw*?G^+)rxlL;glf>;wHMwXC*}b(;112Sz?fBR}Nu^gybQ*0bE|^)b`jp!G~KX%HkIyKNWJ +zNOj#5XJo0>YXwX044tIqBh4D$9<$qiJOFA!dea%H=2}>SvS^U&8E2$M^95L3=4eY0A<4)#BcJj1`zf$fs!= +z>;IBe7rw(wd>}X{hx=Yj+1i>-seY)Lz4q3%1dAlyx|-u^951T-#j0oPUc7%?jdOIh +z4v6U)y5Am@3RnkD>nXjL7%fXp-D%s0r%YcouX*afv>8SHV@-t-n(3&N>9)~ft^5v` +z<~TOySb)U+H!#z6I&+OiZAWjjsXcRbsTS>{ORQdXOmlf4e*M8NZNkWm{Z+Wx#_${Zcpr;Tf#v%-?jnwU|fn!_Cd6)sw;YR8YgsSzg_0ijG9UuY>xh +zBw+1|<{9s6_A=ue|E0R#ocg>J)Nn_Qm)4ptr@GgI`YVeJz-71IyZ^4!wZ*mlDKqlV +zpva9=P70d-$RXmRpvN_sz{*`ctM}{w)QMP${4{;Q*5RePa}C9NV@>Z!^ +z!2GWjjOQXVGK(5v^?HFF)F54vE8h}1);yDGyR8!KU3>PRz*PRU=FfI&wn@g=7g#oT +z(7v%jSFUE+a++KIthwSA{u#M$q(R39UAY$JrKR38c4;m&HTg8vFyjjX$pd--w7tdb +zY2Nh3)kgkCvyH)C3qN+-pRfSd7QX3^)Sk6xdGlq4FTPUu1LULWX)53CSMoGTOx*Na +zEhQdiZX{PL4fw+E#&aT?*u3O-`*J-&t~XfJg=9CL@6gQV@y}_l>84QLBiBu1!8IUR +z&l3_}hi%@lV_#V*Y!ftHNH160CG*BT~m`ixL+)n0-LwKurJ%O +zWIKuVc}7xvl(%M^pZ&wWTuaF{o#tPVtfPDJhHLYyFKVtC#{9e5Rjy9<;C46fE?Uh) +zUfx&O@5punb9sBRn*Pm;u+1&6Xs#IO;bU^$ISyP8C;M^>Rc^61U;pa9!YWafP5&4J +zw(ZGg?sAHsH?MzfU$z6uHjMqxACrB#LCE%DHE;T(W{XS?_>ySTXY|TF$v)h@la|)J +z{ZIQ!TSK;kn1e5qeYj00*GijTd|k7xG17iUwjr#jRM7NPce3G5Xz%H7?klb7Q`%J( +z^yY?_-0rk`9nBog)c(8pDb4?^uYc{fXZDZ%ccyQq0OOnY7`AGoeE^u6en`>t{2HF= +zi~D*{@2mV+ay`c!ukfqcw~71aexTEB`%+v2_>f33M{!l^PrioYxU|wH}w*FV0ciougdFRTvo+amTs+H!nD>cE1H*V +z*74Xyl~3I;n7El4**{U_t89|pB|p`%Lk!ngaw%ry=tMPNV3X_)`MKsQ8m_a*^+y)n +z4T;`-rAV^d=TXfS4-2j2n#t;YBvHo~e5AFuY|&hC|L|x#*RzQ_zQ`l3b<$(|+VwWM +zHd5B-iCVsnBh7HyFZb2xq9mGJ`dz`V;wvv~hP~%)-B)ANU)lNf^1Jf27Pc*`f0ro; +zdB>9i-ed|G;qtNDPG~RScf3*UqxINBkmeUU&C*SpcYrA%yY2T#Bh%Q&JTuE&(6o)M +z^>HuP7tBuUd>N{L>6uCC(#8d6;vV*s9&QjYS|+8>dd_jeyx8jBMynsv`sNsYC@%Tf +zZQr!p_>gx{yN&%=lk-fPdku3UPV?8{vE$5()95MI{Me}JdM^9}&&-8SXx?F@Offk< +z4>FqGWAQEVYB@s?w<_MJbp(d1ja)KLUGCL#4^-T$&;6P!?p=OGuHVzwf8_P%9wgnW +z_xJ}iR}5UzbPL=5ZJrFkbSbOXNi3R2T&cc|w`lflO8?qz?x;AMkGRqsun&>K|AlMj +zNo^~1Mz^?~ajbZ^k)?mEE##7sXN)(HM@@Ph%iN>m +z5i6f}$aW4J&}45wU3ao=##k}lu*HtnbOKxDG_T)ja77uztX>bYLztkwW8RHMtfznN +zwtuvH#{_q{ZaBIT9HE`VX*G>tiuMhs^@QdZjg(1_mU0nfG?lVCPjHKz@9IWyvyPpv +zf2=#mbvdhZm0QQRj>I)q8m{XN*Kf%+`cQEF$Sv~SA!!8BEjoI!;c9x4`Mllj$9I5q +zBiO)(Gt-equ=R(UZ*xlj+HE@ziW|X9N3zKwSsKA?$25XXrV*Uxm_~5Visp6KXaOtr +zk9FFCuI`Uc_z20!GZs%GRb79W+nc;ffaQ&2Ads`su$4+;?{49-N +z=UN@T#CXvja(%^$f57R+H3@Rt#P@UUP5Ny;xAlI^RHpq%CmU~)Ws%>eFIn?1I^Fn= +zuDJV#>x^*yV+|qK?>UhD-RZ;kS;gIprY@N5$Qz8?IG`YbCi( +zpc5#!2jA-yci&^UE;C&BlIwYP%U#_f-;)$~@4ev1I)0Zizv(uPb&YQA{*~I*n~q{1 +z*Q8(i(~jN$D%Qh^y2dw}8b==FW4Gm6;u=5Ek!b;|s@Imok)~FsS+hp-#`6=qZ57kV +z)>5t0tMk@Uy>=3a7;qYR2FiYCe@7P1R_{imyr|`wC3A~omdr~r!tS9*@3qA{=d9Lz +z9a|_{AyaRm{MT;ZLg`h`{B1O8;$n7nTC9f;HrpW&;b={DF)d2=AanDzS_`Y|z(DU|J%*_q{&J{ZOT1Wrd +zZEvd=U4hDtWGgiSGKY^8E3!c)qhvp1(W_&v$o0#bdAV=hSTn8zD9+$R6In +zU^L1!AhL%yI7u!*p$`QyH1!al10s8P`wNi^i0t7F6Cw)k=mFvYA&LQ!J-p#UGzLWW +z@J0wRAm9OtH&TdU0g*ktQ9`r?ME3Angcu(X*~2?nh$#V)J-kDNm=^q|KZr3E(_!a~ +zU|tr)xH7)DHz!yJ3%&7T^@4!N9^PR>EDnh5;Z0DBz_27BvWItgh!$_H42bOE9Z`BR +zh)aTxA;y~=%)!s40g*ktBTJWnSQQZ2!#lo&ez!ItvWItK<)w&O7w~|@o8E;GJnI7@ +zdw3^_IU9q!iy%%;wII#rfXE)+DP*>`1Vr}mW{7Ru0wQ~Orv^kS*={*R_DCeVYz1G6 +z$R1vEHm#98jst@qFha53Xjg{L!_dhf(ls#450>*$BYRwhN8#NN^A@ZUB768(Wj7

g23{2;LpIRl^rP|OR4NF{!4~`sIZCB7 +zjKG^sh)JpZjeNG8AEOsb4-Dyjr7P1TQp3o9Jy_DCOZf~NDPlbSBtNB=^Z8W7j!V=d +z$T<$2sQo|Cm%-m$V?Rc3kiY~U`nQIb{?Ls;ND|ER0-h) +zyBJd~L=e2pm>MB6!2lAq>8VJQ3zk80rY=ok`Cuf}XNn~=Knw|Z0G6p2Vi@09wybaP +zCsxE|>I};nKR2_aHnkh$eY=0J@jFAe!U_(IhX3CV4?L$qS-M{{BkTQeF^E +z@`7lR7etf1Ae!U_(IhX3CV4?L$qS-MUJy<4f@qQ#M3cNAn&e+7wX9i|LqwC({hVWA +zN~obo#JKs{KIn+@0!5M+D3W}H04Fa{Bzb`%$qN)oUPF;MYp~2KJ>UHZf|7etE?((H +zxfw_j5Q?O9Y1tq|SOK9(N|$AM)!wljLXniNsN{aH9}L5Ha{g$`DwbZHdxR+oMN)dH +z&u1&(QB3J&IhvIVwzq(|JfN7efQK-pS0oXHcPXWPYzI^9dkY}3bd|FZLC$~C4d$Bj +zcY)Ih;3D~+C9uFM&E?N@dZL>z%wJ&T&k7i31q0!P`FTQk!47htEkqCy(j|Y65E&+3 +z;G7yKUT6~EHxn$2OyV1vcyZ^%=bFT2=b$m=@@FJhK|uLwAoBCwJutQWSZY7drB#;k +znEcItRT80h!0jO%LhbxLaAzm~81m)je}!-_{{o&9`MY7FpP!G|Wd25k1o;L$r}7uz +zIi0@}&nkZ$c<|5NA*Up-5T4EBO%JOye=NRp`Ptyf=U>8im|p{93i);TF3VqnROMF5 +zb};3)l(VQxKB3)PihQnEpUGL_e)a&gm0&Bv!~La*tpXuC!{H^2@G3VzR5(InJiGEz +z@{JTKuq%H<>cEl~FlOw^W~d7flDM5gv}mRk9xTMJAUYewA>}(!TDybFuPJe~MC}PG +zC!PpujKqBqRGz}Pu@d)jP&t`d8Yk3eL8VRVP@(n)l}Dfm!|_6W9aR2}=?)XhN>#2t +z1=K{Lyi~Mk5&l<}5J9T)ATk~7hX1O8&XR-$=Sh`YfUQkbaZ& +zJfR1WK9%;JE%Xr5TNr*FOo>BSO1g>)0s +zpC|NG(l628^M#&9`ZtVUQoRZJnNHdveW48dZE$tQ!OdJMW5^j-nXYg7DHLm(vLZoV(Vf_3Jp=DX^GG^xV3_wVrxtntQvbRjJwDg +zj2xeH=w)53bXp<4vga#Z#2AaiCTEXL1cIX+coRU1hlHPRCyE@MH^=rragQ +zBuTnDPMWf6AK6xdcHGm0*81kzVPp+ +z@YG{1%lS+#d5Do*Y?s_)HVb-|jxL($vX1B_tml(-^w(yo-=jUcSj*^vI(kg0F0L*5 +z2gNlX(}-?ZI}UWJ*z~a@)qO&RBMvyckxu3>4n<;dQXImN +zQk{+6CEETO?b&$8WTVuH_Q^)6Q)jY4tMai`#^$iyX05R3q+^9W{zHAA+u~(CjJ|Eg +zJiDzphE?{8j^3)Y9dp{vS%|)>`!b9OVCk+6n$!IO7Sk*CfEVHH*ktPdj*dT2(=+NX +zVzItv8>d}Te=q4hwxXZYiF>Cg;FntG?zC3+db>$Kht8gSJ@JWH#B^OVPug+KSjBhf +zO4n%-n^IcDuy(Vjp`X@1e4TB4_+;(F*V)F0r)VF(&Ne+Aahz5Hw`m}FE)m=UN+b=j&L8_D&EdwS*A@i|BKRE-=50{V4_yJ +z@;fRoj#Vxam6yb&u-Ga#FxLyU$QR8P|HyWce}+g&vN*O99mZ1j?+KG6J~Bd%__5nA +z&YL8GEn|)G`oPX^u?9dDy?He~9`{jt!XI +zG|AVs67Ox+-^R*sj0#3awijVxA9}+_#(x&qN@w(OTrair +z>0Y0hdcn4O8O7Zt;x^e@`3$r^Esoe5eWiE1tGlk)$$drMU4s~fE$Y6~x7~G!?%KxJ +z?xFa5^B+P4@>lyD$&JRhr`3jRJ{x5e!of%%_`rQ8ZiZO>OGC|Wid=2W0By>5yAE`r +zw5RzeY_6-t`WeRhjxmAnF4xMKaD$P%)av&f{cNeE2uup}GxD+9`d`MmqWfm#O(}* +zo8%S_`&3y`*;b0HbnkZgFOVs&(mjnxn&K+m(}<+$4^TC^#K7EVNT&uOBZKs1r4&EbU6@{~FrM4iM0YBgi( +zB_^W|A~9TIa_Vpr2MJN8eomsL>?;U}usluPydUNX1Cpat8=$M?X=q7~t!9%c;eTCB +zjteB5|8+5WXomY;R+44(2sorH`dgj{k;(Dyc?fcX#5tH_W;M1@Ngw-P2rT^!3|8s0 +z^wiR0@a&ZS0N<{a<6cpKy&_^~`T@&WLj|V>2CEPyP{FCrP{FC8DROD3;MD#?XsF=S +zFd;NlaOwadG*obExDXmDI5k2D4HcXkDTIa!PK^>mLj|W=gwRmIse^^kP{FA~gwRmI +zsWBCIz)lSnoElelF9;14oazh}oazh}oazh}oazh}oazh}oSGaw2x%HBICW&{6CgBH +zaH=y@aO%X$XAz^Jf>YDGyaGZ)1*c9Db2Lg3cil$(YMPMwlo142Uur#eFgr%nyt +zfB*v(oKAMJ(dp#5p_ppUhI&Jh|8&t07$J^8yTlO~dOe6xZz%qnk9tG#1w0Dx-(%i_ +zmEwk?x+?oQf_$m$6gL#r)e@58hN4<6&jR0@(eS;-ud;O|o6uF2%BEJSY-*LtrdFwJ +zYL&{SR_V%aXi%lHsZ}bQTBWk7RVtfWrLw72Dw|rRvZ+-nn_8u^sZ}bQTBWk7RVtfW +zrLw72Dw|rRdQ(eadb9gEbugvy9-X^q#AcClx0y9Z*#I<9dsCXmer7tbxc9}u!C1y# +zBeC1RA6tedg7?Xp_WJL~)-dhS5i?V +z>+(vOL5@hUe~IvSH5$2Ry@>uTuy4ocm|1cLn)?iNNCjjLpE>C6_?deM+q*0yU3~x{ +zJ*NLsC5~IzwaDSbC1X(eja4TgC?P1~1?wg}`$Q4vgXI%NoKJyI6mdS~{8pr5ej=YJ +z;(V&Ml0m@8|9h{mPdU8nVPep$ay|JRIq~ow!HOYhtiG2)`t(E4(Svne-a?R|qX#!t +z@i`SFn4Dds83NJ_P;$nBE@>TnKEpE(bV*X!8J=;VOJa&3!!r(aNhER^o^hZ{A`xZo +z=mFvYA&MEEaiB|LOk;*;9O#lr49M_|16>k{VHuurpi3grlHnN#x+D_gGd$x!mqcPp +zhG!h;l1NO;@Qedp5?A3fGCbozm-HxzIhl2cN0&sa7i4(Gfi8)};tbC?&?UVKVo8Q) +z9O#l*Rx2|+<3N}6a}bwgc*cP)=?VN?n&BA-x}@hptjh3=16|U;z_vESGY)h~uOnt% +zhQ}7@lHLQcKEpE(bV)R4W9IH6h?7&S&dnK~aiB}$khUemGY)h~v~634XB_B~{*E*q +zT@sgVC8kTtvP((@o4}9?7*Wa!qg^@rAVW8R$g)dH1+VatT~aFeGaiNa%b2%d2`0H3 +z5*>kbdDA`R(LJT4;`63^Vo2U}Px5@ea +zcy_^(U)#!aUQ&8{mP1FL^ODl_B00}_N$DMVx_SOx^4z0&ZY0l7G|xrkc}RH5TVPhw +z`w7?+8~p*Ohl-x3gQyq>o9&8cj)$=o3ukZ;uY4H=5GMNDfs4so^jEMY2HHTT0DJU@ +znV^Ph%8q<+CWhOJW2O@wbtb4$I?jv!0g;J=HI<0IBWb|j4mYAre +z1kqijj?h#(`pHS4j?`2p8U|w%Q+2v*G>saL(^P4+oH9?)R4zJ(QcluT-sM1eU +zsmmcpSrT3TNrT2XwcQv(qRZ8D5i;57IfNl3x}Jt$Q)bvPIUnH_7oY>RD$YWeYFAu5 +zkA?OQO2n<$3Cp~S)wHi7iDL9|ITk-A^=*!SD^m}VbTg%}A7%=xawCXL;wMf(M8${@ +z@QKY%DeK9K{z2+zn)0GAF)L5}!l^v~jDgi<@>w9aJGu8jrh>oYyXrH1Rr3o0U*V^6 +z;v94~i5*Vx6n6Qdk4{617o3QM72St^FY%I-X1xYc#PWL8$*pH%!2wD9NmJ>F>y^Y? +z+Kh}gW4AUVrwxAJ@#*bl+Taf~6-95+!jGMZIV(oZD6Pc59qIBLBi@-veBtB?B{v{C +znm+cGPB$!SWS#%d>Gd4qMj|T>NS_L5St(2LO$65*3d-_$7?bN+Lgn5m@V;DQ=}mmz +zihSpqi%3#kuxE^JRd +zxpV3%LYUM?3Sm+o)sgxbhyMv$YdEfR>S-pmSarNf{SR7of=R7jgog~sjSfD9gu2=D +z=2^Lk?l;IhZs)>-b4R<(RxTqMKhdR?MJr8pstR6OmOD8(H~{l;AaXNOEF>#)5Q&*W +zc$xp8$>dHIBFMZ9XUokJB9qBLb#As0IV=4sWTGU_bS{OwIvjT8&I+_R9(LvC3E^dU +z*p)k5h#%)_qS;?9ZBHHnLI*p)jY`8Q~<=V4cF +zzB`W3JnYJy=h7;xn{H~koBazg1XsvmSA`sQRmfpig&cNO{0hG8Rmfpig&cNO$YEE7 +z9ClU6VOND5c2&q>SA`sQRmfpig&cNO$YEE79ClU6VOND5c2&q>SA`sQRp`U6{B|_4 +z+!o?nSa}|H<+c?0+})TO+V&{)+!Z0p!K&zjZ@Z$1Z>ORG-)==ee0vr9;X6?=65oEs +zXnZFtHqSwOsCXAXpeowXeUwzZgtk>$@dQ1$q6E)j#Vz!AXpKncF3uDEb +z^4FEfXdvE{zg`Giyea=E+|B? +z_r#%%i5d+VcDN+nuRZF*IO+rZ9-QP-Yo=5FNaW)@3gXx}1mtlUD`4+7v +zd|Ico)HZRO?dksQQNM|!evYg-;qTM481)S-40q@#Dc|Si+18c*LJ651UBHX*7;C;A +z%Ixr!^vwv9WUpxvI@upf7;X%{zf-b5LYo`Dnf?G_TJ=toZZx{O@NJ{}TKe*zg)rXt +zP6?A3@B6xw#PWGGSoP3#}(Hb|&D2T=DWeHD73@ZSjrLoao1!e6ZSTU1#P +z?oGdnunhkRVfa-EpDpznYbVR^@Q< +zM$b++BQg@9zOAj%tVvDTfH#vaBWGR;w~Xi%f($JAEtVJj`w=G?CF3QUxO? +zdXiL`rkrRv#@w)6Q*N{$sR~VD{&${qH(l)XA1QPYyTB?PX+;Yurdm^W)SGcNnsThl +z8tEVE?Q{)xbF?+xOk2v9CYV2teM*K%hVJ}T#vVV~@=_cfuVnly)Eap*`e;*?T +zSZ>gWf5c&@7m@WkP~o7MwUMR{ZfAYy{}A^kaCQ|{9{;=VzIweUy(a0b?{&J9&h~ms +zI@{|dfoz?Ggd{)`z-(m0gv2cDn3BMQp@UPL1_nt)~l^v?#GFZd_5u)R<909_0{oFe}YEUYa$?i +z&y=cO>vF-UUn{rH<>1OY0U@kDD=7UyuHlA$4L9~{cy_MgKO(?I)vpUmUsOY@|29Vr +ze<=EG2`XejgHhXYVXC*fTsZ1sJ=^ATCN}b@rQVL9bYwN%e1p(`^{%L!uSx^%4l4A> +zQ*Sc25#dikzJlsKLFt-Y(+i@e2k-~0_XQPt +zi(HNwwi5!yt1k;mA5zutORZfIRkh~(%3Rf1mO~u+{+_B@1AfF;jg8!9ZNl|I=}WnO +zZp=OGMH++Zn}gEfgdknZx8xo^4~b0m+k(=4dT1fI)jw>Ky?=+x1da*sbh-E_YiVzD +zxv)w0|8|#2G|ATfLr|gqjI#w-aU0R~jn>%S5tM!;2h5$WWo(pn0p1%_=#i)Erwf|0 +z`vb8)5R|^4re8#Yt3MPq{iR5Ex647-?^t@=6O_hlBdk8=tHve;)ei?|j2?_bu&X~4 +z40C=E4?Y)|nYjm_j~+~ZgEe5E3QG0y&*s-j&3`sXs_*8zq=&u`B-I}uyQRZq_5DHV +zqw2+~x(6Zw)PtgZfPQ2L(? +zVJZJLS2NaR&qaMbsL&HnzgM`8NdGPLMNs`sW6A?GiB +zFHEn#Eg^?4y9-)$)gMgAsY>7XdhYK@$eBw2Om!Ye$YDzJN*@1zC?TgP +z{ZD(i|3X4uP5K%2`PGEHne<+@{Z>NmOS%X8RR2pt{zv*u_5WN#PDQ#;X8WfJxdZ7k +z;qu#r%z66tBK@lgnce0G1#=K2WJ{YbRj0)P=9NsPYE=XY8O`Q*tJ{%5LT0h~9qM;{ +zkdPT{zEe*o2ML+4=6C7Ij36PC)cl;#m`NLD-h-G_&kqtZ9nEEW(iRn7k)3S1Q=q@tRi5Clhqgp^S8d}VG55>hkGqtx45gM`#d^F5;Y +zyMlz&Nb_C|`o18cx!wGNG9L~Snyt-$QMG%6gl1{;WYO(Q0mr||+%IwZMv&0tXueID +zJ{cq=p-xSF5b^V}I=;KQx#UUmOE-qEMGkn8GdBgYT*z{Ns^p?z^p!}z*wy^R}YQ?7h +zkjgJSpF0g3QqGYbOe!DpN@@Uuc$z03VkB-GUzM|IOF4iY3a-GhUo};kw6$(F3dYCj58${U*RkSg5 +zx|_vuf$tXExXo&^eWcE%WBBDyy^kZ!4pzsnW|m`ZnglEwD>8{w|M;A_R9UYP4TMlIgmyR!RQ +zZuD-*nWUb(eDzkq1LUA>cCZHUPoEvE-i{}c|u8{Fbb0hjJvH(S-4B89e`c1F~ +zNd5=47rfs=a^E0G^htIH$@_~Z3z9d}x%L+vB=0Zo5G0RN@D&vblJ^&91;h9Rnd*@C!f<-sT_)9%bN#mIQArZqmRD_37x~?ZtNEVd4L%?%Rt;XrzUYOQ7Fg +zJke%mUCR;)Kv*VhymsoGLc1E#P23yvQe +z2Myj%o+|Zfa0s-{C!K1$KU!R+8hmQcf2MEI9dK^5?Uc=)UM#8P$ukUG-a +zDg0$om13CbL3zrdjHUzSRIY=E3hK0;pw45yj$DDI +zu8z=}Q=4*NSRJ|aJJL))E=mRmsIt(C!jFsE?Cw+VuAMx4z)AZk-|Ezyv>!?%gjRVx +z;G}&FUiC;)#~8`*14V7Bv4aBr8?}z|y|!?n3Kx{&S&*CzKTxznqL{`x9z&WX74l$F +zsmczM-%DC-XTXC_*uP7`w^jJ~Zn}K1$l9TD+~b!iTxMt0gGDw(-?Q06tvQ^xbyg(S +zS`DzS=4e>VJF~^9#^T?e);O&>h>fU$l_-F<@g{^&~q(Z!5B{)?V_jC(XA6yS=DPqw#g6%jR2R-Ck7X +z3$Exq)jJ^K(liFlBcuA#^2c7jLUypUa&m0W9$(v;!CeSIu*QLZ_gKfjqwWIu_ccb~ +zuPK@!rKOPGEhJ}r))Y;91@LFEE=ZHC@nK_3D1Dmz{iKdZrBK!sS&P(!fvqQ5Jl8p; +z^J(%QAuWFIRw|z13NNVQ+qk5~@7rMutJUS7DENa4&lJpO7TH4|T{xW`B&WzOD6&o= +ziYwcVet&A5!z74q7{~qvHy4@fCZbSwQtN)2-$Uv?n@k1%eHp2H6`6K!T1h?6`;Lw= +zvg||TTS436BUV0AlbD^wzS?oB-9`6Q%|Gs(vCb!bMQNDT1rRk}L=&O7f +z2zGf0q`<~{wI>|jSJ1R1EEuDD&H_i2XIC{&$k#*iCtS!mkO_-;4sOG +zU5Asf=gB`ya&j{_CpVpyei8`7Lrs?Uo{IP7sfdz@b*6kxk@2>InwBwZY?Z99B1S&$ +zsyNwEm!h=zC>s><@p}5*UjRW8O2GZWe5{^51dZ?VEgg+7M}mVYN8?JbnSPd|arfki +z##KdQMB}BbJbOu&oK;0lGpTwn`46eg`dL*)EuwoZ>(yZ-OU@dnt#*;$Omf<)cA&PZ +z&1>lW~bA;Sx>0o{N2@2O%Cb2#>vrE;}9Ny9U~o;Mz+s +zrzVMn#jirQhc4?(6p-jN&=Nh5J?%`y(|Hq7?yEWKJOVR>H%T;&94(@(H(Z7;d +zmP^bx`_AHbs@?g6rYgKs3+pUxnXed(3coigg@07Me*xcl{ufOf6pZf~z+>v=iumQ0Vhdu`IL +zTCM}mD@l&K*Cwt1@@ooyMzY+!HaSPUI1|@(4asu%I>+7H$iJ23xO<)BZUD%CP(`a_ +zu5;YoOW`(>k1Hy1BKPugWdXw*-i`|)#_)VL#Egx^HdI*@3%zAEKH6QGB*RtQBsHY4}(*ZhP7F)gSHE)*`%7+P;jXVwHZlan`*v5!B0pQ?L`jlMr_V_l0$oO +zvb_JIW^uAQTGTlG=^+oEgu_8!GCmW)t!(V0lf5LXKkwk?T_mSJ&-0B2xebH@BbQ75 +zf}O)RM`f^ +z63xfxQ_9(`AYAxCZnqcAXMI)2#S6~`?WvB7>${vt-UDg%$2Z?wp}1XRPj!CD1^_yP +z)S>;@U|P}!>fT9#Y*fv2A#i4!M9ZS!QHm7Sq!VjZj{TKx9+lqR(N+%u$g4J +zIKy%ALGllf92YYKxtPgwvGZ9EwNU>G@D7@l{VY?WAND`m0~j@4m1Q0FPYQMZg5#fQ +z15%59jhm1^1fqW>xs`QIG9#@u9(_52)G>XX?d%jayOx40NEW9$htq$Mf1c!U8ZmG} +zj>u2Q#V>52tC6l*4fatsvh!&Vpb)*6F;0$X#7wV$E}IZTHXQ?5Rtjz*S)6|8fcqBtZ;~8NKN^VBkMcP6eTTWQ-w&PGFXi&@CjNFt +z?*1cBeoH4Wk-C3HW*if?UW(w~$!z52Oj6IqzVYXop~C&xAN|_IDw*Oep|q=gmB*>l +zd6&;fJRWBp+Ias=M!)~sBx1g!)}KYK2OYH@n(M@3ox4D-SDCnO7CdOiOOs1yy`9vd +z9dFuA(JUCv%&R8N)VUlAXR7cB1(%RIbaaP8yHt)Lx-U~`>H3hP>o&?Zk+kvjkSUX@ +z_yE~|AURThY9OgUl_z!Q=6McSVg6Ox4w4kRMsw<~^W}od|79z)J{fH5$~`q5h34Qz +z1ot}%Rr)6kX8(fY*UgG3bic8&gjU3Lx@ME5(EVnbh_RP~-6Th$`;84Ie1w7zl6snb +zuaeCI`0eh}8eUFEeFspZcf5G@eg{df=hdMcB#SyDNZ#)td4axvLUQ{0{bs62+sGK> +zNtOd2a2z;5em}{P`-20?{lNlq-|UAykOEW&EC6>1LO$SYJ3{_(6W||l;NR}wi@!Su +ze*NqS{3FIX4gUy4?;v&PL>cWS3w-TM{zZj$8GOXFtMCSXt|VEUu5~#5h5VmL4yWq| +z;&fdBPOo}cgi{$%oE)c!@D8VuuLHKl4yUVUJ5kIp?W^WQI4yQ8$sjEal9(g1fr}kW +z^eOpIsZi(YD6~ua8zJr$B#YBhhtmjvt0g&{mJP&dSstgAuX6FT`PY#g-qQx+JuQ#-;8{zeG&w@* +zTv34Gixixk!4VrBqQ#=wiwSEsD`z=G?{OFOHO92%0Fh%YAQBbTw%e3(hHi2hf?n$3I3{}ag}`m4kMv-zt;&TP(FcFLMq@au&A +z4B)S5@&ak`H}){-ea9+2^1&AzO&XdQ?*Bd-AQZDdBoRtv`U@L +z@ZWc|x_YJ~(k-B>zu@?AAau0)zN6K*fbJWlnFqHYQo9a$6T`Z2F-S9ay23^BsJ2qD +zk<_7+x70jSHT4bV&yy?xpLPVS>t;WY;Dm?Ew^`0ic~6(TMdP(ap5^ +zszWs9`?(q<^%op}B8TW#6V@bTfoKlN;q=u+hj6-rg2N;W{?{D%KO+Au$$|g%f#83= +z0Q{u|;6M6T!H>A%!2g~U>Vppa{T&1O^hsFaZGOT=+)NMENsdnsCT5EIr&7?ZLd&NI +z6N`n@?G)TXa(sF)ah7WSiGu$jSwtUlh%WCXu0nE%erh11pDIA~F%O{l^kG0dIiDhK +zI7FY(G*V@Hx|2q{;DKu5GisNdhIPRq2T_lU>H4f4LBL5=EA$nvWqDKl4ear(WMCSq8 +z$q^mf57FwgL3EizbXUe9dbztGkf-%Vh%R${ns6%TvPd2F|358D*qwl{QSccR>Z5RU +zwph*1S;SU1$>Ox!;q*E350e~DD+c1UB9D_?@0G66A8GJAQfIcs!6h{786k(}nnI8I +zse)R)w$_jy_4B@(Wp_#Oqs4f$Tebs!yQ9U=THRnrW9~0FUcVrsMZ42Nr!OWzLUN(R +z_Joc5KS{w?RA>p*p0I)cRZCcqk{p3L5)(zBCn@+6NvO_psBT`0RUuiLb-J>Tk-vx3 +zxzux6!dC_?9{t#9dkP-JdUu`&5)GcA9*N6yNDN0Fo#Zwo#%lTWJ-YrjX(n$#(rl6( +zf!bwQJyM5WW~9&_Y}!G=W)X7;fN +zAz9QK6V~H<2l=;?=3jI=6`K+x#RYxc`fd-mPz``M$7y%UjViG@&-*%VzOLOy&1%m& +z&)PiJhI!<$u69^I!l)0CEY{Ty>pzhH9jQa_f6|x5dd_k-#Yr7{50pZS^$ippRiVYY +z+F|`=3O;WOg>`kpVx3&Ut_Ot{>sp8PPRh2E9M*MtteXq4*4JQ%!uq^^ST8zxufW3HD`T;< +zN$ynEZ^Gf?Yt?DI%|UVpuznMcQQ=!CxK4#HN$!3VS^@eU1-~R&w0{>`PjbtuSnMp4 +zoBO{H2Y8ad4|ATRjf8&5qZ70y=r>HnyTHaqLcdQZ-ys!5$shBTa}m%#7X&BRI9*$? +zaSD1i5ZdUKT@c-j1snYZ#fk94(O?r-6A&Tg1EE)vyPVWB({~UBLKW0JJ?=I$+z}dk +zMB;f5o3z$bbPHE~EL10^`fY5S=X-P_y=pVC-0GP7*c8WAeN$3@!SQv>S;yR4L+cZL +z7?|Ema?HIo%!rSbOsry(WA3eCmkO_pQ)3SJ~x +zHonub@k?uCF@1c?vGKNWKtTJpFc;8Xd_;5dcGv7v>teBwk`~8gZ*C9mak~}Fsb13J +zD_qUd8dP89e1f#>)s42M-EZsrDj~?&R7Zrwqj8?RD=c~odbay{p8WAlv<|8J*JQSx +zh3t~LpCC0`G%?f;;Yrq55mO%2t4hG{TEIDlT;wFFZ#+}ViW91 +zClQ~roBb}>b+HD7qxgECwOjsw^aE9T5aN$&pcg`O4pzht)DC{rNd*Hn`pRBPE2068 +zJ$YG@Ax=*m`9hdB}g>z*5^b+ZVBs-C=bTi^K1f!4SCel>{ +z_2E@{eb{-Phef!L1`2TRztdN^r_lLGLG1;$_K*(HmwYvcdizeG%{tWQOm>3&l)HfX +zQrR_YNwT4J*KYyvqa?fkoeixQn8Fy1BH8`#Y&cg7kekR~Lvs7y*>Hho_@60wQ5Eg} +zcUNdX^Y*QCW3kVXtWxR +z_?74J3IWM7{tt1>_$02#pDDA9|6|)bmsRrqz;{QL4g({4UGm@6g{9B+KJryEy1WatASP0V2!jr4%hD +zfy*f0mpI)Bd&FtCw|cYXw7Bl~R%d#Nv{QWbN+dn_WxOIdK&yq0iBG+1su8^R$zfTfDD%Uxe22+vEvaMe($gmwf>J +zdXhU?@pRno&gfeocdO8ztav&;?-e>2xtli(NS5c%IObhR{z8)D`40y2{0DiSTTV{* +z@*A{@lP|=>a{$Lq+aJ-%Go%8;ILB9x+&6c!;(DxI=kp#fk@!Zs7^H6tPownuew-ey +zVjcuvcI1iv*Y_#W7Bahx(ttVNezv_@)PyS4jL;A6SNI#ZGy7SZmKs)Gr +z5TJ#IVNS#@2kA}7e{i3Jbk{^T1#Znj`imT-_rw+0_wE-y64P`6od1Ly}cd?~Pll +zJf1E_lU%&}y>Yuqb1nsEku34w?@;q8rMn7H>McO&K7cqm@govDl$KyS +zgYz9qo6`=ZTigY$`vrOIb{3uQ#N-(udV-EGjTh~g1^Us|0MaxNe=wI +z1Hs>$2Y>NrsTN$|K7ciPFYh~(7T+iFy&zuuF~~dd0wUL>&OM&y;@#T-4gYM2J<878 +zeYJnZia(%g@mqS!emkSsajLR6HYZ}9qrvC4FxHazm~d?@cIPOE{M|XWs?^b7Nqn{f +z70&_6vm}e|vbcSfblg6s4{81c+=-wsKK7*|y%p8!-->ls>&$ +z_Ou@=aVJ9tE92&OtZ=&T=gArLw3gKUK{8ixbD1*#K;{G7yjPi<$^4j`A1b4Rmu5d( +zRHW_$WTtU5MVakn)^M|0ne}8YwRGFN#?Lme?<0^`4Jf3u@wHKE95S(nv?fCv#*}sUu^JBjZCr@c_w^ +zvCfh4cjW(@H2?dUp*B8E=4ABunTsxLK==2z?bdmnb7bKf%r8%81av<>n=2 +zMCj26a5YJm&`q&Ot9Vvf#{|(LSR8W{sGYLZll&N +zhTI_-n#jC`o12xXC-VtzK2D0wiNxCTOW!=}O-k>+!gm0uu+;PGXf(j_-?Q>{{CXv@ +z4%Z8G^b?Xhb@xhO4d|qUY)O)4ZRG{GR|ET@y6eebOFDHgZcbpofEPb@krnx?{V<_| +zN5P*1^D{=VoVbSuA0b&zJjKm-lo2Oh<>qB&#EIM!aia4Ox|L)(aSk^dm66CF;pUCX +zh!gj4b2q8yW%wf{1zEFmq|6B`5A +zPi_y1rV^6r5lv&F=`VxuvuY~A_%M||M6!bMEpEQ4j0EF%-28?Vo0IjeUjm<4@1>f; +zdxCPQxlwfvt7qK>Yw#f=2Q%&Wi!`4yt=Zn +z7L`~!Pr3*OktAromr?W*hYIxM7d8CnfX<`-X%kOJ+oz|4VXX5`U*1l+zGp7L+G3se +z`Qjdmm-^z?*qmlhh!qrfuJD-+WDdDHVd>Ly?c*h1jCF4Ik2T`W`4Q(_?#so^IluK8 +zE3jwQv)l=ORW7zgUnYJr$5{on&N{}LCivA9)i?y&=a5?7Au)fcYCc3L319Xf1XvHd +zf1}eTvFk3TE@`c(bQ+z^vf?p5sL>|_PP+sIN%NmWU+s&vHow&sD-Jg2E?;hG`B*`vPZd*``Lysj+K>* +zZCEak<`b^3`MJJ6F++W+%_rSLX7%ZSZ9W~=hLUdkk|(*vddYL4{hH{*q5YcZLi_p9 +zhr{+e>3pI6w&x?E{kG>q`$f}7T##a+{UYci;e34&bm25$FrNwS2SM!{-(*rBql4Ij +zZ^DlF?jR5cL!HN4SaOal(N}k4ulpvV67CFM(PL?tjU70#6iC5rJc5eg{!D6aywBZB +zI%2PT8Dzrwf#?$Ibh&Hg3O0ULUCy^7x>oabu7Fn4plmq7wbC~TT&oGeyLsrwnh?A- +zH`WB->PAF0ao8bnhg$s@z9tT*EmT`sUM3FDKF#+3L;T1@gRA*9YM#Am(?JzjTx_cb +zi_5&&CbpPw$dEnG&11^Qt1Gz-_K>XcTg=Tu(%gIe@ck_mAvT?Dbgy5n<+2vXjLSOg6c^q| +zIg`toGF86`&f>)2nJGRL?LWD2Y7P^9o}v3Z9$n8+SCO)+_nfbnyQz&D@b>ZWsL3y> +z{&PY2TVGx8=rMJJIZROgXH`zA&W-wuDqumWuq#(#^H$c|N{O?}w|o?_P}+Lk*(ei| +zxh-L~JqvfgL#l~wy#)zVGM9z*TX#@X$q*Uc`aj$#ne7R)^=7!NWUdU8+aywH63uU7 +z9Hsb}_^_>7Q7Oe|#VfYG2Wfo=sV25f;{HVv^*1uAQtcaq;pgq&cTr5K?&e_YGaFg9 +zlgt)IJGPk@@<}EYCO6**bV~92sWSnqRNo~(-!yf_HX;@dn^!i!Y;M`I8aUve6w`P(l~{V|qDMuOV!H7ENtV?F +z+?1rrw@{;WW% +zU)itF%q>%=RUUe>f{pJ1`mX)+8sD{juCDo%Q&`NlJL;Va>xIjBQvivo^D&M* +ztSaC|`Ka}>8Wp7bci6AHhB6pmUBptkup7d1g>9DA2(>1xqAl<@ynX +z&Atk<(yt2V!98B~NdaDjD09ONe5M}RKeH%W=@UjAQ^<>>3TAk!1J0nZ7M6|oXAdRfh!vYAk-H2=&AU|FFUNWjYTW7yZ%o$w5cCe83@(h%y+ +zBkJU?YVf3~jwVe_Kj{Z|QLnaNp%?kO{!?Ov?ZHTp2h5F89`xK)kVyBN8>4L#>`xJ|7^@jt1%cJZfEqKGW|1@C7f2c|5hnUs>X>NXN+|GeBYW7f- +zeMfT&pSf;$0*XVKnfzSPd<*kdC*f?1$A}={kyoME$*cA=$FT$9aftIH#nuOK;=9>pkCMKtktce*JO*CJlt`GrUfMUR8 +z-ujI!e5!w~ta+L5kb-Dl(j9t;^}^_WO(+;+QPzC4HS$zPWv5CNGe-WGtY!zPb{t8%pCilg_BG!K8b*Y`-Xue%(=Mjk-*( +zZpJ!;J5Io&F8b?5neN=I5z487YA#(!6m-L2@tRmrgRX5WL;l{tDS2;9@nNa36%{(KW3gl$v62EMb7`7DFP(iCN +zu;aQWyc0Q;UvKSV-ip&8@|wLZ?dYd1M}Bf4OS75%RH`fE^|t~w>&iNBye7cpw%MiF +z?3-9i$44Do2z+yRz}G3;z;3Rq^Nxk}%FWa4VdvZ;Y@ruA*>O}|6FjuAOe%DJ*#>i# +zrA(KJwb?aBx4m(L_C$jc7tT#ji&y0Hd(0LLe44VIE-XZtt^Gn=*&OJHCa^8a!FI+- +z2N|K@eh4_QmIy?a+5HD~LoO?HH0*8!VHG7%b;l@_##ySKLN+_r6qI&-7;{W^;cFB2G>g?VZ)jDtY1&3xF=H~)R1jY8fTlVkT +zcR<6FjT!!zYy9Sk-0>H-2Yse|gDGw>{8#owkTsQEW_YWKx0vFTsY;vSJ4{KdDbAS6 +zmi$e5E1gigC3z?rmi6_Sk_~1UEzP>Q+;kG370UBb~ +z`lzXEF-0p($q^H@+^cSa^h{$~y4+u{zjk$*psUxG55CFO@i(~|Lo}kw(2sliOz}C! +zge6&1=P;&3P#&ntTv?=Z|bzLUWoi-Iap^Hgmj+!!tY!f6yb~4O%GGag{^(X8k +zY_sSTbvcYo;}P&Olb7pviv3O7-|60WlAF~H|d=MGi4hV{*JdL6YZ}B)=blVL5GF38XNf}!|W2z~mz8+COrAvw#@8`g%F3~&HWyTIA#}@8^ay->i-Ll=w@l?wJD{=n| +z4h)IcxB+mYG)E7`ok5h%&3U-<8hV~-=(!)~ijSCy;+zCK`Yqt%Kx$01)Nm8R&MiN~ +z-Q;j34VFIk-qI&T$)ugJXvNa3_KJCE4eHeM0R0-N)za6XRtHST6U@ftW{d|b;7{}y#ku`Nv2Q3*Y?mQn +z^0T%plote#g~F`A58IvKIngQtkOlQ;A1k)i4IfzQSo4Wml=mP$K|bCZawz`FXZp123P{jx8mujYrPiZ1hcbX +zf;c|7a`)>>EI0mslZA=eZlQ7fEl@`%7y~Asz|0P0i¨uhCB$V6|T3WbePA8l<|I +zzxa6=ooOjEYY^nQx%?V#24dHY4CRGx4mpHQ76;#9DHnvUN0)&@M^H+h#3o((TO$n5 +z$d={&DK0T`rx}+u6Rovuw>Jy2W=Yn}Ntu;dGwhH_wC0zUPB{ODHO~oc6uOf*3$WXX +zZk&iZUG1z>Ui?nvf#%#fId{2C;mzOTqnoeE%@~dbxI!ql48MK=GyJ(XEM#2n>jGbdup~iOl +zqQHeHT(*}*p(8?S5V6&g(*0sKDLEl2U)ww#=*%Km)2v`I2IA#@Pbf^Q?4kmh=~-{s +z@+qEZl3m86PZld2PF!z=!k!7-RbqEU`-&Qj>F(+xO1o1L8HGRc*;Z3djW%O??DOI- +zlk7IbcN(HdqX|A9HpQ?Fu^EPSqeg?8kK!h)ER}{6K}?y^;y6n?$9U;1a#jl*h}Ifb +zk)_NOo)KlVfm)(o?PkOVGn)KHQ~e%}SRTxpiau+*s8keIW(hyHn30-7fL8TUV|q;z +ze7aT;#q0)2ff2NQPEeZ$6(NljB{Qu;oi-siZ!(Px8y_FJC~*r!Na!;RFU*=CEK9YS +zBnk&jG|>iK!9FY}?tIwFY(={%&$Mt$^mLXP!Jx#x*AtQLGGiJ{WuF23@gCR+~dWJ83Vng07KiQK*lchSBIdo$6t +z4*M>CE2nV7MnmVfayY~}U@NDvq#u}oz_Z*o4}E609^Sp@(2U&|blVLYHZ)4&H(Y7& +zW8oWvz|^Ie@03;K&x}}3AQ*X#r!~`(Qo_MKCWUesfq4ox^q7(!Q{JR7XC*=VJ~OG+ +zjL4cveR2VC>hKn7nYZiBLC@S+0GkAl+ta*`~^x@|WA$Hz8!s +zt^{b>(b9Gs2+L!8U1lsKR7Eu~fzh1d{!DmLhU3;4!C+$4l?lhZ#Ch!3r~alM+rk6B +zv(a?cNM~(=>+jK7y4}P#n%WKh`ZMO74I!%bwc*uJ)ANV9lsTI +zhfmt`3YVFLYk~3(!;7&6sN+VH+-WM%^;uKfV(QrOYcNGw8^~t}t#lXy8LcKF+pQ2_ +z(M~h0M^)I_8?nMvrp*NQ*7{7ls%ETw&_eMm41_`<@M>&}sil37Z*RCcVv1T!1zTXV +z0AmfJx0(a}!!x4PY&8m3ry}tz3BM4-cBoVvqNkZEfX*5@#0==erDb*plVXWB#fr=T +z$0D`L7`e;9At#urvPKu|YO8@?O*FC5A*LFJ2%BduCqPq+4GU^jVY5;$4<9l5*d=CU +zJN)S|MZGePRlO#i6;ul9F?=N!Ratgb`JL$sEyU2lmN^n9cbIazt8Dj`p=&kq+b$Ls +zt)_$#8rt2iX}e5rRhqCSG%tQd45)55by;owrd!RlZja~i4d(eGTh5jo3%l!>FqYBWTmuNFwAT*tFvZu +z#&oopX4hBN%x*Eg+-J=E7SoM50nIvEvIR!;NO*JY!~=#QCP7 +z*-Ys+eK6NHIh7{tR<&q}!|G>Bi&<_T72dEIS^@LX!!2esD7BeR_Nr!>Y@2DwnpDcP +zvo~&i@WkuQ^hP~B8;~+W=L<+6cfkELcVNIe2q-2_GL2oP9vx=0jo~nQ=`xeEo`h{J +zW>VJni|Dk7K&rUgq$UaanRZcjO3KV(|J{ZX;UED;ehpK9w;A7LntB9llZ6<636kM2 +z&1P}erxOCHv>E@HNfCqO+yRfr6jz%n_UW@`LW^0rLNY{LrLk2YPU}z4@zEf-$N*K^ +zh^6Q-Wj)eN@$MBS^{mtcA`d7WduVDC9AjGzP8Ed2sailVwoiqy4*RCCO^dlAYer?n +z)j8ax1R26poAHuNTWY3JH(1sd(~3UIn2Au`wsJGfd%KFPLun0;6WeNvSXj20hKw0& +z5ydI50=kSj)lEpL1t#l-Tu>6{yNiRIIUVjc6Ch=mMx2>4J%~Do98kC|dX#E1eO+d4 +z)-CRk>smbY;o| +zFLY(fPl{(onCV^l>8&1jnMsX96gD>+j$ttQolvy4NXHHSO|+_qrbe^CiXM|$k_=2O +zW)*EyW=6_vXfa!}1|vjvv6V#jis2j+P5Pxz)MfIgs9*)qLDk%(S+D@@n=+{JMR+w< +zkbANQu{|wiPU+J?Zq_@%=neUG&C`<%s}SIaaNRBH$0?eePMOnU=4Z_eD=`SlsVTE6 +zWlrsrn40kbT1A3W=!n(QXqI$IZ9xL``>H+x&|_OINtre5D`A=~t>9Ulf +z&QcT(`xLhFtc*FcMS2$Ut+WWTV%pYX_R<#BZtr(;pVB?}G78$g%T8+tNn4{?)Mb{@ +zoDdXIqdv{%Q|%}y(6iVV=`*v3Dw)?}x)8Vw80|EzO43Sg#VkUzWX$>&vjv%lDlKM>RetK*&#j4WZedQ{+#3IkY3u5zR*?~m!VDyz +ziJFpg47ZW+LKOycs51+ZL-tZ;ZlAXx)I^v&03&4R)tZ|^#v&tbcI1SJ;Rcsz@>)0xF+${Bx04&igF@6W +zM^3c6Q)U^nvQL(Ja0xPAXq_OV>yW?*HzhI_ZO)zPFgUBjn#@$(`NvEtv3wR;D^b9? +zMb-!wS(PlZ%tn(~FRwSj0s|wZBU~jNmW9Jupb$C;>oC9J;S5_B^4o)kS@M;J;g>xS +zpH_Rc*;EvN-HakovvIN+QT#PC`W92M!4>d&DlN);WD^ux!5Els*^U|+ZosPXHHkW +z-DYg#kiB-8nSR_!TvwX1MpM#eeg3lLLT%(f4~bT*6AHj!F7k^vFXS3PZm=YSoCjv( +zWQeii#MQD67OG9B8di8{QZ0AlZFZ;3o0%^Uk)9y2=KLv=aTDwSr2AQ{CNg*0UWS0F +z%`EVPna0UOLfvNiq8j5)gjZKoW5S7QJl}Sd`je&9g=QLpH{?jmA}nW| +zsK&~u#`K|Uw3^dBEEfuhUFL-KRz*EcL0|_%vjDEJ#D~LpKEBH%4xz< +zTpY1j(Zqy3I+C;zd|#|R`~MG$6*cn4mVXGQAx(!a*kv8ILsk{afYFNhky8wVoZ?F4 +z6i`CF`kYZNCCd(Pn}`wZFyq>^y=~Zi-)Yj_rmIIQ?d%3QjXgMaxSfaP@^$Z&AD=y} +za-EBghx-nhkQ?0h;*iA_qBDhE2EzWWZ08W0q`NM&s9TGYRqSkM%<0EW7m=o8W)ADR +zV}u&am}_Ma7pXgTe%xh07mU|s?y^xA4x_f3aTn#F>@o|x1=ETnW-dpsZ0DqnMs{v0-*1hT+XY)J=b8zS-y_hHF)@a3<%jYE|-5$FbgYm)L*}> +zDoM|AeNcgzrKIi8VI3^Buj-unkPm^>cBu+tcJz_R;qax$Dd8Ifo +zgf4rui!`!Z+gt=CD%P8Xj!;q8B&lsr#sxNBR*)&5bOzXx#A{Qd=3{xT}KF^z?EDO_1(JIaBy>*79H(&ncUuI%5VxBT=+EW +z+{Tomjg{<8BD}O>ywVlM5QF5+4PmAoI#h5nt>}yoLe`_&i1W;K^*tau?*bqSuK);P +z9YMA|RbC2KBK!;IOX3nby)n*R&fEKADTO+8DTf#msHpe_gb`kDXV +z_rX>t@wW;>6;K07n669KY~}*Nd_ezdkrs;W(S=EN0$9sim{T^4rG1+LJ5q|!pJ+#_ +zp+^g9Z42}j>`1Y?Ios}qG}^ro791zs3n^kovN>G(H7mf3WT*N{Q^by)UP2;*kB4nH +zu@l9=XN3{I&5U73dc|M)CG5$jHxpZO1oWeIVKuDFGOISBRZ8QraM1-V;Bp+c|35Wm +zJ4$mA$}m@j09rF>!No|P&0A!=UbaF+3DX)4mDwznX&trZ_vvONipVKj6r9srJIqun +zX=)Q)CX~;yg7tcdt8~5LH5}%9uAZ=rC#N`6vS#=xZ28-9cz+7zNEf;8=XJ@1vTRF4 +zgG~9WHMDV+11{IDiG2}aAOkMFuWgqS+&p()fHp8{N{6wryxn)w_bPX7*^_^-@^5`- +z@&p_De{J`^;C;#e%cj2vT`y@4e0NhXZ5EalR0YR^t$4dh&&LgSZ`ZiBF@&$M3dB>| +zE;QB4mlM_Gji-_1yEmB1qyBjf-f|zadLrA>ts7RFlB0INd$e}n+26%zGv}Rmz*Iih +z#Muolew(T8HkG&Nh!7qm5i$m?<_sjx9p;xKNDr$Okt}}4&NNl*`~gV=hi_U;{eHc9 +zDkmO2RddwWdRdTmfmVUq{bDQxTH$m7Ey +z=Ao<-u~AN;ea+NRC8LtzYy-0~COS0O^B)+UvC1utj82J&gV9-_(KstyErKw+`(465lSr%lca0CmP*=g!| +zziG%){Na#u11x>f-W#Douc@|>z#)`6vjRF-uM}*BC2^#m(bKrA=4{);ayh8+7S>iA +z*WjH+07f$8(c^&lb142iOFcFcb}=Oz!Q?H4x_~X#mI3O) +zo>bd_)(vAn{c9)H`WdbNS3U+%XqQf4<@_7}ConUG#rk%^Nh}hNPGrOKXU43d!bH5b +z?+F~*bzu9J^JW~}wdKI}^JYYL4C4BOZF>(N+I}%6fRg>LZb6-#70X*L|5*X-PyQ}C +z2uH2l$+rGy-mq-GcZMpg=DuaXAvb4#nyX~!Bbvc@a+jh{M|dl}O{9Rh +zWFZ^S!n55M?A)|t-+@EBckJG-Pd`{r@_mPPcTd&B2UXj(%za>jUUEko3mE(wPB&`U +zOAc<@e&E0!zBb`T*}LV?F77Nu13xI?&p-0aW8q*qymi|S9jO#t_#M0T;S2uypJ#OV +zxt=w~wk>=1_^)Mn`S2f)4u2H{$-pEpF~Jzar~YedO^~cG3AWnf$*`P2CQswZN%mTf +zY6>W22g}~^L|39ei6qNhYU(}5cyf_Z&A59UPg;$ZNpc7f6PFBHCg7^0%aY+NWHTAw +zf7PcsQ*>!y$~6+YxhbqB%r-I^UJ#Yhe^_?N)G$IKnXWO#0vTT_*HBFiAYCA~}lq;ibg6lC0`#Ybd}SBLYMWqkOc6(-JpKhUc-TMh5L4(rIzB##BwP +zwKP;b**GfSnk7fRwN9(C5~30=*Kmg!II`|ZhGzz57!O!h4Vyq7mrM_W@RzYnawZSz +z_9%C$D2=HeY3e9b*M=)-CgMCjL{Y7&Oa|FRU~0qCfYQ?N!VEbLP1~9}Dyv~QA{F5f +zPc}msfWWkXj(fhsJ40&ErK!#DsqL8s^WEdmVn +zL2r0XgL@0Y?}!zahCy-|poUMdzZyqQkVSDm2=B!Ys13i((IiJAjofN#Dxp$spQv;{ +zavs(sLh3$oIk#bX0CUQc;RnNj($esm%QGp*t`CO+hv$cw;@&Dfs5CvBT +z(@#d!?y9L_C;Qe4ByW_+p|bGT2ZV?l-U%hz9C9OcLCcOzau&~On_yIU2@o&Pe6DSZ +zey7-8>uPF%4t`6l=#ukh>aheCAY>+dK{L>fm?HX~4DUE7DbxI>a+$CR!dEVHIEw3i +zpv99vh3W%hamW~8(xUglTTDYTNT<`|$)&kxD?FJ-Y=W>PNKVwK;gcwmAiVFO#XpxR +zd|;tQC7JNcInXRHp93;L*KBPt)$}$p%izuE5s>F~iIM4XT3C#P+>?^wo#l5JQv+Ys +zhCX@MU*Iz7l4BAHV0hO)km9qklJXx{29%YC@7*V^1>`e6pV^^l2VGvMM5NV2BZ7qx +z)CzrYNwV;}&wrO(gmw=y2&jGZX!NLb(4!~wkLb5tDmEUnOBalH8598}9G?hFB_@aH +zGErEGM^u&Mpdymtg}?^kL+}n7f%whBAQ|4fFE|7!XPB@~@C!fK_g%0-kW$I;R+K@! +z#-w3Z^#qe<;WU8?9FYPhMSV5DSZtNRNX_3VrlcM%%y=)t34_oMS5Hh03k@eIBv}>7 +z3r)%N6o=(y6RPYYE?&t;hOLFrawVRG!@5q#+0S^@p#V8jjF_ETYucItH +z$QfWZ{_I>cXGghvWzewcCc)8bRG4fAwl1#250cwpA~5NeBlXEF +zXh?&?7CSB9{stt|ay26%Wx)R$MoCS$owxQZY70OOt+ZS83#Y^FXVHDC`2lh867DAR +zfaw!IMKyGDI)l_CN0|87Bovb^t#Rh6$r;i(&)tlgoG@lYGJNDBy*HtA>mw(~u2h)# +z$QtCL4jSsC7%4Fq^r>l0N+0RoP?)dm2B@niYCXV(_FeWep_t$d0fuEG@_BHw@Qt4oWr! +z_qRe;pV+6ZAGX3`34Q4d1ybPGXRl&?sy;XYUr;p&e;tFOk1~Ipo{`8EajYIf9)=i1 +zDw<3QuS4}v0OVByoYPSDsjUYtm!xXyYHA}Lh4;6(?Nr=06*wr6`S@iOT%4)e-!GOC%ndy?-M1C +z4=79|>_L*9KdKzCRU+E(^*_})5Y-7Q0(`(*4reV|$7*UuN$wCBxQGMkJONDx0_#Rx +z=)sjB%h_f)Ytkm=95Odw5DByrS}1MOcB1&%Ksj~?Ho!y)5&lVy!Q3#LxhKFu88~I{ +z5Wq}M*$(-J;xg|rz}BjH6c7WaK)qXui3DAuDDSh<%xutJ8pnazPUDwz^%MEE2jR=I +z99c?+`%|`aNt4W-2*ou6H3L{_O<+~Kscd3Qk@-T-r;g{iuUNo~4QZ5+or9?KTBZ;h +zvIdx{1ff(i8tM+2o9JKE$#<;cH6oqF4lm+_DSZTEO%+0+o-UT`*q&@h;&A~^7SL%{ +zBCE$sF8LL_Mal5}o^@Kg&>v{&zc=A2q30f7VwAle% +z+RXRk^km}D%m^mkBB7aMCZR;+XnpolS+q&v7l;@FzSWDLW?kW}UCP_LFB=&Y#2}pv +zt5Zon{uXKY4WhGK{+KyzcC)>sIb0lWLz@>Rw8ogV5IY( +zwIFInKx?JvNdCB8nh_3*$~mR=o<` +zy5zWA4Gh}nV^;smQ?eV+Qa-2InKCbvY|pXC`^HX1hT-V-u;x6@hlk^x?%&O;J9Mr= +zrf}6K1~r}19D>!VPLVvvmj*Luys1%6WX`e1(&-BYbn^b*BXlONX)cRP%q{lt#tmQ~ +z;#NkMK0!rz`&E!M +zM`q^-pPbC4;df(lPlB*5o9uL01ia7U6h%C_T=P#h2ltK%S1&!DF{7O7m|QpoVQkvg +z3?_l?yW|8-rd=FPGq0E;xZvbVi6M-dLXEU(vXA@CW7|oPoRpFld(8iPV`;H?@?SI! +z%fk;|imqXrCc__^ppPJIGJHRt#Sp7iyFMxpMiDbW7VQFoNPk#|^8_Ht@Dt4VqB^(| +zevvJ`qVO|UX-braM=y~|C=P$0++p)KU6Rp~hFSh+I&$JN5x>TEYLY9>7!}L*mC5$W +zJcRWu)iefrLXefoR;fIiE)#3aczyv9*eR>4k! +z!ktn+G?CzGGKR^?_Nt9o=2n7ujrALgW@yD5wBN$ZUqJuatMFS?KY{Dx!Kb*CAUcH% +z3kH^qTFC1Hhi$i5$)?XKR$ejGaXPFbzQMAC+XA$ls(SGf=TC{V#8|Y+ +zB~3XYSe2-(G`t1X%$X#IZ2}H +zn$?iXlTvYZzo^+iu+?kbUT1h18CSKyHCGhIwL{6;@E?T<}ImSjx6}zH;#p5bS#0Ykval=WeYmmNh!;p&|SZE`S8radX +zU|_mods^K{>d@}tyRQ;QMoH{A1IP>SHqeYOT8n>KXGTm1c4n@nznjT+Ex>USTV!3` +zLm6u(cIkhi@`st=MW6puS3mPzvAC@vf(qN^_r(Pr6H6D~i&+yfOJ~=@8pr>ncI`s; +zn{`P}i}>TX$-i|KDw>-_J{@rpAS*baL}bf18hEd?BVdMpds? +z3PtF6yHFsjC`G{nfiHa18f>N})7)dqwOF8mv|9SV?Yon4e>bv~I9T!_dqi*s%ki0~|DJ^_b( +zF&>bteK98ybS(f@UKr}tgI-X#f1O5oO!Bzwehi{hnNpn35Y)5F+e=x9$CGv`=nMx@ +zR~~EDW1Zv$#(9+sl1v=05OeKRQ`u}rjWtD0>=Rt1whb)U!K>DcAFI$D{ +zHsm^y9jFZ)i8%s2wok4D>fcf|+MP0X7Y2u|%ImpWw`tda_bANWDp`g?_$wdHXpi{5 +zI|jQ1j<-lHOXLs?^3>AU*F)S&fG%`#6bKLj_~lV9P^u-E^y`!-QC- +zpu84N&;njfF!MQ)nj}`p^Z98xQ-ZV#Bg~Z=6I_AyF_kDWNFW0yd3YDjD#;EuP*(QXVZ^by;=Z3Wg-&e-{+6;FU#;MXV-+-um39_n4%Vc>0 +zRgKn>yy>vq$RK>FG-LB`Ijm)u^0;_fn7!q&bu?8XZX+#q)*U>GKV;VwRmt%8?1ic> +zovAl~e1*!I$s&mSIhOrslp;8=#Fq6J9mP$s9KF|Ml5$^(l*wzf<~8NxT9o+-sTiEw +zXO&^s46CMdY<*gB90ZC5GW(4pCYL}{LDcoGVd#Ae5S8ki#~PGFGxOU +z=M>+w5cGcG@jdnk`)zc6m`a)vMTC2Yk_bm-G1#pJ-1_D5TsK)SXZO>OK!%J{@ZA)@ +zrdJzBiQ=vkC)vHnJT0&Yj)iSj>CVI6ao`YFISstatX7j6mrfPC)xC4mZs^JLh4-4T +z@yxIhSEy4Z!{Od{hOj^+VX7Kq2n98C?YrH<5VdVp%NQVE$a;GZ1 +zgIz?S+33-gY%1@}T>cuBSAbOlGhni7s@VvP0t2%xtzKbs-fzFLO!dm^traN+FP*7i +zfFs`MX}K5JmjiSf9bd%$ClL1OT&`3X?5!?>Z=#up>YdnN=8cz0nU~HR7J)4)T556> +z0U}KZpYX&zF)=^VkC<}Ucr8oBIWaZAYa=*8_ydcm)3@)daC7rV2kgom`M9eh@Cy%! +zt|=ySWr;mqAR?LM{ML+g93aUkhUGYtYeZn)X=DyEg>5Ns;nfLz+pLC;wgAq9qJw2Edr})6?ApfHsdG8r?lJE%bCZyL*6vNZVMO +zvalANKrz>bE$$iYnrF>e^cvnMYn&AwAsfbvb$E_>*31cGGYP$m#LO`r)3!F|iMZx| +zRkyzT?)zzoyWZePe08hqR@JRrw{G2^_omtDMyi3zm^v~wSFM156 +ztu!HH(J)>t#p5&81Bs?aF*9C~#w;vO;dykt0{DlgCaP1D@l?4y?^;%Q2qI>s=_+%2 +z&xAC;Iu0{T&5a+JnM$}$PfblZ8;Q^Z)6jGGJ@M|n@t)H7bUB(kGP{U&9XK3%_{vCT7L?@2b>nRasO$n?ZiTx?vbIyp5lJqayQxl%1JPE;4mQ}NzX +zT&VyvGj(Wu;-Sbn(UkP!Y;AC|++4=(%qGE +zSX+u}gF$P#(`-z%0acpyZU;9~&m>9}HhNEq?d?I_L~U)*R7Ljejql!_)HRE%CX-V$ +z)95fbs5)e2dhSp>BV94RSe=h2;EAw=cViB;(35S5pyNuet?h1SIT2Qxjn$XXA@`2K +zt+Nm|m@MkCK}^tHZ@dG+LOv&<5yr +zxS9l&2!@{Mt|2zWYaN)ou_tMHVHd#+lj4^$CKJ;6>S6RjbuXGH4iB!)cy)PoXpyci +z65y?C^_70y8^Uej`xEoCvoVH!x_i(7Q%yT0j=M`s7^>|(^(A!5pjpLV)Qd{psTlS` +zFo_Qym4^z%z2#vOUtUF^t&7*iwML_*pMUM0?wcm7lg(2IgO98=L7R0>HBrU&rK&g? +zbkN+qbXGh*;rdRUZ)9NFD}gDVTpXW?D+ofcba^TooStoUy8R=~zIJZXhUvNKyhEtd +z9UY%`vjTqi9jKy14-R9oT1|a29bXU6Pn6&(K0aFgsbfGT%e;<0}P%& +zH$Uh4UAk9BsM@;SZuDXV$hc7(*38U8VBKMJ9XdP{YAwRXkM2IT)A9)AQx& +z>O-nh)`(+Gz%h{+NZyv+hh +zlT%d;LD&tHPY3QpJ}Hp^;@eFPo)J1LN5x@#{Z_Z%8oC&s=}R#cqSMs) +zY&?evtBQ~uIIQc#idZXUPxHa)$?rDV?~ZqmIm^m)Bjyy-kIzKCM%j&JOwD6qSU6gq +zhY2V0eNy1oI*KKzIfqM+n`6#xkHzy3YKT8Db$I*;{1cO8z13(oN|P1+Q=Bks)T{Mt +zt7^m3FjN!4zhS+SpSTM$!-4jr^@|(sGM$J^9GTWwBAHU+Ww7*obsENoT@O42(`vpY +ziNsOF#p$UT*C012st=W>kZB!56e`t*^%aXkwNtfLyLO`8EOk#KK;zGYBG`&Q40hie +z@3~ujNZrHxkT#Ou6UW0Zc517sh^%ql<^dg8IwVGgN^MRm3)!nZ9k>q$WinwEdXSCt +z;!MCei78!@aA17yLFX7@e4m}J%#K$l4#$#NW2DcP;Qx4Ox7Da1k--S-H!}m#napA> +z+yiN|ntuEMQb>&;;_#R>BK$Sm)#hDafT0HQpcmt>*50+;8r}sT7t&nwhV-`AV~SOyo$l4=3|*;x8*_T-;gecUR+Deb_pMw4jE!n%2$B7pLc{yYIE^ +zb^_l`pKP{kXMFPLER5HJ>TB(q%-3uEzN}-40xc5Qsq)PHxCA0u@o1~m78-tKI@NmW +zp1RB`N3CYFd7z5eaR7hFcWQmOd-v`!TOYvvhtZ%vm^m^Tj^Q#^P{@_M0;R(bp{EZb +z(_}{Mev~vOa0x{Bz|K-hHLK2+Fea0{2Vm9H%bZOs4!!ODvzw@gY}&Pg(!z*LDT +zVd{ROaa=nf5VVVmYHhY42FP_r63{VTOwCo{NzBS$c=w#VC$yYs0Rt +zMP`#Z5TDw2iih&lOpPM~xl|alNIpx%9s#C%O`s8e07z=Y +z977VP(tHI206vJ7VAc5{2467tQsGzzqD;NIIB|0t<~^i4os*o?@Zw~=mRWE0z$YXIZFf4*6 +zYhd(&+l|5CkaRm*!ji0k#Zar>9E>j^&pXiV4i|fgo@tqLSQ_Ki&*bM|g295=EsK*0 +zMmo|a3m|oOp{R4Y1dxp^aYWRyv^tVMe9@4!QjC+FSJJ3Kyj2y+(FZw7a#2uCfCQa789V +z#|u)xt+ZYC;ifN_KdXo!qHDM^x73}C&KV6toO)aqQr!N~EcS-7Eu-8WrsAqk)FHT&Xm$VmpRFS_`cZL!-dMPQc=WZ7%QR@{Uv#||$d +zZ=OFo7h&@bOLcC$C|%*iY1@Bs<-_-oS5K>ZnsKy+~yanK0nojf=hAlj=FP$!KItnD$hb;5C>Be?8G91{cx}% +zj;Z5GhhOi+>LA#M95HVo^6Km)o5exvG;cZZP<1NCE@)*O%W;V=(!3SmTw4<|b@%OY1Iqbx#(L2QY^wkw`kBE*nE( +zATlFY7AGpH{gPlvl;#i1Y=VdLxnKvbj7bk+1;e>Nz;3I?<7EE3dry4#{XyF6>=ioh +zkIc_a?a@uc-CFlZw>{Kzm|S3VzFnR=h&kyn1O@@9Bk?EjY;hx=m*_;Kwis_CtxJZy +zi??p9EKb^nj>hAld9q}X9Y(nPG*1FT_1$jn3=Ah*67l#EB&3-LSddisJ-b+pFH5W# +zvwrMzEeyS2n^-cBvQ9;wbuxKsV(m^(?%i9EvPxnihbO@ztlnF5F@5(`zpu`riI;9q +z)mQPQi-GJmG-EL-+hXIJ35$d@w@ZnRP@B2laav<&N`M-`X~zi!=TU)U`B;lXE1nF* +z_vE(nHN*sMmW^!{n$@+I)Lf;bwuyzasWK_I)E88E`hPF0TYB(%w%T&r;kEAxRH!04G6yM5t8 +z+d9Q2kAjUBIdj}?hc4qYwiy~G{FBoM4`Tcx9h#n~#0RD@O~D__4Xt6PcFQH;8UgfM79TD5P=F`}&3H!M2 +zp;+3U)GwUQ5k;|BtjI~?#5j_EIR{2gGlO#}9Y#Uuk+5TjOS0K6gUYswqxwp#S7{C< +zBk`>?b!EJxrk$5gXjqp0B*YmzoT2=tP|`)hfa2g{QH|y76Ti +zWhU!aY*avl{QA}ATMOXH)F&IV;tqB+p&{iq>?3UIHL93-twHusOi&*yhW2Xgx)c`Se-hC +zJPe*U?+$yy!NA!>N0{vZSOOBPFtRrmT+imE=n1c?%>?_fZsMxZSEr+9hCLAvvw+XCp=({GJQ0U5T=prj@ft_zz%-~GdWe{pkcfUkV-DH^0U~km#`l-t+QQ&yV +zU<|@7E`(rA;=e(-%^C}H+9_Bj#(_t(Z59inmCWe#2x*%CNPj_9B+VEVdXke30b(-U +zoy9>^e0aP(d2}2zT5`G{%putLo7Sl6d5oS^SJMpin=F0I6#h(b5_|vzpsHzh}3b +z($YJN!LFj;mU9`D&oz7g6i?#RtuW&`se7D7{EytS*Wj3_7!1+EEpa9H8Ig`m +z<{k~{&eS1Wk~+Itp9`<3+iP}^-Qms=mb1?6T;qG1x}1y5G&{?~6}rOceFr_Z^LEx1 +zedvAnjvbY}>TW!2m}-|5HMWGHaKOzCwt2XxwCXl>5M1g=F6yT+@548hg`0E(ubV;I +zHW}emtl8hQ=4>|6~G +z$K168^$0Kv&%a;eOGH!H<$pa&Fggt!2~8CF8nM7J|oTkXl+qQt`abTzz#){_eg_z$)o +zPWQ26d%BOq_0xT)Wp=z=BlTn4Xn0#n%d=|$R +zh@B{YYvZI2p*0!7T{qgn?n{rTCHk5R)FWE?SD+%ujc5b6La}=o-3nGiGv-GM{ +z;%FI1O^+9?Zvo0(WJ%5n{D2*u#x1&w#JZ~$Asdp^Y!EHCnwW_KrOUXyhhPniE??y0 +ziH=Xrq^8zodo%E1XJB{0lr*EbzmYzsL!`U1l>QA9Y4F=#Nd_^K^}CI=dTQG$5buwy!_^}03=byUU=+!Nm2FMhEoHOL7Op5d@qH7iddMx&c!ZOVze(&37SQhW$K{SW^xfeWhTP@TRjLd3lg$pkzwN|hYSzQlmD9LG +z=@uNcqA3giR^7R1*4I>$*-*x{I%YD-Oidh~*PWSYVxrs}$WEZXcA@u@B!Vur`m3kq +zdf-}bxnILf>h>-nI5P@0WV(|s)d2^t(??w3Twbg78p*dRt&c@pdu=ty{72^A%1Nrr>}6M$z2?E>#(OYA3QD9T@-mJ1$w034 +z2%!5DsaJp2+W0oSoa!gGPG54=gIhhf)t<-sEMELV-{U%~%SLPUlh`=cgw$XB<~4y} +zzYQbP9}mcDDl*Ne%#7=CrHwR*H=blnO4bDy;%LdBMAh_0VO(&Y#_40Z+mNIvWkWH?nwR{E-f_)axY@t?cRIAI#b&&>1*a5 +zQaXf}DyamMf^Y?)Yqy-oF +zbs-{I-cV-bDDJi!vSEvIsJWhlyL&h;0hMEt)N~t6d=_h~^YhqGc5|a!&jj|}>+K6$ +zIJ{mgp2HO$y~pAgH5sQ$GVNqc%htX(g5QI$%k+VmZILWqYS)$rd*s|oR|Y$Zc_hZfx`1leu+nnXZoM`CJ5F}&PePK{f)bV}Ajal6?tpA?02 +zL*rgIH1=wcOK!aAWdUK$oWR}z@bSszoBFzg^Mu60E+NF4I=P?bIs;)%cK+m&R$_&8 +zf~h%su)Y?Z)xiQA_>G2Kj;sj?mK1sJSizW88~PSN5np{N3i&9`vt>SY9%Mc2#3y@K +zm9?Hke+j~t$$O6J2JOXB{vn(xxQ5;BN~&La7St_e-20Y&R=K!<1UNL3U6RD^%TZNA +z!*k@Xz_@uOYbewD+ECxq&RfcMVIp^+DZwsrXT||ep6S<; +zeMHF2HttPneWM(P;2C`spBlX7RlY7P%n-KYaf^$Xeuh7{G_JTG^y +zkfL%Y3n|pTe8u|}b!Zv~y^C{L9$-y4U0x8R*m<#s7i^p3okm5kv8aW`U^99>dNY +z(A0bHV*G>c?rB*(4x>)-Mo +zQ_@B3N#Si+X9C>O&Ggr%M-&nf0R8}=Z!iI +z%Deb6PM4$ybW<^Cd@`)Fexz1TT)fdMo$fF8bOSPxX8{9b1LvTktQZ%sRVG%l_%w?% +zV!87xciLRMK|im$Zbp@4oWZPa5Tv8JGc4i^M`b4Z)sUof=v2;_LK;bg^+dZ_>w~j) +zJu_(wrJPuuD^$i0BG1qxSapNYTyD%+2*lgvhj6T=0XbtXLRRRy8tsl!KXl*v|-UOja- +zvnnpo>w0Rovuysv`H&NB)B{t5H2At5f#F(LRo!4&qjoa+q8v=E;AdkWt4Qn#opd(j +zn1=fWQ>nU#+%b{>C+?+#4Q?gT4hqBeNvKG0r{L>R`J0d#%llYJfa8)yKNujA6#Rg4;g#xUBc}SLG +zsYQhwj@aqJO*Xt2g-gYJ?aNzCk9sxd(CCoK1AW9m?yHoRzsb@Z3duxGUvXnYqIsfy +z(WuOMpucn`9>)<%8~Kqc9%DJ39^v5-Q$m$_oe!06A&(c2pa=Hxt%hhc-O-N^MLn!I +zoY6&-DlR|b9bJ4gNg`QR^9clP%S-T?npVTTH=rY$>hGIX_%A%E`ePR-SktsysJmXHX*34K3_z^=me+)Y<$<5Z{xfhDJPX3f_ub>&e{# +zv0muz;-Z`$WlY8KseU}{VsNGXw=f$LMkNtX4Nj%qzX#D~QqHvlmvBE>#+fy^ +zWER$7H^cYj9ZhZ3gj_7B@HSQwE|ZBKXSq0#vRh7aVQpr5)_nsfr8;F+POCSHw;h_9 +zKOkS#Sv(N9n)Qn+&vwh?AbsX14y`S@wM>2EgW1THBS7 +zT_c7y*HLEz2gSk?P9{?wdqaGhd27{$^_1oi>Rh1H?Pws8k%0RcDqn@ju8PG3V +zdIW}cx;zyM*<{0{9Da8I7t3W*9O(3sB$F~^WNSGeaj|R>j}9|BO*E3J-WZw`7xU9K +zbR8?nh%T7CV&*Jpc9=L=X6{~Q(Db}nU+D(J>?pz&{V@q!seIVQcQ*+Pma%^;9RMM^ +zt;67`VI-oR#WD8?s3< +zGjdLnSx9|COowF=VwKp(?auiyr1RE@F)OtL7fc((;+HdtYm2rd(-|^25I=2=B1WTV +z|2@2Lesx1lql}Crgddzy?!iVr{?hO&{x~vDcH~PIv3{8bX-F>~d@&mITDaOOP#iD$ +zoFSF`AuvQsz0<34V-24!*7@dS^Gw`dkCuC_E+oqmR#cF~ +z?}7U!6M~#v{l<=P1W*^k0V6Sm@=20Vn4>{~99p)#wMor>A76`f$Z>5i +zdJCIGK6#d=h}yMAJziZ~hmFNH!{~%FM|~w4p28Nl1d>!8udV4*`4M!mt+yVVmTVer{?NI9DTIm +z4l+>dG6C9x!?iGBt!qGsM9^&FlQ_~?2slw&LkfU5t})QztC&9ZiF8v0Hyg`1Uhj66 +zTCj{dJnj^#r`2en;W|4oFtYS{Vq|J6JCJQ7 +zT-VV4l&f~y6EM0CFKjGzI=HnC@dw~8>}2d7H1TDr2%~F&!@|{?u*F;j&(UGg8RC3a +zT?=0?#Wxs!WJ;QCo+rb$gFe?cM8Z1;E46lhBgn32jv5TR4di5>6hS*bR^B*R<;45AYv3tH4w3mJ>DE<&;{gB&0GgsELD#mi-n +z;9l{nTpeyEp_#Zsoa&4Pl;3y +ztu~3> +zy{=e852uAmA5&T!ccd+dqFCSJAs-3C1972)L@}j|Hq2clg*NHm#wW*1`fVKi0+#3+ +zNs3(no*z^+_$6vP1(A$#tB{(vvB?0%zx$}{4lp9qDoALa6g%OquhShYJ2d3VIyzBA +z4Kdw;cX-_twb+@FcBhewYL)bQ-!Ph)KCoCh5LfZiRt2vY$9Q93<~DiNI2xbC=T`Ub +zw&$K`W@6I5t|B>sLn9*X9y=DbTPI|?ZwT$hUGb^z{Onuh6EY +z)nT-D0?We_$V9NN!xpXPxQ_chCj6ePa5%PXwo15^1j8i|E>rPyCQ=AoFd$L_mjoM3 +zqB<=MBw+R%xUVnc3w!Cfl3T|?phQ}Px42%bugDh&W$#!GaW5{OVEU9%+`(yl$t)?0mg4^LN=y0LWG+5Vi-8#a+m45_p)Z%QohC9XV73KXhV+Sg1DzDD +zbQ*2tqm#(GQbSwUc!^F;r|Et8x(@J?N(}TSu@*&njU~t(V_OBQb*KteVD6=J4pyk^ +zB#??QI#>q18`lQ)7MgcvfFXx|Y)K7gQ|MqVcFNU;-4=Pl#PULU;3eil?gzR9+;rH* +zbuk%zaQfhazg^E9|c;D474vH_#<7_(T +zv&jukN#(Gf1l3`8pt}3McXpsUzvut&<5cM(O_lIEV`|{J+*@1t~6Ai2sV +z9;P>NbT$-D8ne|mr6lt+CLDapSxPdfoh!Gyas;761xy`@bhr3A{B+Xo&PdWF5;6k< +zhw?2Ml8>yl`bbQrH`N8DvNpy>gHYfD!-_+vAw`g1#s6F)tt$DU=YDj&FtV~C&0Tqr +zEg;O)=4H5>-G+i~d^wH-FI&ylTrU5%Kp`t3nN{TDT0<;`;&`>WTJN2~rvpziyGUXR +zRBkj+tSw_t^c1o^OsQB{oLCzU@%EF(Am1g3rY->nslHzawvqzc@EO!=9UW3(1XhbP +z?n>-$;DtyDAP@^H$(*A?yy}ur*1Nqk$q;posr9@Zi8T^sgg@Oe5XspxWsa6gRCf>to#jaue~f#SRgk`#s9OVv3J3A +z8sRHr?%`%fd}2e4Sh?Fh_PWPC?s2bs+?Sj4;Bs!N>983xyj)+c*(+-jUTq~JgBeq) +zI7sAYKK!O`*~Mpy`a=vonQ}CPvw$GxRkjwVG08J4(Dzre#>RIxCh+|#EXt)OB0I9C +zRFqM?%wz-EDHb9TX>KV+iTG}|k&;lVV?YUfNnZ79uS6$i@wW&xO{w6kR%2Ml_3=74 +zM?o@RS`{3-)Y^0IgHEB3v&$pB4UF4on5BoOTXFShsS=Jl9Z8}IK9q#EaB_5mX3&#w +z#Q5c(A16phRIYEIHo;H&YI5PZBxg5nwBZY+*m99PLxxNzT5Z*_y1;u81F@f^3aDjL +zQB!zfzen8W5Kd;SW#EYwMlv`g`M~B)KW@lpU`Uknl79DetdoeHG)ORvm+)C+1WK%C +zlW2+Dp@U$l&2kgDbsWPS!w+Sp1GG%?xcz{McZOXhUZ4#NG5}SjHCyYf$)`bZ*L_3+ +zI$fEcIE=4c&*LNhVok9LwghBl2VY;pSNyO=Vv~bRR#{)gZ9BKgrnPn3t0+`yLe2DA +zNiFxvF~qsn4E|b#UsNX@2Zw-yGLW3>>*vZb#r95OLRED!3I=^_WJpqLz3paXHwL_& +zBmiSlM^cW?z+B^7?rLEbrhbG;-Z>anac(r7GGE1e6kw6~aYAQ(S;Y$&TxECk~1qR +zxGf$xe>(q1@)oR9unva)40&}`d +z#Ovw0%?2&~IM&U$69{M%I@?*GM>YZ>N@V#W>H&qts77QstB?pnlz*i(QKs^NA%m5Z*j-kM&a>R0 +zU=O4{5r(sMwp(OdugZC=ZIMhAwt)sKVe11`d|t0y +zF<5o2iclr9pg5B#9In4Pz(fJuCdG?~a(h3jaMhxGG{oAF@6@m<+Cy@RyjN_F?{OcI +zw<~lT38vvTmJL448~qj>4tqn$rQ2=sy=1VtuEPLMn@%j?-GMDPH@1EaeDaZC3Noqc +z3}d#1F}5d&&K6J9PN{*a7SHyXSSQpDz33xUTIE2WWU?1_W;W|Sj)Az2B%-4RoZP)9 +z^yWwWO8b!@ve`J4^9hlZmW{my1cT73a=1!=fo?Zwe^fJlGGRK=O$^l +z9VZ7Qstx|Cl6yMqB^I%4@IaYgA$Gn;YFq9=Ka37BlXcMIfikugPn2EfWkmE);SkzngvKGQqHNIahhhCix3=tiIE#Z;r+`2tVLi +z)~g2g5>(Qp1bXJ(4t~|1=naC8TSr~bHd2`^b{YMqXo2A2fW^WFOO1q(;G-T@Cir-& +zZlbY++~4B+f5-8$>v9yn7t9L3nplG%TX{Weu=>-!`T{|+*%Xxth8&AMB~j?2=U664 +zHk+af!H{F#eWZcsjL$E6ekFob{(22$^(TGx1%hOQ1`-T8j%pw|p7$Kf1jz;sBp7lm +zZlE+W!k>L~&%K^&iQqm%xn{D|NC*j@^r$Mq$5M5jh~&SUB64dR-Fu=frJr)1nj6f8 +z)Q7KpQ2FJkDP`Mx9W-W73|E3XZ*)Ixik1nE8OpVlrPmWevdumz=CBvDK=2k{yGf9Y +zMa;qmONp3fmOaZ96MHdbg5c-?_WP!2g<#m4#R4%aS@w}mG9HW4OV&Ft`(7#$eA7@{ +zq8r}!%=dYlmZ}D>*i+^z!fj7hCwSIS%8rE#LEXy+^C|oYKOa{1`WFCaP3eD-w1?oU +z9#yB|sP3kyPK};5NkCQ` +zAtZP$Maa^d2_eB71AP}ZSlVgWO;M9z*sxKPV!Cx~+IBCsOpr~)6iM(&PgN(#_PM~x +z(klreLAK8k`jT%%eXD_NpCe@H_JojN*xFGOHrw}>A21byY}BS`kzmNNlJn1Znd$af +z;~w^nEV12}64dhsUQJMJ%XZ(Eoab)ZOzwPciMH*}sgmwQS7L>p7uXe%|`(WqWRm9!GHc*uA?ph@laYs?d0BC{PsgRw9gGWS0AI^!Vo=7q&Zh +zjooqErs%^Ty5Y)4Z!Hdhl#tk=MLST^rl^%|PEx*R%}A6k7jw)4{)M19knr%dpA7-B2zxvGiC%nAOFVDdc4@WP#ugU$;(>>_kXWh)(nTW6!fpklG??B1lz* +zXL*AqN&;cA;!#A^$r}-aV9%?*OpuI4Or=1~$k5HU-{yIi2(EZkogl@)CkZA^$&GC` +z?X@un-Qp+862YfDszLB+L%FVIiF5U)Xk;{|nC+hD0zv#4N&N>S5}fy_GC|6?UjI|b +z{-ioVvca52Fyxp|B6ZASnMz{}ji;;)2|woLlxT`)6BNO#zUE|MrX!7i@h)eBC#^To +zhXkK9lruR?f0z&wyp|$#{EGfdS+AH(n1mo@ZittI_bpzbE4g3NOp{DuCBy!P=#i)&eSBNvV;dAh%<6EIscDO9bf#j$>N4utYtd^Lj22 +zobX(a5u`xp=qz3JgbM^i@x_krl%V(*z4$W0YaVr!AO(u}@&-$kiS2KKq4?25g~E4w +z{VN2?TO?HqBvpze6%7^IIxnkASv2mZ=pllk_-cXpYLWQr$jFJsjT!TbH|iom%0!4G +z7>Zvk5WiR?e(@cMXOlNYM+j0TdXHcz{z!rNBSqqm^y_7P+u=41*Lk83hQ#8R)&5Bo( +zRsbQvP}1nQlb2L2l2k2_R4tNpy%0lLZEu!Eg4?{A8wB?S9lE%|5@jMuCKxvKyZhK) +zFZ>9>F)w_HAjOF@9Pz>_39GiOV_`V^vzfyt;#GUf@F)C+7hfXC2213i+~Z!Q5IhfzeAe?U6MVy?mI=OTDABUK!4f4E9UfUrDCVN)St0nkM>PqO +zv52V@h#9#-aK(5%?|GI8zUEO4g4?_kl?WzH$t|hHiMCpe8}0dStPQrk{m~7UKj1l* +zt>L-HEP*U;Kb-T5VOfVo=IZm3Lv!Nkg{o4+>+3Q#$_>@O25q!o_&S)%sBOxpjLlK|# +zWD5jYQ}~UtW4?Ns)%Sajb%G(sVta{-UUR0v-5sAYm|r)XK(V2P4Oj97}Gu81lG +zSyT8GPTk1w9yT=^UY!!bp-0uJ%O#I0WqSa(YV5}c>=|s{=82J;8X2{P+Y=;*;_h-Y +z1hwoLn|I4rF@`tG1H;3|39>;X&1*%bq#R-MF>~gBU{4GMg0C1#R4+bwW99R{@&duI +zaiy9m+PCYgZ~gd_n=qa} +z<(0VE^Issi(@M5{|M&834tJ|psYI}9DA$oJJ)95{q>)GWIHkO9 +z(hzM3hLwv)ohV2K+r0ELK`Q1tjV0ub6!wC6A&?k6{ +z{q#N9(R@#I_LCb#(5RrzF*U?CGtL9vNF{>LdQ_9(Hw@*B&Jyi3Vn|TLyyv$-kTr#0 +zQ9nFpRi5xwbJp1!9kw4!_QVB|2XfmpvScA4rNbczvTm^=#g$9>%3uA?qdCcm<zhFwB@dPhjWuIc;a}(2q*~) +z^E7i;dcepIdw!*t45Y3FgIF^d+fn$oDYwn4$#S3Y&7NzO0)`${BDij-Em3dN#^Y8v +zXHQ|rwos#@9R+F5YgXrNdqQ)99JXSd;U$?J)b* +zeJ7U)K4GZQN=Ff^kNN5g1jz=Mpa_N>i(1k!E?@E7av_Rs=zYI~e&3!jHo>18btq)f~T1SwFsE^M%Lvlm|_7>X~lMz*OJz4$Ug%7l#xQlN-0 +z7l>ah5??f%zGUL~EEtH?P@czjxzg9|337rj8Oqt2rQ3aTN(A>A$`P`(k`NMXrwBte +zieRetq*rZ$AeC{Q#Zu%YE)d)vNL<)pX;(r>kXk#AEKzaH6a>RIT(A2R(>~?(FB7E3 +zBCWi^(rsR?GC?Zh2w9>oNU{iqY8AP~v!(=}1#Ynkm(g&o!Iao(&&|=kjjF-N?70;= +z*4B-Nm8gPXHx!8dw}+@lujiziLnP2EkiA$11^)V{r$OUu2ax +zN9XqwX6<)Jf4SxV+J8sBIh$^?T6`8*a`UF`8KO@)cHh2Zn^@x2xBqPa#|@66hxUK$ +zulD{`lowSnC|>)dL+<>PdqOzD^Bz?p_$wY&BKU%#oV{6kDIp~Isz+4_{)tDG2)>bG +z$I^MbJKXbEpK9BEm8AfP3@ +zKSRrMHJ~MYEJMrkV*xGUvl&{JX;IOaFs(~{i!JG}wCB+G<^n;QPdaH~gQZszLW16Q +zO32dVrZL7RK`Q1r=F~z;__T576CVA#p~$yjge9EXMob4U>PEq3yGwA{ZV_D8{DMoQ +zImkuIO;Ofe7zEjq*Beu;e$H24AV@aILI{Q& +zi({u4fIOe_Jj(=M@u&vDYladn%Ns0F(ui}YL`ctbtPrHOxKKfm>_kY>mfa=e^2eTA +zVT$_lPS?SoNXQ7X(bqF}6p_JJ&tQSzj7K#HRt+UQ7dBX;q(al|v?@nEx59=TwuWrj +z6JA5ms|cZ^W?WWZ_th5&k`26uV90T_*O2EEo@bfh3m(-V_>!TV*RVuMg{Fz{k3x=n +zjunE`7G6V;>_&ObMdR`>Jhwt)U-$$h_!>;4dXK5^(!>?n;&-; +z{k#`iBKV}Cu4n8hB7ZG>vo}g&g-BD+H;n +z3{m@)>_&ObMWg#m&#lnd&S&Jm`#8_w|IV~XAS&Dg34NKlOoQWT9@r9TYe?0RJEtzXot%IF3T|~ +zU->=<-;%f(!B2Qph2VZeIgep!!V{JVPNoPGaaoAsUobV`1_ZzDQAY?;pzCm!C=&yV +zU?_fcher{`zvyL^39`x1h#&>JE@z1{K}awZU$9>xM%cVrO+f`-^$Ju7QY!XA2<|ki +zZi#++eS-z+AzD>7SfVPZO)%6dpGIztHbEuo^Oor&4n;wH3XWpPQ*hb7#g{`&Us59+ +z<%tlrOxRC)Ba{d}XDH`zMU|845Bus11jz=jK``Vv$~CA^&vPsjBpXaW1VfI+y-j|s +zfh%_e!^-(ikp|~0SBolF3+(UgMFz)xYZeJ!@~8&E%Z3t*FK)0zH47)cvsUGso?Brz +zU$KDnwmsnu1Rn^57N_m3{EDxN5TqDKn3oY^DDN>ZuT1c& +zN39TKLxeL9IE-MsS7C)9wR40ljd{W{!BE#?7j)WE&$C{s3PIWjQvg8<6!8^rD$0Zt +z6AZ-{JF$qT@V#DmmEap5)gVZ-i14a65+xP;p*E6Y*a}JgjeXdl#exPc7Bwh;>D*;l +zBJ8j+zG6?A*a*Mi+f?#x@jX}CY9Lj@Z3%)@qG*;B(N7s;w(17C*XrJpChDS*$h#et +z5$|@mR#3HVrq2!T?Q(hHnyB}Bt;+;&%u}oFga2%b$eP3jFI<5FGPjmI#uuh*>BQGcx)(g%feRKEfuH3GO#> +zTcWSN_$Uh$xF!0#FFwk`lYh%qR!SDWW=ITHg5M75Sa>U;BSsjCq3W +z42(pARN2J~mZ&ob2~uaUBS?)wMes&HfGPy3{B?#uo03<(O4Vs^nBavX1JbU9Sb)(I$H6P+L=qJUf7?4&iQqPKtj*Eqy~|$nxUmhw +zuX}$lZ8ax(+@2zV@DtvFN(A2s$k^0v)>TrKFx$L2n%E$Gb3n&t^SOlpo@{g@Xmrou +z3jr=NU2gPhwr?@;_CQVc-0K03s$Wkfx9W2LeKI2+H-n!x6m1Sv!_1l}w0v7eAyDlz +z)D!juimFj9paOd+xFveGN12D{H&bY=*Db24bJ5pnK}9}c3bQTmicUqJ|KtXXv@8Pk +zMWbXBh4P0!xxpfz64I>=^rCl1=b~+Id~}25#1bnzjg%I7SJaE{`{V|Tw|i@>5Zr4h +zp}gml8!Xa(1vARKw!%iR4vn(Q8X}(gq;aFI1xI_+YX$dCymjjcIq#1C;@*D)6|%C3 +z&&ne{E0cKN;|7e9i&-x#5~!>+pt6Drr%To&v3?aWtBRDLGLv5ReOF?g?LK_xRs-)! +z`7Nhl?GE$dH@z?8N*fDXtuG5U24svrXJhZ5_|R4+_`IQRh`!8JDcc%1%3m|WH}VyT +z`cA^0;9Gg>EPENS4KvcRH&&V8ilMHfAUVGFy$<@UPhv_0hlX;A5lcUx5E6VUMM%#1 +zCuQyMEEWjv^r$L93Umn*OO%NVW&}g=qt@U~87gqQmsTdY-=i7?R}3Wzls8zSB1jqt +zKIZF|35GfqFQFc=N@M~ze9}-~^ZatY9vXG~&92n5CpZw?XT1s~39cB*^(IR%B!mQC +z^r#ZSYpJ@S4k1i^9`pJv5F~Hcmn^;HB`pvPC5`S&N_xOcDidrNPs~uSKgt4Ii&Xga +zM_HgKr3~8Fh&%?+r6|VK`JLbSoNwtmJkx8#*UCBYKVm?K`INm1lc97 +zZlTsePu%9sxk&I~uTPy|sQ98+oRSLWE5ugc?d;)g##g$8@D4AlL@?>i&w5GigpA-Y +z;6?+{1R^2ZaOSeqhTSBzgeiJc)MkrmXrKsQPf8;7aWm{w-oQ%)FB(eTd3z$dW#efp +z-|kzvMDcV8TY)rgj_YY!JF4a{k~VKOz@>VbdZu+g13Cg{eCdB16t5UO_-U*fo(m-xv +zVCnUQkRTn&5wb+3u?!|ir7`;uq*YzrP}vZs;$yy}7YWXIed+|Ms_~W*lr`q)$xGrd +z8?qiWgfO+nw_&Mt+l&4JHKaUH5oG5TiPm+Y_T6J9@`63_snVwnOeD7``J9*Bx?tc_ +z9(9Z$H7NM(soPH>yN1=hA^NYlTqLUN*_H{itpRoDegX@7GG~9@82zj<|1zdBV#yRi +zJIh4MmrVR~UX2pLR}6&^lON2Yz_XdU8jG^EC6s3VZS_*GCQ>srT3orwVZUilw1MCb +z>pK}$#YeVMl?*O;1`7mV_oyX;ZyHK?VotCUB^6{WPP;_Rvz}*}AbBI}B}m312A@&M +ziD{B;_IbrfpZ8))1Yh&02ElFK(MtrArZlp=r9Zb?jT`Ohzi(pY4|tB{Y;`HWyxn0x +z=5;9%WIv4Rty`?hZAsN43HwdLm+c9EAo!A@MoBnlzdxB&Es}8c0}lI%=QGS1CAaEh8&Bw7j~EupZCg?iW*GZzV|!mb$i0J1b3P~ +zuHh_Acr8l=FQf=rx{?qQWJ^bzQk0=eD_*4qf;&9VCPC^YJQp@tqNEY;jvqEYCC{%! +zkm?sq(6pI6U7W|hr78JLqAbC080tMZR-OO;e)Or``1Z8nt|a7F4SXp<5q#NDABqMa +z=)1#N`&#!spWe7;KeD?JaAz{jx*_`NcihJpHrTx5Ns9?~4HZz+2v4qbZ-F_rgY;+%@H&RQUqq|UO`>fB$?Ph+uucc}JUWLFBv +zidyBnhU$*)nrGy21^?db`=LZ|-B6<|-)Iy&lFG*nTuD$)K=R+s(d#CZ^^5y8Pq#VR +zo3nr$UF7(Nan^2Rfek`;6QtzA?k*CX9~DJZ`R>kB6?S(aS-!hBM>O?qX5Y=x{sNO^ +zsUY+1cR+@}+8Fb`i}0#7j47!Ly3h6?ljb>%3JOC8-3M+Z24v5Ph$935;`0t6eN4i$Yp*boK(&6 +z-xBf1?WRQ004ky?>KO83gTB{a58JzI%Z~rWEebxB>-Thf-mpaJM#~e>V1mazszLCY +zp`49bdLtnu_%Q9L%RrWfhLr<417AoHrgf9jCFA{^myzob3~c-HuImxuoqGG3Jki#3 +zCjJSpSpj>f;f@{L#?Ka`HD&kO6Wj0T!Zm_U! +zNUW#`CZ=1Uo%qzMEWDUhy=EXZ(0^DNJZvB>Bbq#IxJ&jF9BZbZd4@|{tTv +z`Ed3#>4=Tr84+Md~EVU{2NR5G6rSiG6E=Zro1rY{tqZdsgjvY{WCm@4J?_AjM)34~e%# +zo1<#MB(Npg60H~FxB6r}&F5XwL-iR+irtvpMFWNhBY5e=5v!4nv4&D;IKf3v#<%z-1TcQs{w-w^INBh52 +zM1NEC>dzM8KNy|=wY=fBL?4PS6yk4=E*9dyH+u2eB0h+;Ts5Wi|47vPNBP-cOJtEO +zpcQZn?~v#47Ey9|d;KVfza@il#Vve6G4tz|$lf^4;XjeVxPybO(VxGa{b5QGd4E2v +z_K%a+AA)U-V)||9@}#XYqex_~=#u!9QoW4@cWF{`S|P5j*fxW2|yBhQp>P@k5Rd$0zUq +zw<>)e|HHrw|8s@<}M&WuxsPxPezYv5Dl503r=(OAa*4*%h3d&WNW +zpC>Z%L +z(eu3F$>&zXznbB*-|*WGIsV)km^b{5t|R=uVaMK7czYQPs86b +z?c|crW-Ky9|7r$*o8h0x;13!8`3!!=@NZ@CKV$g4Kb*Gnvxa}%@GI`;=${$>b;DCn +zSqzDuyCeYOAMtV~BKU_5Pd;}U{`m}j#qe(#e(2amj~KpZyHMo+Rl_${9U=YgqT#O? +zo^ros_}e;;o_zkb;g4tVTd;@{{Y$6P^ix{ADLVEQ43Oa8_kw=(c>i$pOlDl)1$zAb +zXOE{opELZcMo;{_;y)5SV)HVkA2obGgLiI*xc3u*k^r6lABe7SE75*-_zy=HGkUVU +z7r#o0u7blS`cTSo=yN?g?D$O#*x=u3)BmjLf7X5@f8tr?CyYM&mdj7ze)>-~-DJMl +zn!$g?@Y@XkfYJXw!ynGzf64IY48Oxe^x1Xj|84Y7JmCm$F-GSwu7&@)%_AVwe;>L*?2PrxM;zgc +zhQHPDlRxbc&lvu*hQIW;9Q}5~FBpFNXB~d0;g19VDTBkuqelOl?ZQ89KRyAx=*ffJ +zH_Q=#+34T+l;gi{^nc&*$9~A+t=ppCQa+(X2mh|oZ~u&=|AvwLOU38u-}PQ+=bit1 +z+8h7G_&oO?T^-uzz3&nF59j*jgTRZOFMZn4UougjP<&qQUZa1;I`DC)ZggM-ec9-@ +zPddWajOD|IziI~NcyE)x<&DqnbQQj6_!aAy$BfUH4FCG84)MT^?)h_yH=^M2E5J)X +zZZm)0X}|ps#^<&_bqJ2H-!=U4A4ub0HvEg*T)UW`{E6a?Y4G@}#FNeWeSoba`f)q( +z>7I4WZXJQYSMgYn?|1q%tX~cqe&w7ggLRAi`%&O;f;K#~Gu) +zYH?uQ`s-&$&_4tGO+kHv-!wkwY#lUX6YxJb{Mj!%N{+{WYxqkab?uroMt`Mva!sD^ +zd7ty2%a(T;`{-ui#cr?M(J5X4FBv64sY%ll?>1I +z&S7g;-SCHPK7HKy^hm$Q5k719p9Eg)cIk?XLX2-eWB7d;KR*w=%rDve;lDBdJ( +zFMr+e+w2YEV!a;3Y-KEG@Hk6XL;8nb_8_*;I^A)c|r<3Bb0i(9RsHjv&1{-(|O +z{b6~dL+pQ{IpcrU +z;>>wt`D2EE{ns7h9LnG_$!V)IC*`0O(Ne_QcE +zgADu}@Y1dw)~;=a|6$|P{warGUh$)bf6NrLG&kxQ{_K5D;LVhaI40|?Z2td~Mqf4m +z=eYiP#pm_>1&g=Yb5eQfQ|)l46Zn|P{U1m0`KLzzd?rr5YN4zxA;ara`{H|-)sH2)2jVb#akhG{0pOh>Prs! +zlKu9_hClun4)L%Bn!g^wXD1YZNpt`19)XuHZHS&@A9o#l&HDG)2>OQ6uYARc;5a%x +zg8oUPf7as9e$(vN4gb3B18|%^XZS1kIz_G+{r@(C{~wLO|HTOW4fq~}wD;Ttjz9bN +zV}`%D!{IrP|DfVciQqAA^bh=wLr$VB{~j7a-!}TIA9MWK-bW38o9zR??tYG*0A9w? +zbD8}77mWVKt&Z?{CpP*u#akhG{I=2W|1*c=y!m@0=>K>G{w?Ek`FklbDP~5<((LeJwhq!`up!_=tyyPv}eX7$&-@DuC +z$$9YH2>$ZYxIr3a=+bZ^j|Ri71L+CRsHc1 +ze9jyF@LP`Xs;zf^bp-u4N8ta!_&jTVa@^L@e>#Hx{c4BzMeSd7avw0m?K1qE2V8?V +zpYAdIj_-B&SFF9C9bwOTqu+1-JTyD}*a-Tb(Vw@Dx0@4E9&`(OUYO1(ea +zeP=h?)rfYj|BX0-Q45UfwRSr`-K?FAmpXq_ejVZ09}b3VOG|gwqeipeTy719&3-&w +zjqB}hr#Xn?xY3Q5+uakjcH9_t`-8Z)wjR~HtG#w}*lgT+|L%SF7Zb%xtxhYh_4~Cm +zakDe*pNW?Gwbf?aSX*5^gDOEO2IVkCy3!pC<6gH3HCm_)?W8a`1MODhwLxvU86pO? +zQ%zu-{S#+~0%U(~f>*zFs)iriwG+*DF-h|jBtey7KVGd3P8Jij8mC75x(q3!e;tSp +z-P5pbtJ7%JYr|Hz6Std?v47A=&nw{iylcwI73 +zDCttayBgQ(!xr43n5*jsD3fcvGDw7GZIk}F--NS4i0jeB;nGw&1Eznjch@=?Y@vlS +z1nLDD?!E=r)j_D*?M5%|HR68rks{-|p9dI_wP9^EL1BGiUl;D;(QCc9)*hZHV)5N* +zJfA`->fs_KujK0TYUof}be54JcB0lf8Jbmpc76L@euihPHfw{mesdMUAmp*uTkh8y +z98O7m>aMP?bvU3Ar^?Mos{LAL(5^|eM6uUC6C#@RmG0cyYILgBpYAl8>rsl83_J{4 +z@aZ>ejio`fT3cUgM8n~k7>{ndfp`#gny2N_+EYJpVr?nIpgVBEa&~P9=9snyYbSuw +z2n$bGYxSEAg!)r)9bxspJ@<@7Ac#*j`zYLZe^g&uj!*R(DD1m80{1)byKnE_sM%h+ +zLpa>otsrtAERWAl#Zz;Wag0(bb~mDU@}ar$+3AV&FBl5_Ay9|r7UQYI#^LZ}If@U> +z%pVw^iRTXiB_~sW@6~uGV{J_U}J5Gkstp-gD>f`%o8csmJxfnocayu)fq@ +z8?2;gq$Lr2gk)GM!-bPz{_VSmqBeWliq2ADiBuML{1S~|_FHo$){RAa!f2!7q3 +zOfeJa-^u2w`ChZLu-05_3b$c*t)1ckT)Wvxq2hReDW@}Bit8&UQ@=FVTf-DWv|j3+ +zhHBl;QfoOX%}Y4l%w0#lFn7rNJUnOJGoPnO}4 +zP7Tpmh7-JIfO(8mM{4bs=&aNg_&DhhEL+GQI%}&Z&@+OqHDF>@1On^pHR)5-{$jdk +zgmSgf>S~Y1aA!fN@7C%o=n9miugq>zMDGt<40I-UHw=YFR*lB{(a4&5|p +z!pk(L(K%qX*6JvoG=J|s5v+Z%-8~Jj2UHsl(+xv9CQgdLL5_?#-hXBX%aOXiS3GfU +z6+gX4hO8TSIiGb-(d;zf603vd`Y`SPOUgNEBZjM3;DqZQwSk%TXstC&`w==x2Oiqh +zYc+B_q<>HMTf=6wl(VvPU*FVO^oV4Bt4NW%^%N&->-?b7ZZ>;4BeA0^r~6_j8)e!k +z#(?>O2GqsQOt*fLNZ5R$-K_O3GN8#aj4=--(WfGLf{rv9)0O7%NUcBK_cCM@A$q`J +z;n#zDztzL65!VLwR!dDN?mCp|L_(T{KsPqULsD&o!*|!xkwqfgQmemuy4J_UWfPdX +z7RR+{FOEkUv8*pn)X+qD0veK%fS!M()eyf;eCMe2O%hTT$IDf$DVm4^)*a3^qDdVw +zR%4>JtX*$d$7YzZGbXyojxYx+OX@3ehy*!5>U5Q}xQzN-2g?n`=uosMVVx_6cbK)l +zCgZT~sihGiTeNSuY&x`__dE^Kvz=ve9&!BTUaN~(8jgbi(-)`3E+ +z2*aL%SqF2lPG=0?&{GpOH>0v9MiE+{u+|~%dD}o7)N377N6q?48RGF$t(6|gz2S;z +z9j{9Apfh{Q0TTY&?a~@iKw{LMJ(O-EWwJT!chBhWCf*HWso+M|i7z($-4uWM&4`1T +z?xtgxKP<0e*~G~yY|8Rlt)Gq_DlWy|)HemEk_;{yLLFA;@(ygO-dLAulv^q$fk&-2nweQ@pF-GD# +zGD^ihjpm89Wvm=eHQQ-9l{14>k{}*#POAa7w>BK4lm&Cl{wl3vlNrWaAH!mG70t!d +zyitRLEUPfp56~2GbHoA&Nby4)tFQJ_D4%q&_1?Qrn0s3b{ZK+HD#AZV_awp8de8$i +zoDE!M0F3rI2(DzKr2CWOunqKtvY#iSiAy!Nf1b3!Gal^_yua(t4jLN#FGA +zr&8@SF6R0=hv^E|@=B>MLCeLg82dFc)0+h_4VX_I0z5QB`8EM+RE +zbDnMuSK?EcS1|pjEi&D~9+6|a(p<;BQ7@MDPD;9su4D!Z29gFTvlv!8X?HL#N+V+{ +z#Z_`GSur3$q#`2bXo+em(~8??)+%N=>88Xx#1q1iWJK!SCfw3&$pC4oU=$|_0+scn +zMlBV1lmssZ3|(5F56Mxr3Il^g{8WofGi)xkR%Jh|*@-zf^pT~Cm?-O5es&cL1fd7TsdZ#7x;ijv;IoPyP9G^! +z&L;M7ULMC-vf08~M7unK#vb-NSw|Bh_@Ax>F`;1fSGe}m`8Ji0IlK5SVR&W=EqoL +zCmqU+MWTE2lz0=SHyN=hY3acWh0-hWbZFK7OxIY$@-I^-)pHnPuH(dBEtxrW0WT$q +zaFOMcDV^j;aVev1b+d~p^$-~GZR +zzmi!Y#&7**yCxM3>a~Z_of_Ki)T!@IISjyWU0p!m*<7*h|CI*nvgB&GbAU)|5C-Gg +zYO4+vy5Q@0V4EVkQ*sp~Ex>77gbkn0GEOb5*y=2G3D-`X=p)SAFEURPhJ^^Cy9pX6 +zJ52f;JU)iHa^z*lYW}+d{Jwzv9{#iAF^{?x5U!;7`uzR?pSwJz19*-}^t}MW`ut7- +zpF2rt&uslk;Q!;>Z+EHx1q1lJ#p>BL5PXp!{cjFMIT~jD%LedyL6pNkIlh#u8?2Ax +zIQ@47{}nvz^ZN*VelVkO)_y;Rx^D;i^E(QB{&y-Ril{&3@Ocuy|8-EG-&^4GtkoC& +zMHT9A=t!>L3ZDG%WY;9Gd|B_cShA{V_8v{flzhFMotO +zqN$8w`N!{Wyl5|AjqwNfv-e-}`FFsF_5D5QORoLB_fwK%zcjts_4)iStiC5O;D;`{`k#I*{R`_6E7zQ|IQgx9i;H|a>9|%QODko@4kOXW +zxlg(Jw|&}SKZ(av_&@!J@mH=l)At;u`|l " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+psu.i2c_addr ++ if os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ cmd="echo 0x" + str(int(psu.i2c_addr) - 8) + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+ str(int(psu.i2c_addr) - 8) ++ if os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ ++ def probe_device(self, index): ++ psu = self.cha.get_psu(index) ++ path="/sys/bus/i2c/devices/i2c-3/new_device" ++ cmd="echo pmbus 0x" + psu.i2c_addr + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+psu.i2c_addr ++ if not os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ cmd="echo wistron_eeprom 0x" + str(int(psu.i2c_addr) - 8) + " > " + path ++ driver_path="/sys/bus/i2c/devices/3-00"+str(int(psu.i2c_addr) - 8) ++ if not os.path.exists(driver_path): ++ subprocess.getstatusoutput(cmd) ++ ++ def update_psu(self): ++ #fan status detect ++ for i in range(0, 2): ++ psu = self.cha.get_psu(i) ++ pres = psu.get_presence() ++ ++ if pres and not self.pre_sta[i]: ++ self.probe_device(i) ++ elif not pres and self.pre_sta[i]: ++ self.remove_device(i) ++ ++ self.pre_sta[i] = pres ++ ++def main(): ++ monitor = psu_monitor() ++ ++ # Loop forever: ++ while True: ++ time.sleep(1) ++ monitor.update_psu() ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/rst_button.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/rst_button.py +new file mode 100755 +index 000000000..3f47e8776 +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/rst_button.py +@@ -0,0 +1,66 @@ ++import subprocess ++import time ++from sonic_py_common import device_info ++ ++CPLD_SYSFS_DIR = "/sys/bus/i2c/devices/0-0033" ++ ++class rst_button_monitor(object): ++ def __init__(self): ++ self.intr_path = "{}/rst_button_10s".format(CPLD_SYSFS_DIR) ++ ++ def __read_txt_file(self, file_path): ++ try: ++ with open(file_path, 'r') as fd: ++ data = fd.read() ++ return data.strip() ++ except IOError: ++ pass ++ return None ++ ++ def check_intr(self): ++ val=self.__read_txt_file(self.intr_path) ++ if val is not None: ++ return int(val, 10)==1 ++ else: ++ return True ++ ++ def restore_default(self): ++ version_info = device_info.get_sonic_version_info() ++ subprocess.run(["rm", "/etc/sonic/config_db.json"]) ++ time.sleep(0.5) ++ image_ver=version_info['build_version'] ++ path="/host/image-{}/platform/firsttime".format(image_ver) ++ cmd="touch {}".format(path) ++ subprocess.run(cmd.split()) ++ time.sleep(0.5) ++ subprocess.run(["sync"]) ++ time.sleep(0.5) ++ subprocess.run(["sync"]) ++ time.sleep(0.5) ++ cmd = ["passwd", "admin"] ++ try: ++ p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE) ++ p.stdin.write("YourPaSsWoRd\n".encode('utf-8')) ++ p.stdin.flush() ++ p.stdin.write("YourPaSsWoRd\n".encode('utf-8')) ++ p.stdin.flush() ++ except Exception as e: ++ print("restore_default failed: {}".format(e)) ++ ++def main(): ++ monitor = rst_button_monitor() ++ cont=True ++ ++ # Loop forever: ++ while cont: ++ time.sleep(1) ++ cont=monitor.check_intr() ++ ++ monitor.restore_default() ++ time.sleep(2) ++ ++ subprocess.run(["reboot"]) ++ ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/sysled_health.py b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/sysled_health.py +new file mode 100755 +index 000000000..b303dbcff +--- /dev/null ++++ b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/sysled_health.py +@@ -0,0 +1,14 @@ ++import sonic_platform ++import time ++ ++def main(): ++ ++ pl=sonic_platform.platform.Platform() ++ cha=pl.get_chassis() ++ # Loop forever: ++ while True: ++ time.sleep(5) ++ cha.set_status_led("green") ++ ++if __name__ == '__main__': ++ main() +diff --git a/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/updateCPLD b/platform/marvell-prestera/sonic-platform-wistron/es2227_54ts_p/utils/updateCPLD +new file mode 100755 +index 0000000000000000000000000000000000000000..5d9f81e6a5bb85f10d06a363a220717c4f1f3c64 +GIT binary patch +literal 23328 +zcmeHv3wRvWmFBH3y&tw7wq?fzm5_~vL$~AywqzT-CE?e^!9q5K4cTqAx=T_It!~i| +zBgLMLFqsJfl5ww{fy{z&F#9DYGhfI|c4E(vARgJU!_E#Ngk^VuZHbx0vq?4vzJL{M +zdjE6lp6=@E?%>QOn{U34D^;C)&OPVcd(ORe>(=R8_37<dkF|bo^z0RDGmH%B1rkkc8LOdWrpD+7FjT4xf>uy?Yz{~pcn^LeWm=e +zRJEU>GFNnlL&KfnpgSCjBq!Z|e=IPzVZA3F^{lb%CjG>_^ZFZQP1N6&GH0C{0hZxt +zQM5&XbvPC(oaC!jo|>>22l=)MM-7f8IO=f}OH?n_N8_ZJPuOSNo?4rd1;{VO(X43H +zPD<1UqLXf^({hCL4$*twyyr52lIbRtP}`lU4TNHJYEv=#-V$_bZ!!LVQ-V(ZF2+xN +zQjGrD67*dq=ybUh(=$+lehPF0hcjIRLNPrZCFs*7=$lK>zf^)gRe~NXL8q}>tet%& +z=;0D{6ZA%mv}e0|k+a6U%;0(p(Dk)J#3y2*NMb~cL?_IMh$mu^!1#oiFk`W3OiUyb +zaS=29;czq{{KL^$f;bYEPXwVwgrb2&SR~_N +z)0_|^x5q*W$w{^NeAEtKJmHTeeB=I5M2y5tQ|#QcyRYB3*0W|KI7Y{#5yjy{(_JP0 +zN|i`!ah=hh5Ij%am--W2b}n(;Di-NZ%Rd?}X8SzAexu2kuFGsv{&ay(dO20u=<;G# +z1r0Vj%_W?c+UPuwP?=$)+wV^uHoAQ->ax*!9wI&6Hag!+i0-w~d0r&?E*qWZMNR`Y +zx_y4T*+!=^%W23)xBGLj8|Jp93|H$*t%m+XK2Ub9(dC_Qa0yu^@e1Hq*zg+QeKvdn@L?O?1pKfK +zUjqDL8~!2SPucLxfzR3SD}cMST>V!9zru#E2Ht1GJ-~-;_*&qHZTJS@58Lofz@M_= +zTY=Bn@IK%!SFZjYz^}03zX!a}hF=eS*oF@RKWxKq0{*ZK{{---Ed0Y_`i0AJ{G%=& +zoz=bbbL}GaBlMpT=@*2Uc~exKcvJkB!*A-qb>KR1{nb0)ECXH!ybO5R&+dHlFEW|? +zzKdfTeJjrGoc9Xx&2MKiE!6+ix1gUBhMu|uunlmV5I;GAt_4lCe +zYtm?&A*Kh1`t+W+YQ6Ip4?ZQw=8w?Eiw7T&EiaEn>d5D^P==gk-9>g +zenErmA3#TXoA->E`0ze)$a{2lp?BU8;vUQ{^XV2bPrQBL1Mdr8AYSN6Z}y(iE)z{@ +z)CpUA2x4wcrBRR6RVEtKsEhKgTf}XjzmVBa{kR5ZVYc@UoLb}y^<}mRJaogX*=a7FMvv}$%(7g52P4FY8g6To_$;E?b +zEPs%msOXt%fj^!QJ(-UH-ijlN_O^J>_{qj7+Wo-7+rpJ%fBI>WIt<&%S8J&(pru?c +z3-=KIx=6XoEPOTL+H@0SdNSX`@f?o7hkv5p9M9dk6kl`poT?mS-%X{jH*XZd0e^*L-3 +z)GuV`6KKz6qM7(_J)fb+kwxTl_JKiml<>hD&}sL<&j`2q;Gcj`SE7x-2_Kxad@y~9 +zK6npx=lMXmQvU%o8V|VN<@?|x@Q0{tB7VQk2Lg3nJor5|PHkgmxi}-oOlNMayhOIM +zpDOal%2!JHVL9skRbzq6?PK9De?31u?)1Y6S1M4-51r(P2I+^P`P^8@_rqW3t{wOx +zvkGGfeZ$v9m~B0Y@%|MYU&HZrjC-~vfN?*HF--m0s>c1Tz`6WRHSRwP+EMVVQatwn +zf7-I$OJm>`)Z3pw?(fLA^)WoYjoN-qo+^&?{byaL +zU)FGq$^NwLH55Lp8>@%JkwM(IYUp|%viV^q&ky<6a|YKkjV~U@e~o(6l||-n9;c<| +zZ!Z6TxMu$zb=&5y$AnRqI-vZ3weF%cuG91rS`R^SsA^yOZ#dtuFa0g#pXlwG{hQvN +zxo`FMyso=e&*|FgSzWA__tojL)YqXa|C)CAg6<18U)&DfHXQ+;@9li&AJG+ib--&xYY(RaFrm<$J0k2#mHPiaV+e7__HQatGW880z#imBI +zd$t8@s=eO7*oJlD=P-7sY0ZLlBdxVwht7xf=@;6t){t!(sz_~uenVJm8LUmPzI$5D +zSEbvu@)Fu~N3puGhRN2Qu1GD19*mbJIrdO@Yn6E8^JE+4U(w$9d=VW_mD_YoSEk56 +z#oC|ItG|Eopvc`*u&$%J(%W2TGMjO1#L=S7r}e5->xK2FEO?EA8x-8AV7G!j3T{$x +zvx4hRWm=(cx$6wAQ)XMIU%<8TD6Qwda{>K_b!2Ouxb0rpHjREyqyCpPj4@i%8uZNI +zo&Pkghgu-t(szdX_-^t8<`v?7j(NQn@0W?N>Uxap8lrJXV+=Z`Nr&svlaS-_H;cMS{u#`zCn3Z53~*}m +z>}IQeaiS`9is}O{WxHS(*=^UKw)FdmuM&My**g#3H|~HBPAGrfjXKcJgK79V-3r~| +z%jC1fO(aA8*rH^rp$~2K1%JPa;#UI +z3<~oC5>2ZT`(JM_PtB?8MKh|UFME|AsC}|c=ywmz8LBRSIog0WQoZ#qE6?qf*EQO@ +zh1#vt_{-VK?cPi62A%B6v{&}bzFvm4e0k~-k|Ep6#0^<}&~*i#rD*($&%{r8%fu<- +zbv0Pe3zw4&1_8du8@smw{aR>B?-~?-Je*Ts_OY1AKY``V=+_4RBQ@o|P(l((OBY +zviFsAb!r*ahw&!Yv?ukc%vba&swe$(F+W6O;%mU6H~p@9mU&mheWo%ceZ8&k%v~gp +zG09`_$;;3uq!0c4ur=4Nrm=hkd_0anNpqY{#=l%X|6%P{n|hV(K>d7A|E|N%CmnWv +z8~6;_2Ro;!y~@r^Cu}WYm*jgNy9OP0-LWKRm+P1E9wP1fgw3ui9d@-XhK$XYf9J5} +z3l3ZECR?g3TQa{PI}C>%Pc|rDpQue8rus3))6KXRFlTR~>kRkE!|M5X#L?bi;DW}~ +zop?U@ERK6bk3l~FV>~M~_acViJvG-XQr@D_is_X_VH0mzK4Fy +z(bQHRU-o`D4;da`&p2%UGR<2X<+a_IhMjz!&w{p1h+F9y+TKqc4!c(nj%$FgEd%&W +z?Qgc9{)+0b+1y)3He1(`Ygul*eFuCJM;TpLJEg7Gd@+mp(3(f;Qnlbi07b?HXdO=R +zfd&N;^OZPa#S$XMEFnFQ5FcXN5+W8Zp-Vx&4-C=$6XWK+U!u)u1Lop2l7{>&(dd43 +zOk4A1;-mW!?sajrhwA5f;sn+o+54DLpLz#!cKj^|{&S`G;z92ztUpo|lj9iKTl=(A +z$1r~$dun6q7q_@heG&Qp`0&QmG1ubf-p1PUoq&Go9jqD7<34-rz5b(zpevz?Z#LuJ +zL-wBhRQ&v$zVy*}1=bgO%cE(137$u`z4VZ)`6q3e%>K9b^`830Eq$ln3G|=h7#PV} +zZLng?_PDYp;ISg9=Ek^x)ZApOj2m10vC-tX8A)udsWFT#!^!wo(1O9(R>OUhvB?0@ +zFoL1@MA$!N1d_2BSdAT>A2$w|v3MvN@f3({83~0=U&KFdZe{tAP;C5mf6O$J6QePI +z(DWGFZ+%YPQ+R`^Q2P28{(X9yda91FkmwMkF~tY{p9R*_9a` +zsC%8eYjWept4N?TXddW9f4Wx&W&7PXNr0ae6UMd1${^KEDP{rr&`H@nT{6L6JdlF^ +zgx?59F_wamGq6#>jC-sEB{kb42{UH&MbGvF*dH>)aMV} +zIvR^6Bf%P@f5WD|J9dzcoC?{3ntk+BB)smAha#g!|BjvHr~ZLG*C|HTPQ^D7i(+_> +zkC)`Fxp4vwH;s5Q5P(ldlHu@_#~28k{K^DN*wzzcwsFb~V5eQHpYOwQOEyIys|L)45a@8jemi>vo{XWFb{ckV-@TDKTNP;w0ZidWHA!F}z68|85;DHZ3 +z@PP+D@W2Ni_`n0dIS3eu8+5<@)S%hXWqm5}#0X(`-V&K; +zX+R0T)yQ;CmDBoz5|{IRe$wS7viQY&*nxo5p?e7k-ZS^ratr6Zas#TIpF2)VZbbhS +zT&mz=1sU+3y|ZecAT9AIb*K!jJ1OzrJKh6!w!)i7Kdo@KL#|`NQ7yT0dko*pSoYkn +z_%jM;|6&;>?Hy9(O8mD5cz^o)RnVpS`(GM#+O@O4f0NOH-R8#rXfzxc!`4(|BpNdk +zV|Z+H5Ady6*quaC2y|!yjkEd&$(czDcyJKe94dRBYuA(xJ>}q

yNKTzW$19v!1zJ;z(BC +z*~`7i3-K9wE<9}k$t7Yi$VMXsP}e)-P7SN2JW=ISOZGhxwu4G&Za9QPo2J^z +zXmb|0zl3w$H*h^r@h5P&?#4-LsYNJRRO{2KV!f;!yPHMXI#9*sI9y^k&Q;nSL_pf7 +zR9H2<2CPin0(zBJ3#;n>TopSVaS<%8s`40$^)KM$dbwpgNM-9Kz4A1X$|}E2psIYF +zKttI}P*@%Y105BjvWlV}RkRhpTAsc@IXa0NtJRfN$ADB;{VC2at?DOGQ+p04tz)4d +zq}n+s)K**hgG9gD%D+u?kIa|90!BKhzB$0U+CL@Eu7%$x4gZ7kYh=FuZz=E7#+2vE +zP)VjpqcI^ +zTBC+sEm0aUx4YI0eZi*M&9yzXyPLNybK$n3uMoAhTWfWU^s+0(ZVJRmMK@LySAz;F +zr79)204kQ)v}VQH#Jp~NE3>y*g>ke +z`E!RgFd*P`_hH1Tm!|sQw#6WdMr{pbmQdriEQ>7Q1{QT81rT+y2In&E-39eRLn21} +zdpw;8q6N)~c&B=U2mxh^=Xv&73zKRW&$s#-t*yPitzBPYeDtF?w7c+jfYvTGf4G=t +z5sHKoo&bsv4#T0#K*c3BAP`H0a`p4Prf=2S+S;y=^@?g2Pt*F}2`xwE$y)!Ppi0*3 +zVWuvgMGFe*?o5nNbOuLYbCJ?e1YQk?Whj3%5MXE91vz~JO!xin#L` +z7QW-@S1VfKsO;oH`CI6-cr4I4N-x!P2I5J2UC!v;XRP(CTZ{FFZ}(pOv=9tM=%h?(uLakqDb^`~nm5M}Yf>L)V5UHmoY6ltxD+5eHR9+YuXwuEZE|0l4u>P$UW@5`{v<E{d7`_%&qrE({#eXEWxYZq +z;-OEOzJxF%2k7mi5tQc@+eWI?l8nSdqY?b%V5yUDE5Wf+Fkc>S!>>gC7^o95v!Gu5 +z=oa{0dwgJb|F7$Jcnbz)%_g%1OgSK=cY@L6aF`hKEhbmwxt<8c`;0E8{Ipr2ni$~h +zM3ywdSzdyaiMOUPUE>XxtZ}eV<5)3`g9REjYI-ZUAIX<7iT5vodpI#$4Zjeu}73}|fdY$M}{>-P>XP>9? +z=?et+TRwfE;K!zXdPDZT@qButFjjc&B$?Oo<|@Z^?1egho#c2*-@Soao5dN%r$U#QDxgnSxdy8Lyl7@gLVg-Mss +zAjRmdg+x$vVHD7@4#acn8yRQ8A4)>u_@{@WV*J&lNED8f(|9r}#&78_94B?qQ;eUU +z)QZu$UY=iMvvK-7_+4lZ(-)}%i@$LETlB*5OwYKb>#Y?$4{^P$hvy@v*Ol-Cx4%Qp +zi_G5wermsyzD&_?cJN#NY!Ne#aeKAmKjPr;16{+L$j>W&m?@K`r||l^LGl;UCzXDV +z<8u2gJ%!irXQZA&I**6D9P_tDZxrht^MggtwV&%f3H_z}t6n_g@B`O-e~EhUchpNS +zNB%1P`~<@7;r4s4^fF1pQsaU7?{e@zA^p}UoODuFtUZ4RetPrYIZwVO^%TyNKUVzC +z`SzERUN~>pV@08f!gm;4pnxA%-pdTy~!ob%#ob&T1z~5l| +zJ^^bRE1~C*q}Pj=o4k^h<{e7+D*B1VUWw1hvk=EYFZTU|{|q|S`?BM@`-Y^qWWSf7 +z)QHncf7L>-Bw5i)A>2fF70y4;meBvA)WceH@W&v&IJdq8eXs=GEJ2?Fy`f0|{*mOb7x$`m?ot*1utYnLg5TiA+2F%U&p$MKB~|WG +zLGCX>Z*&#TpEHX8oD3~uFO-x*6j0I?Vgs*|9(*l^*FQjI`l-^>;L!6<2|ZQi)Gvi; +zxun+%o@e-J<0B>b|2wYVV&ijb3I0#3c5-}+Td)`W#q@k!(VumU|A5qAFNT(Qr3$%M +z2e~mtf45?_?^f}g}`kiCB#}vIzU8l#C)X5Th{t9&JUuQc*CC1N6(&H*z +zCp=X`|BI5IyT3f3+Vj6k@QdF<$VSHGiiFvs!@r*k<#Zw%5NV!IurbBStkO6Zu%9>_OqDV3PKh!bvP91M1Vj=ZEb->8Och*V0jZ#gy}BXn-;DVZ<34;02b)t70trTa +zqv7bVKkN%4ycPHPlanG49iIrB*rn^~UbAsSaVC3Q3cIgkQ}`?nc31m?$?@?ih}bZD +zgv(-0${nY)WtBEkqj9#Fme03iu=iuzecP|U&gUzP(fF?WSJ(G`Y;sqZc2(J+``2L~~!;cAyW +zOv(E~l5+<+%7gK!Z_FPFB2<^#$8LSiDZh^V_;7A7y!;GQ9xLoDVJ1aKWthwJ7X3ZH?p>Q?*e)kmZ9B;{a8(n}2pMMiH;PDp=XZ@c=?R35X>xBp}P +zYS7E?R^^pq^6@3$A#>9DR8?M~@WiLa6aHa9eD_MiG0q_-Y{n*pM^4MVeY@QW|ETaF +zGVU4k$H#;xI2D1g1rsr=ga@x=Q-}{`2yOdGK;>(I|A`ChhI2Lp9@p6N>kqQ;Gc~wha@fe<>L(?$N#z&fy(VkJsxC9?Z{Q) +zVEO$nFEG3;qzHz@awlE~GUXa%ur$cZb3Borrzt&Vf$aXHDuuHi`rYzv?A_t|J9Mw) +z=)ii0(h3U{$Sbm-aC0pVmgo57fRevi70?gyWINZt6nRShIEaMekSghLU%-Uy;QqGUQ8^=lJPq +zCEukOl{p3W-=^gI6d%V~&nkJ|&qeY}a5(*U5H#|MV$a578>&G>;&_#XS#9M!!2>w# +z@*KDAQu0R}4sTGx4DWEr^Ll?qZD{*5M+3P1N{ygR8ut1*4jfjYN3MtYdE7FN_xPne +z`=6herj0Fr~*?|DS`7ofh&M +zAQq0B@b^lc{ERa^0~z{09h=E8yC|Ts!}1*W=I_C#RsZw&Vma=Y +z{|Z@RVR?>^zuXBT67yMDVf{ZqfnA>C=x3Gu^DL+!*U#`3hdjq~PIp-XrRrz3bI6b` +zZa+WQJ$s4rKZY!|U$G-+C6>RD2?{EAN*N-Z!@)GgB7s2@Gg5=2&}k0^+#M`Zu1igP +z#~kC&$y*D8lST@jSufRyvv)~l~12}lx^8JsdS%-;I +fApLt1h&TAgVWC<36^a;9ary64Wk|c<$Nv8dA~k3V + +literal 0 +HcmV?d00001 + +diff --git a/platform/marvell-prestera/sonic_fit.its b/platform/marvell-prestera/sonic_fit.its +index f3ff5ac7c..e0f4da853 100644 +--- a/platform/marvell-prestera/sonic_fit.its ++++ b/platform/marvell-prestera/sonic_fit.its +@@ -117,6 +117,40 @@ + algo = "sha1"; + }; + }; ++ kernel_es1227 { ++ description = "Linux Kernel"; ++ data = /incbin/("/boot/vmlinuz-6.1.0-29-2-arm64"); ++ type = "kernel"; ++ arch = "arm64"; ++ os = "linux"; ++ compression = "none"; ++ load = <0x6000000>; ++ entry = <0x6000000>; ++ hash@1 { ++ algo = "sha1"; ++ }; ++ }; ++ ramdisk_es1227 { ++ description = "ramdisk"; ++ data = /incbin/("/boot/initrd.img-6.1.0-29-2-arm64"); ++ type = "ramdisk"; ++ arch = "arm64"; ++ os = "linux"; ++ compression = "gzip"; ++ hash@1 { ++ algo = "sha1"; ++ }; ++ }; ++ fdt_es1227 { ++ description = "Flattened Device Tree blob for Wistron ES1227"; ++ data = /incbin/("/usr/lib/linux-image-6.1.0-29-2-arm64/marvell/es1227-54ts.dtb"); ++ type = "flat_dt"; ++ arch = "arm64"; ++ compression = "none"; ++ hash@1 { ++ algo = "sha1"; ++ }; ++ }; + }; + configurations { + default = "conf_ac5x"; +@@ -147,5 +181,14 @@ + algo = "sha1"; + }; + }; ++ conf_es1227 { ++ description = "Boot Linux kernel with FDT blob + ramdisk for Wistron ES1227-54TS"; ++ kernel = "kernel_es1227"; ++ fdt = "fdt_es1227"; ++ ramdisk = "ramdisk_es1227"; ++ hash@1 { ++ algo = "sha1"; ++ }; ++ }; + }; + }; +-- +2.25.1 + diff --git a/files/202605/20250-2-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch b/files/202605/20250-2-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch new file mode 100644 index 000000000..03e0f4b86 --- /dev/null +++ b/files/202605/20250-2-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch @@ -0,0 +1,94 @@ +From 6febfaa8a18ed8551080b9c1eed3f2d9a8e8f756 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Fri, 23 May 2025 18:25:45 +0300 +Subject: [PATCH 1/1] Add Wistron platform ES1227-54TS and ES2227-54TS + +Add Wistron platform ES1227-54TS and ES2227-54TS into + platform/marvell-prestera/one-image.mk + platform/marvell-prestera/platform_arm64.conf +merged with predecessor AC5P. + +Signed-off-by: Yan Markman +--- + platform/marvell-prestera/one-image.mk | 3 +++ + platform/marvell-prestera/platform_arm64.conf | 22 ++++++++++++++++--- + 2 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/platform/marvell-prestera/one-image.mk b/platform/marvell-prestera/one-image.mk +index 4d1b87ea2..6a50fee19 100644 +--- a/platform/marvell-prestera/one-image.mk ++++ b/platform/marvell-prestera/one-image.mk +@@ -14,6 +14,9 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(NOKIA_7215_PLATFORM) \ + $(AC5X_RD98DX35xx_PLATFORM) \ + $(AC5X_RD98DX35xxCN9131_PLATFORM) \ + $(AC5P_RD98DX45xxCN9131_PLATFORM) ++$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WISTRON_ES2227_PLATFORM) ++$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WISTRON_ES2227_P_PLATFORM) ++$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(WISTRON_ES1227_PLATFORM) + else ifeq ($(CONFIGURED_ARCH),armhf) + $(SONIC_ONE_IMAGE)_INSTALLS += $(MRVL_PRESTERA_DEB) + $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(NOKIA_7215_PLATFORM) +diff --git a/platform/marvell-prestera/platform_arm64.conf b/platform/marvell-prestera/platform_arm64.conf +index 2df8a4974..9d40c1000 100644 +--- a/platform/marvell-prestera/platform_arm64.conf ++++ b/platform/marvell-prestera/platform_arm64.conf +@@ -28,6 +28,7 @@ echo "Intalling SONiC from $install_env on Platform $PLATFORM" + PLATFORM_AC5X=0 + PLATFORM_CN9131=0 + PLATFORM_7215_A1=0 ++PLATFORM_WISTRON=0 + disk_interface="mmc" + + case $PLATFORM in +@@ -51,6 +52,10 @@ case $PLATFORM in + fi + fdt_fname="/boot/cn9131-db-comexpress.dtb"; + fit_conf_name="#conf_cn9131";; ++ arm64-wistron_es1227_54ts-r0|arm64-wistron_es2227_54ts-r0|arm64-wistron_es2227_54ts_p-r0) PLATFORM_WISTRON=1; ++ mmc_bus="mmc0:0001"; ++ fdt_fname="/usr/lib/linux-image-$kernel_version/marvell/es1227-54ts.dtb"; ++ fit_conf_name="#conf_es1227";; + esac + + if [ $PLATFORM_AC5X -eq 1 ]; then +@@ -69,6 +74,12 @@ elif [ $PLATFORM_CN9131 -eq 1 ]; then + fit_addr=0x8000000 + initrd_addr=0x2000000 + FW_ENV_DEFAULT='/dev/mtd1 0x1F0000 0x10000 0x10000' ++elif [ $PLATFORM_WISTRON -eq 1 ]; then ++ kernel_addr=0x7000000 ++ fdt_addr=0x6f00000 ++ fit_addr=0x20000000 ++ initrd_addr=0xa00000 ++ FW_ENV_DEFAULT='/dev/mtd1 0x0 0x10000 0x10000' + else + fdt_addr=0x1000000 + fit_addr=0x8000000 +@@ -244,7 +255,7 @@ prepare_boot_menu() { + fw_setenv ${FW_ARG} sonic_version_1 $demo_volume_revision_label > /dev/null + BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";echo;' + BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";echo;' +- BOOT3='echo " > Boot3: ONIE - run onie_boot";echo;' ++ BOOT3='echo " > Boot3: ONIE - run onie_bootcmd";echo;' + BORDER='echo "---------------------------------------------------";echo;' + fw_setenv ${FW_ARG} print_menu "$BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER" > /dev/null + +@@ -264,8 +275,13 @@ prepare_boot_menu() { + demo_part=$(sgdisk -p $blk_dev | grep -e "$demo_volume_label" | awk '{print $1}') + DISK_LOAD=''$disk_scan' ext4load '$disk_interface' 0:'$demo_part' $fit_addr $fit_name' + fw_setenv ${FW_ARG} sonic_boot_load "$DISK_LOAD" > /dev/null +- SONIC_BOOT_CMD='run sonic_bootargs; run sonic_boot_load; bootm $fit_addr${fit_conf_name}' +- SONIC_BOOT_CMD_OLD='run sonic_bootargs_old; run sonic_boot_load_old; bootm $fit_addr${fit_conf_name}' ++ if [ $PLATFORM_WISTRON -eq 1 ]; then ++ SONIC_BOOT_CMD='run release_i2c_bus; run sonic_bootargs; run sonic_boot_load; bootm $fit_addr${fit_conf_name}' ++ SONIC_BOOT_CMD_OLD='run release_i2c_bus; run sonic_bootargs_old; run sonic_boot_load_old; bootm $fit_addr${fit_conf_name}' ++ else ++ SONIC_BOOT_CMD='run sonic_bootargs; run sonic_boot_load; bootm $fit_addr${fit_conf_name}' ++ SONIC_BOOT_CMD_OLD='run sonic_bootargs_old; run sonic_boot_load_old; bootm $fit_addr${fit_conf_name}' ++ fi + BOOTARGS='setenv bootargs root=UUID='$uuid' rw rootwait panic=1 console=ttyS0,${baudrate} ${linuxargs}' + fw_setenv ${FW_ARG} sonic_bootargs "$BOOTARGS" > /dev/null + fw_setenv ${FW_ARG} sonic_image_2 "$SONIC_BOOT_CMD_OLD" > /dev/null +-- +2.25.1 + diff --git a/files/202605/4372-fast-reboot-warm-reboot-prohibit-from-root.patch b/files/202605/4372-fast-reboot-warm-reboot-prohibit-from-root.patch new file mode 100644 index 000000000..66dd93ffe --- /dev/null +++ b/files/202605/4372-fast-reboot-warm-reboot-prohibit-from-root.patch @@ -0,0 +1,45 @@ +From 47aadcb96a77d9d2417d1bc6050f75baeebf0ae9 Mon Sep 17 00:00:00 2001 +From: Yan Markman +Date: Thu, 19 Mar 2026 13:03:02 +0200 +Subject: [PATCH 1/1] fast-reboot warm-reboot prohibit from root + +PROBLEM: +fast-reboot and warm-reboot are working properly only +when called "sudo x-reboot" from admin, but NOT from "root" + +PROBLEM appearances: +- x-reboot stuck forever or till watchdog expiry +- after reboot SAI started improperly +- "fast-reboot" passes over full system-reset (including reset-BIOS-GRUB) + +SOLUTION: +Prohibit call from "root" + +Signed-off-by: Yan Markman +--- + scripts/fast-reboot | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/scripts/fast-reboot b/scripts/fast-reboot +index 6d994693..194d6872 100755 +--- a/scripts/fast-reboot ++++ b/scripts/fast-reboot +@@ -897,10 +897,14 @@ parseOptions $@ + # Filter ASIC list based on -m option + filter_asic_list + ++if [[ -z "$SUDO_USER" || "$SUDO_USER" == "root" ]]; then ++ echo "This command must be run as admin#sudo... but not as root" >&2 ++ exit "${EXIT_FAILURE}" ++fi + # Check root privileges + if [[ "$EUID" -ne 0 ]] + then +- echo "This command must be run as root" >&2 ++ echo "This command must be run as sudo" >&2 + exit "${EXIT_FAILURE}" + fi + +-- +2.34.1 + diff --git a/files/202605/prestera_hwsku.tgz b/files/202605/prestera_hwsku.tgz new file mode 100644 index 000000000..be3fea83d Binary files /dev/null and b/files/202605/prestera_hwsku.tgz differ diff --git a/files/202605/series_marvell-prestera b/files/202605/series_marvell-prestera new file mode 100644 index 000000000..2ec56e7b8 --- /dev/null +++ b/files/202605/series_marvell-prestera @@ -0,0 +1,31 @@ +##------------------------------------------------------------------------------------- +## Patches with PR: +## 0013 https://github.com/sonic-net/sonic-utilities/pull/4419 +## 0041 https://github.com/sonic-net/sonic-buildimage/pull/25468 +## 0064 https://github.com/sonic-net/sonic-buildimage/pull/26484 +##------------------------------------------------------------------------------------- + +# Apply optional and oldest first, but newest - last for easy debug + +# OPTIONAL +0041-buildimage-print-each-build-target-on-separated-line.patch |sonic-buildimage + +0013-sonic_installer-add-sync-before-migration.patch |src/sonic-utilities +0064-build_templates-marvell-blacklist-with-kempld.patch |sonic-buildimage +0031-Falcon-usb-disk-hung_task-WA.patch |sonic-buildimage + +0041-grub2-grub_cmd_sleep-increase-tolerance-to-14sec.patch |sonic-buildimage +0043-marvell-prestera-rpc-pin-ptf_nn_agent.py-to-use-nnpy.patch |sonic-buildimage + +0060-sonic-ext.target-wrapper-for-sonic.target.patch |platform/marvell-prestera/mrvl-prestera +0061-sonic.target-no-install-oveload-for-sonic-ext.target.patch |platform/marvell-prestera/mrvl-prestera +0104-platform-X-arm64-mrvl-pcie-ep-check-reboot-on-EP-miss.patch |platform/marvell-prestera/mrvl-prestera + +# Extension WISTRON +#20250-1-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch |sonic-buildimage +#20250-2-Add-Wistron-platform-ES1227-54TS-and-ES2227-54TS.patch |sonic-buildimage +#0057-sonic-platform-wistron-rules-for-trixie.patch |sonic-buildimage + +# mrvllib version update if needed +#0777-marvell-prestera-sai-1.17.1-13.patch |sonic-buildimage +#27704-docker-fpm-frr-Dockerfile.j2-update-libgoogle-perfto.patch |sonic-buildimage diff --git a/marvell_sonic_patch_script.sh b/marvell_sonic_patch_script.sh index ba76a3200..9558c00ab 100755 --- a/marvell_sonic_patch_script.sh +++ b/marvell_sonic_patch_script.sh @@ -261,7 +261,7 @@ main() # wget patch series file PATCH_SERIES_FILE=series_${PLATFORM}_${ARCH} wget_cp_silent $WGET_PATH/${PATCH_SERIES_FILE} -P ./patches/ - if [ ! -f ${PATCH_SERIES_FILE} ]; then + if [ ! -f ./patches/${PATCH_SERIES_FILE} ]; then PATCH_SERIES_FILE=series_${PLATFORM} wget_cp $WGET_PATH/${PATCH_SERIES_FILE} -P ./patches/ if [ ! -f ./patches/${PATCH_SERIES_FILE} ]; then