From 481b001462a1785c31de3c36a209f56722aa4e10 Mon Sep 17 00:00:00 2001 From: Roger Ho Date: Wed, 23 Apr 2025 09:43:46 +0800 Subject: [PATCH 1/4] [Accton][as9817-32d][as9817-32o] Add new platform CPU : COM-e Module Ice Lake-D (D-1713NTE) RAM : DDR4 SDRAM (16GB x 2 with ECC (SO-DIMM) DDR4) NOR Flash (Boot) : 64MB NOR Flash (Backup) : 64MB M.2 2280 SSD : 240G NVMe SSD Management : UART RS232 console port(RJ45 x1 port), Out-Band Management Ethernet port(RJ45 x 1 port), In-Band Management Ethernet port 2 x SFP28 ports MAC : Broadcom Tomahawk 5(BCM78902), 1 pcs, 25.6Tbs multi-layer Ethernet switch controller Ethernet Port : 32 x 800G QSFP-DD ports / 32 x 800G OSFP ports Power Supply : 12V/2400W PSU front to back airflow(AC to DC), 1+1 redundant load-sharing, hot-swappable Cooling : 7 FAN-tray modules with 7 pcs of 40mm x 56mm 12V hot-swappable fans DS-SCM Module : Aspeed AST2600 (BMC) + AST1060 (RoT) Dimension : 1U , 438.4mm(W) x 589mm(L) x 43mm(H) Note: 1. The latest kernel version supported by the Open Network Linux (ONL) upstream is 5.4, and there is no newer kernel version available or maintained at this time. Therefore, this platform is based on kernel 5.4. 2. Some advanced features, such as SDK-based management or advanced switching, require proprietary Broadcom binaries. These binaries are not included in ONL due to licensing restrictions. This commit only ports the platform code and does not include any Broadcom SDK or proprietary binaries. Signed-off-by: Roger Ho --- .../buster/common/all-base-packages.yml | 1 + .../src/python/onl/platform/base.py | 3 + .../x86-64/as9817-32/as9817-32d/.gitignore | 2 + .../x86-64/as9817-32/as9817-32d/Makefile | 1 + .../as9817-32/as9817-32d/modules/Makefile | 1 + .../as9817-32/as9817-32d/modules/PKG.yml | 1 + .../as9817-32d/modules/builds/.gitignore | 1 + .../as9817-32d/modules/builds/Makefile | 6 + .../x86-64/as9817-32/as9817-32d/onlp/Makefile | 1 + .../x86-64/as9817-32/as9817-32d/onlp/PKG.yml | 1 + .../as9817-32/as9817-32d/onlp/builds/Makefile | 2 + .../as9817-32d/onlp/builds/lib/Makefile | 3 + .../as9817-32d/onlp/builds/onlpdump/Makefile | 3 + .../as9817-32d/platform-config/Makefile | 1 + .../as9817-32d/platform-config/r0/Makefile | 1 + .../as9817-32d/platform-config/r0/PKG.yml | 1 + .../src/lib/x86-64-accton-as9817-32d-r0.yml | 31 + .../x86_64_accton_as9817_32d_r0/__init__.py | 114 ++ .../x86-64/as9817-32/as9817-32o/.gitignore | 2 + .../x86-64/as9817-32/as9817-32o/Makefile | 1 + .../as9817-32/as9817-32o/modules/Makefile | 1 + .../as9817-32/as9817-32o/modules/PKG.yml | 1 + .../as9817-32o/modules/builds/.gitignore | 1 + .../as9817-32o/modules/builds/Makefile | 6 + .../x86-64/as9817-32/as9817-32o/onlp/Makefile | 1 + .../x86-64/as9817-32/as9817-32o/onlp/PKG.yml | 1 + .../as9817-32/as9817-32o/onlp/builds/Makefile | 2 + .../as9817-32o/onlp/builds/lib/Makefile | 3 + .../as9817-32o/onlp/builds/onlpdump/Makefile | 3 + .../as9817-32o/platform-config/Makefile | 1 + .../as9817-32o/platform-config/r0/Makefile | 1 + .../as9817-32o/platform-config/r0/PKG.yml | 1 + .../src/lib/x86-64-accton-as9817-32o-r0.yml | 31 + .../x86_64_accton_as9817_32o_r0/__init__.py | 114 ++ .../x86-64/as9817-32/src/modules/.gitignore | 6 + .../x86-64/as9817-32/src/modules/Makefile | 8 + .../src/modules/x86-64-accton-as9817-32-fan.c | 841 +++++++++++++ .../modules/x86-64-accton-as9817-32-fpga.c | 1054 ++++++++++++++++ .../x86-64-accton-as9817-32-i2c-ocores.c | 960 +++++++++++++++ .../modules/x86-64-accton-as9817-32-leds.c | 558 +++++++++ .../src/modules/x86-64-accton-as9817-32-mux.c | 196 +++ .../src/modules/x86-64-accton-as9817-32-psu.c | 1083 +++++++++++++++++ .../src/modules/x86-64-accton-as9817-32-sys.c | 482 ++++++++ .../modules/x86-64-accton-as9817-32-thermal.c | 526 ++++++++ .../src/x86_64_accton_as9817_32/.gitignore | 1 + .../src/x86_64_accton_as9817_32/.module | 1 + .../src/x86_64_accton_as9817_32/Makefile | 9 + .../module/auto/make.mk | 8 + .../module/auto/x86_64_accton_as9817_32.yml | 50 + .../x86_64_accton_as9817_32.x | 12 + .../x86_64_accton_as9817_32_config.h | 137 +++ .../x86_64_accton_as9817_32_dox.h | 26 + .../x86_64_accton_as9817_32_porting.h | 107 ++ .../x86_64_accton_as9817_32/module/make.mk | 9 + .../module/src/Makefile | 8 + .../module/src/debug.c | 68 ++ .../x86_64_accton_as9817_32/module/src/fani.c | 299 +++++ .../x86_64_accton_as9817_32/module/src/ledi.c | 236 ++++ .../module/src/make.mk | 9 + .../module/src/platform_lib.c | 190 +++ .../module/src/platform_lib.h | 116 ++ .../x86_64_accton_as9817_32/module/src/psui.c | 167 +++ .../x86_64_accton_as9817_32/module/src/sfpi.c | 321 +++++ .../x86_64_accton_as9817_32/module/src/sysi.c | 610 ++++++++++ .../module/src/thermali.c | 172 +++ .../src/x86_64_accton_as9817_32_config.c | 80 ++ .../src/x86_64_accton_as9817_32_enums.c | 9 + .../module/src/x86_64_accton_as9817_32_int.h | 11 + .../module/src/x86_64_accton_as9817_32_log.c | 17 + .../module/src/x86_64_accton_as9817_32_log.h | 12 + .../src/x86_64_accton_as9817_32_module.c | 24 + .../module/src/x86_64_accton_as9817_32_ucli.c | 49 + 72 files changed, 8816 insertions(+) create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/lib/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/onlpdump/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/lib/x86-64-accton-as9817-32d-r0.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/lib/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/onlpdump/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/lib/x86-64-accton-as9817-32o-r0.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fpga.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-i2c-ocores.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-mux.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.module create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/make.mk create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/x86_64_accton_as9817_32.yml create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32.x create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_config.h create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_dox.h create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_porting.h create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/make.mk create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/Makefile create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/debug.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/ledi.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/make.mk create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sfpi.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sysi.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_config.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_enums.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_int.h create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.h create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_module.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_ucli.c diff --git a/builds/any/rootfs/buster/common/all-base-packages.yml b/builds/any/rootfs/buster/common/all-base-packages.yml index b8e9df5f3a..36a5d200c9 100644 --- a/builds/any/rootfs/buster/common/all-base-packages.yml +++ b/builds/any/rootfs/buster/common/all-base-packages.yml @@ -85,3 +85,4 @@ - htop - tree - memtester +- ipmitool diff --git a/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py b/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py index 08bdb9839b..2f4d35d646 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/platform/base.py @@ -650,3 +650,6 @@ class OnlPlatformPortConfig_40x100_13x400_2x10(object): class OnlPlatformPortConfig_64x800_2x25(object): PORT_COUNT=66 PORT_CONFIG="64x800 + 2x25" +class OnlPlatformPortConfig_32x800_2x25(object): + PORT_COUNT=34 + PORT_CONFIG="32x800 + 2x25" diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/.gitignore b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/.gitignore new file mode 100644 index 0000000000..690f2b5bde --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/.gitignore @@ -0,0 +1,2 @@ +*x86*64*accton*as9817*32d*.mk +onlpdump.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/PKG.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/PKG.yml new file mode 100644 index 0000000000..21c65846e7 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-modules.yml VENDOR=accton BASENAME=x86-64-accton-as9817-32d ARCH=amd64 KERNELS="onl-kernel-5.4-lts-x86-64-all:amd64" diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/.gitignore b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/.gitignore new file mode 100644 index 0000000000..a65b41774a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/Makefile new file mode 100644 index 0000000000..be70eba185 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/modules/builds/Makefile @@ -0,0 +1,6 @@ +KERNELS := onl-kernel-5.4-lts-x86-64-all:amd64 +KMODULES := $(ONL)/packages/platforms/accton/x86-64/as9817-32/src/modules/ +VENDOR := accton +BASENAME := x86-64-accton-as9817-32d +ARCH := x86_64 +include $(ONL)/make/kmodule.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/PKG.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/PKG.yml new file mode 100644 index 0000000000..d4ef05adca --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/onlp-platform-any.yml PLATFORM=x86-64-accton-as9817-32d ARCH=amd64 TOOLCHAIN=x86_64-linux-gnu diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/Makefile new file mode 100644 index 0000000000..e7437cb23a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/Makefile @@ -0,0 +1,2 @@ +FILTER=src +include $(ONL)/make/subdirs.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/lib/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/lib/Makefile new file mode 100644 index 0000000000..db8cbca41a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/lib/Makefile @@ -0,0 +1,3 @@ +PLATFORM := x86-64-accton-as9817-32d +PLATFORM_MODULE := x86_64_accton_as9817_32 +include $(ONL)/packages/base/any/onlp/builds/platform/libonlp-platform.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/onlpdump/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/onlpdump/Makefile new file mode 100644 index 0000000000..e35020b90b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/onlp/builds/onlpdump/Makefile @@ -0,0 +1,3 @@ +PLATFORM := x86-64-accton-as9817-32d +PLATFORM_MODULE := x86_64_accton_as9817_32 +include $(ONL)/packages/base/any/onlp/builds/platform/onlps.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/PKG.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/PKG.yml new file mode 100644 index 0000000000..4ab5972a5f --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-config-platform.yml ARCH=amd64 VENDOR=accton BASENAME=x86-64-accton-as9817-32d REVISION=r0 diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/lib/x86-64-accton-as9817-32d-r0.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/lib/x86-64-accton-as9817-32d-r0.yml new file mode 100644 index 0000000000..551df5b460 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/lib/x86-64-accton-as9817-32d-r0.yml @@ -0,0 +1,31 @@ +--- + +###################################################################### +# +# platform-config for AS9817-32D +# +###################################################################### + +x86-64-accton-as9817-32d-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-5-4 + + args: >- + console=ttyS0,115200n8 + intel_iommu=off pcie_aspm=off + + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py new file mode 100644 index 0000000000..c92eb80570 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py @@ -0,0 +1,114 @@ +import commands +from itertools import chain +from onl.platform.base import * +from onl.platform.accton import * +from time import sleep + +init_ipmi_dev = [ + 'echo "remove,kcs,i/o,0xca2" > /sys/module/ipmi_si/parameters/hotmod', + 'echo "add,kcs,i/o,0xca2" > /sys/module/ipmi_si/parameters/hotmod'] + +ATTEMPTS = 5 +INTERVAL = 3 + +def init_ipmi_dev_intf(): + attempts = ATTEMPTS + interval = INTERVAL + + while attempts: + if os.path.exists('/dev/ipmi0') or os.path.exists('/dev/ipmidev/0'): + return (True, (ATTEMPTS - attempts) * interval) + + for i in range(0, len(init_ipmi_dev)): + commands.getstatusoutput(init_ipmi_dev[i]) + + attempts -= 1 + sleep(interval) + + return (False, ATTEMPTS * interval) + +def init_ipmi_oem_cmd(): + attempts = ATTEMPTS + interval = INTERVAL + + while attempts: + status, output = commands.getstatusoutput('ipmitool raw 0x34 0x95') + if status: + attempts -= 1 + sleep(interval) + continue + + return (True, (ATTEMPTS - attempts) * interval) + + return (False, ATTEMPTS * interval) + +def init_ipmi(): + attempts = ATTEMPTS + interval = 60 + + while attempts: + attempts -= 1 + + (status, elapsed_dev) = init_ipmi_dev_intf() + if status is not True: + sleep(interval - elapsed_dev) + continue + + (status, elapsed_oem) = init_ipmi_oem_cmd() + if status is not True: + sleep(interval - elapsed_dev - elapsed_oem) + continue + + print('IPMI dev interface is ready.') + return True + + print('Failed to initialize IPMI dev interface') + return False + + +class OnlPlatform_x86_64_accton_as9817_32d_r0(OnlPlatformAccton, + OnlPlatformPortConfig_32x800_2x25): + PLATFORM='x86-64-accton-as9817-32d-r0' + MODEL="AS9817-32D" + SYS_OBJECT_ID=".9817.32" + + def modprobe(self, module, required=True, params={}): + cmd = "modprobe %s" % module + subprocess.check_call(cmd, shell=True) + + def baseconfig(self): + if init_ipmi() is not True: + return False + + self.modprobe('optoe') + self.modprobe('at24') + + for m in [ 'i2c-ocores', 'fpga', 'mux', 'fan', 'psu', 'thermal', 'sys', 'leds' ]: + self.insmod("x86-64-accton-as9817-32-%s" % m) + + ########### initialize I2C bus 0 ########### + self.new_i2c_devices( + [ + # initialize multiplexer (PCA9548) + ('as9817_32_mux', 0x78, 0), + + # initiate IDPROM + ('24c02', 0x56, 35), + ] + ) + + # initialize SFP devices + for port in range(1, 33): + subprocess.call('echo 0 > /sys/devices/platform/as9817_32_fpga/module_reset_%d' % (port), shell=True) + + sfp_bus = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34 + ] + + for port in range(1, len(sfp_bus)+1): + self.new_i2c_device('optoe3' if (port <= 32) else 'optoe2', 0x50, sfp_bus[port-1]) + subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port, sfp_bus[port-1]), shell=True) + + return True diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/.gitignore b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/.gitignore new file mode 100644 index 0000000000..61e7694929 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/.gitignore @@ -0,0 +1,2 @@ +*x86*64*accton*as9817*32o*.mk +onlpdump.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/PKG.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/PKG.yml new file mode 100644 index 0000000000..490230c916 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-modules.yml VENDOR=accton BASENAME=x86-64-accton-as9817-32o ARCH=amd64 KERNELS="onl-kernel-5.4-lts-x86-64-all:amd64" diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/.gitignore b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/.gitignore new file mode 100644 index 0000000000..a65b41774a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/Makefile new file mode 100644 index 0000000000..78b05e4c95 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/modules/builds/Makefile @@ -0,0 +1,6 @@ +KERNELS := onl-kernel-5.4-lts-x86-64-all:amd64 +KMODULES := $(ONL)/packages/platforms/accton/x86-64/as9817-32/src/modules/ +VENDOR := accton +BASENAME := x86-64-accton-as9817-32o +ARCH := x86_64 +include $(ONL)/make/kmodule.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/PKG.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/PKG.yml new file mode 100644 index 0000000000..f46a3ac295 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/onlp-platform-any.yml PLATFORM=x86-64-accton-as9817-32o ARCH=amd64 TOOLCHAIN=x86_64-linux-gnu diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/Makefile new file mode 100644 index 0000000000..e7437cb23a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/Makefile @@ -0,0 +1,2 @@ +FILTER=src +include $(ONL)/make/subdirs.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/lib/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/lib/Makefile new file mode 100644 index 0000000000..e58502de97 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/lib/Makefile @@ -0,0 +1,3 @@ +PLATFORM := x86-64-accton-as9817-32o +PLATFORM_MODULE := x86_64_accton_as9817_32 +include $(ONL)/packages/base/any/onlp/builds/platform/libonlp-platform.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/onlpdump/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/onlpdump/Makefile new file mode 100644 index 0000000000..09f9bc009e --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/onlp/builds/onlpdump/Makefile @@ -0,0 +1,3 @@ +PLATFORM := x86-64-accton-as9817-32o +PLATFORM_MODULE := x86_64_accton_as9817_32 +include $(ONL)/packages/base/any/onlp/builds/platform/onlps.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/Makefile b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/PKG.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/PKG.yml new file mode 100644 index 0000000000..6e9458f644 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-config-platform.yml ARCH=amd64 VENDOR=accton BASENAME=x86-64-accton-as9817-32o REVISION=r0 diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/lib/x86-64-accton-as9817-32o-r0.yml b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/lib/x86-64-accton-as9817-32o-r0.yml new file mode 100644 index 0000000000..0b380f2167 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/lib/x86-64-accton-as9817-32o-r0.yml @@ -0,0 +1,31 @@ +--- + +###################################################################### +# +# platform-config for AS9817-32O +# +###################################################################### + +x86-64-accton-as9817-32o-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-5-4 + + args: >- + console=ttyS0,115200n8 + intel_iommu=off pcie_aspm=off + + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py new file mode 100644 index 0000000000..a2752fd8ec --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py @@ -0,0 +1,114 @@ +import commands +from itertools import chain +from onl.platform.base import * +from onl.platform.accton import * +from time import sleep + +init_ipmi_dev = [ + 'echo "remove,kcs,i/o,0xca2" > /sys/module/ipmi_si/parameters/hotmod', + 'echo "add,kcs,i/o,0xca2" > /sys/module/ipmi_si/parameters/hotmod'] + +ATTEMPTS = 5 +INTERVAL = 3 + +def init_ipmi_dev_intf(): + attempts = ATTEMPTS + interval = INTERVAL + + while attempts: + if os.path.exists('/dev/ipmi0') or os.path.exists('/dev/ipmidev/0'): + return (True, (ATTEMPTS - attempts) * interval) + + for i in range(0, len(init_ipmi_dev)): + commands.getstatusoutput(init_ipmi_dev[i]) + + attempts -= 1 + sleep(interval) + + return (False, ATTEMPTS * interval) + +def init_ipmi_oem_cmd(): + attempts = ATTEMPTS + interval = INTERVAL + + while attempts: + status, output = commands.getstatusoutput('ipmitool raw 0x34 0x95') + if status: + attempts -= 1 + sleep(interval) + continue + + return (True, (ATTEMPTS - attempts) * interval) + + return (False, ATTEMPTS * interval) + +def init_ipmi(): + attempts = ATTEMPTS + interval = 60 + + while attempts: + attempts -= 1 + + (status, elapsed_dev) = init_ipmi_dev_intf() + if status is not True: + sleep(interval - elapsed_dev) + continue + + (status, elapsed_oem) = init_ipmi_oem_cmd() + if status is not True: + sleep(interval - elapsed_dev - elapsed_oem) + continue + + print('IPMI dev interface is ready.') + return True + + print('Failed to initialize IPMI dev interface') + return False + + +class OnlPlatform_x86_64_accton_as9817_32o_r0(OnlPlatformAccton, + OnlPlatformPortConfig_32x800_2x25): + PLATFORM='x86-64-accton-as9817-32o-r0' + MODEL="AS9817-32O" + SYS_OBJECT_ID=".9817.32" + + def modprobe(self, module, required=True, params={}): + cmd = "modprobe %s" % module + subprocess.check_call(cmd, shell=True) + + def baseconfig(self): + if init_ipmi() is not True: + return False + + self.modprobe('optoe') + self.modprobe('at24') + + for m in [ 'i2c-ocores', 'fpga', 'mux', 'fan', 'psu', 'thermal', 'sys', 'leds' ]: + self.insmod("x86-64-accton-as9817-32-%s" % m) + + ########### initialize I2C bus 0 ########### + self.new_i2c_devices( + [ + # initialize multiplexer (PCA9548) + ('as9817_32_mux', 0x78, 0), + + # initiate IDPROM + ('24c02', 0x56, 35), + ] + ) + + # initialize SFP devices + for port in range(1, 33): + subprocess.call('echo 0 > /sys/devices/platform/as9817_32_fpga/module_reset_%d' % (port), shell=True) + + sfp_bus = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34 + ] + + for port in range(1, len(sfp_bus)+1): + self.new_i2c_device('optoe3' if (port <= 32) else 'optoe2', 0x50, sfp_bus[port-1]) + subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port, sfp_bus[port-1]), shell=True) + + return True diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/.gitignore b/packages/platforms/accton/x86-64/as9817-32/src/modules/.gitignore new file mode 100644 index 0000000000..e35baed358 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/.gitignore @@ -0,0 +1,6 @@ +*.ko +*.mod* +*.o +*.a +Module.* +modules.order diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile b/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile new file mode 100644 index 0000000000..49cb1ea7e9 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile @@ -0,0 +1,8 @@ +obj-m += x86-64-accton-as9817-32-fan.o +obj-m += x86-64-accton-as9817-32-fpga.o +obj-m += x86-64-accton-as9817-32-i2c-ocores.o +obj-m += x86-64-accton-as9817-32-leds.o +obj-m += x86-64-accton-as9817-32-psu.o +obj-m += x86-64-accton-as9817-32-sys.o +obj-m += x86-64-accton-as9817-32-thermal.o +obj-m += x86-64-accton-as9817-32-mux.o diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c new file mode 100644 index 0000000000..9cb1e692b9 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c @@ -0,0 +1,841 @@ +/* + * Copyright (C) Roger Ho + * + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9817_32_fan" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_FAN_READ_CMD 0x14 +#define IPMI_FAN_WRITE_CMD 0x15 +#define IPMI_FAN_READ_RPM_CMD 0x20 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_FAN_REG_READ_CMD 0x20 +#define IPMI_FAN_REG_WRITE_CMD 0x21 +#define MAX_FAN_SPEED_RPM 33000 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf); +static int as9817_32_fan_probe(struct platform_device *pdev); +static int as9817_32_fan_remove(struct platform_device *pdev); + +enum fan_id { + FAN_1, + FAN_2, + FAN_3, + FAN_4, + FAN_5, + FAN_6, + FAN_7, + FAN_8, + FAN_9, + FAN_10, + FAN_11, + FAN_12, + FAN_13, + FAN_14, + NUM_OF_FAN, + NUM_OF_FAN_MODULE = NUM_OF_FAN +}; + +enum fan_data_index { + FAN_PRESENT, + FAN_PWM, + FAN_SPEED0, + FAN_SPEED1, + FAN_DATA_COUNT, + + FAN_TARGET_SPEED0 = 0, + FAN_TARGET_SPEED1, + FAN_SPEED_TOLERANCE, + FAN_SPEED_DATA_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as9817_32_fan_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + /* 4 bytes for each fan, the last 2 bytes is fan dir */ + unsigned char ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT + 2]; + unsigned char ipmi_resp_cpld[2]; + unsigned char ipmi_resp_speed[NUM_OF_FAN * FAN_SPEED_DATA_COUNT]; + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[3]; /* 0: FAN id, 1: 0x02, 2: PWM */ +}; + +struct as9817_32_fan_data *data = NULL; + +static struct platform_driver as9817_32_fan_driver = { + .probe = as9817_32_fan_probe, + .remove = as9817_32_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define FAN_PRESENT_ATTR_ID(index) FAN##index##_PRESENT +#define FAN_PWM_ATTR_ID(index) FAN##index##_PWM +#define FAN_RPM_ATTR_ID(index) FAN##index##_INPUT +#define FAN_DIR_ATTR_ID(index) FAN##index##_DIR +#define FAN_FAULT_ATTR_ID(index) FAN##index##_FAULT +#define FAN_RPM_TARGET_ATTR_ID(index) FAN##index##_TARGET +#define FAN_RPM_TOLERANCE_ATTR_ID(index) FAN##index##_TOLERANCE + +#define FAN_ATTR(fan_id) \ + FAN_PRESENT_ATTR_ID(fan_id), \ + FAN_PWM_ATTR_ID(fan_id), \ + FAN_RPM_ATTR_ID(fan_id), \ + FAN_DIR_ATTR_ID(fan_id), \ + FAN_FAULT_ATTR_ID(fan_id) + +#define FAN_RPM_THRESHOLD_ATTR(fan_id) \ + FAN_RPM_TARGET_ATTR_ID(fan_id), \ + FAN_RPM_TOLERANCE_ATTR_ID(fan_id) + +enum as9817_32_fan_sysfs_attrs { + FAN_ATTR(1), + FAN_ATTR(2), + FAN_ATTR(3), + FAN_ATTR(4), + FAN_ATTR(5), + FAN_ATTR(6), + FAN_ATTR(7), + FAN_ATTR(8), + FAN_ATTR(9), + FAN_ATTR(10), + FAN_ATTR(11), + FAN_ATTR(12), + FAN_ATTR(13), + FAN_ATTR(14), + NUM_OF_FAN_ATTR, + FAN_VERSION, + FAN_MAX_RPM, + NUM_OF_PER_FAN_ATTR = (NUM_OF_FAN_ATTR/NUM_OF_FAN), + FAN_RPM_THRESHOLD_ATTR(1), + FAN_RPM_THRESHOLD_ATTR(2), + FAN_RPM_THRESHOLD_ATTR(3), + FAN_RPM_THRESHOLD_ATTR(4), + FAN_RPM_THRESHOLD_ATTR(5), + FAN_RPM_THRESHOLD_ATTR(6), + FAN_RPM_THRESHOLD_ATTR(7), + FAN_RPM_THRESHOLD_ATTR(8), + FAN_RPM_THRESHOLD_ATTR(9), + FAN_RPM_THRESHOLD_ATTR(10), + FAN_RPM_THRESHOLD_ATTR(11), + FAN_RPM_THRESHOLD_ATTR(12), + FAN_RPM_THRESHOLD_ATTR(13), + FAN_RPM_THRESHOLD_ATTR(14) +}; + +/* fan attributes */ +#define DECLARE_FAN_VER_SENSOR_DEVICE_ATTR() \ + static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, FAN_VERSION) +#define DECLARE_FAN_VER_ATTR() \ + &sensor_dev_attr_version.dev_attr.attr + +#define DECLARE_FAN_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, show_fan, NULL, \ + FAN##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(fan##index##_pwm, S_IWUSR | S_IRUGO, show_fan, \ + set_fan, FAN##index##_PWM); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, show_fan, NULL, \ + FAN##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(fan##index##_dir, S_IRUGO, show_dir, NULL, \ + FAN##index##_DIR); \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, show_fan, NULL, \ + FAN##index##_FAULT); \ + static SENSOR_DEVICE_ATTR(fan##index##_target, S_IRUGO, show_threshold, \ + NULL, FAN##index##_TARGET); \ + static SENSOR_DEVICE_ATTR(fan##index##_tolerance, S_IRUGO, show_threshold,\ + NULL, FAN##index##_TOLERANCE) + +static SENSOR_DEVICE_ATTR(fan_max_speed_rpm, S_IRUGO, show_fan, NULL, \ + FAN_MAX_RPM); +#define DECLARE_FAN_MAX_RPM_ATTR(index) \ + &sensor_dev_attr_fan_max_speed_rpm.dev_attr.attr + +#define DECLARE_FAN_ATTR(index) \ + &sensor_dev_attr_fan##index##_present.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_pwm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_dir.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_fault.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_target.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_tolerance.dev_attr.attr + +DECLARE_FAN_SENSOR_DEVICE_ATTR(1); +DECLARE_FAN_SENSOR_DEVICE_ATTR(2); +DECLARE_FAN_SENSOR_DEVICE_ATTR(3); +DECLARE_FAN_SENSOR_DEVICE_ATTR(4); +DECLARE_FAN_SENSOR_DEVICE_ATTR(5); +DECLARE_FAN_SENSOR_DEVICE_ATTR(6); +DECLARE_FAN_SENSOR_DEVICE_ATTR(7); +DECLARE_FAN_SENSOR_DEVICE_ATTR(8); +DECLARE_FAN_SENSOR_DEVICE_ATTR(9); +DECLARE_FAN_SENSOR_DEVICE_ATTR(10); +DECLARE_FAN_SENSOR_DEVICE_ATTR(11); +DECLARE_FAN_SENSOR_DEVICE_ATTR(12); +DECLARE_FAN_SENSOR_DEVICE_ATTR(13); +DECLARE_FAN_SENSOR_DEVICE_ATTR(14); +DECLARE_FAN_VER_SENSOR_DEVICE_ATTR(); + +static struct attribute *as9817_32_fan_attrs[] = { + /* fan attributes */ + DECLARE_FAN_ATTR(1), + DECLARE_FAN_ATTR(2), + DECLARE_FAN_ATTR(3), + DECLARE_FAN_ATTR(4), + DECLARE_FAN_ATTR(5), + DECLARE_FAN_ATTR(6), + DECLARE_FAN_ATTR(7), + DECLARE_FAN_ATTR(8), + DECLARE_FAN_ATTR(9), + DECLARE_FAN_ATTR(10), + DECLARE_FAN_ATTR(11), + DECLARE_FAN_ATTR(12), + DECLARE_FAN_ATTR(13), + DECLARE_FAN_ATTR(14), + DECLARE_FAN_VER_ATTR(), + DECLARE_FAN_MAX_RPM_ATTR(), + NULL +}; +ATTRIBUTE_GROUPS(as9817_32_fan); + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + + int i = 0; + char raw_cmd[20] = ""; + sprintf(raw_cmd, "0x%02x", cmd); + if(tx_len) { + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi,cmd, tx_data, tx_len, rx_data, + rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + if (cmdline) + kfree(cmdline); + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as9817_32_fan_data *as9817_32_fan_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) + return data; + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_tx_data[0] = IPMI_FAN_READ_RPM_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_speed, + sizeof(data->ipmi_resp_speed)); + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + if (attr->index == FAN_MAX_RPM) + return sprintf(buf, "%d\n", MAX_FAN_SPEED_RPM); + + mutex_lock(&data->update_lock); + + data = as9817_32_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + switch (attr->index) { + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + case FAN6_PRESENT: + case FAN7_PRESENT: + case FAN8_PRESENT: + case FAN9_PRESENT: + case FAN10_PRESENT: + case FAN11_PRESENT: + case FAN12_PRESENT: + case FAN13_PRESENT: + case FAN14_PRESENT: + value = present; + break; + case FAN1_PWM: + case FAN2_PWM: + case FAN3_PWM: + case FAN4_PWM: + case FAN5_PWM: + case FAN6_PWM: + case FAN7_PWM: + case FAN8_PWM: + case FAN9_PWM: + case FAN10_PWM: + case FAN11_PWM: + case FAN12_PWM: + case FAN13_PWM: + case FAN14_PWM: + index = (fid % NUM_OF_FAN_MODULE) * FAN_DATA_COUNT; + value = DIV_ROUND_CLOSEST(data->ipmi_resp[index + FAN_PWM] * 666, 100); + break; + case FAN1_INPUT: + case FAN2_INPUT: + case FAN3_INPUT: + case FAN4_INPUT: + case FAN5_INPUT: + case FAN6_INPUT: + case FAN7_INPUT: + case FAN8_INPUT: + case FAN9_INPUT: + case FAN10_INPUT: + case FAN11_INPUT: + case FAN12_INPUT: + case FAN13_INPUT: + case FAN14_INPUT: + value = (int)data->ipmi_resp[index + FAN_SPEED0] | + (int)data->ipmi_resp[index + FAN_SPEED1] << 8; + break; + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + case FAN5_FAULT: + case FAN6_FAULT: + case FAN7_FAULT: + case FAN8_FAULT: + case FAN9_FAULT: + case FAN10_FAULT: + case FAN11_FAULT: + case FAN12_FAULT: + case FAN13_FAULT: + case FAN14_FAULT: + value = (int)data->ipmi_resp[index + FAN_SPEED0] | + (int)data->ipmi_resp[index + FAN_SPEED1] << 8; + value = !value; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long pwm; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + + status = kstrtol(buf, 10, &pwm); + if (status) + return status; + + pwm = (pwm * 100) / 666; /* Convert pwm to register value */ + + mutex_lock(&data->update_lock); + + /* + * Send IPMI write command : + * BMC supports a design with four fan modules, each containing two fans. + * Since NUM_OF_FAN_MODULE is 8 in AS9817, it needs to be divided by 2. + * The result : + * fan1_pwm(Front) : ipmi_tx_data[0] = 1, fan2_pwm(Front) : ipmi_tx_data[0] = 2 + * fan3_pwm(Front) : ipmi_tx_data[0] = 3, fan4_pwm(Front) : ipmi_tx_data[0] = 4 + * fan5_pwm(Rear) : ipmi_tx_data[0] = 1, fan6_pwm(Rear) : ipmi_tx_data[0] = 2 + * fan7_pwm(Rear) : ipmi_tx_data[0] = 3, fan8_pwm(Rear) : ipmi_tx_data[0] = 4 + * + */ + data->ipmi_tx_data[0] = (fid % (NUM_OF_FAN_MODULE / 2)) + 1; + data->ipmi_tx_data[1] = 0x02; + data->ipmi_tx_data[2] = pwm; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_WRITE_CMD, + data->ipmi_tx_data, sizeof(data->ipmi_tx_data), + NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* force update */ + data->valid = 0; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static struct as9817_32_fan_data *as9817_32_fan_update_cpld_ver(void) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = 0x33; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_REG_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_cpld, + sizeof(data->ipmi_resp_cpld)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + unsigned char major; + unsigned char minor; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_fan_update_cpld_ver(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + major = data->ipmi_resp_cpld[0]; + minor = data->ipmi_resp_cpld[1]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d.%d\n", major, minor); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = (attr->index / NUM_OF_PER_FAN_ATTR); + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + value = data->ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT] | + (data->ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT + 1] << 8); + mutex_unlock(&data->update_lock); + + if (!present) + return sprintf(buf, "0\n"); + else + return sprintf(buf, "%s\n", + (value & BIT(fid % NUM_OF_FAN_MODULE)) ? "B2F" : "F2B"); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (attr->index) { + case FAN1_TARGET: + case FAN2_TARGET: + case FAN3_TARGET: + case FAN4_TARGET: + case FAN5_TARGET: + case FAN6_TARGET: + case FAN7_TARGET: + case FAN8_TARGET: + case FAN9_TARGET: + case FAN10_TARGET: + case FAN11_TARGET: + case FAN12_TARGET: + case FAN13_TARGET: + case FAN14_TARGET: + value = (int)data->ipmi_resp_speed[FAN_TARGET_SPEED0] | + (int)data->ipmi_resp_speed[FAN_TARGET_SPEED1] << 8; + break; + case FAN1_TOLERANCE: + case FAN2_TOLERANCE: + case FAN3_TOLERANCE: + case FAN4_TOLERANCE: + case FAN5_TOLERANCE: + case FAN6_TOLERANCE: + case FAN7_TOLERANCE: + case FAN8_TOLERANCE: + case FAN9_TOLERANCE: + case FAN10_TOLERANCE: + case FAN11_TOLERANCE: + case FAN12_TOLERANCE: + case FAN13_TOLERANCE: + case FAN14_TOLERANCE: + value = (int)data->ipmi_resp_speed[FAN_SPEED_TOLERANCE]; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as9817_32_fan_probe(struct platform_device *pdev) +{ + int status = 0; + struct device *hwmon_dev; + + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9817_32_fan_groups); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + return status; + } + + mutex_lock(&data->update_lock); + data->hwmon_dev = hwmon_dev; + mutex_unlock(&data->update_lock); + + dev_info(&pdev->dev, "Device Created\n"); + + return status; +} + +static int as9817_32_fan_remove(struct platform_device *pdev) +{ + mutex_lock(&data->update_lock); + if (data->hwmon_dev) { + hwmon_device_unregister(data->hwmon_dev); + data->hwmon_dev = NULL; + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int __init as9817_32_fan_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9817_32_fan_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9817_32_fan_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) { + goto ipmi_err; + } + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as9817_32_fan_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9817_32_fan_exit(void) +{ + if (data) { + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + kfree(data); + } + platform_driver_unregister(&as9817_32_fan_driver); +} + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9817_32_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(as9817_32_fan_init); +module_exit(as9817_32_fan_exit); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fpga.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fpga.c new file mode 100644 index 0000000000..b9cd858ba2 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fpga.c @@ -0,0 +1,1054 @@ +/* + * Copyright (C) Roger Ho + * + * This module supports the accton fpga via pcie that read/write reg + * mechanism to get OSFP/SFP status ...etc. + * This includes the: + * Accton as9817_32 FPGA + * + * Copyright (C) 2017 Finisar Corp. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include + +/*********************************************** + * variable define + * *********************************************/ +#define DRVNAME "as9817_32_fpga" +#define OCORES_I2C_DRVNAME "ocores-as9817-32" + +#define PORT_NUM (32 + 2) /* 32 OSFPs/QSFPDDs + 2 SFP28s */ + +/* + * PCIE BAR0 address + */ +#define BAR0_NUM 0 +#define BAR1_NUM 1 +#define BAR2_NUM 2 +#define REGION_LEN 0xFF +#define FPGA_PCI_VENDOR_ID 0x10ee +#define FPGA_PCI_DEVICE_ID 0x7021 + +#define FPGA_PCIE_START_OFFSET 0x0000 +#define FPGA_MAJOR_VER_REG 0x01 +#define FPGA_MINOR_VER_REG 0x02 +#define SPI_BUSY_MASK_CPLD1 0x01 +#define SPI_BUSY_MASK_CPLD2 0x02 + +#define FPGA_PCIE_START_OFFSET 0x0000 +#define FPGA_BOARD_INFO_REG (FPGA_PCIE_START_OFFSET + 0x00) +#define FPGA_MAC_MIN_TEMP1_REG (FPGA_PCIE_START_OFFSET + 0xA0) +#define FPGA_MAC_MIN_TEMP2_REG (FPGA_PCIE_START_OFFSET + 0xA1) +#define FPGA_MAC_MIN_TEMP3_REG (FPGA_PCIE_START_OFFSET + 0xA2) +#define FPGA_MAC_MIN_TEMP4_REG (FPGA_PCIE_START_OFFSET + 0xA3) +#define FPGA_MAC_MAX_TEMP1_REG (FPGA_PCIE_START_OFFSET + 0xA4) +#define FPGA_MAC_MAX_TEMP2_REG (FPGA_PCIE_START_OFFSET + 0xA5) +#define FPGA_MAC_MAX_TEMP3_REG (FPGA_PCIE_START_OFFSET + 0xA6) +#define FPGA_MAC_MAX_TEMP4_REG (FPGA_PCIE_START_OFFSET + 0xA7) + +/* CPLD 1 */ +#define CPLD1_PCIE_START_OFFSET 0x2000 +#define CPLD1_MAJOR_VER_REG (CPLD1_PCIE_START_OFFSET + 0x00) +#define CPLD1_MINOR_VER_REG (CPLD1_PCIE_START_OFFSET + 0x01) +#define XCVR_P7_P0_LPMODE_REG (CPLD1_PCIE_START_OFFSET + 0x70) +#define XCVR_P15_P8_LPMODE_REG (CPLD1_PCIE_START_OFFSET + 0x71) +#define XCVR_P7_P0_RESET_REG (CPLD1_PCIE_START_OFFSET + 0x78) +#define XCVR_P15_P8_RESET_REG (CPLD1_PCIE_START_OFFSET + 0x79) +#define XCVR_P7_P0_PRESENT_REG (CPLD1_PCIE_START_OFFSET + 0x88) +#define XCVR_P15_P8_PRESENT_REG (CPLD1_PCIE_START_OFFSET + 0x89) + +/* CPLD 2 */ +#define CPLD2_PCIE_START_OFFSET 0x3000 +#define CPLD2_MAJOR_VER_REG (CPLD2_PCIE_START_OFFSET + 0x00) +#define CPLD2_MINOR_VER_REG (CPLD2_PCIE_START_OFFSET + 0x01) +#define SFP_TXFAULT_REG (CPLD2_PCIE_START_OFFSET + 0x06) +#define SFP_TXDIS_REG (CPLD2_PCIE_START_OFFSET + 0x07) +#define SFP_RXLOSS_REG (CPLD2_PCIE_START_OFFSET + 0x08) +#define SFP_PRESENT_REG (CPLD2_PCIE_START_OFFSET + 0x09) +#define XCVR_P23_P16_LPMODE_REG (CPLD2_PCIE_START_OFFSET + 0x70) +#define XCVR_P31_P24_LPMODE_REG (CPLD2_PCIE_START_OFFSET + 0x71) +#define XCVR_P23_P16_RESET_REG (CPLD2_PCIE_START_OFFSET + 0x78) +#define XCVR_P31_P24_RESET_REG (CPLD2_PCIE_START_OFFSET + 0x79) +#define XCVR_P23_P16_PRESENT_REG (CPLD2_PCIE_START_OFFSET + 0x88) +#define XCVR_P31_P24_PRESENT_REG (CPLD2_PCIE_START_OFFSET + 0x89) + +/* DC-SCM CPLD */ +#define CPLD3_PCIE_START_OFFSET 0x4000 +#define CPLD3_BOARD_INFO_REG (CPLD3_PCIE_START_OFFSET + 0x00) +#define CPLD3_VERSION_REG (CPLD3_PCIE_START_OFFSET + 0x01) + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_TX_DISABLE_ATTR_ID(index) MODULE_TX_DISABLE_##index +#define TRANSCEIVER_TX_FAULT_ATTR_ID(index) MODULE_TX_FAULT_##index +#define TRANSCEIVER_RX_LOS_ATTR_ID(index) MODULE_RX_LOS_##index + +/*********************************************** + * macro define + * *********************************************/ +#define pcie_err(fmt, args...) \ + printk(KERN_ERR "["DRVNAME"]: " fmt " ", ##args) + +#define pcie_info(fmt, args...) \ + printk(KERN_ERR "["DRVNAME"]: " fmt " ", ##args) + + +#define LOCK(lock) \ +do { \ + spin_lock(lock); \ +} while (0) + +#define UNLOCK(lock) \ +do { \ + spin_unlock(lock); \ +} while (0) + + +/*********************************************** + * structure & variable declare + * *********************************************/ +typedef struct pci_fpga_device_s { + void __iomem *data_base_addr0; + void __iomem *data_base_addr1; + void __iomem *data_base_addr2; + resource_size_t data_region1; + resource_size_t data_region2; + struct pci_dev *pci_dev; + struct platform_device *fpga_i2c[PORT_NUM]; +} pci_fpga_device_t; + +/*fpga port status*/ +struct as9817_32_fpga_data { + u8 cpld_reg[3]; + unsigned long last_updated; /* In jiffies */ + pci_fpga_device_t pci_fpga_dev; + int platform_id; /* 0: 64O, 1: 64D */ +}; + +static struct platform_device *pdev = NULL; +extern spinlock_t cpld_access_lock; +extern int wait_spi(u32 mask, unsigned long timeout); +extern void __iomem *spi_busy_reg; + +/*********************************************** + * enum define + * *********************************************/ +enum fpga_sysfs_attributes { + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(31), + TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_PRESENT_ATTR_ID(33), + TRANSCEIVER_PRESENT_ATTR_ID(34), + /*Reset*/ + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_LPMODE_ATTR_ID(1), + TRANSCEIVER_LPMODE_ATTR_ID(2), + TRANSCEIVER_LPMODE_ATTR_ID(3), + TRANSCEIVER_LPMODE_ATTR_ID(4), + TRANSCEIVER_LPMODE_ATTR_ID(5), + TRANSCEIVER_LPMODE_ATTR_ID(6), + TRANSCEIVER_LPMODE_ATTR_ID(7), + TRANSCEIVER_LPMODE_ATTR_ID(8), + TRANSCEIVER_LPMODE_ATTR_ID(9), + TRANSCEIVER_LPMODE_ATTR_ID(10), + TRANSCEIVER_LPMODE_ATTR_ID(11), + TRANSCEIVER_LPMODE_ATTR_ID(12), + TRANSCEIVER_LPMODE_ATTR_ID(13), + TRANSCEIVER_LPMODE_ATTR_ID(14), + TRANSCEIVER_LPMODE_ATTR_ID(15), + TRANSCEIVER_LPMODE_ATTR_ID(16), + TRANSCEIVER_LPMODE_ATTR_ID(17), + TRANSCEIVER_LPMODE_ATTR_ID(18), + TRANSCEIVER_LPMODE_ATTR_ID(19), + TRANSCEIVER_LPMODE_ATTR_ID(20), + TRANSCEIVER_LPMODE_ATTR_ID(21), + TRANSCEIVER_LPMODE_ATTR_ID(22), + TRANSCEIVER_LPMODE_ATTR_ID(23), + TRANSCEIVER_LPMODE_ATTR_ID(24), + TRANSCEIVER_LPMODE_ATTR_ID(25), + TRANSCEIVER_LPMODE_ATTR_ID(26), + TRANSCEIVER_LPMODE_ATTR_ID(27), + TRANSCEIVER_LPMODE_ATTR_ID(28), + TRANSCEIVER_LPMODE_ATTR_ID(29), + TRANSCEIVER_LPMODE_ATTR_ID(30), + TRANSCEIVER_LPMODE_ATTR_ID(31), + TRANSCEIVER_LPMODE_ATTR_ID(32), + TRANSCEIVER_TX_DISABLE_ATTR_ID(33), + TRANSCEIVER_TX_DISABLE_ATTR_ID(34), + TRANSCEIVER_TX_FAULT_ATTR_ID(33), + TRANSCEIVER_TX_FAULT_ATTR_ID(34), + TRANSCEIVER_RX_LOS_ATTR_ID(33), + TRANSCEIVER_RX_LOS_ATTR_ID(34), + /* MODULE_RESET_ALL, */ + CPLD1_VERSION, + CPLD2_VERSION, + CPLD3_VERSION, + CPLD1_REG, + CPLD2_REG, + CPLD3_REG, + PLATFORM_ID, + MAC_MIN_TEMP, + MAC_MAX_TEMP +}; + + +/*********************************************** + * function declare + * *********************************************/ +static ssize_t reg_read(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t reg_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t status_read(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t status_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +#define DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, status_read, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO|S_IWUSR, status_read, status_write, MODULE_RESET_##index); \ + static SENSOR_DEVICE_ATTR(module_lp_mode_##index, S_IRUGO|S_IWUSR, status_read, status_write, MODULE_LPMODE_##index) +#define DECLARE_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr, \ + &sensor_dev_attr_module_lp_mode_##index.dev_attr.attr + +/* transceiver attributes */ +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +static SENSOR_DEVICE_ATTR(module_present_33, S_IRUGO, status_read, NULL, MODULE_PRESENT_33); +static SENSOR_DEVICE_ATTR(module_present_34, S_IRUGO, status_read, NULL, MODULE_PRESENT_34); +//static SENSOR_DEVICE_ATTR(module_reset_all, S_IWUSR, NULL, status_write, MODULE_RESET_ALL); +static SENSOR_DEVICE_ATTR(module_tx_disable_33, S_IRUGO|S_IWUSR, status_read, + status_write, MODULE_TX_DISABLE_33); +static SENSOR_DEVICE_ATTR(module_tx_disable_34, S_IRUGO|S_IWUSR, status_read, + status_write, MODULE_TX_DISABLE_34); +static SENSOR_DEVICE_ATTR(module_tx_fault_33, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_33); +static SENSOR_DEVICE_ATTR(module_tx_fault_34, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_34); +static SENSOR_DEVICE_ATTR(module_rx_los_33, S_IRUGO, status_read, NULL, MODULE_RX_LOS_33); +static SENSOR_DEVICE_ATTR(module_rx_los_34, S_IRUGO, status_read, NULL, MODULE_RX_LOS_34); +static SENSOR_DEVICE_ATTR(cpld1_version, S_IRUGO, status_read, NULL, CPLD1_VERSION); +static SENSOR_DEVICE_ATTR(cpld2_version, S_IRUGO, status_read, NULL, CPLD2_VERSION); +static SENSOR_DEVICE_ATTR(cpld3_version, S_IRUGO, status_read, NULL, CPLD3_VERSION); +static SENSOR_DEVICE_ATTR(cpld1_reg, S_IRUGO|S_IWUSR, reg_read, reg_write, CPLD1_REG); +static SENSOR_DEVICE_ATTR(cpld2_reg, S_IRUGO|S_IWUSR, reg_read, reg_write, CPLD2_REG); +static SENSOR_DEVICE_ATTR(cpld3_reg, S_IRUGO|S_IWUSR, reg_read, reg_write, CPLD3_REG); +static SENSOR_DEVICE_ATTR(platform_id, S_IRUGO, status_read, NULL, PLATFORM_ID); +static SENSOR_DEVICE_ATTR(mac_min_temp, S_IRUGO, status_read, NULL, MAC_MIN_TEMP); +static SENSOR_DEVICE_ATTR(mac_max_temp, S_IRUGO, status_read, NULL, MAC_MAX_TEMP); + +static struct attribute *fpga_transceiver_attributes[] = { + DECLARE_TRANSCEIVER_ATTR(1), + DECLARE_TRANSCEIVER_ATTR(2), + DECLARE_TRANSCEIVER_ATTR(3), + DECLARE_TRANSCEIVER_ATTR(4), + DECLARE_TRANSCEIVER_ATTR(5), + DECLARE_TRANSCEIVER_ATTR(6), + DECLARE_TRANSCEIVER_ATTR(7), + DECLARE_TRANSCEIVER_ATTR(8), + DECLARE_TRANSCEIVER_ATTR(9), + DECLARE_TRANSCEIVER_ATTR(10), + DECLARE_TRANSCEIVER_ATTR(11), + DECLARE_TRANSCEIVER_ATTR(12), + DECLARE_TRANSCEIVER_ATTR(13), + DECLARE_TRANSCEIVER_ATTR(14), + DECLARE_TRANSCEIVER_ATTR(15), + DECLARE_TRANSCEIVER_ATTR(16), + DECLARE_TRANSCEIVER_ATTR(17), + DECLARE_TRANSCEIVER_ATTR(18), + DECLARE_TRANSCEIVER_ATTR(19), + DECLARE_TRANSCEIVER_ATTR(20), + DECLARE_TRANSCEIVER_ATTR(21), + DECLARE_TRANSCEIVER_ATTR(22), + DECLARE_TRANSCEIVER_ATTR(23), + DECLARE_TRANSCEIVER_ATTR(24), + DECLARE_TRANSCEIVER_ATTR(25), + DECLARE_TRANSCEIVER_ATTR(26), + DECLARE_TRANSCEIVER_ATTR(27), + DECLARE_TRANSCEIVER_ATTR(28), + DECLARE_TRANSCEIVER_ATTR(29), + DECLARE_TRANSCEIVER_ATTR(30), + DECLARE_TRANSCEIVER_ATTR(31), + DECLARE_TRANSCEIVER_ATTR(32), + &sensor_dev_attr_module_present_33.dev_attr.attr, + &sensor_dev_attr_module_present_34.dev_attr.attr, + /* &sensor_dev_attr_module_reset_all.dev_attr.attr,*/ + &sensor_dev_attr_module_tx_disable_33.dev_attr.attr, + &sensor_dev_attr_module_tx_disable_34.dev_attr.attr, + &sensor_dev_attr_module_tx_fault_33.dev_attr.attr, + &sensor_dev_attr_module_tx_fault_34.dev_attr.attr, + &sensor_dev_attr_module_rx_los_33.dev_attr.attr, + &sensor_dev_attr_module_rx_los_34.dev_attr.attr, + &sensor_dev_attr_cpld1_version.dev_attr.attr, + &sensor_dev_attr_cpld2_version.dev_attr.attr, + &sensor_dev_attr_cpld3_version.dev_attr.attr, + &sensor_dev_attr_cpld1_reg.dev_attr.attr, + &sensor_dev_attr_cpld2_reg.dev_attr.attr, + &sensor_dev_attr_cpld3_reg.dev_attr.attr, + &sensor_dev_attr_platform_id.dev_attr.attr, + &sensor_dev_attr_mac_min_temp.dev_attr.attr, + &sensor_dev_attr_mac_max_temp.dev_attr.attr, + NULL +}; + +static const struct attribute_group fpga_port_stat_group = { + .attrs = fpga_transceiver_attributes, +}; + +struct attribute_mapping { + u16 attr_base; + u16 reg; + u8 revert; +}; + +// Define an array of attribute mappings +static struct attribute_mapping attribute_mappings[] = { + [MODULE_PRESENT_1 ... MODULE_PRESENT_8] = {MODULE_PRESENT_1, XCVR_P7_P0_PRESENT_REG, 1}, + [MODULE_PRESENT_9 ... MODULE_PRESENT_16] = {MODULE_PRESENT_9, XCVR_P15_P8_PRESENT_REG, 1}, + [MODULE_PRESENT_17 ... MODULE_PRESENT_24] = {MODULE_PRESENT_17, XCVR_P23_P16_PRESENT_REG, 1}, + [MODULE_PRESENT_25 ... MODULE_PRESENT_32] = {MODULE_PRESENT_25, XCVR_P31_P24_PRESENT_REG, 1}, + [MODULE_PRESENT_33 ... MODULE_PRESENT_34] = {MODULE_PRESENT_33, SFP_PRESENT_REG, 1}, + + [MODULE_LPMODE_1 ... MODULE_LPMODE_8] = {MODULE_LPMODE_1, XCVR_P7_P0_LPMODE_REG, 1}, + [MODULE_LPMODE_9 ... MODULE_LPMODE_16] = {MODULE_LPMODE_9, XCVR_P15_P8_LPMODE_REG, 1}, + [MODULE_LPMODE_17 ... MODULE_LPMODE_24] = {MODULE_LPMODE_17, XCVR_P23_P16_LPMODE_REG, 1}, + [MODULE_LPMODE_25 ... MODULE_LPMODE_32] = {MODULE_LPMODE_25, XCVR_P31_P24_LPMODE_REG, 1}, + + [MODULE_RESET_1 ... MODULE_RESET_8] = {MODULE_RESET_1, XCVR_P7_P0_RESET_REG, 1}, + [MODULE_RESET_9 ... MODULE_RESET_16] = {MODULE_RESET_9, XCVR_P15_P8_RESET_REG, 1}, + [MODULE_RESET_17 ... MODULE_RESET_24] = {MODULE_RESET_17, XCVR_P23_P16_RESET_REG, 1}, + [MODULE_RESET_25 ... MODULE_RESET_32] = {MODULE_RESET_25, XCVR_P31_P24_RESET_REG, 1}, + + [MODULE_TX_DISABLE_33 ... MODULE_TX_DISABLE_34] ={MODULE_TX_DISABLE_33, SFP_TXDIS_REG, 0}, + [MODULE_TX_FAULT_33 ... MODULE_TX_FAULT_34] = {MODULE_TX_FAULT_33, SFP_TXFAULT_REG, 0}, + [MODULE_RX_LOS_33 ... MODULE_RX_LOS_34] = {MODULE_RX_LOS_33, SFP_RXLOSS_REG, 0}, +}; + +static inline unsigned int fpga_read(void __iomem *addr, u32 spi_mask) +{ + wait_spi(spi_mask, usecs_to_jiffies(20)); + return ioread8(addr); +} + +static inline void fpga_write(void __iomem *addr, u8 val, u32 spi_mask) +{ + wait_spi(spi_mask, usecs_to_jiffies(20)); + iowrite8(val, addr); +} + +static ssize_t reg_read(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as9817_32_fpga_data *fpga_ctl = dev_get_drvdata(dev); + void __iomem *addr; + ssize_t ret = -EINVAL; + u8 reg_val; + u32 spi_mask; + + switch(attr->index) + { + case CPLD1_REG: + addr = fpga_ctl->pci_fpga_dev.data_base_addr1 + + CPLD1_PCIE_START_OFFSET + + fpga_ctl->cpld_reg[attr->index - CPLD1_REG]; + spi_mask = SPI_BUSY_MASK_CPLD1; + break; + case CPLD2_REG: + addr = fpga_ctl->pci_fpga_dev.data_base_addr2 + + CPLD2_PCIE_START_OFFSET + + fpga_ctl->cpld_reg[attr->index - CPLD1_REG]; + spi_mask = SPI_BUSY_MASK_CPLD2; + break; + case CPLD3_REG: + addr = fpga_ctl->pci_fpga_dev.data_base_addr2 + + CPLD3_PCIE_START_OFFSET + + fpga_ctl->cpld_reg[attr->index - CPLD1_REG]; + spi_mask = SPI_BUSY_MASK_CPLD2; + break; + default: + ret = -EINVAL; + goto exit; + } + + LOCK(&cpld_access_lock); + reg_val = fpga_read(addr, spi_mask); + UNLOCK(&cpld_access_lock); + ret = sprintf(buf, "0x%02x\n", reg_val); + +exit: + return ret; +} + +static ssize_t reg_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as9817_32_fpga_data *fpga_ctl = dev_get_drvdata(dev); + void __iomem *base; + int args; + char *opt, tmp[32] = {0}; + char *tmp_p; + size_t copy_size; + u8 input[2] = {0}; + u32 spi_mask; + + switch(attr->index) + { + case CPLD1_REG: + base = fpga_ctl->pci_fpga_dev.data_base_addr1 + + CPLD1_PCIE_START_OFFSET; + spi_mask = SPI_BUSY_MASK_CPLD1; + break; + case CPLD2_REG: + base = fpga_ctl->pci_fpga_dev.data_base_addr2 + + CPLD2_PCIE_START_OFFSET; + spi_mask = SPI_BUSY_MASK_CPLD2; + break; + case CPLD3_REG: + base = fpga_ctl->pci_fpga_dev.data_base_addr2 + + CPLD3_PCIE_START_OFFSET; + spi_mask = SPI_BUSY_MASK_CPLD2; + break; + default: + return -EINVAL; + } + + copy_size = (count < sizeof(tmp)) ? count : sizeof(tmp) - 1; + #ifdef __STDC_LIB_EXT1__ + memcpy_s(tmp, copy_size, buf, copy_size); + #else + memcpy(tmp, buf, copy_size); + #endif + tmp[copy_size] = '\0'; + + args = 0; + tmp_p = tmp; + while (args < 2 && (opt = strsep(&tmp_p, " ")) != NULL) { + if (kstrtou8(opt, 16, &input[args]) == 0) { + args++; + } + } + + switch(args) + { + case 2: + /* Write value to register */ + LOCK(&cpld_access_lock); + fpga_write(base + input[0], input[1], spi_mask); + UNLOCK(&cpld_access_lock); + break; + case 1: + /* Read value from register */ + fpga_ctl->cpld_reg[attr->index - CPLD1_REG] = input[0]; + break; + default: + return -EINVAL; + } + + return count; +} + +static ssize_t status_read(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as9817_32_fpga_data *fpga_ctl = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + u16 reg, tmp; + u8 major, minor, reg_val = 0; + u8 bits_shift; + u8 mac_temp_val[4]; + + switch(attr->index) + { + case CPLD1_VERSION: + LOCK(&cpld_access_lock); + reg = CPLD1_MAJOR_VER_REG; + major = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr1 + reg, + SPI_BUSY_MASK_CPLD1); + reg = CPLD1_MINOR_VER_REG; + minor = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr1 + reg, + SPI_BUSY_MASK_CPLD1); + UNLOCK(&cpld_access_lock); + + ret = sprintf(buf, "%d.%d\n", major, minor); + break; + case CPLD2_VERSION: + LOCK(&cpld_access_lock); + reg = CPLD2_MAJOR_VER_REG; + major = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr2 + reg, + SPI_BUSY_MASK_CPLD2); + reg = CPLD2_MINOR_VER_REG; + minor = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr2 + reg, + SPI_BUSY_MASK_CPLD2); + UNLOCK(&cpld_access_lock); + + ret = sprintf(buf, "%d.%d\n", major, minor); + break; + case CPLD3_VERSION: + LOCK(&cpld_access_lock); + reg = CPLD3_VERSION_REG; + major = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr2 + reg, + SPI_BUSY_MASK_CPLD2); + UNLOCK(&cpld_access_lock); + + ret = sprintf(buf, "%d\n", major); + break; + case MODULE_PRESENT_1 ... MODULE_RX_LOS_34: + reg = attribute_mappings[attr->index].reg; + LOCK(&cpld_access_lock); + if ((reg & 0xF000) == CPLD1_PCIE_START_OFFSET) { + reg_val = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr1 + reg, + SPI_BUSY_MASK_CPLD1); + } else if ((reg & 0xF000) == CPLD2_PCIE_START_OFFSET) { + reg_val = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr2 + reg, + SPI_BUSY_MASK_CPLD2); + } + UNLOCK(&cpld_access_lock); + + bits_shift = attr->index - attribute_mappings[attr->index].attr_base; + reg_val = (reg_val >> bits_shift) & 0x01; + if (attribute_mappings[attr->index].revert) { + reg_val = !reg_val; + } + + ret = sprintf(buf, "%u\n", reg_val); + break; + case PLATFORM_ID: + ret = sprintf(buf, "%d\n", fpga_ctl->platform_id); + break; + case MAC_MIN_TEMP: + tmp = ioread16(fpga_ctl->pci_fpga_dev.data_base_addr0 + FPGA_MAC_MIN_TEMP1_REG); + mac_temp_val[0] = tmp & 0xFF; + mac_temp_val[1] = (tmp >> 8) & 0xFF; + tmp = ioread16(fpga_ctl->pci_fpga_dev.data_base_addr0 + FPGA_MAC_MIN_TEMP3_REG); + mac_temp_val[2] = tmp & 0xFF; + mac_temp_val[3] = (tmp >> 8) & 0xFF; + ret = sprintf(buf, "%02x %02x %02x %02x\n", + mac_temp_val[0], mac_temp_val[1], + mac_temp_val[2], mac_temp_val[3]); + break; + case MAC_MAX_TEMP: + tmp = ioread16(fpga_ctl->pci_fpga_dev.data_base_addr0 + FPGA_MAC_MAX_TEMP1_REG); + mac_temp_val[0] = tmp & 0xFF; + mac_temp_val[1] = (tmp >> 8) & 0xFF; + tmp = ioread16(fpga_ctl->pci_fpga_dev.data_base_addr0 + FPGA_MAC_MAX_TEMP3_REG); + mac_temp_val[2] = tmp & 0xFF; + mac_temp_val[3] = (tmp >> 8) & 0xFF; + ret = sprintf(buf, "%02x %02x %02x %02x\n", + mac_temp_val[0], mac_temp_val[1], + mac_temp_val[2], mac_temp_val[3]); + break; + default: + break; + } + + return ret; +} + +static ssize_t status_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as9817_32_fpga_data *fpga_ctl = dev_get_drvdata(dev); + void __iomem *addr = 0; + int status; + u16 reg; + u8 input; + u8 reg_val = 0, bit_mask, should_set_bit; + u32 spi_mask = 0; + + status = kstrtou8(buf, 10, &input); + if (status) { + return status; + } + + reg = attribute_mappings[attr->index].reg; + if ((reg & 0xF000) == CPLD1_PCIE_START_OFFSET) { + spi_mask = SPI_BUSY_MASK_CPLD1; + addr = fpga_ctl->pci_fpga_dev.data_base_addr1; + } else if ((reg & 0xF000) == CPLD2_PCIE_START_OFFSET) { + spi_mask = SPI_BUSY_MASK_CPLD2; + addr = fpga_ctl->pci_fpga_dev.data_base_addr2; + } + bit_mask = 0x01 << (attr->index - attribute_mappings[attr->index].attr_base); + should_set_bit = attribute_mappings[attr->index].revert ? !input : input; + + LOCK(&cpld_access_lock); + reg_val = fpga_read(addr + reg, spi_mask); + if (should_set_bit) { + reg_val |= bit_mask; + } else { + reg_val &= ~bit_mask; + } + fpga_write(addr + reg, reg_val, spi_mask); + UNLOCK(&cpld_access_lock); + + return count; +} + +struct _port_data { + u16 offset; + u16 mask; /* SPI Busy mask : 0x01 --> CPLD1, 0x02 --> CPLD2 */ +}; +/* ============PCIe Bar Offset to I2C Master Mapping============== */ +static const struct _port_data port[PORT_NUM]= { + {0x2100, SPI_BUSY_MASK_CPLD1},/* 0x2100 - 0x2110 CPLD1 I2C Master Port1 */ + {0x2120, SPI_BUSY_MASK_CPLD1},/* 0x2120 - 0x2130 CPLD1 I2C Master Port2 */ + {0x2140, SPI_BUSY_MASK_CPLD1},/* 0x2140 - 0x2150 CPLD1 I2C Master Port3 */ + {0x2160, SPI_BUSY_MASK_CPLD1},/* 0x2160 - 0x2170 CPLD1 I2C Master Port4 */ + {0x2180, SPI_BUSY_MASK_CPLD1},/* 0x2180 - 0x2190 CPLD1 I2C Master Port5 */ + {0x21A0, SPI_BUSY_MASK_CPLD1},/* 0x21A0 - 0x21B0 CPLD1 I2C Master Port6 */ + {0x21C0, SPI_BUSY_MASK_CPLD1},/* 0x21C0 - 0x21D0 CPLD1 I2C Master Port7 */ + {0x21E0, SPI_BUSY_MASK_CPLD1},/* 0x21E0 - 0x21F0 CPLD1 I2C Master Port8 */ + {0x2200, SPI_BUSY_MASK_CPLD1},/* 0x2200 - 0x2210 CPLD1 I2C Master Port9 */ + {0x2220, SPI_BUSY_MASK_CPLD1},/* 0x2220 - 0x2230 CPLD1 I2C Master Port10 */ + {0x2240, SPI_BUSY_MASK_CPLD1},/* 0x2240 - 0x2250 CPLD1 I2C Master Port11 */ + {0x2260, SPI_BUSY_MASK_CPLD1},/* 0x2260 - 0x2270 CPLD1 I2C Master Port12 */ + {0x2280, SPI_BUSY_MASK_CPLD1},/* 0x2280 - 0x2290 CPLD1 I2C Master Port13 */ + {0x22A0, SPI_BUSY_MASK_CPLD1},/* 0x22A0 - 0x22B0 CPLD1 I2C Master Port14 */ + {0x22C0, SPI_BUSY_MASK_CPLD1},/* 0x22C0 - 0x22D0 CPLD1 I2C Master Port15 */ + {0x22E0, SPI_BUSY_MASK_CPLD1},/* 0x22E0 - 0x22F0 CPLD1 I2C Master Port16 */ + {0x3100, SPI_BUSY_MASK_CPLD2},/* 0x3100 - 0x3110 CPLD2 I2C Master Port17 */ + {0x3120, SPI_BUSY_MASK_CPLD2},/* 0x3120 - 0x3130 CPLD2 I2C Master Port18 */ + {0x3140, SPI_BUSY_MASK_CPLD2},/* 0x3140 - 0x3150 CPLD2 I2C Master Port19 */ + {0x3160, SPI_BUSY_MASK_CPLD2},/* 0x3160 - 0x3170 CPLD2 I2C Master Port20 */ + {0x3180, SPI_BUSY_MASK_CPLD2},/* 0x3180 - 0x3190 CPLD2 I2C Master Port21 */ + {0x31A0, SPI_BUSY_MASK_CPLD2},/* 0x31A0 - 0x31B0 CPLD2 I2C Master Port22 */ + {0x31C0, SPI_BUSY_MASK_CPLD2},/* 0x31C0 - 0x31D0 CPLD2 I2C Master Port23 */ + {0x31E0, SPI_BUSY_MASK_CPLD2},/* 0x31E0 - 0x31F0 CPLD2 I2C Master Port24 */ + {0x3200, SPI_BUSY_MASK_CPLD2},/* 0x3200 - 0x3210 CPLD2 I2C Master Port25 */ + {0x3220, SPI_BUSY_MASK_CPLD2},/* 0x3220 - 0x3230 CPLD2 I2C Master Port26 */ + {0x3240, SPI_BUSY_MASK_CPLD2},/* 0x3240 - 0x3250 CPLD2 I2C Master Port27 */ + {0x3260, SPI_BUSY_MASK_CPLD2},/* 0x3260 - 0x3270 CPLD2 I2C Master Port28 */ + {0x3280, SPI_BUSY_MASK_CPLD2},/* 0x3280 - 0x3290 CPLD2 I2C Master Port29 */ + {0x32A0, SPI_BUSY_MASK_CPLD2},/* 0x32A0 - 0x32B0 CPLD2 I2C Master Port30 */ + {0x32C0, SPI_BUSY_MASK_CPLD2},/* 0x32C0 - 0x34D0 CPLD2 I2C Master Port31 */ + {0x32E0, SPI_BUSY_MASK_CPLD2},/* 0x32E0 - 0x3490 CPLD2 I2C Master Port32 */ + {0x3500, SPI_BUSY_MASK_CPLD2},/* 0x3500 - 0x3510 CPLD2 I2C Master SFP-28 Port33 */ + {0x3520, SPI_BUSY_MASK_CPLD2},/* 0x3520 - 0x3530 CPLD2 I2C Master SFP-28 Port24 */ +}; + +static struct ocores_i2c_platform_data as9817_32_platform_data = { + .reg_io_width = 1, + .reg_shift = 2, + /* + * PRER_L and PRER_H are calculated based on clock_khz and bus_khz + * in i2c-ocores.c:ocores_init. + */ +#if 1 + /* SCL 400KHZ in FPGA spec. => PRER_L = 0x0B, PRER_H = 0x00 */ + .clock_khz = 24000, + .bus_khz = 400, +#else + /* SCL 100KHZ in FPGA spec. => PRER_L = 0x2F, PRER_H = 0x00 */ + .clock_khz = 24000, + .bus_khz = 100, +#endif +}; + +extern struct bus_type platform_bus_type; + +struct platform_device *ocore_i2c_device_add(unsigned int id, unsigned long bar_base, + unsigned int offset) +{ + struct resource res = DEFINE_RES_MEM(bar_base + offset, 0x20); + struct platform_device *pdev; + int err; + + if (!driver_find(OCORES_I2C_DRVNAME, &platform_bus_type)) { + pcie_err("Platform driver %s not found, delaying device registration\n", OCORES_I2C_DRVNAME); + err = -ENODEV; + goto exit; + } + + pdev = platform_device_alloc(OCORES_I2C_DRVNAME, id); + if (!pdev) { + err = -ENOMEM; + pcie_err("Port%u device allocation failed (%d)\n", (id & 0xFF), err); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + pcie_err("Port%u device resource addition failed (%d)\n", (id & 0xFF), err); + goto exit_device_put; + } + + err = platform_device_add_data(pdev, &as9817_32_platform_data, + sizeof(struct ocores_i2c_platform_data)); + if (err) { + pcie_err("Port%u platform data allocation failed (%d)\n", (id & 0xFF), err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + pcie_err("Port%u device addition failed (%d)\n", (id & 0xFF), err); + goto exit_device_put; + } + + return pdev; + +exit_device_put: + platform_device_put(pdev); +exit: + return NULL; +} + +static int as9817_32_pcie_fpga_stat_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct as9817_32_fpga_data *fpga_ctl; + struct pci_dev *pcidev; + struct resource *ret; + int i; + int status = 0, err = 0; + unsigned long bar_base = 0; + unsigned int val; + + fpga_ctl = devm_kzalloc(dev, sizeof(struct as9817_32_fpga_data), GFP_KERNEL); + if (!fpga_ctl) { + return -ENOMEM; + } + platform_set_drvdata(pdev, fpga_ctl); + + pcidev = pci_get_device(FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID, NULL); + if (!pcidev) { + dev_err(dev, "Cannot found PCI device(%x:%x)\n", + FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID); + return -ENODEV; + } + fpga_ctl->pci_fpga_dev.pci_dev = pcidev; + + err = pci_enable_device(pcidev); + if (err != 0) { + dev_err(dev, "Cannot enable PCI device(%x:%x)\n", + FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID); + status = -ENODEV; + goto exit_pci_disable; + } + /* enable PCI bus-mastering */ + pci_set_master(pcidev); + + /* + * Detect platform for changing the setting behavior of LP mode. + */ + fpga_ctl->pci_fpga_dev.data_base_addr0 = pci_iomap(pcidev, BAR0_NUM, 0); + if (fpga_ctl->pci_fpga_dev.data_base_addr0 == NULL) { + dev_err(dev, "Failed to map BAR0\n"); + status = -EIO; + goto exit_pci_disable; + } + + val = ioread8(fpga_ctl->pci_fpga_dev.data_base_addr0 + FPGA_BOARD_INFO_REG); + switch (val & 0x0C) + { + case 0x00: /* OSFP */ + case 0x08: /* OSFP_ROT */ + fpga_ctl->platform_id = 0; + dev_info(dev, "Platform: AS9817-32O(0x%02x)\n", val); + break; + case 0x04: /* QDD */ + case 0x0C: /* QDD_ROT */ + for (i = MODULE_LPMODE_1; i <= MODULE_LPMODE_32; i++) { + attribute_mappings[i].revert = 0; + } + fpga_ctl->platform_id = 1; + dev_info(dev, "Platform: AS9817-32D(0x%02x)\n", val); + break; + default: + dev_warn(dev, "Unknown platform detected\n"); + break; + } + + /* + * The register address of SPI Busy is 0x33. + * It can not only read one byte. It needs to read four bytes from 0x30. + * The value is obtained by '(ioread32(spi_busy_reg) >> 24) & 0xFF'. + */ + spi_busy_reg = fpga_ctl->pci_fpga_dev.data_base_addr0 + 0x30; + + + + /* + * Cannot use 'pci_request_regions(pcidev, DRVNAME)' + * to request all Region 1, Region 2 because another + * address will be allocated by the i2c-ocores.ko. + */ + fpga_ctl->pci_fpga_dev.data_base_addr1 = pci_iomap(pcidev, BAR1_NUM, 0); + if (fpga_ctl->pci_fpga_dev.data_base_addr1 == NULL) { + dev_err(dev, "Failed to map BAR1\n"); + status = -EIO; + goto exit_pci_iounmap0; + } + fpga_ctl->pci_fpga_dev.data_region1 = pci_resource_start(pcidev, BAR1_NUM) + CPLD1_PCIE_START_OFFSET; + ret = request_mem_region(fpga_ctl->pci_fpga_dev.data_region1, REGION_LEN, DRVNAME"_cpld1"); + if (ret == NULL) { + dev_err(dev, "[%s] cannot request region\n", DRVNAME"_cpld1"); + status = -EIO; + goto exit_pci_iounmap1; + } + dev_info(dev, "(BAR%d resource: Start=0x%lx, Length=0x%x)", BAR1_NUM, + (unsigned long)fpga_ctl->pci_fpga_dev.data_region1, REGION_LEN); + + fpga_ctl->pci_fpga_dev.data_base_addr2 = pci_iomap(pcidev, BAR2_NUM, 0); + if (fpga_ctl->pci_fpga_dev.data_base_addr2 == NULL) { + dev_err(dev, "Failed to map BAR2\n"); + status = -EIO; + goto exit_pci_release1; + } + fpga_ctl->pci_fpga_dev.data_region2 = pci_resource_start(pcidev, BAR2_NUM) + CPLD2_PCIE_START_OFFSET; + ret = request_mem_region(fpga_ctl->pci_fpga_dev.data_region2, REGION_LEN, DRVNAME"_cpld2"); + if (ret == NULL) { + dev_err(dev, "[%s] cannot request region\n", DRVNAME"_cpld2"); + status = -EIO; + goto exit_pci_iounmap2; + } + dev_info(dev, "(BAR%d resource: Start=0x%lx, Length=0x%x)", BAR2_NUM, + (unsigned long)fpga_ctl->pci_fpga_dev.data_region2, REGION_LEN); + + /* Create I2C ocore devices first, then create the FPGA sysfs. + * To prevent the application from accessing an ocore device + * that has not been fully created due to the port status + * being present. + */ + + /* + * Create ocore_i2c device for OSFP EEPROM + */ + for (i = 0; i < PORT_NUM; i++) { + switch (i) + { + case 0 ... 15: + bar_base = pci_resource_start(pcidev, BAR1_NUM); + break; + case 16 ... 33: + bar_base = pci_resource_start(pcidev, BAR2_NUM); + break; + default: + break; + } + fpga_ctl->pci_fpga_dev.fpga_i2c[i] = + ocore_i2c_device_add((i | (port[i].mask << 8)), bar_base, port[i].offset); + if (IS_ERR(fpga_ctl->pci_fpga_dev.fpga_i2c[i])) { + status = PTR_ERR(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); + dev_err(dev, "rc:%d, unload Port%u[0x%ux] device\n", + status, i, port[i].offset); + goto exit_ocores_device; + } + } + + status = sysfs_create_group(&pdev->dev.kobj, &fpga_port_stat_group); + if (status) { + goto exit_ocores_device; + } + + return 0; + +exit_ocores_device: + while (i > 0) { + i--; + platform_device_unregister(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); + } + release_mem_region(fpga_ctl->pci_fpga_dev.data_region2, REGION_LEN); +exit_pci_iounmap2: + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr2); +exit_pci_release1: + release_mem_region(fpga_ctl->pci_fpga_dev.data_region1, REGION_LEN); +exit_pci_iounmap1: + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr1); +exit_pci_iounmap0: + spi_busy_reg = NULL; + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr0); +exit_pci_disable: + pci_disable_device(fpga_ctl->pci_fpga_dev.pci_dev); + + return status; +} + +static int as9817_32_pcie_fpga_stat_remove(struct platform_device *pdev) +{ + struct as9817_32_fpga_data *fpga_ctl = platform_get_drvdata(pdev); + + if (pci_is_enabled(fpga_ctl->pci_fpga_dev.pci_dev)) { + int i; + + sysfs_remove_group(&pdev->dev.kobj, &fpga_port_stat_group); + /* Unregister ocore_i2c device */ + for (i = 0; i < PORT_NUM; i++) { + platform_device_unregister(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); + } + spi_busy_reg = NULL; + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr0); + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr1); + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr2); + release_mem_region(fpga_ctl->pci_fpga_dev.data_region1, REGION_LEN); + release_mem_region(fpga_ctl->pci_fpga_dev.data_region2, REGION_LEN); + pci_disable_device(fpga_ctl->pci_fpga_dev.pci_dev); + } + + return 0; +} + +static struct platform_driver pcie_fpga_port_stat_driver = { + .probe = as9817_32_pcie_fpga_stat_probe, + .remove = as9817_32_pcie_fpga_stat_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, +}; + +static int __init as9817_32_pcie_fpga_init(void) +{ + int status = 0; + + /* + * Create FPGA platform driver and device + */ + status = platform_driver_register(&pcie_fpga_port_stat_driver); + if (status < 0) { + return status; + } + + pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(pdev)) { + status = PTR_ERR(pdev); + goto exit_pci; + } + + return status; + +exit_pci: + platform_driver_unregister(&pcie_fpga_port_stat_driver); + + return status; +} + +static void __exit as9817_32_pcie_fpga_exit(void) +{ + platform_device_unregister(pdev); + platform_driver_unregister(&pcie_fpga_port_stat_driver); +} + + +module_init(as9817_32_pcie_fpga_init); +module_exit(as9817_32_pcie_fpga_exit); + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("AS9817-32O/AS9817-32D FPGA via PCIE"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-i2c-ocores.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-i2c-ocores.c new file mode 100644 index 0000000000..b8a8420ab9 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-i2c-ocores.c @@ -0,0 +1,960 @@ + +// SPDX-License-Identifier: GPL-2.0 +/* + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (https://opencores.org/project/i2c/overview) + * + * Peter Korsgaard + * + * Support for the GRLIB port of the controller by + * Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + void __iomem *base; + int iobase; + u32 reg_shift; + u32 reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + spinlock_t process_lock; + struct clk *clk; + int ip_clock_khz; + int bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); +}; + +/* registers */ +#define OCI2C_PRELOW 0 +#define OCI2C_PREHIGH 1 +#define OCI2C_CONTROL 2 +#define OCI2C_DATA 3 +#define OCI2C_CMD 4 /* write only */ +#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ + +#define OCI2C_CTRL_IEN 0x40 +#define OCI2C_CTRL_EN 0x80 + +#define OCI2C_CMD_START 0x91 +#define OCI2C_CMD_STOP 0x41 +#define OCI2C_CMD_READ 0x21 +#define OCI2C_CMD_WRITE 0x11 +#define OCI2C_CMD_READ_ACK 0x21 +#define OCI2C_CMD_READ_NACK 0x29 +#define OCI2C_CMD_IACK 0x01 + +#define OCI2C_STAT_IF 0x01 +#define OCI2C_STAT_TIP 0x02 +#define OCI2C_STAT_ARBLOST 0x20 +#define OCI2C_STAT_BUSY 0x40 +#define OCI2C_STAT_NACK 0x80 + +#define STATE_DONE 0 +#define STATE_START 1 +#define STATE_WRITE 2 +#define STATE_READ 3 +#define STATE_ERROR 4 + +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 +#define TYPE_SIFIVE_REV0 2 + +#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */ + +static unsigned int timeout = 1; +module_param(timeout , uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(timeout, "Tiemout for ocores_poll_wait, in unit of milliseconds."); + +static unsigned int debug = 0; +module_param(debug , uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug, "Enable or disable debug message. 1 -> enable, 0 -> disable"); + +spinlock_t cpld_access_lock; +EXPORT_SYMBOL(cpld_access_lock); + +#define LOCK(lock) \ +do { \ + spin_lock(lock); \ +} while (0) + +#define UNLOCK(lock) \ +do { \ + spin_unlock(lock); \ +} while (0) + +void __iomem *spi_busy_reg=NULL; +EXPORT_SYMBOL(spi_busy_reg); +int wait_spi(u32 mask, unsigned long timeout) { + u32 data; + u32 ri = 0; + unsigned long j; + + /* pr_info("CPLD %u, Will time-out at jiffie %lu\n", cpld_id,timeout); */ + if (!spi_busy_reg) { + return -EFAULT; + } + + j = jiffies + timeout; + while(1) { + data = ioread32(spi_busy_reg); + /* pr_info("@ %u, Read spi_busy_reg: 0x%08x 0x%08x\n", ri, data, mask); */ + if (!((( data >> 24) & 0xFF) & mask)) { + break; + } + + if (time_after(jiffies, j)) { + if (debug) { + pr_warn("@ %u, wait_spi TIMEOUT \n", ri); + } + return -ETIMEDOUT; + } + + ri++; + } + + return 0; +} +EXPORT_SYMBOL(wait_spi); + +static int wait_cpld(struct ocores_i2c *i2c, unsigned long timeout) { + struct platform_device *pdev; + struct device *dev; + + if (!i2c->adap.dev.parent) { + return -EFAULT; + } + + /* Get SPI Busy mask from pdev->id */ + dev = i2c->adap.dev.parent; + pdev = container_of(dev, struct platform_device, dev); + wait_spi((pdev->id & 0xFF00) >> 8, timeout); + + return 0; +} + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + outb(value, i2c->iobase + reg); +} + +static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) +{ + return inb(i2c->iobase + reg); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + wait_cpld(i2c, usecs_to_jiffies(20)); + i2c->setreg(i2c, reg, value); +} + +static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + wait_cpld(i2c, usecs_to_jiffies(20)); + return i2c->getreg(i2c, reg); +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + unsigned long flags; + struct device *dev = i2c->adap.dev.parent; + + /* + * If we spin here is because we are in timeout, so we are going + * to be in STATE_ERROR. See ocores_process_timeout() + */ + spin_lock_irqsave(&i2c->process_lock, flags); + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + if (debug) { + dev_warn(dev, "I2C %s arbitration lost", i2c->adap.name); + } + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + i2c->state = STATE_ERROR; + if (debug) { + dev_warn(dev, "I2C %s, no ACK from slave 0x%02x", + i2c->adap.name, msg->addr); + } + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = i2c_8bit_addr_from_msg(msg); + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + goto out; + } + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } + +out: + spin_unlock_irqrestore(&i2c->process_lock, flags); + +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat = oc_getreg(i2c, OCI2C_STATUS); + + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) { + if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY)) + return IRQ_NONE; + } else if (!(stat & OCI2C_STAT_IF)) { + return IRQ_NONE; + } + ocores_process(i2c, stat); + + return IRQ_HANDLED; +} + +/** + * Process timeout event + * @i2c: ocores I2C device instance + */ +static void ocores_process_timeout(struct ocores_i2c *i2c) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c->process_lock, flags); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +/** + * Wait until something change in a given register + * @i2c: ocores I2C device instance + * @reg: register to query + * @mask: bitmask to apply on register value + * @val: expected result + * @timeout: timeout in jiffies + * + * Timeout is necessary to avoid to stay here forever when the chip + * does not answer correctly. + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_wait(struct ocores_i2c *i2c, + int reg, u8 mask, u8 val, + const unsigned long timeout) +{ + unsigned long j; + + j = jiffies + timeout; + while (1) { + u8 status = oc_getreg(i2c, reg); + + if ((status & mask) == val) + break; + + if (time_after(jiffies, j)) + return -ETIMEDOUT; + } + return 0; +} + +/** + * Wait until is possible to process some data + * @i2c: ocores I2C device instance + * + * Used when the device is in polling mode (interrupts disabled). + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_poll_wait(struct ocores_i2c *i2c) +{ + u8 mask; + int err; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* transfer is over */ + mask = OCI2C_STAT_BUSY; + } else { + /* on going transfer */ + mask = OCI2C_STAT_TIP; + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + */ + udelay((8 * 1000) / i2c->bus_clock_khz); + } + + /* + * once we are here we expect to get the expected result immediately + * so if after 1ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(timeout)); + if (err) { + if (debug) { + dev_warn(i2c->adap.dev.parent, + "%s: STATUS timeout, bit 0x%x did not clear in %ums(msecs_to_jiffies(%u)=%lu)\n", + __func__, mask, timeout, timeout, msecs_to_jiffies(timeout)); + } + } + return err; +} + +/** + * It handles an IRQ-less transfer + * @i2c: ocores I2C device instance + * + * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same + * (only that IRQ are not produced). This means that we can re-use entirely + * ocores_isr(), we just add our polling code around it. + * + * It can run in atomic context + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_process_polling(struct ocores_i2c *i2c) +{ + irqreturn_t ret; + int err; + + while (1) { + err = ocores_poll_wait(i2c); + if (err) { + break; /* timeout */ + } + + ret = ocores_isr(-1, i2c); + if (ret == IRQ_NONE) + break; /* all messages have been transferred */ + else { + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) + if (i2c->state == STATE_DONE) + break; + } + } + + return err; +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret = 0; + u8 ctrl; + + LOCK(&cpld_access_lock); + + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + if (polling) + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); + else + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + if (polling) { + ret = ocores_process_polling(i2c); + } else { + if (wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ) == 0) + ret = -ETIMEDOUT; + } + if (ret) { + ocores_process_timeout(i2c); + UNLOCK(&cpld_access_lock); + return ret; + } + + UNLOCK(&cpld_access_lock); + return (i2c->state == STATE_DONE) ? num : -EIO; +} + +static int ocores_xfer_polling(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); +} + +static int ocores_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, false); +} + +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) +{ + struct device *org; + int prescale; + int diff; + u8 ctrl; + + /* Temporary assignment for checking SPI Busy status. */ + org = i2c->adap.dev.parent; + i2c->adap.dev.parent = dev; + + LOCK(&cpld_access_lock); + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + UNLOCK(&cpld_access_lock); + + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + i2c->adap.dev.parent = org; + dev_err(dev, + "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + dev_info(dev, "OCI2C_PRELOW=0x%02x OCI2C_PREHIGH=0x%02x\n", + prescale & 0xff, prescale >> 8); + LOCK(&cpld_access_lock); + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + UNLOCK(&cpld_access_lock); + + i2c->adap.dev.parent = org; + + return 0; +} + + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + //.master_xfer_atomic = ocores_xfer_polling, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "i2c-ocores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + { + .compatible = "sifive,fu540-c000-i2c", + .data = (void *)TYPE_SIFIVE_REV0, + }, + { + .compatible = "sifive,i2c0", + .data = (void *)TYPE_SIFIVE_REV0, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +#ifdef CONFIG_OF +/* + * Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers have their offsets decreased accordingly. + */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + u32 val; + u32 clock_frequency; + bool clock_frequency_present; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } + } + + clock_frequency_present = !of_property_read_u32(np, "clock-frequency", + &clock_frequency); + i2c->bus_clock_khz = 100; + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(i2c->clk)) { + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + + if (i2c->ip_clock_khz == 0) { + if (of_property_read_u32(np, "opencores,ip-clock-frequency", + &val)) { + if (!clock_frequency_present) { + dev_err(&pdev->dev, + "Missing required parameter 'opencores,ip-clock-frequency'\n"); + clk_disable_unprepare(i2c->clk); + return -ENODEV; + } + i2c->ip_clock_khz = clock_frequency / 1000; + dev_warn(&pdev->dev, + "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); + } else { + i2c->ip_clock_khz = val / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + } + + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + + return 0; +} +#else +#define ocores_i2c_of_probe(pdev, i2c) -ENODEV +#endif + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + struct ocores_i2c_platform_data *pdata; + const struct of_device_id *match; + struct resource *res; + int irq; + int ret; + int i; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + spin_lock_init(&i2c->process_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + i2c->base = devm_ioremap_resource(&pdev->dev, res); + dev_info(&pdev->dev, "Resouce start:0x%llx, end:0x%llx", res->start, res->end); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + } else { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EINVAL; + i2c->iobase = res->start; + if (!devm_request_region(&pdev->dev, res->start, + resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Can't get I/O resource.\n"); + return -EBUSY; + } + i2c->setreg = oc_setreg_io_8; + i2c->getreg = oc_getreg_io_8; + } + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; + i2c->ip_clock_khz = pdata->clock_khz; + dev_info(&pdev->dev, "Write %d KHz, ioWidth:%d, shift:%d", i2c->ip_clock_khz, pdata->reg_io_width ,pdata->reg_shift); + if (pdata->bus_khz) + i2c->bus_clock_khz = pdata->bus_khz; + else + i2c->bus_clock_khz = 100; + } else { + ret = ocores_i2c_of_probe(pdev, i2c); + if (ret) + return ret; + } + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->setreg || !i2c->getreg) { + bool be = pdata ? pdata->big_endian : + of_device_is_big_endian(pdev->dev.of_node); + + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case 4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto err_clk; + } + } + + init_waitqueue_head(&i2c->wait); + + irq = platform_get_irq_optional(pdev, 0); + //irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) { + ocores_algorithm.master_xfer = ocores_xfer_polling; + + /* + * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for + * FU540-C000 SoC in polling mode. + */ + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_SIFIVE_REV0) + i2c->flags |= OCORES_FLAG_BROKEN_IRQ; + } else { + if (irq < 0) + return irq; + } + + if (ocores_algorithm.master_xfer != ocores_xfer_polling) { + ret = devm_request_any_context_irq(&pdev->dev, irq, + ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_clk; + } + } + ret = ocores_init(&pdev->dev, i2c); + if (ret) { + goto err_clk; + } + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) { + goto err_clk; + } + /* add in known devices to the bus */ + if (pdata) { + for (i = 0; i < pdata->num_devices; i++){ + i2c_new_client_device(&i2c->adap, pdata->devices + i); + //i2c_new_device(&i2c->adap, pdata->devices + i); + } + } + + return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int ocores_i2c_remove(struct platform_device *pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + u8 ctrl; + + LOCK(&cpld_access_lock); + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* disable i2c logic */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + UNLOCK(&cpld_access_lock); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ocores_i2c_suspend(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + return 0; +} + +static int ocores_i2c_resume(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + + if (!IS_ERR(i2c->clk)) { + unsigned long rate; + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; + } + return ocores_init(dev, i2c); +} + +static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); +#define OCORES_I2C_PM (&ocores_i2c_pm) +#else +#define OCORES_I2C_PM NULL +#endif + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "ocores-as9817-32", + .of_match_table = ocores_i2c_match, + .pm = OCORES_I2C_PM, + }, +}; + +#if 0 +module_platform_driver(ocores_i2c_driver); +#else +static int __init ocores_i2c_as9817_32_init(void) +{ + int err; + + err = platform_driver_register(&ocores_i2c_driver); + if (err < 0) { + pr_err("Failed to register ocores_i2c_driver"); + return err; + } + + spin_lock_init(&cpld_access_lock); + + return 0; +} +static void __exit ocores_i2c_as9817_32_exit(void) +{ + platform_driver_unregister(&ocores_i2c_driver); +} + +module_init(ocores_i2c_as9817_32_init); +module_exit(ocores_i2c_as9817_32_exit); +#endif + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-as9817-32"); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c new file mode 100644 index 0000000000..a1b924ef0c --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c @@ -0,0 +1,558 @@ +/* + * Copyright (C) Roger Ho + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9817_32_led" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_LED_READ_CMD 0x1A +#define IPMI_LED_WRITE_CMD 0x1B +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_led(struct device *dev, struct device_attribute *attr, + char *buf); +static int as9817_32_led_probe(struct platform_device *pdev); +static int as9817_32_led_remove(struct platform_device *pdev); + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as9817_32_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned char ipmi_resp[6]; /* 0:Loc 1:Diag 2:Gnss 3:Fan 4:Psu1 5:Psu2 */ + struct ipmi_data ipmi; +}; + +struct as9817_32_led_data *data = NULL; + +static struct platform_driver as9817_32_led_driver = { + .probe = as9817_32_led_probe, + .remove = as9817_32_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum ipmi_led_light_mode { + IPMI_LED_MODE_OFF, + IPMI_LED_MODE_RED = 2, + IPMI_LED_MODE_RED_BLINKING = 3, + IPMI_LED_MODE_GREEN = 4, + IPMI_LED_MODE_GREEN_BLINKING = 5, + IPMI_LED_MODE_BLUE = 8, + IPMI_LED_MODE_BLUE_BLINKING = 9, + IPMI_LED_MODE_CYAN = 0xC, + IPMI_LED_MODE_WHITE = 0xE, + IPMI_LED_MODE_AMBER = 0x10, + IPMI_LED_MODE_ORANGE = 0x20, +}; + +enum led_light_mode { + LED_MODE_OFF, + LED_MODE_RED = 10, + LED_MODE_RED_BLINKING = 11, + LED_MODE_ORANGE = 12, + LED_MODE_ORANGE_BLINKING = 13, + LED_MODE_YELLOW = 14, + LED_MODE_YELLOW_BLINKING = 15, + LED_MODE_GREEN = 16, + LED_MODE_GREEN_BLINKING = 17, + LED_MODE_BLUE = 18, + LED_MODE_BLUE_BLINKING = 19, + LED_MODE_PURPLE = 20, + LED_MODE_PURPLE_BLINKING = 21, + LED_MODE_AUTO = 22, + LED_MODE_AUTO_BLINKING = 23, + LED_MODE_WHITE = 24, + LED_MODE_WHITE_BLINKING = 25, + LED_MODE_CYAN = 26, + LED_MODE_CYAN_BLINKING = 27, + LED_MODE_UNKNOWN = 99 +}; + +enum as9817_32_led_sysfs_attrs { + LED_LOC, + LED_DIAG, + LED_ALARM, + LED_FAN, + LED_PSU1, + LED_PSU2 +}; + +static SENSOR_DEVICE_ATTR(led_loc, S_IWUSR | S_IRUGO, show_led, set_led, + LED_LOC); +static SENSOR_DEVICE_ATTR(led_diag, S_IWUSR | S_IRUGO, show_led, set_led, + LED_DIAG); +static SENSOR_DEVICE_ATTR(led_alarm, S_IWUSR | S_IRUGO, show_led, set_led, + LED_ALARM); +static SENSOR_DEVICE_ATTR(led_fan, S_IWUSR | S_IRUGO, show_led, set_led, + LED_FAN); +static SENSOR_DEVICE_ATTR(led_psu1, S_IWUSR | S_IRUGO, show_led, set_led, + LED_PSU1); +static SENSOR_DEVICE_ATTR(led_psu2, S_IWUSR | S_IRUGO, show_led, set_led, + LED_PSU2); + +static struct attribute *as9817_32_led_attributes[] = { + &sensor_dev_attr_led_loc.dev_attr.attr, + &sensor_dev_attr_led_diag.dev_attr.attr, + &sensor_dev_attr_led_alarm.dev_attr.attr, + &sensor_dev_attr_led_fan.dev_attr.attr, + &sensor_dev_attr_led_psu1.dev_attr.attr, + &sensor_dev_attr_led_psu2.dev_attr.attr, + NULL +}; + +static const struct attribute_group as9817_32_led_group = { + .attrs = as9817_32_led_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + + int i = 0; + char raw_cmd[20] = ""; + sprintf(raw_cmd, "0x%02x", cmd); + if(tx_len){ + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + if (cmdline) + kfree(cmdline); + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as9817_32_led_data *as9817_32_led_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) { + return data; + } + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_LED_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_led_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (data->ipmi_resp[attr->index]) { + case IPMI_LED_MODE_OFF: + value = LED_MODE_OFF; + break; + case IPMI_LED_MODE_RED: + value = LED_MODE_RED; + break; + case IPMI_LED_MODE_RED_BLINKING: + value = LED_MODE_RED_BLINKING; + break; + case IPMI_LED_MODE_GREEN: + value = LED_MODE_GREEN; + break; + case IPMI_LED_MODE_GREEN_BLINKING: + value = LED_MODE_GREEN_BLINKING; + break; + case IPMI_LED_MODE_BLUE: + value = LED_MODE_BLUE; + break; + case IPMI_LED_MODE_BLUE_BLINKING: + value = LED_MODE_BLUE_BLINKING; + break; + case IPMI_LED_MODE_CYAN: + value = LED_MODE_CYAN; + break; + case IPMI_LED_MODE_WHITE: + value = LED_MODE_WHITE; + break; + case IPMI_LED_MODE_AMBER: + value = LED_MODE_YELLOW; + break; + case IPMI_LED_MODE_ORANGE: + value = LED_MODE_ORANGE; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long mode; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &mode); + if (status) + return status; + + mutex_lock(&data->update_lock); + + data = as9817_32_led_update_device(); + if (!data->valid) { + status = -EIO; + goto exit; + } + + data->ipmi_resp[0] = attr->index + 1; + + switch (mode) { + case LED_MODE_OFF: + data->ipmi_resp[1] = IPMI_LED_MODE_OFF; + break; + case LED_MODE_RED: + data->ipmi_resp[1] = IPMI_LED_MODE_RED; + break; + case LED_MODE_RED_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_RED_BLINKING; + break; + case LED_MODE_GREEN: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN; + break; + case LED_MODE_GREEN_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN_BLINKING; + break; + case LED_MODE_BLUE: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE; + break; + case LED_MODE_BLUE_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE_BLINKING; + break; + case LED_MODE_CYAN: + data->ipmi_resp[1] = IPMI_LED_MODE_CYAN; + break; + case LED_MODE_WHITE: + data->ipmi_resp[1] = IPMI_LED_MODE_WHITE; + break; + case LED_MODE_YELLOW: + data->ipmi_resp[1] = IPMI_LED_MODE_AMBER; + break; + case LED_MODE_ORANGE: + data->ipmi_resp[1] = IPMI_LED_MODE_ORANGE; + break; + default: + status = -EINVAL; + goto exit; + } + + /* Send IPMI write command */ + status = ipmi_send_message(&data->ipmi, IPMI_LED_WRITE_CMD, + data->ipmi_resp, 2, NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = count; + data->valid = 0; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as9817_32_led_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as9817_32_led_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as9817_32_led_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as9817_32_led_group); + + return 0; +} + +static int __init as9817_32_led_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9817_32_led_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as9817_32_led_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as9817_32_led_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9817_32_led_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9817_32_led_driver); + kfree(data); +} + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9817_32_led driver"); +MODULE_LICENSE("GPL"); + +module_init(as9817_32_led_init); +module_exit(as9817_32_led_exit); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-mux.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-mux.c new file mode 100644 index 0000000000..04be2a614d --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-mux.c @@ -0,0 +1,196 @@ +/* + * Copyright (C) Brandon Chuang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as456x CPLD1/CPLD2/CPLD3 + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9817_32_mux" + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +#define AS9817_MUX_NCHANS 8 +#define AS9817_MUX_SELECT_REG 0x0 +#define AS9817_MUX_DESELECT_VAL 0x0 + +enum mux_type { + as9817_32_mux +}; + +struct chip_desc { + u8 nchans; + u8 select_reg; + u8 deselect_val; +}; + +struct as9817_32_mux_data { + enum mux_type type; + struct mutex update_lock; + struct i2c_client *client; +}; + +/* Provide specs for the as456x CPLD types we know about */ +static const struct chip_desc chips[] = { + [as9817_32_mux] = { + .nchans = AS9817_MUX_NCHANS, + .select_reg = AS9817_MUX_SELECT_REG, + .deselect_val = AS9817_MUX_DESELECT_VAL + } +}; + +static const struct i2c_device_id as9817_32_mux_id[] = { + { "as9817_32_mux", as9817_32_mux }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as9817_32_mux_id); + +static const struct of_device_id as9817_32_mux_of_match[] = { + { .compatible = "edgecore,as9817_32_mux", .data = &chips[as9817_32_mux] }, + {} +}; +MODULE_DEVICE_TABLE(of, as9817_32_mux_of_match); + +/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() + for this as they will try to lock adapter a second time */ +static int as9817_32_mux_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 reg, u8 val) +{ + union i2c_smbus_data data; + + data.byte = val; + return __i2c_smbus_xfer(adap, client->addr, client->flags, + I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data); +} + +static int as9817_32_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct as9817_32_mux_data *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret = 0; + + mutex_lock(&data->update_lock); + switch (data->type) { + case as9817_32_mux: + ret = as9817_32_mux_write(muxc->parent, client, + chips[data->type].select_reg, 1 << chan); + break; + default: + break; + } + + mutex_unlock(&data->update_lock); + return ret; +} + +static int as9817_32_mux_deselect_mux(struct i2c_mux_core *muxc, u32 chan) +{ + struct as9817_32_mux_data *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret = 0; + + mutex_lock(&data->update_lock); + ret = as9817_32_mux_write(muxc->parent, client, + chips[data->type].select_reg, chips[data->type].deselect_val); + mutex_unlock(&data->update_lock); + return ret; +} + +static void as9817_32_mux_cleanup(struct i2c_mux_core *muxc) +{ + i2c_mux_del_adapters(muxc); +} + +/* + * I2C init/probing/exit functions + */ +static int as9817_32_mux_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct device *dev = &client->dev; + struct as9817_32_mux_data *data; + struct i2c_mux_core *muxc; + int ret = -ENODEV; + int i = 0; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + return -ENODEV; + + muxc = i2c_mux_alloc(adap, dev, AS9817_MUX_NCHANS, sizeof(*data), 0, + as9817_32_mux_select_chan, as9817_32_mux_deselect_mux); + if (!muxc) + return -ENOMEM; + + data = i2c_mux_priv(muxc); + mutex_init(&data->update_lock); + data->type = id->driver_data; + data->client = client; + i2c_set_clientdata(client, muxc); + + /* Now create an adapter for each channel */ + for (i = 0; i < chips[data->type].nchans; i++) { + ret = i2c_mux_add_adapter(muxc, 0, i, 0); + if (ret) + goto exit_mux; + } + + return 0; + +exit_mux: + as9817_32_mux_cleanup(muxc); + return ret; +} + +static int as9817_32_mux_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + as9817_32_mux_cleanup(muxc); + return 0; +} + +static struct i2c_driver as9817_32_mux_driver = { + .driver = { + .name = "as9817_32_mux", + .owner = THIS_MODULE, + }, + .probe = as9817_32_mux_probe, + .remove = as9817_32_mux_remove, + .id_table = as9817_32_mux_id, +}; + +module_i2c_driver(as9817_32_mux_driver); + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9817_32_mux driver"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c new file mode 100644 index 0000000000..c834fd8bca --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c @@ -0,0 +1,1083 @@ +/* + * Copyright (C) Roger Ho + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9817_32_psu" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_PSU_READ_CMD 0x16 +#define IPMI_PSU_MODEL_NAME_CMD 0x10 +#define IPMI_PSU_SERIAL_NUM_CMD 0x11 +#define IPMI_PSU_FAN_DIR_CMD 0x13 +#define IPMI_PSU_INFO_CMD 0x20 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_MODEL_SERIAL_LEN 32 +#define IPMI_FAN_DIR_LEN 3 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_psu(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_psu_info(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *attr, + char *buf); +static int as9817_32_psu_probe(struct platform_device *pdev); +static int as9817_32_psu_remove(struct platform_device *pdev); + +enum psu_id { + PSU_1, + PSU_2, + NUM_OF_PSU +}; + +enum psu_data_index { + PSU_PRESENT = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD_CPLD, + PSU_POWER_GOOD_PMBUS, + PSU_OVER_VOLTAGE, + PSU_OVER_CURRENT, + PSU_POWER_ON, + PSU_VIN0, + PSU_VIN1, + PSU_VIN2, + PSU_VOUT0, + PSU_VOUT1, + PSU_VOUT2, + PSU_IIN0, + PSU_IIN1, + PSU_IIN2, + PSU_IOUT0, + PSU_IOUT1, + PSU_IOUT2, + PSU_PIN0, + PSU_PIN1, + PSU_PIN2, + PSU_PIN3, + PSU_POUT0, + PSU_POUT1, + PSU_POUT2, + PSU_POUT3, + PSU_TEMP1_0, + PSU_TEMP1_1, + PSU_TEMP2_0, + PSU_TEMP2_1, + PSU_TEMP3_0, + PSU_TEMP3_1, + PSU_FAN0, + PSU_FAN1, + PSU_VOUT_MODE, + PSU_STATUS_COUNT, + PSU_MODEL = 0, + PSU_SERIAL = 0, + PSU_TEMP1_MAX0 = 2, + PSU_TEMP1_MAX1, + PSU_TEMP1_MIN0, + PSU_TEMP1_MIN1, + PSU_TEMP2_MAX0, + PSU_TEMP2_MAX1, + PSU_TEMP2_MIN0, + PSU_TEMP2_MIN1, + PSU_TEMP3_MAX0, + PSU_TEMP3_MAX1, + PSU_TEMP3_MIN0, + PSU_TEMP3_MIN1, + PSU_VIN_UPPER_CRIT0, + PSU_VIN_UPPER_CRIT1, + PSU_VIN_UPPER_CRIT2, + PSU_VIN_MAX0, + PSU_VIN_MAX1, + PSU_VIN_MAX2, + PSU_VIN_MIN0, + PSU_VIN_MIN1, + PSU_VIN_MIN2, + PSU_VIN_LOWER_CRIT0, + PSU_VIN_LOWER_CRIT1, + PSU_VIN_LOWER_CRIT2, + PSU_VOUT_MAX0, + PSU_VOUT_MAX1, + PSU_VOUT_MAX2, + PSU_VOUT_MIN0, + PSU_VOUT_MIN1, + PSU_VOUT_MIN2, + PSU_IIN_MAX0, + PSU_IIN_MAX1, + PSU_IIN_MAX2, + PSU_IOUT_MAX0, + PSU_IOUT_MAX1, + PSU_IOUT_MAX2, + PSU_PIN_MAX0, + PSU_PIN_MAX1, + PSU_PIN_MAX2, + PSU_PIN_MAX3, + PSU_POUT_MAX0, + PSU_POUT_MAX1, + PSU_POUT_MAX2, + PSU_POUT_MAX3, + PSU_INFO_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user * user; + int interface; + int pid; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct ipmi_psu_resp_data { + unsigned char status[PSU_STATUS_COUNT]; + unsigned char info[PSU_INFO_COUNT]; + char serial[IPMI_MODEL_SERIAL_LEN+1]; + char model[IPMI_MODEL_SERIAL_LEN+1]; + char fandir[IPMI_FAN_DIR_LEN+1]; +}; + +struct as9817_32_psu_data { + struct platform_device *pdev[2]; + struct device *hwmon_dev[2]; + struct mutex update_lock; + char valid[2]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ + unsigned long last_updated[2]; /* In jiffies, 0: PSU1, 1: PSU2 */ + struct ipmi_data ipmi; + struct ipmi_psu_resp_data ipmi_resp[2]; /* 0: PSU1, 1: PSU2 */ + unsigned char ipmi_tx_data[2]; +}; + +struct as9817_32_psu_data *data = NULL; + +static struct platform_driver as9817_32_psu_driver = { + .probe = as9817_32_psu_probe, + .remove = as9817_32_psu_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define PSU_PRESENT_ATTR_ID(index) PSU##index##_PRESENT +#define PSU_POWERGOOD_ATTR_ID(index) PSU##index##_POWER_GOOD +#define PSU_VIN_ATTR_ID(index) PSU##index##_VIN +#define PSU_VOUT_ATTR_ID(index) PSU##index##_VOUT +#define PSU_IIN_ATTR_ID(index) PSU##index##_IIN +#define PSU_IOUT_ATTR_ID(index) PSU##index##_IOUT +#define PSU_PIN_ATTR_ID(index) PSU##index##_PIN +#define PSU_POUT_ATTR_ID(index) PSU##index##_POUT +#define PSU_MODEL_ATTR_ID(index) PSU##index##_MODEL +#define PSU_SERIAL_ATTR_ID(index) PSU##index##_SERIAL +#define PSU_TEMP1_INPUT_ATTR_ID(index) PSU##index##_TEMP1_INPUT +#define PSU_TEMP2_INPUT_ATTR_ID(index) PSU##index##_TEMP2_INPUT +#define PSU_TEMP3_INPUT_ATTR_ID(index) PSU##index##_TEMP3_INPUT +#define PSU_FAN_INPUT_ATTR_ID(index) PSU##index##_FAN_INPUT +#define PSU_FAN_DIR_ATTR_ID(index) PSU##index##_FAN_DIR + +#define PSU_TEMP1_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP1_INPUT_MAX +#define PSU_TEMP1_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP1_INPUT_MIN +#define PSU_TEMP2_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP2_INPUT_MAX +#define PSU_TEMP2_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP2_INPUT_MIN +#define PSU_TEMP3_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP3_INPUT_MAX +#define PSU_TEMP3_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP3_INPUT_MIN +#define PSU_VIN_MAX_ATTR_ID(index) PSU##index##_VIN_MAX +#define PSU_VIN_MIN_ATTR_ID(index) PSU##index##_VIN_MIN +#define PSU_VIN_UPPER_CRIT_ATTR_ID(index) PSU##index##_VIN_UPPER_CRIT +#define PSU_VIN_LOWER_CRIT_ATTR_ID(index) PSU##index##_VIN_LOWER_CRIT +#define PSU_VOUT_MAX_ATTR_ID(index) PSU##index##_VOUT_MAX +#define PSU_VOUT_MIN_ATTR_ID(index) PSU##index##_VOUT_MIN +#define PSU_IIN_MAX_ATTR_ID(index) PSU##index##_IIN_MAX +#define PSU_IOUT_MAX_ATTR_ID(index) PSU##index##_IOUT_MAX +#define PSU_PIN_MAX_ATTR_ID(index) PSU##index##_PIN_MAX +#define PSU_POUT_MAX_ATTR_ID(index) PSU##index##_POUT_MAX + +#define PSU_ATTR(psu_id) \ + PSU_PRESENT_ATTR_ID(psu_id), \ + PSU_POWERGOOD_ATTR_ID(psu_id), \ + PSU_VIN_ATTR_ID(psu_id), \ + PSU_VOUT_ATTR_ID(psu_id), \ + PSU_IIN_ATTR_ID(psu_id), \ + PSU_IOUT_ATTR_ID(psu_id), \ + PSU_PIN_ATTR_ID(psu_id), \ + PSU_POUT_ATTR_ID(psu_id), \ + PSU_MODEL_ATTR_ID(psu_id), \ + PSU_SERIAL_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_DIR_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_VIN_MAX_ATTR_ID(psu_id), \ + PSU_VIN_MIN_ATTR_ID(psu_id), \ + PSU_VIN_UPPER_CRIT_ATTR_ID(psu_id), \ + PSU_VIN_LOWER_CRIT_ATTR_ID(psu_id), \ + PSU_VOUT_MAX_ATTR_ID(psu_id), \ + PSU_VOUT_MIN_ATTR_ID(psu_id), \ + PSU_IIN_MAX_ATTR_ID(psu_id), \ + PSU_IOUT_MAX_ATTR_ID(psu_id), \ + PSU_PIN_MAX_ATTR_ID(psu_id), \ + PSU_POUT_MAX_ATTR_ID(psu_id) + +enum as9817_32_psu_sysfs_attrs { + /* psu attributes */ + PSU_ATTR(1), + PSU_ATTR(2), + NUM_OF_PSU_ATTR, + NUM_OF_PER_PSU_ATTR = (NUM_OF_PSU_ATTR/NUM_OF_PSU) +}; + +/* psu attributes */ +#define DECLARE_PSU_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(psu##index##_present, S_IRUGO, show_psu, NULL, \ + PSU##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(psu##index##_power_good, S_IRUGO, show_psu, NULL,\ + PSU##index##_POWER_GOOD); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin, S_IRUGO, show_psu, NULL, \ + PSU##index##_VIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout, S_IRUGO, show_psu, NULL, \ + PSU##index##_VOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin, S_IRUGO, show_psu, NULL, \ + PSU##index##_IIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout, S_IRUGO, show_psu, NULL, \ + PSU##index##_IOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin, S_IRUGO, show_psu, NULL, \ + PSU##index##_PIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout, S_IRUGO, show_psu, NULL, \ + PSU##index##_POUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_model, S_IRUGO, show_string, NULL, \ + PSU##index##_MODEL); \ + static SENSOR_DEVICE_ATTR(psu##index##_serial, S_IRUGO, show_string, NULL,\ + PSU##index##_SERIAL);\ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP1_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP2_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP3_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan1_input, S_IRUGO, show_psu, NULL,\ + PSU##index##_FAN_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan_dir, S_IRUGO, show_string, NULL,\ + PSU##index##_FAN_DIR); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP1_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP1_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP2_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP2_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP3_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP3_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_upper_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_UPPER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_lower_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_LOWER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_PIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_POUT_MAX) + +#define DECLARE_PSU_ATTR(index) \ + &sensor_dev_attr_psu##index##_present.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_power_good.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_model.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_serial.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_temp1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan_dir.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_upper_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_lower_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout_max.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_vout_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout_max.dev_attr.attr + +DECLARE_PSU_SENSOR_DEVICE_ATTR(1); +/*Duplicate nodes for lm-sensors.*/ +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_psu, NULL, PSU1_VOUT); +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, show_psu, NULL, PSU1_IOUT); +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, show_psu, NULL, PSU1_POUT); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_psu, NULL, PSU1_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_psu, NULL, PSU1_FAN_INPUT); + +static struct attribute *as9817_32_psu1_attrs[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(1), + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + NULL +}; +static struct attribute_group as9817_32_psu1_group = { + .attrs = as9817_32_psu1_attrs, +}; +/* ATTRIBUTE_GROUPS(as9817_32_psu1); */ + +DECLARE_PSU_SENSOR_DEVICE_ATTR(2); +/*Duplicate nodes for lm-sensors.*/ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_psu, NULL, PSU2_VOUT); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_psu, NULL, PSU2_IOUT); +static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_psu, NULL, PSU2_POUT); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_psu, NULL, PSU2_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_psu, NULL, PSU2_FAN_INPUT); +static struct attribute *as9817_32_psu2_attrs[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(2), + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_power2_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + NULL +}; +static struct attribute_group as9817_32_psu2_group = { + .attrs = as9817_32_psu2_attrs, +}; +/* ATTRIBUTE_GROUPS(as9817_32_psu2); */ + +const struct attribute_group *as9817_32_psu_groups[][2] = { + {&as9817_32_psu1_group, NULL}, + {&as9817_32_psu2_group, NULL} +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev, + int pid) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + ipmi->pid = dev->id; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len, + unsigned char pid) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev[pid]->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev[pid]->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev[pid]->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len, + unsigned char pid) +{ + int status = 0, retry = 0; + + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + + int i = 0; + char raw_cmd[20] = ""; + sprintf(raw_cmd, "0x%02x", cmd); + if(tx_len){ + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len + , pid); + if (unlikely(status != 0)) { + dev_err(&data->pdev[pid]->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev[pid]->dev, + "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + if (cmdline) + kfree(cmdline); + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev[ipmi->pid]->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attribute *da) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + int status = 0; + + if (time_before(jiffies, data->last_updated[pid] + HZ * 5) && data->valid[pid]) + return data; + + data->valid[pid] = 0; + /* To be compatible for older BMC firmware */ + data->ipmi_resp[pid].status[PSU_VOUT_MODE] = 0xff; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = pid + 1; /* PSU ID base id for ipmi start from 1 */ + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp[pid].status, + sizeof(data->ipmi_resp[pid].status), pid); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get model name from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_MODEL_NAME_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].model, + sizeof(data->ipmi_resp[pid].model) - 1, pid); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get serial number from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_SERIAL_NUM_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].serial, + sizeof(data->ipmi_resp[pid].serial) - 1, pid); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get fan direction from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_FAN_DIR_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].fandir, + sizeof(data->ipmi_resp[pid].fandir) - 1, pid); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* Get capability from ipmi */ + data->ipmi_tx_data[1] = IPMI_PSU_INFO_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp[pid].info, + sizeof(data->ipmi_resp[pid].info), pid); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated[pid] = jiffies; + data->valid[pid] = 1; + +exit: + return data; +} + +#define VALIDATE_PRESENT_RETURN(id) \ +do { \ + if (data->ipmi_resp[id].status[PSU_PRESENT] == 0) { \ + mutex_unlock(&data->update_lock); \ + return -ENXIO; \ + } \ +} while (0) + +static ssize_t show_psu(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + u32 value = 0; + int present = 0; + int error = 0; + int multiplier = 1000; + + mutex_lock(&data->update_lock); + + data = as9817_32_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_PRESENT: + case PSU2_PRESENT: + value = present; + break; + case PSU1_POWER_GOOD: + case PSU2_POWER_GOOD: + VALIDATE_PRESENT_RETURN(pid); + value = data->ipmi_resp[pid].status[PSU_POWER_GOOD_PMBUS]; + break; + case PSU1_IIN: + case PSU2_IIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IIN0] | + (u32)data->ipmi_resp[pid].status[PSU_IIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IIN2] << 16); + break; + case PSU1_IOUT: + case PSU2_IOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_IOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IOUT2] << 16); + break; + case PSU1_VIN: + case PSU2_VIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VIN0] | + (u32)data->ipmi_resp[pid].status[PSU_VIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VIN2] << 16); + break; + case PSU1_VOUT: + case PSU2_VOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_VOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VOUT2] << 16); + break; + case PSU1_PIN: + case PSU2_PIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_PIN0] | + (u32)data->ipmi_resp[pid].status[PSU_PIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_PIN2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_PIN3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT: + case PSU2_POUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_POUT0] | + (u32)data->ipmi_resp[pid].status[PSU_POUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_POUT2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_POUT3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_TEMP1_INPUT: + case PSU2_TEMP1_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].status[PSU_TEMP1_0] | + (u16)data->ipmi_resp[pid].status[PSU_TEMP1_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT: + case PSU2_TEMP2_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].status[PSU_TEMP2_0] | + (u16)data->ipmi_resp[pid].status[PSU_TEMP2_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT: + case PSU2_TEMP3_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].status[PSU_TEMP3_0] | + (u16)data->ipmi_resp[pid].status[PSU_TEMP3_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_FAN_INPUT: + case PSU2_FAN_INPUT: + VALIDATE_PRESENT_RETURN(pid); + multiplier = 1; + value = ((u32)data->ipmi_resp[pid].status[PSU_FAN0] | + (u32)data->ipmi_resp[pid].status[PSU_FAN1] << 8); + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_psu_info(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + s32 value = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_TEMP1_INPUT_MAX: + case PSU2_TEMP1_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP1_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP1_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP1_INPUT_MIN: + case PSU2_TEMP1_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP1_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP1_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT_MAX: + case PSU2_TEMP2_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP2_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP2_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT_MIN: + case PSU2_TEMP2_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP2_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP2_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT_MAX: + case PSU2_TEMP3_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP3_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP3_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT_MIN: + case PSU2_TEMP3_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP3_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP3_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_VIN_UPPER_CRIT: + case PSU2_VIN_UPPER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT2] << 16); + break; + case PSU1_VIN_LOWER_CRIT: + case PSU2_VIN_LOWER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT2] << 16); + break; + case PSU1_VIN_MAX: + case PSU2_VIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX2] << 16); + break; + case PSU1_VIN_MIN: + case PSU2_VIN_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN2] << 16); + break; + case PSU1_VOUT_MAX: + case PSU2_VOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX2] << 16); + break; + case PSU1_VOUT_MIN: + case PSU2_VOUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN2] << 16); + break; + case PSU1_IIN_MAX: + case PSU2_IIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX2] << 16); + break; + case PSU1_IOUT_MAX: + case PSU2_IOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX2] << 16); + break; + case PSU1_PIN_MAX: + case PSU2_PIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_PIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT_MAX: + case PSU2_POUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_POUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + char *str = NULL; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + switch (attr->index) { + case PSU1_MODEL: + case PSU2_MODEL: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].model; + break; + case PSU1_SERIAL: + case PSU2_SERIAL: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].serial; + break; + case PSU1_FAN_DIR: + case PSU2_FAN_DIR: + VALIDATE_PRESENT_RETURN(pid); + str = data->ipmi_resp[pid].fandir; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%s\n", str); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as9817_32_psu_probe(struct platform_device *pdev) +{ + int status = 0; + struct device *hwmon_dev = NULL; + + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9817_32_psu_groups[pdev->id]); + if (IS_ERR(hwmon_dev)) { + status = PTR_ERR(hwmon_dev); + return status; + } + + mutex_lock(&data->update_lock); + data->hwmon_dev[pdev->id] = hwmon_dev; + mutex_unlock(&data->update_lock); + + dev_info(&pdev->dev, "PSU%d device created\n", pdev->id + 1); + + return 0; +} + +static int as9817_32_psu_remove(struct platform_device *pdev) +{ + mutex_lock(&data->update_lock); + if (data->hwmon_dev[pdev->id]) { + hwmon_device_unregister(data->hwmon_dev[pdev->id]); + data->hwmon_dev[pdev->id] = NULL; + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int __init as9817_32_psu_init(void) +{ + int ret; + int i; + + data = kzalloc(sizeof(struct as9817_32_psu_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9817_32_psu_driver); + if (ret < 0) + goto dri_reg_err; + + for (i = 0; i < NUM_OF_PSU; i++) { + data->pdev[i] = platform_device_register_simple(DRVNAME, i, NULL, 0); + if (IS_ERR(data->pdev[i])) { + ret = PTR_ERR(data->pdev[i]); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev[i]->dev, i); + if (ret) + goto ipmi_err; + } + + return 0; + +ipmi_err: + while (i > 0) { + i--; + platform_device_unregister(data->pdev[i]); + } +dev_reg_err: + platform_driver_unregister(&as9817_32_psu_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9817_32_psu_exit(void) +{ + int i; + + ipmi_destroy_user(data->ipmi.user); + for (i = 0; i < NUM_OF_PSU; i++) { + platform_device_unregister(data->pdev[i]); + } + platform_driver_unregister(&as9817_32_psu_driver); + kfree(data); +} + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9817_32_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(as9817_32_psu_init); +module_exit(as9817_32_psu_exit); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c new file mode 100644 index 0000000000..7636d1b88b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c @@ -0,0 +1,482 @@ +/* + * Copyright (C) Roger Ho + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9817_32_sys" +#define ACCTON_IPMI_NETFN 0x34 + +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_READ_MAX_LEN 128 + +#define IPMI_CPLD_READ_CMD 0x20 +#define IPMI_OTP_PROTECT_CMD 0x94 +#define IPMI_SEND_THERMAL_DATA_CMD 0x13 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static int as9817_32_sys_probe(struct platform_device *pdev); +static int as9817_32_sys_remove(struct platform_device *pdev); +static ssize_t show_version(struct device *dev, + struct device_attribute *da, char *buf); +static ssize_t set_otp_protect(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_bmc_thermal_data(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user * user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as9817_32_sys_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + struct ipmi_data ipmi; + unsigned char ipmi_resp_cpld[2]; + unsigned char ipmi_tx_data[3]; +}; + +struct as9817_32_sys_data *data = NULL; + +static struct platform_driver as9817_32_sys_driver = { + .probe = as9817_32_sys_probe, + .remove = as9817_32_sys_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as9817_32_sys_sysfs_attrs { + FPGA_VER, /* FPGA version */ + OTP_PROTECT, + THERMAL_DATA +}; + +static SENSOR_DEVICE_ATTR(fpga_version, S_IRUGO, show_version, NULL, FPGA_VER); +static SENSOR_DEVICE_ATTR(otp_protect, S_IWUSR, NULL, set_otp_protect, OTP_PROTECT); +static SENSOR_DEVICE_ATTR(bmc_thermal_data, S_IWUSR, NULL, set_bmc_thermal_data, THERMAL_DATA); + +static struct attribute *as9817_32_sys_attributes[] = { + &sensor_dev_attr_fpga_version.dev_attr.attr, + &sensor_dev_attr_otp_protect.dev_attr.attr, + &sensor_dev_attr_bmc_thermal_data.dev_attr.attr, + NULL +}; + +static const struct attribute_group as9817_32_sys_group = { + .attrs = as9817_32_sys_attributes, +}; + +/* Functions to talk to the IPMI layer */ +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + + int i = 0; + char raw_cmd[20] = ""; + sprintf(raw_cmd, "0x%02x", cmd); + if(tx_len) { + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi,cmd, tx_data, tx_len, rx_data, + rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err rx_result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + if (cmdline) + kfree(cmdline); + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } + else { + ipmi->rx_msg_len = 0; + } + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static struct as9817_32_sys_data *as9817_32_sys_update_fpga_ver(void) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = 0x60; + status = ipmi_send_message(&data->ipmi, IPMI_CPLD_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_cpld, + sizeof(data->ipmi_resp_cpld)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_version(struct device *dev, + struct device_attribute *da, char *buf) +{ + unsigned char major; + unsigned char minor; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9817_32_sys_update_fpga_ver(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + major = data->ipmi_resp_cpld[0]; + minor = data->ipmi_resp_cpld[1]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d.%d\n", major, minor); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_otp_protect(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long otp_protect; + int status; + + status = kstrtol(buf, 10, &otp_protect); + if (status) + return status; + + if (!otp_protect) + return count; + + mutex_lock(&data->update_lock); + + data->ipmi_tx_data[0] = 3; + status = ipmi_send_message(&data->ipmi, IPMI_OTP_PROTECT_CMD, + data->ipmi_tx_data, 1, + NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_bmc_thermal_data(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + int args; + char *opt, tmp[32] = {0}; + char *tmp_p; + size_t copy_size; + u8 input[3] = {0}; + + copy_size = (count < sizeof(tmp)) ? count : sizeof(tmp) - 1; + #ifdef __STDC_LIB_EXT1__ + memcpy_s(tmp, copy_size, buf, copy_size); + #else + memcpy(tmp, buf, copy_size); + #endif + tmp[copy_size] = '\0'; + + args = 0; + tmp_p = strim(tmp); + while (args < 3 && (opt = strsep(&tmp_p, " ")) != NULL) { + if (kstrtou8(opt, 10, &input[args]) == 0) { + args++; + } + } + if (args != 3) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + data->ipmi_tx_data[0] = input[0]; + data->ipmi_tx_data[1] = input[1]; + data->ipmi_tx_data[2] = input[2]; + status = ipmi_send_message(&data->ipmi, IPMI_SEND_THERMAL_DATA_CMD, + data->ipmi_tx_data, 3, + NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EINVAL; + goto exit; + } + + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as9817_32_sys_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as9817_32_sys_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as9817_32_sys_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as9817_32_sys_group); + + return 0; +} + +static int __init as9817_32_sys_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9817_32_sys_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9817_32_sys_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as9817_32_sys_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9817_32_sys_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9817_32_sys_driver); + kfree(data); +} + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9817_32_sys driver"); +MODULE_LICENSE("GPL"); + +module_init(as9817_32_sys_init); +module_exit(as9817_32_sys_exit); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c new file mode 100644 index 0000000000..72dfaa11c3 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c @@ -0,0 +1,526 @@ +/* + * Copyright (C) Roger Ho + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9817_32_thermal" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_THERMAL_READ_CMD 0x12 +#define THERMAL_COUNT 8 +#define THERMAL_DATA_LEN 3 +#define THERMAL_DATA_COUNT (THERMAL_COUNT * THERMAL_DATA_LEN) + +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf); +#ifdef ENABLE_THRESHOLD +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf); +#endif +static int as9817_32_thermal_probe(struct platform_device *pdev); +static int as9817_32_thermal_remove(struct platform_device *pdev); + +enum temp_data_index { + TEMP_ADDR, + TEMP_FAULT, + TEMP_INPUT, + TEMP_DATA_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user * user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as9817_32_thermal_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + char ipmi_resp[THERMAL_DATA_COUNT]; /* 3 bytes for each thermal */ + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[2]; /* 0: thermal id, 1: temp */ +}; + +#ifdef ENABLE_THRESHOLD +static s8 temp_max_alarm[THERMAL_COUNT] = { 85, 85, 85, 79, 92, 85, 92, 92}; +static s8 temp_max[THERMAL_COUNT] = { 80, 80, 80, 74, 87, 80, 87, 87 }; +static s8 temp_min[THERMAL_COUNT] = { -45, -45, -45, -45, -45, -45, -45, -45 }; +static s8 temp_min_alarm[THERMAL_COUNT] = { -50, -50, -50, -50, -50, -50, -50, -50 }; +#endif + +struct as9817_32_thermal_data *data = NULL; + +static struct platform_driver as9817_32_thermal_driver = { + .probe = as9817_32_thermal_probe, + .remove = as9817_32_thermal_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as9817_32_thermal_sysfs_attrs { + TEMP1_INPUT, // 0x48 + TEMP2_INPUT, // 0x49 + TEMP3_INPUT, // 0x4A + TEMP4_INPUT, // 0x4B + TEMP5_INPUT, // 0x4C + TEMP6_INPUT, // 0x4D + TEMP7_INPUT, // FAN 0x4D + TEMP8_INPUT, // FAN 0x4E + TEMP1_MAX_ALARM, + TEMP2_MAX_ALARM, + TEMP3_MAX_ALARM, + TEMP4_MAX_ALARM, + TEMP5_MAX_ALARM, + TEMP6_MAX_ALARM, + TEMP7_MAX_ALARM, + TEMP8_MAX_ALARM, + TEMP1_MAX, + TEMP2_MAX, + TEMP3_MAX, + TEMP4_MAX, + TEMP5_MAX, + TEMP6_MAX, + TEMP7_MAX, + TEMP8_MAX, + TEMP1_MIN, + TEMP2_MIN, + TEMP3_MIN, + TEMP4_MIN, + TEMP5_MIN, + TEMP6_MIN, + TEMP7_MIN, + TEMP8_MIN, + TEMP1_MIN_ALARM, + TEMP2_MIN_ALARM, + TEMP3_MIN_ALARM, + TEMP4_MIN_ALARM, + TEMP5_MIN_ALARM, + TEMP6_MIN_ALARM, + TEMP7_MIN_ALARM, + TEMP8_MIN_ALARM, +}; + +#ifdef ENABLE_THRESHOLD +// Read only temp_input +#define DECLARE_THERMAL_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, show_temp, \ + NULL, TEMP##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(temp##index##_crit, S_IRUGO, show_threshold,\ + NULL, TEMP##index##_MAX_ALARM); \ + static SENSOR_DEVICE_ATTR(temp##index##_max, S_IRUGO, show_threshold,\ + NULL, TEMP##index##_MAX); \ + static SENSOR_DEVICE_ATTR(temp##index##_min, S_IRUGO, show_threshold,\ + NULL, TEMP##index##_MIN); \ + static SENSOR_DEVICE_ATTR(temp##index##_lcrit, S_IRUGO, show_threshold,\ + NULL, TEMP##index##_MIN_ALARM) + +#define DECLARE_THERMAL_ATTR(index) \ + &sensor_dev_attr_temp##index##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_crit.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_max.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_min.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_lcrit.dev_attr.attr +#else +#define DECLARE_THERMAL_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, show_temp, \ + NULL, TEMP##index##_INPUT); + +#define DECLARE_THERMAL_ATTR(index) \ + &sensor_dev_attr_temp##index##_input.dev_attr.attr +#endif + +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(1); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(2); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(3); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(4); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(5); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(6); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(7); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(8); + +static struct attribute *as9817_32_thermal_attrs[] = { + DECLARE_THERMAL_ATTR(1), + DECLARE_THERMAL_ATTR(2), + DECLARE_THERMAL_ATTR(3), + DECLARE_THERMAL_ATTR(4), + DECLARE_THERMAL_ATTR(5), + DECLARE_THERMAL_ATTR(6), + DECLARE_THERMAL_ATTR(7), + DECLARE_THERMAL_ATTR(8), + NULL +}; +ATTRIBUTE_GROUPS(as9817_32_thermal); + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + + int i = 0; + char raw_cmd[20] = ""; + sprintf(raw_cmd, "0x%02x", cmd); + if(tx_len) { + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, + rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi cmd(%x) err status(%d)[%s] raw_cmd=[%s]\r\n tx_msgid=(%02x)", + cmd, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi cmd(%x) err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + cmd, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + if (cmdline) + kfree(cmdline); + + return status; +} + +/* Dispatch IPMI messages to callers */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + if (msg->msgid != ipmi->tx_msgid) { + dev_err(&data->pdev->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, + (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + ipmi->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else + ipmi->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +#ifdef ENABLE_THRESHOLD +static ssize_t show_threshold(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + mutex_lock(&data->update_lock); + + switch (attr->index) { + case TEMP1_MAX_ALARM ... TEMP8_MAX_ALARM: + status = (int)temp_max_alarm[attr->index - TEMP1_MAX_ALARM]; + break; + case TEMP1_MAX ... TEMP8_MAX: + status = (int)temp_max[attr->index - TEMP1_MAX]; + break; + case TEMP1_MIN ... TEMP8_MIN: + status = (int)temp_min[attr->index - TEMP1_MIN]; + break; + case TEMP1_MIN_ALARM ... TEMP8_MIN_ALARM: + status = (int)temp_min_alarm[attr->index - TEMP1_MIN_ALARM]; + break; + default: + status = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status * 1000); + +exit: + mutex_unlock(&data->update_lock); + return status; +} +#endif + +static ssize_t show_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status = 0; + int index = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ * 5) || !data->valid) { + data->valid = 0; + + status = ipmi_send_message(&data->ipmi, IPMI_THERMAL_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + /* Get temp fault status */ + index = attr->index * TEMP_DATA_COUNT + TEMP_FAULT; + if (unlikely(data->ipmi_resp[index] == 0)) { + status = -EIO; + goto exit; + } + + /* Get temperature in degree celsius */ + index = attr->index * TEMP_DATA_COUNT + TEMP_INPUT; + status = ((s8)data->ipmi_resp[index]) * 1000; + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as9817_32_thermal_probe(struct platform_device *pdev) +{ + int status = 0; + struct device *hwmon_dev; + + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9817_32_thermal_groups); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + return status; + } + + mutex_lock(&data->update_lock); + data->hwmon_dev = hwmon_dev; + mutex_unlock(&data->update_lock); + + dev_info(&pdev->dev, "Device Created\n"); + + return status; +} + +static int as9817_32_thermal_remove(struct platform_device *pdev) +{ + mutex_lock(&data->update_lock); + if (data->hwmon_dev) { + hwmon_device_unregister(data->hwmon_dev); + data->hwmon_dev = NULL; + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int __init as9817_32_thermal_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9817_32_thermal_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9817_32_thermal_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) { + goto ipmi_err; + } + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as9817_32_thermal_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9817_32_thermal_exit(void) +{ + if (data) { + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9817_32_thermal_driver); + kfree(data); + } +} + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9817_32_thermal driver"); +MODULE_LICENSE("GPL"); + +module_init(as9817_32_thermal_init); +module_exit(as9817_32_thermal_exit); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.gitignore b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.gitignore new file mode 100644 index 0000000000..bfcc348c23 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.gitignore @@ -0,0 +1 @@ +x86_64_accton_as9817_32.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.module b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.module new file mode 100644 index 0000000000..d45ed2e001 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/.module @@ -0,0 +1 @@ +name: x86_64_accton_as9817_32 diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/Makefile b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/Makefile new file mode 100644 index 0000000000..148f55d6d1 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/Makefile @@ -0,0 +1,9 @@ +############################################################ +# +# +# +############################################################ +include $(ONL)/make/config.mk +MODULE := x86_64_accton_as9817_32 +AUTOMODULE := x86_64_accton_as9817_32 +include $(BUILDER)/definemodule.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/make.mk b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/make.mk new file mode 100644 index 0000000000..e29031ea68 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/make.mk @@ -0,0 +1,8 @@ +############################################################################### +# +# x86_64_accton_as9817_32 Autogeneration +# +############################################################################### +x86_64_accton_as9817_32_AUTO_DEFS := module/auto/x86_64_accton_as9817_32.yml +x86_64_accton_as9817_32_AUTO_DIRS := module/inc/x86_64_accton_as9817_32 module/src +include $(BUILDER)/auto.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/x86_64_accton_as9817_32.yml b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/x86_64_accton_as9817_32.yml new file mode 100644 index 0000000000..e05772b136 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/auto/x86_64_accton_as9817_32.yml @@ -0,0 +1,50 @@ +############################################################################### +# +# x86_64_accton_as9817_32 Autogeneration Definitions +# +############################################################################### + +cdefs: &cdefs +- X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING: + doc: "Include or exclude logging." + default: 1 +- X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT: + doc: "Default enabled log options." + default: AIM_LOG_OPTIONS_DEFAULT +- X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT: + doc: "Default enabled log bits." + default: AIM_LOG_BITS_DEFAULT +- X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT: + doc: "Default enabled custom log bits." + default: 0 +- X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB: + doc: "Default all porting macros to use the C standard libraries." + default: 1 +- X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS: + doc: "Include standard library headers for stdlib porting macros." + default: x86_64_accton_as9817_32_CONFIG_PORTING_STDLIB +- X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI: + doc: "Include generic uCli support." + default: 0 +- X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION: + doc: "Assume chassis fan direction is the same as the PSU fan direction." + default: 0 + + +definitions: + cdefs: + x86_64_accton_as9817_32_CONFIG_HEADER: + defs: *cdefs + basename: x86_64_accton_as9817_32_config + + portingmacro: + x86_64_accton_as9817_32: + macros: + - malloc + - free + - memset + - memcpy + - strncpy + - vsnprintf + - snprintf + - strlen diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32.x b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32.x new file mode 100644 index 0000000000..36bad51c3c --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32.x @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.xmacro(ALL).define> */ +/* */ + +/* <--auto.start.xenum(ALL).define> */ +/* */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_config.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_config.h new file mode 100644 index 0000000000..636a0633ad --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_config.h @@ -0,0 +1,137 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_accton_as9817_32 Configuration Header + * + * @addtogroup x86_64_accton_as9817_32-config + * @{ + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9817_32_CONFIG_H__ +#define __x86_64_accton_as9817_32_CONFIG_H__ + +#ifdef GLOBAL_INCLUDE_CUSTOM_CONFIG +#include +#endif +#ifdef x86_64_accton_as9817_32_INCLUDE_CUSTOM_CONFIG +#include +#endif + +/* */ +#include +/** + * X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING + * + * Include or exclude logging. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING +#define X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING 1 +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT + * + * Default enabled log options. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT +#define X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT AIM_LOG_OPTIONS_DEFAULT +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT + * + * Default enabled log bits. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT +#define X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT AIM_LOG_BITS_DEFAULT +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT + * + * Default enabled custom log bits. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT +#define X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT 0 +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB + * + * Default all porting macros to use the C standard libraries. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB +#define X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB 1 +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + * + * Include standard library headers for stdlib porting macros. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS +#define X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS x86_64_accton_as9817_32_CONFIG_PORTING_STDLIB +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI + * + * Include generic uCli support. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI +#define X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI 0 +#endif + +/** + * X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION + * + * Assume chassis fan direction is the same as the PSU fan direction. */ + + +#ifndef X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION +#define X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION 0 +#endif + + + +/** + * All compile time options can be queried or displayed + */ + +/** Configuration settings structure. */ +typedef struct x86_64_accton_as9817_32_config_settings_s { + /** name */ + const char* name; + /** value */ + const char* value; +} x86_64_accton_as9817_32_config_settings_t; + +/** Configuration settings table. */ +/** x86_64_accton_as9817_32_config_settings table. */ +extern x86_64_accton_as9817_32_config_settings_t x86_64_accton_as9817_32_config_settings[]; + +/** + * @brief Lookup a configuration setting. + * @param setting The name of the configuration option to lookup. + */ +const char* x86_64_accton_as9817_32_config_lookup(const char* setting); + +/** + * @brief Show the compile-time configuration. + * @param pvs The output stream. + */ +int x86_64_accton_as9817_32_config_show(struct aim_pvs_s* pvs); + +/* */ + +#include "x86_64_accton_as9817_32_porting.h" + +#endif /* __x86_64_accton_as9817_32_CONFIG_H__ */ +/* @} */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_dox.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_dox.h new file mode 100644 index 0000000000..6dd19449b5 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_dox.h @@ -0,0 +1,26 @@ +/**************************************************************************//** + * + * x86_64_accton_as9817_32 Doxygen Header + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9817_32_DOX_H__ +#define __x86_64_accton_as9817_32_DOX_H__ + +/** + * @defgroup x86_64_accton_as9817_32 x86_64_accton_as9817_32 - x86_64_accton_as9817_32 Description + * + +The documentation overview for this module should go here. + + * + * @{ + * + * @defgroup x86_64_accton_as9817_32-x86_64_accton_as9817_32 Public Interface + * @defgroup x86_64_accton_as9817_32-config Compile Time Configuration + * @defgroup x86_64_accton_as9817_32-porting Porting Macros + * + * @} + * + */ + +#endif /* __x86_64_accton_as9817_32_DOX_H__ */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_porting.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_porting.h new file mode 100644 index 0000000000..c1269bdcfa --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/inc/x86_64_accton_as9817_32/x86_64_accton_as9817_32_porting.h @@ -0,0 +1,107 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_accton_as9817_32 Porting Macros. + * + * @addtogroup x86_64_accton_as9817_32-porting + * @{ + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9817_32_PORTING_H__ +#define __x86_64_accton_as9817_32_PORTING_H__ + + +/* */ +#if X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS == 1 +#include +#include +#include +#include +#include +#endif + +#ifndef X86_64_ACCTON_AS9817_32_MALLOC + #if defined(GLOBAL_MALLOC) + #define X86_64_ACCTON_AS9817_32_MALLOC GLOBAL_MALLOC + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_MALLOC malloc + #else + #error The macro X86_64_ACCTON_AS9817_32_MALLOC is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_FREE + #if defined(GLOBAL_FREE) + #define X86_64_ACCTON_AS9817_32_FREE GLOBAL_FREE + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_FREE free + #else + #error The macro X86_64_ACCTON_AS9817_32_FREE is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_MEMSET + #if defined(GLOBAL_MEMSET) + #define X86_64_ACCTON_AS9817_32_MEMSET GLOBAL_MEMSET + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_MEMSET memset + #else + #error The macro X86_64_ACCTON_AS9817_32_MEMSET is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_MEMCPY + #if defined(GLOBAL_MEMCPY) + #define X86_64_ACCTON_AS9817_32_MEMCPY GLOBAL_MEMCPY + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_MEMCPY memcpy + #else + #error The macro X86_64_ACCTON_AS9817_32_MEMCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_STRNCPY + #if defined(GLOBAL_STRNCPY) + #define X86_64_ACCTON_AS9817_32_STRNCPY GLOBAL_STRNCPY + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_STRNCPY strncpy + #else + #error The macro X86_64_ACCTON_AS9817_32_STRNCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_VSNPRINTF + #if defined(GLOBAL_VSNPRINTF) + #define X86_64_ACCTON_AS9817_32_VSNPRINTF GLOBAL_VSNPRINTF + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_VSNPRINTF vsnprintf + #else + #error The macro X86_64_ACCTON_AS9817_32_VSNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_SNPRINTF + #if defined(GLOBAL_SNPRINTF) + #define X86_64_ACCTON_AS9817_32_SNPRINTF GLOBAL_SNPRINTF + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_SNPRINTF snprintf + #else + #error The macro X86_64_ACCTON_AS9817_32_SNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9817_32_STRLEN + #if defined(GLOBAL_STRLEN) + #define X86_64_ACCTON_AS9817_32_STRLEN GLOBAL_STRLEN + #elif X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9817_32_STRLEN strlen + #else + #error The macro X86_64_ACCTON_AS9817_32_STRLEN is required but cannot be defined. + #endif +#endif + +/* */ + + +#endif /* __x86_64_accton_as9817_32_PORTING_H__ */ +/* @} */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/make.mk b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/make.mk new file mode 100644 index 0000000000..2de0d0cb0e --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/make.mk @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### +THIS_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +x86_64_accton_as9817_32_INCLUDES := -I $(THIS_DIR)inc +x86_64_accton_as9817_32_INTERNAL_INCLUDES := -I $(THIS_DIR)src +x86_64_accton_as9817_32_DEPENDMODULE_ENTRIES := init:x86_64_accton_as9817_32 ucli:x86_64_accton_as9817_32 diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/Makefile b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/Makefile new file mode 100644 index 0000000000..24bf28329b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/Makefile @@ -0,0 +1,8 @@ +############################################################################### +# +# Local source generation targets. +# +############################################################################### + +ucli: + @../../../../tools/uclihandlers.py x86_64_accton_as9817_32_ucli.c diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/debug.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/debug.c new file mode 100644 index 0000000000..43948a86c4 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/debug.c @@ -0,0 +1,68 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include "x86_64_accton_as9817_32_int.h" + +#if x86_64_accton_as9817_32_CONFIG_INCLUDE_DEBUG == 1 + +#include + +static char help__[] = + "Usage: debug [options]\n" + " -c CPLD Versions\n" + " -h Help\n" + ; + +int +x86_64_accton_as9817_32_debug_main(int argc, char* argv[]) +{ + int c = 0; + int help = 0; + int rv = 0; + + while( (c = getopt(argc, argv, "ch")) != -1) { + switch(c) + { + case 'c': c = 1; break; + case 'h': help = 1; rv = 0; break; + default: help = 1; rv = 1; break; + } + + } + + if(help || argc == 1) { + printf("%s", help__); + return rv; + } + + if(c) { + printf("Not implemented.\n"); + } + + + return 0; +} + +#endif diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c new file mode 100644 index 0000000000..5cabfcf9f4 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c @@ -0,0 +1,299 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * Fan Platform Implementation Defaults. + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +enum fan_id { + FAN_1_ON_FAN_BOARD = 1, + FAN_2_ON_FAN_BOARD, + FAN_3_ON_FAN_BOARD, + FAN_4_ON_FAN_BOARD, + FAN_5_ON_FAN_BOARD, + FAN_6_ON_FAN_BOARD, + FAN_7_ON_FAN_BOARD, + FAN_8_ON_FAN_BOARD, + FAN_9_ON_FAN_BOARD, + FAN_10_ON_FAN_BOARD, + FAN_11_ON_FAN_BOARD, + FAN_12_ON_FAN_BOARD, + FAN_13_ON_FAN_BOARD, + FAN_14_ON_FAN_BOARD, + FAN_1_ON_PSU_1, + FAN_1_ON_PSU_2 +}; + +#define MAX_PSU_FAN_SPEED 25500 + +#define CHASSIS_FAN_INFO(fid) \ + { \ + { ONLP_FAN_ID_CREATE(FAN_##fid##_ON_FAN_BOARD), "Chassis Fan - "#fid, 0, {0} },\ + 0x0,\ + ONLP_FAN_CAPS_SET_PERCENTAGE | ONLP_FAN_CAPS_GET_RPM | ONLP_FAN_CAPS_GET_PERCENTAGE,\ + 0,\ + 0,\ + ONLP_FAN_MODE_INVALID,\ + } + +#define PSU_FAN_INFO(pid, fid) \ + { \ + { ONLP_FAN_ID_CREATE(FAN_##fid##_ON_PSU_##pid), "PSU "#pid" - Fan "#fid, 0, {0} },\ + 0x0,\ + ONLP_FAN_CAPS_GET_RPM | ONLP_FAN_CAPS_GET_PERCENTAGE,\ + 0,\ + 0,\ + ONLP_FAN_MODE_INVALID,\ + } + +/* Static fan information */ +onlp_fan_info_t finfo[] = { + { }, /* Not used */ + CHASSIS_FAN_INFO(1), + CHASSIS_FAN_INFO(2), + CHASSIS_FAN_INFO(3), + CHASSIS_FAN_INFO(4), + CHASSIS_FAN_INFO(5), + CHASSIS_FAN_INFO(6), + CHASSIS_FAN_INFO(7), + CHASSIS_FAN_INFO(8), + CHASSIS_FAN_INFO(9), + CHASSIS_FAN_INFO(10), + CHASSIS_FAN_INFO(11), + CHASSIS_FAN_INFO(12), + CHASSIS_FAN_INFO(13), + CHASSIS_FAN_INFO(14), + PSU_FAN_INFO(1,1), + PSU_FAN_INFO(2,1) +}; + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_FAN(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static int +_onlp_fani_set_fan_dir_info(int fid, onlp_fan_info_t* info) +{ + enum onlp_fan_dir dir = onlp_get_fan_dir(fid); + + if (FAN_DIR_F2B == dir) { + info->caps |= ONLP_FAN_CAPS_F2B; + info->status |= ONLP_FAN_STATUS_F2B; + } + else { + info->caps |= ONLP_FAN_CAPS_B2F; + info->status |= ONLP_FAN_STATUS_B2F; + } + + return ONLP_STATUS_OK; +} + +static int +_onlp_fani_info_get_fan(int fid, onlp_fan_info_t* info) +{ + int value, ret, pwm; + + /* get fan present status + */ + ret = onlp_file_read_int(&value, FAN_SYSFS_FORMAT"fan%d_present", fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + if (value == 0) { + return ONLP_STATUS_OK; + } + info->status |= ONLP_FAN_STATUS_PRESENT; + + /* get fan fault status (turn on when any one fails) + */ + ret = onlp_file_read_int(&value, "%s""fan%d_fault", FAN_SYSFS_FORMAT, fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + if (value > 0) { + info->status |= ONLP_FAN_STATUS_FAILED; + return ONLP_STATUS_OK; + } + + /* get fan speed + */ + ret = onlp_file_read_int(&value, "%s""fan%d_input", FAN_SYSFS_FORMAT, fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + info->rpm = value; + + /* get speed percentage from rpm + */ + pwm = 0; + ret = onlp_file_read_int(&pwm, "%s""fan%d_pwm", FAN_SYSFS_FORMAT, fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + value = 0; + ret = onlp_file_read_int(&value, "%s""fan%d_target", FAN_SYSFS_FORMAT, fid); + if (ret < 0 || value == 0) { + return ONLP_STATUS_E_INTERNAL; + } + + info->percentage = (info->rpm*pwm)/value; + if (info->percentage > 100) + info->percentage = 100; + + _onlp_fani_set_fan_dir_info(fid, info); + + return ONLP_STATUS_OK; +} + +static int +_onlp_fani_info_get_fan_on_psu(int pid, onlp_fan_info_t* info) +{ + char *str = NULL; + int len = 0; + int val = 0; + int ret = 0; + int hwmon_idx; + + info->status |= ONLP_FAN_STATUS_PRESENT; + + /* get fan direction + */ + hwmon_idx = onlp_get_psu_hwmon_idx(pid); + if (hwmon_idx >= 0) { + char file[32]; + snprintf(file, sizeof(file), "psu%d_fan_dir", pid); + + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + if (str && len >= 3) { + if (strncmp(str, "B2F", strlen("B2F")) == 0) { + info->status |= ONLP_FAN_STATUS_B2F; + } + else { + info->status |= ONLP_FAN_STATUS_F2B; + } + } + AIM_FREE_IF_PTR(str); + } + + /* get fan speed + */ + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "fan1_input"); + if (ret < 0) { + AIM_LOG_WARN("Unable to read status from PSU(%d)\r\n", pid); + } else { + info->rpm = val; + info->percentage = (info->rpm * 100)/MAX_PSU_FAN_SPEED; + } + + ret = onlp_get_psu_power_good(pid); + if (ret != ONLP_STATUS_OK) { + info->status |= ONLP_FAN_STATUS_FAILED; + } + + return ONLP_STATUS_OK; +} + +/* + * This function will be called prior to all of onlp_fani_* functions. + */ +int +onlp_fani_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_fani_info_get(onlp_oid_t id, onlp_fan_info_t* info) +{ + int rc = 0; + int fid; + VALIDATE(id); + + fid = ONLP_OID_ID_GET(id); + *info = finfo[fid]; + + switch (fid) { + case FAN_1_ON_FAN_BOARD: + case FAN_2_ON_FAN_BOARD: + case FAN_3_ON_FAN_BOARD: + case FAN_4_ON_FAN_BOARD: + case FAN_5_ON_FAN_BOARD: + case FAN_6_ON_FAN_BOARD: + case FAN_7_ON_FAN_BOARD: + case FAN_8_ON_FAN_BOARD: + case FAN_9_ON_FAN_BOARD: + case FAN_10_ON_FAN_BOARD: + case FAN_11_ON_FAN_BOARD: + case FAN_12_ON_FAN_BOARD: + case FAN_13_ON_FAN_BOARD: + case FAN_14_ON_FAN_BOARD: + rc = _onlp_fani_info_get_fan(fid, info); + break; + case FAN_1_ON_PSU_1: + case FAN_1_ON_PSU_2: + rc = _onlp_fani_info_get_fan_on_psu(fid-FAN_14_ON_FAN_BOARD, info); + break; + default: + rc = ONLP_STATUS_E_INVALID; + break; + } + + return rc; +} + +/* + * This function sets the fan speed of the given OID as a percentage. + * + * This will only be called if the OID has the PERCENTAGE_SET + * capability. + * + * It is optional if you have no fans at all with this feature. + */ +int +onlp_fani_percentage_set(onlp_oid_t id, int p) +{ + int fid; + + VALIDATE(id); + + fid = ONLP_OID_ID_GET(id); + + if (fid < FAN_1_ON_FAN_BOARD || fid > FAN_14_ON_FAN_BOARD) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + if (onlp_file_write_int(p, "%s""fan%d_pwm", FAN_SYSFS_FORMAT, fid) != 0) { + AIM_LOG_ERROR("Unable to change duty cycle of fan (%d)\r\n", fid); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/ledi.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/ledi.c new file mode 100644 index 0000000000..bd187e22aa --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/ledi.c @@ -0,0 +1,236 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2013 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_LED(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +#define LED_FORMAT "/sys/devices/platform/as9817_32_led/led_%s" + +enum led_light_mode { /*must be the same with the definition @ kernel driver */ + LED_MODE_OFF, + LED_MODE_RED = 10, + LED_MODE_RED_BLINKING = 11, + LED_MODE_ORANGE = 12, + LED_MODE_ORANGE_BLINKING = 13, + LED_MODE_YELLOW = 14, + LED_MODE_YELLOW_BLINKING = 15, + LED_MODE_GREEN = 16, + LED_MODE_GREEN_BLINKING = 17, + LED_MODE_BLUE = 18, + LED_MODE_BLUE_BLINKING = 19, + LED_MODE_PURPLE = 20, + LED_MODE_PURPLE_BLINKING = 21, + LED_MODE_AUTO = 22, + LED_MODE_AUTO_BLINKING = 23, + LED_MODE_WHITE = 24, + LED_MODE_WHITE_BLINKING = 25, + LED_MODE_CYAN = 26, + LED_MODE_CYAN_BLINKING = 27, + LED_MODE_UNKNOWN = 99 +}; + +typedef struct led_light_mode_map { + enum onlp_led_id id; + enum led_light_mode driver_led_mode; + enum onlp_led_mode_e onlp_led_mode; +} led_light_mode_map_t; + +led_light_mode_map_t led_map[] = { + { LED_LOC, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_LOC, LED_MODE_BLUE_BLINKING, ONLP_LED_MODE_BLUE_BLINKING }, + { LED_DIAG, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_DIAG, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_DIAG, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_PSU1, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_PSU1, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_PSU1, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_PSU2, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_PSU2, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_PSU2, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_FAN, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_FAN, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_FAN, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_ALARM, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_ALARM, LED_MODE_RED, ONLP_LED_MODE_RED } +}; + +static char *leds[] = { /* must map with onlp_led_id */ + NULL, + "loc", + "diag", + "psu1", + "psu2", + "fan", + "alarm", +}; + +/* + * Get the information for the given LED OID. + */ +static onlp_led_info_t linfo[] = +{ + { }, /* Not used */ + { + { ONLP_LED_ID_CREATE(LED_LOC), "Chassis LED 1 (LOC LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_BLUE_BLINKING, + }, + { + { ONLP_LED_ID_CREATE(LED_DIAG), "Chassis LED 2 (DIAG LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_PSU1), "Chassis LED 3 (PSU1 LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_PSU2), "Chassis LED 4 (PSU2 LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_FAN), "Chassis LED 5 (FAN LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_ALARM), "Chassis LED 6 (ALARM LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_RED, + }, +}; + +static int driver_to_onlp_led_mode(enum onlp_led_id id, enum led_light_mode driver_led_mode) +{ + int i, nsize = sizeof(led_map)/sizeof(led_map[0]); + + for (i = 0; i < nsize; i++) { + if (id == led_map[i].id && driver_led_mode == led_map[i].driver_led_mode) { + return led_map[i].onlp_led_mode; + } + } + + return 0; +} + +static int onlp_to_driver_led_mode(enum onlp_led_id id, onlp_led_mode_t onlp_led_mode) +{ + int i, nsize = sizeof(led_map)/sizeof(led_map[0]); + + for (i = 0; i < nsize; i++) { + if (id == led_map[i].id && onlp_led_mode == led_map[i].onlp_led_mode) { + return led_map[i].driver_led_mode; + } + } + + return 0; +} + +/* + * This function will be called prior to any other onlp_ledi_* functions. + */ +int +onlp_ledi_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t* info) +{ + int lid, value; + VALIDATE(id); + + lid = ONLP_OID_ID_GET(id); + + /* Set the onlp_oid_hdr_t and capabilities */ + *info = linfo[ONLP_OID_ID_GET(id)]; + + /* Get LED mode */ + if (onlp_file_read_int(&value, LED_FORMAT, leds[lid]) < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + info->mode = driver_to_onlp_led_mode(lid, value); + + /* Set the on/off status */ + if (info->mode != ONLP_LED_MODE_OFF) { + info->status |= ONLP_LED_STATUS_ON; + } + + return ONLP_STATUS_OK; +} + +/* + * Turn an LED on or off. + * + * This function will only be called if the LED OID supports the ONOFF + * capability. + * + * What 'on' means in terms of colors or modes for multimode LEDs is + * up to the platform to decide. This is intended as baseline toggle mechanism. + */ +int +onlp_ledi_set(onlp_oid_t id, int on_or_off) +{ + VALIDATE(id); + + if (!on_or_off) { + return onlp_ledi_mode_set(id, ONLP_LED_MODE_OFF); + } + + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * This function puts the LED into the given mode. It is a more functional + * interface for multimode LEDs. + * + * Only modes reported in the LED's capabilities will be attempted. + */ +int +onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode) +{ + int lid; + VALIDATE(id); + + lid = ONLP_OID_ID_GET(id); + + if (onlp_file_write_int(onlp_to_driver_led_mode(lid , mode), LED_FORMAT, leds[lid]) != 0) { + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/make.mk b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/make.mk new file mode 100644 index 0000000000..892b3c9439 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/make.mk @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### + +LIBRARY := x86_64_accton_as9817_32 +$(LIBRARY)_SUBDIR := $(dir $(lastword $(MAKEFILE_LIST))) +include $(BUILDER)/lib.mk diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c new file mode 100644 index 0000000000..da0b287bfc --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c @@ -0,0 +1,190 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include +#include "platform_lib.h" + +enum onlp_fan_dir onlp_get_fan_dir(int fid) +{ + int len = 0; + int i = 0; + int hwmon_idx; + char *str = NULL; + char *dirs[FAN_DIR_COUNT] = { "F2B", "B2F" }; + char file[32]; + enum onlp_fan_dir dir = FAN_DIR_F2B; + + hwmon_idx = onlp_get_fan_hwmon_idx(); + if (hwmon_idx >= 0) { + /* Read attribute */ + snprintf(file, sizeof(file), "fan%d_dir", fid); + len = onlp_file_read_str(&str, FAN_SYSFS_FORMAT_1, hwmon_idx, file); + + /* Verify Fan dir string length */ + if (!str || len < 3) { + AIM_FREE_IF_PTR(str); + return dir; + } + + for (i = 0; i < AIM_ARRAYSIZE(dirs); i++) { + if (strncmp(str, dirs[i], strlen(dirs[i])) == 0) { + dir = (enum onlp_fan_dir)i; + break; + } + } + + AIM_FREE_IF_PTR(str); + } + + return dir; +} + +int onlp_get_psu_hwmon_idx(int pid) +{ + /* find hwmon index */ + char* file = NULL; + char path[64]; + int ret, hwmon_idx, max_hwmon_idx = 20; + + for (hwmon_idx = 0; hwmon_idx <= max_hwmon_idx; hwmon_idx++) { + snprintf(path, sizeof(path), "/sys/devices/platform/as9817_32_psu.%d/hwmon/hwmon%d/", pid-1, hwmon_idx); + + ret = onlp_file_find(path, "name", &file); + AIM_FREE_IF_PTR(file); + + if (ONLP_STATUS_OK == ret) + return hwmon_idx; + } + + return -1; +} + +int onlp_get_psu_power_good(int pid) +{ + int ret = 0; + int val = 0; + + /* Get power good status */ + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "power_good"); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + if (val != PSU_STATUS_POWER_GOOD) { + return ONLP_STATUS_E_MISSING; + } + + return ONLP_STATUS_OK; +} + +int onlp_get_fan_hwmon_idx(void) +{ + /* find hwmon index */ + char* file = NULL; + char path[64]; + int ret, hwmon_idx, max_hwmon_idx = 20; + + for (hwmon_idx = 0; hwmon_idx <= max_hwmon_idx; hwmon_idx++) { + snprintf(path, sizeof(path), "/sys/devices/platform/as9817_32_fan/hwmon/hwmon%d/", hwmon_idx); + + ret = onlp_file_find(path, "name", &file); + AIM_FREE_IF_PTR(file); + + if (ONLP_STATUS_OK == ret) + return hwmon_idx; + } + + return -1; +} + +as9817_32_platform_id_t get_platform_id(void) +{ + int ret, pid = 0; + + ret = onlp_file_read_int(&pid, "/sys/devices/platform/as9817_32_fpga/platform_id"); + if (ONLP_STATUS_OK != ret) { + return PID_UNKNOWN; + } + + return (pid == 0) ? AS9817_32O : AS9817_32D; +} + +/** + * get_bmc_version - Get BMC version as int array + * @ver: int[3], ver[0]=major, ver[1]=minor, ver[2]=aux last byte + * + * Return: ONLP_STATUS_OK on success, or ONLP error code + */ +int get_bmc_version(int *ver) +{ + char *tmp; + char primary_fw_ver[32] = {0}; + char aux_fw_raw[64] = {0}; + const char *last_aux = NULL; + int len; + + if (!ver) { + return ONLP_STATUS_E_INVALID; + } + memset(ver, 0, sizeof(int) * 3); + + len = onlp_file_read_str(&tmp, BMC_VER1_PATH); + if (tmp && len) { + memcpy(primary_fw_ver, tmp, len); + primary_fw_ver[len] = '\0'; + } else { + return ONLP_STATUS_E_INTERNAL; + } + AIM_FREE_IF_PTR(tmp); + + len = onlp_file_read_str(&tmp, BMC_VER2_PATH); + if (tmp && len) { + memcpy(aux_fw_raw, tmp, len); + aux_fw_raw[len] = '\0'; + } else { + return ONLP_STATUS_E_INTERNAL; + } + AIM_FREE_IF_PTR(tmp); + + primary_fw_ver[strcspn(primary_fw_ver, "\n")] = '\0'; + aux_fw_raw[strcspn(aux_fw_raw, "\n")] = '\0'; + + /* Parse main version: "0.3" => ver[0]=0, ver[1]=3 */ + if (sscanf(primary_fw_ver, "%d.%d", &ver[0], &ver[1]) != 2) { + return ONLP_STATUS_E_INTERNAL; + } + + /* Get last AUX byte (e.g., from "0x00 0x00 0x00 0x02") */ + last_aux = strrchr(aux_fw_raw, ' '); + last_aux = last_aux ? last_aux + 1 : aux_fw_raw; + + if (sscanf(last_aux, "0x%x", &ver[2]) != 1) { + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h new file mode 100644 index 0000000000..add363487d --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h @@ -0,0 +1,116 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#ifndef __PLATFORM_LIB_H__ +#define __PLATFORM_LIB_H__ + +#include +#include +#include "x86_64_accton_as9817_32_log.h" + +#define CHASSIS_FAN_COUNT 14 +#define CHASSIS_THERMAL_COUNT 9 +#define CHASSIS_LED_COUNT 6 +#define CHASSIS_PSU_COUNT 2 +#define NUM_OF_THERMAL_PER_PSU 3 + +#define PSU1_ID 1 +#define PSU2_ID 2 + +#define PSU_STATUS_PRESENT 1 +#define PSU_STATUS_POWER_GOOD 1 + +#define PSU_SYSFS_FORMAT "/sys/devices/platform/as9817_32_psu.%d*psu%d_%s" +#define PSU_SYSFS_FORMAT_1 "/sys/devices/platform/as9817_32_psu.%d/hwmon/hwmon%d/%s" +#define FAN_SYSFS_FORMAT "/sys/devices/platform/as9817_32_fan*" +#define FAN_SYSFS_FORMAT_1 "/sys/devices/platform/as9817_32_fan/hwmon/hwmon%d/%s" +#define SYS_LED_PATH "/sys/devices/platform/as9817_32_led/" +#define IDPROM_PATH "/sys/bus/i2c/devices/35-0056/eeprom" +#define BIOS_VER_PATH "/sys/devices/virtual/dmi/id/bios_version" +#define BMC_FAN_CONTROLLER_PATH "/sys/devices/platform/as9817_32_sys/bmc_fan_controller" +#define BMC_THERMAL_DATA_PATH "/sys/devices/platform/as9817_32_sys/bmc_thermal_data" +#define FGPA_MAC_MIN_TEMP_PATH "/sys/devices/platform/as9817_32_fpga/mac_min_temp" +#define FGPA_MAC_MAX_TEMP_PATH "/sys/devices/platform/as9817_32_fpga/mac_max_temp" +#define BMC_VER1_PATH "/sys/devices/platform/ipmi_bmc.0/firmware_revision" +#define BMC_VER2_PATH "/sys/devices/platform/ipmi_bmc.0/aux_firmware_revision" + +enum onlp_thermal_id { + THERMAL_RESERVED = 0, + THERMAL_CPU_CORE, + THERMAL_1_ON_MAIN_BROAD, + THERMAL_2_ON_MAIN_BROAD, + THERMAL_3_ON_MAIN_BROAD, + THERMAL_4_ON_MAIN_BROAD, + THERMAL_5_ON_MAIN_BROAD, + THERMAL_6_ON_MAIN_BROAD, + THERMAL_7_ON_MAIN_BROAD, + THERMAL_8_ON_MAIN_BROAD, + THERMAL_1_ON_PSU1, + THERMAL_2_ON_PSU1, + THERMAL_3_ON_PSU1, + THERMAL_1_ON_PSU2, + THERMAL_2_ON_PSU2, + THERMAL_3_ON_PSU2, + THERMAL_COUNT +}; + +enum onlp_led_id { + LED_LOC = 1, + LED_DIAG, + LED_PSU1, + LED_PSU2, + LED_FAN, + LED_ALARM +}; + +enum onlp_fan_dir { + FAN_DIR_F2B, + FAN_DIR_B2F, + FAN_DIR_COUNT +}; + +typedef enum as9817_32_platform_id { + AS9817_32O, + AS9817_32D, + PID_UNKNOWN +} as9817_32_platform_id_t; + +enum onlp_fan_dir onlp_get_fan_dir(int fid); +int onlp_get_psu_hwmon_idx(int pid); +int onlp_get_psu_power_good(int pid); +int onlp_get_fan_hwmon_idx(void); +as9817_32_platform_id_t get_platform_id(void); +int get_bmc_version(int *ver); + +#define AIM_FREE_IF_PTR(p) \ + do \ + { \ + if (p) { \ + aim_free(p); \ + p = NULL; \ + } \ + } while (0) + +#endif /* __PLATFORM_LIB_H__ */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c new file mode 100644 index 0000000000..182c2eb323 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c @@ -0,0 +1,167 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_PSU(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +int +onlp_psui_init(void) +{ + return ONLP_STATUS_OK; +} + +/* + * Get all information about the given PSU oid. + */ +static onlp_psu_info_t pinfo[] = { + { }, /* Not used */ + { + { ONLP_PSU_ID_CREATE(PSU1_ID), "PSU-1", 0, {0} }, + }, + { + { ONLP_PSU_ID_CREATE(PSU2_ID), "PSU-2", 0, {0} }, + } +}; + +int +onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) +{ + int val = 0; + int ret = ONLP_STATUS_OK; + int pid = ONLP_OID_ID_GET(id); + int thermal_count = 0; + int hwmon_idx; + VALIDATE(id); + + memset(info, 0, sizeof(onlp_psu_info_t)); + *info = pinfo[pid]; /* Set the onlp_oid_hdr_t */ + + /* Get the present state */ + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "present"); + if (ret < 0) { + info->status &= ~ONLP_PSU_STATUS_PRESENT; + return ONLP_STATUS_E_INTERNAL; + } + + if (val != PSU_STATUS_PRESENT) { + info->status &= ~ONLP_PSU_STATUS_PRESENT; + return ONLP_STATUS_OK; + } + info->status |= ONLP_PSU_STATUS_PRESENT; + + ret = onlp_get_psu_power_good(pid); + if (ret != ONLP_STATUS_OK) { + info->status |= ONLP_PSU_STATUS_UNPLUGGED; + } else { + /* Set capability */ + info->caps = ONLP_PSU_CAPS_AC; + } + + /* Set the associated oid_table */ + thermal_count = CHASSIS_THERMAL_COUNT; + + info->hdr.coids[0] = ONLP_THERMAL_ID_CREATE(thermal_count + (pid-1)*NUM_OF_THERMAL_PER_PSU + 1); + info->hdr.coids[1] = ONLP_THERMAL_ID_CREATE(thermal_count + (pid-1)*NUM_OF_THERMAL_PER_PSU + 2); + info->hdr.coids[2] = ONLP_THERMAL_ID_CREATE(thermal_count + (pid-1)*NUM_OF_THERMAL_PER_PSU + 3); + info->hdr.coids[3] = ONLP_FAN_ID_CREATE(pid + CHASSIS_FAN_COUNT); + + /* Read voltage, current and power */ + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vin"); + if (ret == ONLP_STATUS_OK && val) { + info->mvin = val; + info->caps |= ONLP_PSU_CAPS_VIN; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iin"); + if (ret == ONLP_STATUS_OK && val) { + info->miin = val; + info->caps |= ONLP_PSU_CAPS_IIN; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pin"); + if (ret == ONLP_STATUS_OK && val) { + info->mpin = val; + info->caps |= ONLP_PSU_CAPS_PIN; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vout"); + if (ret == ONLP_STATUS_OK && val) { + info->mvout = val; + info->caps |= ONLP_PSU_CAPS_VOUT; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iout"); + if (ret == ONLP_STATUS_OK && val) { + info->miout = val; + info->caps |= ONLP_PSU_CAPS_IOUT; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pout"); + if (ret == ONLP_STATUS_OK && val) { + info->mpout = val; + info->caps |= ONLP_PSU_CAPS_POUT; + } + + hwmon_idx = onlp_get_psu_hwmon_idx(pid); + if (hwmon_idx >= 0) { + char *str = NULL; + int len; + char file[32]; + + /* Read model */ + snprintf(file, sizeof(file), "psu%d_model", pid); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + if (str && len) { + memcpy(info->model, str, len); + info->model[len] = '\0'; + } + AIM_FREE_IF_PTR(str); + + /* Read serial */ + snprintf(file, sizeof(file), "psu%d_serial", pid); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + if (str && len) { + memcpy(info->serial, str, len); + info->serial[len] = '\0'; + } + AIM_FREE_IF_PTR(str); + } + + return ret; +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sfpi.c new file mode 100644 index 0000000000..dd16aa5f3e --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sfpi.c @@ -0,0 +1,321 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2013 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include +#include "x86_64_accton_as9817_32_int.h" +#include "x86_64_accton_as9817_32_log.h" + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < 32 || _port > 33) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < 0 || _port > 31 ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define MODULE_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" +#define MODULE_PRESENT_FORMAT "/sys/devices/platform/as9817_32_fpga/module_present_%d" +#define MODULE_RXLOS_FORMAT "/sys/devices/platform/as9817_32_fpga/module_rx_los_%d" +#define MODULE_TXFAULT_FORMAT "/sys/devices/platform/as9817_32_fpga/module_tx_fault_%d" +#define MODULE_TXDISABLE_FORMAT "/sys/devices/platform/as9817_32_fpga/module_tx_disable_%d" +#define MODULE_RESET_FORMAT "/sys/devices/platform/as9817_32_fpga/module_reset_%d" +#define MODULE_LPMODE_FORMAT "/sys/devices/platform/as9817_32_fpga/module_lp_mode_%d" + +#define NUM_OF_SFP_PORT 34 +static const int port_bus_index[NUM_OF_SFP_PORT] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34 +}; + +#define PORT_BUS_INDEX(port) (port_bus_index[port]) + +/************************************************************ + * + * SFPI Entry Points + * + ***********************************************************/ +int +onlp_sfpi_init(void) +{ + /* Called at initialization time */ + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_bitmap_get(onlp_sfp_bitmap_t* bmap) +{ + /* + * Ports {1, 34} + */ + int p; + + AIM_BITMAP_CLR_ALL(bmap); + for(p = 0; p < NUM_OF_SFP_PORT; p++) { + AIM_BITMAP_SET(bmap, p); + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* bmap) +{ + /* + * Ports {33, 34} + */ + int p; + + AIM_BITMAP_CLR_ALL(bmap); + for(p = 32; p < NUM_OF_SFP_PORT; p++) { + int value; + + if (onlp_file_read_int(&value, MODULE_RXLOS_FORMAT, PORT_BUS_INDEX(p)) < 0) { + AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", p); + return ONLP_STATUS_E_INTERNAL; + } + if (value) { + AIM_BITMAP_SET(bmap, p); + } + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_is_present(int port) +{ + /* + * Return 1 if present. + * Return 0 if not present. + * Return < 0 if error. + */ + int present; + + if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return present; +} + +int +onlp_sfpi_eeprom_read(int port, uint8_t data[256]) +{ + /* + * Read the SFP eeprom into data[] + * + * Return MISSING if SFP is missing. + * Return OK if eeprom is read + */ + int size = 0; + memset(data, 0, 256); + + if(onlp_file_read(data, 256, &size, MODULE_EEPROM_FORMAT, PORT_BUS_INDEX(port)) != ONLP_STATUS_OK) { + AIM_LOG_ERROR("Unable to read eeprom from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + if (size != 256) { + AIM_LOG_ERROR("Unable to read eeprom from port(%d), size is different!\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_dom_read(int port, uint8_t data[256]) +{ + FILE* fp; + char file[64] = {0}; + + sprintf(file, MODULE_EEPROM_FORMAT, PORT_BUS_INDEX(port)); + fp = fopen(file, "r"); + if(fp == NULL) { + AIM_LOG_ERROR("Unable to open the eeprom device file of port(%d)", port); + return ONLP_STATUS_E_INTERNAL; + } + + if (fseek(fp, 256, SEEK_CUR) != 0) { + fclose(fp); + AIM_LOG_ERROR("Unable to set the file position indicator of port(%d)", port); + return ONLP_STATUS_E_INTERNAL; + } + + int ret = fread(data, 1, 256, fp); + fclose(fp); + if (ret != 256) { + AIM_LOG_ERROR("Unable to read the module_eeprom device file of port(%d)", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_dev_readb(int port, uint8_t devaddr, uint8_t addr) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_readb(bus, devaddr, addr, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_writeb(int port, uint8_t devaddr, uint8_t addr, uint8_t value) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_writeb(bus, devaddr, addr, value, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_readw(int port, uint8_t devaddr, uint8_t addr) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_readw(bus, devaddr, addr, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_writew(bus, devaddr, addr, value, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) +{ + switch(control) { + case ONLP_SFP_CONTROL_TX_DISABLE: { + VALIDATE_SFP(port); + + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_RESET: { + VALIDATE_QSFP(port); + + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_LP_MODE: { + VALIDATE_QSFP(port); + + if (onlp_file_write_int(value, MODULE_LPMODE_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + default: + break; + } + + return ONLP_STATUS_E_UNSUPPORTED; +} + +int +onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) +{ + switch(control) { + case ONLP_SFP_CONTROL_RX_LOS: { + VALIDATE_SFP(port); + + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + + case ONLP_SFP_CONTROL_TX_FAULT: { + VALIDATE_SFP(port); + + if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + + case ONLP_SFP_CONTROL_TX_DISABLE: { + VALIDATE_SFP(port); + + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_RESET_STATE: { + VALIDATE_QSFP(port); + + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_LP_MODE: { + VALIDATE_QSFP(port); + + if (onlp_file_read_int(value, MODULE_LPMODE_FORMAT, PORT_BUS_INDEX(port)) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + default: + break; + } + + return ONLP_STATUS_E_UNSUPPORTED; +} + +int +onlp_sfpi_denit(void) +{ + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sysi.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sysi.c new file mode 100644 index 0000000000..a998b7d164 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/sysi.c @@ -0,0 +1,610 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "platform_lib.h" + +#include "x86_64_accton_as9817_32_int.h" +#include "x86_64_accton_as9817_32_log.h" + +#define NUM_OF_QSFP_PORT 32 +#define TEMPERATURE_COMPENSATION (5.0f) +#define MAC_MAX_TEMP 90000 +#define MAC_XCVR_TEMP 70000 +#define BMC_FILE_RETRY_COUNT 3 // Retry count for file read/write operations +#define BMC_FILE_RETRY_DELAY_US 1000000 // Delay between retries (in microseconds, 1s) + +int onlp_sysi_get_max_xcvr_temp(int *temp, int *port_num); + +typedef struct { + const char* name; + const char* path; + int is_fan; +} cpld_version_entry_t; + +enum { + CPLD_IDX_FPGA = 0, + CPLD_IDX_CPLD1, + CPLD_IDX_CPLD2, + CPLD_IDX_DSCM, + CPLD_IDX_FAN, + NUM_OF_CPLD_VER +}; + +static const cpld_version_entry_t cpld_versions[NUM_OF_CPLD_VER] = { + { "FPGA", "/sys/devices/platform/as9817_32_sys/fpga_version", 0 }, + { "Port CPLD1", "/sys/devices/platform/as9817_32_fpga/cpld1_version", 0 }, + { "Port CPLD2", "/sys/devices/platform/as9817_32_fpga/cpld2_version", 0 }, + { "DSCM CPLD", "/sys/devices/platform/as9817_32_fpga/cpld3_version", 0 }, + { "Fan CPLD", "/sys/devices/platform/as9817_32_fan/hwmon/hwmon*/version", 1 } +}; + +const char* +onlp_sysi_platform_get(void) +{ + as9817_32_platform_id_t pid = get_platform_id(); + + switch (pid) { + case AS9817_32O: return "x86-64-accton-as9817-32o-r0"; + case AS9817_32D: return "x86-64-accton-as9817-32d-r0"; + default: break; + } + + return "Unknown Platform"; +} + +int +onlp_sysi_onie_data_get(uint8_t** data, int* size) +{ + uint8_t* rdata = aim_zmalloc(256); + if (onlp_file_read(rdata, 256, size, IDPROM_PATH) == ONLP_STATUS_OK) { + if(*size == 256) { + *data = rdata; + return ONLP_STATUS_OK; + } + } + + aim_free(rdata); + *size = 0; + return ONLP_STATUS_E_INTERNAL; +} + +void +onlp_sysi_onie_data_free(uint8_t* data) +{ + AIM_FREE_IF_PTR(data); +} + +int +onlp_sysi_oids_get(onlp_oid_t* table, int max) +{ + int i; + onlp_oid_t* e = table; + memset(table, 0, max*sizeof(onlp_oid_t)); + + /* 9 Thermal sensors on the chassis */ + for (i = 1; i <= CHASSIS_THERMAL_COUNT; i++) { + *e++ = ONLP_THERMAL_ID_CREATE(i); + } + + /* 6 LEDs on the chassis */ + for (i = 1; i <= CHASSIS_LED_COUNT; i++) { + *e++ = ONLP_LED_ID_CREATE(i); + } + + /* 2 PSUs on the chassis */ + for (i = 1; i <= CHASSIS_PSU_COUNT; i++) { + *e++ = ONLP_PSU_ID_CREATE(i); + } + + /* 14 Fans on the chassis */ + for (i = 1; i <= CHASSIS_FAN_COUNT; i++) { + *e++ = ONLP_FAN_ID_CREATE(i); + } + + return 0; +} + + +void convert_version_format(const char *input, char *output, size_t output_size) { + int major, minor; + + if (sscanf(input, "%d.%d", &major, &minor) == 2) { + snprintf(output, output_size, "%02X.%02X", major, minor); + } + else if (sscanf(input, "%d", &major) == 1) { + snprintf(output, output_size, "%02X", major); + } + else { + snprintf(output, output_size, "ERR"); + } +} + +int +onlp_sysi_platform_info_get(onlp_platform_info_t* pi) +{ + int i, len; + char *v[NUM_OF_CPLD_VER] = {NULL}; + char n[NUM_OF_CPLD_VER][8] = {0}; + onlp_onie_info_t onie; + char *bios_ver = NULL; + char *bmc_buf = NULL; + char *aux_buf = NULL; + int bmc_major = 0, bmc_minor = 0; + unsigned int bmc_aux[4] = {0}; + char bmc_ver[16] = ""; + const char *bios = ""; + const char *onie_ver = ""; + + for (i = 0; i < AIM_ARRAYSIZE(cpld_versions); i++) { + if (cpld_versions[i].is_fan) { + int hwmon_idx = onlp_get_fan_hwmon_idx(); + + if (hwmon_idx < 0) { + continue; + } + + len = onlp_file_read_str(&v[i], FAN_SYSFS_FORMAT_1, hwmon_idx, "version"); + } + else { + len = onlp_file_read_str(&v[i], cpld_versions[i].path); + } + + if (v[i] == NULL || len <= 0) { + continue; + } + + convert_version_format(v[i], n[i], sizeof(n[i])); + } + + pi->cpld_versions = aim_fstrdup("\r\n\t %s: %s" + "\r\n\t %s: %s" + "\r\n\t %s: %s" + "\r\n\t %s: %s" + "\r\n\t %s: %s", + cpld_versions[CPLD_IDX_FPGA].name, n[CPLD_IDX_FPGA], + cpld_versions[CPLD_IDX_CPLD1].name, n[CPLD_IDX_CPLD1], + cpld_versions[CPLD_IDX_CPLD2].name, n[CPLD_IDX_CPLD2], + cpld_versions[CPLD_IDX_DSCM].name, n[CPLD_IDX_DSCM], + cpld_versions[CPLD_IDX_FAN].name, n[CPLD_IDX_FAN]); + + for (i = 0; i < AIM_ARRAYSIZE(v); i++) { + AIM_FREE_IF_PTR(v[i]); + } + + if ((onlp_file_read_str(&bmc_buf, BMC_VER1_PATH) >= 0) && + (onlp_file_read_str(&aux_buf, BMC_VER2_PATH) >= 0)) + { + bmc_buf[strcspn(bmc_buf, "\n")] = '\0'; + aux_buf[strcspn(aux_buf, "\n")] = '\0'; + + /* + * NOTE: The value in /sys/devices/platform/ipmi_bmc.0/firmware_revision is formatted + * using "%u.%x" in the kernel driver (see ipmi_msghandler.c::firmware_revision_show). + * The second field (after the dot) is output in hexadecimal format and must be parsed + * using "%x" from user-space. + */ + if (sscanf(bmc_buf, "%u.%x", &bmc_major, &bmc_minor) == 2 && + sscanf(aux_buf, "0x%x 0x%x 0x%x 0x%x", &bmc_aux[0], &bmc_aux[1], &bmc_aux[2], &bmc_aux[3]) == 4) + { + snprintf(bmc_ver, sizeof(bmc_ver), "%02X.%02X.%02X", + bmc_major, bmc_minor, bmc_aux[3]); + } + } + + if (onlp_file_read_str(&bios_ver, BIOS_VER_PATH) > 0) { + bios = bios_ver; + } + if (onlp_onie_decode_file(&onie, IDPROM_PATH) >= 0) { + onie_ver = onie.onie_version; + } + + pi->other_versions = aim_fstrdup("\r\n\t BIOS: %s\r\n\t ONIE: %s\r\n\t BMC: %s", + bios, onie_ver, bmc_ver); + + AIM_FREE_IF_PTR(bmc_buf); + AIM_FREE_IF_PTR(aux_buf); + AIM_FREE_IF_PTR(bios_ver); + onlp_onie_info_free(&onie); + + return ONLP_STATUS_OK; +} + +void +onlp_sysi_platform_info_free(onlp_platform_info_t* pi) +{ + AIM_FREE_IF_PTR(pi->cpld_versions); + AIM_FREE_IF_PTR(pi->other_versions); +} + +/** + * Reads a 32-bit frequency value from sysfs file (formatted as 4 space-separated hex bytes), + * and converts it into temperature in Celsius using a datasheet-defined formula. + * + * Expected input file content format: "A0 A1 A2 A3" + * + * Datasheet Formula: + * Period = (Data + 1) x 80 ns + * Period = 1 / freq + * -> Data = (1 / freq / 80e-9) - 1 + * -> Temp = -0.317704 x Data + 476.359 + * + * @param file_path Path to the file containing the 32-bit frequency as 4 hex values. + * @param temp Pointer to store the resulting temperature in Celsius + * @return ONLP_STATUS_OK if successful; + * ONLP_STATUS_E_MISSING if I2C read fails, frequency is 0, + * or calculated Data is out of expected range. + */ +int get_mac_temperature_from_fpga(const char *file_path, float *temp) +{ + uint8_t bytes[4] = {0, 0, 0, 0}; + uint32_t freq = 0; + int ret; + double period, data; + char *tmp = NULL; + + if (file_path == NULL || temp == NULL) { + AIM_LOG_ERROR("Null pointer passed for file_path or temperature result\n"); + return ONLP_STATUS_E_MISSING; + } + + ret = onlp_file_read_str(&tmp, file_path); + if (ret <= 0) { + AIM_LOG_ERROR("Failed to read 4-byte frequency from %s\n", file_path); + return ONLP_STATUS_E_MISSING; + } + ret = sscanf(tmp, "%x %x %x %x", + (unsigned int *)&bytes[0], + (unsigned int *)&bytes[1], + (unsigned int *)&bytes[2], + (unsigned int *)&bytes[3]); + if (ret != 4) { + AIM_FREE_IF_PTR(tmp); + AIM_LOG_ERROR("Expected 4 hex values from %s, got %d\n", file_path, ret); + return ONLP_STATUS_E_MISSING; + } + AIM_FREE_IF_PTR(tmp); + + freq = ((uint32_t)bytes[0]) | + ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | + ((uint32_t)bytes[3] << 24); + + if (freq == 0) { + AIM_SYSLOG_WARN("Temperature warning", "Temperature warning", + "Invalid MAC temperature detected! " + "Please check the FPGA firmware version."); + return ONLP_STATUS_E_MISSING; + } + + period = 1.0 / (double)freq; + data = (period / 80e-9) - 1.0; + + if (data < 0.0 || data > 2047.0) { + AIM_LOG_ERROR("ADC data %.2f out of range\n", data); + return ONLP_STATUS_E_MISSING; + } + + *temp = (float)(-0.317704 * data + 476.359); + return ONLP_STATUS_OK; +} + +int onlp_sysi_get_mac_temp(int *temp) +{ + int ret; + float min_temp, max_temp; + + ret = get_mac_temperature_from_fpga(FGPA_MAC_MIN_TEMP_PATH, &min_temp); + if (ret != ONLP_STATUS_OK) { + return ret; + } + ret = get_mac_temperature_from_fpga(FGPA_MAC_MAX_TEMP_PATH, &max_temp); + if (ret != ONLP_STATUS_OK) { + return ret; + } + + *temp = (int)(((min_temp + max_temp) / 2.0f) + TEMPERATURE_COMPENSATION); + *temp *= 1000; + + return ONLP_STATUS_OK; +} + +int onlp_sysi_get_xcvr_presence(void) +{ + onlp_sfp_bitmap_t bitmap; + onlp_sfp_bitmap_t_init(&bitmap); + onlp_sfp_presence_bitmap_get(&bitmap); + + /* Ignore SFP */ + AIM_BITMAP_CLR(&bitmap, 32); + AIM_BITMAP_CLR(&bitmap, 33); + return !(AIM_BITMAP_COUNT(&bitmap) == 0); +} + +int onlp_sysi_get_sff8436_temp(int port, int *temp) +{ + int value; + int16_t port_temp; + + /* Read memory model */ + value = onlp_sfpi_dev_readb(port, 0x50, 0x2); + if (value & 0x04) { + *temp = ONLP_STATUS_E_MISSING; + return ONLP_STATUS_OK; + } + + value = onlp_sfpi_dev_readb(port, 0x50, 22); + if (value < 0) { + *temp = ONLP_STATUS_E_MISSING; + return ONLP_STATUS_OK; + } + port_temp = (int16_t)((value & 0xFF) << 8); + + value = onlp_sfpi_dev_readb(port, 0x50, 23); + if (value < 0) { + *temp = ONLP_STATUS_E_MISSING; + return ONLP_STATUS_OK; + } + port_temp = (port_temp | (int16_t)(value & 0xFF)); + + *temp = (int)port_temp * 1000 / 256; + return ONLP_STATUS_OK; +} + +int onlp_sysi_get_cmis_temp(int port, int *temp) +{ + int value; + int16_t port_temp; + + /* Read memory model */ + value = onlp_sfpi_dev_readb(port, 0x50, 0x2); + if (value & 0x80) { + *temp = ONLP_STATUS_E_MISSING; + return ONLP_STATUS_OK; + } + + value = onlp_sfpi_dev_readb(port, 0x50, 14); + if (value < 0) { + *temp = ONLP_STATUS_E_MISSING; + return ONLP_STATUS_OK; + } + port_temp = (int16_t)((value & 0xFF) << 8); + + value = onlp_sfpi_dev_readb(port, 0x50, 15); + if (value < 0) { + *temp = ONLP_STATUS_E_MISSING; + return ONLP_STATUS_OK; + } + port_temp = (port_temp | (int16_t)(value & 0xFF)); + + *temp = (int)port_temp * 1000 / 256; + return ONLP_STATUS_OK; +} + +int onlp_sysi_get_max_xcvr_temp(int *temp, int *port_num) +{ + int ret = ONLP_STATUS_OK; + int value, port; + int port_temp = MAC_XCVR_TEMP; + int max_temp_port = ONLP_STATUS_E_MISSING, max_temp = ONLP_STATUS_E_MISSING; + + *temp = ONLP_STATUS_E_MISSING; + *port_num = ONLP_STATUS_E_MISSING; + + if (!onlp_sysi_get_xcvr_presence()) { + return ONLP_STATUS_OK; + } + + for (port = 0; port < NUM_OF_QSFP_PORT; port++) { + if (!onlp_sfpi_is_present(port)) { + continue; + } + + value = onlp_sfpi_dev_readb(port, 0x50, 0); + if (value < 0) { + AIM_LOG_ERROR("Unable to get read port(%d) eeprom\r\n", port); + continue; + } + + if (value == 0x18 || value == 0x19 || value == 0x1E || value == 0x1B) { + ret = onlp_sysi_get_cmis_temp(port, &port_temp); + if (ret != ONLP_STATUS_OK) { + continue; + } + } + else if (value == 0x0C || value == 0x0D || value == 0x11 || value == 0xE1) { + ret = onlp_sysi_get_sff8436_temp(port, &port_temp); + if (ret != ONLP_STATUS_OK) { + continue; + } + } + else { + continue; + } + + if (port_temp > max_temp) { + max_temp = port_temp; + max_temp_port = port + 1; + } + } + + *temp = max_temp; + *port_num = max_temp_port; + return ONLP_STATUS_OK; +} + +/* + * Send thermal data (MAC temp, XCVR temp, port number) to BMC. + * + * This writes to the BMC thermal policy interface, equivalent to: + * ipmitool raw 0x34 0x13 + * + * Temperatures are in millidegree Celsius and converted to degrees Celsius before sending. + * + * @param mac_temp MAC sensor temperature in milli-degrees Celsius + * @param xcvr_temp Transceiver temperature in milli-degrees Celsius + * @param xcvr_num Transceiver port number + * + * @return ONLP_STATUS_OK on success + * ONLP_STATUS_E_INTERNAL if formatting fails + * ONLP_STATUS_E_MISSING if writing to BMC fails + */ +int send_thermal_data_to_bmc(int mac_temp, int xcvr_temp, int xcvr_num) +{ + char data[32]; + int ret = ONLP_STATUS_E_INTERNAL; + + ret = snprintf(data, sizeof(data), "%d %d %d", + (mac_temp / 1000), (xcvr_temp / 1000), xcvr_num); + if (ret < 0 || ret >= (int)sizeof(data)) { + AIM_LOG_WARN("snprintf failed or truncated: mac=%d xcvr=%d port=%d (ret=%d)\n", + mac_temp, xcvr_temp, xcvr_num, ret); + return ONLP_STATUS_E_INTERNAL; + } + + for (int i = 0; i < BMC_FILE_RETRY_COUNT; i++) { + ret = onlp_file_write_str(data, BMC_THERMAL_DATA_PATH); + if (ret == ONLP_STATUS_OK) { + return ONLP_STATUS_OK; + } + usleep(BMC_FILE_RETRY_DELAY_US); + } + + AIM_LOG_ERROR("Failed to write '%s' to %s", data , BMC_THERMAL_DATA_PATH); + return ONLP_STATUS_E_MISSING; +} + +/* + * Control BMC thermal policy by collecting and sending temperature data. + * + *This function performs the following: + * . Checks if the current BMC firmware version supports thermal policy. + * . Enables the BMC thermal policy if it is not already enabled. + * . Reads MAC and transceiver temperatures via registered readers. + * . Sends the collected data to the BMC for thermal management. + * + * @return ONLP_STATUS_OK on success, + * ONLP_STATUS_E_MISSING if: + * - BMC version is below the minimum required, + * - enabling the policy fails, + * - or sending thermal data fails. + */ +int control_thermal_policy_via_bmc(void) +{ + int ret; + int mac_temp; + int port_temp, port_number; + + ret = onlp_sysi_get_mac_temp(&mac_temp); + if (ret != ONLP_STATUS_OK) { + mac_temp = MAC_MAX_TEMP; + } + + ret = onlp_sysi_get_max_xcvr_temp(&port_temp, &port_number); + if (ret != ONLP_STATUS_OK || + /* No transceiver detected. */ + port_temp == ONLP_STATUS_E_MISSING || + port_number == ONLP_STATUS_E_MISSING) { + /* + * If port_number is 0, the BMC will ignore the transceiver temperature. + */ + port_temp = 0; + port_number = 0; + } + + return send_thermal_data_to_bmc(mac_temp, port_temp, port_number); +} + +static pthread_mutex_t thermal_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t thermal_cond = PTHREAD_COND_INITIALIZER; +static bool thermal_thread_started = false; +static bool thermal_thread_waiting = false; +static pthread_t thermal_thread; +/* + * Thermal policy thread loop. + * + * This background thread waits for a condition signal and runs the thermal policy. + * It uses a condition variable to sleep until triggered, and only one instance runs at a time. + * + * Note: Signals are ignored if the thread is busy. No event queueing. + */ +void *thermal_policy_thread_loop(void *arg) +{ + while (1) { + pthread_mutex_lock(&thermal_lock); + thermal_thread_waiting = true; + pthread_cond_wait(&thermal_cond, &thermal_lock); + thermal_thread_waiting = false; + pthread_mutex_unlock(&thermal_lock); + + control_thermal_policy_via_bmc(); + } + + return NULL; +} + +/* + * Launch the thermal policy thread once. + */ +void start_thermal_policy_thread_once(void) +{ + pthread_mutex_lock(&thermal_lock); + if (!thermal_thread_started) { + thermal_thread_started = true; + if (pthread_create(&thermal_thread, NULL, thermal_policy_thread_loop, NULL) != 0) { + AIM_LOG_ERROR("Failed to start thermal policy thread."); + thermal_thread_started = false; + } else { + pthread_detach(thermal_thread); + thermal_thread_waiting = true; + AIM_LOG_INFO("Thermal policy thread started."); + } + } + pthread_mutex_unlock(&thermal_lock); +} + +/* + * Called periodically to trigger thermal policy evaluation. + */ +int onlp_sysi_platform_manage_fans(void) +{ + start_thermal_policy_thread_once(); + + pthread_mutex_lock(&thermal_lock); + if (thermal_thread_waiting) { + pthread_cond_signal(&thermal_cond); + } else { + AIM_LOG_INFO("Thermal policy thread is busy; skipping this trigger."); + } + pthread_mutex_unlock(&thermal_lock); + + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c new file mode 100644 index 0000000000..87dac9afff --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c @@ -0,0 +1,172 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * Thermal Sensor Platform Implementation. + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_THERMAL(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static char* devfiles__[] = { /* must map with onlp_thermal_id */ + NULL, + NULL, /* CPU_CORE files */ + "/sys/devices/platform/as9817_32_thermal*temp1_input", + "/sys/devices/platform/as9817_32_thermal*temp2_input", + "/sys/devices/platform/as9817_32_thermal*temp3_input", + "/sys/devices/platform/as9817_32_thermal*temp4_input", + "/sys/devices/platform/as9817_32_thermal*temp5_input", + "/sys/devices/platform/as9817_32_thermal*temp6_input", + "/sys/devices/platform/as9817_32_thermal*temp7_input", + "/sys/devices/platform/as9817_32_thermal*temp8_input", + "/sys/devices/platform/as9817_32_psu.0*psu1_temp1_input", + "/sys/devices/platform/as9817_32_psu.0*psu1_temp2_input", + "/sys/devices/platform/as9817_32_psu.0*psu1_temp3_input", + "/sys/devices/platform/as9817_32_psu.1*psu2_temp1_input", + "/sys/devices/platform/as9817_32_psu.1*psu2_temp2_input", + "/sys/devices/platform/as9817_32_psu.1*psu2_temp3_input" +}; + +static char* cpu_coretemp_files[] = { + "/sys/devices/platform/coretemp.0*temp1_input", + "/sys/devices/platform/coretemp.0*temp2_input", + "/sys/devices/platform/coretemp.0*temp3_input", + "/sys/devices/platform/coretemp.0*temp4_input", + "/sys/devices/platform/coretemp.0*temp5_input", + NULL, +}; + +/* Static values */ +static onlp_thermal_info_t tinfo[] = { + { }, /* Not used */ + { { ONLP_THERMAL_ID_CREATE(THERMAL_CPU_CORE), "CPU Core", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 90000, 100000, 100000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_MAIN_BROAD), "MB_RearCenter_temp(0x48)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 70900, 80900, 85900 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_MAIN_BROAD), "MB_RearRight_temp(0x49)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 58600, 68600, 73600 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_MAIN_BROAD), "MB_RearCenter_temp(0x4A)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 74800, 84800, 89800 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_4_ON_MAIN_BROAD), "MB_RearLeft_temp(0x4B)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 68400, 78400, 83400 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_5_ON_MAIN_BROAD), "MB_FrontLeft_temp(0x4C)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 73000, 83000, 88000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_6_ON_MAIN_BROAD), "MB_FrontRight_temp(0x4D)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 59100, 69100, 74100 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_7_ON_MAIN_BROAD), "FB_temp(0x4D)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 60800, 70800, 75800 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_8_ON_MAIN_BROAD), "FB_temp(0x4E)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 60900, 70900, 75900 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_PSU1), "PSU-1 Thermal Sensor 1", ONLP_PSU_ID_CREATE(PSU1_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 70000, 75000, 75000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_PSU1), "PSU-1 Thermal Sensor 2", ONLP_PSU_ID_CREATE(PSU1_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 125000, 130000, 130000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_PSU1), "PSU-1 Thermal Sensor 3", ONLP_PSU_ID_CREATE(PSU1_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 110000, 115000, 115000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_PSU2), "PSU-2 Thermal Sensor 1", ONLP_PSU_ID_CREATE(PSU2_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 70000, 75000, 75000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_PSU2), "PSU-2 Thermal Sensor 2", ONLP_PSU_ID_CREATE(PSU2_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 125000, 130000, 130000 } + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_PSU2), "PSU-2 Thermal Sensor 3", ONLP_PSU_ID_CREATE(PSU2_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, { 110000, 115000, 115000 } + } +}; + +/* + * This will be called to intiialize the thermali subsystem. + */ +int +onlp_thermali_init(void) +{ + return ONLP_STATUS_OK; +} + +/* + * Retrieve the information structure for the given thermal OID. + * + * If the OID is invalid, return ONLP_E_STATUS_INVALID. + * If an unexpected error occurs, return ONLP_E_STATUS_INTERNAL. + * Otherwise, return ONLP_STATUS_OK with the OID's information. + * + * Note -- it is expected that you fill out the information + * structure even if the sensor described by the OID is not present. + */ +int +onlp_thermali_info_get(onlp_oid_t id, onlp_thermal_info_t* info) +{ + int tid; + int psu_id; + VALIDATE(id); + + tid = ONLP_OID_ID_GET(id); + *info = tinfo[tid]; + + if ((tid >= THERMAL_1_ON_PSU1) && (tid <= THERMAL_3_ON_PSU2)) { + psu_id = ((tid - THERMAL_1_ON_PSU1) / NUM_OF_THERMAL_PER_PSU) + 1; + + if (onlp_get_psu_power_good(psu_id) != ONLP_STATUS_OK) { + info->status |= ONLP_THERMAL_STATUS_FAILED; + } + } + + if (tid == THERMAL_CPU_CORE) { + return onlp_file_read_int_max(&info->mcelsius, cpu_coretemp_files); + } + + return onlp_file_read_int(&info->mcelsius, devfiles__[tid]); +} diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_config.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_config.c new file mode 100644 index 0000000000..e7ea366306 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_config.c @@ -0,0 +1,80 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* */ +#define __x86_64_accton_as9817_32_config_STRINGIFY_NAME(_x) #_x +#define __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(_x) __x86_64_accton_as9817_32_config_STRINGIFY_NAME(_x) +x86_64_accton_as9817_32_config_settings_t x86_64_accton_as9817_32_config_settings[] = +{ +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_LOGGING(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_PORTING_STDLIB(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_UCLI(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION + { __x86_64_accton_as9817_32_config_STRINGIFY_NAME(X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION), __x86_64_accton_as9817_32_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION) }, +#else +{ X86_64_ACCTON_AS9817_32_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION(__x86_64_accton_as9817_32_config_STRINGIFY_NAME), "__undefined__" }, +#endif + { NULL, NULL } +}; +#undef __x86_64_accton_as9817_32_config_STRINGIFY_VALUE +#undef __x86_64_accton_as9817_32_config_STRINGIFY_NAME + +const char* +x86_64_accton_as9817_32_config_lookup(const char* setting) +{ + int i; + for(i = 0; x86_64_accton_as9817_32_config_settings[i].name; i++) { + if(!strcmp(x86_64_accton_as9817_32_config_settings[i].name, setting)) { + return x86_64_accton_as9817_32_config_settings[i].value; + } + } + return NULL; +} + +int +x86_64_accton_as9817_32_config_show(struct aim_pvs_s* pvs) +{ + int i; + for(i = 0; x86_64_accton_as9817_32_config_settings[i].name; i++) { + aim_printf(pvs, "%s = %s\n", x86_64_accton_as9817_32_config_settings[i].name, x86_64_accton_as9817_32_config_settings[i].value); + } + return i; +} + +/* */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_enums.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_enums.c new file mode 100644 index 0000000000..8590103402 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_enums.c @@ -0,0 +1,9 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.enum(ALL).source> */ +/* */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_int.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_int.h new file mode 100644 index 0000000000..e95604e2bd --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_int.h @@ -0,0 +1,11 @@ +/**************************************************************************//** + * + * x86_64_accton_as9817_32 Internal Header + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9817_32_INT_H__ +#define __x86_64_accton_as9817_32_INT_H__ + +#include + +#endif /* __x86_64_accton_as9817_32_INT_H__ */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.c new file mode 100644 index 0000000000..7390b39c3a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.c @@ -0,0 +1,17 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_accton_as9817_32_log.h" +/* + * x86_64_accton_as9817_32 log struct. + */ +AIM_LOG_STRUCT_DEFINE( + X86_64_ACCTON_AS9817_32_CONFIG_LOG_OPTIONS_DEFAULT, + X86_64_ACCTON_AS9817_32_CONFIG_LOG_BITS_DEFAULT, + NULL, /* Custom log map */ + X86_64_ACCTON_AS9817_32_CONFIG_LOG_CUSTOM_BITS_DEFAULT + ); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.h new file mode 100644 index 0000000000..3d22403518 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_log.h @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9817_32_LOG_H__ +#define __x86_64_accton_as9817_32_LOG_H__ + +#define AIM_LOG_MODULE_NAME x86_64_accton_as9817_32 +#include + +#endif /* __x86_64_accton_as9817_32_LOG_H__ */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_module.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_module.c new file mode 100644 index 0000000000..11f0a2f07b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_module.c @@ -0,0 +1,24 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_accton_as9817_32_log.h" + +static int +datatypes_init__(void) +{ +#define x86_64_accton_as9817_32_ENUMERATION_ENTRY(_enum_name, _desc) AIM_DATATYPE_MAP_REGISTER(_enum_name, _enum_name##_map, _desc, AIM_LOG_INTERNAL); +#include + return 0; +} + +void __x86_64_accton_as9817_32_module_init__(void) +{ + AIM_LOG_STRUCT_REGISTER(); + datatypes_init__(); +} + +int __onlp_platform_version__ = 1; diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_ucli.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_ucli.c new file mode 100644 index 0000000000..c440325998 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/x86_64_accton_as9817_32_ucli.c @@ -0,0 +1,49 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#if x86_64_accton_as9817_32_CONFIG_INCLUDE_UCLI == 1 + +#include +#include +#include + +static ucli_status_t +x86_64_accton_as9817_32_ucli_ucli__config__(ucli_context_t* uc) +{ + UCLI_HANDLER_MACRO_MODULE_CONFIG(x86_64_accton_as9817_32) +} + +/* */ +/* */ + +static ucli_module_t +x86_64_accton_as9817_32_ucli_module__ = + { + "x86_64_accton_as9817_32_ucli", + NULL, + x86_64_accton_as9817_32_ucli_ucli_handlers__, + NULL, + NULL, + }; + +ucli_node_t* +x86_64_accton_as9817_32_ucli_node_create(void) +{ + ucli_node_t* n; + ucli_module_init(&x86_64_accton_as9817_32_ucli_module__); + n = ucli_node_create("x86_64_accton_as9817_32", NULL, &x86_64_accton_as9817_32_ucli_module__); + ucli_node_subnode_add(n, ucli_module_log_node_create("x86_64_accton_as9817_32")); + return n; +} + +#else +void* +x86_64_accton_as9817_32_ucli_node_create(void) +{ + return NULL; +} +#endif From 1121b00ddf4482ab6d25d24961df1dd6ad1bc5a6 Mon Sep 17 00:00:00 2001 From: Willy Liu Date: Wed, 23 Jul 2025 06:20:27 +0000 Subject: [PATCH 2/4] [ACCTON][AS9817-32] Modularize IPMI-Related functions Signed-off-by: Willy Liu --- .../x86_64_accton_as9817_32d_r0/__init__.py | 1 + .../x86_64_accton_as9817_32o_r0/__init__.py | 1 + .../x86-64/as9817-32/src/modules/Makefile | 1 + .../as9817-32/src/modules/accton_ipmi_intf.c | 232 ++++++++++++++++++ .../as9817-32/src/modules/accton_ipmi_intf.h | 72 ++++++ .../src/modules/x86-64-accton-as9817-32-fan.c | 177 +------------ .../modules/x86-64-accton-as9817-32-leds.c | 175 +------------ .../src/modules/x86-64-accton-as9817-32-psu.c | 192 +-------------- .../src/modules/x86-64-accton-as9817-32-sys.c | 177 +------------ .../modules/x86-64-accton-as9817-32-thermal.c | 177 +------------ 10 files changed, 319 insertions(+), 886 deletions(-) create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c create mode 100644 packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.h diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py index c92eb80570..0f8e88e0be 100644 --- a/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32d/platform-config/r0/src/python/x86_64_accton_as9817_32d_r0/__init__.py @@ -82,6 +82,7 @@ def baseconfig(self): self.modprobe('optoe') self.modprobe('at24') + self.modprobe('accton_ipmi_intf') for m in [ 'i2c-ocores', 'fpga', 'mux', 'fan', 'psu', 'thermal', 'sys', 'leds' ]: self.insmod("x86-64-accton-as9817-32-%s" % m) diff --git a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py index a2752fd8ec..74eb7bf352 100644 --- a/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py +++ b/packages/platforms/accton/x86-64/as9817-32/as9817-32o/platform-config/r0/src/python/x86_64_accton_as9817_32o_r0/__init__.py @@ -82,6 +82,7 @@ def baseconfig(self): self.modprobe('optoe') self.modprobe('at24') + self.modprobe('accton_ipmi_intf') for m in [ 'i2c-ocores', 'fpga', 'mux', 'fan', 'psu', 'thermal', 'sys', 'leds' ]: self.insmod("x86-64-accton-as9817-32-%s" % m) diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile b/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile index 49cb1ea7e9..96dfd24ca0 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/Makefile @@ -1,3 +1,4 @@ +obj-m += accton_ipmi_intf.o obj-m += x86-64-accton-as9817-32-fan.o obj-m += x86-64-accton-as9817-32-fpga.o obj-m += x86-64-accton-as9817-32-i2c-ocores.o diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c new file mode 100644 index 0000000000..0bf88f6461 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright 2024 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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. + * + * + * Description: + * IPMI driver related interface implementation + */ +#include +#include +#include +#include "accton_ipmi_intf.h" + +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define RAW_CMD_BUF_SIZE 32 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI data structure and create a user interface for communication */ +int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev) +{ + int err; + + if (!ipmi || !dev) + return -EINVAL; + + init_completion(&ipmi->read_complete); + + // Initialize IPMI address + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + ipmi->dev = dev; // Storing the device for future reference + + // Initialize message buffers + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + // Assign the message handler + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + // Create IPMI messaging interface user + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, + "Unable to register user with IPMI interface %d, err: %d\n", + ipmi->interface, err); + return err; + } + + return 0; +} +EXPORT_SYMBOL(init_ipmi_data); + +/* Handler function for receiving IPMI messages */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + // Check for message ID mismatch + if (msg->msgid != ipmi->tx_msgid) { + dev_err(ipmi->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + // Handle received message type + ipmi->rx_recv_type = msg->recv_type; + + // Parse message data + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + // Copy remaining message data if available + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else { + ipmi->rx_msg_len = 0; + } + + // Free the received message and signal completion + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static void _ipmi_log_error(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + int status, int retry) +{ + int i, pos; + char *cmdline = NULL; + char raw_cmd[RAW_CMD_BUF_SIZE] = { 0 }; + + // Format the command and data into a raw command string + pos = snprintf(raw_cmd, sizeof(raw_cmd), "0x%02x", cmd); + for (i = 0; i < tx_len && pos < sizeof(raw_cmd); i++) { + pos += snprintf(raw_cmd + pos, sizeof(raw_cmd) - pos, + " 0x%02x", tx_data[i]); + } + + // Log the error message + cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + dev_err(ipmi->dev, + "ipmi_send_message: retry(%d), error(%d), cmd(%s) raw_cmd=[%s]\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd); + + if (cmdline) { + kfree(cmdline); + } +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + // Validate the input parameters + if ((tx_len && !tx_data) || (rx_len && !rx_data)) { + return -EINVAL; + } + + // Initialize IPMI message + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_len ? tx_data : NULL; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_len ? rx_data : NULL; + ipmi->rx_msg_len = rx_len; + + // Validate the IPMI address + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) { + dev_err(ipmi->dev, "Invalid IPMI address: %x\n", err); + return err; + } + + // Increment message ID and send the request + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) { + dev_err(ipmi->dev, "IPMI request_settime failed: %x\n", err); + return err; + } + + // Wait for the message to complete + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) { + dev_err(ipmi->dev, "IPMI command timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +/* Send an IPMI command to the IPMI device and receive the response */ +int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + // Validate the input parameters + if ((tx_len && !tx_data) || (rx_len && !rx_data)) { + return -EINVAL; + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + _ipmi_log_error(ipmi, cmd, tx_data, tx_len, status, retry); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + _ipmi_log_error(ipmi, cmd, tx_data, tx_len, status, retry); + continue; + } + + // Success, exit the retry loop + break; + } + + return status; +} + +EXPORT_SYMBOL(ipmi_send_message); + +static int __init ipmi_module_init(void) +{ + printk(KERN_INFO "Accton IPMI Module loaded\n"); + return 0; +} + +static void __exit ipmi_module_exit(void) +{ + printk(KERN_INFO "Accton IPMI Module unloaded\n"); +} + +module_init(ipmi_module_init); +module_exit(ipmi_module_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton IPMI messaging module"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.h b/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.h new file mode 100644 index 0000000000..4b2fe59f93 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.h @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright 2024 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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. + * + * + * Description: + * IPMI driver related interface declarations + */ + +#ifndef ACCTON_IPMI_INTF_H +#define ACCTON_IPMI_INTF_H + +#include +#include + +/* Structure to hold IPMI (Intelligent Platform Management Interface) data */ +struct ipmi_data { + struct completion read_complete; // Synchronization primitive for signaling message read completion + struct ipmi_addr address; // Structure to store the IPMI system interface address + struct ipmi_user *user; // Pointer to IPMI user created by the kernel + int interface; // Interface identifier for the IPMI system + + struct kernel_ipmi_msg tx_message; // Message structure for sending IPMI commands + long tx_msgid; // Message ID for tracking IPMI message transactions + + void *rx_msg_data; // Pointer to buffer for storing received IPMI message data + unsigned short rx_msg_len; // Length of the received IPMI message + unsigned char rx_result; // Result code from the received IPMI message + int rx_recv_type; // Type of the received message (e.g., system interface, LAN, etc.) + + struct ipmi_user_hndl ipmi_hndlrs; // IPMI handler structure for handling incoming IPMI messages + struct device *dev; // Device structure for logging errors +}; + +/* Function declarations */ + +/* + * Initialize IPMI data structure and create a user interface for communication. + * + * @param ipmi: Pointer to ipmi_data structure to be initialized. + * @param iface: IPMI interface identifier. + * @param dev: Device structure for logging errors. + * @return 0 on success, or an error code on failure. + */ +extern int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev); + +/* + * Send an IPMI command to the IPMI device and receive the response. + * + * @param ipmi: Pointer to ipmi_data structure containing IPMI communication information. + * @param cmd: IPMI command byte. + * @param tx_data: Pointer to data buffer for the command payload. + * @param tx_len: Length of the command payload data. + * @param rx_data: Pointer to buffer for storing the response data. + * @param rx_len: Length of the response data buffer. + * @return 0 on success, or an error code on failure. + */ +extern int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len); + +#endif /* ACCTON_IPMI_INTF_H */ diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c index 9cb1e692b9..f9b7524184 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-fan.c @@ -33,19 +33,17 @@ #include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9817_32_fan" -#define ACCTON_IPMI_NETFN 0x34 + #define IPMI_FAN_READ_CMD 0x14 #define IPMI_FAN_WRITE_CMD 0x15 #define IPMI_FAN_READ_RPM_CMD 0x20 -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 #define IPMI_FAN_REG_READ_CMD 0x20 #define IPMI_FAN_REG_WRITE_CMD 0x21 #define MAX_FAN_SPEED_RPM 33000 -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t set_fan(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t show_fan(struct device *dev, struct device_attribute *attr, @@ -91,23 +89,6 @@ enum fan_data_index { FAN_SPEED_DATA_COUNT }; -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user *user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct as9817_32_fan_data { struct platform_device *pdev; struct device *hwmon_dev; @@ -261,160 +242,6 @@ static struct attribute *as9817_32_fan_attrs[] = { }; ATTRIBUTE_GROUPS(as9817_32_fan); -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - - int i = 0; - char raw_cmd[20] = ""; - sprintf(raw_cmd, "0x%02x", cmd); - if(tx_len) { - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi,cmd, tx_data, tx_len, rx_data, - rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - if (cmdline) - kfree(cmdline); - - return status; -} - -/* Dispatch IPMI messages to callers */ -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) -{ - unsigned short rx_len; - struct ipmi_data *ipmi = user_msg_data; - - if (msg->msgid != ipmi->tx_msgid) { - dev_err(&data->pdev->dev, "Mismatch between received msgid " - "(%02x) and transmitted msgid (%02x)!\n", - (int)msg->msgid, - (int)ipmi->tx_msgid); - ipmi_free_recv_msg(msg); - return; - } - - ipmi->rx_recv_type = msg->recv_type; - if (msg->msg.data_len > 0) - ipmi->rx_result = msg->msg.data[0]; - else - ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; - - if (msg->msg.data_len > 1) { - rx_len = msg->msg.data_len - 1; - if (ipmi->rx_msg_len < rx_len) - rx_len = ipmi->rx_msg_len; - ipmi->rx_msg_len = rx_len; - memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); - } else - ipmi->rx_msg_len = 0; - - ipmi_free_recv_msg(msg); - complete(&ipmi->read_complete); -} - static struct as9817_32_fan_data *as9817_32_fan_update_device(void) { int status = 0; diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c index a1b924ef0c..f765ecebcf 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-leds.c @@ -31,15 +31,12 @@ #include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9817_32_led" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_LED_READ_CMD 0x1A #define IPMI_LED_WRITE_CMD 0x1B -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t set_led(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t show_led(struct device *dev, struct device_attribute *attr, @@ -47,23 +44,6 @@ static ssize_t show_led(struct device *dev, struct device_attribute *attr, static int as9817_32_led_probe(struct platform_device *pdev); static int as9817_32_led_remove(struct platform_device *pdev); -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user *user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct as9817_32_led_data { struct platform_device *pdev; struct mutex update_lock; @@ -157,159 +137,6 @@ static const struct attribute_group as9817_32_led_group = { .attrs = as9817_32_led_attributes, }; -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - - int i = 0; - char raw_cmd[20] = ""; - sprintf(raw_cmd, "0x%02x", cmd); - if(tx_len){ - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - if (cmdline) - kfree(cmdline); - - return status; -} - -/* Dispatch IPMI messages to callers */ -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) -{ - unsigned short rx_len; - struct ipmi_data *ipmi = user_msg_data; - - if (msg->msgid != ipmi->tx_msgid) { - dev_err(&data->pdev->dev, "Mismatch between received msgid " - "(%02x) and transmitted msgid (%02x)!\n", - (int)msg->msgid, - (int)ipmi->tx_msgid); - ipmi_free_recv_msg(msg); - return; - } - - ipmi->rx_recv_type = msg->recv_type; - if (msg->msg.data_len > 0) - ipmi->rx_result = msg->msg.data[0]; - else - ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; - - if (msg->msg.data_len > 1) { - rx_len = msg->msg.data_len - 1; - if (ipmi->rx_msg_len < rx_len) - rx_len = ipmi->rx_msg_len; - ipmi->rx_msg_len = rx_len; - memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); - } else - ipmi->rx_msg_len = 0; - - ipmi_free_recv_msg(msg); - complete(&ipmi->read_complete); -} - static struct as9817_32_led_data *as9817_32_led_update_device(void) { int status = 0; diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c index c834fd8bca..9412d3e630 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c @@ -31,20 +31,17 @@ #include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9817_32_psu" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_PSU_READ_CMD 0x16 #define IPMI_PSU_MODEL_NAME_CMD 0x10 #define IPMI_PSU_SERIAL_NUM_CMD 0x11 #define IPMI_PSU_FAN_DIR_CMD 0x13 #define IPMI_PSU_INFO_CMD 0x20 -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 #define IPMI_MODEL_SERIAL_LEN 32 #define IPMI_FAN_DIR_LEN 3 -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t show_psu(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t show_psu_info(struct device *dev, struct device_attribute *attr, @@ -147,24 +144,6 @@ enum psu_data_index { PSU_INFO_COUNT }; -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user * user; - int interface; - int pid; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct ipmi_psu_resp_data { unsigned char status[PSU_STATUS_COUNT]; unsigned char info[PSU_INFO_COUNT]; @@ -417,163 +396,6 @@ const struct attribute_group *as9817_32_psu_groups[][2] = { {&as9817_32_psu2_group, NULL} }; -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev, - int pid) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - ipmi->pid = dev->id; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len, - unsigned char pid) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev[pid]->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev[pid]->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev[pid]->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len, - unsigned char pid) -{ - int status = 0, retry = 0; - - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - - int i = 0; - char raw_cmd[20] = ""; - sprintf(raw_cmd, "0x%02x", cmd); - if(tx_len){ - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len - , pid); - if (unlikely(status != 0)) { - dev_err(&data->pdev[pid]->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev[pid]->dev, - "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - if (cmdline) - kfree(cmdline); - - return status; -} - -/* Dispatch IPMI messages to callers */ -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) -{ - unsigned short rx_len; - struct ipmi_data *ipmi = user_msg_data; - - if (msg->msgid != ipmi->tx_msgid) { - dev_err(&data->pdev[ipmi->pid]->dev, "Mismatch between received msgid " - "(%02x) and transmitted msgid (%02x)!\n", - (int)msg->msgid, - (int)ipmi->tx_msgid); - ipmi_free_recv_msg(msg); - return; - } - - ipmi->rx_recv_type = msg->recv_type; - if (msg->msg.data_len > 0) - ipmi->rx_result = msg->msg.data[0]; - else - ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; - - if (msg->msg.data_len > 1) { - rx_len = msg->msg.data_len - 1; - if (ipmi->rx_msg_len < rx_len) - rx_len = ipmi->rx_msg_len; - ipmi->rx_msg_len = rx_len; - memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); - } else - ipmi->rx_msg_len = 0; - - ipmi_free_recv_msg(msg); - complete(&ipmi->read_complete); -} - static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attribute *da) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); @@ -592,7 +414,7 @@ static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attr status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, data->ipmi_tx_data, 1, data->ipmi_resp[pid].status, - sizeof(data->ipmi_resp[pid].status), pid); + sizeof(data->ipmi_resp[pid].status)); if (unlikely(status != 0)) goto exit; @@ -606,7 +428,7 @@ static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attr status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, data->ipmi_tx_data, 2, data->ipmi_resp[pid].model, - sizeof(data->ipmi_resp[pid].model) - 1, pid); + sizeof(data->ipmi_resp[pid].model) - 1); if (unlikely(status != 0)) goto exit; @@ -620,7 +442,7 @@ static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attr status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, data->ipmi_tx_data, 2, data->ipmi_resp[pid].serial, - sizeof(data->ipmi_resp[pid].serial) - 1, pid); + sizeof(data->ipmi_resp[pid].serial) - 1); if (unlikely(status != 0)) goto exit; @@ -634,7 +456,7 @@ static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attr status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, data->ipmi_tx_data, 2, data->ipmi_resp[pid].fandir, - sizeof(data->ipmi_resp[pid].fandir) - 1, pid); + sizeof(data->ipmi_resp[pid].fandir) - 1); if (unlikely(status != 0)) goto exit; @@ -648,7 +470,7 @@ static struct as9817_32_psu_data *as9817_32_psu_update_device(struct device_attr status = ipmi_send_message(&data->ipmi, IPMI_PSU_READ_CMD, data->ipmi_tx_data, 2, data->ipmi_resp[pid].info, - sizeof(data->ipmi_resp[pid].info), pid); + sizeof(data->ipmi_resp[pid].info)); if (unlikely(status != 0)) goto exit; @@ -1043,7 +865,7 @@ static int __init as9817_32_psu_init(void) } /* Set up IPMI interface */ - ret = init_ipmi_data(&data->ipmi, 0, &data->pdev[i]->dev, i); + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev[i]->dev); if (ret) goto ipmi_err; } diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c index 7636d1b88b..76356512f5 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-sys.c @@ -31,19 +31,16 @@ #include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9817_32_sys" -#define ACCTON_IPMI_NETFN 0x34 -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 #define IPMI_READ_MAX_LEN 128 #define IPMI_CPLD_READ_CMD 0x20 #define IPMI_OTP_PROTECT_CMD 0x94 #define IPMI_SEND_THERMAL_DATA_CMD 0x13 -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static int as9817_32_sys_probe(struct platform_device *pdev); static int as9817_32_sys_remove(struct platform_device *pdev); static ssize_t show_version(struct device *dev, @@ -53,23 +50,6 @@ static ssize_t set_otp_protect(struct device *dev, struct device_attribute *da, static ssize_t set_bmc_thermal_data(struct device *dev, struct device_attribute *da, const char *buf, size_t count); -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user * user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct as9817_32_sys_data { struct platform_device *pdev; struct mutex update_lock; @@ -112,161 +92,6 @@ static const struct attribute_group as9817_32_sys_group = { .attrs = as9817_32_sys_attributes, }; -/* Functions to talk to the IPMI layer */ -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - - int i = 0; - char raw_cmd[20] = ""; - sprintf(raw_cmd, "0x%02x", cmd); - if(tx_len) { - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi,cmd, tx_data, tx_len, rx_data, - rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err rx_result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - if (cmdline) - kfree(cmdline); - - return status; -} - -/* Dispatch IPMI messages to callers */ -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) -{ - unsigned short rx_len; - struct ipmi_data *ipmi = user_msg_data; - - if (msg->msgid != ipmi->tx_msgid) { - dev_err(&data->pdev->dev, "Mismatch between received msgid " - "(%02x) and transmitted msgid (%02x)!\n", - (int)msg->msgid, - (int)ipmi->tx_msgid); - ipmi_free_recv_msg(msg); - return; - } - - ipmi->rx_recv_type = msg->recv_type; - if (msg->msg.data_len > 0) - ipmi->rx_result = msg->msg.data[0]; - else - ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; - - if (msg->msg.data_len > 1) { - rx_len = msg->msg.data_len - 1; - if (ipmi->rx_msg_len < rx_len) - rx_len = ipmi->rx_msg_len; - ipmi->rx_msg_len = rx_len; - memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); - } - else { - ipmi->rx_msg_len = 0; - } - - ipmi_free_recv_msg(msg); - complete(&ipmi->read_complete); -} - static struct as9817_32_sys_data *as9817_32_sys_update_fpga_ver(void) { int status = 0; diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c index 72dfaa11c3..e62942db79 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-thermal.c @@ -32,18 +32,14 @@ #include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9817_32_thermal" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_THERMAL_READ_CMD 0x12 #define THERMAL_COUNT 8 #define THERMAL_DATA_LEN 3 #define THERMAL_DATA_COUNT (THERMAL_COUNT * THERMAL_DATA_LEN) -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 - -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf); #ifdef ENABLE_THRESHOLD @@ -60,23 +56,6 @@ enum temp_data_index { TEMP_DATA_COUNT }; -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user * user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct as9817_32_thermal_data { struct platform_device *pdev; struct device *hwmon_dev; @@ -200,160 +179,6 @@ static struct attribute *as9817_32_thermal_attrs[] = { }; ATTRIBUTE_GROUPS(as9817_32_thermal); -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - - int i = 0; - char raw_cmd[20] = ""; - sprintf(raw_cmd, "0x%02x", cmd); - if(tx_len) { - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, - rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi cmd(%x) err status(%d)[%s] raw_cmd=[%s]\r\n tx_msgid=(%02x)", - cmd, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi cmd(%x) err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - cmd, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - if (cmdline) - kfree(cmdline); - - return status; -} - -/* Dispatch IPMI messages to callers */ -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) -{ - unsigned short rx_len; - struct ipmi_data *ipmi = user_msg_data; - - if (msg->msgid != ipmi->tx_msgid) { - dev_err(&data->pdev->dev, "Mismatch between received msgid " - "(%02x) and transmitted msgid (%02x)!\n", - (int)msg->msgid, - (int)ipmi->tx_msgid); - ipmi_free_recv_msg(msg); - return; - } - - ipmi->rx_recv_type = msg->recv_type; - if (msg->msg.data_len > 0) - ipmi->rx_result = msg->msg.data[0]; - else - ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; - - if (msg->msg.data_len > 1) { - rx_len = msg->msg.data_len - 1; - if (ipmi->rx_msg_len < rx_len) - rx_len = ipmi->rx_msg_len; - ipmi->rx_msg_len = rx_len; - memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); - } else - ipmi->rx_msg_len = 0; - - ipmi_free_recv_msg(msg); - complete(&ipmi->read_complete); -} - #ifdef ENABLE_THRESHOLD static ssize_t show_threshold(struct device *dev, struct device_attribute *da, char *buf) From 56f5bf35e0c5b0a0814b878125262fa4c9258022 Mon Sep 17 00:00:00 2001 From: Willy Liu Date: Mon, 11 Aug 2025 08:48:09 +0000 Subject: [PATCH 3/4] [ACCTON][AS9817-32] Fix the ipmi device name and sysfs path. 1. The PSU device name without index 2. PSU releated sysfs without index Signed-off-by: Willy Liu --- .../src/modules/x86-64-accton-as9817-32-psu.c | 72 +++++++++---------- .../x86_64_accton_as9817_32/module/src/fani.c | 4 +- .../module/src/platform_lib.c | 12 +++- .../module/src/platform_lib.h | 4 +- .../x86_64_accton_as9817_32/module/src/psui.c | 20 +++--- .../module/src/thermali.c | 12 ++-- 6 files changed, 63 insertions(+), 61 deletions(-) diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c index 9412d3e630..57c054ec58 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/x86-64-accton-as9817-32-psu.c @@ -153,7 +153,7 @@ struct ipmi_psu_resp_data { }; struct as9817_32_psu_data { - struct platform_device *pdev[2]; + struct platform_device *pdev; struct device *hwmon_dev[2]; struct mutex update_lock; char valid[2]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ @@ -811,31 +811,37 @@ static int as9817_32_psu_probe(struct platform_device *pdev) { int status = 0; struct device *hwmon_dev = NULL; + int i = 0; + + for (i = 0 ; i < 2 ; i++){ + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9817_32_psu_groups[i]); + if (IS_ERR(hwmon_dev)) { + status = PTR_ERR(hwmon_dev); + return status; + } + mutex_lock(&data->update_lock); + data->hwmon_dev[i] = hwmon_dev; + mutex_unlock(&data->update_lock); - hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, - NULL, NULL, as9817_32_psu_groups[pdev->id]); - if (IS_ERR(hwmon_dev)) { - status = PTR_ERR(hwmon_dev); - return status; + dev_info(&pdev->dev, "PSU%d device created\n", i+1); } - mutex_lock(&data->update_lock); - data->hwmon_dev[pdev->id] = hwmon_dev; - mutex_unlock(&data->update_lock); - - dev_info(&pdev->dev, "PSU%d device created\n", pdev->id + 1); - return 0; } static int as9817_32_psu_remove(struct platform_device *pdev) { - mutex_lock(&data->update_lock); - if (data->hwmon_dev[pdev->id]) { - hwmon_device_unregister(data->hwmon_dev[pdev->id]); - data->hwmon_dev[pdev->id] = NULL; + int i = 0; + + for (i = 0 ; i < 2 ; i++){ + mutex_lock(&data->update_lock); + if (data->hwmon_dev[i]) { + hwmon_device_unregister(data->hwmon_dev[i]); + data->hwmon_dev[i] = NULL; + } + mutex_unlock(&data->update_lock); } - mutex_unlock(&data->update_lock); return 0; } @@ -843,7 +849,6 @@ static int as9817_32_psu_remove(struct platform_device *pdev) static int __init as9817_32_psu_init(void) { int ret; - int i; data = kzalloc(sizeof(struct as9817_32_psu_data), GFP_KERNEL); if (!data) { @@ -857,26 +862,21 @@ static int __init as9817_32_psu_init(void) if (ret < 0) goto dri_reg_err; - for (i = 0; i < NUM_OF_PSU; i++) { - data->pdev[i] = platform_device_register_simple(DRVNAME, i, NULL, 0); - if (IS_ERR(data->pdev[i])) { - ret = PTR_ERR(data->pdev[i]); - goto dev_reg_err; - } - - /* Set up IPMI interface */ - ret = init_ipmi_data(&data->ipmi, 0, &data->pdev[i]->dev); - if (ret) - goto ipmi_err; + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; } + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + return 0; ipmi_err: - while (i > 0) { - i--; - platform_device_unregister(data->pdev[i]); - } + platform_device_unregister(data->pdev); dev_reg_err: platform_driver_unregister(&as9817_32_psu_driver); dri_reg_err: @@ -887,12 +887,8 @@ static int __init as9817_32_psu_init(void) static void __exit as9817_32_psu_exit(void) { - int i; - ipmi_destroy_user(data->ipmi.user); - for (i = 0; i < NUM_OF_PSU; i++) { - platform_device_unregister(data->pdev[i]); - } + platform_device_unregister(data->pdev); platform_driver_unregister(&as9817_32_psu_driver); kfree(data); } diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c index 5cabfcf9f4..03569fe0c4 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/fani.c @@ -191,7 +191,7 @@ _onlp_fani_info_get_fan_on_psu(int pid, onlp_fan_info_t* info) char file[32]; snprintf(file, sizeof(file), "psu%d_fan_dir", pid); - len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, hwmon_idx, file); if (str && len >= 3) { if (strncmp(str, "B2F", strlen("B2F")) == 0) { info->status |= ONLP_FAN_STATUS_B2F; @@ -205,7 +205,7 @@ _onlp_fani_info_get_fan_on_psu(int pid, onlp_fan_info_t* info) /* get fan speed */ - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "fan1_input"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "fan1_input"); if (ret < 0) { AIM_LOG_WARN("Unable to read status from PSU(%d)\r\n", pid); } else { diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c index da0b287bfc..e79dbd9800 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.c @@ -71,9 +71,15 @@ int onlp_get_psu_hwmon_idx(int pid) int ret, hwmon_idx, max_hwmon_idx = 20; for (hwmon_idx = 0; hwmon_idx <= max_hwmon_idx; hwmon_idx++) { - snprintf(path, sizeof(path), "/sys/devices/platform/as9817_32_psu.%d/hwmon/hwmon%d/", pid-1, hwmon_idx); + snprintf(path, sizeof(path), "/sys/devices/platform/as9817_32_psu/hwmon/hwmon%d/", hwmon_idx); + + if (pid == 1) + ret = onlp_file_find(path, "psu1_present", &file); + else if (pid == 2) + ret = onlp_file_find(path, "psu2_present", &file); + else + return -1; - ret = onlp_file_find(path, "name", &file); AIM_FREE_IF_PTR(file); if (ONLP_STATUS_OK == ret) @@ -89,7 +95,7 @@ int onlp_get_psu_power_good(int pid) int val = 0; /* Get power good status */ - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "power_good"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "power_good"); if (ret < 0) { return ONLP_STATUS_E_INTERNAL; } diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h index add363487d..f4787b9993 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/platform_lib.h @@ -42,8 +42,8 @@ #define PSU_STATUS_PRESENT 1 #define PSU_STATUS_POWER_GOOD 1 -#define PSU_SYSFS_FORMAT "/sys/devices/platform/as9817_32_psu.%d*psu%d_%s" -#define PSU_SYSFS_FORMAT_1 "/sys/devices/platform/as9817_32_psu.%d/hwmon/hwmon%d/%s" +#define PSU_SYSFS_FORMAT "/sys/devices/platform/as9817_32_psu*psu%d_%s" +#define PSU_SYSFS_FORMAT_1 "/sys/devices/platform/as9817_32_psu/hwmon/hwmon%d/%s" #define FAN_SYSFS_FORMAT "/sys/devices/platform/as9817_32_fan*" #define FAN_SYSFS_FORMAT_1 "/sys/devices/platform/as9817_32_fan/hwmon/hwmon%d/%s" #define SYS_LED_PATH "/sys/devices/platform/as9817_32_led/" diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c index 182c2eb323..3fb8f8f4a3 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/psui.c @@ -67,7 +67,7 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) *info = pinfo[pid]; /* Set the onlp_oid_hdr_t */ /* Get the present state */ - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "present"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "present"); if (ret < 0) { info->status &= ~ONLP_PSU_STATUS_PRESENT; return ONLP_STATUS_E_INTERNAL; @@ -97,42 +97,42 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) /* Read voltage, current and power */ val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vin"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "vin"); if (ret == ONLP_STATUS_OK && val) { info->mvin = val; info->caps |= ONLP_PSU_CAPS_VIN; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iin"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "iin"); if (ret == ONLP_STATUS_OK && val) { info->miin = val; info->caps |= ONLP_PSU_CAPS_IIN; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pin"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "pin"); if (ret == ONLP_STATUS_OK && val) { info->mpin = val; info->caps |= ONLP_PSU_CAPS_PIN; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vout"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "vout"); if (ret == ONLP_STATUS_OK && val) { info->mvout = val; info->caps |= ONLP_PSU_CAPS_VOUT; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iout"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "iout"); if (ret == ONLP_STATUS_OK && val) { info->miout = val; info->caps |= ONLP_PSU_CAPS_IOUT; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pout"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "pout"); if (ret == ONLP_STATUS_OK && val) { info->mpout = val; info->caps |= ONLP_PSU_CAPS_POUT; @@ -143,10 +143,10 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) char *str = NULL; int len; char file[32]; - /* Read model */ snprintf(file, sizeof(file), "psu%d_model", pid); - len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, hwmon_idx, file); + if (str && len) { memcpy(info->model, str, len); info->model[len] = '\0'; @@ -155,7 +155,7 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) /* Read serial */ snprintf(file, sizeof(file), "psu%d_serial", pid); - len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, hwmon_idx, file); if (str && len) { memcpy(info->serial, str, len); info->serial[len] = '\0'; diff --git a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c index 87dac9afff..78f1ce5154 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/x86_64_accton_as9817_32/module/src/thermali.c @@ -45,12 +45,12 @@ static char* devfiles__[] = { /* must map with onlp_thermal_id */ "/sys/devices/platform/as9817_32_thermal*temp6_input", "/sys/devices/platform/as9817_32_thermal*temp7_input", "/sys/devices/platform/as9817_32_thermal*temp8_input", - "/sys/devices/platform/as9817_32_psu.0*psu1_temp1_input", - "/sys/devices/platform/as9817_32_psu.0*psu1_temp2_input", - "/sys/devices/platform/as9817_32_psu.0*psu1_temp3_input", - "/sys/devices/platform/as9817_32_psu.1*psu2_temp1_input", - "/sys/devices/platform/as9817_32_psu.1*psu2_temp2_input", - "/sys/devices/platform/as9817_32_psu.1*psu2_temp3_input" + "/sys/devices/platform/as9817_32_psu*psu1_temp1_input", + "/sys/devices/platform/as9817_32_psu*psu1_temp2_input", + "/sys/devices/platform/as9817_32_psu*psu1_temp3_input", + "/sys/devices/platform/as9817_32_psu*psu2_temp1_input", + "/sys/devices/platform/as9817_32_psu*psu2_temp2_input", + "/sys/devices/platform/as9817_32_psu*psu2_temp3_input" }; static char* cpu_coretemp_files[] = { From 9a26788a552141445c09358e733973997b3b760a Mon Sep 17 00:00:00 2001 From: Alex Lai Date: Tue, 4 Nov 2025 02:05:46 +0000 Subject: [PATCH 4/4] [Accton][as9817-32d][as9817-32o] Enlarge ipmi raw cmd buf size 1. Enlarge ipmi raw cmd buf size to 40 bytes. Signed-off-by: Alex Lai --- .../accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c b/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c index 0bf88f6461..48a0c9acfd 100644 --- a/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c +++ b/packages/platforms/accton/x86-64/as9817-32/src/modules/accton_ipmi_intf.c @@ -24,7 +24,7 @@ #define ACCTON_IPMI_NETFN 0x34 #define IPMI_TIMEOUT (5 * HZ) #define IPMI_ERR_RETRY_TIMES 1 -#define RAW_CMD_BUF_SIZE 32 +#define RAW_CMD_BUF_SIZE 40 static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);