From d70fb948b6aefc4a844e28a7089a42ebf65e6adb Mon Sep 17 00:00:00 2001 From: Brandon Chuang Date: Wed, 6 Jul 2022 16:00:08 +0800 Subject: [PATCH] [Edgecore][as7926_40xfb] Support ONLP V2 CPU: Intel Broadwell-DE, 4 Core MAC: Broadcom BCM88690 TCAM: Broadcom BCM16K knowledge-Based Processor PHY: Broadcom BCM81724 CPLD: ALTERA 10M04SAU169C8G (1pc, BGA169 package) ALTERA 10M04SCU169C8G (2pc, BGA169 package) ALTERA 5M1270 ZF256C5N FPGA: ALTERA EP4CGX30BF14C7N Ethernet Ports: 40x QSFP28 Fabric Ports: 13x QSFP-DD OOB Ports: 2x SFP+ Power Supply: 12V from 1600W PSU * 2 Cooling: 12V 60X60 fan-tray module *5, hot-swappable Dimension: 635 mm (D: Depth) x 440mm (W: Width) x 87 mm (H: Height) Signed-off-by: Brandon Chuang --- .../accton/x86-64/as7926-40xfb/.gitignore | 2 + .../accton/x86-64/as7926-40xfb/Makefile | 1 + .../x86-64/as7926-40xfb/modules/Makefile | 1 + .../x86-64/as7926-40xfb/modules/PKG.yml | 1 + .../as7926-40xfb/modules/builds/.gitignore | 1 + .../as7926-40xfb/modules/builds/Makefile | 6 + .../builds/x86-64-accton-as7926-40xfb-cpld.c | 1053 +++++++++++++++++ .../builds/x86-64-accton-as7926-40xfb-fan.c | 761 ++++++++++++ .../builds/x86-64-accton-as7926-40xfb-leds.c | 674 +++++++++++ .../builds/x86-64-accton-as7926-40xfb-psu.c | 922 +++++++++++++++ .../builds/x86-64-accton-as7926-40xfb-sys.c | 396 +++++++ .../x86-64-accton-as7926-40xfb-thermal.c | 455 +++++++ .../accton/x86-64/as7926-40xfb/onlp/Makefile | 1 + .../accton/x86-64/as7926-40xfb/onlp/PKG.yml | 1 + .../x86-64/as7926-40xfb/onlp/builds/Makefile | 2 + .../as7926-40xfb/onlp/builds/lib/Makefile | 3 + .../as7926-40xfb/onlp/builds/onlps/Makefile | 3 + .../builds/x86_64_accton_as7926_40xfb/.module | 1 + .../x86_64_accton_as7926_40xfb/Makefile | 9 + .../builds/x86_64_accton_as7926_40xfb/README | 6 + .../module/auto/make.mk | 9 + .../auto/x86_64_accton_as7926_40xfb.yml | 52 + .../x86_64_accton_as7926_40xfb.x | 12 + .../x86_64_accton_as7926_40xfb_config.h | 147 +++ .../x86_64_accton_as7926_40xfb_dox.h | 26 + .../x86_64_accton_as7926_40xfb_porting.h | 107 ++ .../x86_64_accton_as7926_40xfb/module/make.mk | 10 + .../module/src/Makefile | 9 + .../module/src/attributei.c | 100 ++ .../module/src/chassisi.c | 82 ++ .../module/src/fani.c | 356 ++++++ .../module/src/ledi.c | 257 ++++ .../module/src/make.mk | 9 + .../module/src/platform_lib.h | 47 + .../module/src/platformi.c | 57 + .../module/src/psui.c | 181 +++ .../module/src/sfpi.c | 380 ++++++ .../module/src/thermali.c | 297 +++++ .../src/x86_64_accton_as7926_40xfb_config.c | 81 ++ .../src/x86_64_accton_as7926_40xfb_enums.c | 10 + .../src/x86_64_accton_as7926_40xfb_int.h | 12 + .../src/x86_64_accton_as7926_40xfb_log.c | 17 + .../src/x86_64_accton_as7926_40xfb_log.h | 12 + .../src/x86_64_accton_as7926_40xfb_module.c | 24 + .../src/x86_64_accton_as7926_40xfb_ucli.c | 50 + .../as7926-40xfb/platform-config/Makefile | 1 + .../as7926-40xfb/platform-config/r0/Makefile | 1 + .../as7926-40xfb/platform-config/r0/PKG.yml | 1 + .../src/lib/x86-64-accton-as7926-40xfb-r0.yml | 31 + .../x86_64_accton_as7926_40xfb_r0/__init__.py | 137 +++ setup.env | 1 + 51 files changed, 6815 insertions(+) create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/.gitignore create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/.gitignore create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-cpld.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-fan.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-leds.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-psu.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-sys.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-thermal.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/lib/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/onlps/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/.module create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/README create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/make.mk create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/x86_64_accton_as7926_40xfb.yml create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb.x create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_config.h create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_dox.h create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_porting.h create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/make.mk create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/attributei.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/chassisi.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/fani.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/ledi.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/make.mk create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platform_lib.h create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platformi.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/psui.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/thermali.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_config.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_enums.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_int.h create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.h create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_module.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_ucli.c create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/platform-config/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/Makefile create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/lib/x86-64-accton-as7926-40xfb-r0.yml create mode 100644 packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/python/x86_64_accton_as7926_40xfb_r0/__init__.py diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/.gitignore b/packages/platforms/accton/x86-64/as7926-40xfb/.gitignore new file mode 100644 index 0000000000..c1b2eeca0a --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/.gitignore @@ -0,0 +1,2 @@ +*x86*64*accton*as7926*40xfb*.mk +onlpdump.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/modules/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/PKG.yml b/packages/platforms/accton/x86-64/as7926-40xfb/modules/PKG.yml new file mode 100644 index 0000000000..eb73b2d847 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-modules.yml VENDOR=accton BASENAME=x86-64-accton-as7926-40xfb ARCH=amd64 KERNELS="onl-kernel-4.14-lts-x86-64-all:amd64" diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/.gitignore b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/.gitignore new file mode 100644 index 0000000000..a65b41774a --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/Makefile new file mode 100644 index 0000000000..4b943ac753 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/Makefile @@ -0,0 +1,6 @@ +KERNELS := onl-kernel-4.14-lts-x86-64-all:amd64 +KMODULES := $(wildcard *.c) +VENDOR := accton +BASENAME := x86-64-accton-as7926-40xfb +ARCH := x86_64 +include $(ONL)/make/kmodule.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-cpld.c b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-cpld.c new file mode 100644 index 0000000000..fa6f6b9ac7 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-cpld.c @@ -0,0 +1,1053 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the as7926_40xfb_cpld + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as7926_40xfb_cpld" + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as7926_40xfb_cpld2, + as7926_40xfb_cpld3, + as7926_40xfb_cpld4, + as7926_40xfb_7sgmt +}; + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); + +struct as7926_40xfb_cpld_data { + struct device *hwmon_dev; + struct mutex update_lock; + u8 index; /* CPLD index */ +}; + +/* Addresses scanned for as7926_40xfb_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index + +enum as7926_40xfb_cpld_sysfs_attributes { + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(31), + TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(33), + TRANSCEIVER_PRESENT_ATTR_ID(34), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(35), + TRANSCEIVER_PRESENT_ATTR_ID(36), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(37), + TRANSCEIVER_PRESENT_ATTR_ID(38), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(39), + TRANSCEIVER_PRESENT_ATTR_ID(40), + TRANSCEIVER_PRESENT_ATTR_ID(41), + TRANSCEIVER_PRESENT_ATTR_ID(42), + TRANSCEIVER_PRESENT_ATTR_ID(43), + TRANSCEIVER_PRESENT_ATTR_ID(44), + TRANSCEIVER_PRESENT_ATTR_ID(45), + TRANSCEIVER_PRESENT_ATTR_ID(46), + TRANSCEIVER_PRESENT_ATTR_ID(47), + TRANSCEIVER_PRESENT_ATTR_ID(48), + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(33), + TRANSCEIVER_RESET_ATTR_ID(34), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(35), + TRANSCEIVER_RESET_ATTR_ID(36), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(37), + TRANSCEIVER_RESET_ATTR_ID(38), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(39), + TRANSCEIVER_RESET_ATTR_ID(40), + TRANSCEIVER_RESET_ATTR_ID(41), + TRANSCEIVER_RESET_ATTR_ID(42), + TRANSCEIVER_RESET_ATTR_ID(43), + TRANSCEIVER_RESET_ATTR_ID(44), + TRANSCEIVER_RESET_ATTR_ID(45), + TRANSCEIVER_RESET_ATTR_ID(46), + TRANSCEIVER_RESET_ATTR_ID(47), + TRANSCEIVER_RESET_ATTR_ID(48), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_PRESENT_ATTR_ID(55), + TRANSCEIVER_TXDISABLE_ATTR_ID(54), + TRANSCEIVER_TXDISABLE_ATTR_ID(55), + TRANSCEIVER_RXLOS_ATTR_ID(54), + TRANSCEIVER_RXLOS_ATTR_ID(55), + MODULE_PRESENT_ALL, + CPLD_VERSION, + ACCESS, +}; + +/* sysfs attributes for hwmon + */ + +/* qsfp transceiver attributes */ +#define DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, \ + NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, \ + show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFP28_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +#define DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, \ + show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, \ + show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFPDD_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +/* sfp transceiver attributes */ +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, \ + NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, \ + show_status, set_tx_disable, \ + MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, \ + NULL, MODULE_RXLOS_##index) + +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, + NULL, MODULE_PRESENT_ALL); + +/* transceiver attributes */ +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); +DECLARE_QSFP28_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFPDD_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(55); + +static struct attribute *as7926_40xfb_cpld2_attributes[] = { + /* transceiver attributes */ + DECLARE_QSFP28_TRANSCEIVER_ATTR(1), + DECLARE_QSFP28_TRANSCEIVER_ATTR(2), + DECLARE_QSFP28_TRANSCEIVER_ATTR(3), + DECLARE_QSFP28_TRANSCEIVER_ATTR(4), + DECLARE_QSFP28_TRANSCEIVER_ATTR(5), + DECLARE_QSFP28_TRANSCEIVER_ATTR(6), + DECLARE_QSFP28_TRANSCEIVER_ATTR(7), + DECLARE_QSFP28_TRANSCEIVER_ATTR(8), + DECLARE_QSFP28_TRANSCEIVER_ATTR(9), + DECLARE_QSFP28_TRANSCEIVER_ATTR(10), + DECLARE_QSFP28_TRANSCEIVER_ATTR(21), + DECLARE_QSFP28_TRANSCEIVER_ATTR(22), + DECLARE_QSFP28_TRANSCEIVER_ATTR(23), + DECLARE_QSFP28_TRANSCEIVER_ATTR(24), + DECLARE_QSFP28_TRANSCEIVER_ATTR(25), + DECLARE_QSFP28_TRANSCEIVER_ATTR(26), + DECLARE_QSFP28_TRANSCEIVER_ATTR(27), + DECLARE_QSFP28_TRANSCEIVER_ATTR(28), + DECLARE_QSFP28_TRANSCEIVER_ATTR(29), + DECLARE_QSFP28_TRANSCEIVER_ATTR(30), + DECLARE_SFP_TRANSCEIVER_ATTR(54), + DECLARE_SFP_TRANSCEIVER_ATTR(55), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static struct attribute *as7926_40xfb_cpld3_attributes[] = { + DECLARE_QSFP28_TRANSCEIVER_ATTR(11), + DECLARE_QSFP28_TRANSCEIVER_ATTR(12), + DECLARE_QSFP28_TRANSCEIVER_ATTR(13), + DECLARE_QSFP28_TRANSCEIVER_ATTR(14), + DECLARE_QSFP28_TRANSCEIVER_ATTR(15), + DECLARE_QSFP28_TRANSCEIVER_ATTR(16), + DECLARE_QSFP28_TRANSCEIVER_ATTR(17), + DECLARE_QSFP28_TRANSCEIVER_ATTR(18), + DECLARE_QSFP28_TRANSCEIVER_ATTR(19), + DECLARE_QSFP28_TRANSCEIVER_ATTR(20), + DECLARE_QSFP28_TRANSCEIVER_ATTR(31), + DECLARE_QSFP28_TRANSCEIVER_ATTR(32), + DECLARE_QSFP28_TRANSCEIVER_ATTR(33), + DECLARE_QSFP28_TRANSCEIVER_ATTR(34), + DECLARE_QSFP28_TRANSCEIVER_ATTR(35), + DECLARE_QSFP28_TRANSCEIVER_ATTR(36), + DECLARE_QSFP28_TRANSCEIVER_ATTR(37), + DECLARE_QSFP28_TRANSCEIVER_ATTR(38), + DECLARE_QSFP28_TRANSCEIVER_ATTR(39), + DECLARE_QSFP28_TRANSCEIVER_ATTR(40), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static struct attribute *as7926_40xfb_cpld4_attributes[] = { + DECLARE_QSFPDD_TRANSCEIVER_ATTR(41), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(42), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(43), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(44), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(45), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(46), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(47), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(48), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(49), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(50), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(51), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(52), + DECLARE_QSFPDD_TRANSCEIVER_ATTR(53), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static struct attribute *as7926_40xfb_7sgmt_attributes[] = { + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as7926_40xfb_cpld2_group = { + .attrs = as7926_40xfb_cpld2_attributes, +}; + +static const struct attribute_group as7926_40xfb_cpld3_group = { + .attrs = as7926_40xfb_cpld3_attributes, +}; + +static const struct attribute_group as7926_40xfb_cpld4_group = { + .attrs = as7926_40xfb_cpld4_attributes, +}; + +static const struct attribute_group as7926_40xfb_7sgmt_group = { + .attrs = as7926_40xfb_7sgmt_attributes, +}; + +static const struct attribute_group *cpld_groups[] = { + &as7926_40xfb_cpld2_group, + &as7926_40xfb_cpld3_group, + &as7926_40xfb_cpld4_group, + &as7926_40xfb_7sgmt_group +}; + +int as7926_40xfb_cpld_read(int bus_num, unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) { + cpld_node = + list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr + && cpld_node->client->adapter->nr == bus_num) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} + +EXPORT_SYMBOL(as7926_40xfb_cpld_read); + +int as7926_40xfb_cpld_write(int bus_num, unsigned short cpld_addr, u8 reg, + u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr + && cpld_node->client->adapter->nr == bus_num) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} + +EXPORT_SYMBOL(as7926_40xfb_cpld_write); + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, invert = 1; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_2: + case MODULE_PRESENT_3 ... MODULE_PRESENT_4: + case MODULE_PRESENT_21 ... MODULE_PRESENT_22: + case MODULE_PRESENT_23 ... MODULE_PRESENT_24: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_5 ... MODULE_PRESENT_6: + case MODULE_PRESENT_7 ... MODULE_PRESENT_8: + case MODULE_PRESENT_25 ... MODULE_PRESENT_26: + case MODULE_PRESENT_27 ... MODULE_PRESENT_28: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_5); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_10: + case MODULE_PRESENT_29 ... MODULE_PRESENT_30: + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_11 ... MODULE_PRESENT_12: + case MODULE_PRESENT_13 ... MODULE_PRESENT_14: + case MODULE_PRESENT_31 ... MODULE_PRESENT_32: + case MODULE_PRESENT_33 ... MODULE_PRESENT_34: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_11); + break; + case MODULE_PRESENT_15 ... MODULE_PRESENT_16: + case MODULE_PRESENT_17 ... MODULE_PRESENT_18: + case MODULE_PRESENT_35 ... MODULE_PRESENT_36: + case MODULE_PRESENT_37 ... MODULE_PRESENT_38: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_15); + break; + case MODULE_PRESENT_19 ... MODULE_PRESENT_20: + case MODULE_PRESENT_39 ... MODULE_PRESENT_40: + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_19); + break; + case MODULE_PRESENT_41 ... MODULE_PRESENT_48: /*QSFP-DD */ + reg = 0x50; + mask = 0x1 << (attr->index - MODULE_PRESENT_41); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_53: /*QSFP-DD */ + reg = 0x51; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + break; + case MODULE_RESET_1 ... MODULE_RESET_2: + case MODULE_RESET_3 ... MODULE_RESET_4: + case MODULE_RESET_21 ... MODULE_RESET_22: + case MODULE_RESET_23 ... MODULE_RESET_24: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_1); + break; + case MODULE_RESET_5 ... MODULE_RESET_6: + case MODULE_RESET_7 ... MODULE_RESET_8: + case MODULE_RESET_25 ... MODULE_RESET_26: + case MODULE_RESET_27 ... MODULE_RESET_28: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_5); + break; + case MODULE_RESET_9 ... MODULE_RESET_10: + case MODULE_RESET_29 ... MODULE_RESET_30: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_9); + break; + case MODULE_RESET_11 ... MODULE_RESET_12: + case MODULE_RESET_13 ... MODULE_RESET_14: + case MODULE_RESET_31 ... MODULE_RESET_32: + case MODULE_RESET_33 ... MODULE_RESET_34: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_11); + break; + case MODULE_RESET_15 ... MODULE_RESET_16: + case MODULE_RESET_17 ... MODULE_RESET_18: + case MODULE_RESET_35 ... MODULE_RESET_36: + case MODULE_RESET_37 ... MODULE_RESET_38: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_15); + break; + case MODULE_RESET_19 ... MODULE_RESET_20: + case MODULE_RESET_39 ... MODULE_RESET_40: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_19); + break; + case MODULE_RESET_41 ... MODULE_RESET_48: /*QSFP-DD */ + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_41); + break; + case MODULE_RESET_49 ... MODULE_RESET_53: /*QSFP-DD */ + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + case MODULE_PRESENT_54 ... MODULE_PRESENT_55: + reg = 0x13; + mask = 0x1 << (attr->index - MODULE_PRESENT_54); + break; + case MODULE_TXDISABLE_54 ... MODULE_TXDISABLE_55: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_54); + invert = 0; + break; + case MODULE_RXLOS_54 ... MODULE_RXLOS_55: + reg = 0x23; + mask = 0x1 << (attr->index - MODULE_RXLOS_54); + invert = 0; + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + switch (data->index) { + /* Port 1-20, 41-42 present statuus: read from i2c bus number '12' + and CPLD slave address 0x62 */ + case as7926_40xfb_cpld2: + status = as7926_40xfb_cpld_read(12, 0x62, reg); + break; + /* Port 21-40 present statuus: read from i2c bus number '13' + and CPLD slave address 0x63 */ + case as7926_40xfb_cpld3: + status = as7926_40xfb_cpld_read(13, 0x63, reg); + break; + /* Port 41-53 plug-unplug read from i2c bus number '20' + and CPLD slave address 0x64 */ + case as7926_40xfb_cpld4: + status = as7926_40xfb_cpld_read(20, 0x64, reg); + break; + default: + status = -ENXIO; + break; + } + + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", + invert ? !(status & mask) : ! !(status & mask)); + + exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[4] = { 0 }; + u8 regs_cpld2[] = { 0x10, 0x11, 0x12, 0x13 }; + u8 regs_cpld3[] = { 0x10, 0x11, 0x12 }; + u8 regs_cpld4[] = { 0x50, 0x51 }; + u8 *regs[] = { NULL, regs_cpld2, regs_cpld3, regs_cpld4 }; + u8 size[] = { 0, ARRAY_SIZE(regs_cpld2), + ARRAY_SIZE(regs_cpld3),ARRAY_SIZE(regs_cpld3) }; + u8 bus[] = { 0, 12, 13, 20 }; + u8 addr[] = { 0, 0x62, 0x63, 0x64 }; + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + for (i = 0; i < size[data->index]; i++) { + status = as7926_40xfb_cpld_read(bus[data->index], + addr[data->index], + regs[data->index][i]); + if (status < 0) + goto exit; + + values[i] = ~(u8) status; + } + + mutex_unlock(&data->update_lock); + + switch (data->index) { + case as7926_40xfb_cpld2: + return sprintf(buf, "%.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2] & 0xF, + values[3] & 0x3); + case as7926_40xfb_cpld3: + return sprintf(buf, "%.2x %.2x %.2x\n", + values[0], values[1], (values[2] & 0xF)); + case as7926_40xfb_cpld4: + return sprintf(buf, "%.2x %.2x\n", values[0], + (values[1] & 0x1F)); + default: + return -EINVAL; + } + + exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status, val; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) + return status; + + reg = 0xB; + switch (attr->index) { + case MODULE_TXDISABLE_54: + mask = 0x1; + break; + case MODULE_TXDISABLE_55: + mask = 0x2; + break; + default: + return 0; + } + /* Read current status */ + mutex_lock(&data->update_lock); + val = as7926_40xfb_cpld_read(12, 0x62, reg); + if (unlikely(status < 0)) + goto exit; + + /* Update tx_disable status */ + if (disable) + val |= mask; + else + val &= ~mask; + + status = as7926_40xfb_cpld_write(12, 0x62, reg, val); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + + exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + long reset; + int status, bus, addr; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &reset); + if (status) + return status; + + switch (attr->index) { + case MODULE_RESET_1 ... MODULE_RESET_2: + case MODULE_RESET_3 ... MODULE_RESET_4: + case MODULE_RESET_21 ... MODULE_RESET_22: + case MODULE_RESET_23 ... MODULE_RESET_24: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_1); + break; + case MODULE_RESET_5 ... MODULE_RESET_6: + case MODULE_RESET_7 ... MODULE_RESET_8: + case MODULE_RESET_25 ... MODULE_RESET_26: + case MODULE_RESET_27 ... MODULE_RESET_28: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_5); + break; + case MODULE_RESET_9 ... MODULE_RESET_10: + case MODULE_RESET_29 ... MODULE_RESET_30: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_9); + break; + case MODULE_RESET_11 ... MODULE_RESET_12: + case MODULE_RESET_13 ... MODULE_RESET_14: + case MODULE_RESET_31 ... MODULE_RESET_32: + case MODULE_RESET_33 ... MODULE_RESET_34: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_RESET_11); + break; + case MODULE_RESET_15 ... MODULE_RESET_16: + case MODULE_RESET_17 ... MODULE_RESET_18: + case MODULE_RESET_35 ... MODULE_RESET_36: + case MODULE_RESET_37 ... MODULE_RESET_38: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_RESET_15); + break; + case MODULE_RESET_19 ... MODULE_RESET_20: + case MODULE_RESET_39 ... MODULE_RESET_40: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_19); + break; + case MODULE_RESET_41 ... MODULE_RESET_48: /*QSFP-DD */ + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_RESET_41); + break; + case MODULE_RESET_49 ... MODULE_RESET_53: /*QSFP-DD */ + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + default: + return -ENXIO; + } + + mutex_lock(&data->update_lock); + switch (data->index) { + /* Port 1-20, 41-42 present statuus: read from i2c bus number '12' + and CPLD slave address 0x62 */ + case as7926_40xfb_cpld2: + bus = 12; + addr = 0x62; + break; + /* Port 21-40 present statuus: read from i2c bus number '13' + and CPLD slave address 0x63 */ + case as7926_40xfb_cpld3: + bus = 13; + addr = 0x63; + break; + /* Port 41-53 plug-unplug read from i2c bus number '20' + and CPLD slave address 0x64 */ + case as7926_40xfb_cpld4: + bus = 20; + addr = 0x64; + break; + default: + status = -ENXIO; + goto exit; + } + + /* Read current status */ + status = as7926_40xfb_cpld_read(bus, addr, reg); + if (unlikely(status < 0)) + goto exit; + + /* Update reset status */ + if (reset) + status &= ~mask; + else + status |= mask; + + status = as7926_40xfb_cpld_write(bus, addr, reg, status); + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + + exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as7926_40xfb_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), + GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, + "Can't allocate cpld_client_node (0x%x)\n", + client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as7926_40xfb_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 reg, val; + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", ®, &val) != 2) + return -EINVAL; + + if (reg > 0xFF || val > 0xFF) + return -EINVAL; + + mutex_lock(&data->update_lock); + switch (data->index) { + case as7926_40xfb_cpld2: + status = as7926_40xfb_cpld_write(12, 0x62, reg, val); + break; + case as7926_40xfb_cpld3: + status = as7926_40xfb_cpld_write(13, 0x63, reg, val); + break; + case as7926_40xfb_cpld4: + status = as7926_40xfb_cpld_write(20, 0x64, reg, val); + break; + case as7926_40xfb_7sgmt: + status = as7926_40xfb_cpld_write(32, 0x20, reg, val); + break; + default: + status = -ENXIO; + break; + } + + if (unlikely(status < 0)) + goto exit; + + mutex_unlock(&data->update_lock); + return count; + + exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + + mutex_lock(&data->update_lock); + switch (data->index) { + case as7926_40xfb_cpld2: + status = as7926_40xfb_cpld_read(12, 0x62, 0x1); + break; + case as7926_40xfb_cpld3: + status = as7926_40xfb_cpld_read(13, 0x63, 0x1); + break; + case as7926_40xfb_cpld4: + status = as7926_40xfb_cpld_read(20, 0x64, 0x1); + break; + default: + status = -1; + break; + } + + if (unlikely(status < 0)) { + mutex_unlock(&data->update_lock); + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", status); + exit: + return status; +} + +static int as7926_40xfb_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct as7926_40xfb_cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", + client->addr); + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as7926_40xfb_cpld_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, cpld_groups[data->index]); + if (status) + goto exit_free; + + data->hwmon_dev = + hwmon_device_register_with_info(&client->dev, DRVNAME, NULL, NULL, + NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + as7926_40xfb_cpld_add_client(client); + + dev_info(&client->dev, "%s: cpld '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + + exit_remove: + sysfs_remove_group(&client->dev.kobj, cpld_groups[data->index]); + exit_free: + kfree(data); + exit: + + return status; +} + +static int as7926_40xfb_cpld_remove(struct i2c_client *client) +{ + struct as7926_40xfb_cpld_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, cpld_groups[data->index]); + kfree(data); + as7926_40xfb_cpld_remove_client(client); + + return 0; +} + +static const struct i2c_device_id as7926_40xfb_cpld_id[] = { + {"as7926_40xfb_cpld2", as7926_40xfb_cpld2}, + {"as7926_40xfb_cpld3", as7926_40xfb_cpld3}, + {"as7926_40xfb_cpld4", as7926_40xfb_cpld4}, + {"as7926_40xfb_7sgmt", as7926_40xfb_7sgmt}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, as7926_40xfb_cpld_id); + +static struct i2c_driver as7926_40xfb_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as7926_40xfb_cpld_probe, + .remove = as7926_40xfb_cpld_remove, + .id_table = as7926_40xfb_cpld_id, + .address_list = normal_i2c, +}; + +static int __init as7926_40xfb_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as7926_40xfb_cpld_driver); +} + +static void __exit as7926_40xfb_cpld_exit(void) +{ + i2c_del_driver(&as7926_40xfb_cpld_driver); +} + +module_init(as7926_40xfb_cpld_init); +module_exit(as7926_40xfb_cpld_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb_cpld driver"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-fan.c b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-fan.c new file mode 100644 index 0000000000..ab4575eeb8 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-fan.c @@ -0,0 +1,761 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the as7926_40xfb_fan + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * 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 + +#define DRVNAME "as7926_40xfb_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_FRONT_SPEED 18225 +#define MAX_FAN_REAR_SPEED 13950 + +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 as7926_40xfb_fan_probe(struct platform_device *pdev); +static int as7926_40xfb_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, + NUM_OF_FAN, + NUM_OF_FAN_MODULE = NUM_OF_FAN / 2 +}; + +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 as7926_40xfb_fan_data { + struct platform_device *pdev; + 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; + 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 as7926_40xfb_fan_data *data = NULL; + +static struct platform_driver as7926_40xfb_fan_driver = { + .probe = as7926_40xfb_fan_probe, + .remove = as7926_40xfb_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_RPM_MAX_ATTR_ID(index) FAN##index##_MAX +#define FAN_DIR_ATTR_ID(index) FAN##index##_DIR +#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_RPM_MAX_ATTR_ID(fan_id), \ + FAN_DIR_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 as7926_40xfb_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), + NUM_OF_FAN_ATTR, + FAN_VERSION, + 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 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##_max, S_IRUGO, show_fan, NULL, \ + FAN##index##_MAX); \ + static SENSOR_DEVICE_ATTR(fan##index##_dir, S_IRUGO, show_dir, NULL, \ + FAN##index##_DIR); \ + 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) + +#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##_max.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_dir.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_VER_SENSOR_DEVICE_ATTR(); + +static struct attribute *as7926_40xfb_fan_attributes[] = { + /* 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_VER_ATTR(), + NULL +}; + +static const struct attribute_group as7926_40xfb_fan_group = { + .attrs = as7926_40xfb_fan_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; + + 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)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + 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 as7926_40xfb_fan_data *as7926_40xfb_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; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_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: + 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: + index = (fid % NUM_OF_FAN_MODULE) * FAN_DATA_COUNT; + value = (data->ipmi_resp[index + FAN_PWM] + 1) * 625 / 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: + value = (int)data->ipmi_resp[index + FAN_SPEED0] | + (int)data->ipmi_resp[index + FAN_SPEED1] << 8; + break; + case FAN1_MAX: + case FAN2_MAX: + case FAN3_MAX: + case FAN4_MAX: + case FAN5_MAX: + value = MAX_FAN_FRONT_SPEED; + break; + case FAN6_MAX: + case FAN7_MAX: + case FAN8_MAX: + case FAN9_MAX: + case FAN10_MAX: + value = MAX_FAN_REAR_SPEED; + 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 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) / 625 - 1; /* Convert pwm to register value */ + + mutex_lock(&data->update_lock); + + /* Send IPMI write command */ + data->ipmi_tx_data[0] = (fid % NUM_OF_FAN_MODULE) + 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; + } + + /* Update pwm to ipmi_resp buffer to prevent from the impact of lazy update */ + data->ipmi_resp[fid * FAN_DATA_COUNT + FAN_PWM] = pwm; + status = count; + + exit: + mutex_unlock(&data->update_lock); + return status; +} + +static struct as7926_40xfb_fan_data *as7926_40xfb_fan_update_cpld_ver(void) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = 0x66; + 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 value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_fan_update_cpld_ver(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp_cpld; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + + 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 = as7926_40xfb_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[40] | (data->ipmi_resp[41] << 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 index = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_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: + value = (int)data->ipmi_resp_speed[FAN_TARGET_SPEED0] | + (int)data->ipmi_resp_speed[FAN_TARGET_SPEED1] << 8; + break; + case FAN6_TARGET: + case FAN7_TARGET: + case FAN8_TARGET: + case FAN9_TARGET: + case FAN10_TARGET: + index = NUM_OF_FAN_MODULE * FAN_SPEED_DATA_COUNT; + value = (int)data->ipmi_resp_speed[index + FAN_TARGET_SPEED0] | + (int)data->ipmi_resp_speed[index + FAN_TARGET_SPEED1] << 8; + break; + case FAN1_TOLERANCE: + case FAN2_TOLERANCE: + case FAN3_TOLERANCE: + case FAN4_TOLERANCE: + case FAN5_TOLERANCE: + value = (int)data->ipmi_resp_speed[FAN_SPEED_TOLERANCE]; + break; + case FAN6_TOLERANCE: + case FAN7_TOLERANCE: + case FAN8_TOLERANCE: + case FAN9_TOLERANCE: + case FAN10_TOLERANCE: + index = NUM_OF_FAN_MODULE * FAN_SPEED_DATA_COUNT; + value = (int)data->ipmi_resp_speed[index + 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 as7926_40xfb_fan_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_fan_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + + exit: + return status; +} + +static int as7926_40xfb_fan_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_fan_group); + + return 0; +} + +static int __init as7926_40xfb_fan_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_fan_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7926_40xfb_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(&as7926_40xfb_fan_driver); + dri_reg_err: + kfree(data); + alloc_err: + return ret; +} + +static void __exit as7926_40xfb_fan_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_fan_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb fan driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_fan_init); +module_exit(as7926_40xfb_fan_exit); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-leds.c b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-leds.c new file mode 100644 index 0000000000..15fa0e16d5 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-leds.c @@ -0,0 +1,674 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the as7926_40xfb_led + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * 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 + +#define DRVNAME "as7926_40xfb_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 + +#define LED_7SGMT_BUS 32 +#define LED_7SGMT_I2C_ADDR 0x20 +#define LED_7SGMT_STATUS_REG_OFFSET 0x02 +#define LED_7SGMT_CONFIG_REG_OFFSET 0x06 + +/* The map of 7-segment LED register value to digital number. + index 0 is for digital number 0, index 10 is for OFF + */ +static const int regval_map_7sgmt[] = { + 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x83, 0xD8, 0x80, 0x98, 0xFF +}; + +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 set_7sgmt_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 ssize_t show_7sgmt_led(struct device *dev, struct device_attribute *attr, + char *buf); +static int as7926_40xfb_led_probe(struct platform_device *pdev); +static int as7926_40xfb_led_remove(struct platform_device *pdev); + +extern int as7926_40xfb_cpld_read(int bus_num, unsigned short cpld_addr, u8 reg); +extern int as7926_40xfb_cpld_write(int bus_num, unsigned short cpld_addr, u8 reg, + u8 value); + +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 as7926_40xfb_sys_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[4]; /* 0:PSU 1:FAN 2:DIAG 3:LOC */ + struct ipmi_data ipmi; +}; + +struct as7926_40xfb_7segment_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 regval[2]; /* 0:LEFT 1:RIGHT */ +}; + +struct as7926_40xfb_sys_led_data *data_sys = NULL; +struct as7926_40xfb_7segment_led_data *data_7sgmt = NULL; + +static struct platform_driver as7926_40xfb_led_driver = { + .probe = as7926_40xfb_led_probe, + .remove = as7926_40xfb_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, +}; + +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 as7926_40xfb_led_sysfs_attrs { + LED_PSU, + LED_LOC, + LED_DIAG, + LED_FAN, + LED_7SGMT_LEFT, + LED_7SGMT_RIGHT +}; + +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_psu, S_IRUGO, show_led, NULL, LED_PSU); +static SENSOR_DEVICE_ATTR(led_fan, S_IRUGO, show_led, NULL, LED_FAN); +static SENSOR_DEVICE_ATTR(led_7sgmt_left, S_IWUSR | S_IRUGO, show_7sgmt_led, + set_7sgmt_led, LED_7SGMT_LEFT); +static SENSOR_DEVICE_ATTR(led_7sgmt_right, S_IWUSR | S_IRUGO, show_7sgmt_led, + set_7sgmt_led, LED_7SGMT_RIGHT); + +static struct attribute *as7926_40xfb_led_attributes[] = { + &sensor_dev_attr_led_loc.dev_attr.attr, + &sensor_dev_attr_led_diag.dev_attr.attr, + &sensor_dev_attr_led_psu.dev_attr.attr, + &sensor_dev_attr_led_fan.dev_attr.attr, + &sensor_dev_attr_led_7sgmt_left.dev_attr.attr, + &sensor_dev_attr_led_7sgmt_right.dev_attr.attr, + NULL +}; + +static const struct attribute_group as7926_40xfb_led_group = { + .attrs = as7926_40xfb_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_sys->pdev->dev, "request_timeout=%x\n", err); + return err; + ipmi_req_err: + dev_err(&data_sys->pdev->dev, "request_settime=%x\n", err); + return err; + addr_err: + dev_err(&data_sys->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; + + 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_sys->pdev->dev, + "ipmi_send_message_%d err status(%d)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data_sys->pdev->dev, + "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + 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_sys->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 as7926_40xfb_sys_led_data *as7926_40xfb_sys_led_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data_sys->last_updated + HZ * 5) && data_sys->valid) { + return data_sys; + } + + data_sys->valid = 0; + status = ipmi_send_message(&data_sys->ipmi, IPMI_LED_READ_CMD, NULL, 0, + data_sys->ipmi_resp, sizeof(data_sys->ipmi_resp)); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data_sys->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data_sys->last_updated = jiffies; + data_sys->valid = 1; + + exit: + return data_sys; +} + +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; + + if (attr->index == LED_PSU || attr->index == LED_FAN) + return sprintf(buf, "%d\n", LED_MODE_AUTO); + + mutex_lock(&data_sys->update_lock); + + as7926_40xfb_sys_led_update_device(); + if (!data_sys->valid) { + error = -EIO; + goto exit; + } + + switch (data_sys->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; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data_sys->update_lock); + return sprintf(buf, "%d\n", value); + + exit: + mutex_unlock(&data_sys->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_sys->update_lock); + + as7926_40xfb_sys_led_update_device(); + if (!data_sys->valid) { + status = -EIO; + goto exit; + } + + data_sys->ipmi_resp[0] = attr->index + 1; + + switch (mode) { + case LED_MODE_OFF: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_OFF; + break; + case LED_MODE_RED: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_RED; + break; + case LED_MODE_RED_BLINKING: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_RED_BLINKING; + break; + case LED_MODE_GREEN: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_GREEN; + break; + case LED_MODE_GREEN_BLINKING: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_GREEN_BLINKING; + break; + case LED_MODE_BLUE: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_BLUE; + break; + case LED_MODE_BLUE_BLINKING: + data_sys->ipmi_resp[1] = IPMI_LED_MODE_BLUE_BLINKING; + break; + default: + status = -EINVAL; + goto exit; + } + + /* Send IPMI write command */ + status = ipmi_send_message(&data_sys->ipmi, IPMI_LED_WRITE_CMD, + data_sys->ipmi_resp, 2, NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data_sys->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data_sys->valid = 0; /* Force next update if led is set successfully */ + status = count; + + exit: + mutex_unlock(&data_sys->update_lock); + return status; +} + +static struct as7926_40xfb_7segment_led_data *as7926_40xfb_7sgmt_led_update_device(void) +{ + int i, status = 0; + + if (time_before(jiffies, data_7sgmt->last_updated + HZ * 5) && data_7sgmt->valid) { + return data_7sgmt; + } + + data_7sgmt->valid = 0; + + /* Read led status */ + for (i = 0; i < ARRAY_SIZE(data_7sgmt->regval); i++) { + status = as7926_40xfb_cpld_read(LED_7SGMT_BUS, LED_7SGMT_I2C_ADDR, LED_7SGMT_STATUS_REG_OFFSET+i); + if (status < 0) { + dev_dbg(&data_7sgmt->pdev->dev, "7-segment led reg (0x%x) err %d\n", LED_7SGMT_STATUS_REG_OFFSET+i, status); + goto exit; + } + else { + data_7sgmt->regval[i] = status; + } + } + + data_7sgmt->last_updated = jiffies; + data_7sgmt->valid = 1; + + exit: + return data_7sgmt; +} + +static int seven_sgmt_led_regval_to_digit(int regval) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(regval_map_7sgmt); i++) { + if (regval == regval_map_7sgmt[i]) + return i; + } + + return -EINVAL; +} + +static int seven_sgmt_led_digit_to_regval(int digit) +{ + if (digit < 0 || digit >= ARRAY_SIZE(regval_map_7sgmt)) + return -EINVAL; + + return regval_map_7sgmt[digit]; +} + +static ssize_t show_7sgmt_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int status = 0; + + mutex_lock(&data_7sgmt->update_lock); + + as7926_40xfb_7sgmt_led_update_device(); + if (!data_7sgmt->valid) { + status = -EIO; + goto exit; + } + + status = data_7sgmt->regval[attr->index - LED_7SGMT_LEFT]; + status = seven_sgmt_led_regval_to_digit(status); + if (status < 0) + goto exit; + + mutex_unlock(&data_7sgmt->update_lock); + return sprintf(buf, "%d\n", status); + + exit: + mutex_unlock(&data_7sgmt->update_lock); + return status; +} + +static ssize_t set_7sgmt_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long mode; + int reg; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &mode); + if (status) + return status; + + mutex_lock(&data_7sgmt->update_lock); + + /* enable write access for 7-segment led */ + reg = LED_7SGMT_CONFIG_REG_OFFSET + (attr->index - LED_7SGMT_LEFT); + status = as7926_40xfb_cpld_write(LED_7SGMT_BUS, LED_7SGMT_I2C_ADDR, reg, 0); + if (status < 0) + goto exit; + + status = seven_sgmt_led_digit_to_regval(mode); + if (status < 0) + goto exit; + + reg = LED_7SGMT_STATUS_REG_OFFSET + (attr->index - LED_7SGMT_LEFT); + status = as7926_40xfb_cpld_write(LED_7SGMT_BUS, LED_7SGMT_I2C_ADDR, reg, status); + if (status < 0) + goto exit; + + data_7sgmt->valid = 0; /* Force next update if led is set successfully */ + status = count; + + exit: + mutex_unlock(&data_7sgmt->update_lock); + return status; +} + +static int as7926_40xfb_led_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_led_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + + exit: + return status; +} + +static int as7926_40xfb_led_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_led_group); + + return 0; +} + +static int __init as7926_40xfb_led_init(void) +{ + int ret; + + data_sys = kzalloc(sizeof(struct as7926_40xfb_sys_led_data), GFP_KERNEL); + if (!data_sys) { + ret = -ENOMEM; + goto alloc_err; + } + + data_7sgmt = kzalloc(sizeof(struct as7926_40xfb_7segment_led_data), GFP_KERNEL); + if (!data_7sgmt) { + ret = -ENOMEM; + goto alloc_err_7sgmt; + } + + mutex_init(&data_sys->update_lock); + mutex_init(&data_7sgmt->update_lock); + data_sys->valid = 0; + data_7sgmt->valid = 0; + + ret = platform_driver_register(&as7926_40xfb_led_driver); + if (ret < 0) + goto dri_reg_err; + + data_sys->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data_sys->pdev)) { + ret = PTR_ERR(data_sys->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data_sys->ipmi, 0, &data_sys->pdev->dev); + if (ret) + goto ipmi_err; + + data_7sgmt->pdev = data_sys->pdev; + + return 0; + + ipmi_err: + platform_device_unregister(data_sys->pdev); + dev_reg_err: + platform_driver_unregister(&as7926_40xfb_led_driver); + dri_reg_err: + kfree(data_7sgmt); + alloc_err_7sgmt: + kfree(data_sys); + alloc_err: + return ret; +} + +static void __exit as7926_40xfb_led_exit(void) +{ + ipmi_destroy_user(data_sys->ipmi.user); + platform_device_unregister(data_sys->pdev); + platform_driver_unregister(&as7926_40xfb_led_driver); + kfree(data_7sgmt); + kfree(data_sys); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("AS7926 40XFB led driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_led_init); +module_exit(as7926_40xfb_led_exit); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-psu.c b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-psu.c new file mode 100644 index 0000000000..162b79d464 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-psu.c @@ -0,0 +1,922 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the as7926_40xfb_psu + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * 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 + +#define DRVNAME "as7926_40xfb_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 as7926_40xfb_psu_probe(struct platform_device *pdev); +static int as7926_40xfb_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_TEMP0, + PSU_TEMP1, + PSU_FAN0, + PSU_FAN1, + PSU_VOUT_MODE, + PSU_STATUS_COUNT, + PSU_MODEL = 0, + PSU_SERIAL = 0, + PSU_TEMP_MAX0 = 2, + PSU_TEMP_MAX1, + PSU_TEMP_MIN0, + PSU_TEMP_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, +}; + +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 ipmi_psu_resp_data { + unsigned char status[32]; + unsigned char info[38]; + char serial[IPMI_MODEL_SERIAL_LEN + 1]; + char model[IPMI_MODEL_SERIAL_LEN + 1]; + char fandir[IPMI_FAN_DIR_LEN + 1]; +}; + +struct as7926_40xfb_psu_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid[3]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ + unsigned long last_updated[3]; /* In jiffies, 0: PSU1, 1: PSU2 */ + struct ipmi_data ipmi; + struct ipmi_psu_resp_data ipmi_resp[3]; /* 0: PSU1, 1: PSU2 */ + unsigned char ipmi_tx_data[2]; +}; + +struct as7926_40xfb_psu_data *data = NULL; + +static struct platform_driver as7926_40xfb_psu_driver = { + .probe = as7926_40xfb_psu_probe, + .remove = as7926_40xfb_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_TEMP_INPUT_ATTR_ID(index) PSU##index##_TEMP_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_TEMP_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP_INPUT_MAX +#define PSU_TEMP_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP_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_TEMP_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_DIR_ATTR_ID(psu_id), \ + PSU_TEMP_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP_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 as7926_40xfb_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##_TEMP_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##_TEMP_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP_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##_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##_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); +DECLARE_PSU_SENSOR_DEVICE_ATTR(2); + +static struct attribute *as7926_40xfb_psu_attributes[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(1), + DECLARE_PSU_ATTR(2), + NULL +}; + +static const struct attribute_group as7926_40xfb_psu_group = { + .attrs = as7926_40xfb_psu_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; + + 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)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + 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 as7926_40xfb_psu_data *as7926_40xfb_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)); + 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); + 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); + 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); + 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)); + 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; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_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_TEMP_INPUT: + case PSU2_TEMP_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32) data->ipmi_resp[pid].status[PSU_TEMP0] | + (u32) data->ipmi_resp[pid].status[PSU_TEMP1] << 8); + break; + case PSU1_FAN_INPUT: + case PSU2_FAN_INPUT: + VALIDATE_PRESENT_RETURN(pid); + 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; + u32 value = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as7926_40xfb_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_TEMP_INPUT_MAX: + case PSU2_TEMP_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32) data->ipmi_resp[pid].info[PSU_TEMP_MAX0] | + (u32) data->ipmi_resp[pid].info[PSU_TEMP_MAX1] << 8); + break; + case PSU1_TEMP_INPUT_MIN: + case PSU2_TEMP_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32) data->ipmi_resp[pid].info[PSU_TEMP_MIN0] | + (u32) data->ipmi_resp[pid].info[PSU_TEMP_MIN1] << 8); + 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 = as7926_40xfb_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 as7926_40xfb_psu_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_psu_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + + exit: + return status; +} + +static int as7926_40xfb_psu_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_psu_group); + return 0; +} + +static int __init as7926_40xfb_psu_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_psu_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as7926_40xfb_psu_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(&as7926_40xfb_psu_driver); + dri_reg_err: + kfree(data); + alloc_err: + return ret; +} + +static void __exit as7926_40xfb_psu_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_psu_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_psu_init); +module_exit(as7926_40xfb_psu_exit); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-sys.c b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-sys.c new file mode 100644 index 0000000000..45f4304421 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-sys.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the as7926_40xfb_sys + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * 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 + +#define DRVNAME "as7926_40xfb_sys" +#define ACCTON_IPMI_NETFN 0x34 + +#define IPMI_SYSEEPROM_READ_CMD 0x18 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_READ_MAX_LEN 128 + +#define EEPROM_NAME "eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ + +static int as7926_40xfb_sys_probe(struct platform_device *pdev); +static int as7926_40xfb_sys_remove(struct platform_device *pdev); +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); + +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 as7926_40xfb_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_eeprom[EEPROM_SIZE]; + unsigned char ipmi_tx_data[2]; + struct bin_attribute eeprom; /* eeprom data */ +}; + +struct as7926_40xfb_sys_data *data = NULL; + +static struct platform_driver as7926_40xfb_sys_driver = { + .probe = as7926_40xfb_sys_probe, + .remove = as7926_40xfb_sys_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +/* 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; + + 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)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err rx_result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + 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 ssize_t sys_eeprom_read(loff_t off, char *buf, size_t count) +{ + int status = 0; + unsigned char length = 0; + + if ((off + count) > EEPROM_SIZE) { + return -EINVAL; + } + + length = (count >= IPMI_READ_MAX_LEN) ? IPMI_READ_MAX_LEN : count; + data->ipmi_tx_data[0] = (off & 0xff); + data->ipmi_tx_data[1] = length; + status = ipmi_send_message(&data->ipmi, IPMI_SYSEEPROM_READ_CMD, + data->ipmi_tx_data, + sizeof(data->ipmi_tx_data), + data->ipmi_resp_eeprom + off, length); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = length; /* Read length */ + memcpy(buf, data->ipmi_resp_eeprom + off, length); + + exit: + return status; +} + +static ssize_t sysfs_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sys_eeprom_read(off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; + +} + +static int sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IRUGO; + eeprom->read = sysfs_bin_read; + eeprom->write = NULL; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + return sysfs_create_bin_file(kobj, eeprom); +} + +static int sysfs_eeprom_cleanup(struct kobject *kobj, + struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + +static int as7926_40xfb_sys_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_eeprom_init(&pdev->dev.kobj, &data->eeprom); + if (status) { + goto exit; + } + + dev_info(&pdev->dev, "device created\n"); + + return 0; + + exit: + return status; +} + +static int as7926_40xfb_sys_remove(struct platform_device *pdev) +{ + sysfs_eeprom_cleanup(&pdev->dev.kobj, &data->eeprom); + + return 0; +} + +static int __init as7926_40xfb_sys_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as7926_40xfb_sys_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as7926_40xfb_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(&as7926_40xfb_sys_driver); + dri_reg_err: + kfree(data); + alloc_err: + return ret; +} + +static void __exit as7926_40xfb_sys_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_sys_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as7926_40xfb_sys driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_sys_init); +module_exit(as7926_40xfb_sys_exit); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-thermal.c b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-thermal.c new file mode 100644 index 0000000000..6a7e43c726 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/modules/builds/x86-64-accton-as7926-40xfb-thermal.c @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the as7926_40xfb_thermal + * + * Copyright (C) 2019 Accton Technology Corporation. + * Brandon Chuang + * + * 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 + +#define DRVNAME "as7926_40xfb_thermal" +#define THERMAL_COUNT 10 +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_THERMAL_READ_CMD 0x12 +#define IPMI_THERMAL_WRITE_CMD 0x13 + +#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); +static ssize_t set_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int as7926_40xfb_thermal_probe(struct platform_device *pdev); +static int as7926_40xfb_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 as7926_40xfb_thermal_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + char ipmi_resp[THERMAL_COUNT * TEMP_DATA_COUNT]; /* 3 bytes for each thermal */ + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[2]; /* 0: thermal id, 1: temp */ + char temp_max[THERMAL_COUNT]; +}; + +struct as7926_40xfb_thermal_data *data = NULL; + +static struct platform_driver as7926_40xfb_thermal_driver = { + .probe = as7926_40xfb_thermal_probe, + .remove = as7926_40xfb_thermal_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as7926_40xfb_thermal_sysfs_attrs { + TEMP1_INPUT, + TEMP2_INPUT, + TEMP3_INPUT, + TEMP4_INPUT, + TEMP5_INPUT, + TEMP6_INPUT, + TEMP7_INPUT, + TEMP8_INPUT, + TEMP9_INPUT, + TEMP10_INPUT, + TEMP1_MAX, + TEMP2_MAX, + TEMP3_MAX, + TEMP4_MAX, + TEMP5_MAX, + TEMP6_MAX, + TEMP7_MAX, + TEMP8_MAX, + TEMP9_MAX, + TEMP10_MAX, +}; + +#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##_max, S_IWUSR | S_IRUGO, show_temp,\ + set_max, TEMP##index##_MAX) + +#define DECLARE_THERMAL_ATTR(index) \ + &sensor_dev_attr_temp##index##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##index##_max.dev_attr.attr + +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); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(9); +DECLARE_THERMAL_SENSOR_DEVICE_ATTR(10); + +static struct attribute *as7926_40xfb_thermal_attributes[] = { + 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), + DECLARE_THERMAL_ATTR(9), + DECLARE_THERMAL_ATTR(10), + NULL +}; + +static const struct attribute_group as7926_40xfb_thermal_group = { + .attrs = as7926_40xfb_thermal_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; + + 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)\r\n", + retry, status); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)\r\n", + retry, ipmi->rx_result); + continue; + } + + break; + } + + 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 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 (attr->index >= TEMP1_MAX && attr->index <= TEMP10_MAX) { + int max = data->temp_max[attr->index - TEMP1_MAX]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", max * 1000); + } + + 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 ssize_t set_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long temp; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &temp); + if (status) + return status; + + if (temp > 127 || temp < -128) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->temp_max[attr->index - TEMP1_MAX] = temp; + status = count; + mutex_unlock(&data->update_lock); + + return status; +} + +static int as7926_40xfb_thermal_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as7926_40xfb_thermal_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + + exit: + return status; +} + +static int as7926_40xfb_thermal_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as7926_40xfb_thermal_group); + + return 0; +} + +static int __init as7926_40xfb_thermal_init(void) +{ + int ret; + int i = 0; + + data = kzalloc(sizeof(struct as7926_40xfb_thermal_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as7926_40xfb_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; + + for (i = 0; i < ARRAY_SIZE(data->temp_max); i++) { + data->temp_max[i] = 70; /* default high threshold */ + } + + return 0; + + ipmi_err: + platform_device_unregister(data->pdev); + dev_reg_err: + platform_driver_unregister(&as7926_40xfb_thermal_driver); + dri_reg_err: + kfree(data); + alloc_err: + return ret; +} + +static void __exit as7926_40xfb_thermal_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as7926_40xfb_thermal_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("AS7926 40xfb Thermal driver"); +MODULE_LICENSE("GPL"); + +module_init(as7926_40xfb_thermal_init); +module_exit(as7926_40xfb_thermal_exit); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/Makefile new file mode 100644 index 0000000000..502e772a7b --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/PKG.yml b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/PKG.yml new file mode 100644 index 0000000000..8b1349a29c --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/onlp-platform-any.yml PLATFORM=x86-64-accton-as7926-40xfb ARCH=amd64 TOOLCHAIN=x86_64-linux-gnu diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/Makefile new file mode 100644 index 0000000000..e7437cb23a --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/Makefile @@ -0,0 +1,2 @@ +FILTER=src +include $(ONL)/make/subdirs.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/lib/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/lib/Makefile new file mode 100644 index 0000000000..d9a5175150 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/lib/Makefile @@ -0,0 +1,3 @@ +PLATFORM := x86-64-accton-as7926-40xfb +include $(ONL)/packages/base/any/onlp/builds/platform/libonlp-platform.mk + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/onlps/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/onlps/Makefile new file mode 100644 index 0000000000..e93011ea44 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/onlps/Makefile @@ -0,0 +1,3 @@ +PLATFORM := x86-64-accton-as7926-40xfb +include $(ONL)/packages/base/any/onlp/builds/platform/onlps.mk + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/.module b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/.module new file mode 100644 index 0000000000..5c449c8a51 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/.module @@ -0,0 +1 @@ +name: x86_64_accton_as7926_40xfb diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/Makefile new file mode 100644 index 0000000000..7efc193dad --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/Makefile @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### +include $(ONL)/make/config.mk +MODULE := x86_64_accton_as7926_40xfb +AUTOMODULE := x86_64_accton_as7926_40xfb +include $(BUILDER)/definemodule.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/README b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/README new file mode 100644 index 0000000000..bd11c2a8cb --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/README @@ -0,0 +1,6 @@ +############################################################################### +# +# x86_64_accton_as7926_40xfb README +# +############################################################################### + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/make.mk b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/make.mk new file mode 100644 index 0000000000..ca2caa996a --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/make.mk @@ -0,0 +1,9 @@ +############################################################################### +# +# x86_64_accton_as7926_40xfb Autogeneration +# +############################################################################### +x86_64_accton_as7926_40xfb_AUTO_DEFS := module/auto/x86_64_accton_as7926_40xfb.yml +x86_64_accton_as7926_40xfb_AUTO_DIRS := module/inc/x86_64_accton_as7926_40xfb module/src +include $(BUILDER)/auto.mk + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/x86_64_accton_as7926_40xfb.yml b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/x86_64_accton_as7926_40xfb.yml new file mode 100644 index 0000000000..2ce9be7a72 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/auto/x86_64_accton_as7926_40xfb.yml @@ -0,0 +1,52 @@ +############################################################################### +# +# x86_64_accton_as7926_40xfb Autogeneration Definitions +# +############################################################################### + +cdefs: &cdefs +- X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING: + doc: "Include or exclude logging." + default: 1 +- X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT: + doc: "Default enabled log options." + default: AIM_LOG_OPTIONS_DEFAULT +- X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT: + doc: "Default enabled log bits." + default: AIM_LOG_BITS_DEFAULT +- X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT: + doc: "Default enabled custom log bits." + default: 0 +- X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB: + doc: "Default all porting macros to use the C standard libraries." + default: 1 +- X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS: + doc: "Include standard library headers for stdlib porting macros." + default: x86_64_accton_as7926_40xfb_CONFIG_PORTING_STDLIB +- X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI: + doc: "Include generic uCli support." + default: 0 +- X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION: + doc: "Assume chassis fan direction is the same as the PSU fan direction." + default: 0 +- X86_64_ACCTON_AS7926_40XFB_CONFIG_SYS_FAN_FRONT_RPM_MAX: + doc: "Maximum system fan(Front) rpm." + default: 18225 + +definitions: + cdefs: + X86_64_ACCTON_AS7926_40XFB_CONFIG_HEADER: + defs: *cdefs + basename: x86_64_accton_as7926_40xfb_config + + portingmacro: + x86_64_accton_as7926_40xfb: + macros: + - malloc + - free + - memset + - memcpy + - strncpy + - vsnprintf + - snprintf + - strlen diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb.x b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb.x new file mode 100644 index 0000000000..6949b0094f --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb.x @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.xmacro(ALL).define> */ +/* */ + +/* <--auto.start.xenum(ALL).define> */ +/* */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_config.h b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_config.h new file mode 100644 index 0000000000..be4865b13d --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_config.h @@ -0,0 +1,147 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_accton_as7926_40xfb Configuration Header + * + * @addtogroup x86_64_accton_as7926_40xfb-config + * @{ + * + *****************************************************************************/ +#ifndef __x86_64_accton_as7926_40xfb_CONFIG_H__ +#define __x86_64_accton_as7926_40xfb_CONFIG_H__ + +#ifdef GLOBAL_INCLUDE_CUSTOM_CONFIG +#include +#endif +#ifdef x86_64_accton_as7926_40xfb_INCLUDE_CUSTOM_CONFIG +#include +#endif + +/* */ +#include +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING + * + * Include or exclude logging. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING 1 +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT + * + * Default enabled log options. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT AIM_LOG_OPTIONS_DEFAULT +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT + * + * Default enabled log bits. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT AIM_LOG_BITS_DEFAULT +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT + * + * Default enabled custom log bits. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT 0 +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB + * + * Default all porting macros to use the C standard libraries. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB 1 +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + * + * Include standard library headers for stdlib porting macros. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS x86_64_accton_as7926_40xfb_CONFIG_PORTING_STDLIB +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI + * + * Include generic uCli support. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI 0 +#endif + +/** + * X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION + * + * Assume chassis fan direction is the same as the PSU fan direction. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION 0 +#endif + +/** + * x86_64_accton_as7926_40xfb_CONFIG_SYS_FAN_FRONT_RPM_MAX + * + * Maximum system fan(Front) rpm. */ + + +#ifndef X86_64_ACCTON_AS7926_40XFB_CONFIG_SYS_FAN_FRONT_RPM_MAX +#define X86_64_ACCTON_AS7926_40XFB_CONFIG_SYS_FAN_FRONT_RPM_MAX 18225 +#endif + + + +/** + * All compile time options can be queried or displayed + */ + +/** Configuration settings structure. */ +typedef struct x86_64_accton_as7926_40xfb_config_settings_s { + /** name */ + const char* name; + /** value */ + const char* value; +} x86_64_accton_as7926_40xfb_config_settings_t; + +/** Configuration settings table. */ +/** x86_64_accton_as7926_40xfb_config_settings table. */ +extern x86_64_accton_as7926_40xfb_config_settings_t x86_64_accton_as7926_40xfb_config_settings[]; + +/** + * @brief Lookup a configuration setting. + * @param setting The name of the configuration option to lookup. + */ +const char* x86_64_accton_as7926_40xfb_config_lookup(const char* setting); + +/** + * @brief Show the compile-time configuration. + * @param pvs The output stream. + */ +int x86_64_accton_as7926_40xfb_config_show(struct aim_pvs_s* pvs); + +/* */ + +#include "x86_64_accton_as7926_40xfb_porting.h" + +#endif /* __x86_64_accton_as7926_40xfb_CONFIG_H__ */ +/* @} */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_dox.h b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_dox.h new file mode 100644 index 0000000000..caf3598ba3 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_dox.h @@ -0,0 +1,26 @@ +/**************************************************************************//** + * + * x86_64_accton_as7926_40xfb Doxygen Header + * + *****************************************************************************/ +#ifndef __x86_64_accton_as7926_40xfb_DOX_H__ +#define __x86_64_accton_as7926_40xfb_DOX_H__ + +/** + * @defgroup x86_64_accton_as7926_40xfb x86_64_accton_as7926_40xfb - x86_64_accton_as7926_40xfb Description + * + +The documentation overview for this module should go here. + + * + * @{ + * + * @defgroup x86_64_accton_as7926_40xfb-x86_64_accton_as7926_40xfb Public Interface + * @defgroup x86_64_accton_as7926_40xfb-config Compile Time Configuration + * @defgroup x86_64_accton_as7926_40xfb-porting Porting Macros + * + * @} + * + */ + +#endif /* __x86_64_accton_as7926_40xfb_DOX_H__ */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_porting.h b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_porting.h new file mode 100644 index 0000000000..5e6d56fa74 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/inc/x86_64_accton_as7926_40xfb/x86_64_accton_as7926_40xfb_porting.h @@ -0,0 +1,107 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_accton_as7926_40xfb Porting Macros. + * + * @addtogroup x86_64_accton_as7926_40xfb-porting + * @{ + * + *****************************************************************************/ +#ifndef __x86_64_accton_as7926_40xfb_PORTING_H__ +#define __x86_64_accton_as7926_40xfb_PORTING_H__ + + +/* */ +#if X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS == 1 +#include +#include +#include +#include +#include +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_MALLOC + #if defined(GLOBAL_MALLOC) + #define X86_64_ACCTON_AS7926_40XFB_MALLOC GLOBAL_MALLOC + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_MALLOC malloc + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_MALLOC is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_FREE + #if defined(GLOBAL_FREE) + #define X86_64_ACCTON_AS7926_40XFB_FREE GLOBAL_FREE + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_FREE free + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_FREE is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_MEMSET + #if defined(GLOBAL_MEMSET) + #define X86_64_ACCTON_AS7926_40XFB_MEMSET GLOBAL_MEMSET + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_MEMSET memset + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_MEMSET is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_MEMCPY + #if defined(GLOBAL_MEMCPY) + #define X86_64_ACCTON_AS7926_40XFB_MEMCPY GLOBAL_MEMCPY + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_MEMCPY memcpy + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_MEMCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_STRNCPY + #if defined(GLOBAL_STRNCPY) + #define X86_64_ACCTON_AS7926_40XFB_STRNCPY GLOBAL_STRNCPY + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_STRNCPY strncpy + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_STRNCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_VSNPRINTF + #if defined(GLOBAL_VSNPRINTF) + #define X86_64_ACCTON_AS7926_40XFB_VSNPRINTF GLOBAL_VSNPRINTF + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_VSNPRINTF vsnprintf + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_VSNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_SNPRINTF + #if defined(GLOBAL_SNPRINTF) + #define X86_64_ACCTON_AS7926_40XFB_SNPRINTF GLOBAL_SNPRINTF + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_SNPRINTF snprintf + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_SNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS7926_40XFB_STRLEN + #if defined(GLOBAL_STRLEN) + #define X86_64_ACCTON_AS7926_40XFB_STRLEN GLOBAL_STRLEN + #elif X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS7926_40XFB_STRLEN strlen + #else + #error The macro X86_64_ACCTON_AS7926_40XFB_STRLEN is required but cannot be defined. + #endif +#endif + +/* */ + + +#endif /* __x86_64_accton_as7926_40xfb_PORTING_H__ */ +/* @} */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/make.mk b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/make.mk new file mode 100644 index 0000000000..0a1eeeca23 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/make.mk @@ -0,0 +1,10 @@ +############################################################################### +# +# +# +############################################################################### +THIS_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +x86_64_accton_as7926_40xfb_INCLUDES := -I $(THIS_DIR)inc +x86_64_accton_as7926_40xfb_INTERNAL_INCLUDES := -I $(THIS_DIR)src +x86_64_accton_as7926_40xfb_DEPENDMODULE_ENTRIES := init:x86_64_accton_as7926_40xfb ucli:x86_64_accton_as7926_40xfb + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/Makefile new file mode 100644 index 0000000000..8d78af9676 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/Makefile @@ -0,0 +1,9 @@ +############################################################################### +# +# Local source generation targets. +# +############################################################################### + +ucli: + @../../../../tools/uclihandlers.py x86_64_accton_as7926_40xfb_ucli.c + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/attributei.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/attributei.c new file mode 100644 index 0000000000..23094516a5 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/attributei.c @@ -0,0 +1,100 @@ +/************************************************************ + * + * + * Copyright 2017 Big Switch Networks, Inc. + * Copyright 2017 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 "x86_64_accton_as7926_40xfb_log.h" + +#define NUM_OF_CPLD 3 + +#define IDPROM_PATH "/sys/devices/platform/as7926_40xfb_sys/eeprom" + +static char* cpld_path[NUM_OF_CPLD] = { + "/sys/bus/i2c/devices/12-0062/version", + "/sys/bus/i2c/devices/13-0063/version", + "/sys/bus/i2c/devices/20-0064/version" +}; + +int +onlp_attributei_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_attributei_sw_denit(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_attributei_onie_info_get(onlp_oid_t oid, onlp_onie_info_t* rp) +{ + if (oid != ONLP_OID_CHASSIS) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + if (rp == NULL) { + return 1; + } + + return onlp_onie_decode_file(rp, IDPROM_PATH); +} + +int +onlp_attributei_asset_info_get(onlp_oid_t oid, onlp_asset_info_t* rp) +{ + int rv = ONLP_STATUS_OK; + int i, v[NUM_OF_CPLD] = {0}; + + if (oid != ONLP_OID_CHASSIS) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + if (rp == NULL) { + return 1; + } + + rp->oid = oid; + rp->manufacturer = aim_strdup("Accton"); + + for (i = 0; i < AIM_ARRAYSIZE(cpld_path); i++) { + rv = onlp_file_read_int(v+i, cpld_path[i]); + + if (ONLP_FAILURE(rv)) { + break; + } + + if(onlp_file_read_int(v+i, cpld_path[i]) < 0) { + return ONLP_STATUS_E_INTERNAL; + } + } + + if (ONLP_SUCCESS(rv)) { + rp->firmware_revision = aim_fstrdup("%d.%d.%d", v[0], v[1], v[2]); + } + + return rv; +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/chassisi.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/chassisi.c new file mode 100644 index 0000000000..a5c48ff651 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/chassisi.c @@ -0,0 +1,82 @@ +/************************************************************ + * + * + * Copyright 2014, 2015 Big Switch Networks, Inc. + * Copyright 2017 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 "platform_lib.h" + +int +onlp_chassisi_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_chassisi_sw_denit(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_chassisi_hdr_get(onlp_oid_id_t id, onlp_oid_hdr_t* hdr) +{ + int i; + onlp_oid_t* e = hdr->coids; + + ONLP_OID_STATUS_FLAG_SET(hdr, PRESENT); + ONLP_OID_STATUS_FLAG_SET(hdr, OPERATIONAL); + + /* 11 Thermal sensors on the chassis */ + for (i = 1; i <= CHASSIS_THERMAL_COUNT; i++) { + *e++ = ONLP_THERMAL_ID_CREATE(i); + } + + /* 4 LEDs on the chassis */ + for (i = 1; i <= CHASSIS_LED_COUNT; i++) { + *e++ = ONLP_LED_ID_CREATE(i); + } + + /* 3 PSUs on the chassis */ + for (i = 1; i <= CHASSIS_PSU_COUNT; i++) { + *e++ = ONLP_PSU_ID_CREATE(i); + } + + /* 12 Fans on the chassis */ + for (i = 1; i <= CHASSIS_FAN_COUNT; i++) { + *e++ = ONLP_FAN_ID_CREATE(i); + } + + /* 55 Ports */ + for (i = 1; i <= CHASSIS_SFP_COUNT; i++) { + *e++ = ONLP_SFP_ID_CREATE(i); + } + + return ONLP_STATUS_OK; +} + +int onlp_chassisi_info_get(onlp_oid_id_t id, onlp_chassis_info_t* info) +{ + onlp_chassisi_hdr_get(id, &info->hdr); + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/fani.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/fani.c new file mode 100644 index 0000000000..ad045fa3f9 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/fani.c @@ -0,0 +1,356 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2017 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 "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_1_ON_PSU_1, + FAN_1_ON_PSU_2, + ONLP_FAN_MAX +}; + +#define MAX_PSU_FAN_SPEED 23000 + +#define CREATE_FAN_INFO_ON_MAIN_BOARD(fid) \ + { \ + { ONLP_FAN_ID_CREATE(FAN_##fid##_ON_FAN_BOARD), "Fan "#fid, ONLP_OID_CHASSIS, { 0 }, 0 }, \ + 0x0,\ + ONLP_FAN_CAPS_SET_PERCENTAGE | ONLP_FAN_CAPS_GET_RPM | ONLP_FAN_CAPS_GET_PERCENTAGE,\ + 0,\ + 0,\ + } + +#define CREATE_FAN_INFO_ON_PSU(psu_id, fan_id) \ + { \ + { ONLP_FAN_ID_CREATE(FAN_##fan_id##_ON_PSU_##psu_id), "PSU-"#psu_id " Fan "#fan_id, ONLP_PSU_ID_CREATE(psu_id), { 0 }, 0 }, \ + 0x0,\ + ONLP_FAN_CAPS_GET_RPM | ONLP_FAN_CAPS_GET_PERCENTAGE,\ + 0,\ + 0, \ + } + +#define AIM_FREE_IF_PTR(p) \ + do \ + { \ + if (p) { \ + aim_free(p); \ + p = NULL; \ + } \ + } while (0) + +/* Static fan information */ +onlp_fan_info_t finfo[] = { + { }, /* Not used */ + CREATE_FAN_INFO_ON_MAIN_BOARD(1), + CREATE_FAN_INFO_ON_MAIN_BOARD(2), + CREATE_FAN_INFO_ON_MAIN_BOARD(3), + CREATE_FAN_INFO_ON_MAIN_BOARD(4), + CREATE_FAN_INFO_ON_MAIN_BOARD(5), + CREATE_FAN_INFO_ON_MAIN_BOARD(6), + CREATE_FAN_INFO_ON_MAIN_BOARD(7), + CREATE_FAN_INFO_ON_MAIN_BOARD(8), + CREATE_FAN_INFO_ON_MAIN_BOARD(9), + CREATE_FAN_INFO_ON_MAIN_BOARD(10), + CREATE_FAN_INFO_ON_PSU(1,1), + CREATE_FAN_INFO_ON_PSU(2,1) +}; + +static int +_onlp_fani_info_get_fan(int fid, onlp_fan_info_t* info) +{ + char *fandir = NULL; + int len = 0; + int value; + + /* get fan present status + */ + ONLP_TRY(onlp_file_read_int(&value, "%s""fan%d_present", FAN_SYSFS_PATH, fid)); + if (value == 0) { + ONLP_OID_STATUS_FLAG_CLR(info, PRESENT); + return ONLP_STATUS_OK; /* fan is not present */ + } + else { + ONLP_OID_STATUS_FLAG_SET(info, PRESENT); + } + + /* get fan direction + */ + len = onlp_file_read_str(&fandir, "%s""fan%d_dir", FAN_SYSFS_PATH, fid); + if (fandir && len) { + if (strncmp(fandir, "B2F", strlen("B2F")) == 0) { + info->dir = ONLP_FAN_DIR_B2F; + } + else { + info->dir = ONLP_FAN_DIR_F2B; + } + } + AIM_FREE_IF_PTR(fandir); + + /* get fan speed + */ + ONLP_TRY(onlp_file_read_int(&value, "%s""fan%d_input", FAN_SYSFS_PATH, fid)); + info->rpm = value; + + /* get fan fault status (turn on when any one fails) + */ + if (info->rpm == 0) { + ONLP_OID_STATUS_FLAG_SET(info, FAILED); + } + else { + ONLP_OID_STATUS_FLAG_CLR(info, FAILED); + } + + /* get speed percentage from rpm + */ + ONLP_TRY(onlp_file_read_int(&value, "%s""fan%d_max", FAN_SYSFS_PATH, fid)); + if (value) + info->percentage = (info->rpm * 100)/value; + + return ONLP_STATUS_OK; +} + +static int +_onlp_fani_info_get_fan_on_psu(int pid, onlp_fan_info_t* info) +{ + char *fandir = NULL; + int len = 0; + int val = 0; + + ONLP_TRY(onlp_file_read_int(&val, "%s""psu%d_present", PSU_SYSFS_PATH, pid)); + if (val != PSU_STATUS_PRESENT) { + ONLP_OID_STATUS_FLAG_CLR(info, PRESENT); + return ONLP_STATUS_OK; + } + else { + ONLP_OID_STATUS_FLAG_SET(info, PRESENT); + } + + /* get fan direction + */ + len = onlp_file_read_str(&fandir, "%s""psu%d_fan_dir", PSU_SYSFS_PATH, pid); + if (fandir && len) { + if (strncmp(fandir, "B2F", strlen("B2F")) == 0) { + info->dir = ONLP_FAN_DIR_B2F; + } + else { + info->dir = ONLP_FAN_DIR_F2B; + } + } + AIM_FREE_IF_PTR(fandir); + + /* get fan speed + */ + ONLP_TRY(onlp_file_read_int(&val, "%s""psu%d_fan1_input", PSU_SYSFS_PATH, pid)); + info->rpm = val; + + /* get fan fault status (turn on when failed) + */ + if (info->rpm == 0) { + ONLP_OID_STATUS_FLAG_SET(info, FAILED); + } + else { + ONLP_OID_STATUS_FLAG_CLR(info, FAILED); + } + + /* get speed percentage from rpm + */ + info->percentage = (info->rpm * 100)/MAX_PSU_FAN_SPEED; + + return ONLP_STATUS_OK; +} + +/* + * 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_id_t id, int p) +{ + int fid = ONLP_OID_ID_GET(id); + + /* reject p=0 (p=0, stop fan) */ + if (p == 0){ + AIM_LOG_ERROR("Zero percentage is not allowed\r\n"); + return ONLP_STATUS_E_INVALID; + } + + if (fid < FAN_1_ON_FAN_BOARD || fid > FAN_10_ON_FAN_BOARD) { + AIM_LOG_ERROR("Invalid fan id(%d)\r\n", fid); + return ONLP_STATUS_E_INVALID; + } + + return onlp_file_write_int(p, "%s%s%d%s", FAN_SYSFS_PATH, "fan", fid, "_pwm"); +} + +/* + * This function will be called prior to all of onlp_fani_* functions. + */ +int +onlp_fani_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_fani_sw_denit(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_fani_info_get(onlp_oid_id_t id, onlp_fan_info_t* info) +{ + int rc = 0; + int fid; + + fid = ONLP_OID_ID_GET(id); + *info = finfo[fid]; + + switch (fid) { + case FAN_1_ON_PSU_1: + case FAN_1_ON_PSU_2: + rc = _onlp_fani_info_get_fan_on_psu(fid-FAN_1_ON_PSU_1+1, info); + break; + 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: + rc =_onlp_fani_info_get_fan(fid, info); + break; + default: + AIM_LOG_ERROR("Invalid fan id(%d)\r\n", fid); + rc = ONLP_STATUS_E_INVALID; + break; + } + + return rc; +} + +static int +chassis_fani_hdr_get__(int id, onlp_oid_hdr_t* hdr) +{ + int value; + *hdr = finfo[id].hdr; + + ONLP_TRY(onlp_file_read_int(&value, "%s""fan%d_present", FAN_SYSFS_PATH, id)); + if (value == 0) { + ONLP_OID_STATUS_FLAG_CLR(hdr, PRESENT); + return ONLP_STATUS_OK; /* fan is not present */ + } + else { + ONLP_OID_STATUS_FLAG_SET(hdr, PRESENT); + } + + ONLP_TRY(onlp_file_read_int(&value, "%s""fan%d_input", FAN_SYSFS_PATH, id)); + if (value == 0) { + ONLP_OID_STATUS_FLAG_SET(hdr, FAILED); + } + else { + ONLP_OID_STATUS_FLAG_CLR(hdr, FAILED); + } + + return ONLP_STATUS_OK; +} + +static int +psu_fani_hdr_get__(int id, onlp_oid_hdr_t* hdr) +{ + int v; + *hdr = finfo[id].hdr; + + ONLP_TRY(onlp_file_read_int(&v, "%s""psu%d_present", PSU_SYSFS_PATH, id)); + if (v != PSU_STATUS_PRESENT) { + ONLP_OID_STATUS_FLAG_CLR(hdr, PRESENT); + return ONLP_STATUS_OK; + } + else { + ONLP_OID_STATUS_FLAG_SET(hdr, PRESENT); + } + + ONLP_TRY(onlp_file_read_int(&v, "%s""psu%d_fan1_input", PSU_SYSFS_PATH, id)); + if (v == 0) { + ONLP_OID_STATUS_FLAG_SET(hdr, FAILED); + } + else { + ONLP_OID_STATUS_FLAG_CLR(hdr, FAILED); + } + + return ONLP_STATUS_OK; +} + +int +onlp_fani_hdr_get(onlp_oid_t oid, onlp_oid_hdr_t* hdr) +{ + int fid = ONLP_OID_ID_GET(oid); + + switch (fid) { + case FAN_1_ON_PSU_1: + case FAN_1_ON_PSU_2: + return psu_fani_hdr_get__(fid-FAN_1_ON_PSU_1+1, hdr); + 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: + return chassis_fani_hdr_get__(fid, hdr); + default: + AIM_LOG_ERROR("Invalid fan id(%d)\r\n", fid); + break; + } + + return ONLP_STATUS_E_PARAM; +} + +int +onlp_fani_id_validate(onlp_oid_id_t id) +{ + return ONLP_OID_ID_VALIDATE_RANGE(id, 1, ONLP_FAN_MAX-1); +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/ledi.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/ledi.c new file mode 100644 index 0000000000..38f831bead --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/ledi.c @@ -0,0 +1,257 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2017 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 LED_FORMAT "/sys/devices/platform/as7926_40xfb_led/%s" + +/* LED related data + */ +enum onlp_led_id +{ + LED_RESERVED = 0, + LED_PSU, + LED_FAN, + LED_DIAG, + LED_LOC, + LED_7SGMT_LEFT, + LED_7SGMT_RIGHT, + ONLP_LED_MAX +}; + +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 +}; + +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_PSU, LED_MODE_AUTO, ONLP_LED_MODE_AUTO}, + {LED_FAN, LED_MODE_AUTO, ONLP_LED_MODE_AUTO}, + {LED_DIAG, LED_MODE_OFF, ONLP_LED_MODE_OFF}, + {LED_DIAG, LED_MODE_RED, ONLP_LED_MODE_RED}, + {LED_DIAG, LED_MODE_GREEN, ONLP_LED_MODE_GREEN}, + {LED_DIAG, LED_MODE_BLUE, ONLP_LED_MODE_BLUE}, + {LED_LOC, LED_MODE_OFF, ONLP_LED_MODE_OFF}, + {LED_LOC, LED_MODE_RED, ONLP_LED_MODE_RED}, + {LED_LOC, LED_MODE_GREEN, ONLP_LED_MODE_GREEN}, + {LED_LOC, LED_MODE_GREEN_BLINKING, ONLP_LED_MODE_GREEN_BLINKING} +}; + +static char *leds[] = { /* must map with onlp_led_id */ + "reserved", + "led_psu", + "led_fan", + "led_diag", + "led_loc", + "led_7sgmt_left", + "led_7sgmt_right" +}; + +/* + * Get the information for the given LED OID. + */ +static onlp_led_info_t linfo[] = { + { }, /* Not used */ + ONLP_CHASSIS_LED_INFO_ENTRY_INIT(LED_PSU, "Chassis LED 1 (PSU LED)", + ONLP_LED_CAPS_AUTO), + ONLP_CHASSIS_LED_INFO_ENTRY_INIT(LED_FAN, "Chassis LED 2 (FAN LED)", + ONLP_LED_CAPS_AUTO), + ONLP_CHASSIS_LED_INFO_ENTRY_INIT(LED_DIAG, "Chassis LED 3 (DIAG LED)", + ONLP_LED_CAPS_OFF | ONLP_LED_CAPS_RED | ONLP_LED_CAPS_BLUE | + ONLP_LED_CAPS_GREEN | ONLP_LED_CAPS_GREEN_BLINKING), + ONLP_CHASSIS_LED_INFO_ENTRY_INIT(LED_LOC, "Chassis LED 4 (LOC LED)", + ONLP_LED_CAPS_RED | ONLP_LED_CAPS_GREEN | ONLP_LED_CAPS_GREEN_BLINKING), + ONLP_CHASSIS_LED_INFO_ENTRY_INIT(LED_7SGMT_LEFT, "Chassis LED 5 (LEFT 7-SEGMENT LED)", + ONLP_LED_CAPS_OFF | ONLP_LED_CAPS_CHAR), + ONLP_CHASSIS_LED_INFO_ENTRY_INIT(LED_7SGMT_RIGHT, "Chassis LED 6 (RIGHT 7-SEGMENT LED)", + ONLP_LED_CAPS_OFF | ONLP_LED_CAPS_CHAR) +}; + +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; +} + +int +onlp_ledi_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_ledi_sw_denit(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_ledi_hdr_get(onlp_oid_t oid, onlp_oid_hdr_t* hdr) +{ + *hdr = linfo[ONLP_OID_ID_GET(oid)].hdr; + return 0; +} + +/* + * Set the character + * Set c as 0 to 9 will set the character accordingly. + * Set c as other values will turn off the 7-segment led + * */ +int onlp_ledi_char_set(onlp_oid_t id, char c) +{ + int lid = ONLP_OID_ID_GET(id); + + if (!(linfo[lid].caps & ONLP_LED_CAPS_CHAR)) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + switch (c) { + case '0' ... '9': c -= 48; break; // convert to integer + default: c = 10; break; // turn off + } + + return onlp_file_write_int(c, LED_FORMAT, leds[lid]); +} + +/** Get the current character */ +int onlp_ledi_char_get(onlp_oid_t id, char* c) +{ + int lid, value; + + lid = ONLP_OID_ID_GET(id); + + if (!(linfo[lid].caps & ONLP_LED_CAPS_CHAR)) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + /* Get LED character */ + ONLP_TRY(onlp_file_read_int(&value, LED_FORMAT, leds[lid])); + + switch (value) { + case 0 ... 9: *c = (value + 48); break; // convert to digital number + default: *c = 0; break; + } + + return ONLP_STATUS_OK; +} + +int +onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t* info) +{ + int lid, value; + + 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 (linfo[lid].caps & ONLP_LED_CAPS_CHAR) { + ONLP_TRY(onlp_ledi_char_get(id, &info->character)); + if (info->character) { + info->mode = ONLP_LED_MODE_CHAR; + } + else { + info->mode = ONLP_LED_MODE_OFF; + } + } + else { + ONLP_TRY(onlp_file_read_int(&value, LED_FORMAT, leds[lid])); + info->mode = driver_to_onlp_led_mode(lid, value); + } + + return ONLP_STATUS_OK; +} + +/* + * 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 = ONLP_OID_ID_GET(id); + + if (linfo[lid].caps & ONLP_LED_CAPS_CHAR) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + ONLP_TRY(onlp_file_write_int(onlp_to_driver_led_mode(lid , mode), LED_FORMAT, leds[lid])); + return ONLP_STATUS_OK; +} + +int +onlp_ledi_id_validate(onlp_oid_id_t id) +{ + return ONLP_OID_ID_VALIDATE_RANGE(id, 1, ONLP_LED_MAX-1); +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/make.mk b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/make.mk new file mode 100644 index 0000000000..26163d1f88 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/make.mk @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### + +LIBRARY := x86_64_accton_as7926_40xfb +$(LIBRARY)_SUBDIR := $(dir $(lastword $(MAKEFILE_LIST))) +include $(BUILDER)/lib.mk diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platform_lib.h b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platform_lib.h new file mode 100644 index 0000000000..e383169919 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platform_lib.h @@ -0,0 +1,47 @@ +/************************************************************ + * + * + * 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 "x86_64_accton_as7926_40xfb_log.h" + +#define CHASSIS_FAN_COUNT 10 +#define CHASSIS_THERMAL_COUNT 11 +#define CHASSIS_LED_COUNT 6 +#define CHASSIS_PSU_COUNT 2 +#define CHASSIS_SFP_COUNT 55 + +#define PSU1_ID 1 +#define PSU2_ID 2 + +#define PSU_SYSFS_PATH "/sys/devices/platform/as7926_40xfb_psu/" +#define FAN_SYSFS_PATH "/sys/devices/platform/as7926_40xfb_fan/" + +#define PSU_STATUS_PRESENT 1 +#define PSU_STATUS_POWER_GOOD 1 + +#endif /* __PLATFORM_LIB_H__ */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platformi.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platformi.c new file mode 100644 index 0000000000..d14ce979f4 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/platformi.c @@ -0,0 +1,57 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2017 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 "x86_64_accton_as7926_40xfb_log.h" + +const char* +onlp_platformi_get(void) +{ + return "x86-64-accton-as7926-40xfb-r0"; +} + +int +onlp_platformi_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_platformi_manage_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_platformi_manage_fans(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_platformi_manage_leds(void) +{ + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/psui.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/psui.c new file mode 100644 index 0000000000..269e9fe491 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/psui.c @@ -0,0 +1,181 @@ +/************************************************************ + * + * + * 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 "platform_lib.h" + +#define AIM_FREE_IF_PTR(p) \ + do \ + { \ + if (p) { \ + aim_free(p); \ + p = NULL; \ + } \ + } while (0) + +int +onlp_psui_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_psui_sw_denit(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", ONLP_OID_CHASSIS, { 0 }, 0 }, + { 0 }, { 0 }, 0, 0, 0, 0, 0, 0, 0, 0, + }, + { + { ONLP_PSU_ID_CREATE(PSU2_ID), "PSU-2", ONLP_OID_CHASSIS, { 0 }, 0 }, + { 0 }, { 0 }, 0, 0, 0, 0, 0, 0, 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); + + *info = pinfo[pid]; /* Set the onlp_oid_hdr_t */ + + /* Get the present state */ + ONLP_TRY(onlp_file_read_int(&val, "%s""psu%d_present", PSU_SYSFS_PATH, pid)); + if (val != PSU_STATUS_PRESENT) { + ONLP_OID_STATUS_FLAG_CLR(info, PRESENT); + return ONLP_STATUS_OK; + } + + ONLP_OID_STATUS_FLAG_SET(info, PRESENT); + info->type = ONLP_PSU_TYPE_AC; + + /* Get power good status */ + ONLP_TRY(onlp_file_read_int(&val, "%s""psu%d_power_good", PSU_SYSFS_PATH, pid)); + if (val != PSU_STATUS_POWER_GOOD) { + ONLP_OID_STATUS_FLAG_SET(info, FAILED); + } + + /* Read voltage, current and power */ + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_vin", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret) && val) { + info->mvin = val; + info->caps |= ONLP_PSU_CAPS_GET_VIN; + } + + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_vout", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret) && val) { + info->mvout = val; + info->caps |= ONLP_PSU_CAPS_GET_VOUT; + } + + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_iin", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret) && val) { + info->miin = val; + info->caps |= ONLP_PSU_CAPS_GET_IIN; + } + + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_iout", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret) && val) { + info->miout = val; + info->caps |= ONLP_PSU_CAPS_GET_IOUT; + } + + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_pin", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret) && val) { + info->mpin = val; + info->caps |= ONLP_PSU_CAPS_GET_PIN; + } + + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_pout", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret) && val) { + info->mpout = val; + info->caps |= ONLP_PSU_CAPS_GET_POUT; + } + + /* Set the associated oid_table */ + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_fan1_input", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret)) { + info->hdr.coids[0] = ONLP_FAN_ID_CREATE(pid + CHASSIS_FAN_COUNT); + } + + val = 0; + ret = onlp_file_read_int(&val, "%s""psu%d_temp1_input", PSU_SYSFS_PATH, pid); + if (ONLP_SUCCESS(ret)) { + info->hdr.coids[1] = ONLP_THERMAL_ID_CREATE(pid + CHASSIS_THERMAL_COUNT); + } + + /* Read model */ + char *string = NULL; + int len = onlp_file_read_str(&string, "%s""psu%d_model", PSU_SYSFS_PATH, pid); + if (string && len) { + memcpy(info->model, string, len); + info->model[len] = '\0'; + } + AIM_FREE_IF_PTR(string); + + /* Read serial */ + len = onlp_file_read_str(&string, "%s""psu%d_serial", PSU_SYSFS_PATH, pid); + if (string && len) { + memcpy(info->serial, string, len); + info->serial[len] = '\0'; + } + AIM_FREE_IF_PTR(string); + + return ONLP_STATUS_OK; +} + +int +onlp_psui_hdr_get(onlp_oid_t id, onlp_oid_hdr_t* hdr) +{ + onlp_psu_info_t info; + + ONLP_TRY(onlp_psui_info_get(id, &info)); + *hdr = info.hdr; + return 0; +} + +int +onlp_psui_id_validate(onlp_oid_id_t id) +{ + return ONLP_OID_ID_VALIDATE_RANGE(id, PSU1_ID, PSU2_ID); +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c new file mode 100644 index 0000000000..1cb83d6fb2 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c @@ -0,0 +1,380 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2017 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_as7926_40xfb_log.h" + +#define EEPROM_I2C_ADDR 0x50 +#define EEPROM_START_OFFSET 0x0 +#define NUM_OF_SFP_PORT 55 + +static const int port_bus_index[NUM_OF_SFP_PORT] = { + 33, 34, 37, 38, 41, 42, 45, 46, 49, 50, + 53, 54, 57, 58, 61, 62, 65, 66, 69, 70, + 35, 36, 39, 40, 43, 44, 47, 48, 51, 52, + 55, 56, 59, 60, 63, 64, 67, 68, 71, 72, + 85, 76, 75, 74, 73, 78, 77, 80, 79, 82, + 81, 84, 83, 30, 31 +}; + +#define PORT_BUS_INDEX(port) (port_bus_index[port]) +#define PORT_FORMAT "/sys/bus/i2c/devices/%d-0050/%s" +#define MODULE_PRESENT_CPLD2_FORMAT "/sys/bus/i2c/devices/12-0062/module_present_%d" +#define MODULE_PRESENT_CPLD3_FORMAT "/sys/bus/i2c/devices/13-0063/module_present_%d" +#define MODULE_PRESENT_CPLD4_FORMAT "/sys/bus/i2c/devices/20-0064/module_present_%d" +#define MODULE_RESET_CPLD2_FORMAT "/sys/bus/i2c/devices/12-0062/module_reset_%d" +#define MODULE_RESET_CPLD3_FORMAT "/sys/bus/i2c/devices/13-0063/module_reset_%d" +#define MODULE_RESET_CPLD4_FORMAT "/sys/bus/i2c/devices/20-0064/module_reset_%d" +#define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_rx_los_%d" +#define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_disable_%d" + +/************************************************************ + * + * SFPI Entry Points + * + ***********************************************************/ +int +onlp_sfpi_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_sw_denit(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_bitmap_get(onlp_sfp_bitmap_t* bmap) +{ + /* + * Ports {0, 55} + */ + 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_is_present(onlp_oid_id_t port) +{ + /* + * Return 1 if present. + * Return 0 if not present. + * Return < 0 if error. + */ + int present; + char *path = NULL; + + switch (port) { + case 0 ... 9: + case 20 ... 29: + case 53 ... 54: + path = MODULE_PRESENT_CPLD2_FORMAT; + break; + case 10 ... 19: + case 30 ... 39: + path = MODULE_PRESENT_CPLD3_FORMAT; + break; + case 40 ... 52: + path = MODULE_PRESENT_CPLD4_FORMAT; + break; + default: + return ONLP_STATUS_E_INVALID; + } + + ONLP_TRY(onlp_file_read_int(&present, path, (port+1))); + + return present; +} + +int +onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) +{ + int i=0, val=0; + /* Populate bitmap */ + for (i = 0; i < 55; i++) { + val = 0; + + if ((i >= 53) && (i <= 54)) { + ONLP_TRY(onlp_file_read_int(&val, MODULE_RXLOS_FORMAT, 12, 62, i+1)); + + if (val) + AIM_BITMAP_MOD(dst, i, 1); + else + AIM_BITMAP_MOD(dst, i, 0); + } + else { + AIM_BITMAP_MOD(dst, i, 0); + } + } + + return ONLP_STATUS_OK; +} + +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; + if (port < 0 || port >= NUM_OF_SFP_PORT) { + AIM_LOG_ERROR("Unable to read eeprom from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + ONLP_TRY(onlp_file_read(data, 256, &size, PORT_FORMAT, PORT_BUS_INDEX(port), "eeprom")); + if (size != 256) { + AIM_LOG_ERROR("Invalid file size(%d)\r\n", size); + 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, PORT_FORMAT, PORT_BUS_INDEX(port), "eeprom"); + 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(onlp_oid_id_t port, int devaddr, int addr) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_readb(bus, devaddr, addr, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_writeb(onlp_oid_id_t port, int devaddr, int 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(onlp_oid_id_t port, int devaddr, int addr) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_readw(bus, devaddr, addr, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_writew(onlp_oid_id_t port, int devaddr, int 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_dev_read(onlp_oid_id_t port, int devaddr, int addr, + uint8_t* dst, int size) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_block_read(bus, devaddr, addr, size, dst, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_control_set(onlp_oid_id_t port, onlp_sfp_control_t control, int value) +{ + int rv = ONLP_STATUS_OK; + int addr = 62; + int bus = 12; + + switch(control) { + case ONLP_SFP_CONTROL_TX_DISABLE: + { + if (port >= 53 && port <= 54) { + ONLP_TRY(onlp_file_write_int(0, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1))); + } + else { + rv = ONLP_STATUS_E_UNSUPPORTED; + } + break; + } + case ONLP_SFP_CONTROL_RESET: + { + char *path = NULL; + + switch (port) { + case 0 ... 9: + case 20 ... 29: + path = MODULE_RESET_CPLD2_FORMAT; + break; + case 10 ... 19: + case 30 ... 39: + path = MODULE_RESET_CPLD3_FORMAT; + break; + case 40 ... 52: + path = MODULE_RESET_CPLD4_FORMAT; + break; + default: + return ONLP_STATUS_E_UNSUPPORTED; + } + + ONLP_TRY(onlp_file_write_int(value, path, (port+1))); + break; + } + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + break; + } + + return rv; +} + +int +onlp_sfpi_control_get(onlp_oid_id_t port, onlp_sfp_control_t control, int* value) +{ + int rv = ONLP_STATUS_OK; + int addr = 62; + int bus = 12; + + switch(control) { + case ONLP_SFP_CONTROL_RX_LOS: + { + if (port >= 53 && port <= 54) { + ONLP_TRY(onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1))); + } + else { + rv = ONLP_STATUS_E_UNSUPPORTED; + } + + break; + } + case ONLP_SFP_CONTROL_TX_DISABLE: + { + if (port >= 53 && port <= 54) { + ONLP_TRY(onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1))); + } + else { + rv = ONLP_STATUS_E_UNSUPPORTED; + } + break; + } + case ONLP_SFP_CONTROL_RESET: + { + char *path = NULL; + + switch (port) { + case 0 ... 9: + case 20 ... 29: + path = MODULE_RESET_CPLD2_FORMAT; + break; + case 10 ... 19: + case 30 ... 39: + path = MODULE_RESET_CPLD3_FORMAT; + break; + case 40 ... 52: + path = MODULE_RESET_CPLD4_FORMAT; + break; + default: + return ONLP_STATUS_E_UNSUPPORTED; + } + + ONLP_TRY(onlp_file_read_int(value, path, (port+1))); + break; + } + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + break; + } + + return rv; +} + +int +onlp_sfpi_port_map(onlp_oid_id_t port, int* rport) +{ + *rport = port; + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_type_get(onlp_oid_id_t port, onlp_sfp_type_t* rtype) +{ + *rtype = (port < 53) ? ONLP_SFP_TYPE_QSFP28 : ONLP_SFP_TYPE_SFP; + return ONLP_STATUS_OK; +} + +int onlp_sfpi_control_supported(onlp_oid_id_t port, + onlp_sfp_control_t control, int* rv) +{ + int ret = ONLP_STATUS_OK; + + switch(control) { + case ONLP_SFP_CONTROL_RX_LOS: + case ONLP_SFP_CONTROL_TX_DISABLE: + { + *rv = (port >= 53 && port <= 54) ? 1 : 0; + break; + } + case ONLP_SFP_CONTROL_RESET: + { + *rv = (port >= 0 && port <= 52) ? 1 : 0; + break; + } + default: + *rv = 0; + break; + } + + return ret; +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/thermali.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/thermali.c new file mode 100644 index 0000000000..29007514eb --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/thermali.c @@ -0,0 +1,297 @@ +/************************************************************ + * + * + * 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 "platform_lib.h" + +enum onlp_thermal_id { + THERMAL_RESERVED = 0, + THERMAL_CPU_CORE, + THERMAL_1_ON_MAINBOARD, /* Main Board Bottom TMP432_1 Temp */ + THERMAL_2_ON_MAINBOARD, /* Main Board Bottom TMP432_2 Temp */ + THERMAL_3_ON_MAINBOARD, /* Main Board Bottom TMP432_3 Temp */ + THERMAL_4_ON_MAINBOARD, /* Main Board Bottom LM75_1 Temp */ + THERMAL_5_ON_MAINBOARD, /* Main Board Bottom LM75_2 Temp */ + THERMAL_6_ON_MAINBOARD, /* Main Board Bottom LM75_3 Temp */ + THERMAL_7_ON_MAINBOARD, /* Main Board Bottom LM75_4 Temp */ + THERMAL_8_ON_MAINBOARD, /* Main Board Bottom LM75_5 Temp */ + THERMAL_9_ON_MAINBOARD, /* Main Board Bottom LM75_6 Temp */ + THERMAL_10_ON_MAINBOARD, /* Main Board Bottom LM75_7 Temp */ + THERMAL_1_ON_PSU1, + THERMAL_1_ON_PSU2, + ONLP_THERMAL_MAX +}; + +static char* ipmi_devfiles__[] = { /* must map with onlp_thermal_id */ + NULL, + NULL, /* CPU_CORE files */ + "/sys/devices/platform/as7926_40xfb_thermal/temp1_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp2_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp3_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp4_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp5_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp6_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp7_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp8_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp9_input", + "/sys/devices/platform/as7926_40xfb_thermal/temp10_input", + "/sys/devices/platform/as7926_40xfb_psu/psu1_temp1_input", + "/sys/devices/platform/as7926_40xfb_psu/psu2_temp1_input", +}; + +static char* cpu_coretemp_files[] = { + "/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", + "/sys/devices/platform/coretemp.0*temp6_input", + "/sys/devices/platform/coretemp.0*temp7_input", + "/sys/devices/platform/coretemp.0*temp8_input", + "/sys/devices/platform/coretemp.0*temp9_input", + NULL, +}; + +/* Static values */ +static onlp_thermal_info_t thermal_info_table__[] = { + { }, /* Not used */ + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_CPU_CORE), + .description = "CPU Core", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 90000, 95000, 100000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_MAINBOARD), + .description = "Main Board TMP432_1", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 84000, 87000, 92000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_MAINBOARD), + .description = "Main Board TMP432_2", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 110000, 115000, 120000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_MAINBOARD), + .description = "Main Board TMP432_3", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 110000, 115000, 120000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_4_ON_MAINBOARD), + .description = "Main Board LM75_1", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 70000, 73000, 78000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_5_ON_MAINBOARD), + .description = "Main Board LM75_2", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 72000, 75000, 80000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_6_ON_MAINBOARD), + .description = "Main Board LM75_3", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 73000, 76000, 81000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_7_ON_MAINBOARD), + .description = "Main Board LM75_4", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 70000, 73000, 78000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_8_ON_MAINBOARD), + .description = "Main Board LM75_5", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 62000, 65000, 70000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_9_ON_MAINBOARD), + .description = "Main Board LM75_6", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 84000, 87000, 92000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_10_ON_MAINBOARD), + .description = "Main Board LM75_7", + .poid = ONLP_OID_CHASSIS, + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 76000, 79000, 84000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_PSU1), + .description = "PSU-1 Thermal Sensor 1", + .poid = ONLP_PSU_ID_CREATE(PSU1_ID), + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 62000, 67000, 72000 } + }, + { + .hdr = { + .id = ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_PSU2), + .description = "PSU-2 Thermal Sensor 1", + .poid = ONLP_PSU_ID_CREATE(PSU2_ID), + .status = ONLP_OID_STATUS_FLAG_PRESENT + }, + .caps = ONLP_THERMAL_CAPS_ALL, + .mcelsius = 0, + .thresholds = { 62000, 67000, 72000 } + } +}; + +/* + * This will be called to intiialize the thermali subsystem. + */ +int +onlp_thermali_sw_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_thermali_sw_denit(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 = ONLP_OID_ID_GET(id); + + /* Set the onlp_oid_hdr_t and capabilities */ + *info = thermal_info_table__[tid]; + + if (tid == THERMAL_CPU_CORE) { + return onlp_file_read_int_max(&info->mcelsius, cpu_coretemp_files); + } + else if (tid >= THERMAL_1_ON_PSU1 && tid <= THERMAL_1_ON_PSU2) { + int val = 0; + int pid = (tid - THERMAL_1_ON_PSU1 + 1); + + ONLP_TRY(onlp_file_read_int(&val, "%s""psu%d_present", PSU_SYSFS_PATH, pid)); + if (val != PSU_STATUS_PRESENT) { + ONLP_OID_STATUS_FLAG_CLR(info, PRESENT); + return ONLP_STATUS_OK; + } + } + + return onlp_file_read_int(&info->mcelsius, ipmi_devfiles__[tid]); +} + +int +onlp_thermali_hdr_get(onlp_oid_id_t id, onlp_oid_hdr_t* hdr) +{ + int tid = ONLP_OID_ID_GET(id); + *hdr = thermal_info_table__[tid].hdr; + + if (tid >= THERMAL_1_ON_PSU1 && tid <= THERMAL_1_ON_PSU2) { + int val = 0; + int pid = (tid - THERMAL_1_ON_PSU1 + 1); + + ONLP_TRY(onlp_file_read_int(&val, "%s""psu%d_present", PSU_SYSFS_PATH, pid)); + if (val != PSU_STATUS_PRESENT) { + ONLP_OID_STATUS_FLAG_CLR(hdr, PRESENT); + } + } + + return ONLP_STATUS_OK; +} + +int +onlp_thermali_id_validate(onlp_oid_id_t id) +{ + return ONLP_OID_ID_VALIDATE_RANGE(id, 1, ONLP_THERMAL_MAX-1); +} diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_config.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_config.c new file mode 100644 index 0000000000..cd3a80d6a2 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_config.c @@ -0,0 +1,81 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* */ +#define __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(_x) #_x +#define __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(_x) __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(_x) +x86_64_accton_as7926_40xfb_config_settings_t x86_64_accton_as7926_40xfb_config_settings[] = +{ +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_LOGGING(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_STDLIB(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_UCLI(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION + { __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME(X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION), __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION) }, +#else +{ X86_64_ACCTON_AS7926_40XFB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION(__x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME), "__undefined__" }, +#endif + { NULL, NULL } +}; +#undef __x86_64_accton_as7926_40xfb_config_STRINGIFY_VALUE +#undef __x86_64_accton_as7926_40xfb_config_STRINGIFY_NAME + +const char* +x86_64_accton_as7926_40xfb_config_lookup(const char* setting) +{ + int i; + for(i = 0; x86_64_accton_as7926_40xfb_config_settings[i].name; i++) { + if(!strcmp(x86_64_accton_as7926_40xfb_config_settings[i].name, setting)) { + return x86_64_accton_as7926_40xfb_config_settings[i].value; + } + } + return NULL; +} + +int +x86_64_accton_as7926_40xfb_config_show(struct aim_pvs_s* pvs) +{ + int i; + for(i = 0; x86_64_accton_as7926_40xfb_config_settings[i].name; i++) { + aim_printf(pvs, "%s = %s\n", x86_64_accton_as7926_40xfb_config_settings[i].name, x86_64_accton_as7926_40xfb_config_settings[i].value); + } + return i; +} + +/* */ + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_enums.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_enums.c new file mode 100644 index 0000000000..419396896a --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_enums.c @@ -0,0 +1,10 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.enum(ALL).source> */ +/* */ + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_int.h b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_int.h new file mode 100644 index 0000000000..6e3326c9ca --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_int.h @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * x86_64_accton_as7926_40xfb Internal Header + * + *****************************************************************************/ +#ifndef __x86_64_accton_as7926_40xfb_INT_H__ +#define __x86_64_accton_as7926_40xfb_INT_H__ + +#include + + +#endif /* __x86_64_accton_as7926_40xfb_INT_H__ */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.c new file mode 100644 index 0000000000..b726b9bd58 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.c @@ -0,0 +1,17 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_accton_as7926_40xfb_log.h" +/* + * x86_64_accton_as7926_40xfb log struct. + */ +AIM_LOG_STRUCT_DEFINE( + X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_OPTIONS_DEFAULT, + X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_BITS_DEFAULT, + NULL, /* Custom log map */ + X86_64_ACCTON_AS7926_40XFB_CONFIG_LOG_CUSTOM_BITS_DEFAULT + ); diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.h b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.h new file mode 100644 index 0000000000..4c4814c77b --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_log.h @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#ifndef __x86_64_accton_as7926_40xfb_LOG_H__ +#define __x86_64_accton_as7926_40xfb_LOG_H__ + +#define AIM_LOG_MODULE_NAME x86_64_accton_as7926_40xfb +#include + +#endif /* __x86_64_accton_as7926_40xfb_LOG_H__ */ diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_module.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_module.c new file mode 100644 index 0000000000..6c7a094f77 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_module.c @@ -0,0 +1,24 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_accton_as7926_40xfb_log.h" + +static int +datatypes_init__(void) +{ +#define x86_64_accton_as7926_40xfb_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_as7926_40xfb_module_init__(void) +{ + AIM_LOG_STRUCT_REGISTER(); + datatypes_init__(); +} + +int __onlp_platform_version__ = 1; diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_ucli.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_ucli.c new file mode 100644 index 0000000000..9d019cbcdd --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/x86_64_accton_as7926_40xfb_ucli.c @@ -0,0 +1,50 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#if x86_64_accton_as7926_40xfb_CONFIG_INCLUDE_UCLI == 1 + +#include +#include +#include + +static ucli_status_t +x86_64_accton_as7926_40xfb_ucli_ucli__config__(ucli_context_t* uc) +{ + UCLI_HANDLER_MACRO_MODULE_CONFIG(x86_64_accton_as7926_40xfb) +} + +/* */ +/* */ + +static ucli_module_t +x86_64_accton_as7926_40xfb_ucli_module__ = + { + "x86_64_accton_as7926_40xfb_ucli", + NULL, + x86_64_accton_as7926_40xfb_ucli_ucli_handlers__, + NULL, + NULL, + }; + +ucli_node_t* +x86_64_accton_as7926_40xfb_ucli_node_create(void) +{ + ucli_node_t* n; + ucli_module_init(&x86_64_accton_as7926_40xfb_ucli_module__); + n = ucli_node_create("x86_64_accton_as7926_40xfb", NULL, &x86_64_accton_as7926_40xfb_ucli_module__); + ucli_node_subnode_add(n, ucli_module_log_node_create("x86_64_accton_as7926_40xfb")); + return n; +} + +#else +void* +x86_64_accton_as7926_40xfb_ucli_node_create(void) +{ + return NULL; +} +#endif + diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/Makefile new file mode 100644 index 0000000000..003238cf6d --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/Makefile b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/Makefile new file mode 100644 index 0000000000..003238cf6d --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/PKG.yml b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/PKG.yml new file mode 100644 index 0000000000..6c1da7da2b --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-config-platform.yml ARCH=amd64 VENDOR=accton BASENAME=x86-64-accton-as7926-40xfb REVISION=r0 diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/lib/x86-64-accton-as7926-40xfb-r0.yml b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/lib/x86-64-accton-as7926-40xfb-r0.yml new file mode 100644 index 0000000000..a70b6a0d62 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/lib/x86-64-accton-as7926-40xfb-r0.yml @@ -0,0 +1,31 @@ +--- + +###################################################################### +# +# platform-config for AS7926-40XFB +# +###################################################################### + +x86-64-accton-as7926-40xfb-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-4-14 + + args: >- + console=ttyS0,115200n8 + intel_iommu=pt + + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/python/x86_64_accton_as7926_40xfb_r0/__init__.py b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/python/x86_64_accton_as7926_40xfb_r0/__init__.py new file mode 100644 index 0000000000..d1c05bac83 --- /dev/null +++ b/packages/platforms/accton/x86-64/as7926-40xfb/platform-config/r0/src/python/x86_64_accton_as7926_40xfb_r0/__init__.py @@ -0,0 +1,137 @@ +import commands +import time +from itertools import chain +from onl.platform.base import * +from onl.platform.accton import * + +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 + time.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 + time.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: + time.sleep(interval - elapsed_dev) + continue + + (status, elapsed_oem) = init_ipmi_oem_cmd() + if status is not True: + time.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_as7926_40xfb_r0(OnlPlatformAccton, + OnlPlatformPortConfig_48x1_4x10): + PLATFORM='x86-64-accton-as7926-40xfb-r0' + MODEL="AS7926-40XFB" + SYS_OBJECT_ID=".7926.40" + + def baseconfig(self): + if init_ipmi() is not True: + return False + + self.insmod('optoe') + for m in [ 'cpld', 'fan', 'psu', 'leds', 'thermal', 'sys' ]: + self.insmod("x86-64-accton-as7926-40xfb-%s.ko" % m) + + ########### initialize I2C bus 0 ########### + self.new_i2c_devices([ + # initialize multiplexer (PCA9548) + ('pca9548', 0x77, 0), # i2c 1-8 + + # initiate multiplexer (PCA9548) of bottom board + ('pca9548', 0x76, 1), # i2c 9-16 + ('pca9548', 0x70, 1), # i2c 17-24 + ('pca9548', 0x73, 9), # i2c 25-32 + + # initiate multiplexer for QSFP ports + ('pca9548', 0x74, 25), # i2c 33-40 + ('pca9548', 0x74, 26), # i2c 41-48 + ('pca9548', 0x74, 27), # i2c 49-56 + ('pca9548', 0x74, 28), # i2c 57-64 + ('pca9548', 0x74, 29), # i2c 65-72 + + # initiate multiplexer for FAB ports + ('pca9548', 0x74, 17), # i2c 73-80 + ('pca9548', 0x74, 18), # i2c 81-88 + + #initiate CPLD + ('as7926_40xfb_cpld2', 0x62, 12), + ('as7926_40xfb_cpld3', 0x63, 13), + ('as7926_40xfb_cpld4', 0x64, 20), + ('as7926_40xfb_7sgmt', 0x20, 32) + ]) + + for port in chain(range(1, 11), range(21, 31)): + subprocess.call('echo 0 > /sys/bus/i2c/devices/12-0062/module_reset_%d' % port, shell=True) + + for port in chain(range(11, 21), range(31, 41)): + subprocess.call('echo 0 > /sys/bus/i2c/devices/13-0063/module_reset_%d' % port, shell=True) + + for port in range(41, 54): + subprocess.call('echo 0 > /sys/bus/i2c/devices/20-0064/module_reset_%d' % port, shell=True) + + # initialize QSFP port(0-39), FAB port(40-52) + port_i2c_bus = [33, 34, 37, 38, 41, 42, 45, 46, 49, 50, + 53, 54, 57, 58, 61, 62, 65, 66, 69, 70, + 35, 36, 39, 40, 43, 44, 47, 48, 51, 52, + 55, 56, 59, 60, 63, 64, 67, 68, 71, 72, + 85, 76, 75, 74, 73, 78, 77, 80, 79, 82, + 81, 84, 83] + + for port in range(0, 53): + self.new_i2c_device('optoe1', 0x50, port_i2c_bus[port]) + subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port+1, port_i2c_bus[port]), shell=True) + + # initialize SFP port 54-55 + self.new_i2c_device('optoe2', 0x50, 30) + subprocess.call('echo port54 > /sys/bus/i2c/devices/30-0050/port_name', shell=True) + self.new_i2c_device('optoe2', 0x50, 31) + subprocess.call('echo port55 > /sys/bus/i2c/devices/31-0050/port_name', shell=True) + + return True diff --git a/setup.env b/setup.env index e02f871ff6..1535e79166 100755 --- a/setup.env +++ b/setup.env @@ -56,6 +56,7 @@ export ONLPM_OPTION_PLATFORM_WHITELIST="\ x86-64-accton-as7712-32x-r0 x86-64-accton-as5812-54x-r0 x86-64-accton-as9716-32d-r0 +x86-64-accton-as7926-40xfb-r0 x86-64-inventec-d5254-r0 x86-64-inventec-d10064-r0 x86-64-inventec-d10056-r0