From 6e2262b7c431b83d0ef19bc8baa29d6329775962 Mon Sep 17 00:00:00 2001 From: Willy Liu Date: Mon, 19 May 2025 10:29:14 +0000 Subject: [PATCH 1/5] [ACCTON][AS9947-72XKB] Add new platform CPU : Ice Lake-D (D-1734NT 8C) MAC: Broadcom J2C+ (BCM88851), 2 pcs , 7.2 Tb/s integrated packet processor Ethernet Ports: 24 x QSFP-DD ports & 48 x QSFP28 ports shared with 4 x 10G SFP+ Power Supply: 12V/3200W PSU back to front airflow (DC to AC), 1+1 redundant load-sharing, hot-swappable Cooling: 4+1 FAN-tray modules with 5 pcs of 80mm x 80mm x 130mm 12V hot-swappable fans, 15400 RPM. 2+1 FAN-tray modules with 3 pcs of 40mm x 40mm x 93mm 12V hot-swappable fans, 31000 RPM. BMC Module: AST2600 Signed-off-by: Willy Liu --- .../accton/x86-64/as9947-72xkb/.gitignore | 2 + .../accton/x86-64/as9947-72xkb/Makefile | 1 + .../x86-64/as9947-72xkb/modules/Makefile | 1 + .../x86-64/as9947-72xkb/modules/PKG.yml | 1 + .../as9947-72xkb/modules/builds/.gitignore | 1 + .../as9947-72xkb/modules/builds/Makefile | 7 + .../as9947-72xkb/modules/builds/src/Makefile | 8 + .../src/x86-64-accton-as9947-72xkb-fan.c | 827 +++++++++++ .../src/x86-64-accton-as9947-72xkb-fpga.c | 1229 +++++++++++++++++ .../x86-64-accton-as9947-72xkb-i2c-ocores.c | 1026 ++++++++++++++ .../src/x86-64-accton-as9947-72xkb-leds.c | 550 ++++++++ .../src/x86-64-accton-as9947-72xkb-psu.c | 1072 ++++++++++++++ .../src/x86-64-accton-as9947-72xkb-sys.c | 519 +++++++ .../src/x86-64-accton-as9947-72xkb-thermal.c | 427 ++++++ .../accton/x86-64/as9947-72xkb/onlp/Makefile | 1 + .../accton/x86-64/as9947-72xkb/onlp/PKG.yml | 1 + .../x86-64/as9947-72xkb/onlp/builds/Makefile | 2 + .../as9947-72xkb/onlp/builds/lib/Makefile | 2 + .../onlp/builds/onlpdump/Makefile | 2 + .../x86_64_accton_as9947_72xkb/.gitignore | 0 .../builds/x86_64_accton_as9947_72xkb/.module | 1 + .../x86_64_accton_as9947_72xkb/Makefile | 9 + .../builds/x86_64_accton_as9947_72xkb/README | 6 + .../module/auto/make.mk | 9 + .../auto/x86_64_accton_as9947_72xkb.yml | 50 + .../x86_64_accton_as9947_72xkb.x | 14 + .../x86_64_accton_as9947_72xkb_config.h | 137 ++ .../x86_64_accton_as9947_72xkb_dox.h | 26 + .../x86_64_accton_as9947_72xkb_porting.h | 107 ++ .../x86_64_accton_as9947_72xkb/module/make.mk | 10 + .../module/src/Makefile | 9 + .../module/src/debug.c | 45 + .../module/src/fani.c | 368 +++++ .../module/src/ledi.c | 235 ++++ .../module/src/make.mk | 9 + .../module/src/platform_lib.c | 150 ++ .../module/src/platform_lib.h | 108 ++ .../module/src/psui.c | 174 +++ .../module/src/sfpi.c | 330 +++++ .../module/src/sysi.c | 194 +++ .../module/src/thermali.c | 210 +++ .../src/x86_64_accton_as9947_72xkb_config.c | 81 ++ .../src/x86_64_accton_as9947_72xkb_enums.c | 10 + .../src/x86_64_accton_as9947_72xkb_int.h | 12 + .../src/x86_64_accton_as9947_72xkb_log.c | 17 + .../src/x86_64_accton_as9947_72xkb_log.h | 12 + .../src/x86_64_accton_as9947_72xkb_module.c | 24 + .../src/x86_64_accton_as9947_72xkb_ucli.c | 50 + .../as9947-72xkb/platform-config/Makefile | 1 + .../as9947-72xkb/platform-config/r0/Makefile | 1 + .../as9947-72xkb/platform-config/r0/PKG.yml | 1 + .../src/lib/x86-64-accton-as9947-72xkb-r0.yml | 34 + .../x86_64_accton_as9947_72xkb_r0/__init__.py | 102 ++ 53 files changed, 8225 insertions(+) create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-i2c-ocores.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/lib/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/onlpdump/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.gitignore create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.module create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/README create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/make.mk create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/x86_64_accton_as9947_72xkb.yml create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb.x create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_config.h create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_dox.h create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_porting.h create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/make.mk create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/debug.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/ledi.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/make.mk create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sysi.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_config.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_enums.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_int.h create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.h create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_module.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_ucli.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/platform-config/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/Makefile create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/PKG.yml create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/lib/x86-64-accton-as9947-72xkb-r0.yml create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/.gitignore b/packages/platforms/accton/x86-64/as9947-72xkb/.gitignore new file mode 100644 index 0000000000..a957d55a6f --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/.gitignore @@ -0,0 +1,2 @@ +*x86*64*accton*as9947*72xkb*.mk +onlpdump.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/modules/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/PKG.yml b/packages/platforms/accton/x86-64/as9947-72xkb/modules/PKG.yml new file mode 100644 index 0000000000..023ef7c382 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-modules.yml VENDOR=accton BASENAME=x86-64-accton-as9947-72xkb ARCH=amd64 KERNELS="onl-kernel-5.4-lts-x86-64-all:amd64" diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/.gitignore b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/.gitignore new file mode 100644 index 0000000000..a65b41774a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/Makefile new file mode 100644 index 0000000000..c8bcde5677 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/Makefile @@ -0,0 +1,7 @@ +KERNELS := onl-kernel-5.4-lts-x86-64-all:amd64 +KMODULES := src +VENDOR := accton +BASENAME := x86-64-accton-as9947-72xkb +ARCH := x86_64 +include $(ONL)/make/kmodule.mk + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile new file mode 100644 index 0000000000..da498dc772 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile @@ -0,0 +1,8 @@ +obj-m += x86-64-accton-as9947-72xkb-i2c-ocores.o +obj-m += x86-64-accton-as9947-72xkb-fpga.o +obj-m += x86-64-accton-as9947-72xkb-fan.o +obj-m += x86-64-accton-as9947-72xkb-thermal.o +obj-m += x86-64-accton-as9947-72xkb-psu.o +obj-m += x86-64-accton-as9947-72xkb-sys.o +obj-m += x86-64-accton-as9947-72xkb-leds.o + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c new file mode 100644 index 0000000000..d6e3929396 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c @@ -0,0 +1,827 @@ +/* + * Copyright (C) Willy Liu + * + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9947_72xkb_fan" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_FAN_READ_CMD 0x14 +#define IPMI_FAN_WRITE_CMD 0x15 +#define IPMI_FAN_READ_MODEL_CMD 0x10 +#define IPMI_FAN_READ_SERIAL_CMD 0x11 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define IPMI_FAN_REG_READ_CMD 0x20 +#define MAX_FAN_SPEED_RPM 33000 +#define IPMI_FAN_MODEL_SIZE 15 +#define IPMI_FAN_SERIAL_SIZE 13 + +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_string(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 int as9947_72xkb_fan_probe(struct platform_device *pdev); +static int as9947_72xkb_fan_remove(struct platform_device *pdev); + +enum fan_id { + FAN_1, + FAN_2, + FAN_3, + FAN_4, + FAN_5, + FAN_6, + FAN_7, + FAN_8, + FAN_9, + FAN_10, + FAN_11, + FAN_12, + FAN_13, + FAN_14, + FAN_15, + FAN_16, + NUM_OF_FAN, + NUM_OF_FAN_MODULE = NUM_OF_FAN +}; + +enum fan_data_index { + FAN_PRESENT, + FAN_PWM, + FAN_SPEED0, + FAN_SPEED1, + FAN_DATA_COUNT +}; + + +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 as9947_72xkb_fan_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + /* 4 bytes for each fan, the last 2 bytes is fan dir */ + unsigned char ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT + 2]; + unsigned char ipmi_resp_cpld[2]; + unsigned char ipmi_resp_string[16]; + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[3]; /* 0: FAN id, 1: 0x02, 2: PWM */ +}; + +struct as9947_72xkb_fan_data *data = NULL; + +static struct platform_driver as9947_72xkb_fan_driver = { + .probe = as9947_72xkb_fan_probe, + .remove = as9947_72xkb_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define FAN_PRESENT_ATTR_ID(index) FAN##index##_PRESENT +#define FAN_PWM_ATTR_ID(index) FAN##index##_PWM +#define FAN_RPM_ATTR_ID(index) FAN##index##_INPUT +#define FAN_DIR_ATTR_ID(index) FAN##index##_DIR +#define FAN_MODEL_ATTR_ID(index) FAN##index##_MODEL +#define FAN_SERIAL_ATTR_ID(index) FAN##index##_SERIAL + +#define FAN_ATTR(fan_id) \ + FAN_PRESENT_ATTR_ID(fan_id), \ + FAN_PWM_ATTR_ID(fan_id), \ + FAN_RPM_ATTR_ID(fan_id), \ + FAN_DIR_ATTR_ID(fan_id), \ + FAN_MODEL_ATTR_ID(fan_id), \ + FAN_SERIAL_ATTR_ID(fan_id) + +enum as9947_72xkb_fan_sysfs_attrs { + FAN_ATTR(1), + FAN_ATTR(2), + FAN_ATTR(3), + FAN_ATTR(4), + FAN_ATTR(5), + FAN_ATTR(6), + FAN_ATTR(7), + FAN_ATTR(8), + FAN_ATTR(9), + FAN_ATTR(10), + FAN_ATTR(11), + FAN_ATTR(12), + FAN_ATTR(13), + FAN_ATTR(14), + FAN_ATTR(15), + FAN_ATTR(16), + NUM_OF_FAN_ATTR, + FAN_VERSION, + FAN_MAX_RPM, + NUM_OF_PER_FAN_ATTR = (NUM_OF_FAN_ATTR/NUM_OF_FAN) +}; + +/* fan attributes */ +#define DECLARE_FAN_VER_SENSOR_DEVICE_ATTR() \ + static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, FAN_VERSION) +#define DECLARE_FAN_VER_ATTR() \ + &sensor_dev_attr_version.dev_attr.attr + +#define DECLARE_FAN_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, show_fan, NULL, \ + FAN##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(fan##index##_pwm, S_IWUSR | S_IRUGO, show_fan, \ + set_fan, FAN##index##_PWM); \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, show_fan, NULL, \ + FAN##index##_INPUT); \ + static SENSOR_DEVICE_ATTR(fan##index##_dir, S_IRUGO, show_dir, NULL, \ + FAN##index##_DIR); \ + static SENSOR_DEVICE_ATTR(fan##index##_model, S_IRUGO, show_string,\ + NULL, FAN##index##_MODEL); \ + static SENSOR_DEVICE_ATTR(fan##index##_serial, S_IRUGO, show_string,\ + NULL, FAN##index##_SERIAL) + +static SENSOR_DEVICE_ATTR(fan_max_speed_rpm, S_IRUGO, show_fan, NULL, \ + FAN_MAX_RPM); +#define DECLARE_FAN_MAX_RPM_ATTR(index) \ + &sensor_dev_attr_fan_max_speed_rpm.dev_attr.attr + +#define DECLARE_FAN_ATTR(index) \ + &sensor_dev_attr_fan##index##_present.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_pwm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_dir.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_model.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_serial.dev_attr.attr + +DECLARE_FAN_SENSOR_DEVICE_ATTR(1); +DECLARE_FAN_SENSOR_DEVICE_ATTR(2); +DECLARE_FAN_SENSOR_DEVICE_ATTR(3); +DECLARE_FAN_SENSOR_DEVICE_ATTR(4); +DECLARE_FAN_SENSOR_DEVICE_ATTR(5); +DECLARE_FAN_SENSOR_DEVICE_ATTR(6); +DECLARE_FAN_SENSOR_DEVICE_ATTR(7); +DECLARE_FAN_SENSOR_DEVICE_ATTR(8); +DECLARE_FAN_SENSOR_DEVICE_ATTR(9); +DECLARE_FAN_SENSOR_DEVICE_ATTR(10); +DECLARE_FAN_SENSOR_DEVICE_ATTR(11); +DECLARE_FAN_SENSOR_DEVICE_ATTR(12); +DECLARE_FAN_SENSOR_DEVICE_ATTR(13); +DECLARE_FAN_SENSOR_DEVICE_ATTR(14); +DECLARE_FAN_SENSOR_DEVICE_ATTR(15); +DECLARE_FAN_SENSOR_DEVICE_ATTR(16); +DECLARE_FAN_VER_SENSOR_DEVICE_ATTR(); + +static struct attribute *as9947_72xkb_fan_attrs[] = { + /* fan attributes */ + DECLARE_FAN_ATTR(1), + DECLARE_FAN_ATTR(2), + DECLARE_FAN_ATTR(3), + DECLARE_FAN_ATTR(4), + DECLARE_FAN_ATTR(5), + DECLARE_FAN_ATTR(6), + DECLARE_FAN_ATTR(7), + DECLARE_FAN_ATTR(8), + DECLARE_FAN_ATTR(9), + DECLARE_FAN_ATTR(10), + DECLARE_FAN_ATTR(11), + DECLARE_FAN_ATTR(12), + DECLARE_FAN_ATTR(13), + DECLARE_FAN_ATTR(14), + DECLARE_FAN_ATTR(15), + DECLARE_FAN_ATTR(16), + DECLARE_FAN_VER_ATTR(), + DECLARE_FAN_MAX_RPM_ATTR(), + NULL +}; +ATTRIBUTE_GROUPS(as9947_72xkb_fan); + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + int i = 0; + char raw_cmd[20] = ""; + + sprintf(raw_cmd, "0x%02x", cmd); + + if(tx_len) { + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi,cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + 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 as9947_72xkb_fan_data *as9947_72xkb_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->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + if (attr->index == FAN_MAX_RPM) + return sprintf(buf, "%d\n", MAX_FAN_SPEED_RPM); + + mutex_lock(&data->update_lock); + data = as9947_72xkb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + switch (attr->index) { + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + case FAN6_PRESENT: + case FAN7_PRESENT: + case FAN8_PRESENT: + case FAN9_PRESENT: + case FAN10_PRESENT: + case FAN11_PRESENT: + case FAN12_PRESENT: + case FAN13_PRESENT: + case FAN14_PRESENT: + case FAN15_PRESENT: + case FAN16_PRESENT: + value = present; + break; + case FAN1_PWM: + case FAN2_PWM: + case FAN3_PWM: + case FAN4_PWM: + case FAN5_PWM: + case FAN6_PWM: + case FAN7_PWM: + case FAN8_PWM: + case FAN9_PWM: + case FAN10_PWM: + case FAN11_PWM: + case FAN12_PWM: + case FAN13_PWM: + case FAN14_PWM: + case FAN15_PWM: + case FAN16_PWM: + index = (fid % NUM_OF_FAN_MODULE) * FAN_DATA_COUNT; + value = data->ipmi_resp[index + FAN_PWM]; + break; + case FAN1_INPUT: + case FAN2_INPUT: + case FAN3_INPUT: + case FAN4_INPUT: + case FAN5_INPUT: + case FAN6_INPUT: + case FAN7_INPUT: + case FAN8_INPUT: + case FAN9_INPUT: + case FAN10_INPUT: + case FAN11_INPUT: + case FAN12_INPUT: + case FAN13_INPUT: + case FAN14_INPUT: + case FAN15_INPUT: + case FAN16_INPUT: + value = (int)data->ipmi_resp[index + FAN_SPEED0] | + (int)data->ipmi_resp[index + FAN_SPEED1] << 8; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_fan(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long pwm; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = attr->index / NUM_OF_PER_FAN_ATTR; + + status = kstrtol(buf, 10, &pwm); + if (status) + return status; + + mutex_lock(&data->update_lock); + data->ipmi_tx_data[0] = (fid % (NUM_OF_FAN_MODULE / 2)) + 1; + data->ipmi_tx_data[1] = 0x02; + data->ipmi_tx_data[2] = pwm; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_WRITE_CMD, + data->ipmi_tx_data, sizeof(data->ipmi_tx_data), + NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + /* force update */ + data->valid = 0; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static struct as9947_72xkb_fan_data *as9947_72xkb_fan_update_cpld_ver(void) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = 0x33; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_REG_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_cpld, + sizeof(data->ipmi_resp_cpld)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static struct as9947_72xkb_fan_data *as9947_72xkb_fan_update_model_serial(int fan_id, int index) +{ + int status = 0; + int string_size = 0 ; + + data->valid = 0; + + switch (index) { + case FAN1_MODEL: + case FAN2_MODEL: + case FAN3_MODEL: + case FAN4_MODEL: + case FAN5_MODEL: + case FAN6_MODEL: + case FAN7_MODEL: + case FAN8_MODEL: + case FAN9_MODEL: + case FAN10_MODEL: + data->ipmi_tx_data[0] = IPMI_FAN_READ_MODEL_CMD; + string_size = IPMI_FAN_MODEL_SIZE; + data->ipmi_resp_string[IPMI_FAN_MODEL_SIZE] = '\0'; + break; + case FAN1_SERIAL: + case FAN2_SERIAL: + case FAN3_SERIAL: + case FAN4_SERIAL: + case FAN5_SERIAL: + case FAN6_SERIAL: + case FAN7_SERIAL: + case FAN8_SERIAL: + case FAN9_SERIAL: + case FAN10_SERIAL: + data->ipmi_tx_data[0] = IPMI_FAN_READ_SERIAL_CMD; + string_size = IPMI_FAN_SERIAL_SIZE; + data->ipmi_resp_string[IPMI_FAN_SERIAL_SIZE] = '\0'; + break; + default: + goto exit; + } + + if (fan_id > 4) + data->ipmi_tx_data[1] = fan_id - 5; + else + data->ipmi_tx_data[1] = fan_id; + status = ipmi_send_message(&data->ipmi, IPMI_FAN_READ_CMD, + data->ipmi_tx_data, 2, + data->ipmi_resp_string, + string_size); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + data->valid = 1; +exit: + return data; +} + +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 fid = attr->index / NUM_OF_PER_FAN_ATTR; + int present = 0; + int error = 0; + int index = 0; + char *str = NULL; + + mutex_lock(&data->update_lock); + /* check fan present */ + data = as9947_72xkb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + mutex_unlock(&data->update_lock); + if (!present) + return sprintf(buf, "\n"); + + mutex_lock(&data->update_lock); + data = as9947_72xkb_fan_update_model_serial(fid, attr->index); + if (!data->valid) { + error = -EIO; + goto exit; + } + mutex_unlock(&data->update_lock); + + str = data->ipmi_resp_string; + return sprintf(buf, "%s\n", str); + exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + unsigned char major; + unsigned char minor; + int error = 0; + + mutex_lock(&data->update_lock); + data = as9947_72xkb_fan_update_cpld_ver(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + major = data->ipmi_resp_cpld[0]; + minor = data->ipmi_resp_cpld[1]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d.%d\n", major, minor); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_dir(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char fid = (attr->index / NUM_OF_PER_FAN_ATTR); + int value = 0; + int index = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + data = as9947_72xkb_fan_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + index = fid * FAN_DATA_COUNT; /* base index */ + present = !!data->ipmi_resp[index + FAN_PRESENT]; + + value = data->ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT] | + (data->ipmi_resp[NUM_OF_FAN * FAN_DATA_COUNT + 1] << 8); + mutex_unlock(&data->update_lock); + + if (!present) + return sprintf(buf, "0\n"); + else + return sprintf(buf, "%s\n", + (value & BIT(fid % NUM_OF_FAN_MODULE)) ? "B2F" : "F2B"); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as9947_72xkb_fan_probe(struct platform_device *pdev) +{ + int status = 0; + struct device *hwmon_dev; + + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9947_72xkb_fan_groups); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + return status; + } + + mutex_lock(&data->update_lock); + data->hwmon_dev = hwmon_dev; + mutex_unlock(&data->update_lock); + + dev_info(&pdev->dev, "Device Created\n"); + + return status; +} + +static int as9947_72xkb_fan_remove(struct platform_device *pdev) +{ + mutex_lock(&data->update_lock); + if (data->hwmon_dev) { + hwmon_device_unregister(data->hwmon_dev); + data->hwmon_dev = NULL; + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int __init as9947_72xkb_fan_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9947_72xkb_fan_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9947_72xkb_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(&as9947_72xkb_fan_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9947_72xkb_fan_exit(void) +{ + if (data) { + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + kfree(data); + } + platform_driver_unregister(&as9947_72xkb_fan_driver); +} + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("as9947_72xkb_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(as9947_72xkb_fan_init); +module_exit(as9947_72xkb_fan_exit); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c new file mode 100644 index 0000000000..c4efb3c341 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c @@ -0,0 +1,1229 @@ +/* + * Copyright (C) Willy Liu + * + * This module supports the accton fpga via pcie that read/write reg + * mechanism to get OSFP/SFP status ...etc. + * This includes the: + * Accton as9947_72xkb FPGA + * + * Copyright (C) 2017 Finisar Corp. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include + +/*********************************************** + * variable define + * *********************************************/ +#define DRVNAME "as9947_72xkb_fpga" +#define OCORES_I2C_DRVNAME "ocores-as9947" + +#define PORT_NUM 76 /* 48 OSFPs + 24 QSFPDDs + 4 SFPs*/ +/* + * PCIE BAR address + */ +#define BAR0_NUM 0 +#define BAR4_NUM 4 +#define BAR5_NUM 5 +/* need checking*/ +#define REGION_LEN 0xFF +#define FPGA_PCI_VENDOR_ID 0x1172 +#define FPGA_PCI_DEVICE_ID 0xe001 +#define FPGA_PCIE_START_OFFSET 0x0000 +#define FPGA_MAJOR_VER_REG 0x01 +#define FPGA_MINOR_VER_REG 0x02 +#define SPI_BUSY_MASK_CPLD1 0x01 +#define SPI_BUSY_MASK_CPLD2 0x02 +#define FPGA_BOARD_INFO_REG (FPGA_PCIE_START_OFFSET + 0x00) +/* CPLD */ +#define CPLD_PCIE_START_OFFSET 0x2000 +/* MB CPLD0, ASYNC_ Region 4, 0: pcie to MB_CPLD0 */ +#define QSFP_DD_P7_P0_RESET_REG (CPLD_PCIE_START_OFFSET + 0x60) +#define QSFP_DD_P11_P8_RESET_REG (CPLD_PCIE_START_OFFSET + 0x61) +#define QSFP_DD_P7_P0_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x64) +#define QSFP_DD_P11_P8_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x65) +#define QSFP_DD_P7_P0_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x68) +#define QSFP_DD_P11_P8_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x69) +/* MB CPLD1, ASYNC_ Region 4, 1: pcie to MB_CPLD1 */ +#define QSFP_DD_P19_P12_RESET_REG (CPLD_PCIE_START_OFFSET + 0x60) +#define QSFP_DD_P23_P20_RESET_REG (CPLD_PCIE_START_OFFSET + 0x61) +#define QSFP_DD_P19_P12_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x64) +#define QSFP_DD_P23_P20_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x65) +#define QSFP_DD_P19_P12_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x68) +#define QSFP_DD_P23_P20_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x69) +/* MEZZ CPLD0, ASYNC_ Region 5, 2'b00: pcie to Mezz_CPLD0 */ +#define QSFP28_P7_P0_RESET_REG (CPLD_PCIE_START_OFFSET + 0x80) +#define QSFP28_P15_P8_RESET_REG (CPLD_PCIE_START_OFFSET + 0x81) +#define QSFP28_P7_P0_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x88) +#define QSFP28_P15_P8_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x89) +#define QSFP28_P7_P0_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x90) +#define QSFP28_P15_P8_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x91) +/* MEZZ CPLD1, ASYNC_ Region 5, 2'b01: pcie to Mezz_CPLD1 */ +#define QSFP28_P39_P32_RESET_REG (CPLD_PCIE_START_OFFSET + 0x80) +#define QSFP28_P47_P40_RESET_REG (CPLD_PCIE_START_OFFSET + 0x81) +#define QSFP28_P39_P32_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x88) +#define QSFP28_P47_P40_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x89) +#define QSFP28_P39_P32_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x90) +#define QSFP28_P47_P40_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x91) +#define SFP_P3_P0_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x92) +#define SFP_P3_P0_TXDIS_REG (CPLD_PCIE_START_OFFSET + 0xA8) +#define SFP_P3_P0_RXLOS_REG (CPLD_PCIE_START_OFFSET + 0xA9) +#define SFP_P3_P0_TXFAULT_REG (CPLD_PCIE_START_OFFSET + 0xB2) +/* MEZZ CPLD2, ASYNC_ Region 5, 2'b10: pcie to Mezz_CPLD2 */ +#define QSFP28_P23_P16_RESET_REG (CPLD_PCIE_START_OFFSET + 0x80) +#define QSFP28_P31_P24_RESET_REG (CPLD_PCIE_START_OFFSET + 0x81) +#define QSFP28_P23_P16_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x88) +#define QSFP28_P31_P24_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x89) +#define QSFP28_P23_P16_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x90) +#define QSFP28_P31_P24_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x91) + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_TX_DISABLE_ATTR_ID(index) MODULE_TX_DISABLE_##index +#define TRANSCEIVER_TX_FAULT_ATTR_ID(index) MODULE_TX_FAULT_##index +#define TRANSCEIVER_RX_LOS_ATTR_ID(index) MODULE_RX_LOS_##index +/*********************************************** + * macro define + * *********************************************/ +#define pcie_err(fmt, args...) \ + printk(KERN_ERR "["DRVNAME"]: " fmt " ", ##args) + +#define pcie_info(fmt, args...) \ + printk(KERN_ERR "["DRVNAME"]: " fmt " ", ##args) + + +#define LOCK(lock) \ +do { \ + spin_lock(lock); \ +} while (0) + +#define UNLOCK(lock) \ +do { \ + spin_unlock(lock); \ +} while (0) + + +/*********************************************** + * structure & variable declare + * *********************************************/ +typedef struct pci_fpga_device_s { + void __iomem *data_base_addr0; + void __iomem *data_base_addr4; + void __iomem *data_base_addr5; + resource_size_t data_region4; + resource_size_t data_region5; + struct pci_dev *pci_dev; + struct platform_device *fpga_i2c[PORT_NUM]; +} pci_fpga_device_t; + +/*fpga port status*/ +struct as9947_72xkb_fpga_data { + u8 cpld_reg[2]; + unsigned long last_updated; /* In jiffies */ + pci_fpga_device_t pci_fpga_dev; +}; + +static struct platform_device *pdev = NULL; +extern spinlock_t cpld_access_lock; +extern int wait_spi(u32 mask, unsigned long timeout); +extern void __iomem *spi_busy_reg; +extern void __iomem *async_reg; +/*********************************************** + * enum define + * *********************************************/ +enum fpga_sysfs_attributes { + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(31), + TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_PRESENT_ATTR_ID(33), + TRANSCEIVER_PRESENT_ATTR_ID(34), + TRANSCEIVER_PRESENT_ATTR_ID(35), + TRANSCEIVER_PRESENT_ATTR_ID(36), + TRANSCEIVER_PRESENT_ATTR_ID(37), + TRANSCEIVER_PRESENT_ATTR_ID(38), + 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_PRESENT_ATTR_ID(54), + TRANSCEIVER_PRESENT_ATTR_ID(55), + TRANSCEIVER_PRESENT_ATTR_ID(56), + TRANSCEIVER_PRESENT_ATTR_ID(57), + TRANSCEIVER_PRESENT_ATTR_ID(58), + TRANSCEIVER_PRESENT_ATTR_ID(59), + TRANSCEIVER_PRESENT_ATTR_ID(60), + TRANSCEIVER_PRESENT_ATTR_ID(61), + TRANSCEIVER_PRESENT_ATTR_ID(62), + TRANSCEIVER_PRESENT_ATTR_ID(63), + TRANSCEIVER_PRESENT_ATTR_ID(64), + TRANSCEIVER_PRESENT_ATTR_ID(65), + TRANSCEIVER_PRESENT_ATTR_ID(66), + TRANSCEIVER_PRESENT_ATTR_ID(67), + TRANSCEIVER_PRESENT_ATTR_ID(68), + TRANSCEIVER_PRESENT_ATTR_ID(69), + TRANSCEIVER_PRESENT_ATTR_ID(70), + TRANSCEIVER_PRESENT_ATTR_ID(71), + TRANSCEIVER_PRESENT_ATTR_ID(72), + TRANSCEIVER_PRESENT_ATTR_ID(73), + TRANSCEIVER_PRESENT_ATTR_ID(74), + TRANSCEIVER_PRESENT_ATTR_ID(75), + TRANSCEIVER_PRESENT_ATTR_ID(76), + /*Reset*/ + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_RESET_ATTR_ID(33), + TRANSCEIVER_RESET_ATTR_ID(34), + TRANSCEIVER_RESET_ATTR_ID(35), + TRANSCEIVER_RESET_ATTR_ID(36), + TRANSCEIVER_RESET_ATTR_ID(37), + TRANSCEIVER_RESET_ATTR_ID(38), + 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_RESET_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(55), + TRANSCEIVER_RESET_ATTR_ID(56), + TRANSCEIVER_RESET_ATTR_ID(57), + TRANSCEIVER_RESET_ATTR_ID(58), + TRANSCEIVER_RESET_ATTR_ID(59), + TRANSCEIVER_RESET_ATTR_ID(60), + TRANSCEIVER_RESET_ATTR_ID(61), + TRANSCEIVER_RESET_ATTR_ID(62), + TRANSCEIVER_RESET_ATTR_ID(63), + TRANSCEIVER_RESET_ATTR_ID(64), + TRANSCEIVER_RESET_ATTR_ID(65), + TRANSCEIVER_RESET_ATTR_ID(66), + TRANSCEIVER_RESET_ATTR_ID(67), + TRANSCEIVER_RESET_ATTR_ID(68), + TRANSCEIVER_RESET_ATTR_ID(69), + TRANSCEIVER_RESET_ATTR_ID(70), + TRANSCEIVER_RESET_ATTR_ID(71), + TRANSCEIVER_RESET_ATTR_ID(72), + TRANSCEIVER_LPMODE_ATTR_ID(1), + TRANSCEIVER_LPMODE_ATTR_ID(2), + TRANSCEIVER_LPMODE_ATTR_ID(3), + TRANSCEIVER_LPMODE_ATTR_ID(4), + TRANSCEIVER_LPMODE_ATTR_ID(5), + TRANSCEIVER_LPMODE_ATTR_ID(6), + TRANSCEIVER_LPMODE_ATTR_ID(7), + TRANSCEIVER_LPMODE_ATTR_ID(8), + TRANSCEIVER_LPMODE_ATTR_ID(9), + TRANSCEIVER_LPMODE_ATTR_ID(10), + TRANSCEIVER_LPMODE_ATTR_ID(11), + TRANSCEIVER_LPMODE_ATTR_ID(12), + TRANSCEIVER_LPMODE_ATTR_ID(13), + TRANSCEIVER_LPMODE_ATTR_ID(14), + TRANSCEIVER_LPMODE_ATTR_ID(15), + TRANSCEIVER_LPMODE_ATTR_ID(16), + TRANSCEIVER_LPMODE_ATTR_ID(17), + TRANSCEIVER_LPMODE_ATTR_ID(18), + TRANSCEIVER_LPMODE_ATTR_ID(19), + TRANSCEIVER_LPMODE_ATTR_ID(20), + TRANSCEIVER_LPMODE_ATTR_ID(21), + TRANSCEIVER_LPMODE_ATTR_ID(22), + TRANSCEIVER_LPMODE_ATTR_ID(23), + TRANSCEIVER_LPMODE_ATTR_ID(24), + TRANSCEIVER_LPMODE_ATTR_ID(25), + TRANSCEIVER_LPMODE_ATTR_ID(26), + TRANSCEIVER_LPMODE_ATTR_ID(27), + TRANSCEIVER_LPMODE_ATTR_ID(28), + TRANSCEIVER_LPMODE_ATTR_ID(29), + TRANSCEIVER_LPMODE_ATTR_ID(30), + TRANSCEIVER_LPMODE_ATTR_ID(31), + TRANSCEIVER_LPMODE_ATTR_ID(32), + TRANSCEIVER_LPMODE_ATTR_ID(33), + TRANSCEIVER_LPMODE_ATTR_ID(34), + TRANSCEIVER_LPMODE_ATTR_ID(35), + TRANSCEIVER_LPMODE_ATTR_ID(36), + TRANSCEIVER_LPMODE_ATTR_ID(37), + TRANSCEIVER_LPMODE_ATTR_ID(38), + TRANSCEIVER_LPMODE_ATTR_ID(39), + TRANSCEIVER_LPMODE_ATTR_ID(40), + TRANSCEIVER_LPMODE_ATTR_ID(41), + TRANSCEIVER_LPMODE_ATTR_ID(42), + TRANSCEIVER_LPMODE_ATTR_ID(43), + TRANSCEIVER_LPMODE_ATTR_ID(44), + TRANSCEIVER_LPMODE_ATTR_ID(45), + TRANSCEIVER_LPMODE_ATTR_ID(46), + TRANSCEIVER_LPMODE_ATTR_ID(47), + TRANSCEIVER_LPMODE_ATTR_ID(48), + TRANSCEIVER_LPMODE_ATTR_ID(49), + TRANSCEIVER_LPMODE_ATTR_ID(50), + TRANSCEIVER_LPMODE_ATTR_ID(51), + TRANSCEIVER_LPMODE_ATTR_ID(52), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), + TRANSCEIVER_LPMODE_ATTR_ID(55), + TRANSCEIVER_LPMODE_ATTR_ID(56), + TRANSCEIVER_LPMODE_ATTR_ID(57), + TRANSCEIVER_LPMODE_ATTR_ID(58), + TRANSCEIVER_LPMODE_ATTR_ID(59), + TRANSCEIVER_LPMODE_ATTR_ID(60), + TRANSCEIVER_LPMODE_ATTR_ID(61), + TRANSCEIVER_LPMODE_ATTR_ID(62), + TRANSCEIVER_LPMODE_ATTR_ID(63), + TRANSCEIVER_LPMODE_ATTR_ID(64), + TRANSCEIVER_LPMODE_ATTR_ID(65), + TRANSCEIVER_LPMODE_ATTR_ID(66), + TRANSCEIVER_LPMODE_ATTR_ID(67), + TRANSCEIVER_LPMODE_ATTR_ID(68), + TRANSCEIVER_LPMODE_ATTR_ID(69), + TRANSCEIVER_LPMODE_ATTR_ID(70), + TRANSCEIVER_LPMODE_ATTR_ID(71), + TRANSCEIVER_LPMODE_ATTR_ID(72), + TRANSCEIVER_TX_DISABLE_ATTR_ID(73), + TRANSCEIVER_TX_DISABLE_ATTR_ID(74), + TRANSCEIVER_TX_DISABLE_ATTR_ID(75), + TRANSCEIVER_TX_DISABLE_ATTR_ID(76), + TRANSCEIVER_TX_FAULT_ATTR_ID(73), + TRANSCEIVER_TX_FAULT_ATTR_ID(74), + TRANSCEIVER_TX_FAULT_ATTR_ID(75), + TRANSCEIVER_TX_FAULT_ATTR_ID(76), + TRANSCEIVER_RX_LOS_ATTR_ID(73), + TRANSCEIVER_RX_LOS_ATTR_ID(74), + TRANSCEIVER_RX_LOS_ATTR_ID(75), + TRANSCEIVER_RX_LOS_ATTR_ID(76), +}; + +/*********************************************** + * function declare + * *********************************************/ +static ssize_t status_read(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t status_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +#define DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, status_read, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO|S_IWUSR, status_read, status_write, MODULE_RESET_##index); \ + static SENSOR_DEVICE_ATTR(module_lp_mode_##index, S_IRUGO|S_IWUSR, status_read, status_write, MODULE_LPMODE_##index) +#define DECLARE_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr, \ + &sensor_dev_attr_module_lp_mode_##index.dev_attr.attr + +/* transceiver attributes */ +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(55); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(56); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(57); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(58); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(59); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(60); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(61); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(62); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(63); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(64); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(65); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(66); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(67); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(68); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(69); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(70); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(71); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(72); +static SENSOR_DEVICE_ATTR(module_present_73, S_IRUGO, status_read, NULL, MODULE_PRESENT_73); +static SENSOR_DEVICE_ATTR(module_present_74, S_IRUGO, status_read, NULL, MODULE_PRESENT_74); +static SENSOR_DEVICE_ATTR(module_present_75, S_IRUGO, status_read, NULL, MODULE_PRESENT_75); +static SENSOR_DEVICE_ATTR(module_present_76, S_IRUGO, status_read, NULL, MODULE_PRESENT_76); +static SENSOR_DEVICE_ATTR(module_tx_disable_73, S_IRUGO|S_IWUSR, status_read, + status_write, MODULE_TX_DISABLE_73); +static SENSOR_DEVICE_ATTR(module_tx_disable_74, S_IRUGO|S_IWUSR, status_read, + status_write, MODULE_TX_DISABLE_74); +static SENSOR_DEVICE_ATTR(module_tx_disable_75, S_IRUGO|S_IWUSR, status_read, + status_write, MODULE_TX_DISABLE_75); +static SENSOR_DEVICE_ATTR(module_tx_disable_76, S_IRUGO|S_IWUSR, status_read, + status_write, MODULE_TX_DISABLE_76); +static SENSOR_DEVICE_ATTR(module_tx_fault_73, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_73); +static SENSOR_DEVICE_ATTR(module_tx_fault_74, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_74); +static SENSOR_DEVICE_ATTR(module_tx_fault_75, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_75); +static SENSOR_DEVICE_ATTR(module_tx_fault_76, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_76); +static SENSOR_DEVICE_ATTR(module_rx_los_73, S_IRUGO, status_read, NULL, MODULE_RX_LOS_73); +static SENSOR_DEVICE_ATTR(module_rx_los_74, S_IRUGO, status_read, NULL, MODULE_RX_LOS_74); +static SENSOR_DEVICE_ATTR(module_rx_los_75, S_IRUGO, status_read, NULL, MODULE_RX_LOS_75); +static SENSOR_DEVICE_ATTR(module_rx_los_76, S_IRUGO, status_read, NULL, MODULE_RX_LOS_76); + +static struct attribute *fpga_transceiver_attributes[] = { + DECLARE_TRANSCEIVER_ATTR(1), + DECLARE_TRANSCEIVER_ATTR(2), + DECLARE_TRANSCEIVER_ATTR(3), + DECLARE_TRANSCEIVER_ATTR(4), + DECLARE_TRANSCEIVER_ATTR(5), + DECLARE_TRANSCEIVER_ATTR(6), + DECLARE_TRANSCEIVER_ATTR(7), + DECLARE_TRANSCEIVER_ATTR(8), + DECLARE_TRANSCEIVER_ATTR(9), + DECLARE_TRANSCEIVER_ATTR(10), + DECLARE_TRANSCEIVER_ATTR(11), + DECLARE_TRANSCEIVER_ATTR(12), + DECLARE_TRANSCEIVER_ATTR(13), + DECLARE_TRANSCEIVER_ATTR(14), + DECLARE_TRANSCEIVER_ATTR(15), + DECLARE_TRANSCEIVER_ATTR(16), + DECLARE_TRANSCEIVER_ATTR(17), + DECLARE_TRANSCEIVER_ATTR(18), + DECLARE_TRANSCEIVER_ATTR(19), + DECLARE_TRANSCEIVER_ATTR(20), + DECLARE_TRANSCEIVER_ATTR(21), + DECLARE_TRANSCEIVER_ATTR(22), + DECLARE_TRANSCEIVER_ATTR(23), + DECLARE_TRANSCEIVER_ATTR(24), + DECLARE_TRANSCEIVER_ATTR(25), + DECLARE_TRANSCEIVER_ATTR(26), + DECLARE_TRANSCEIVER_ATTR(27), + DECLARE_TRANSCEIVER_ATTR(28), + DECLARE_TRANSCEIVER_ATTR(29), + DECLARE_TRANSCEIVER_ATTR(30), + DECLARE_TRANSCEIVER_ATTR(31), + DECLARE_TRANSCEIVER_ATTR(32), + DECLARE_TRANSCEIVER_ATTR(33), + DECLARE_TRANSCEIVER_ATTR(34), + DECLARE_TRANSCEIVER_ATTR(35), + DECLARE_TRANSCEIVER_ATTR(36), + DECLARE_TRANSCEIVER_ATTR(37), + DECLARE_TRANSCEIVER_ATTR(38), + DECLARE_TRANSCEIVER_ATTR(39), + DECLARE_TRANSCEIVER_ATTR(40), + DECLARE_TRANSCEIVER_ATTR(41), + DECLARE_TRANSCEIVER_ATTR(42), + DECLARE_TRANSCEIVER_ATTR(43), + DECLARE_TRANSCEIVER_ATTR(44), + DECLARE_TRANSCEIVER_ATTR(45), + DECLARE_TRANSCEIVER_ATTR(46), + DECLARE_TRANSCEIVER_ATTR(47), + DECLARE_TRANSCEIVER_ATTR(48), + DECLARE_TRANSCEIVER_ATTR(49), + DECLARE_TRANSCEIVER_ATTR(50), + DECLARE_TRANSCEIVER_ATTR(51), + DECLARE_TRANSCEIVER_ATTR(52), + DECLARE_TRANSCEIVER_ATTR(53), + DECLARE_TRANSCEIVER_ATTR(54), + DECLARE_TRANSCEIVER_ATTR(55), + DECLARE_TRANSCEIVER_ATTR(56), + DECLARE_TRANSCEIVER_ATTR(57), + DECLARE_TRANSCEIVER_ATTR(58), + DECLARE_TRANSCEIVER_ATTR(59), + DECLARE_TRANSCEIVER_ATTR(60), + DECLARE_TRANSCEIVER_ATTR(61), + DECLARE_TRANSCEIVER_ATTR(62), + DECLARE_TRANSCEIVER_ATTR(63), + DECLARE_TRANSCEIVER_ATTR(64), + DECLARE_TRANSCEIVER_ATTR(65), + DECLARE_TRANSCEIVER_ATTR(66), + DECLARE_TRANSCEIVER_ATTR(67), + DECLARE_TRANSCEIVER_ATTR(68), + DECLARE_TRANSCEIVER_ATTR(69), + DECLARE_TRANSCEIVER_ATTR(70), + DECLARE_TRANSCEIVER_ATTR(71), + DECLARE_TRANSCEIVER_ATTR(72), + &sensor_dev_attr_module_present_73.dev_attr.attr, + &sensor_dev_attr_module_present_74.dev_attr.attr, + &sensor_dev_attr_module_present_75.dev_attr.attr, + &sensor_dev_attr_module_present_76.dev_attr.attr, + &sensor_dev_attr_module_tx_disable_73.dev_attr.attr, + &sensor_dev_attr_module_tx_disable_74.dev_attr.attr, + &sensor_dev_attr_module_tx_disable_75.dev_attr.attr, + &sensor_dev_attr_module_tx_disable_76.dev_attr.attr, + &sensor_dev_attr_module_tx_fault_73.dev_attr.attr, + &sensor_dev_attr_module_tx_fault_74.dev_attr.attr, + &sensor_dev_attr_module_tx_fault_75.dev_attr.attr, + &sensor_dev_attr_module_tx_fault_76.dev_attr.attr, + &sensor_dev_attr_module_rx_los_73.dev_attr.attr, + &sensor_dev_attr_module_rx_los_74.dev_attr.attr, + &sensor_dev_attr_module_rx_los_75.dev_attr.attr, + &sensor_dev_attr_module_rx_los_76.dev_attr.attr, + NULL +}; + +static const struct attribute_group fpga_port_stat_group = { + .attrs = fpga_transceiver_attributes, +}; + +struct attribute_mapping { + u16 attr_base; + u16 reg; + u8 bar; + u8 revert; +}; + +// Define an array of attribute mappings +static struct attribute_mapping attribute_mappings[] = { + /* QSFP28 */ + [MODULE_PRESENT_1 ... MODULE_PRESENT_8] = {MODULE_PRESENT_1, QSFP28_P7_P0_PRESENT_REG, BAR5_NUM, 1}, + [MODULE_PRESENT_9 ... MODULE_PRESENT_16] = {MODULE_PRESENT_9, QSFP28_P15_P8_PRESENT_REG, BAR5_NUM, 1}, + [MODULE_PRESENT_17 ... MODULE_PRESENT_24] = {MODULE_PRESENT_17, QSFP28_P23_P16_PRESENT_REG, BAR5_NUM, 1}, + [MODULE_PRESENT_25 ... MODULE_PRESENT_32] = {MODULE_PRESENT_25, QSFP28_P31_P24_PRESENT_REG, BAR5_NUM, 1}, + [MODULE_PRESENT_33 ... MODULE_PRESENT_40] = {MODULE_PRESENT_33, QSFP28_P39_P32_PRESENT_REG, BAR5_NUM, 1}, + [MODULE_PRESENT_41 ... MODULE_PRESENT_48] = {MODULE_PRESENT_41, QSFP28_P47_P40_PRESENT_REG, BAR5_NUM, 1}, + /* QSFP-DD */ + [MODULE_PRESENT_49 ... MODULE_PRESENT_56] = {MODULE_PRESENT_49, QSFP_DD_P7_P0_PRESENT_REG, BAR4_NUM, 1}, + [MODULE_PRESENT_57 ... MODULE_PRESENT_60] = {MODULE_PRESENT_57, QSFP_DD_P11_P8_PRESENT_REG, BAR4_NUM, 1}, + [MODULE_PRESENT_61 ... MODULE_PRESENT_68] = {MODULE_PRESENT_61, QSFP_DD_P19_P12_PRESENT_REG, BAR4_NUM, 1}, + [MODULE_PRESENT_69 ... MODULE_PRESENT_72] = {MODULE_PRESENT_69, QSFP_DD_P23_P20_PRESENT_REG, BAR4_NUM, 1}, + /* SFP */ + [MODULE_PRESENT_73 ... MODULE_PRESENT_76] = {MODULE_PRESENT_73, SFP_P3_P0_PRESENT_REG, BAR5_NUM, 1}, + /* QSFP28 */ + [MODULE_RESET_1 ... MODULE_RESET_8] = {MODULE_RESET_1, QSFP28_P7_P0_RESET_REG, BAR5_NUM, 1}, + [MODULE_RESET_9 ... MODULE_RESET_16] = {MODULE_RESET_9, QSFP28_P15_P8_RESET_REG, BAR5_NUM, 1}, + [MODULE_RESET_17 ... MODULE_RESET_24] = {MODULE_RESET_17, QSFP28_P23_P16_RESET_REG, BAR5_NUM, 1}, + [MODULE_RESET_25 ... MODULE_RESET_32] = {MODULE_RESET_25, QSFP28_P31_P24_RESET_REG, BAR5_NUM, 1}, + [MODULE_RESET_33 ... MODULE_RESET_40] = {MODULE_RESET_33, QSFP28_P39_P32_RESET_REG, BAR5_NUM, 1}, + [MODULE_RESET_41 ... MODULE_RESET_48] = {MODULE_RESET_41, QSFP28_P47_P40_RESET_REG, BAR5_NUM, 1}, + /* QSFP-DD */ + [MODULE_RESET_49 ... MODULE_RESET_56] = {MODULE_RESET_49, QSFP_DD_P7_P0_RESET_REG, BAR4_NUM, 1}, + [MODULE_RESET_57 ... MODULE_RESET_60] = {MODULE_RESET_57, QSFP_DD_P11_P8_RESET_REG, BAR4_NUM, 1}, + [MODULE_RESET_61 ... MODULE_RESET_68] = {MODULE_RESET_61, QSFP_DD_P19_P12_RESET_REG, BAR4_NUM, 1}, + [MODULE_RESET_69 ... MODULE_RESET_72] = {MODULE_RESET_69, QSFP_DD_P23_P20_RESET_REG, BAR4_NUM, 1}, + /* QSFP28 */ + [MODULE_LPMODE_1 ... MODULE_LPMODE_8] = {MODULE_LPMODE_1, QSFP28_P7_P0_LPMODE_REG, BAR5_NUM, 0}, + [MODULE_LPMODE_9 ... MODULE_LPMODE_16] = {MODULE_LPMODE_9, QSFP28_P15_P8_LPMODE_REG, BAR5_NUM, 0}, + [MODULE_LPMODE_17 ... MODULE_LPMODE_24] = {MODULE_LPMODE_17, QSFP28_P23_P16_LPMODE_REG, BAR5_NUM, 0}, + [MODULE_LPMODE_25 ... MODULE_LPMODE_32] = {MODULE_LPMODE_25, QSFP28_P31_P24_LPMODE_REG, BAR5_NUM, 0}, + [MODULE_LPMODE_33 ... MODULE_LPMODE_40] = {MODULE_LPMODE_33, QSFP28_P39_P32_LPMODE_REG, BAR5_NUM, 0}, + [MODULE_LPMODE_41 ... MODULE_LPMODE_48] = {MODULE_LPMODE_41, QSFP28_P47_P40_LPMODE_REG, BAR5_NUM, 0}, + /* QSFP-DD */ + [MODULE_LPMODE_49 ... MODULE_LPMODE_56] = {MODULE_LPMODE_49, QSFP_DD_P7_P0_LPMODE_REG, BAR4_NUM, 0}, + [MODULE_LPMODE_57 ... MODULE_LPMODE_60] = {MODULE_LPMODE_57, QSFP_DD_P11_P8_LPMODE_REG, BAR4_NUM, 0}, + [MODULE_LPMODE_61 ... MODULE_LPMODE_68] = {MODULE_LPMODE_61, QSFP_DD_P19_P12_LPMODE_REG, BAR4_NUM, 0}, + [MODULE_LPMODE_69 ... MODULE_LPMODE_72] = {MODULE_LPMODE_69, QSFP_DD_P23_P20_LPMODE_REG, BAR4_NUM, 0}, + + /* SFP TXDIS, TXFAULT, RXLOS*/ + [MODULE_TX_DISABLE_73 ... MODULE_TX_DISABLE_76] ={MODULE_TX_DISABLE_73, SFP_P3_P0_TXDIS_REG,BAR5_NUM, 0}, + [MODULE_TX_FAULT_73 ... MODULE_TX_FAULT_76] = {MODULE_TX_FAULT_73, SFP_P3_P0_TXFAULT_REG, BAR5_NUM, 0}, + [MODULE_RX_LOS_73 ... MODULE_RX_LOS_76] = {MODULE_RX_LOS_73, SFP_P3_P0_RXLOS_REG, BAR5_NUM, 1}, +}; + +static inline unsigned int fpga_read(void __iomem *addr, u32 spi_mask) +{ + wait_spi(spi_mask, usecs_to_jiffies(20)); + return ioread8(addr); +} + +static inline void fpga_write(void __iomem *addr, u8 val, u32 spi_mask) +{ + wait_spi(spi_mask, usecs_to_jiffies(20)); + iowrite8(val, addr); +} + +static ssize_t status_read(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as9947_72xkb_fpga_data *fpga_ctl = dev_get_drvdata(dev); + ssize_t ret = -EINVAL; + u16 reg; + u8 fpga_async_data, reg_val, bar; + u8 bits_shift; + + switch(attr->index) + { + case MODULE_PRESENT_1 ... MODULE_PRESENT_16: + fpga_async_data = 0x0; + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_32: + fpga_async_data = 0x20; + break; + case MODULE_PRESENT_33 ... MODULE_PRESENT_48: + fpga_async_data = 0x10; + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_60: + fpga_async_data = 0x0; + break; + case MODULE_PRESENT_61 ... MODULE_PRESENT_72: + fpga_async_data = 0x01; + break; + case MODULE_PRESENT_73 ... MODULE_PRESENT_76: + fpga_async_data = 0x10; + break; + case MODULE_LPMODE_1 ... MODULE_LPMODE_16: + fpga_async_data = 0x0; + break; + case MODULE_LPMODE_17 ... MODULE_LPMODE_32: + fpga_async_data = 0x20; + break; + case MODULE_LPMODE_33 ... MODULE_LPMODE_48: + fpga_async_data = 0x10; + break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_60: + fpga_async_data = 0x0; + break; + case MODULE_LPMODE_61 ... MODULE_LPMODE_72: + fpga_async_data = 0x01; + break; + case MODULE_RESET_1 ... MODULE_RESET_16: + fpga_async_data = 0x0; + break; + case MODULE_RESET_17 ... MODULE_RESET_32: + fpga_async_data = 0x20; + break; + case MODULE_RESET_33 ... MODULE_RESET_48: + fpga_async_data = 0x10; + break; + case MODULE_RESET_49 ... MODULE_RESET_60: + fpga_async_data = 0x0; + break; + case MODULE_RESET_61 ... MODULE_RESET_72: + fpga_async_data = 0x01; + break; + case MODULE_TX_DISABLE_73 ... MODULE_RX_LOS_76: + fpga_async_data = 0x10; + break; + default: + break; + } + + reg = attribute_mappings[attr->index].reg; + bar = attribute_mappings[attr->index].bar; + + LOCK(&cpld_access_lock); + if (bar == BAR4_NUM){ + iowrite8(fpga_async_data, async_reg); + reg_val = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr4 + reg, + SPI_BUSY_MASK_CPLD1); + } + else + { + iowrite8(fpga_async_data, async_reg); + reg_val = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr5 + reg, + SPI_BUSY_MASK_CPLD2); + } + UNLOCK(&cpld_access_lock); + bits_shift = attr->index - attribute_mappings[attr->index].attr_base; + reg_val = (reg_val >> bits_shift) & 0x01; + + if (attribute_mappings[attr->index].revert) + reg_val = !reg_val; + ret = sprintf(buf, "%u\n", reg_val); + + return ret; +} + +static ssize_t status_write(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as9947_72xkb_fpga_data *fpga_ctl = dev_get_drvdata(dev); + void __iomem *addr; + int status; + u16 reg, bar; + u8 input, fpga_async_data; + u8 reg_val, bit_mask, should_set_bit; + u32 spi_mask; + + status = kstrtou8(buf, 10, &input); + if (status) { + return status; + } + + reg = attribute_mappings[attr->index].reg; + bar = attribute_mappings[attr->index].bar; + switch(attr->index) + { + case MODULE_LPMODE_1 ... MODULE_LPMODE_16: + fpga_async_data = 0x0; + break; + case MODULE_LPMODE_17 ... MODULE_LPMODE_32: + fpga_async_data = 0x20; + break; + case MODULE_LPMODE_33 ... MODULE_LPMODE_48: + fpga_async_data = 0x10; + break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_60: + fpga_async_data = 0x0; + break; + case MODULE_LPMODE_61 ... MODULE_LPMODE_72: + fpga_async_data = 0x01; + break; + case MODULE_RESET_1 ... MODULE_RESET_16: + fpga_async_data = 0x0; + break; + case MODULE_RESET_17 ... MODULE_RESET_32: + fpga_async_data = 0x20; + break; + case MODULE_RESET_33 ... MODULE_RESET_48: + fpga_async_data = 0x10; + break; + case MODULE_RESET_49 ... MODULE_RESET_60: + fpga_async_data = 0x0; + break; + case MODULE_RESET_61 ... MODULE_RESET_72: + fpga_async_data = 0x01; + break; + case MODULE_TX_DISABLE_73 ... MODULE_RX_LOS_76: + fpga_async_data = 0x10; + break; + default: + break; + } + + if (bar == BAR4_NUM){ + spi_mask = SPI_BUSY_MASK_CPLD1; + addr = fpga_ctl->pci_fpga_dev.data_base_addr4; + } + else + { + spi_mask = SPI_BUSY_MASK_CPLD2; + addr = fpga_ctl->pci_fpga_dev.data_base_addr5; + } + + bit_mask = 0x01 << (attr->index - attribute_mappings[attr->index].attr_base); + should_set_bit = attribute_mappings[attr->index].revert ? !input : input; + + LOCK(&cpld_access_lock); + iowrite8(fpga_async_data, async_reg); + reg_val = fpga_read(addr + reg, spi_mask); + if (should_set_bit) { + reg_val |= bit_mask; + } else { + reg_val &= ~bit_mask; + } + fpga_write(addr + reg, reg_val, spi_mask); + UNLOCK(&cpld_access_lock); + + return count; +} + +struct _port_data { + u16 offset; + u16 mask; /* SPI Busy mask : 0x01 --> CPLD1, 0x02 --> CPLD2 */ +}; +/* ============PCIe Bar Offset to I2C Master Mapping============== */ +static const struct _port_data port[PORT_NUM]= { + /* QSFP Port 0-15, Region 5, PCIE to MEZZ_CPLD0 */ + {0x2100, SPI_BUSY_MASK_CPLD2},/* 0x2100 - 0x2110 I2C Master QSFP28 Port0 */ + {0x2120, SPI_BUSY_MASK_CPLD2},/* 0x2120 - 0x2130 I2C Master QSFP28 Port1 */ + {0x2140, SPI_BUSY_MASK_CPLD2},/* 0x2140 - 0x2150 I2C Master QSFP28 Port2 */ + {0x2160, SPI_BUSY_MASK_CPLD2},/* 0x2160 - 0x2170 I2C Master QSFP28 Port3 */ + {0x2180, SPI_BUSY_MASK_CPLD2},/* 0x2180 - 0x2190 I2C Master QSFP28 Port4 */ + {0x21A0, SPI_BUSY_MASK_CPLD2},/* 0x21A0 - 0x21B0 I2C Master QSFP28 Port5 */ + {0x21C0, SPI_BUSY_MASK_CPLD2},/* 0x21C0 - 0x21D0 I2C Master QSFP28 Port6 */ + {0x21E0, SPI_BUSY_MASK_CPLD2},/* 0x21E0 - 0x21F0 I2C Master QSFP28 Port7 */ + {0x2200, SPI_BUSY_MASK_CPLD2},/* 0x2200 - 0x2210 I2C Master QSFP28 Port8 */ + {0x2220, SPI_BUSY_MASK_CPLD2},/* 0x2220 - 0x2230 I2C Master QSFP28 Port9 */ + {0x2240, SPI_BUSY_MASK_CPLD2},/* 0x2240 - 0x2250 I2C Master QSFP28 Port10 */ + {0x2260, SPI_BUSY_MASK_CPLD2},/* 0x2260 - 0x2270 I2C Master QSFP28 Port11 */ + {0x2280, SPI_BUSY_MASK_CPLD2},/* 0x2280 - 0x2290 I2C Master QSFP28 Port12 */ + {0x22A0, SPI_BUSY_MASK_CPLD2},/* 0x22A0 - 0x22B0 I2C Master QSFP28 Port13 */ + {0x22C0, SPI_BUSY_MASK_CPLD2},/* 0x22C0 - 0x22D0 I2C Master QSFP28 Port14 */ + {0x22E0, SPI_BUSY_MASK_CPLD2},/* 0x22E0 - 0x22F0 I2C Master QSFP28 Port15 */ + /* QSFP Port 16-31, Region 5, PCIE to MEZZ_CPLD2 */ + {0x2100, SPI_BUSY_MASK_CPLD2},/* 0x2100 - 0x2110 I2C Master QSFP28 Port16 */ + {0x2120, SPI_BUSY_MASK_CPLD2},/* 0x2120 - 0x2130 I2C Master QSFP28 Port17*/ + {0x2140, SPI_BUSY_MASK_CPLD2},/* 0x2140 - 0x2150 I2C Master QSFP28 Port18 */ + {0x2160, SPI_BUSY_MASK_CPLD2},/* 0x2160 - 0x2170 I2C Master QSFP28 Port19 */ + {0x2180, SPI_BUSY_MASK_CPLD2},/* 0x2180 - 0x2190 I2C Master QSFP28 Port20 */ + {0x21A0, SPI_BUSY_MASK_CPLD2},/* 0x21A0 - 0x21B0 I2C Master QSFP28 Port21 */ + {0x21C0, SPI_BUSY_MASK_CPLD2},/* 0x21C0 - 0x21D0 I2C Master QSFP28 Port22 */ + {0x21E0, SPI_BUSY_MASK_CPLD2},/* 0x21E0 - 0x21F0 I2C Master QSFP28 Port23 */ + {0x2200, SPI_BUSY_MASK_CPLD2},/* 0x2200 - 0x2210 I2C Master QSFP28 Port24 */ + {0x2220, SPI_BUSY_MASK_CPLD2},/* 0x2220 - 0x2230 I2C Master QSFP28 Port25 */ + {0x2240, SPI_BUSY_MASK_CPLD2},/* 0x2240 - 0x2250 I2C Master QSFP28 Port26 */ + {0x2260, SPI_BUSY_MASK_CPLD2},/* 0x2260 - 0x2270 I2C Master QSFP28 Port27 */ + {0x2280, SPI_BUSY_MASK_CPLD2},/* 0x2280 - 0x2290 I2C Master QSFP28 Port28 */ + {0x22A0, SPI_BUSY_MASK_CPLD2},/* 0x22A0 - 0x22B0 I2C Master QSFP28 Port29 */ + {0x22C0, SPI_BUSY_MASK_CPLD2},/* 0x22C0 - 0x22D0 I2C Master QSFP28 Port30 */ + {0x22E0, SPI_BUSY_MASK_CPLD2},/* 0x22E0 - 0x22F0 I2C Master QSFP28 Port31 */ + /* QSFP Port 32-47, Region 5, PCIE to MEZZ_CPLD1 */ + {0x2100, SPI_BUSY_MASK_CPLD2},/* 0x2100 - 0x2110 I2C Master QSFP28 Port32 */ + {0x2120, SPI_BUSY_MASK_CPLD2},/* 0x2120 - 0x2130 I2C Master QSFP28 Port33 */ + {0x2140, SPI_BUSY_MASK_CPLD2},/* 0x2140 - 0x2150 I2C Master QSFP28 Port34 */ + {0x2160, SPI_BUSY_MASK_CPLD2},/* 0x2160 - 0x2170 I2C Master QSFP28 Port35 */ + {0x2180, SPI_BUSY_MASK_CPLD2},/* 0x2180 - 0x2190 I2C Master QSFP28 Port36 */ + {0x21A0, SPI_BUSY_MASK_CPLD2},/* 0x21A0 - 0x21B0 I2C Master QSFP28 Port37 */ + {0x21C0, SPI_BUSY_MASK_CPLD2},/* 0x21C0 - 0x21D0 I2C Master QSFP28 Port38 */ + {0x21E0, SPI_BUSY_MASK_CPLD2},/* 0x21E0 - 0x21F0 I2C Master QSFP28 Port39 */ + {0x2200, SPI_BUSY_MASK_CPLD2},/* 0x2200 - 0x2210 I2C Master QSFP28 Port40 */ + {0x2220, SPI_BUSY_MASK_CPLD2},/* 0x2220 - 0x2230 I2C Master QSFP28 Port41 */ + {0x2240, SPI_BUSY_MASK_CPLD2},/* 0x2240 - 0x2250 I2C Master QSFP28 Port42 */ + {0x2260, SPI_BUSY_MASK_CPLD2},/* 0x2260 - 0x2270 I2C Master QSFP28 Port43 */ + {0x2280, SPI_BUSY_MASK_CPLD2},/* 0x2280 - 0x2290 I2C Master QSFP28 Port44 */ + {0x22A0, SPI_BUSY_MASK_CPLD2},/* 0x22A0 - 0x22B0 I2C Master QSFP28 Port45 */ + {0x22C0, SPI_BUSY_MASK_CPLD2},/* 0x22C0 - 0x22D0 I2C Master QSFP28 Port46 */ + {0x22E0, SPI_BUSY_MASK_CPLD2},/* 0x22E0 - 0x22F0 I2C Master QSFP28 Port47 */ + /* QSFP-DD Port48-59, Region 4, PCIE to MB_CPLD0 */ + {0x2100, SPI_BUSY_MASK_CPLD1},/* 0x2100 - 0x2110 I2C Master QSFP-DD Port48 */ + {0x2120, SPI_BUSY_MASK_CPLD1},/* 0x2120 - 0x2130 I2C Master QSFP-DD Port49 */ + {0x2140, SPI_BUSY_MASK_CPLD1},/* 0x2140 - 0x2150 I2C Master QSFP-DD Port50 */ + {0x2160, SPI_BUSY_MASK_CPLD1},/* 0x2160 - 0x2170 I2C Master QSFP-DD Port51 */ + {0x2180, SPI_BUSY_MASK_CPLD1},/* 0x2180 - 0x2190 I2C Master QSFP-DD Port52 */ + {0x21A0, SPI_BUSY_MASK_CPLD1},/* 0x21A0 - 0x21B0 I2C Master QSFP-DD Port53 */ + {0x21C0, SPI_BUSY_MASK_CPLD1},/* 0x21C0 - 0x21D0 I2C Master QSFP-DD Port54 */ + {0x21E0, SPI_BUSY_MASK_CPLD1},/* 0x21E0 - 0x21F0 I2C Master QSFP-DD Port55 */ + {0x2200, SPI_BUSY_MASK_CPLD1},/* 0x2200 - 0x2210 I2C Master QSFP-DD Port56 */ + {0x2220, SPI_BUSY_MASK_CPLD1},/* 0x2220 - 0x2230 I2C Master QSFP-DD Port57 */ + {0x2240, SPI_BUSY_MASK_CPLD1},/* 0x2240 - 0x2250 I2C Master QSFP-DD Port58 */ + {0x2260, SPI_BUSY_MASK_CPLD1},/* 0x2260 - 0x2270 I2C Master QSFP-DD Port59 */ + /* QSFP-DD Port60-71, Region 4, PCIE to MB_CPLD1 */ + {0x2100, SPI_BUSY_MASK_CPLD1},/* 0x2100 - 0x2110 I2C Master QSFP-DD Port60 */ + {0x2120, SPI_BUSY_MASK_CPLD1},/* 0x2120 - 0x2130 I2C Master QSFP-DD Port61 */ + {0x2140, SPI_BUSY_MASK_CPLD1},/* 0x2140 - 0x2150 I2C Master QSFP-DD Port62 */ + {0x2160, SPI_BUSY_MASK_CPLD1},/* 0x2160 - 0x2170 I2C Master QSFP-DD Port63 */ + {0x2180, SPI_BUSY_MASK_CPLD1},/* 0x2180 - 0x2190 I2C Master QSFP-DD Port64 */ + {0x21A0, SPI_BUSY_MASK_CPLD1},/* 0x21A0 - 0x21B0 I2C Master QSFP-DD Port65 */ + {0x21C0, SPI_BUSY_MASK_CPLD1},/* 0x21C0 - 0x21D0 I2C Master QSFP-DD Port66 */ + {0x21E0, SPI_BUSY_MASK_CPLD1},/* 0x21E0 - 0x21F0 I2C Master QSFP-DD Port67 */ + {0x2200, SPI_BUSY_MASK_CPLD1},/* 0x2200 - 0x2210 I2C Master QSFP-DD Port68 */ + {0x2220, SPI_BUSY_MASK_CPLD1},/* 0x2220 - 0x2230 I2C Master QSFP-DD Port69 */ + {0x2240, SPI_BUSY_MASK_CPLD1},/* 0x2240 - 0x2250 I2C Master QSFP-DD Port70 */ + {0x2260, SPI_BUSY_MASK_CPLD1},/* 0x2260 - 0x2270 I2C Master QSFP-DD Port71 */ + /* SFP port 72-75, Region 5, PCIE to MEZZ_CPLD1 */ + {0x2300, SPI_BUSY_MASK_CPLD2},/* 0x2300 - 0x2310 I2C Master SFP+ Port72 */ + {0x2320, SPI_BUSY_MASK_CPLD2},/* 0x2320 - 0x2330 I2C Master SFP+ Port73 */ + {0x2340, SPI_BUSY_MASK_CPLD2},/* 0x2340 - 0x2350 I2C Master SFP+ Port74 */ + {0x2360, SPI_BUSY_MASK_CPLD2},/* 0x2360 - 0x2370 I2C Master SFP+ Port75 */ + +}; + +static struct ocores_i2c_platform_data as9947_72xkb_platform_data = { + .reg_io_width = 1, + .reg_shift = 2, + /* + * PRER_L and PRER_H are calculated based on clock_khz and bus_khz + * in i2c-ocores.c:ocores_init. + */ + + /* SCL 400KHZ in FPGA spec. => PRER_L = 0x0B, PRER_H = 0x00 */ + .clock_khz = 24000, + .bus_khz = 400, + + /* SCL 100KHZ in FPGA spec. => PRER_L = 0x2F, PRER_H = 0x00 */ + /*.clock_khz = 24000,*/ + /*.bus_khz = 100,*/ + +}; + +struct platform_device *ocore_i2c_device_add(unsigned int id, unsigned long bar_base, + unsigned int offset) +{ + struct resource res = DEFINE_RES_MEM(bar_base + offset, 0x20); + struct platform_device *pdev; + int err; + + pdev = platform_device_alloc(OCORES_I2C_DRVNAME, id); + if (!pdev) { + err = -ENOMEM; + pcie_err("Port%u device allocation failed (%d)\n", (id & 0xFF), err); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + pcie_err("Port%u device resource addition failed (%d)\n", (id & 0xFF), err); + goto exit_device_put; + } + + err = platform_device_add_data(pdev, &as9947_72xkb_platform_data, + sizeof(struct ocores_i2c_platform_data)); + if (err) { + pcie_err("Port%u platform data allocation failed (%d)\n", (id & 0xFF), err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + pcie_err("Port%u device addition failed (%d)\n", (id & 0xFF), err); + goto exit_device_put; + } + + return pdev; + +exit_device_put: + platform_device_put(pdev); +exit: + return NULL; +} + +static int as9947_72xkb_pcie_fpga_stat_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct as9947_72xkb_fpga_data *fpga_ctl; + struct pci_dev *pcidev; + struct resource *ret; + int i; + int status = 0, err = 0; + unsigned long bar_base; + int fpga_async_data; + + fpga_ctl = devm_kzalloc(dev, sizeof(struct as9947_72xkb_fpga_data), GFP_KERNEL); + if (!fpga_ctl) { + return -ENOMEM; + } + platform_set_drvdata(pdev, fpga_ctl); + + pcidev = pci_get_device(FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID, NULL); + if (!pcidev) { + dev_err(dev, "Cannot found PCI device(%x:%x)\n", + FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID); + return -ENODEV; + } + fpga_ctl->pci_fpga_dev.pci_dev = pcidev; + + err = pci_enable_device(pcidev); + if (err != 0) { + dev_err(dev, "Cannot enable PCI device(%x:%x)\n", + FPGA_PCI_VENDOR_ID, FPGA_PCI_DEVICE_ID); + status = -ENODEV; + goto exit_pci_disable; + } + /* enable PCI bus-mastering */ + pci_set_master(pcidev); + /* + * Cannot use 'pci_request_regions(pcidev, DRVNAME)' + * to request all Region 4, Region 5 because another + * address will be allocated by the i2c-ocores.ko. + */ + fpga_ctl->pci_fpga_dev.data_base_addr0 = pci_iomap(pcidev, BAR0_NUM, 0); + if (fpga_ctl->pci_fpga_dev.data_base_addr0 == NULL) { + dev_err(dev, "Failed to map BAR0\n"); + status = -EIO; + goto exit_pci_disable; + } + + spi_busy_reg = fpga_ctl->pci_fpga_dev.data_base_addr0 + 0x30; + async_reg = fpga_ctl->pci_fpga_dev.data_base_addr0 + 0x05; + + fpga_ctl->pci_fpga_dev.data_base_addr4 = pci_iomap(pcidev, BAR4_NUM, 0); + if (fpga_ctl->pci_fpga_dev.data_base_addr4 == NULL) { + dev_err(dev, "Failed to map BAR4\n"); + status = -EIO; + goto exit_pci_iounmap0; + } + + fpga_ctl->pci_fpga_dev.data_region4 = pci_resource_start(pcidev, BAR4_NUM) + CPLD_PCIE_START_OFFSET; + ret = request_mem_region(fpga_ctl->pci_fpga_dev.data_region4, REGION_LEN, DRVNAME"_mb_cpld"); + if (ret == NULL) { + dev_err(dev, "[%s] cannot request region\n", DRVNAME"_mb_cpld"); + status = -EIO; + goto exit_pci_iounmap1; + } + dev_info(dev, "(BAR%d resource: Start=0x%lx, Length=0x%x)", BAR4_NUM, + (unsigned long)fpga_ctl->pci_fpga_dev.data_region4, REGION_LEN); + + fpga_ctl->pci_fpga_dev.data_base_addr5 = pci_iomap(pcidev, BAR5_NUM, 0); + if (fpga_ctl->pci_fpga_dev.data_base_addr5 == NULL) { + dev_err(dev, "Failed to map BAR5\n"); + status = -EIO; + goto exit_pci_release1; + } + fpga_ctl->pci_fpga_dev.data_region5 = pci_resource_start(pcidev, BAR5_NUM) + CPLD_PCIE_START_OFFSET; + ret = request_mem_region(fpga_ctl->pci_fpga_dev.data_region5, REGION_LEN, DRVNAME"_mezz_cpld"); + if (ret == NULL) { + dev_err(dev, "[%s] cannot request region\n", DRVNAME"_mezz_cpld"); + status = -EIO; + goto exit_pci_iounmap2; + } + dev_info(dev, "(BAR%d resource: Start=0x%lx, Length=0x%x)", BAR5_NUM, + (unsigned long)fpga_ctl->pci_fpga_dev.data_region5, REGION_LEN); + /* Create I2C ocore devices first, then create the FPGA sysfs. + * To prevent the application from accessing an ocore device + * that has not been fully created due to the port status + * being present. + */ + + /* + * Create ocore_i2c device for QSFP/QSFP-DD/SFP EEPROM + */ + for (i = 0; i < PORT_NUM; i++) { + switch (i) + { + case 0 ... 15: + /* bit 4-5, 2'b00: pcie to Mezz_CPLD0 */ + fpga_async_data = 0x00; + bar_base = pci_resource_start(pcidev, BAR5_NUM); + break; + case 16 ... 31: + /* bit 4-5, 2'b10: pcie to Mezz_CPLD2 */ + fpga_async_data = 0x20; + bar_base = pci_resource_start(pcidev, BAR5_NUM); + break; + case 32 ... 47: + /* bit 4-5, 2'b01: pcie to Mezz_CPLD1 */ + fpga_async_data = 0x10; + bar_base = pci_resource_start(pcidev, BAR5_NUM); + break; + case 48 ... 59: + /* bit0, 0: pcie to MB_CPLD0 */ + fpga_async_data = 0x00; + bar_base = pci_resource_start(pcidev, BAR4_NUM); + break; + case 60 ... 71: + /* bit0, 1: pcie to MB_CPLD1 */ + fpga_async_data = 0x01; + bar_base = pci_resource_start(pcidev, BAR4_NUM); + break; + /* bit 4-5 2'b01: pcie to Mezz_CPLD1 */ + case 72 ... 75: + fpga_async_data = 0x10; + bar_base = pci_resource_start(pcidev, BAR5_NUM); + break; + default: + break; + } + + iowrite8(fpga_async_data, async_reg); + + fpga_ctl->pci_fpga_dev.fpga_i2c[i] = + ocore_i2c_device_add((i | (port[i].mask << 8)), bar_base, port[i].offset); + if (IS_ERR(fpga_ctl->pci_fpga_dev.fpga_i2c[i])) { + status = PTR_ERR(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); + dev_err(dev, "rc:%d, unload Port%u[0x%ux] device\n", + status, i, port[i].offset); + goto exit_ocores_device; + } + } + status = sysfs_create_group(&pdev->dev.kobj, &fpga_port_stat_group); + if (status) { + goto exit_ocores_device; + } + + return 0; + +exit_ocores_device: + while (i > 0) { + i--; + platform_device_unregister(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); + } + release_mem_region(fpga_ctl->pci_fpga_dev.data_region5, REGION_LEN); +exit_pci_iounmap2: + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr5); +exit_pci_release1: + release_mem_region(fpga_ctl->pci_fpga_dev.data_region4, REGION_LEN); +exit_pci_iounmap1: + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr4); +exit_pci_iounmap0: + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr0); +exit_pci_disable: + pci_disable_device(fpga_ctl->pci_fpga_dev.pci_dev); + + return status; +} + +static int as9947_72xkb_pcie_fpga_stat_remove(struct platform_device *pdev) +{ + struct as9947_72xkb_fpga_data *fpga_ctl = platform_get_drvdata(pdev); + + if (pci_is_enabled(fpga_ctl->pci_fpga_dev.pci_dev)) { + int i; + + sysfs_remove_group(&pdev->dev.kobj, &fpga_port_stat_group); + /* Unregister ocore_i2c device */ + for (i = 0; i < PORT_NUM; i++) { + platform_device_unregister(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); + } + + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr0); + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr4); + pci_iounmap(fpga_ctl->pci_fpga_dev.pci_dev, fpga_ctl->pci_fpga_dev.data_base_addr5); + release_mem_region(fpga_ctl->pci_fpga_dev.data_region4, REGION_LEN); + release_mem_region(fpga_ctl->pci_fpga_dev.data_region5, REGION_LEN); + pci_disable_device(fpga_ctl->pci_fpga_dev.pci_dev); + } + + return 0; +} + +static struct platform_driver pcie_fpga_port_stat_driver = { + .probe = as9947_72xkb_pcie_fpga_stat_probe, + .remove = as9947_72xkb_pcie_fpga_stat_remove, + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, +}; + +static int __init as9947_72xkb_pcie_fpga_init(void) +{ + int status = 0; + + /* + * Create FPGA platform driver and device + */ + status = platform_driver_register(&pcie_fpga_port_stat_driver); + if (status < 0) { + return status; + } + + pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(pdev)) { + status = PTR_ERR(pdev); + goto exit_pci; + } + + return status; + +exit_pci: + platform_driver_unregister(&pcie_fpga_port_stat_driver); + + return status; +} + +static void __exit as9947_72xkb_pcie_fpga_exit(void) +{ + platform_device_unregister(pdev); + platform_driver_unregister(&pcie_fpga_port_stat_driver); +} + + +module_init(as9947_72xkb_pcie_fpga_init); +module_exit(as9947_72xkb_pcie_fpga_exit); + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("AS9947-72XKB FPGA via PCIE"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-i2c-ocores.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-i2c-ocores.c new file mode 100644 index 0000000000..69f71a97aa --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-i2c-ocores.c @@ -0,0 +1,1026 @@ + +// SPDX-License-Identifier: GPL-2.0 +/* + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (https://opencores.org/project/i2c/overview) + * + * Peter Korsgaard + * + * Support for the GRLIB port of the controller by + * Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + void __iomem *base; + int iobase; + u32 reg_shift; + u32 reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + spinlock_t process_lock; + struct clk *clk; + int ip_clock_khz; + int bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); +}; + +/* registers */ +#define OCI2C_PRELOW 0 +#define OCI2C_PREHIGH 1 +#define OCI2C_CONTROL 2 +#define OCI2C_DATA 3 +#define OCI2C_CMD 4 /* write only */ +#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ + +#define OCI2C_CTRL_IEN 0x40 +#define OCI2C_CTRL_EN 0x80 + +#define OCI2C_CMD_START 0x91 +#define OCI2C_CMD_STOP 0x41 +#define OCI2C_CMD_READ 0x21 +#define OCI2C_CMD_WRITE 0x11 +#define OCI2C_CMD_READ_ACK 0x21 +#define OCI2C_CMD_READ_NACK 0x29 +#define OCI2C_CMD_IACK 0x01 + +#define OCI2C_STAT_IF 0x01 +#define OCI2C_STAT_TIP 0x02 +#define OCI2C_STAT_ARBLOST 0x20 +#define OCI2C_STAT_BUSY 0x40 +#define OCI2C_STAT_NACK 0x80 + +#define STATE_DONE 0 +#define STATE_START 1 +#define STATE_WRITE 2 +#define STATE_READ 3 +#define STATE_ERROR 4 + +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 +#define TYPE_SIFIVE_REV0 2 + +#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */ + +static unsigned int timeout = 1; +module_param(timeout , uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(timeout, "Tiemout for ocores_poll_wait, in unit of milliseconds."); + +static unsigned int debug = 1; +module_param(debug , uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(debug, "Enable or disable debug message. 1 -> enable, 0 -> disable"); + +spinlock_t cpld_access_lock; +EXPORT_SYMBOL(cpld_access_lock); + +#define LOCK(lock) \ +do { \ + spin_lock(lock); \ +} while (0) + +#define UNLOCK(lock) \ +do { \ + spin_unlock(lock); \ +} while (0) + +#define IOREMAP_SIZE (0x04) +static void __iomem *spi_busy_reg=NULL; +static void __iomem *async_reg = NULL; +EXPORT_SYMBOL(spi_busy_reg); +EXPORT_SYMBOL(async_reg); + +int wait_spi(u32 mask, u8 times) { + u32 data; + u32 spi_busy_flag = 0; + u8 max_times = 0; + max_times = times; + /* pr_info("CPLD %u, Will time-out at jiffie %lu\n", cpld_id,timeout); */ + if (!spi_busy_reg) { + return -EFAULT; + } + + while(max_times) { + data = ioread32(spi_busy_reg); + /* pr_info("@ %u, Read spi_busy_reg: 0x%08x 0x%08x\n", ri, data, mask); */ + if (!((( data >> 24) & 0xFF) & mask)) + { + /* spi flag is normal*/ + if (spi_busy_flag) + break; + } + else + { + spi_busy_flag = 1; + } + + usleep_range(10, 11); + max_times--; + + if(max_times == 0) + { + if(!spi_busy_flag) + break; + if (debug) { + pr_warn("spi_busy_flag %d as max_times is 0 \n", spi_busy_flag); + } + return -ETIMEDOUT; + } + } + + return 0; +} +EXPORT_SYMBOL(wait_spi); + +static int wait_cpld(struct ocores_i2c *i2c, u8 times) { + struct platform_device *pdev; + struct device *dev; + + if (!i2c->adap.dev.parent) { + return -EFAULT; + } + + /* Get SPI Busy mask from pdev->id */ + dev = i2c->adap.dev.parent; + pdev = container_of(dev, struct platform_device, dev); + wait_spi((pdev->id & 0xFF00) >> 8, times); + + return 0; +} + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + outb(value, i2c->iobase + reg); +} + +static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) +{ + return inb(i2c->iobase + reg); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + wait_cpld(i2c, 6); + i2c->setreg(i2c, reg, value); +} + +static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + wait_cpld(i2c, 6); + return i2c->getreg(i2c, reg); +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + unsigned long flags; + struct device *dev = i2c->adap.dev.parent; + + /* + * If we spin here is because we are in timeout, so we are going + * to be in STATE_ERROR. See ocores_process_timeout() + */ + spin_lock_irqsave(&i2c->process_lock, flags); + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + if (debug) { + dev_warn(dev, "I2C %s arbitration lost", i2c->adap.name); + } + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + i2c->state = STATE_ERROR; + if (debug) { + dev_warn(dev, "I2C %s, no ACK from slave 0x%02x", + i2c->adap.name, msg->addr); + } + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = i2c_8bit_addr_from_msg(msg); + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + goto out; + } + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } + +out: + spin_unlock_irqrestore(&i2c->process_lock, flags); + +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat = oc_getreg(i2c, OCI2C_STATUS); + + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) { + if ((stat & OCI2C_STAT_IF) && !(stat & OCI2C_STAT_BUSY)) + return IRQ_NONE; + } else if (!(stat & OCI2C_STAT_IF)) { + return IRQ_NONE; + } + ocores_process(i2c, stat); + + return IRQ_HANDLED; +} + +/** + * Process timeout event + * @i2c: ocores I2C device instance + */ +static void ocores_process_timeout(struct ocores_i2c *i2c) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c->process_lock, flags); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +/** + * Wait until something change in a given register + * @i2c: ocores I2C device instance + * @reg: register to query + * @mask: bitmask to apply on register value + * @val: expected result + * @timeout: timeout in jiffies + * + * Timeout is necessary to avoid to stay here forever when the chip + * does not answer correctly. + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_wait(struct ocores_i2c *i2c, + int reg, u8 mask, u8 val, + const unsigned long timeout) +{ + unsigned long j; + + j = jiffies + timeout; + while (1) { + u8 status = oc_getreg(i2c, reg); + + if ((status & mask) == val) + break; + + if (time_after(jiffies, j)) + return -ETIMEDOUT; + } + return 0; +} + +/** + * Wait until is possible to process some data + * @i2c: ocores I2C device instance + * + * Used when the device is in polling mode (interrupts disabled). + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_poll_wait(struct ocores_i2c *i2c) +{ + u8 mask; + int err; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* transfer is over */ + mask = OCI2C_STAT_BUSY; + } else { + /* on going transfer */ + mask = OCI2C_STAT_TIP; + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + */ + udelay((8 * 1000) / i2c->bus_clock_khz); + } + + /* + * once we are here we expect to get the expected result immediately + * so if after 1ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(timeout)); + if (err) { + if (debug) { + dev_warn(i2c->adap.dev.parent, + "%s: STATUS timeout, bit 0x%x did not clear in %ums(msecs_to_jiffies(%u)=%lu)\n", + __func__, mask, timeout, timeout, msecs_to_jiffies(timeout)); + } + } + return err; +} + +/** + * It handles an IRQ-less transfer + * @i2c: ocores I2C device instance + * + * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same + * (only that IRQ are not produced). This means that we can re-use entirely + * ocores_isr(), we just add our polling code around it. + * + * It can run in atomic context + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_process_polling(struct ocores_i2c *i2c) +{ + irqreturn_t ret; + int err; + + while (1) { + err = ocores_poll_wait(i2c); + if (err) { + break; /* timeout */ + } + + ret = ocores_isr(-1, i2c); + if (ret == IRQ_NONE) + break; /* all messages have been transferred */ + else { + if (i2c->flags & OCORES_FLAG_BROKEN_IRQ) + if (i2c->state == STATE_DONE) + break; + } + } + + return err; +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret = 0; + u8 ctrl; + int fpga_async_data; + + LOCK(&cpld_access_lock); + + struct platform_device *pdev; + struct device *dev; + int port; + + if (!i2c->adap.dev.parent) { + return -EFAULT; + } + + /* Get FPGA async mux from pdev->id */ + dev = i2c->adap.dev.parent; + pdev = container_of(dev, struct platform_device, dev); + port = (pdev->id & 0x00FF); + switch (port) + { + case 0 ... 15: + /* bit 4-5, 2'b00: pcie to Mezz_CPLD0 */ + fpga_async_data = 0x00; + break; + case 16 ... 31: + /* bit 4-5, 2'b10: pcie to Mezz_CPLD2 */ + fpga_async_data = 0x20; + break; + case 32 ... 47: + /* bit 4-5, 2'b01: pcie to Mezz_CPLD1 */ + fpga_async_data = 0x10; + break; + case 48 ... 59: + /* bit0, 0: pcie to MB_CPLD0 */ + fpga_async_data = 0x00; + break; + case 60 ... 71: + /* bit0, 1: pcie to MB_CPLD1 */ + fpga_async_data = 0x01; + break; + /* bit 4-5 2'b01: pcie to Mezz_CPLD1 */ + case 72 ... 75: + fpga_async_data = 0x10; + break; + default: + break; + } + + iowrite8(fpga_async_data, async_reg); + + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + if (polling) + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); + else + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + if (polling) { + ret = ocores_process_polling(i2c); + } else { + if (wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ) == 0) + ret = -ETIMEDOUT; + } + if (ret) { + ocores_process_timeout(i2c); + UNLOCK(&cpld_access_lock); + return ret; + } + + UNLOCK(&cpld_access_lock); + return (i2c->state == STATE_DONE) ? num : -EIO; +} + +static int ocores_xfer_polling(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); +} + +static int ocores_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, false); +} + +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) +{ + struct device *org; + int prescale; + int diff; + u8 ctrl; + + /* Temporary assignment for checking SPI Busy status. */ + org = i2c->adap.dev.parent; + i2c->adap.dev.parent = dev; + + LOCK(&cpld_access_lock); + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + UNLOCK(&cpld_access_lock); + + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + i2c->adap.dev.parent = org; + dev_err(dev, + "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + dev_info(dev, "OCI2C_PRELOW=0x%02x OCI2C_PREHIGH=0x%02x\n", + prescale & 0xff, prescale >> 8); + LOCK(&cpld_access_lock); + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + UNLOCK(&cpld_access_lock); + + i2c->adap.dev.parent = org; + + return 0; +} + + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .master_xfer_atomic = ocores_xfer_polling, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "i2c-ocores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + { + .compatible = "sifive,fu540-c000-i2c", + .data = (void *)TYPE_SIFIVE_REV0, + }, + { + .compatible = "sifive,i2c0", + .data = (void *)TYPE_SIFIVE_REV0, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +#ifdef CONFIG_OF +/* + * Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers have their offsets decreased accordingly. + */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + u32 val; + u32 clock_frequency; + bool clock_frequency_present; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } + } + + clock_frequency_present = !of_property_read_u32(np, "clock-frequency", + &clock_frequency); + i2c->bus_clock_khz = 100; + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(i2c->clk)) { + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + + if (i2c->ip_clock_khz == 0) { + if (of_property_read_u32(np, "opencores,ip-clock-frequency", + &val)) { + if (!clock_frequency_present) { + dev_err(&pdev->dev, + "Missing required parameter 'opencores,ip-clock-frequency'\n"); + clk_disable_unprepare(i2c->clk); + return -ENODEV; + } + i2c->ip_clock_khz = clock_frequency / 1000; + dev_warn(&pdev->dev, + "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); + } else { + i2c->ip_clock_khz = val / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + } + + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + + return 0; +} +#else +#define ocores_i2c_of_probe(pdev, i2c) -ENODEV +#endif + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + struct ocores_i2c_platform_data *pdata; + const struct of_device_id *match; + struct resource *res; + int irq; + int ret; + int i; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + spin_lock_init(&i2c->process_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + /* i2c->base = devm_ioremap_resource(&pdev->dev, res);*/ + /* For as9947-72xkb design */ + i2c->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + + dev_info(&pdev->dev, "Resouce start:0x%llx, end:0x%llx", res->start, res->end); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + } else { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EINVAL; + i2c->iobase = res->start; + if (!devm_request_region(&pdev->dev, res->start, + resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Can't get I/O resource.\n"); + return -EBUSY; + } + i2c->setreg = oc_setreg_io_8; + i2c->getreg = oc_getreg_io_8; + } + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; + i2c->ip_clock_khz = pdata->clock_khz; + dev_info(&pdev->dev, "Write %d KHz, ioWidth:%d, shift:%d", i2c->ip_clock_khz, pdata->reg_io_width ,pdata->reg_shift); + if (pdata->bus_khz) + i2c->bus_clock_khz = pdata->bus_khz; + else + i2c->bus_clock_khz = 100; + } else { + ret = ocores_i2c_of_probe(pdev, i2c); + if (ret) + return ret; + } + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->setreg || !i2c->getreg) { + bool be = pdata ? pdata->big_endian : + of_device_is_big_endian(pdev->dev.of_node); + + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case 4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto err_clk; + } + } + + init_waitqueue_head(&i2c->wait); + + irq = platform_get_irq_optional(pdev, 0); + if (irq == -ENXIO) { + ocores_algorithm.master_xfer = ocores_xfer_polling; + + /* + * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for + * FU540-C000 SoC in polling mode. + */ + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_SIFIVE_REV0) + i2c->flags |= OCORES_FLAG_BROKEN_IRQ; + } else { + if (irq < 0) + return irq; + } + + if (ocores_algorithm.master_xfer != ocores_xfer_polling) { + ret = devm_request_any_context_irq(&pdev->dev, irq, + ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_clk; + } + } + ret = ocores_init(&pdev->dev, i2c); + if (ret) { + goto err_clk; + } + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) { + goto err_clk; + } + /* add in known devices to the bus */ + if (pdata) { + for (i = 0; i < pdata->num_devices; i++){ + i2c_new_client_device(&i2c->adap, pdata->devices + i); + } + } + + return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int ocores_i2c_remove(struct platform_device *pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + u8 ctrl; + + LOCK(&cpld_access_lock); + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* disable i2c logic */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + UNLOCK(&cpld_access_lock); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ocores_i2c_suspend(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + return 0; +} + +static int ocores_i2c_resume(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + + if (!IS_ERR(i2c->clk)) { + unsigned long rate; + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; + } + return ocores_init(dev, i2c); +} + +static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); +#define OCORES_I2C_PM (&ocores_i2c_pm) +#else +#define OCORES_I2C_PM NULL +#endif + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "ocores-as9947", + .of_match_table = ocores_i2c_match, + .pm = OCORES_I2C_PM, + }, +}; + +#if 0 +module_platform_driver(ocores_i2c_driver); +#else +static int __init ocores_i2c_as9947_72xkb_init(void) +{ + int err; + + err = platform_driver_register(&ocores_i2c_driver); + if (err < 0) { + pr_err("Failed to register ocores_i2c_driver"); + return err; + } + + spin_lock_init(&cpld_access_lock); + + /* + * The register address of SPI Busy is 0x33. + * It can not only read one byte. It needs to read four bytes from 0x30. + * The value is obtained by '(ioread32(spi_busy_reg) >> 24) & 0xFF'. + */ + + return 0; +} +static void __exit ocores_i2c_as9947_72xkb_exit(void) +{ + platform_driver_unregister(&ocores_i2c_driver); +} + +module_init(ocores_i2c_as9947_72xkb_init); +module_exit(ocores_i2c_as9947_72xkb_exit); +#endif + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:ocores-as9947"); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c new file mode 100644 index 0000000000..41def2767c --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c @@ -0,0 +1,550 @@ +/* + * Copyright (C) Willy Liu + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9947_72xkb_led" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_LED_READ_CMD 0x1A +#define IPMI_LED_WRITE_CMD 0x1B +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_led(struct device *dev, struct device_attribute *attr, + char *buf); +static int as9947_72xkb_led_probe(struct platform_device *pdev); +static int as9947_72xkb_led_remove(struct platform_device *pdev); + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user *user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct as9947_72xkb_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned char ipmi_resp[6]; /* 0:Loc 1:Diag 2:Gnss 3:Fan 4:Psu1 5:Psu2 */ + struct ipmi_data ipmi; +}; + +struct as9947_72xkb_led_data *data = NULL; + +static struct platform_driver as9947_72xkb_led_driver = { + .probe = as9947_72xkb_led_probe, + .remove = as9947_72xkb_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum ipmi_led_light_mode { + IPMI_LED_MODE_OFF, + IPMI_LED_MODE_RED = 2, + IPMI_LED_MODE_RED_BLINKING = 3, + IPMI_LED_MODE_GREEN = 4, + IPMI_LED_MODE_GREEN_BLINKING = 5, + IPMI_LED_MODE_BLUE = 8, + IPMI_LED_MODE_BLUE_BLINKING = 9, + IPMI_LED_MODE_CYAN = 0xC, + IPMI_LED_MODE_WHITE = 0xE, + IPMI_LED_MODE_AMBER = 0x10, + IPMI_LED_MODE_ORANGE = 0x20, +}; + +enum led_light_mode { + LED_MODE_OFF, + LED_MODE_RED = 10, + LED_MODE_RED_BLINKING = 11, + LED_MODE_ORANGE = 12, + LED_MODE_ORANGE_BLINKING = 13, + LED_MODE_YELLOW = 14, + LED_MODE_YELLOW_BLINKING = 15, + LED_MODE_GREEN = 16, + LED_MODE_GREEN_BLINKING = 17, + LED_MODE_BLUE = 18, + LED_MODE_BLUE_BLINKING = 19, + LED_MODE_PURPLE = 20, + LED_MODE_PURPLE_BLINKING = 21, + LED_MODE_AUTO = 22, + LED_MODE_AUTO_BLINKING = 23, + LED_MODE_WHITE = 24, + LED_MODE_WHITE_BLINKING = 25, + LED_MODE_CYAN = 26, + LED_MODE_CYAN_BLINKING = 27, + LED_MODE_UNKNOWN = 99 +}; + +enum as9947_72xkb_led_sysfs_attrs { + LED_LOC, + LED_ALARM, + LED_DIAG, + LED_FAN, + LED_PSU1, + LED_PSU2 +}; + +static SENSOR_DEVICE_ATTR(led_loc, S_IWUSR | S_IRUGO, show_led, set_led, + LED_LOC); +static SENSOR_DEVICE_ATTR(led_alarm, S_IWUSR | S_IRUGO, show_led, set_led, + LED_ALARM); +static SENSOR_DEVICE_ATTR(led_diag, S_IWUSR | S_IRUGO, show_led, NULL, + LED_DIAG); +static SENSOR_DEVICE_ATTR(led_fan, S_IWUSR | S_IRUGO, show_led, NULL, + LED_FAN); +static SENSOR_DEVICE_ATTR(led_psu1, S_IWUSR | S_IRUGO, show_led, NULL, + LED_PSU1); +static SENSOR_DEVICE_ATTR(led_psu2, S_IWUSR | S_IRUGO, show_led, NULL, + LED_PSU2); + +static struct attribute *as9947_72xkb_led_attributes[] = { + &sensor_dev_attr_led_loc.dev_attr.attr, + &sensor_dev_attr_led_alarm.dev_attr.attr, + &sensor_dev_attr_led_diag.dev_attr.attr, + &sensor_dev_attr_led_fan.dev_attr.attr, + &sensor_dev_attr_led_psu1.dev_attr.attr, + &sensor_dev_attr_led_psu2.dev_attr.attr, + NULL +}; + +static const struct attribute_group as9947_72xkb_led_group = { + .attrs = as9947_72xkb_led_attributes, +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + int i = 0; + char raw_cmd[20] = ""; + + sprintf(raw_cmd, "0x%02x", cmd); + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + 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 as9947_72xkb_led_data *as9947_72xkb_led_update_device(void) +{ + int status = 0; + + if (time_before(jiffies, data->last_updated + HZ * 5) && data->valid) { + return data; + } + + data->valid = 0; + status = ipmi_send_message(&data->ipmi, IPMI_LED_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_led(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9947_72xkb_led_update_device(); + if (!data->valid) { + error = -EIO; + goto exit; + } + + switch (data->ipmi_resp[attr->index]) { + case IPMI_LED_MODE_OFF: + value = LED_MODE_OFF; + break; + case IPMI_LED_MODE_RED: + value = LED_MODE_RED; + break; + case IPMI_LED_MODE_RED_BLINKING: + value = LED_MODE_RED_BLINKING; + break; + case IPMI_LED_MODE_GREEN: + value = LED_MODE_GREEN; + break; + case IPMI_LED_MODE_GREEN_BLINKING: + value = LED_MODE_GREEN_BLINKING; + break; + case IPMI_LED_MODE_BLUE: + value = LED_MODE_BLUE; + break; + case IPMI_LED_MODE_BLUE_BLINKING: + value = LED_MODE_BLUE_BLINKING; + break; + case IPMI_LED_MODE_CYAN: + value = LED_MODE_CYAN; + break; + case IPMI_LED_MODE_WHITE: + value = LED_MODE_WHITE; + break; + case IPMI_LED_MODE_AMBER: + value = LED_MODE_ORANGE; + break; + case IPMI_LED_MODE_ORANGE: + value = LED_MODE_ORANGE; + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long mode; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + status = kstrtol(buf, 10, &mode); + if (status) + return status; + + mutex_lock(&data->update_lock); + + data = as9947_72xkb_led_update_device(); + if (!data->valid) { + status = -EIO; + goto exit; + } + + data->ipmi_resp[0] = attr->index + 1; + + switch (mode) { + case LED_MODE_OFF: + data->ipmi_resp[1] = IPMI_LED_MODE_OFF; + break; + case LED_MODE_RED: + data->ipmi_resp[1] = IPMI_LED_MODE_RED; + break; + case LED_MODE_RED_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_RED_BLINKING; + break; + case LED_MODE_GREEN: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN; + break; + case LED_MODE_GREEN_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_GREEN_BLINKING; + break; + case LED_MODE_BLUE: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE; + break; + case LED_MODE_BLUE_BLINKING: + data->ipmi_resp[1] = IPMI_LED_MODE_BLUE_BLINKING; + break; + case LED_MODE_CYAN: + data->ipmi_resp[1] = IPMI_LED_MODE_CYAN; + break; + case LED_MODE_WHITE: + data->ipmi_resp[1] = IPMI_LED_MODE_WHITE; + break; + case LED_MODE_YELLOW: + data->ipmi_resp[1] = IPMI_LED_MODE_AMBER; + break; + case LED_MODE_ORANGE: + data->ipmi_resp[1] = IPMI_LED_MODE_AMBER; + break; + default: + status = -EINVAL; + goto exit; + } + + /* Send IPMI write command */ + status = ipmi_send_message(&data->ipmi, IPMI_LED_WRITE_CMD, + data->ipmi_resp, 2, NULL, 0); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + status = count; + data->valid = 0; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as9947_72xkb_led_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as9947_72xkb_led_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as9947_72xkb_led_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as9947_72xkb_led_group); + + return 0; +} + +static int __init as9947_72xkb_led_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9947_72xkb_led_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as9947_72xkb_led_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) + goto ipmi_err; + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as9947_72xkb_led_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9947_72xkb_led_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9947_72xkb_led_driver); + kfree(data); +} + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("as9947_72xkb_led driver"); +MODULE_LICENSE("GPL"); + +module_init(as9947_72xkb_led_init); +module_exit(as9947_72xkb_led_exit); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c new file mode 100644 index 0000000000..945a680d78 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c @@ -0,0 +1,1072 @@ +/* + * Copyright (C) Willy Liu + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9947_72xkb_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 as9947_72xkb_psu_probe(struct platform_device *pdev); +static int as9947_72xkb_psu_remove(struct platform_device *pdev); + +enum psu_id { + PSU_1, + PSU_2, + NUM_OF_PSU +}; + +enum psu_data_index { + PSU_PRESENT = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD_CPLD, + PSU_POWER_GOOD_PMBUS, + PSU_OVER_VOLTAGE, + PSU_OVER_CURRENT, + PSU_POWER_ON, + PSU_VIN0, + PSU_VIN1, + PSU_VIN2, + PSU_VOUT0, + PSU_VOUT1, + PSU_VOUT2, + PSU_IIN0, + PSU_IIN1, + PSU_IIN2, + PSU_IOUT0, + PSU_IOUT1, + PSU_IOUT2, + PSU_PIN0, + PSU_PIN1, + PSU_PIN2, + PSU_PIN3, + PSU_POUT0, + PSU_POUT1, + PSU_POUT2, + PSU_POUT3, + PSU_TEMP1_0, + PSU_TEMP1_1, + PSU_TEMP2_0, + PSU_TEMP2_1, + PSU_TEMP3_0, + PSU_TEMP3_1, + PSU_FAN0, + PSU_FAN1, + PSU_VOUT_MODE, + PSU_STATUS_COUNT, + PSU_MODEL = 0, + PSU_SERIAL = 0, + PSU_TEMP1_MAX0 = 2, + PSU_TEMP1_MAX1, + PSU_TEMP1_MIN0, + PSU_TEMP1_MIN1, + PSU_TEMP2_MAX0, + PSU_TEMP2_MAX1, + PSU_TEMP2_MIN0, + PSU_TEMP2_MIN1, + PSU_TEMP3_MAX0, + PSU_TEMP3_MAX1, + PSU_TEMP3_MIN0, + PSU_TEMP3_MIN1, + PSU_VIN_UPPER_CRIT0, + PSU_VIN_UPPER_CRIT1, + PSU_VIN_UPPER_CRIT2, + PSU_VIN_MAX0, + PSU_VIN_MAX1, + PSU_VIN_MAX2, + PSU_VIN_MIN0, + PSU_VIN_MIN1, + PSU_VIN_MIN2, + PSU_VIN_LOWER_CRIT0, + PSU_VIN_LOWER_CRIT1, + PSU_VIN_LOWER_CRIT2, + PSU_VOUT_MAX0, + PSU_VOUT_MAX1, + PSU_VOUT_MAX2, + PSU_VOUT_MIN0, + PSU_VOUT_MIN1, + PSU_VOUT_MIN2, + PSU_IIN_MAX0, + PSU_IIN_MAX1, + PSU_IIN_MAX2, + PSU_IOUT_MAX0, + PSU_IOUT_MAX1, + PSU_IOUT_MAX2, + PSU_PIN_MAX0, + PSU_PIN_MAX1, + PSU_PIN_MAX2, + PSU_PIN_MAX3, + PSU_POUT_MAX0, + PSU_POUT_MAX1, + PSU_POUT_MAX2, + PSU_POUT_MAX3, + PSU_INFO_COUNT +}; + +struct ipmi_data { + struct completion read_complete; + struct ipmi_addr address; + struct ipmi_user * user; + int interface; + + struct kernel_ipmi_msg tx_message; + long tx_msgid; + + void *rx_msg_data; + unsigned short rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + struct ipmi_user_hndl ipmi_hndlrs; +}; + +struct ipmi_psu_resp_data { + unsigned char status[PSU_STATUS_COUNT]; + unsigned char info[PSU_INFO_COUNT]; + char serial[IPMI_MODEL_SERIAL_LEN+1]; + char model[IPMI_MODEL_SERIAL_LEN+1]; + char fandir[IPMI_FAN_DIR_LEN+1]; +}; + +struct as9947_72xkb_psu_data { + struct platform_device *pdev[2]; + struct device *hwmon_dev[2]; + struct mutex update_lock; + char valid[2]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ + unsigned long last_updated[2]; /* In jiffies, 0: PSU1, 1: PSU2 */ + struct ipmi_data ipmi; + struct ipmi_psu_resp_data ipmi_resp[2]; /* 0: PSU1, 1: PSU2 */ + unsigned char ipmi_tx_data[2]; +}; + +struct as9947_72xkb_psu_data *data = NULL; + +static struct platform_driver as9947_72xkb_psu_driver = { + .probe = as9947_72xkb_psu_probe, + .remove = as9947_72xkb_psu_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define PSU_PRESENT_ATTR_ID(index) PSU##index##_PRESENT +#define PSU_POWERGOOD_ATTR_ID(index) PSU##index##_POWER_GOOD +#define PSU_VIN_ATTR_ID(index) PSU##index##_VIN +#define PSU_VOUT_ATTR_ID(index) PSU##index##_VOUT +#define PSU_IIN_ATTR_ID(index) PSU##index##_IIN +#define PSU_IOUT_ATTR_ID(index) PSU##index##_IOUT +#define PSU_PIN_ATTR_ID(index) PSU##index##_PIN +#define PSU_POUT_ATTR_ID(index) PSU##index##_POUT +#define PSU_MODEL_ATTR_ID(index) PSU##index##_MODEL +#define PSU_SERIAL_ATTR_ID(index) PSU##index##_SERIAL +#define PSU_TEMP1_INPUT_ATTR_ID(index) PSU##index##_TEMP1_INPUT +#define PSU_TEMP2_INPUT_ATTR_ID(index) PSU##index##_TEMP2_INPUT +#define PSU_TEMP3_INPUT_ATTR_ID(index) PSU##index##_TEMP3_INPUT +#define PSU_FAN_INPUT_ATTR_ID(index) PSU##index##_FAN_INPUT +#define PSU_FAN_DIR_ATTR_ID(index) PSU##index##_FAN_DIR + +#define PSU_TEMP1_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP1_INPUT_MAX +#define PSU_TEMP1_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP1_INPUT_MIN +#define PSU_TEMP2_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP2_INPUT_MAX +#define PSU_TEMP2_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP2_INPUT_MIN +#define PSU_TEMP3_INPUT_MAX_ATTR_ID(index) PSU##index##_TEMP3_INPUT_MAX +#define PSU_TEMP3_INPUT_MIN_ATTR_ID(index) PSU##index##_TEMP3_INPUT_MIN +#define PSU_VIN_MAX_ATTR_ID(index) PSU##index##_VIN_MAX +#define PSU_VIN_MIN_ATTR_ID(index) PSU##index##_VIN_MIN +#define PSU_VIN_UPPER_CRIT_ATTR_ID(index) PSU##index##_VIN_UPPER_CRIT +#define PSU_VIN_LOWER_CRIT_ATTR_ID(index) PSU##index##_VIN_LOWER_CRIT +#define PSU_VOUT_MAX_ATTR_ID(index) PSU##index##_VOUT_MAX +#define PSU_VOUT_MIN_ATTR_ID(index) PSU##index##_VOUT_MIN +#define PSU_IIN_MAX_ATTR_ID(index) PSU##index##_IIN_MAX +#define PSU_IOUT_MAX_ATTR_ID(index) PSU##index##_IOUT_MAX +#define PSU_PIN_MAX_ATTR_ID(index) PSU##index##_PIN_MAX +#define PSU_POUT_MAX_ATTR_ID(index) PSU##index##_POUT_MAX + +#define PSU_ATTR(psu_id) \ + PSU_PRESENT_ATTR_ID(psu_id), \ + PSU_POWERGOOD_ATTR_ID(psu_id), \ + PSU_VIN_ATTR_ID(psu_id), \ + PSU_VOUT_ATTR_ID(psu_id), \ + PSU_IIN_ATTR_ID(psu_id), \ + PSU_IOUT_ATTR_ID(psu_id), \ + PSU_PIN_ATTR_ID(psu_id), \ + PSU_POUT_ATTR_ID(psu_id), \ + PSU_MODEL_ATTR_ID(psu_id), \ + PSU_SERIAL_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_INPUT_ATTR_ID(psu_id), \ + PSU_FAN_DIR_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP1_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP2_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_MAX_ATTR_ID(psu_id), \ + PSU_TEMP3_INPUT_MIN_ATTR_ID(psu_id), \ + PSU_VIN_MAX_ATTR_ID(psu_id), \ + PSU_VIN_MIN_ATTR_ID(psu_id), \ + PSU_VIN_UPPER_CRIT_ATTR_ID(psu_id), \ + PSU_VIN_LOWER_CRIT_ATTR_ID(psu_id), \ + PSU_VOUT_MAX_ATTR_ID(psu_id), \ + PSU_VOUT_MIN_ATTR_ID(psu_id), \ + PSU_IIN_MAX_ATTR_ID(psu_id), \ + PSU_IOUT_MAX_ATTR_ID(psu_id), \ + PSU_PIN_MAX_ATTR_ID(psu_id), \ + PSU_POUT_MAX_ATTR_ID(psu_id) + +enum as9947_72xkb_psu_sysfs_attrs { + /* psu attributes */ + PSU_ATTR(1), + PSU_ATTR(2), + NUM_OF_PSU_ATTR, + NUM_OF_PER_PSU_ATTR = (NUM_OF_PSU_ATTR/NUM_OF_PSU) +}; + +/* psu attributes */ +#define DECLARE_PSU_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(psu##index##_present, S_IRUGO, show_psu, NULL, \ + PSU##index##_PRESENT); \ + static SENSOR_DEVICE_ATTR(psu##index##_power_good, S_IRUGO, show_psu, NULL,\ + PSU##index##_POWER_GOOD); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin, S_IRUGO, show_psu, NULL, \ + PSU##index##_VIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout, S_IRUGO, show_psu, NULL, \ + PSU##index##_VOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin, S_IRUGO, show_psu, NULL, \ + PSU##index##_IIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout, S_IRUGO, show_psu, NULL, \ + PSU##index##_IOUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin, S_IRUGO, show_psu, NULL, \ + PSU##index##_PIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout, S_IRUGO, show_psu, NULL, \ + PSU##index##_POUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_model, S_IRUGO, show_string, NULL, \ + PSU##index##_MODEL); \ + static SENSOR_DEVICE_ATTR(psu##index##_serial, S_IRUGO, show_string, NULL,\ + PSU##index##_SERIAL);\ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP1_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP2_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input, S_IRUGO, show_psu,NULL,\ + PSU##index##_TEMP3_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan1_input, S_IRUGO, show_psu, NULL,\ + PSU##index##_FAN_INPUT); \ + static SENSOR_DEVICE_ATTR(psu##index##_fan_dir, S_IRUGO, show_string, NULL,\ + PSU##index##_FAN_DIR); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP1_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp1_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP1_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP2_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp2_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP2_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP3_INPUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_temp3_input_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_TEMP3_INPUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_upper_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_UPPER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vin_lower_crit, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VIN_LOWER_CRIT); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_vout_min, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_VOUT_MIN); \ + static SENSOR_DEVICE_ATTR(psu##index##_iin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_iout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_IOUT_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pin_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_PIN_MAX); \ + static SENSOR_DEVICE_ATTR(psu##index##_pout_max, S_IRUGO, \ + show_psu_info, NULL, PSU##index##_POUT_MAX) + +#define DECLARE_PSU_ATTR(index) \ + &sensor_dev_attr_psu##index##_present.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_power_good.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_model.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_serial.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_temp1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan1_input.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_fan_dir.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp1_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp2_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_temp3_input_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_upper_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vin_lower_crit.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_vout_max.dev_attr.attr,\ + &sensor_dev_attr_psu##index##_vout_min.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_iout_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pin_max.dev_attr.attr, \ + &sensor_dev_attr_psu##index##_pout_max.dev_attr.attr + +DECLARE_PSU_SENSOR_DEVICE_ATTR(1); +/*Duplicate nodes for lm-sensors.*/ +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_psu, NULL, PSU1_VOUT); +static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, show_psu, NULL, PSU1_IOUT); +static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, show_psu, NULL, PSU1_POUT); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_psu, NULL, PSU1_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_psu, NULL, PSU1_FAN_INPUT); + +static struct attribute *as9947_72xkb_psu1_attrs[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(1), + &sensor_dev_attr_curr1_input.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_power1_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + NULL +}; +static struct attribute_group as9947_72xkb_psu1_group = { + .attrs = as9947_72xkb_psu1_attrs, +}; +/* ATTRIBUTE_GROUPS(as9947_72xkb_psu1); */ + +DECLARE_PSU_SENSOR_DEVICE_ATTR(2); +/*Duplicate nodes for lm-sensors.*/ +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_psu, NULL, PSU2_VOUT); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_psu, NULL, PSU2_IOUT); +static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_psu, NULL, PSU2_POUT); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_psu, NULL, PSU2_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_psu, NULL, PSU2_FAN_INPUT); +static struct attribute *as9947_72xkb_psu2_attrs[] = { + /* psu attributes */ + DECLARE_PSU_ATTR(2), + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_power2_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + NULL +}; +static struct attribute_group as9947_72xkb_psu2_group = { + .attrs = as9947_72xkb_psu2_attrs, +}; +/* ATTRIBUTE_GROUPS(as9947_72xkb_psu2); */ + +const struct attribute_group *as9947_72xkb_psu_groups[][2] = { + {&as9947_72xkb_psu1_group, NULL}, + {&as9947_72xkb_psu2_group, NULL} +}; + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface) +{ + 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) { + pr_err("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; + pr_err("request_timeout=%x\n", err); + return err; +ipmi_req_err: + pr_err("request_settime=%x\n", err); + return err; +addr_err: + pr_err("validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + int i = 0; + char raw_cmd[20] = ""; + + sprintf(raw_cmd, "0x%02x", cmd); + + if(tx_len){ + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + pr_err("ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + pr_err("ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + 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) { + pr_err("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 as9947_72xkb_psu_data *as9947_72xkb_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; + int multiplier = 1000; + + mutex_lock(&data->update_lock); + + data = as9947_72xkb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_PRESENT: + case PSU2_PRESENT: + value = present; + break; + case PSU1_POWER_GOOD: + case PSU2_POWER_GOOD: + VALIDATE_PRESENT_RETURN(pid); + value = data->ipmi_resp[pid].status[PSU_POWER_GOOD_PMBUS]; + break; + case PSU1_IIN: + case PSU2_IIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IIN0] | + (u32)data->ipmi_resp[pid].status[PSU_IIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IIN2] << 16); + break; + case PSU1_IOUT: + case PSU2_IOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_IOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_IOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_IOUT2] << 16); + break; + case PSU1_VIN: + case PSU2_VIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VIN0] | + (u32)data->ipmi_resp[pid].status[PSU_VIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VIN2] << 16); + break; + case PSU1_VOUT: + case PSU2_VOUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_VOUT0] | + (u32)data->ipmi_resp[pid].status[PSU_VOUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_VOUT2] << 16); + break; + case PSU1_PIN: + case PSU2_PIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_PIN0] | + (u32)data->ipmi_resp[pid].status[PSU_PIN1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_PIN2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_PIN3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT: + case PSU2_POUT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].status[PSU_POUT0] | + (u32)data->ipmi_resp[pid].status[PSU_POUT1] << 8 | + (u32)data->ipmi_resp[pid].status[PSU_POUT2] << 16 | + (u32)data->ipmi_resp[pid].status[PSU_POUT3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_TEMP1_INPUT: + case PSU2_TEMP1_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].status[PSU_TEMP1_0] | + (u16)data->ipmi_resp[pid].status[PSU_TEMP1_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT: + case PSU2_TEMP2_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].status[PSU_TEMP2_0] | + (u16)data->ipmi_resp[pid].status[PSU_TEMP2_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT: + case PSU2_TEMP3_INPUT: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].status[PSU_TEMP3_0] | + (u16)data->ipmi_resp[pid].status[PSU_TEMP3_1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_FAN_INPUT: + case PSU2_FAN_INPUT: + VALIDATE_PRESENT_RETURN(pid); + multiplier = 1; + value = ((u32)data->ipmi_resp[pid].status[PSU_FAN0] | + (u32)data->ipmi_resp[pid].status[PSU_FAN1] << 8); + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_psu_info(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + s32 value = 0; + int present = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9947_72xkb_psu_update_device(da); + if (!data->valid[pid]) { + error = -EIO; + goto exit; + } + + present = !!(data->ipmi_resp[pid].status[PSU_PRESENT]); + + switch (attr->index) { + case PSU1_TEMP1_INPUT_MAX: + case PSU2_TEMP1_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP1_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP1_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP1_INPUT_MIN: + case PSU2_TEMP1_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP1_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP1_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT_MAX: + case PSU2_TEMP2_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP2_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP2_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP2_INPUT_MIN: + case PSU2_TEMP2_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP2_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP2_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT_MAX: + case PSU2_TEMP3_INPUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP3_MAX0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP3_MAX1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_TEMP3_INPUT_MIN: + case PSU2_TEMP3_INPUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = (s16)((u16)data->ipmi_resp[pid].info[PSU_TEMP3_MIN0] | + (u16)data->ipmi_resp[pid].info[PSU_TEMP3_MIN1] << 8); + value *= 1000; // Convert to millidegree Celsius + break; + case PSU1_VIN_UPPER_CRIT: + case PSU2_VIN_UPPER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_UPPER_CRIT2] << 16); + break; + case PSU1_VIN_LOWER_CRIT: + case PSU2_VIN_LOWER_CRIT: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_LOWER_CRIT2] << 16); + break; + case PSU1_VIN_MAX: + case PSU2_VIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MAX2] << 16); + break; + case PSU1_VIN_MIN: + case PSU2_VIN_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VIN_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VIN_MIN2] << 16); + break; + case PSU1_VOUT_MAX: + case PSU2_VOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MAX2] << 16); + break; + case PSU1_VOUT_MIN: + case PSU2_VOUT_MIN: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN0] | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_VOUT_MIN2] << 16); + break; + case PSU1_IIN_MAX: + case PSU2_IIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IIN_MAX2] << 16); + break; + case PSU1_IOUT_MAX: + case PSU2_IOUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_IOUT_MAX2] << 16); + break; + case PSU1_PIN_MAX: + case PSU2_PIN_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_PIN_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_PIN_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + case PSU1_POUT_MAX: + case PSU2_POUT_MAX: + VALIDATE_PRESENT_RETURN(pid); + value = ((u32)data->ipmi_resp[pid].info[PSU_POUT_MAX0] | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX1] << 8 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX2] << 16 | + (u32)data->ipmi_resp[pid].info[PSU_POUT_MAX3] << 24); + value /= 1000; // Convert to milliwatt + break; + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", present ? value : 0); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_PSU_ATTR; + char *str = NULL; + int error = 0; + + mutex_lock(&data->update_lock); + + data = as9947_72xkb_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 as9947_72xkb_psu_probe(struct platform_device *pdev) +{ + int status = 0; + struct device *hwmon_dev = NULL; + + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9947_72xkb_psu_groups[pdev->id]); + if (IS_ERR(hwmon_dev)) { + status = PTR_ERR(hwmon_dev); + return status; + } + + mutex_lock(&data->update_lock); + data->hwmon_dev[pdev->id] = hwmon_dev; + mutex_unlock(&data->update_lock); + + dev_info(&pdev->dev, "PSU%d device created\n", pdev->id + 1); + + return 0; +} + +static int as9947_72xkb_psu_remove(struct platform_device *pdev) +{ + mutex_lock(&data->update_lock); + if (data->hwmon_dev[pdev->id]) { + hwmon_device_unregister(data->hwmon_dev[pdev->id]); + data->hwmon_dev[pdev->id] = NULL; + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int __init as9947_72xkb_psu_init(void) +{ + int ret; + int i; + + data = kzalloc(sizeof(struct as9947_72xkb_psu_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9947_72xkb_psu_driver); + if (ret < 0) + goto dri_reg_err; + + for (i = 0; i < NUM_OF_PSU; i++) { + data->pdev[i] = platform_device_register_simple(DRVNAME, i, NULL, 0); + if (IS_ERR(data->pdev[i])) { + ret = PTR_ERR(data->pdev[i]); + goto dev_reg_err; + } + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0); + if (ret) { + goto ipmi_err; + } + + return 0; + +ipmi_err: + while (i > 0) { + i--; + platform_device_unregister(data->pdev[i]); + } +dev_reg_err: + platform_driver_unregister(&as9947_72xkb_psu_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9947_72xkb_psu_exit(void) +{ + int i; + + ipmi_destroy_user(data->ipmi.user); + for (i = 0; i < NUM_OF_PSU; i++) { + platform_device_unregister(data->pdev[i]); + } + platform_driver_unregister(&as9947_72xkb_psu_driver); + kfree(data); +} + +MODULE_AUTHOR("Roger Ho "); +MODULE_DESCRIPTION("as9947_72xkb_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(as9947_72xkb_psu_init); +module_exit(as9947_72xkb_psu_exit); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c new file mode 100644 index 0000000000..272ed3583d --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c @@ -0,0 +1,519 @@ +/* + * Copyright (C) Willy Liu + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9947_72xkb_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 */ + +#define IPMI_CPLD_READ_CMD 0x20 +#define IPMI_CPLD_COM_E_CMD 0x21 +#define IPMI_CPLD_1U_FAN_CMD 0x34 +#define IPMI_CPLD_2U_FAN_CMD 0x33 +#define IPMI_CPLD_FPGA_CMD 0x61 +#define IPMI_CPLD_MB_CPLD0_CMD 0x62 +#define IPMI_CPLD_MB_CPLD1_CMD 0x63 + +static int as9947_72xkb_sys_probe(struct platform_device *pdev); +static int as9947_72xkb_sys_remove(struct platform_device *pdev); +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_cpld_version(struct device *dev, struct device_attribute *da, char *buf); +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 as9947_72xkb_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_resp_cpld[2]; + unsigned char ipmi_tx_data[2]; + struct bin_attribute eeprom; /* eeprom data */ +}; + +struct as9947_72xkb_sys_data *data = NULL; + +static struct platform_driver as9947_72xkb_sys_driver = { + .probe = as9947_72xkb_sys_probe, + .remove = as9947_72xkb_sys_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as5916_54xks_sys_sysfs_attrs { + CPU_CPLD, + MB_FPGA, + MB_CPLD0, + MB_CPLD1, + FAN_CPLD1, + FAN_CPLD2 +}; +/* Functions to talk to the IPMI layer */ +static SENSOR_DEVICE_ATTR(cpu_cpld_ver, S_IRUGO, show_cpld_version, NULL, CPU_CPLD); +static SENSOR_DEVICE_ATTR(fpga_ver, S_IRUGO, show_cpld_version, NULL, MB_FPGA); +static SENSOR_DEVICE_ATTR(mb_cpld0_ver, S_IRUGO, show_cpld_version, NULL, MB_CPLD0); +static SENSOR_DEVICE_ATTR(mb_cpld1_ver, S_IRUGO, show_cpld_version, NULL, MB_CPLD1); +static SENSOR_DEVICE_ATTR(fan_cpld1_ver, S_IRUGO, show_cpld_version, NULL, FAN_CPLD1); +static SENSOR_DEVICE_ATTR(fan_cpld2_ver, S_IRUGO, show_cpld_version, NULL, FAN_CPLD2); + +static struct attribute *as9947_72xkb_sys_attributes[] = { + &sensor_dev_attr_cpu_cpld_ver.dev_attr.attr, + &sensor_dev_attr_fpga_ver.dev_attr.attr, + &sensor_dev_attr_mb_cpld0_ver.dev_attr.attr, + &sensor_dev_attr_mb_cpld1_ver.dev_attr.attr, + &sensor_dev_attr_fan_cpld1_ver.dev_attr.attr, + &sensor_dev_attr_fan_cpld2_ver.dev_attr.attr, + NULL +}; + +static const struct attribute_group as9947_72xkb_sys_group = { + .attrs = as9947_72xkb_sys_attributes, +}; + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + int i = 0; + char raw_cmd[20] = ""; + + sprintf(raw_cmd, "0x%02x", cmd); + + if(tx_len) { + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi_send_message_%d err rx_result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + 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 struct as9947_72xkb_sys_data *as9947_72xkb_sys_update_cpld_ver(unsigned char cpld_addr) +{ + int status = 0; + + data->valid = 0; + data->ipmi_tx_data[0] = cpld_addr; + status = ipmi_send_message(&data->ipmi, IPMI_CPLD_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp_cpld, + sizeof(data->ipmi_resp_cpld)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + +exit: + return data; +} + +static ssize_t show_cpld_version(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char major; + unsigned char minor; + unsigned char cpld_addr = 0; + int error = 0; + + switch (attr->index) { + case CPU_CPLD: + cpld_addr = IPMI_CPLD_COM_E_CMD; + break; + case MB_FPGA: + cpld_addr = IPMI_CPLD_FPGA_CMD; + break; + case MB_CPLD0: + cpld_addr = IPMI_CPLD_MB_CPLD0_CMD; + break; + case MB_CPLD1: + cpld_addr = IPMI_CPLD_MB_CPLD1_CMD; + break; + case FAN_CPLD1: + cpld_addr = IPMI_CPLD_1U_FAN_CMD; + case FAN_CPLD2: + cpld_addr = IPMI_CPLD_2U_FAN_CMD; + break; + default: + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + data = as9947_72xkb_sys_update_cpld_ver(cpld_addr); + if (!data->valid) { + error = -EIO; + goto exit; + } + + major = data->ipmi_resp_cpld[0]; + minor = data->ipmi_resp_cpld[1]; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d.%d\n", major, minor); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static int as9947_72xkb_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; + } + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as9947_72xkb_sys_group); + if (status) + goto exit; + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as9947_72xkb_sys_remove(struct platform_device *pdev) +{ + sysfs_eeprom_cleanup(&pdev->dev.kobj, &data->eeprom); + sysfs_remove_group(&pdev->dev.kobj, &as9947_72xkb_sys_group); + + return 0; +} + +static int __init as9947_72xkb_sys_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9947_72xkb_sys_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9947_72xkb_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(&as9947_72xkb_sys_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9947_72xkb_sys_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9947_72xkb_sys_driver); + kfree(data); +} + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("as9947_72xkb_sys driver"); +MODULE_LICENSE("GPL"); + +module_init(as9947_72xkb_sys_init); +module_exit(as9947_72xkb_sys_exit); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c new file mode 100644 index 0000000000..8a9dfe0a6c --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c @@ -0,0 +1,427 @@ +/* + * Copyright (C) Willy Liu + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9947_72xkb_thermal" +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_THERMAL_READ_CMD 0x12 +#define THERMAL_COUNT 10 +#define THERMAL_DATA_LEN 3 +#define THERMAL_DATA_COUNT (THERMAL_COUNT * THERMAL_DATA_LEN) + +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf); +static int as9947_72xkb_thermal_probe(struct platform_device *pdev); +static int as9947_72xkb_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 as9947_72xkb_thermal_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + char ipmi_resp[THERMAL_DATA_COUNT]; /* 3 bytes for each thermal */ + struct ipmi_data ipmi; + unsigned char ipmi_tx_data[2]; /* 0: thermal id, 1: temp */ +}; + +struct as9947_72xkb_thermal_data *data = NULL; + +static struct platform_driver as9947_72xkb_thermal_driver = { + .probe = as9947_72xkb_thermal_probe, + .remove = as9947_72xkb_thermal_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +enum as9947_72xkb_thermal_sysfs_attrs { + TEMP1_INPUT, // 0x4F Main board + TEMP2_INPUT, // 0x4E Main board + TEMP3_INPUT, // 0x4A Main board + TEMP4_INPUT, // 0x4B Main board + TEMP5_INPUT, // 0x48 Main board + TEMP6_INPUT, // 0x49 Main board + TEMP7_INPUT, // 0x4C Main board + TEMP8_INPUT, // 0x4D Main board + TEMP9_INPUT, // 0x4D FAN Board + TEMP10_INPUT, // 0x4E FAN Board +}; + +#define DECLARE_THERMAL_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(temp##index##_input, S_IRUGO, show_temp, \ + NULL, TEMP##index##_INPUT); + +#define DECLARE_THERMAL_ATTR(index) \ + &sensor_dev_attr_temp##index##_input.dev_attr.attr + +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 *as9947_72xkb_thermal_attrs[] = { + DECLARE_THERMAL_ATTR(1), + DECLARE_THERMAL_ATTR(2), + DECLARE_THERMAL_ATTR(3), + DECLARE_THERMAL_ATTR(4), + DECLARE_THERMAL_ATTR(5), + DECLARE_THERMAL_ATTR(6), + DECLARE_THERMAL_ATTR(7), + DECLARE_THERMAL_ATTR(8), + DECLARE_THERMAL_ATTR(9), + DECLARE_THERMAL_ATTR(10), + NULL +}; +ATTRIBUTE_GROUPS(as9947_72xkb_thermal); + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI address, message buffers and user data */ +static int init_ipmi_data(struct ipmi_data *ipmi, int iface, + struct device *dev) +{ + int err; + + init_completion(&ipmi->read_complete); + + /* Initialize IPMI address */ + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + + /* Initialize message buffers */ + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, "Unable to register user with IPMI " + "interface %d\n", ipmi->interface); + return -EACCES; + } + + return 0; +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_data; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_data; + ipmi->rx_msg_len = rx_len; + + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) + goto addr_err; + + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) + goto ipmi_req_err; + + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) + goto ipmi_timeout_err; + + return 0; + +ipmi_timeout_err: + err = -ETIMEDOUT; + dev_err(&data->pdev->dev, "request_timeout=%x\n", err); + return err; +ipmi_req_err: + dev_err(&data->pdev->dev, "request_settime=%x\n", err); + return err; +addr_err: + dev_err(&data->pdev->dev, "validate_addr=%x\n", err); + return err; +} + +/* Send an IPMI command with retry */ +static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + int i = 0; + char raw_cmd[20] = ""; + + sprintf(raw_cmd, "0x%02x", cmd); + + if(tx_len) { + for(i = 0; i < tx_len; i++) + sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + dev_err(&data->pdev->dev, + "ipmi cmd(%x) err status(%d)[%s] raw_cmd=[%s]\r\n tx_msgid=(%02x)", + cmd, status, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + dev_err(&data->pdev->dev, + "ipmi cmd(%x) err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", + cmd, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, + (int)ipmi->tx_msgid); + continue; + } + + break; + } + + 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 (time_after(jiffies, data->last_updated + HZ * 5) || !data->valid) { + data->valid = 0; + + status = ipmi_send_message(&data->ipmi, IPMI_THERMAL_READ_CMD, NULL, 0, + data->ipmi_resp, sizeof(data->ipmi_resp)); + if (unlikely(status != 0)) + goto exit; + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + } + + /* Get temp fault status */ + index = attr->index * TEMP_DATA_COUNT + TEMP_FAULT; + if (unlikely(data->ipmi_resp[index] == 0)) { + status = -EIO; + goto exit; + } + + /* Get temperature in degree celsius */ + index = attr->index * TEMP_DATA_COUNT + TEMP_INPUT; + status = ((s8)data->ipmi_resp[index]) * 1000; + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as9947_72xkb_thermal_probe(struct platform_device *pdev) +{ + int status = 0; + struct device *hwmon_dev; + + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9947_72xkb_thermal_groups); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + return status; + } + + mutex_lock(&data->update_lock); + data->hwmon_dev = hwmon_dev; + mutex_unlock(&data->update_lock); + + dev_info(&pdev->dev, "Device Created\n"); + + return status; +} + +static int as9947_72xkb_thermal_remove(struct platform_device *pdev) +{ + mutex_lock(&data->update_lock); + if (data->hwmon_dev) { + hwmon_device_unregister(data->hwmon_dev); + data->hwmon_dev = NULL; + } + mutex_unlock(&data->update_lock); + + return 0; +} + +static int __init as9947_72xkb_thermal_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9947_72xkb_thermal_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9947_72xkb_thermal_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + /* Set up IPMI interface */ + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); + if (ret) { + goto ipmi_err; + } + + return 0; + +ipmi_err: + platform_device_unregister(data->pdev); +dev_reg_err: + platform_driver_unregister(&as9947_72xkb_thermal_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9947_72xkb_thermal_exit(void) +{ + if (data) { + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9947_72xkb_thermal_driver); + kfree(data); + } +} + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("as9947_72xkb_thermal driver"); +MODULE_LICENSE("GPL"); + +module_init(as9947_72xkb_thermal_init); +module_exit(as9947_72xkb_thermal_exit); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/PKG.yml b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/PKG.yml new file mode 100644 index 0000000000..bd35e547e3 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/onlp-platform-any.yml PLATFORM=x86-64-accton-as9947-72xkb ARCH=amd64 TOOLCHAIN=x86_64-linux-gnu diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/Makefile new file mode 100644 index 0000000000..e7437cb23a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/Makefile @@ -0,0 +1,2 @@ +FILTER=src +include $(ONL)/make/subdirs.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/lib/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/lib/Makefile new file mode 100644 index 0000000000..0d61adeedf --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/lib/Makefile @@ -0,0 +1,2 @@ +PLATFORM := x86-64-accton-as9947-72xkb +include $(ONL)/packages/base/any/onlp/builds/platform/libonlp-platform.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/onlpdump/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/onlpdump/Makefile new file mode 100644 index 0000000000..fcd0c37b39 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/onlpdump/Makefile @@ -0,0 +1,2 @@ +PLATFORM := x86-64-accton-as9947-72xkb +include $(ONL)/packages/base/any/onlp/builds/platform/onlps.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.gitignore b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.module b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.module new file mode 100644 index 0000000000..d606a57e18 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/.module @@ -0,0 +1 @@ +name: x86_64_accton_as9947_72xkb diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/Makefile new file mode 100644 index 0000000000..a7a00d112e --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/Makefile @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### +include $(ONL)/make/config.mk +MODULE := x86_64_accton_as9947_72xkb +AUTOMODULE := x86_64_accton_as9947_72xkb +include $(BUILDER)/definemodule.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/README b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/README new file mode 100644 index 0000000000..94918478ca --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/README @@ -0,0 +1,6 @@ +############################################################################### +# +# x86_64_accton_as9947_72xkb README +# +############################################################################### + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/make.mk b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/make.mk new file mode 100644 index 0000000000..9bee9c18ad --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/make.mk @@ -0,0 +1,9 @@ +############################################################################### +# +# x86_64_accton_as9947_72xkb Autogeneration +# +############################################################################### +x86_64_accton_as9947_72xkb_AUTO_DEFS := module/auto/x86_64_accton_as9947_72xkb.yml +x86_64_accton_as9947_72xkb_AUTO_DIRS := module/inc/x86_64_accton_as9947_72xkb module/src +include $(BUILDER)/auto.mk + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/x86_64_accton_as9947_72xkb.yml b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/x86_64_accton_as9947_72xkb.yml new file mode 100644 index 0000000000..1ed83463ec --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/auto/x86_64_accton_as9947_72xkb.yml @@ -0,0 +1,50 @@ +############################################################################### +# +# x86_64_accton_as9947_72xkb Autogeneration Definitions. +# +############################################################################### + +cdefs: &cdefs +- X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING: + doc: "Include or exclude logging." + default: 1 +- X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT: + doc: "Default enabled log options." + default: AIM_LOG_OPTIONS_DEFAULT +- X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT: + doc: "Default enabled log bits." + default: AIM_LOG_BITS_DEFAULT +- X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT: + doc: "Default enabled custom log bits." + default: 0 +- X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB: + doc: "Default all porting macros to use the C standard libraries." + default: 1 +- X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS: + doc: "Include standard library headers for stdlib porting macros." + default: x86_64_accton_as9947_72xkb_CONFIG_PORTING_STDLIB +- X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI: + doc: "Include generic uCli support." + default: 0 +- X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION: + doc: "Assume chassis fan direction is the same as the PSU fan direction." + default: 0 + + +definitions: + cdefs: + x86_64_accton_as9947_72xkb_CONFIG_HEADER: + defs: *cdefs + basename: x86_64_accton_as9947_72xkb_config + + portingmacro: + x86_64_accton_as9947_72xkb: + macros: + - malloc + - free + - memset + - memcpy + - strncpy + - vsnprintf + - snprintf + - strlen diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb.x b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb.x new file mode 100644 index 0000000000..d0a10a3736 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb.x @@ -0,0 +1,14 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.xmacro(ALL).define> */ +/* */ + +/* <--auto.start.xenum(ALL).define> */ +/* */ + + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_config.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_config.h new file mode 100644 index 0000000000..b8236ecf98 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_config.h @@ -0,0 +1,137 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_accton_as9947_72xkb Configuration Header + * + * @addtogroup x86_64_accton_as9947_72xkb-config + * @{ + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9947_72xkb_CONFIG_H__ +#define __x86_64_accton_as9947_72xkb_CONFIG_H__ + +#ifdef GLOBAL_INCLUDE_CUSTOM_CONFIG +#include +#endif +#ifdef x86_64_accton_as9947_72xkb_INCLUDE_CUSTOM_CONFIG +#include +#endif + +/* */ +#include +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING + * + * Include or exclude logging. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING 1 +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT + * + * Default enabled log options. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT AIM_LOG_OPTIONS_DEFAULT +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT + * + * Default enabled log bits. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT AIM_LOG_BITS_DEFAULT +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT + * + * Default enabled custom log bits. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT 0 +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB + * + * Default all porting macros to use the C standard libraries. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB 1 +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + * + * Include standard library headers for stdlib porting macros. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS x86_64_accton_as9947_72xkb_CONFIG_PORTING_STDLIB +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI + * + * Include generic uCli support. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI 0 +#endif + +/** + * X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION + * + * Assume chassis fan direction is the same as the PSU fan direction. */ + + +#ifndef X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION +#define X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION 0 +#endif + + + +/** + * All compile time options can be queried or displayed + */ + +/** Configuration settings structure. */ +typedef struct x86_64_accton_as9947_72xkb_config_settings_s { + /** name */ + const char* name; + /** value */ + const char* value; +} x86_64_accton_as9947_72xkb_config_settings_t; + +/** Configuration settings table. */ +/** x86_64_accton_as9947_72xkb_config_settings table. */ +extern x86_64_accton_as9947_72xkb_config_settings_t x86_64_accton_as9947_72xkb_config_settings[]; + +/** + * @brief Lookup a configuration setting. + * @param setting The name of the configuration option to lookup. + */ +const char* x86_64_accton_as9947_72xkb_config_lookup(const char* setting); + +/** + * @brief Show the compile-time configuration. + * @param pvs The output stream. + */ +int x86_64_accton_as9947_72xkb_config_show(struct aim_pvs_s* pvs); + +/* */ + +#include "x86_64_accton_as9947_72xkb_porting.h" + +#endif /* __x86_64_accton_as9947_72xkb_CONFIG_H__ */ +/* @} */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_dox.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_dox.h new file mode 100644 index 0000000000..b2fbffcc88 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_dox.h @@ -0,0 +1,26 @@ +/**************************************************************************//** + * + * x86_64_accton_as9947_72xkb Doxygen Header + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9947_72xkb_DOX_H__ +#define __x86_64_accton_as9947_72xkb_DOX_H__ + +/** + * @defgroup x86_64_accton_as9947_72xkb x86_64_accton_as9947_72xkb - x86_64_accton_as9947_72xkb Description + * + +The documentation overview for this module should go here. + + * + * @{ + * + * @defgroup x86_64_accton_as9947_72xkb-x86_64_accton_as9947_72xkb Public Interface + * @defgroup x86_64_accton_as9947_72xkb-config Compile Time Configuration + * @defgroup x86_64_accton_as9947_72xkb-porting Porting Macros + * + * @} + * + */ + +#endif /* __x86_64_accton_as9947_72xkb_DOX_H__ */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_porting.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_porting.h new file mode 100644 index 0000000000..cc72c11493 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/inc/x86_64_accton_as9947_72xkb/x86_64_accton_as9947_72xkb_porting.h @@ -0,0 +1,107 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_accton_as9947_72xkb Porting Macros. + * + * @addtogroup x86_64_accton_as9947_72xkb-porting + * @{ + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9947_72xkb_PORTING_H__ +#define __x86_64_accton_as9947_72xkb_PORTING_H__ + + +/* */ +#if X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS == 1 +#include +#include +#include +#include +#include +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_MALLOC + #if defined(GLOBAL_MALLOC) + #define X86_64_ACCTON_AS9947_72XKB_MALLOC GLOBAL_MALLOC + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_MALLOC malloc + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_MALLOC is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_FREE + #if defined(GLOBAL_FREE) + #define X86_64_ACCTON_AS9947_72XKB_FREE GLOBAL_FREE + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_FREE free + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_FREE is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_MEMSET + #if defined(GLOBAL_MEMSET) + #define X86_64_ACCTON_AS9947_72XKB_MEMSET GLOBAL_MEMSET + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_MEMSET memset + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_MEMSET is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_MEMCPY + #if defined(GLOBAL_MEMCPY) + #define X86_64_ACCTON_AS9947_72XKB_MEMCPY GLOBAL_MEMCPY + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_MEMCPY memcpy + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_MEMCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_STRNCPY + #if defined(GLOBAL_STRNCPY) + #define X86_64_ACCTON_AS9947_72XKB_STRNCPY GLOBAL_STRNCPY + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_STRNCPY strncpy + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_STRNCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_VSNPRINTF + #if defined(GLOBAL_VSNPRINTF) + #define X86_64_ACCTON_AS9947_72XKB_VSNPRINTF GLOBAL_VSNPRINTF + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_VSNPRINTF vsnprintf + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_VSNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_SNPRINTF + #if defined(GLOBAL_SNPRINTF) + #define X86_64_ACCTON_AS9947_72XKB_SNPRINTF GLOBAL_SNPRINTF + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_SNPRINTF snprintf + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_SNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_ACCTON_AS9947_72XKB_STRLEN + #if defined(GLOBAL_STRLEN) + #define X86_64_ACCTON_AS9947_72XKB_STRLEN GLOBAL_STRLEN + #elif X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB == 1 + #define X86_64_ACCTON_AS9947_72XKB_STRLEN strlen + #else + #error The macro X86_64_ACCTON_AS9947_72XKB_STRLEN is required but cannot be defined. + #endif +#endif + +/* */ + + +#endif /* __x86_64_accton_as9947_72xkb_PORTING_H__ */ +/* @} */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/make.mk b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/make.mk new file mode 100644 index 0000000000..cdfee90399 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/make.mk @@ -0,0 +1,10 @@ +############################################################################### +# +# +# +############################################################################### +THIS_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +x86_64_accton_as9947_72xkb_INCLUDES := -I $(THIS_DIR)inc +x86_64_accton_as9947_72xkb_INTERNAL_INCLUDES := -I $(THIS_DIR)src +x86_64_accton_as9947_72xkb_DEPENDMODULE_ENTRIES := init:x86_64_accton_as9947_72xkb ucli:x86_64_accton_as9947_72xkb + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/Makefile new file mode 100644 index 0000000000..17828d5903 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/Makefile @@ -0,0 +1,9 @@ +############################################################################### +# +# Local source generation targets. +# +############################################################################### + +ucli: + @../../../../tools/uclihandlers.py x86_64_accton_as9947_72xkb_ucli.c + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/debug.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/debug.c new file mode 100644 index 0000000000..c76009c470 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/debug.c @@ -0,0 +1,45 @@ +#include "x86_64_accton_as9947_72xkb_int.h" + +#if x86_64_accton_as9947_72xkb_CONFIG_INCLUDE_DEBUG == 1 + +#include + +static char help__[] = + "Usage: debug [options]\n" + " -c CPLD Versions\n" + " -h Help\n" + ; + +int +x86_64_accton_as9947_72xkb_debug_main(int argc, char* argv[]) +{ + int c = 0; + int help = 0; + int rv = 0; + + while( (c = getopt(argc, argv, "ch")) != -1) { + switch(c) + { + case 'c': c = 1; break; + case 'h': help = 1; rv = 0; break; + default: help = 1; rv = 1; break; + } + + } + + if(help || argc == 1) { + printf("%s", help__); + return rv; + } + + if(c) { + printf("Not implemented.\n"); + } + + + return 0; +} + +#endif + + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c new file mode 100644 index 0000000000..6202eff51a --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c @@ -0,0 +1,368 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * Fan Platform Implementation Defaults. + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +enum fan_id { + FAN_1_ON_FAN_BOARD = 1, + FAN_2_ON_FAN_BOARD, + FAN_3_ON_FAN_BOARD, + FAN_4_ON_FAN_BOARD, + FAN_5_ON_FAN_BOARD, + FAN_6_ON_FAN_BOARD, + FAN_7_ON_FAN_BOARD, + FAN_8_ON_FAN_BOARD, + FAN_9_ON_FAN_BOARD, + FAN_10_ON_FAN_BOARD, + FAN_11_ON_FAN_BOARD, + FAN_12_ON_FAN_BOARD, + FAN_13_ON_FAN_BOARD, + FAN_14_ON_FAN_BOARD, + FAN_15_ON_FAN_BOARD, + FAN_16_ON_FAN_BOARD, + FAN_1_ON_PSU_1, + FAN_1_ON_PSU_2 +}; + +#define MAX_1U_FRONT_FAN_SPEED 28000 +#define MAX_1U_REAR_FAN_SPEED 31000 +#define MAX_2U_FRONT_FAN_SPEED 13600 +#define MAX_2U_REAR_FAN_SPEED 15400 +#define MAX_PSU_FAN_SPEED 25500 + +#define CHASSIS_FAN_INFO(fid) \ + { \ + { ONLP_FAN_ID_CREATE(FAN_##fid##_ON_FAN_BOARD), "Chassis Fan - "#fid, 0, {0} },\ + 0x0,\ + ONLP_FAN_CAPS_SET_PERCENTAGE | ONLP_FAN_CAPS_GET_RPM | ONLP_FAN_CAPS_GET_PERCENTAGE,\ + 0,\ + 0,\ + ONLP_FAN_MODE_INVALID,\ + } + +#define PSU_FAN_INFO(pid, fid) \ + { \ + { ONLP_FAN_ID_CREATE(FAN_##fid##_ON_PSU_##pid), "PSU "#pid" - Fan "#fid, 0, {0} },\ + 0x0,\ + ONLP_FAN_CAPS_GET_RPM | ONLP_FAN_CAPS_GET_PERCENTAGE,\ + 0,\ + 0,\ + ONLP_FAN_MODE_INVALID,\ + } + +/* Static fan information */ +onlp_fan_info_t finfo[] = { + { }, /* Not used */ + CHASSIS_FAN_INFO(1), + CHASSIS_FAN_INFO(2), + CHASSIS_FAN_INFO(3), + CHASSIS_FAN_INFO(4), + CHASSIS_FAN_INFO(5), + CHASSIS_FAN_INFO(6), + CHASSIS_FAN_INFO(7), + CHASSIS_FAN_INFO(8), + CHASSIS_FAN_INFO(9), + CHASSIS_FAN_INFO(10), + CHASSIS_FAN_INFO(11), + CHASSIS_FAN_INFO(12), + CHASSIS_FAN_INFO(13), + CHASSIS_FAN_INFO(14), + CHASSIS_FAN_INFO(15), + CHASSIS_FAN_INFO(16), + PSU_FAN_INFO(1,1), + PSU_FAN_INFO(2,1) +}; + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_FAN(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static int +_onlp_fani_set_fan_dir_info(int fid, onlp_fan_info_t* info) +{ + enum onlp_fan_dir dir = onlp_get_fan_dir(fid); + + if (FAN_DIR_F2B == dir) { + info->caps |= ONLP_FAN_CAPS_F2B; + info->status |= ONLP_FAN_STATUS_F2B; + } + else { + info->caps |= ONLP_FAN_CAPS_B2F; + info->status |= ONLP_FAN_STATUS_B2F; + } + + return ONLP_STATUS_OK; +} + +static int +_onlp_fani_info_get_fan(int fid, onlp_fan_info_t* info) +{ + int value, ret, pwm; + char *str = NULL; + int len; + int copy_len; + int hwmon_idx; + char file[32]; + int max_speed; + + hwmon_idx = onlp_get_fan_hwmon_idx(); + + /* get fan present status + */ + ret = onlp_file_read_int(&value, FAN_SYSFS_FORMAT"fan%d_present", fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + if (value == 0) { + return ONLP_STATUS_OK; + } + info->status |= ONLP_FAN_STATUS_PRESENT; + + /* get fan speed + */ + ret = onlp_file_read_int(&value, "%s""fan%d_input", FAN_SYSFS_FORMAT, fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + info->rpm = value; + + /* get speed percentage from rpm + */ + pwm = 0; + ret = onlp_file_read_int(&pwm, "%s""fan%d_pwm", FAN_SYSFS_FORMAT, fid); + if (ret < 0) { + return ONLP_STATUS_E_INTERNAL; + } + switch(fid){ + case FAN_1_ON_FAN_BOARD: + case FAN_2_ON_FAN_BOARD: + case FAN_3_ON_FAN_BOARD: + case FAN_4_ON_FAN_BOARD: + case FAN_5_ON_FAN_BOARD: + max_speed = MAX_2U_FRONT_FAN_SPEED; + break; + 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: + max_speed = MAX_2U_REAR_FAN_SPEED; + break; + case FAN_11_ON_FAN_BOARD: + case FAN_12_ON_FAN_BOARD: + case FAN_13_ON_FAN_BOARD: + max_speed = MAX_1U_FRONT_FAN_SPEED; + break; + case FAN_14_ON_FAN_BOARD: + case FAN_15_ON_FAN_BOARD: + case FAN_16_ON_FAN_BOARD: + max_speed = MAX_1U_REAR_FAN_SPEED; + break; + } + info->percentage = (info->rpm*100)/max_speed; + if (info->percentage > 100) + info->percentage = 100; + + /* Read model name for 2U fan + There are no eeprom for 1U fan */ + if(fid < 11) + { + snprintf(file, sizeof(file), "fan%d_model", fid); + len = onlp_file_read_str(&str, FAN_SYSFS_FORMAT_1, hwmon_idx, file); + if (str && len) { + if (sizeof(info->model) > len) + { + copy_len = len; + } + else + { + copy_len = sizeof(info->model) - 1; + } + + memcpy(info->model, str, copy_len); + info->model[copy_len] = '\0'; + } + AIM_FREE_IF_PTR(str); + + /* serial number*/ + snprintf(file, sizeof(file), "fan%d_serial", fid); + len = onlp_file_read_str(&str, FAN_SYSFS_FORMAT_1, hwmon_idx, file); + if (str && len) { + if (sizeof(info->serial) > len) + { + copy_len = len; + } + else + { + copy_len = sizeof(info->serial) - 1; + } + + memcpy(info->serial, str, copy_len); + info->serial[copy_len] = '\0'; + } + AIM_FREE_IF_PTR(str); + } + + + _onlp_fani_set_fan_dir_info(fid, info); + + return ONLP_STATUS_OK; +} + +static int +_onlp_fani_info_get_fan_on_psu(int pid, onlp_fan_info_t* info) +{ + char *str = NULL; + int val = 0; + int ret = 0; + + info->status |= ONLP_FAN_STATUS_PRESENT; + /* Get PSU power good status */ + ret = psu_status_info_get(pid, "power_good", &val); + if (ret < 0) + { + AIM_LOG_ERROR("Unable to read PSU(%d) node(power_good)\r\n", pid); + } + + if (val != PSU_STATUS_POWER_GOOD) { + info->rpm = 0; + info->percentage = 0; + info->status |= ONLP_FAN_STATUS_FAILED; + AIM_FREE_IF_PTR(str); + return ONLP_STATUS_OK; + } + /* get fan direction */ + ret = psu_status_string_get(pid, "fan_dir", &str); + if (ret < 0) + { + AIM_LOG_ERROR("Unable to read PSU(%d) node(fan_dir)\r\n", pid); + } + + if (str) { + if (strncmp(str, "B2F", strlen("B2F")) == 0) { + info->status |= ONLP_FAN_STATUS_B2F; + } + else { + info->status |= ONLP_FAN_STATUS_F2B; + } + AIM_FREE_IF_PTR(str); + } + /* get fan speed */ + ret = psu_status_info_get(pid, "fan1_input", &val); + if (ret < 0) + { + AIM_LOG_ERROR("Unable to read PSU(%d) node(fan1_input)\r\n", pid); + } + + info->rpm = val; + info->percentage = (info->rpm * 100)/MAX_PSU_FAN_SPEED; + + return ONLP_STATUS_OK; +} + +/* + * This function will be called prior to all of onlp_fani_* functions. + */ +int +onlp_fani_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_fani_info_get(onlp_oid_t id, onlp_fan_info_t* info) +{ + int rc = 0; + int fid; + VALIDATE(id); + + fid = ONLP_OID_ID_GET(id); + *info = finfo[fid]; + + switch (fid) { + case FAN_1_ON_FAN_BOARD: + case FAN_2_ON_FAN_BOARD: + case FAN_3_ON_FAN_BOARD: + case FAN_4_ON_FAN_BOARD: + case FAN_5_ON_FAN_BOARD: + case FAN_6_ON_FAN_BOARD: + case FAN_7_ON_FAN_BOARD: + case FAN_8_ON_FAN_BOARD: + case FAN_9_ON_FAN_BOARD: + case FAN_10_ON_FAN_BOARD: + case FAN_11_ON_FAN_BOARD: + case FAN_12_ON_FAN_BOARD: + case FAN_13_ON_FAN_BOARD: + case FAN_14_ON_FAN_BOARD: + case FAN_15_ON_FAN_BOARD: + case FAN_16_ON_FAN_BOARD: + rc = _onlp_fani_info_get_fan(fid, info); + break; + case FAN_1_ON_PSU_1: + case FAN_1_ON_PSU_2: + rc = _onlp_fani_info_get_fan_on_psu(fid-FAN_16_ON_FAN_BOARD, info); + break; + default: + rc = ONLP_STATUS_E_INVALID; + break; + } + + return rc; +} + +/* + * This function sets the fan speed of the given OID as a percentage. + * + * This will only be called if the OID has the PERCENTAGE_SET + * capability. + * + * It is optional if you have no fans at all with this feature. + */ +int +onlp_fani_percentage_set(onlp_oid_t id, int p) +{ + int fid; + + VALIDATE(id); + + fid = ONLP_OID_ID_GET(id); + + if (fid < FAN_1_ON_FAN_BOARD || fid > FAN_16_ON_FAN_BOARD) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + if (onlp_file_write_int(p, "%s""fan%d_pwm", FAN_SYSFS_FORMAT, fid) != 0) { + AIM_LOG_ERROR("Unable to change duty cycle of fan (%d)\r\n", fid); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/ledi.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/ledi.c new file mode 100644 index 0000000000..cfdd5f4be0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/ledi.c @@ -0,0 +1,235 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2013 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_LED(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +enum led_light_mode { /*must be the same with the definition @ kernel driver */ + LED_MODE_OFF, + LED_MODE_RED = 10, + LED_MODE_RED_BLINKING = 11, + LED_MODE_ORANGE = 12, + LED_MODE_ORANGE_BLINKING = 13, + LED_MODE_YELLOW = 14, + LED_MODE_YELLOW_BLINKING = 15, + LED_MODE_GREEN = 16, + LED_MODE_GREEN_BLINKING = 17, + LED_MODE_BLUE = 18, + LED_MODE_BLUE_BLINKING = 19, + LED_MODE_PURPLE = 20, + LED_MODE_PURPLE_BLINKING = 21, + LED_MODE_AUTO = 22, + LED_MODE_AUTO_BLINKING = 23, + LED_MODE_WHITE = 24, + LED_MODE_WHITE_BLINKING = 25, + LED_MODE_CYAN = 26, + LED_MODE_CYAN_BLINKING = 27, + LED_MODE_UNKNOWN = 99 +}; + +typedef struct led_light_mode_map { + enum onlp_led_id id; + enum led_light_mode driver_led_mode; + enum onlp_led_mode_e onlp_led_mode; +} led_light_mode_map_t; + +led_light_mode_map_t led_map[] = { + { LED_LOC, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_LOC, LED_MODE_BLUE_BLINKING, ONLP_LED_MODE_BLUE_BLINKING }, + { LED_DIAG, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_DIAG, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_DIAG, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_ALARM, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_ALARM, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_PSU1, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_PSU1, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_PSU1, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_PSU2, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_PSU2, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_PSU2, LED_MODE_RED, ONLP_LED_MODE_RED }, + { LED_FAN, LED_MODE_OFF, ONLP_LED_MODE_OFF }, + { LED_FAN, LED_MODE_GREEN, ONLP_LED_MODE_GREEN }, + { LED_FAN, LED_MODE_RED, ONLP_LED_MODE_RED } +}; + +static char *leds[] = { /* must map with onlp_led_id */ + NULL, + "loc", + "alarm", + "diag", + "psu1", + "psu2", + "fan", + "alarm", +}; + +/* + * Get the information for the given LED OID. + */ +static onlp_led_info_t linfo[] = +{ + { }, /* Not used */ + { + { ONLP_LED_ID_CREATE(LED_LOC), "Chassis LED 1 (LOC LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_BLUE_BLINKING, + }, + { + { ONLP_LED_ID_CREATE(LED_LOC), "Chassis LED 1 (ALARM LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_RED, + }, + { + { ONLP_LED_ID_CREATE(LED_DIAG), "Chassis LED 2 (DIAG LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_PSU1), "Chassis LED 3 (PSU1 LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_PSU2), "Chassis LED 4 (PSU2 LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_AUTO, + }, + { + { ONLP_LED_ID_CREATE(LED_FAN), "Chassis LED 5 (FAN LED)", 0, {0} }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_AUTO, + }, +}; + +static int driver_to_onlp_led_mode(enum onlp_led_id id, enum led_light_mode driver_led_mode) +{ + int i, nsize = sizeof(led_map)/sizeof(led_map[0]); + + for (i = 0; i < nsize; i++) { + if (id == led_map[i].id && driver_led_mode == led_map[i].driver_led_mode) { + return led_map[i].onlp_led_mode; + } + } + + return 0; +} + +static int onlp_to_driver_led_mode(enum onlp_led_id id, onlp_led_mode_t onlp_led_mode) +{ + int i, nsize = sizeof(led_map)/sizeof(led_map[0]); + + for (i = 0; i < nsize; i++) { + if (id == led_map[i].id && onlp_led_mode == led_map[i].onlp_led_mode) { + return led_map[i].driver_led_mode; + } + } + + return 0; +} + +/* + * This function will be called prior to any other onlp_ledi_* functions. + */ +int +onlp_ledi_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_ledi_info_get(onlp_oid_t id, onlp_led_info_t* info) +{ + int lid, value; + VALIDATE(id); + + lid = ONLP_OID_ID_GET(id); + + /* Set the onlp_oid_hdr_t and capabilities */ + *info = linfo[ONLP_OID_ID_GET(id)]; + + /* Get LED mode */ + if (onlp_file_read_int(&value, LED_FORMAT, leds[lid]) < 0) { + return ONLP_STATUS_E_INTERNAL; + } + + info->mode = driver_to_onlp_led_mode(lid, value); + + /* Set the on/off status */ + if (info->mode != ONLP_LED_MODE_OFF) { + info->status |= ONLP_LED_STATUS_ON; + } + + return ONLP_STATUS_OK; +} + +/* + * Turn an LED on or off. + * + * This function will only be called if the LED OID supports the ONOFF + * capability. + * + * What 'on' means in terms of colors or modes for multimode LEDs is + * up to the platform to decide. This is intended as baseline toggle mechanism. + */ +int +onlp_ledi_set(onlp_oid_t id, int on_or_off) +{ + VALIDATE(id); + + if (!on_or_off) { + return onlp_ledi_mode_set(id, ONLP_LED_MODE_OFF); + } + + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * This function puts the LED into the given mode. It is a more functional + * interface for multimode LEDs. + * + * Only modes reported in the LED's capabilities will be attempted. + */ +int +onlp_ledi_mode_set(onlp_oid_t id, onlp_led_mode_t mode) +{ + int lid; + VALIDATE(id); + + lid = ONLP_OID_ID_GET(id); + + if (onlp_file_write_int(onlp_to_driver_led_mode(lid , mode), LED_FORMAT, leds[lid]) != 0) { + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/make.mk b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/make.mk new file mode 100644 index 0000000000..e2167b05fa --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/make.mk @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### + +LIBRARY := x86_64_accton_as9947_72xkb +$(LIBRARY)_SUBDIR := $(dir $(lastword $(MAKEFILE_LIST))) +include $(BUILDER)/lib.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c new file mode 100644 index 0000000000..9ad7238019 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c @@ -0,0 +1,150 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +char psu_prefix[64]; + +enum onlp_fan_dir onlp_get_fan_dir(int fid) +{ + int len = 0; + int i = 0; + int hwmon_idx; + char *str = NULL; + char *dirs[FAN_DIR_COUNT] = { "F2B", "B2F" }; + char file[32]; + enum onlp_fan_dir dir = FAN_DIR_F2B; + + hwmon_idx = onlp_get_fan_hwmon_idx(); + if (hwmon_idx >= 0) { + /* Read attribute */ + snprintf(file, sizeof(file), "fan%d_dir", fid); + len = onlp_file_read_str(&str, FAN_SYSFS_FORMAT_1, hwmon_idx, file); + + /* Verify Fan dir string length */ + if (!str || len < 3) { + AIM_FREE_IF_PTR(str); + return dir; + } + + for (i = 0; i < AIM_ARRAYSIZE(dirs); i++) { + if (strncmp(str, dirs[i], strlen(dirs[i])) == 0) { + dir = (enum onlp_fan_dir)i; + break; + } + } + + AIM_FREE_IF_PTR(str); + } + + return dir; +} + +int onlp_get_psu_hwmon_idx(int pid) +{ + /* find hwmon index */ + char* file = NULL; + int ret, hwmon_idx, max_hwmon_idx = 20; + + for (hwmon_idx = 0; hwmon_idx <= max_hwmon_idx; hwmon_idx++) { + snprintf(psu_prefix, sizeof(psu_prefix), "/sys/devices/platform/as9947_72xkb_psu.%d/hwmon/hwmon%d/", pid-1, hwmon_idx); + + ret = onlp_file_find(psu_prefix, "name", &file); + AIM_FREE_IF_PTR(file); + + if (ONLP_STATUS_OK == ret) + return hwmon_idx; + } + + return -1; +} + +int onlp_get_fan_hwmon_idx(void) +{ + /* find hwmon index */ + char* file = NULL; + char path[64]; + int ret, hwmon_idx, max_hwmon_idx = 20; + + for (hwmon_idx = 0; hwmon_idx <= max_hwmon_idx; hwmon_idx++) { + snprintf(path, sizeof(path), "/sys/devices/platform/as9947_72xkb_fan/hwmon/hwmon%d/", hwmon_idx); + + ret = onlp_file_find(path, "name", &file); + AIM_FREE_IF_PTR(file); + + if (ONLP_STATUS_OK == ret) + return hwmon_idx; + } + + return -1; +} + +int psu_status_info_get(int id, char *node, int *value) +{ + int ret = ONLP_STATUS_OK; + char path[128] = {0}; + + *value = 0; + + onlp_get_psu_hwmon_idx(id); + + if (PSU1_ID == id) { + sprintf(path, "%s%s%s", psu_prefix, "psu1_", node); + } + else if (PSU2_ID == id) { + sprintf(path, "%s%s%s", psu_prefix, "psu2_", node); + } + + if (onlp_file_read_int(value, path) < 0) { + AIM_LOG_ERROR("Unable to read status from file(%s)\r\n", path); + return ONLP_STATUS_E_INTERNAL; + } + + return ret; +} + +int psu_status_string_get(int id, char *node, char **string) +{ + int ret = ONLP_STATUS_OK, len; + char path[128]; + + if (PSU1_ID == id) { + sprintf(path, "%s%s%s", psu_prefix, "psu1_", node); + } + else if (PSU2_ID == id) { + sprintf(path, "%s%s%s", psu_prefix, "psu2_", node); + } + + len = onlp_file_read_str(string, path); + if (len < 3) + { + AIM_LOG_ERROR("Unable to read status from file(%s)\r\n", path); + return ONLP_STATUS_E_INTERNAL; + } + + return ret; +} diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h new file mode 100644 index 0000000000..87808568f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h @@ -0,0 +1,108 @@ +/************************************************************ + * + * + * 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 "x86_64_accton_as9947_72xkb_log.h" + +#define CHASSIS_FAN_COUNT 16 +#define CHASSIS_THERMAL_COUNT 11 +#define CHASSIS_LED_COUNT 6 +#define CHASSIS_PSU_COUNT 2 +#define NUM_OF_THERMAL_PER_PSU 3 + +#define PSU1_ID 1 +#define PSU2_ID 2 + +#define PSU_STATUS_PRESENT 1 +#define PSU_STATUS_POWER_GOOD 1 + +#define LED_FORMAT "/sys/devices/platform/as9947_72xkb_led/led_%s" +#define PSU_SYSFS_FORMAT "/sys/devices/platform/as9947_72xkb_psu.%d*psu%d_%s" +#define PSU_SYSFS_FORMAT_1 "/sys/devices/platform/as9947_72xkb_psu.%d/hwmon/hwmon%d/%s" +#define FAN_SYSFS_FORMAT "/sys/devices/platform/as9947_72xkb_fan*" +#define FAN_SYSFS_FORMAT_1 "/sys/devices/platform/as9947_72xkb_fan/hwmon/hwmon%d/%s" +#define SYS_LED_PATH "/sys/devices/platform/as9947_72xkb_led/" +#define IDPROM_PATH "/sys/bus/platform/devices/as9947_72xkb_sys/eeprom" + +enum onlp_thermal_id { + THERMAL_RESERVED = 0, + THERMAL_CPU_CORE, + THERMAL_1_ON_MAIN_BROAD, + THERMAL_2_ON_MAIN_BROAD, + THERMAL_3_ON_MAIN_BROAD, + THERMAL_4_ON_MAIN_BROAD, + THERMAL_5_ON_MAIN_BROAD, + THERMAL_6_ON_MAIN_BROAD, + THERMAL_7_ON_MAIN_BROAD, + THERMAL_8_ON_MAIN_BROAD, + THERMAL_1_ON_FAN_BROAD, + THERMAL_2_ON_FAN_BROAD, + THERMAL_1_ON_PSU1, + THERMAL_2_ON_PSU1, + THERMAL_3_ON_PSU1, + THERMAL_1_ON_PSU2, + THERMAL_2_ON_PSU2, + THERMAL_3_ON_PSU2, + THERMAL_COUNT +}; + +enum onlp_led_id { + LED_LOC = 1, + LED_ALARM, + LED_DIAG, + LED_PSU1, + LED_PSU2, + LED_FAN +}; + +enum onlp_fan_dir { + FAN_DIR_F2B, + FAN_DIR_B2F, + FAN_DIR_COUNT +}; + +typedef enum as9947_72xkb_platform_id { + as9947_72xkb, + PID_UNKNOWN +} as9947_72xkb_platform_id_t; + +enum onlp_fan_dir onlp_get_fan_dir(int fid); +int onlp_get_psu_hwmon_idx(int pid); +int onlp_get_fan_hwmon_idx(void); +int psu_status_info_get(int id, char *node, int *value); +int psu_status_string_get(int id, char *node, char **string); + +#define AIM_FREE_IF_PTR(p) \ + do \ + { \ + if (p) { \ + aim_free(p); \ + p = NULL; \ + } \ + } while (0) + +#endif /* __PLATFORM_LIB_H__ */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c new file mode 100644 index 0000000000..6fd51b7d0c --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c @@ -0,0 +1,174 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_PSU(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +int +onlp_psui_init(void) +{ + return ONLP_STATUS_OK; +} + +/* + * Get all information about the given PSU oid. + */ +static onlp_psu_info_t pinfo[] = { + { }, /* Not used */ + { + { ONLP_PSU_ID_CREATE(PSU1_ID), "PSU-1", 0, {0} }, + }, + { + { ONLP_PSU_ID_CREATE(PSU2_ID), "PSU-2", 0, {0} }, + } +}; + +int +onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) +{ + int val = 0; + int ret = ONLP_STATUS_OK; + int pid = ONLP_OID_ID_GET(id); + int thermal_count = 0; + int hwmon_idx; + VALIDATE(id); + + memset(info, 0, sizeof(onlp_psu_info_t)); + *info = pinfo[pid]; /* Set the onlp_oid_hdr_t */ + + /* Get the present state */ + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "present"); + if (ret < 0) { + info->status &= ~ONLP_PSU_STATUS_PRESENT; + return ONLP_STATUS_E_INTERNAL; + } + + if (val != PSU_STATUS_PRESENT) { + info->status &= ~ONLP_PSU_STATUS_PRESENT; + return ONLP_STATUS_OK; + } + info->status |= ONLP_PSU_STATUS_PRESENT; + + /* Get power good status */ + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "power_good"); + if (ret < 0) { + info->status |= ONLP_PSU_STATUS_FAILED; + return ONLP_STATUS_E_INTERNAL; + } + + if (val != PSU_STATUS_POWER_GOOD) { + info->status |= ONLP_PSU_STATUS_UNPLUGGED; + } + + /* Set capability + */ + info->caps = ONLP_PSU_CAPS_AC; + + /* Set the associated oid_table */ + thermal_count = CHASSIS_THERMAL_COUNT; + + info->hdr.coids[0] = ONLP_THERMAL_ID_CREATE(thermal_count + (pid-1)*NUM_OF_THERMAL_PER_PSU + 1); + info->hdr.coids[1] = ONLP_THERMAL_ID_CREATE(thermal_count + (pid-1)*NUM_OF_THERMAL_PER_PSU + 2); + info->hdr.coids[2] = ONLP_THERMAL_ID_CREATE(thermal_count + (pid-1)*NUM_OF_THERMAL_PER_PSU + 3); + info->hdr.coids[3] = ONLP_FAN_ID_CREATE(pid + CHASSIS_FAN_COUNT); + + /* Read voltage, current and power */ + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vin"); + if (ret == ONLP_STATUS_OK && val) { + info->mvin = val; + info->caps |= ONLP_PSU_CAPS_VIN; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iin"); + if (ret == ONLP_STATUS_OK && val) { + info->miin = val; + info->caps |= ONLP_PSU_CAPS_IIN; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pin"); + if (ret == ONLP_STATUS_OK && val) { + info->mpin = val; + info->caps |= ONLP_PSU_CAPS_PIN; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vout"); + if (ret == ONLP_STATUS_OK && val) { + info->mvout = val; + info->caps |= ONLP_PSU_CAPS_VOUT; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iout"); + if (ret == ONLP_STATUS_OK && val) { + info->miout = val; + info->caps |= ONLP_PSU_CAPS_IOUT; + } + + val = 0; + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pout"); + if (ret == ONLP_STATUS_OK && val) { + info->mpout = val; + info->caps |= ONLP_PSU_CAPS_POUT; + } + + hwmon_idx = onlp_get_psu_hwmon_idx(pid); + if (hwmon_idx >= 0) { + char *str = NULL; + int len; + char file[32]; + + /* Read model */ + snprintf(file, sizeof(file), "psu%d_model", pid); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + if (str && len) { + memcpy(info->model, str, len); + info->model[len] = '\0'; + } + AIM_FREE_IF_PTR(str); + + /* Read serial */ + snprintf(file, sizeof(file), "psu%d_serial", pid); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + if (str && len) { + memcpy(info->serial, str, len); + info->serial[len] = '\0'; + } + AIM_FREE_IF_PTR(str); + } + + return ret; +} diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c new file mode 100644 index 0000000000..ccad4d0945 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c @@ -0,0 +1,330 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2013 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include +#include "x86_64_accton_as9947_72xkb_int.h" +#include "x86_64_accton_as9947_72xkb_log.h" + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < 73 || _port > 76) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < 1 || _port > 72 ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define MODULE_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" +#define MODULE_PRESENT_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_present_%d" +#define MODULE_RXLOS_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_rx_los_%d" +#define MODULE_TXFAULT_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_tx_fault_%d" +#define MODULE_TXDISABLE_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_tx_disable_%d" +#define MODULE_RESET_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_reset_%d" +#define MODULE_LPMODE_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_lp_mode_%d" + +#define NUM_OF_PORT 76 +#define NUM_OF_QSFP_PORT 72 +#define NUM_OF_SFP_PORT 4 +static const int port_bus_index[NUM_OF_PORT] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 +}; + +#define PORT_BUS_INDEX(port) (port_bus_index[port-1]) + +/************************************************************ + * + * SFPI Entry Points + * + ***********************************************************/ +int +onlp_sfpi_init(void) +{ + /* Called at initialization time */ + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_bitmap_get(onlp_sfp_bitmap_t* bmap) +{ + int p; + + for(p = 1; p <= NUM_OF_PORT; p++) { + AIM_BITMAP_SET(bmap, p); + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_is_present(int port) +{ + /* + * Return 1 if present. + * Return 0 if not present. + * Return < 0 if error. + */ + + int present; + + if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return present; +} + +int onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) +{ + + int i = 1, value = 0; + + for(i = 1; i <= NUM_OF_QSFP_PORT; i++) + { + AIM_BITMAP_MOD(dst, i, 0); + } + + for (i = 73; i <= NUM_OF_PORT; i++) + + { + /* check present */ + if (onlp_sfpi_is_present(i)) + { + if (onlp_file_read_int(&value, MODULE_RXLOS_FORMAT, i) < 0) { + AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", i); + return ONLP_STATUS_E_INTERNAL; + } + } + + if (value) + AIM_BITMAP_MOD(dst, i, 1); + 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; + memset(data, 0, 256); + + if(onlp_file_read(data, 256, &size, MODULE_EEPROM_FORMAT, PORT_BUS_INDEX(port)) != ONLP_STATUS_OK) { + AIM_LOG_ERROR("Unable to read eeprom from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + if (size != 256) { + AIM_LOG_ERROR("Unable to read eeprom from port(%d), size is different!\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_dom_read(int port, uint8_t data[256]) +{ + FILE* fp; + char file[64] = {0}; + + sprintf(file, MODULE_EEPROM_FORMAT, PORT_BUS_INDEX(port)); + fp = fopen(file, "r"); + if(fp == NULL) { + AIM_LOG_ERROR("Unable to open the eeprom device file of port(%d)", port); + return ONLP_STATUS_E_INTERNAL; + } + + if (fseek(fp, 256, SEEK_CUR) != 0) { + fclose(fp); + AIM_LOG_ERROR("Unable to set the file position indicator of port(%d)", port); + return ONLP_STATUS_E_INTERNAL; + } + + int ret = fread(data, 1, 256, fp); + fclose(fp); + if (ret != 256) { + AIM_LOG_ERROR("Unable to read the module_eeprom device file of port(%d)", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_dev_readb(int port, uint8_t devaddr, uint8_t addr) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_readb(bus, devaddr, addr, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_writeb(int port, uint8_t devaddr, uint8_t addr, uint8_t value) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_writeb(bus, devaddr, addr, value, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_readw(int port, uint8_t devaddr, uint8_t addr) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_readw(bus, devaddr, addr, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) +{ + int bus = PORT_BUS_INDEX(port); + return onlp_i2c_writew(bus, devaddr, addr, value, ONLP_I2C_F_FORCE); +} + +int +onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) +{ + switch(control) { + case ONLP_SFP_CONTROL_TX_DISABLE: { + VALIDATE_SFP(port); + + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to set tx disable status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_RESET_STATE: { + VALIDATE_QSFP(port); + + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_LP_MODE: { + VALIDATE_QSFP(port); + + if (onlp_file_write_int(value, MODULE_LPMODE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to write lp mode status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + default: + break; + } + + return ONLP_STATUS_E_UNSUPPORTED; +} + +int +onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) +{ + switch(control) { + case ONLP_SFP_CONTROL_RX_LOS: { + VALIDATE_SFP(port); + + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read rx loss status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + + case ONLP_SFP_CONTROL_TX_FAULT: { + VALIDATE_SFP(port); + + if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read tx fault status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + + case ONLP_SFP_CONTROL_TX_DISABLE: { + VALIDATE_SFP(port); + + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read tx disabled status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_RESET_STATE: { + VALIDATE_QSFP(port); + + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + case ONLP_SFP_CONTROL_LP_MODE: { + VALIDATE_QSFP(port); + + if (onlp_file_read_int(value, MODULE_LPMODE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read lp mode status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + + return ONLP_STATUS_OK; + } + default: + break; + } + + return ONLP_STATUS_E_UNSUPPORTED; +} + +int +onlp_sfpi_denit(void) +{ + return ONLP_STATUS_OK; +} diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sysi.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sysi.c new file mode 100644 index 0000000000..cfcb0eb0b1 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sysi.c @@ -0,0 +1,194 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include + +#include +#include +#include +#include +#include +#include +#include "platform_lib.h" + +#include "x86_64_accton_as9947_72xkb_int.h" +#include "x86_64_accton_as9947_72xkb_log.h" + + +#define NUM_OF_CPLD_VER 6 +#define BIOS_VER_PATH "/sys/devices/virtual/dmi/id/bios_version" +#define BMC_VER1_PATH "/sys/devices/platform/ipmi_bmc.0/firmware_revision" +#define BMC_VER2_PATH "/sys/devices/platform/ipmi_bmc.0/aux_firmware_revision" + +static char* cpld_ver_path[NUM_OF_CPLD_VER] = { + "/sys/bus/platform/devices/as9947_72xkb_sys/cpu_cpld_ver", + /* Main CPLD */ + "/sys/bus/platform/devices/as9947_72xkb_sys/mb_cpld0_ver", + "/sys/bus/platform/devices/as9947_72xkb_sys/mb_cpld1_ver", + /* Fan CPLD */ + "/sys/bus/platform/devices/as9947_72xkb_sys/fan_cpld1_ver", + "/sys/bus/platform/devices/as9947_72xkb_sys/fan_cpld2_ver", + "/sys/bus/platform/devices/as9947_72xkb_sys/fpga_ver", +}; + +const char* +onlp_sysi_platform_get(void) +{ + return "x86-64-accton-as9947-72xkb-r0"; +} + +int +onlp_sysi_onie_data_get(uint8_t** data, int* size) +{ + uint8_t* rdata = aim_zmalloc(256); + if (onlp_file_read(rdata, 256, size, IDPROM_PATH) == ONLP_STATUS_OK) { + if(*size == 256) { + *data = rdata; + return ONLP_STATUS_OK; + } + } + + aim_free(rdata); + *size = 0; + return ONLP_STATUS_E_INTERNAL; +} + +int +onlp_sysi_oids_get(onlp_oid_t* table, int max) +{ + int i; + onlp_oid_t* e = table; + memset(table, 0, max*sizeof(onlp_oid_t)); + + /* 11 Thermal sensors on the chassis */ + for (i = 1; i <= CHASSIS_THERMAL_COUNT; i++) { + *e++ = ONLP_THERMAL_ID_CREATE(i); + } + + /* 6 LEDs on the chassis */ + for (i = 1; i <= CHASSIS_LED_COUNT; i++) { + *e++ = ONLP_LED_ID_CREATE(i); + } + + /* 2 PSUs on the chassis */ + for (i = 1; i <= CHASSIS_PSU_COUNT; i++) { + *e++ = ONLP_PSU_ID_CREATE(i); + } + + /* 16 Fans on the chassis */ + for (i = 1; i <= CHASSIS_FAN_COUNT; i++) { + *e++ = ONLP_FAN_ID_CREATE(i); + } + + return 0; +} + + +int +onlp_sysi_platform_info_get(onlp_platform_info_t* pi) +{ + int i; + char *v[NUM_OF_CPLD_VER] = {NULL}; + char *bmc_buf = NULL; + char *aux_buf = NULL; + int bmc_major = 0, bmc_minor = 0; + unsigned int bmc_aux[4] = {0}; + char bmc_ver[16] = ""; + onlp_onie_info_t onie; + char *bios_ver = NULL; + + onlp_file_read_str(&bios_ver, BIOS_VER_PATH); + onlp_onie_decode_file(&onie, IDPROM_PATH); + /* BMC version */ + if ((onlp_file_read_str(&bmc_buf, BMC_VER1_PATH) >= 0) && + (onlp_file_read_str(&aux_buf, BMC_VER2_PATH) >= 0)) + { + bmc_buf[strcspn(bmc_buf, "\n")] = '\0'; + aux_buf[strcspn(aux_buf, "\n")] = '\0'; + + /* + * NOTE: The value in /sys/devices/platform/ipmi_bmc.0/firmware_revision is formatted + * using "%u.%x" in the kernel driver (see ipmi_msghandler.c::firmware_revision_show). + * The second field (after the dot) is output in hexadecimal format and must be parsed + * using "%x" from user-space. + */ + if (sscanf(bmc_buf, "%u.%x", &bmc_major, &bmc_minor) == 2 && + sscanf(aux_buf, "0x%x 0x%x 0x%x 0x%x", &bmc_aux[0], &bmc_aux[1], &bmc_aux[2], &bmc_aux[3]) == 4) + { + snprintf(bmc_ver, sizeof(bmc_ver), "%02X.%02X.%02X", + bmc_major, bmc_minor, bmc_aux[3]); + } + } + + for (i = 0; i < AIM_ARRAYSIZE(cpld_ver_path); i++) { + v[i] = 0; + onlp_file_read_str(&v[i], cpld_ver_path[i]); + } + + pi->cpld_versions = aim_fstrdup("\r\n\t CPU CPLD(0x21): %s" + "\r\n\t SMB CPLD(0x62, 0x63): %s" + "\r\n\t Fan CPLD(0x33, 0x34): %s" + , v[0], v[1], v[3]); + + pi->other_versions = aim_fstrdup("\r\n\t FPGA(0x61): %s" + "\r\n\t BIOS: %s" + "\r\n\t ONIE: %s" + "\r\n\t BMC: %s" + ,v[5], bios_ver + , onie.onie_version, bmc_ver); + + + for (i = 0; i < AIM_ARRAYSIZE(v); i++) { + AIM_FREE_IF_PTR(v[i]); + } + + AIM_FREE_IF_PTR(bmc_buf); + AIM_FREE_IF_PTR(aux_buf); + AIM_FREE_IF_PTR(bios_ver); + onlp_onie_info_free(&onie); + + return ONLP_STATUS_OK; +} + +void +onlp_sysi_platform_info_free(onlp_platform_info_t* pi) +{ + aim_free(pi->cpld_versions); + aim_free(pi->other_versions); +} + +int +onlp_sysi_platform_manage_fans(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_sysi_platform_manage_leds(void) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c new file mode 100644 index 0000000000..d57d1ec9ea --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c @@ -0,0 +1,210 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * Copyright 2014 Accton Technology Corporation. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * Thermal Sensor Platform Implementation. + * + ***********************************************************/ +#include +#include +#include "platform_lib.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_THERMAL(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static char* devfiles__[] = { /* must map with onlp_thermal_id */ + NULL, + NULL, /* CPU_CORE files */ + "/sys/devices/platform/as9947_72xkb_thermal*temp1_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp2_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp3_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp4_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp5_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp6_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp7_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp8_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp9_input", + "/sys/devices/platform/as9947_72xkb_thermal*temp10_input", + "/sys/devices/platform/as9947_72xkb_psu.0*psu1_temp1_input", + "/sys/devices/platform/as9947_72xkb_psu.0*psu1_temp2_input", + "/sys/devices/platform/as9947_72xkb_psu.0*psu1_temp3_input", + "/sys/devices/platform/as9947_72xkb_psu.1*psu2_temp1_input", + "/sys/devices/platform/as9947_72xkb_psu.1*psu2_temp2_input", + "/sys/devices/platform/as9947_72xkb_psu.1*psu2_temp3_input" +}; + +static char* cpu_coretemp_files[] = { + "/sys/devices/platform/coretemp.0*temp1_input", + "/sys/devices/platform/coretemp.0*temp2_input", + "/sys/devices/platform/coretemp.0*temp3_input", + "/sys/devices/platform/coretemp.0*temp4_input", + "/sys/devices/platform/coretemp.0*temp5_input", + "/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 tinfo[] = { + { }, /* Not used */ + { { ONLP_THERMAL_ID_CREATE(THERMAL_CPU_CORE), "CPU Core", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_MAIN_BROAD), "MB_RearRight_temp(0x4F)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_MAIN_BROAD), "MB_RearLeft_temp(0x4E)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_MAIN_BROAD), "MB_FrontRight_temp(0x4A)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_4_ON_MAIN_BROAD), "MB_FrontLeft_temp(0x4B)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_5_ON_MAIN_BROAD), "MZB_CenterLeft_temp(0x48)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_6_ON_MAIN_BROAD), "MZB_FrontLeft_temp(0x49)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_7_ON_MAIN_BROAD), "MB_CenterLeft_temp(0x4C)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_FAN_BROAD), "MB_CenterRight_temp(0x4D)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_FAN_BROAD), "FCB_Up_temp(0x4D)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_FAN_BROAD), "FCB_Down_temp(0x4E)", 0, {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_PSU1), "PSU-1 Thermal Sensor 1", ONLP_PSU_ID_CREATE(PSU1_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_PSU1), "PSU-1 Thermal Sensor 2", ONLP_PSU_ID_CREATE(PSU1_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_PSU1), "PSU-1 Thermal Sensor 3", ONLP_PSU_ID_CREATE(PSU1_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_1_ON_PSU2), "PSU-2 Thermal Sensor 1", ONLP_PSU_ID_CREATE(PSU2_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_2_ON_PSU2), "PSU-2 Thermal Sensor 2", ONLP_PSU_ID_CREATE(PSU2_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + }, + { { ONLP_THERMAL_ID_CREATE(THERMAL_3_ON_PSU2), "PSU-2 Thermal Sensor 3", ONLP_PSU_ID_CREATE(PSU2_ID), {0} }, + ONLP_THERMAL_STATUS_PRESENT, + ONLP_THERMAL_CAPS_ALL, 0, ONLP_THERMAL_THRESHOLD_INIT_DEFAULTS + } +}; + +/* + * This will be called to intiialize the thermali subsystem. + */ +int +onlp_thermali_init(void) +{ + return ONLP_STATUS_OK; +} + +/* + * Retrieve the information structure for the given thermal OID. + * + * If the OID is invalid, return ONLP_E_STATUS_INVALID. + * If an unexpected error occurs, return ONLP_E_STATUS_INTERNAL. + * Otherwise, return ONLP_STATUS_OK with the OID's information. + * + * Note -- it is expected that you fill out the information + * structure even if the sensor described by the OID is not present. + */ +int +onlp_thermali_info_get(onlp_oid_t id, onlp_thermal_info_t* info) +{ + int tid; + int pid, val, ret; + VALIDATE(id); + + tid = ONLP_OID_ID_GET(id); + *info = tinfo[tid]; + + if (tid == THERMAL_CPU_CORE) { + return onlp_file_read_int_max(&info->mcelsius, cpu_coretemp_files); + } + + switch(tid){ + case THERMAL_1_ON_PSU1: + case THERMAL_2_ON_PSU1: + case THERMAL_3_ON_PSU1: + case THERMAL_1_ON_PSU2: + case THERMAL_2_ON_PSU2: + case THERMAL_3_ON_PSU2: + if((tid >= THERMAL_1_ON_PSU1) && (tid <=THERMAL_3_ON_PSU1)) + pid = 1; + else + pid = 2; + /* Get PSU power good status */ + ret = psu_status_info_get(pid, "power_good", &val); + if (ret < 0) + { + AIM_LOG_ERROR("Unable to read PSU(%d) node(power_good)\r\n", pid); + } + + if (val != PSU_STATUS_POWER_GOOD) { + info->status |= ONLP_THERMAL_STATUS_FAILED; + info->mcelsius = 0; + return ONLP_STATUS_OK; + } + else + { + return onlp_file_read_int(&info->mcelsius, devfiles__[tid]); + } + break; + default: + break; + } + + return onlp_file_read_int(&info->mcelsius, devfiles__[tid]); +} diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_config.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_config.c new file mode 100644 index 0000000000..c6c9a6710d --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_config.c @@ -0,0 +1,81 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* */ +#define __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(_x) #_x +#define __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(_x) __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(_x) +x86_64_accton_as9947_72xkb_config_settings_t x86_64_accton_as9947_72xkb_config_settings[] = +{ +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_LOGGING(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_STDLIB(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_UCLI(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION + { __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME(X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION), __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE(X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION) }, +#else +{ X86_64_ACCTON_AS9947_72XKB_CONFIG_INCLUDE_DEFAULT_FAN_DIRECTION(__x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME), "__undefined__" }, +#endif + { NULL, NULL } +}; +#undef __x86_64_accton_as9947_72xkb_config_STRINGIFY_VALUE +#undef __x86_64_accton_as9947_72xkb_config_STRINGIFY_NAME + +const char* +x86_64_accton_as9947_72xkb_config_lookup(const char* setting) +{ + int i; + for(i = 0; x86_64_accton_as9947_72xkb_config_settings[i].name; i++) { + if(!strcmp(x86_64_accton_as9947_72xkb_config_settings[i].name, setting)) { + return x86_64_accton_as9947_72xkb_config_settings[i].value; + } + } + return NULL; +} + +int +x86_64_accton_as9947_72xkb_config_show(struct aim_pvs_s* pvs) +{ + int i; + for(i = 0; x86_64_accton_as9947_72xkb_config_settings[i].name; i++) { + aim_printf(pvs, "%s = %s\n", x86_64_accton_as9947_72xkb_config_settings[i].name, x86_64_accton_as9947_72xkb_config_settings[i].value); + } + return i; +} + +/* */ + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_enums.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_enums.c new file mode 100644 index 0000000000..b42f3f213d --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_enums.c @@ -0,0 +1,10 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.enum(ALL).source> */ +/* */ + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_int.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_int.h new file mode 100644 index 0000000000..033851256b --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_int.h @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * x86_64_accton_as9947_72xkb Internal Header + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9947_72xkb_INT_H__ +#define __x86_64_accton_as9947_72xkb_INT_H__ + +#include + + +#endif /* __x86_64_accton_as9947_72xkb_INT_H__ */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.c new file mode 100644 index 0000000000..e3d46a9bed --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.c @@ -0,0 +1,17 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_accton_as9947_72xkb_log.h" +/* + * x86_64_accton_as9947_72xkb log struct. + */ +AIM_LOG_STRUCT_DEFINE( + X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_OPTIONS_DEFAULT, + X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_BITS_DEFAULT, + NULL, /* Custom log map */ + X86_64_ACCTON_AS9947_72XKB_CONFIG_LOG_CUSTOM_BITS_DEFAULT + ); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.h new file mode 100644 index 0000000000..a03de43357 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_log.h @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#ifndef __x86_64_accton_as9947_72xkb_LOG_H__ +#define __x86_64_accton_as9947_72xkb_LOG_H__ + +#define AIM_LOG_MODULE_NAME x86_64_accton_as9947_72xkb +#include + +#endif /* __x86_64_accton_as9947_72d_LOG_H__ */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_module.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_module.c new file mode 100644 index 0000000000..d70ce54923 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_module.c @@ -0,0 +1,24 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_accton_as9947_72xkb_log.h" + +static int +datatypes_init__(void) +{ +#define x86_64_accton_as9947_72xkb_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_as9947_72xkb_module_init__(void) +{ + AIM_LOG_STRUCT_REGISTER(); + datatypes_init__(); +} + +int __onlp_platform_version__ = 1; diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_ucli.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_ucli.c new file mode 100644 index 0000000000..ae3b1d2f6d --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/x86_64_accton_as9947_72xkb_ucli.c @@ -0,0 +1,50 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#if x86_64_accton_as9947_72xkb_CONFIG_INCLUDE_UCLI == 1 + +#include +#include +#include + +static ucli_status_t +x86_64_accton_as9947_72xkb_ucli_ucli__config__(ucli_context_t* uc) +{ + UCLI_HANDLER_MACRO_MODULE_CONFIG(x86_64_accton_as9947_72xkb) +} + +/* */ +/* */ + +static ucli_module_t +x86_64_accton_as9947_72xkb_ucli_module__ = + { + "x86_64_accton_as9947_72xkb_ucli", + NULL, + x86_64_accton_as9947_72xkb_ucli_ucli_handlers__, + NULL, + NULL, + }; + +ucli_node_t* +x86_64_accton_as9947_72xkb_ucli_node_create(void) +{ + ucli_node_t* n; + ucli_module_init(&x86_64_accton_as9947_72xkb_ucli_module__); + n = ucli_node_create("x86_64_accton_as9947_72xkb", NULL, &x86_64_accton_as9947_72xkb_ucli_module__); + ucli_node_subnode_add(n, ucli_module_log_node_create("x86_64_accton_as9947_72xkb")); + return n; +} + +#else +void* +x86_64_accton_as9947_72xkb_ucli_node_create(void) +{ + return NULL; +} +#endif + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/Makefile new file mode 100644 index 0000000000..dc1e7b86f0 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/PKG.yml b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/PKG.yml new file mode 100644 index 0000000000..18018bf999 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-config-platform.yml ARCH=amd64 VENDOR=accton BASENAME=x86-64-accton-as9947-72xkb REVISION=r0 diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/lib/x86-64-accton-as9947-72xkb-r0.yml b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/lib/x86-64-accton-as9947-72xkb-r0.yml new file mode 100644 index 0000000000..efd6efd926 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/lib/x86-64-accton-as9947-72xkb-r0.yml @@ -0,0 +1,34 @@ +--- + +###################################################################### +# +# platform-config for AS9947 +# +###################################################################### + +x86-64-accton-as9947-72xkb-r0: + + grub: + + serial: >- + --port=0x3f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-5-4 + + args: >- + nopat + console=ttyS0,115200n8 + intel_iommu=off + pcie_aspm=off + intremap=off + + ##network + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py new file mode 100644 index 0000000000..6a92f5d3a5 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py @@ -0,0 +1,102 @@ +import commands +from itertools import chain +from onl.platform.base import * +from onl.platform.accton import * +from time import sleep + + +init_ipmi_dev = [ + 'echo "remove,kcs,i/o,0xca2" > /sys/module/ipmi_si/parameters/hotmod', + 'echo "add,kcs,i/o,0xca2" > /sys/module/ipmi_si/parameters/hotmod'] + +ATTEMPTS = 5 +INTERVAL = 3 + +def init_ipmi_dev_intf(): + attempts = ATTEMPTS + interval = INTERVAL + + while attempts: + if os.path.exists('/dev/ipmi0') or os.path.exists('/dev/ipmidev/0'): + return (True, (ATTEMPTS - attempts) * interval) + + for i in range(0, len(init_ipmi_dev)): + commands.getstatusoutput(init_ipmi_dev[i]) + + attempts -= 1 + sleep(interval) + + return (False, ATTEMPTS * interval) + +def init_ipmi_oem_cmd(): + attempts = ATTEMPTS + interval = INTERVAL + + while attempts: + status, output = commands.getstatusoutput('ipmitool raw 0x34 0x95') + if status: + attempts -= 1 + sleep(interval) + continue + + return (True, (ATTEMPTS - attempts) * interval) + + return (False, ATTEMPTS * interval) + +def init_ipmi(): + attempts = ATTEMPTS + interval = 60 + + while attempts: + attempts -= 1 + + (status, elapsed_dev) = init_ipmi_dev_intf() + if status is not True: + sleep(interval - elapsed_dev) + continue + + (status, elapsed_oem) = init_ipmi_oem_cmd() + if status is not True: + sleep(interval - elapsed_dev - elapsed_oem) + continue + + print('IPMI dev interface is ready.') + return True + + print('Failed to initialize IPMI dev interface') + return False + +class OnlPlatform_x86_64_accton_as9947_72xkb_r0(OnlPlatformAccton, + OnlPlatformPortConfig_24x400_2x10): + PLATFORM='x86-64-accton-as9947-72xkb-r0' + MODEL="AS9947-72XKB" + SYS_OBJECT_ID=".9947.72" + + def modprobe(self, module, required=True, params={}): + cmd = "modprobe %s" % module + subprocess.check_call(cmd, shell=True) + + def baseconfig(self): + if init_ipmi() is not True: + return False + + self.modprobe('optoe') + + for m in [ 'i2c-ocores', 'fpga', 'fan', 'psu', 'thermal', 'sys', 'leds']: + self.insmod("x86-64-accton-as9947-72xkb-%s" % m) + + # QSFP + for port in range(1, 49): + self.new_i2c_device('optoe1', 0x50, port) + # QSFP-DD + for port in range(49, 73): + self.new_i2c_device('optoe3', 0x50, port) + # SFP + for port in range(73,77): + self.new_i2c_device('optoe2', 0x50, port) + + + for port in range(1, 77): + subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port, port), shell=True) + + return True From 76415c7d33e496b97a9fda605687d795bab48b17 Mon Sep 17 00:00:00 2001 From: Willy Liu Date: Mon, 25 Aug 2025 10:04:37 +0000 Subject: [PATCH 2/5] [ACCTON][AS9947-72XKB] Modularize IPMI-Related functions 1. Add ipmi interface common code 2. Remove the ipmi codebase from each device driver 3. Remove ipmi PSU device index 4. Fix the each device functions because there is no PSU index 5. Fix functions of psu status and string accessing 6. Fix function of psu hwmon index accessing Signed-off-by: Willy Liu --- .../as9947-72xkb/modules/builds/src/Makefile | 1 + .../modules/builds/src/accton_ipmi_intf.c | 232 +++++++++++++++++ .../modules/builds/src/accton_ipmi_intf.h | 72 ++++++ .../src/x86-64-accton-as9947-72xkb-fan.c | 175 +------------ .../src/x86-64-accton-as9947-72xkb-leds.c | 169 +------------ .../src/x86-64-accton-as9947-72xkb-psu.c | 233 +++--------------- .../src/x86-64-accton-as9947-72xkb-sys.c | 172 +------------ .../src/x86-64-accton-as9947-72xkb-thermal.c | 175 +------------ .../module/src/fani.c | 1 - .../module/src/platform_lib.c | 56 ++--- .../module/src/platform_lib.h | 8 +- .../module/src/psui.c | 20 +- .../module/src/thermali.c | 12 +- .../x86_64_accton_as9947_72xkb_r0/__init__.py | 1 + 14 files changed, 388 insertions(+), 939 deletions(-) create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.h diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile index da498dc772..820a8c64d5 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile @@ -1,3 +1,4 @@ +obj-m += accton_ipmi_intf.o obj-m += x86-64-accton-as9947-72xkb-i2c-ocores.o obj-m += x86-64-accton-as9947-72xkb-fpga.o obj-m += x86-64-accton-as9947-72xkb-fan.o diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c new file mode 100644 index 0000000000..0bf88f6461 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright 2024 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Description: + * IPMI driver related interface implementation + */ +#include +#include +#include +#include "accton_ipmi_intf.h" + +#define ACCTON_IPMI_NETFN 0x34 +#define IPMI_TIMEOUT (5 * HZ) +#define IPMI_ERR_RETRY_TIMES 1 +#define RAW_CMD_BUF_SIZE 32 + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); + +/* Functions to talk to the IPMI layer */ + +/* Initialize IPMI data structure and create a user interface for communication */ +int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev) +{ + int err; + + if (!ipmi || !dev) + return -EINVAL; + + init_completion(&ipmi->read_complete); + + // Initialize IPMI address + ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi->address.channel = IPMI_BMC_CHANNEL; + ipmi->address.data[0] = 0; + ipmi->interface = iface; + ipmi->dev = dev; // Storing the device for future reference + + // Initialize message buffers + ipmi->tx_msgid = 0; + ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; + + // Assign the message handler + ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; + + // Create IPMI messaging interface user + err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, + ipmi, &ipmi->user); + if (err < 0) { + dev_err(dev, + "Unable to register user with IPMI interface %d, err: %d\n", + ipmi->interface, err); + return err; + } + + return 0; +} +EXPORT_SYMBOL(init_ipmi_data); + +/* Handler function for receiving IPMI messages */ +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + unsigned short rx_len; + struct ipmi_data *ipmi = user_msg_data; + + // Check for message ID mismatch + if (msg->msgid != ipmi->tx_msgid) { + dev_err(ipmi->dev, "Mismatch between received msgid " + "(%02x) and transmitted msgid (%02x)!\n", + (int)msg->msgid, (int)ipmi->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + // Handle received message type + ipmi->rx_recv_type = msg->recv_type; + + // Parse message data + if (msg->msg.data_len > 0) + ipmi->rx_result = msg->msg.data[0]; + else + ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + // Copy remaining message data if available + if (msg->msg.data_len > 1) { + rx_len = msg->msg.data_len - 1; + if (ipmi->rx_msg_len < rx_len) + rx_len = ipmi->rx_msg_len; + + ipmi->rx_msg_len = rx_len; + memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len); + } else { + ipmi->rx_msg_len = 0; + } + + // Free the received message and signal completion + ipmi_free_recv_msg(msg); + complete(&ipmi->read_complete); +} + +static void _ipmi_log_error(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + int status, int retry) +{ + int i, pos; + char *cmdline = NULL; + char raw_cmd[RAW_CMD_BUF_SIZE] = { 0 }; + + // Format the command and data into a raw command string + pos = snprintf(raw_cmd, sizeof(raw_cmd), "0x%02x", cmd); + for (i = 0; i < tx_len && pos < sizeof(raw_cmd); i++) { + pos += snprintf(raw_cmd + pos, sizeof(raw_cmd) - pos, + " 0x%02x", tx_data[i]); + } + + // Log the error message + cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); + dev_err(ipmi->dev, + "ipmi_send_message: retry(%d), error(%d), cmd(%s) raw_cmd=[%s]\r\n", + retry, status, cmdline ? cmdline : "", raw_cmd); + + if (cmdline) { + kfree(cmdline); + } +} + +/* Send an IPMI command */ +static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int err; + + // Validate the input parameters + if ((tx_len && !tx_data) || (rx_len && !rx_data)) { + return -EINVAL; + } + + // Initialize IPMI message + ipmi->tx_message.cmd = cmd; + ipmi->tx_message.data = tx_len ? tx_data : NULL; + ipmi->tx_message.data_len = tx_len; + ipmi->rx_msg_data = rx_len ? rx_data : NULL; + ipmi->rx_msg_len = rx_len; + + // Validate the IPMI address + err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); + if (err) { + dev_err(ipmi->dev, "Invalid IPMI address: %x\n", err); + return err; + } + + // Increment message ID and send the request + ipmi->tx_msgid++; + err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, + &ipmi->tx_message, ipmi, 0, 0, 0); + if (err) { + dev_err(ipmi->dev, "IPMI request_settime failed: %x\n", err); + return err; + } + + // Wait for the message to complete + err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); + if (!err) { + dev_err(ipmi->dev, "IPMI command timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +/* Send an IPMI command to the IPMI device and receive the response */ +int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len) +{ + int status = 0, retry = 0; + + // Validate the input parameters + if ((tx_len && !tx_data) || (rx_len && !rx_data)) { + return -EINVAL; + } + + for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { + status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); + if (unlikely(status != 0)) { + _ipmi_log_error(ipmi, cmd, tx_data, tx_len, status, retry); + continue; + } + + if (unlikely(ipmi->rx_result != 0)) { + _ipmi_log_error(ipmi, cmd, tx_data, tx_len, status, retry); + continue; + } + + // Success, exit the retry loop + break; + } + + return status; +} + +EXPORT_SYMBOL(ipmi_send_message); + +static int __init ipmi_module_init(void) +{ + printk(KERN_INFO "Accton IPMI Module loaded\n"); + return 0; +} + +static void __exit ipmi_module_exit(void) +{ + printk(KERN_INFO "Accton IPMI Module unloaded\n"); +} + +module_init(ipmi_module_init); +module_exit(ipmi_module_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton IPMI messaging module"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.h b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.h new file mode 100644 index 0000000000..4b2fe59f93 --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.h @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/* + * Copyright 2024 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Description: + * IPMI driver related interface declarations + */ + +#ifndef ACCTON_IPMI_INTF_H +#define ACCTON_IPMI_INTF_H + +#include +#include + +/* Structure to hold IPMI (Intelligent Platform Management Interface) data */ +struct ipmi_data { + struct completion read_complete; // Synchronization primitive for signaling message read completion + struct ipmi_addr address; // Structure to store the IPMI system interface address + struct ipmi_user *user; // Pointer to IPMI user created by the kernel + int interface; // Interface identifier for the IPMI system + + struct kernel_ipmi_msg tx_message; // Message structure for sending IPMI commands + long tx_msgid; // Message ID for tracking IPMI message transactions + + void *rx_msg_data; // Pointer to buffer for storing received IPMI message data + unsigned short rx_msg_len; // Length of the received IPMI message + unsigned char rx_result; // Result code from the received IPMI message + int rx_recv_type; // Type of the received message (e.g., system interface, LAN, etc.) + + struct ipmi_user_hndl ipmi_hndlrs; // IPMI handler structure for handling incoming IPMI messages + struct device *dev; // Device structure for logging errors +}; + +/* Function declarations */ + +/* + * Initialize IPMI data structure and create a user interface for communication. + * + * @param ipmi: Pointer to ipmi_data structure to be initialized. + * @param iface: IPMI interface identifier. + * @param dev: Device structure for logging errors. + * @return 0 on success, or an error code on failure. + */ +extern int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev); + +/* + * Send an IPMI command to the IPMI device and receive the response. + * + * @param ipmi: Pointer to ipmi_data structure containing IPMI communication information. + * @param cmd: IPMI command byte. + * @param tx_data: Pointer to data buffer for the command payload. + * @param tx_len: Length of the command payload data. + * @param rx_data: Pointer to buffer for storing the response data. + * @param rx_len: Length of the response data buffer. + * @return 0 on success, or an error code on failure. + */ +extern int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, + unsigned char *tx_data, unsigned short tx_len, + unsigned char *rx_data, unsigned short rx_len); + +#endif /* ACCTON_IPMI_INTF_H */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c index d6e3929396..8b5bde161e 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fan.c @@ -29,25 +29,20 @@ #include #include #include -#include -#include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9947_72xkb_fan" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_FAN_READ_CMD 0x14 #define IPMI_FAN_WRITE_CMD 0x15 #define IPMI_FAN_READ_MODEL_CMD 0x10 #define IPMI_FAN_READ_SERIAL_CMD 0x11 -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 #define IPMI_FAN_REG_READ_CMD 0x20 #define MAX_FAN_SPEED_RPM 33000 #define IPMI_FAN_MODEL_SIZE 15 #define IPMI_FAN_SERIAL_SIZE 13 -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, @@ -90,24 +85,6 @@ enum fan_data_index { FAN_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 as9947_72xkb_fan_data { struct platform_device *pdev; struct device *hwmon_dev; @@ -246,156 +223,6 @@ static struct attribute *as9947_72xkb_fan_attrs[] = { }; ATTRIBUTE_GROUPS(as9947_72xkb_fan); -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - int i = 0; - char raw_cmd[20] = ""; - - sprintf(raw_cmd, "0x%02x", cmd); - - if(tx_len) { - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi,cmd, tx_data, tx_len, rx_data, rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - 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 as9947_72xkb_fan_data *as9947_72xkb_fan_update_device(void) { int status = 0; diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c index 41def2767c..4399b45874 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-leds.c @@ -27,19 +27,14 @@ #include #include #include -#include -#include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9947_72xkb_led" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_LED_READ_CMD 0x1A #define IPMI_LED_WRITE_CMD 0x1B -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t set_led(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t show_led(struct device *dev, struct device_attribute *attr, @@ -47,23 +42,6 @@ static ssize_t show_led(struct device *dev, struct device_attribute *attr, static int as9947_72xkb_led_probe(struct platform_device *pdev); static int as9947_72xkb_led_remove(struct platform_device *pdev); -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user *user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct as9947_72xkb_led_data { struct platform_device *pdev; struct mutex update_lock; @@ -157,151 +135,6 @@ static const struct attribute_group as9947_72xkb_led_group = { .attrs = as9947_72xkb_led_attributes, }; -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - int i = 0; - char raw_cmd[20] = ""; - - sprintf(raw_cmd, "0x%02x", cmd); - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - 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 as9947_72xkb_led_data *as9947_72xkb_led_update_device(void) { int status = 0; diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c index 945a680d78..69d4199896 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-psu.c @@ -27,24 +27,19 @@ #include #include #include -#include -#include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9947_72xkb_psu" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_PSU_READ_CMD 0x16 #define IPMI_PSU_MODEL_NAME_CMD 0x10 #define IPMI_PSU_SERIAL_NUM_CMD 0x11 #define IPMI_PSU_FAN_DIR_CMD 0x13 #define IPMI_PSU_INFO_CMD 0x20 -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 #define IPMI_MODEL_SERIAL_LEN 32 #define IPMI_FAN_DIR_LEN 3 -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t show_psu(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t show_psu_info(struct device *dev, struct device_attribute *attr, @@ -147,23 +142,6 @@ enum psu_data_index { PSU_INFO_COUNT }; -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user * user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct ipmi_psu_resp_data { unsigned char status[PSU_STATUS_COUNT]; unsigned char info[PSU_INFO_COUNT]; @@ -173,7 +151,7 @@ struct ipmi_psu_resp_data { }; struct as9947_72xkb_psu_data { - struct platform_device *pdev[2]; + struct platform_device *pdev; struct device *hwmon_dev[2]; struct mutex update_lock; char valid[2]; /* != 0 if registers are valid, 0: PSU1, 1: PSU2 */ @@ -416,152 +394,6 @@ const struct attribute_group *as9947_72xkb_psu_groups[][2] = { {&as9947_72xkb_psu2_group, NULL} }; -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface) -{ - 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) { - pr_err("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; - pr_err("request_timeout=%x\n", err); - return err; -ipmi_req_err: - pr_err("request_settime=%x\n", err); - return err; -addr_err: - pr_err("validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - int i = 0; - char raw_cmd[20] = ""; - - sprintf(raw_cmd, "0x%02x", cmd); - - if(tx_len){ - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); - if (unlikely(status != 0)) { - pr_err("ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - pr_err("ipmi_send_message_%d err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - 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) { - pr_err("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 as9947_72xkb_psu_data *as9947_72xkb_psu_update_device(struct device_attribute *da) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); @@ -977,31 +809,38 @@ static int as9947_72xkb_psu_probe(struct platform_device *pdev) { int status = 0; struct device *hwmon_dev = NULL; + int i = 0; - hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, - NULL, NULL, as9947_72xkb_psu_groups[pdev->id]); - if (IS_ERR(hwmon_dev)) { - status = PTR_ERR(hwmon_dev); - return status; - } + for (i = 0; i < 2; i++) { + hwmon_dev = hwmon_device_register_with_info(&pdev->dev, DRVNAME, + NULL, NULL, as9947_72xkb_psu_groups[i]); + if (IS_ERR(hwmon_dev)) { + status = PTR_ERR(hwmon_dev); + return status; + } - mutex_lock(&data->update_lock); - data->hwmon_dev[pdev->id] = hwmon_dev; - mutex_unlock(&data->update_lock); + mutex_lock(&data->update_lock); + data->hwmon_dev[i] = hwmon_dev; + mutex_unlock(&data->update_lock); - dev_info(&pdev->dev, "PSU%d device created\n", pdev->id + 1); + dev_info(&pdev->dev, "PSU%d device created\n", i + 1); + } return 0; } static int as9947_72xkb_psu_remove(struct platform_device *pdev) { - mutex_lock(&data->update_lock); - if (data->hwmon_dev[pdev->id]) { - hwmon_device_unregister(data->hwmon_dev[pdev->id]); - data->hwmon_dev[pdev->id] = NULL; + int i = 0; + + for(i = 0; i < 2; i++) { + mutex_lock(&data->update_lock); + if (data->hwmon_dev[i]) { + hwmon_device_unregister(data->hwmon_dev[i]); + data->hwmon_dev[i] = NULL; + } + mutex_unlock(&data->update_lock); } - mutex_unlock(&data->update_lock); return 0; } @@ -1009,7 +848,6 @@ static int as9947_72xkb_psu_remove(struct platform_device *pdev) static int __init as9947_72xkb_psu_init(void) { int ret; - int i; data = kzalloc(sizeof(struct as9947_72xkb_psu_data), GFP_KERNEL); if (!data) { @@ -1023,16 +861,14 @@ static int __init as9947_72xkb_psu_init(void) if (ret < 0) goto dri_reg_err; - for (i = 0; i < NUM_OF_PSU; i++) { - data->pdev[i] = platform_device_register_simple(DRVNAME, i, NULL, 0); - if (IS_ERR(data->pdev[i])) { - ret = PTR_ERR(data->pdev[i]); - goto dev_reg_err; - } + 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); + ret = init_ipmi_data(&data->ipmi, 0, &data->pdev->dev); if (ret) { goto ipmi_err; } @@ -1040,10 +876,7 @@ static int __init as9947_72xkb_psu_init(void) return 0; ipmi_err: - while (i > 0) { - i--; - platform_device_unregister(data->pdev[i]); - } + platform_device_unregister(data->pdev); dev_reg_err: platform_driver_unregister(&as9947_72xkb_psu_driver); dri_reg_err: @@ -1054,12 +887,8 @@ static int __init as9947_72xkb_psu_init(void) static void __exit as9947_72xkb_psu_exit(void) { - int i; - ipmi_destroy_user(data->ipmi.user); - for (i = 0; i < NUM_OF_PSU; i++) { - platform_device_unregister(data->pdev[i]); - } + platform_device_unregister(data->pdev); platform_driver_unregister(&as9947_72xkb_psu_driver); kfree(data); } diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c index 272ed3583d..10a7b8dd8f 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sys.c @@ -27,17 +27,12 @@ #include #include #include -#include -#include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9947_72xkb_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" @@ -53,24 +48,7 @@ static int as9947_72xkb_sys_probe(struct platform_device *pdev); static int as9947_72xkb_sys_remove(struct platform_device *pdev); -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t show_cpld_version(struct device *dev, struct device_attribute *da, char *buf); -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 as9947_72xkb_sys_data { struct platform_device *pdev; @@ -125,154 +103,6 @@ static const struct attribute_group as9947_72xkb_sys_group = { .attrs = as9947_72xkb_sys_attributes, }; -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - int i = 0; - char raw_cmd[20] = ""; - - sprintf(raw_cmd, "0x%02x", cmd); - - if(tx_len) { - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err status(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi_send_message_%d err rx_result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - retry, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - 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; diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c index 8a9dfe0a6c..5ee2f87bbc 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-thermal.c @@ -28,22 +28,16 @@ #include #include #include -#include -#include #include #include +#include "accton_ipmi_intf.h" #define DRVNAME "as9947_72xkb_thermal" -#define ACCTON_IPMI_NETFN 0x34 #define IPMI_THERMAL_READ_CMD 0x12 #define THERMAL_COUNT 10 #define THERMAL_DATA_LEN 3 #define THERMAL_DATA_COUNT (THERMAL_COUNT * THERMAL_DATA_LEN) -#define IPMI_TIMEOUT (5 * HZ) -#define IPMI_ERR_RETRY_TIMES 1 - -static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf); static int as9947_72xkb_thermal_probe(struct platform_device *pdev); @@ -56,23 +50,6 @@ enum temp_data_index { TEMP_DATA_COUNT }; -struct ipmi_data { - struct completion read_complete; - struct ipmi_addr address; - struct ipmi_user * user; - int interface; - - struct kernel_ipmi_msg tx_message; - long tx_msgid; - - void *rx_msg_data; - unsigned short rx_msg_len; - unsigned char rx_result; - int rx_recv_type; - - struct ipmi_user_hndl ipmi_hndlrs; -}; - struct as9947_72xkb_thermal_data { struct platform_device *pdev; struct device *hwmon_dev; @@ -141,156 +118,6 @@ static struct attribute *as9947_72xkb_thermal_attrs[] = { }; ATTRIBUTE_GROUPS(as9947_72xkb_thermal); -/* Functions to talk to the IPMI layer */ - -/* Initialize IPMI address, message buffers and user data */ -static int init_ipmi_data(struct ipmi_data *ipmi, int iface, - struct device *dev) -{ - int err; - - init_completion(&ipmi->read_complete); - - /* Initialize IPMI address */ - ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - ipmi->address.channel = IPMI_BMC_CHANNEL; - ipmi->address.data[0] = 0; - ipmi->interface = iface; - - /* Initialize message buffers */ - ipmi->tx_msgid = 0; - ipmi->tx_message.netfn = ACCTON_IPMI_NETFN; - - ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler; - - /* Create IPMI messaging interface user */ - err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs, - ipmi, &ipmi->user); - if (err < 0) { - dev_err(dev, "Unable to register user with IPMI " - "interface %d\n", ipmi->interface); - return -EACCES; - } - - return 0; -} - -/* Send an IPMI command */ -static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int err; - - ipmi->tx_message.cmd = cmd; - ipmi->tx_message.data = tx_data; - ipmi->tx_message.data_len = tx_len; - ipmi->rx_msg_data = rx_data; - ipmi->rx_msg_len = rx_len; - - err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address)); - if (err) - goto addr_err; - - ipmi->tx_msgid++; - err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid, - &ipmi->tx_message, ipmi, 0, 0, 0); - if (err) - goto ipmi_req_err; - - err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT); - if (!err) - goto ipmi_timeout_err; - - return 0; - -ipmi_timeout_err: - err = -ETIMEDOUT; - dev_err(&data->pdev->dev, "request_timeout=%x\n", err); - return err; -ipmi_req_err: - dev_err(&data->pdev->dev, "request_settime=%x\n", err); - return err; -addr_err: - dev_err(&data->pdev->dev, "validate_addr=%x\n", err); - return err; -} - -/* Send an IPMI command with retry */ -static int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd, - unsigned char *tx_data, unsigned short tx_len, - unsigned char *rx_data, unsigned short rx_len) -{ - int status = 0, retry = 0; - char *cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL); - int i = 0; - char raw_cmd[20] = ""; - - sprintf(raw_cmd, "0x%02x", cmd); - - if(tx_len) { - for(i = 0; i < tx_len; i++) - sprintf(raw_cmd + strlen(raw_cmd), " 0x%02x", tx_data[i]); - } - - for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) { - status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len); - if (unlikely(status != 0)) { - dev_err(&data->pdev->dev, - "ipmi cmd(%x) err status(%d)[%s] raw_cmd=[%s]\r\n tx_msgid=(%02x)", - cmd, status, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - if (unlikely(ipmi->rx_result != 0)) { - dev_err(&data->pdev->dev, - "ipmi cmd(%x) err result(%d)[%s] raw_cmd=[%s] tx_msgid=(%02x)\r\n", - cmd, ipmi->rx_result, cmdline ? cmdline : "", raw_cmd, - (int)ipmi->tx_msgid); - continue; - } - - break; - } - - 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) { diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c index 6202eff51a..8cce5e9d07 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c @@ -256,7 +256,6 @@ _onlp_fani_info_get_fan_on_psu(int pid, onlp_fan_info_t* info) info->rpm = 0; info->percentage = 0; info->status |= ONLP_FAN_STATUS_FAILED; - AIM_FREE_IF_PTR(str); return ONLP_STATUS_OK; } /* get fan direction */ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c index 9ad7238019..dbf97e52d8 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.c @@ -27,8 +27,6 @@ #include #include "platform_lib.h" -char psu_prefix[64]; - enum onlp_fan_dir onlp_get_fan_dir(int fid) { int len = 0; @@ -68,12 +66,19 @@ int onlp_get_psu_hwmon_idx(int pid) { /* find hwmon index */ char* file = NULL; + char path[64]; int ret, hwmon_idx, max_hwmon_idx = 20; for (hwmon_idx = 0; hwmon_idx <= max_hwmon_idx; hwmon_idx++) { - snprintf(psu_prefix, sizeof(psu_prefix), "/sys/devices/platform/as9947_72xkb_psu.%d/hwmon/hwmon%d/", pid-1, hwmon_idx); + snprintf(path, sizeof(path), "/sys/devices/platform/as9947_72xkb_psu/hwmon/hwmon%d/", hwmon_idx); + + if (pid == 1) + ret = onlp_file_find(path, "psu1_present", &file); + else if (pid == 2) + ret = onlp_file_find(path, "psu2_present", &file); + else + return -1; - ret = onlp_file_find(psu_prefix, "name", &file); AIM_FREE_IF_PTR(file); if (ONLP_STATUS_OK == ret) @@ -103,46 +108,39 @@ int onlp_get_fan_hwmon_idx(void) return -1; } -int psu_status_info_get(int id, char *node, int *value) +int psu_status_info_get(int pid, char *node, int *value) { int ret = ONLP_STATUS_OK; - char path[128] = {0}; *value = 0; - onlp_get_psu_hwmon_idx(id); - - if (PSU1_ID == id) { - sprintf(path, "%s%s%s", psu_prefix, "psu1_", node); - } - else if (PSU2_ID == id) { - sprintf(path, "%s%s%s", psu_prefix, "psu2_", node); - } - - if (onlp_file_read_int(value, path) < 0) { - AIM_LOG_ERROR("Unable to read status from file(%s)\r\n", path); + if (onlp_file_read_int(value, PSU_SYSFS_FORMAT, pid, node) < 0) { + AIM_LOG_ERROR("Unable to read status from pid(%d) node(%s)\r\n", pid, node); return ONLP_STATUS_E_INTERNAL; } return ret; } -int psu_status_string_get(int id, char *node, char **string) +int psu_status_string_get(int pid, char *node, char **string) { int ret = ONLP_STATUS_OK, len; - char path[128]; + char file[32]; + int hwmon_idx; - if (PSU1_ID == id) { - sprintf(path, "%s%s%s", psu_prefix, "psu1_", node); - } - else if (PSU2_ID == id) { - sprintf(path, "%s%s%s", psu_prefix, "psu2_", node); + hwmon_idx = onlp_get_psu_hwmon_idx(pid); + if (hwmon_idx >= 0) { + /* Read serial */ + snprintf(file, sizeof(file), "psu%d_%s", pid, node); + len = onlp_file_read_str(string, PSU_SYSFS_FORMAT_1, hwmon_idx, file); + if (len < 3) + { + AIM_LOG_ERROR("Unable to read string from pid(%d) node(%s)\r\n", pid, node); + return ONLP_STATUS_E_INTERNAL; + } } - - len = onlp_file_read_str(string, path); - if (len < 3) - { - AIM_LOG_ERROR("Unable to read status from file(%s)\r\n", path); + else { + AIM_LOG_ERROR("Unable to get hwmon index from pid(%d)\r\n", pid); return ONLP_STATUS_E_INTERNAL; } diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h index 87808568f0..9cca84daac 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/platform_lib.h @@ -41,8 +41,8 @@ #define PSU_STATUS_POWER_GOOD 1 #define LED_FORMAT "/sys/devices/platform/as9947_72xkb_led/led_%s" -#define PSU_SYSFS_FORMAT "/sys/devices/platform/as9947_72xkb_psu.%d*psu%d_%s" -#define PSU_SYSFS_FORMAT_1 "/sys/devices/platform/as9947_72xkb_psu.%d/hwmon/hwmon%d/%s" +#define PSU_SYSFS_FORMAT "/sys/devices/platform/as9947_72xkb_psu*psu%d_%s" +#define PSU_SYSFS_FORMAT_1 "/sys/devices/platform/as9947_72xkb_psu/hwmon/hwmon%d/%s" #define FAN_SYSFS_FORMAT "/sys/devices/platform/as9947_72xkb_fan*" #define FAN_SYSFS_FORMAT_1 "/sys/devices/platform/as9947_72xkb_fan/hwmon/hwmon%d/%s" #define SYS_LED_PATH "/sys/devices/platform/as9947_72xkb_led/" @@ -93,8 +93,8 @@ typedef enum as9947_72xkb_platform_id { enum onlp_fan_dir onlp_get_fan_dir(int fid); int onlp_get_psu_hwmon_idx(int pid); int onlp_get_fan_hwmon_idx(void); -int psu_status_info_get(int id, char *node, int *value); -int psu_status_string_get(int id, char *node, char **string); +int psu_status_info_get(int pid, char *node, int *value); +int psu_status_string_get(int pid, char *node, char **string); #define AIM_FREE_IF_PTR(p) \ do \ diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c index 6fd51b7d0c..cd0c278747 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/psui.c @@ -67,7 +67,7 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) *info = pinfo[pid]; /* Set the onlp_oid_hdr_t */ /* Get the present state */ - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "present"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "present"); if (ret < 0) { info->status &= ~ONLP_PSU_STATUS_PRESENT; return ONLP_STATUS_E_INTERNAL; @@ -80,7 +80,7 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) info->status |= ONLP_PSU_STATUS_PRESENT; /* Get power good status */ - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "power_good"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "power_good"); if (ret < 0) { info->status |= ONLP_PSU_STATUS_FAILED; return ONLP_STATUS_E_INTERNAL; @@ -104,42 +104,42 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) /* Read voltage, current and power */ val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vin"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "vin"); if (ret == ONLP_STATUS_OK && val) { info->mvin = val; info->caps |= ONLP_PSU_CAPS_VIN; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iin"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "iin"); if (ret == ONLP_STATUS_OK && val) { info->miin = val; info->caps |= ONLP_PSU_CAPS_IIN; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pin"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "pin"); if (ret == ONLP_STATUS_OK && val) { info->mpin = val; info->caps |= ONLP_PSU_CAPS_PIN; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "vout"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "vout"); if (ret == ONLP_STATUS_OK && val) { info->mvout = val; info->caps |= ONLP_PSU_CAPS_VOUT; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "iout"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "iout"); if (ret == ONLP_STATUS_OK && val) { info->miout = val; info->caps |= ONLP_PSU_CAPS_IOUT; } val = 0; - ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, (pid-1), pid, "pout"); + ret = onlp_file_read_int(&val, PSU_SYSFS_FORMAT, pid, "pout"); if (ret == ONLP_STATUS_OK && val) { info->mpout = val; info->caps |= ONLP_PSU_CAPS_POUT; @@ -153,7 +153,7 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) /* Read model */ snprintf(file, sizeof(file), "psu%d_model", pid); - len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, hwmon_idx, file); if (str && len) { memcpy(info->model, str, len); info->model[len] = '\0'; @@ -162,7 +162,7 @@ onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) /* Read serial */ snprintf(file, sizeof(file), "psu%d_serial", pid); - len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, (pid-1), hwmon_idx, file); + len = onlp_file_read_str(&str, PSU_SYSFS_FORMAT_1, hwmon_idx, file); if (str && len) { memcpy(info->serial, str, len); info->serial[len] = '\0'; diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c index d57d1ec9ea..e11d473a5e 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/thermali.c @@ -47,12 +47,12 @@ static char* devfiles__[] = { /* must map with onlp_thermal_id */ "/sys/devices/platform/as9947_72xkb_thermal*temp8_input", "/sys/devices/platform/as9947_72xkb_thermal*temp9_input", "/sys/devices/platform/as9947_72xkb_thermal*temp10_input", - "/sys/devices/platform/as9947_72xkb_psu.0*psu1_temp1_input", - "/sys/devices/platform/as9947_72xkb_psu.0*psu1_temp2_input", - "/sys/devices/platform/as9947_72xkb_psu.0*psu1_temp3_input", - "/sys/devices/platform/as9947_72xkb_psu.1*psu2_temp1_input", - "/sys/devices/platform/as9947_72xkb_psu.1*psu2_temp2_input", - "/sys/devices/platform/as9947_72xkb_psu.1*psu2_temp3_input" + "/sys/devices/platform/as9947_72xkb_psu*psu1_temp1_input", + "/sys/devices/platform/as9947_72xkb_psu*psu1_temp2_input", + "/sys/devices/platform/as9947_72xkb_psu*psu1_temp3_input", + "/sys/devices/platform/as9947_72xkb_psu*psu2_temp1_input", + "/sys/devices/platform/as9947_72xkb_psu*psu2_temp2_input", + "/sys/devices/platform/as9947_72xkb_psu*psu2_temp3_input" }; static char* cpu_coretemp_files[] = { diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py index 6a92f5d3a5..c1050f906c 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py @@ -81,6 +81,7 @@ def baseconfig(self): return False self.modprobe('optoe') + self.modprobe('accton_ipmi_intf') for m in [ 'i2c-ocores', 'fpga', 'fan', 'psu', 'thermal', 'sys', 'leds']: self.insmod("x86-64-accton-as9947-72xkb-%s" % m) From cff482017642eba6ede572d0adb01f67cf1222e3 Mon Sep 17 00:00:00 2001 From: acctalex Date: Thu, 13 Nov 2025 10:06:03 +0800 Subject: [PATCH 3/5] [Accton][as9947-72xkb] Enlarge ipmi raw cmd buf size (#13) 1. Enlarge ipmi raw cmd buf size to 40 bytes. Signed-off-by: Alex Lai --- .../x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c index 0bf88f6461..48a0c9acfd 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/accton_ipmi_intf.c @@ -24,7 +24,7 @@ #define ACCTON_IPMI_NETFN 0x34 #define IPMI_TIMEOUT (5 * HZ) #define IPMI_ERR_RETRY_TIMES 1 -#define RAW_CMD_BUF_SIZE 32 +#define RAW_CMD_BUF_SIZE 40 static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); From 188c35f6b9f7eb16ac29080aa5efee1cc2ed5ca0 Mon Sep 17 00:00:00 2001 From: Willy Liu Date: Wed, 26 Nov 2025 08:33:46 +0000 Subject: [PATCH 4/5] [ACCTON][AS9947-72XKB] Modify to access transceiver eeprom by ipmi 1. Remove the transceiver attr of pcie accessing in fpga driver 2. Add sfp driver for ipmi accessing transceiver attr 3. Add sfp ko in init.py 4. Modify the transceiver attr sysfs path 5. Fix rxlos bitmap Signed-off-by: Willy Liu --- .../as9947-72xkb/modules/builds/src/Makefile | 1 + .../src/x86-64-accton-as9947-72xkb-fpga.c | 737 ---------- .../src/x86-64-accton-as9947-72xkb-sfp.c | 1277 +++++++++++++++++ .../module/src/sfpi.c | 36 +- .../x86_64_accton_as9947_72xkb_r0/__init__.py | 2 +- 5 files changed, 1300 insertions(+), 753 deletions(-) create mode 100644 packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sfp.c diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile index 820a8c64d5..c75932e144 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile @@ -6,4 +6,5 @@ obj-m += x86-64-accton-as9947-72xkb-thermal.o obj-m += x86-64-accton-as9947-72xkb-psu.o obj-m += x86-64-accton-as9947-72xkb-sys.o obj-m += x86-64-accton-as9947-72xkb-leds.o +obj-m += x86-64-accton-as9947-72xkb-sfp.o diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c index c4efb3c341..f541ffcb70 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-fpga.c @@ -58,52 +58,7 @@ #define FPGA_BOARD_INFO_REG (FPGA_PCIE_START_OFFSET + 0x00) /* CPLD */ #define CPLD_PCIE_START_OFFSET 0x2000 -/* MB CPLD0, ASYNC_ Region 4, 0: pcie to MB_CPLD0 */ -#define QSFP_DD_P7_P0_RESET_REG (CPLD_PCIE_START_OFFSET + 0x60) -#define QSFP_DD_P11_P8_RESET_REG (CPLD_PCIE_START_OFFSET + 0x61) -#define QSFP_DD_P7_P0_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x64) -#define QSFP_DD_P11_P8_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x65) -#define QSFP_DD_P7_P0_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x68) -#define QSFP_DD_P11_P8_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x69) -/* MB CPLD1, ASYNC_ Region 4, 1: pcie to MB_CPLD1 */ -#define QSFP_DD_P19_P12_RESET_REG (CPLD_PCIE_START_OFFSET + 0x60) -#define QSFP_DD_P23_P20_RESET_REG (CPLD_PCIE_START_OFFSET + 0x61) -#define QSFP_DD_P19_P12_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x64) -#define QSFP_DD_P23_P20_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x65) -#define QSFP_DD_P19_P12_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x68) -#define QSFP_DD_P23_P20_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x69) -/* MEZZ CPLD0, ASYNC_ Region 5, 2'b00: pcie to Mezz_CPLD0 */ -#define QSFP28_P7_P0_RESET_REG (CPLD_PCIE_START_OFFSET + 0x80) -#define QSFP28_P15_P8_RESET_REG (CPLD_PCIE_START_OFFSET + 0x81) -#define QSFP28_P7_P0_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x88) -#define QSFP28_P15_P8_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x89) -#define QSFP28_P7_P0_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x90) -#define QSFP28_P15_P8_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x91) -/* MEZZ CPLD1, ASYNC_ Region 5, 2'b01: pcie to Mezz_CPLD1 */ -#define QSFP28_P39_P32_RESET_REG (CPLD_PCIE_START_OFFSET + 0x80) -#define QSFP28_P47_P40_RESET_REG (CPLD_PCIE_START_OFFSET + 0x81) -#define QSFP28_P39_P32_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x88) -#define QSFP28_P47_P40_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x89) -#define QSFP28_P39_P32_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x90) -#define QSFP28_P47_P40_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x91) -#define SFP_P3_P0_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x92) -#define SFP_P3_P0_TXDIS_REG (CPLD_PCIE_START_OFFSET + 0xA8) -#define SFP_P3_P0_RXLOS_REG (CPLD_PCIE_START_OFFSET + 0xA9) -#define SFP_P3_P0_TXFAULT_REG (CPLD_PCIE_START_OFFSET + 0xB2) -/* MEZZ CPLD2, ASYNC_ Region 5, 2'b10: pcie to Mezz_CPLD2 */ -#define QSFP28_P23_P16_RESET_REG (CPLD_PCIE_START_OFFSET + 0x80) -#define QSFP28_P31_P24_RESET_REG (CPLD_PCIE_START_OFFSET + 0x81) -#define QSFP28_P23_P16_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x88) -#define QSFP28_P31_P24_LPMODE_REG (CPLD_PCIE_START_OFFSET + 0x89) -#define QSFP28_P23_P16_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x90) -#define QSFP28_P31_P24_PRESENT_REG (CPLD_PCIE_START_OFFSET + 0x91) -#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index -#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index -#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index -#define TRANSCEIVER_TX_DISABLE_ATTR_ID(index) MODULE_TX_DISABLE_##index -#define TRANSCEIVER_TX_FAULT_ATTR_ID(index) MODULE_TX_FAULT_##index -#define TRANSCEIVER_RX_LOS_ATTR_ID(index) MODULE_RX_LOS_##index /*********************************************** * macro define * *********************************************/ @@ -150,696 +105,10 @@ extern spinlock_t cpld_access_lock; extern int wait_spi(u32 mask, unsigned long timeout); extern void __iomem *spi_busy_reg; extern void __iomem *async_reg; -/*********************************************** - * enum define - * *********************************************/ -enum fpga_sysfs_attributes { - /* transceiver attributes */ - TRANSCEIVER_PRESENT_ATTR_ID(1), - TRANSCEIVER_PRESENT_ATTR_ID(2), - TRANSCEIVER_PRESENT_ATTR_ID(3), - TRANSCEIVER_PRESENT_ATTR_ID(4), - TRANSCEIVER_PRESENT_ATTR_ID(5), - TRANSCEIVER_PRESENT_ATTR_ID(6), - TRANSCEIVER_PRESENT_ATTR_ID(7), - TRANSCEIVER_PRESENT_ATTR_ID(8), - TRANSCEIVER_PRESENT_ATTR_ID(9), - TRANSCEIVER_PRESENT_ATTR_ID(10), - TRANSCEIVER_PRESENT_ATTR_ID(11), - TRANSCEIVER_PRESENT_ATTR_ID(12), - TRANSCEIVER_PRESENT_ATTR_ID(13), - TRANSCEIVER_PRESENT_ATTR_ID(14), - TRANSCEIVER_PRESENT_ATTR_ID(15), - TRANSCEIVER_PRESENT_ATTR_ID(16), - TRANSCEIVER_PRESENT_ATTR_ID(17), - TRANSCEIVER_PRESENT_ATTR_ID(18), - TRANSCEIVER_PRESENT_ATTR_ID(19), - TRANSCEIVER_PRESENT_ATTR_ID(20), - TRANSCEIVER_PRESENT_ATTR_ID(21), - TRANSCEIVER_PRESENT_ATTR_ID(22), - TRANSCEIVER_PRESENT_ATTR_ID(23), - TRANSCEIVER_PRESENT_ATTR_ID(24), - TRANSCEIVER_PRESENT_ATTR_ID(25), - TRANSCEIVER_PRESENT_ATTR_ID(26), - TRANSCEIVER_PRESENT_ATTR_ID(27), - TRANSCEIVER_PRESENT_ATTR_ID(28), - TRANSCEIVER_PRESENT_ATTR_ID(29), - TRANSCEIVER_PRESENT_ATTR_ID(30), - TRANSCEIVER_PRESENT_ATTR_ID(31), - TRANSCEIVER_PRESENT_ATTR_ID(32), - TRANSCEIVER_PRESENT_ATTR_ID(33), - TRANSCEIVER_PRESENT_ATTR_ID(34), - TRANSCEIVER_PRESENT_ATTR_ID(35), - TRANSCEIVER_PRESENT_ATTR_ID(36), - TRANSCEIVER_PRESENT_ATTR_ID(37), - TRANSCEIVER_PRESENT_ATTR_ID(38), - 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_PRESENT_ATTR_ID(54), - TRANSCEIVER_PRESENT_ATTR_ID(55), - TRANSCEIVER_PRESENT_ATTR_ID(56), - TRANSCEIVER_PRESENT_ATTR_ID(57), - TRANSCEIVER_PRESENT_ATTR_ID(58), - TRANSCEIVER_PRESENT_ATTR_ID(59), - TRANSCEIVER_PRESENT_ATTR_ID(60), - TRANSCEIVER_PRESENT_ATTR_ID(61), - TRANSCEIVER_PRESENT_ATTR_ID(62), - TRANSCEIVER_PRESENT_ATTR_ID(63), - TRANSCEIVER_PRESENT_ATTR_ID(64), - TRANSCEIVER_PRESENT_ATTR_ID(65), - TRANSCEIVER_PRESENT_ATTR_ID(66), - TRANSCEIVER_PRESENT_ATTR_ID(67), - TRANSCEIVER_PRESENT_ATTR_ID(68), - TRANSCEIVER_PRESENT_ATTR_ID(69), - TRANSCEIVER_PRESENT_ATTR_ID(70), - TRANSCEIVER_PRESENT_ATTR_ID(71), - TRANSCEIVER_PRESENT_ATTR_ID(72), - TRANSCEIVER_PRESENT_ATTR_ID(73), - TRANSCEIVER_PRESENT_ATTR_ID(74), - TRANSCEIVER_PRESENT_ATTR_ID(75), - TRANSCEIVER_PRESENT_ATTR_ID(76), - /*Reset*/ - TRANSCEIVER_RESET_ATTR_ID(1), - TRANSCEIVER_RESET_ATTR_ID(2), - TRANSCEIVER_RESET_ATTR_ID(3), - TRANSCEIVER_RESET_ATTR_ID(4), - TRANSCEIVER_RESET_ATTR_ID(5), - TRANSCEIVER_RESET_ATTR_ID(6), - TRANSCEIVER_RESET_ATTR_ID(7), - TRANSCEIVER_RESET_ATTR_ID(8), - TRANSCEIVER_RESET_ATTR_ID(9), - TRANSCEIVER_RESET_ATTR_ID(10), - TRANSCEIVER_RESET_ATTR_ID(11), - TRANSCEIVER_RESET_ATTR_ID(12), - TRANSCEIVER_RESET_ATTR_ID(13), - TRANSCEIVER_RESET_ATTR_ID(14), - TRANSCEIVER_RESET_ATTR_ID(15), - TRANSCEIVER_RESET_ATTR_ID(16), - TRANSCEIVER_RESET_ATTR_ID(17), - TRANSCEIVER_RESET_ATTR_ID(18), - TRANSCEIVER_RESET_ATTR_ID(19), - TRANSCEIVER_RESET_ATTR_ID(20), - TRANSCEIVER_RESET_ATTR_ID(21), - TRANSCEIVER_RESET_ATTR_ID(22), - TRANSCEIVER_RESET_ATTR_ID(23), - TRANSCEIVER_RESET_ATTR_ID(24), - TRANSCEIVER_RESET_ATTR_ID(25), - TRANSCEIVER_RESET_ATTR_ID(26), - TRANSCEIVER_RESET_ATTR_ID(27), - TRANSCEIVER_RESET_ATTR_ID(28), - TRANSCEIVER_RESET_ATTR_ID(29), - TRANSCEIVER_RESET_ATTR_ID(30), - TRANSCEIVER_RESET_ATTR_ID(31), - TRANSCEIVER_RESET_ATTR_ID(32), - TRANSCEIVER_RESET_ATTR_ID(33), - TRANSCEIVER_RESET_ATTR_ID(34), - TRANSCEIVER_RESET_ATTR_ID(35), - TRANSCEIVER_RESET_ATTR_ID(36), - TRANSCEIVER_RESET_ATTR_ID(37), - TRANSCEIVER_RESET_ATTR_ID(38), - 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_RESET_ATTR_ID(54), - TRANSCEIVER_RESET_ATTR_ID(55), - TRANSCEIVER_RESET_ATTR_ID(56), - TRANSCEIVER_RESET_ATTR_ID(57), - TRANSCEIVER_RESET_ATTR_ID(58), - TRANSCEIVER_RESET_ATTR_ID(59), - TRANSCEIVER_RESET_ATTR_ID(60), - TRANSCEIVER_RESET_ATTR_ID(61), - TRANSCEIVER_RESET_ATTR_ID(62), - TRANSCEIVER_RESET_ATTR_ID(63), - TRANSCEIVER_RESET_ATTR_ID(64), - TRANSCEIVER_RESET_ATTR_ID(65), - TRANSCEIVER_RESET_ATTR_ID(66), - TRANSCEIVER_RESET_ATTR_ID(67), - TRANSCEIVER_RESET_ATTR_ID(68), - TRANSCEIVER_RESET_ATTR_ID(69), - TRANSCEIVER_RESET_ATTR_ID(70), - TRANSCEIVER_RESET_ATTR_ID(71), - TRANSCEIVER_RESET_ATTR_ID(72), - TRANSCEIVER_LPMODE_ATTR_ID(1), - TRANSCEIVER_LPMODE_ATTR_ID(2), - TRANSCEIVER_LPMODE_ATTR_ID(3), - TRANSCEIVER_LPMODE_ATTR_ID(4), - TRANSCEIVER_LPMODE_ATTR_ID(5), - TRANSCEIVER_LPMODE_ATTR_ID(6), - TRANSCEIVER_LPMODE_ATTR_ID(7), - TRANSCEIVER_LPMODE_ATTR_ID(8), - TRANSCEIVER_LPMODE_ATTR_ID(9), - TRANSCEIVER_LPMODE_ATTR_ID(10), - TRANSCEIVER_LPMODE_ATTR_ID(11), - TRANSCEIVER_LPMODE_ATTR_ID(12), - TRANSCEIVER_LPMODE_ATTR_ID(13), - TRANSCEIVER_LPMODE_ATTR_ID(14), - TRANSCEIVER_LPMODE_ATTR_ID(15), - TRANSCEIVER_LPMODE_ATTR_ID(16), - TRANSCEIVER_LPMODE_ATTR_ID(17), - TRANSCEIVER_LPMODE_ATTR_ID(18), - TRANSCEIVER_LPMODE_ATTR_ID(19), - TRANSCEIVER_LPMODE_ATTR_ID(20), - TRANSCEIVER_LPMODE_ATTR_ID(21), - TRANSCEIVER_LPMODE_ATTR_ID(22), - TRANSCEIVER_LPMODE_ATTR_ID(23), - TRANSCEIVER_LPMODE_ATTR_ID(24), - TRANSCEIVER_LPMODE_ATTR_ID(25), - TRANSCEIVER_LPMODE_ATTR_ID(26), - TRANSCEIVER_LPMODE_ATTR_ID(27), - TRANSCEIVER_LPMODE_ATTR_ID(28), - TRANSCEIVER_LPMODE_ATTR_ID(29), - TRANSCEIVER_LPMODE_ATTR_ID(30), - TRANSCEIVER_LPMODE_ATTR_ID(31), - TRANSCEIVER_LPMODE_ATTR_ID(32), - TRANSCEIVER_LPMODE_ATTR_ID(33), - TRANSCEIVER_LPMODE_ATTR_ID(34), - TRANSCEIVER_LPMODE_ATTR_ID(35), - TRANSCEIVER_LPMODE_ATTR_ID(36), - TRANSCEIVER_LPMODE_ATTR_ID(37), - TRANSCEIVER_LPMODE_ATTR_ID(38), - TRANSCEIVER_LPMODE_ATTR_ID(39), - TRANSCEIVER_LPMODE_ATTR_ID(40), - TRANSCEIVER_LPMODE_ATTR_ID(41), - TRANSCEIVER_LPMODE_ATTR_ID(42), - TRANSCEIVER_LPMODE_ATTR_ID(43), - TRANSCEIVER_LPMODE_ATTR_ID(44), - TRANSCEIVER_LPMODE_ATTR_ID(45), - TRANSCEIVER_LPMODE_ATTR_ID(46), - TRANSCEIVER_LPMODE_ATTR_ID(47), - TRANSCEIVER_LPMODE_ATTR_ID(48), - TRANSCEIVER_LPMODE_ATTR_ID(49), - TRANSCEIVER_LPMODE_ATTR_ID(50), - TRANSCEIVER_LPMODE_ATTR_ID(51), - TRANSCEIVER_LPMODE_ATTR_ID(52), - TRANSCEIVER_LPMODE_ATTR_ID(53), - TRANSCEIVER_LPMODE_ATTR_ID(54), - TRANSCEIVER_LPMODE_ATTR_ID(55), - TRANSCEIVER_LPMODE_ATTR_ID(56), - TRANSCEIVER_LPMODE_ATTR_ID(57), - TRANSCEIVER_LPMODE_ATTR_ID(58), - TRANSCEIVER_LPMODE_ATTR_ID(59), - TRANSCEIVER_LPMODE_ATTR_ID(60), - TRANSCEIVER_LPMODE_ATTR_ID(61), - TRANSCEIVER_LPMODE_ATTR_ID(62), - TRANSCEIVER_LPMODE_ATTR_ID(63), - TRANSCEIVER_LPMODE_ATTR_ID(64), - TRANSCEIVER_LPMODE_ATTR_ID(65), - TRANSCEIVER_LPMODE_ATTR_ID(66), - TRANSCEIVER_LPMODE_ATTR_ID(67), - TRANSCEIVER_LPMODE_ATTR_ID(68), - TRANSCEIVER_LPMODE_ATTR_ID(69), - TRANSCEIVER_LPMODE_ATTR_ID(70), - TRANSCEIVER_LPMODE_ATTR_ID(71), - TRANSCEIVER_LPMODE_ATTR_ID(72), - TRANSCEIVER_TX_DISABLE_ATTR_ID(73), - TRANSCEIVER_TX_DISABLE_ATTR_ID(74), - TRANSCEIVER_TX_DISABLE_ATTR_ID(75), - TRANSCEIVER_TX_DISABLE_ATTR_ID(76), - TRANSCEIVER_TX_FAULT_ATTR_ID(73), - TRANSCEIVER_TX_FAULT_ATTR_ID(74), - TRANSCEIVER_TX_FAULT_ATTR_ID(75), - TRANSCEIVER_TX_FAULT_ATTR_ID(76), - TRANSCEIVER_RX_LOS_ATTR_ID(73), - TRANSCEIVER_RX_LOS_ATTR_ID(74), - TRANSCEIVER_RX_LOS_ATTR_ID(75), - TRANSCEIVER_RX_LOS_ATTR_ID(76), -}; /*********************************************** * function declare * *********************************************/ -static ssize_t status_read(struct device *dev, struct device_attribute *da, - char *buf); -static ssize_t status_write(struct device *dev, struct device_attribute *da, - const char *buf, size_t count); - -#define DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ - static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, status_read, NULL, MODULE_PRESENT_##index); \ - static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO|S_IWUSR, status_read, status_write, MODULE_RESET_##index); \ - static SENSOR_DEVICE_ATTR(module_lp_mode_##index, S_IRUGO|S_IWUSR, status_read, status_write, MODULE_LPMODE_##index) -#define DECLARE_TRANSCEIVER_ATTR(index) \ - &sensor_dev_attr_module_present_##index.dev_attr.attr, \ - &sensor_dev_attr_module_reset_##index.dev_attr.attr, \ - &sensor_dev_attr_module_lp_mode_##index.dev_attr.attr - -/* transceiver attributes */ -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(55); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(56); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(57); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(58); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(59); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(60); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(61); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(62); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(63); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(64); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(65); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(66); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(67); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(68); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(69); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(70); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(71); -DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(72); -static SENSOR_DEVICE_ATTR(module_present_73, S_IRUGO, status_read, NULL, MODULE_PRESENT_73); -static SENSOR_DEVICE_ATTR(module_present_74, S_IRUGO, status_read, NULL, MODULE_PRESENT_74); -static SENSOR_DEVICE_ATTR(module_present_75, S_IRUGO, status_read, NULL, MODULE_PRESENT_75); -static SENSOR_DEVICE_ATTR(module_present_76, S_IRUGO, status_read, NULL, MODULE_PRESENT_76); -static SENSOR_DEVICE_ATTR(module_tx_disable_73, S_IRUGO|S_IWUSR, status_read, - status_write, MODULE_TX_DISABLE_73); -static SENSOR_DEVICE_ATTR(module_tx_disable_74, S_IRUGO|S_IWUSR, status_read, - status_write, MODULE_TX_DISABLE_74); -static SENSOR_DEVICE_ATTR(module_tx_disable_75, S_IRUGO|S_IWUSR, status_read, - status_write, MODULE_TX_DISABLE_75); -static SENSOR_DEVICE_ATTR(module_tx_disable_76, S_IRUGO|S_IWUSR, status_read, - status_write, MODULE_TX_DISABLE_76); -static SENSOR_DEVICE_ATTR(module_tx_fault_73, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_73); -static SENSOR_DEVICE_ATTR(module_tx_fault_74, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_74); -static SENSOR_DEVICE_ATTR(module_tx_fault_75, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_75); -static SENSOR_DEVICE_ATTR(module_tx_fault_76, S_IRUGO, status_read, NULL, MODULE_TX_FAULT_76); -static SENSOR_DEVICE_ATTR(module_rx_los_73, S_IRUGO, status_read, NULL, MODULE_RX_LOS_73); -static SENSOR_DEVICE_ATTR(module_rx_los_74, S_IRUGO, status_read, NULL, MODULE_RX_LOS_74); -static SENSOR_DEVICE_ATTR(module_rx_los_75, S_IRUGO, status_read, NULL, MODULE_RX_LOS_75); -static SENSOR_DEVICE_ATTR(module_rx_los_76, S_IRUGO, status_read, NULL, MODULE_RX_LOS_76); - -static struct attribute *fpga_transceiver_attributes[] = { - DECLARE_TRANSCEIVER_ATTR(1), - DECLARE_TRANSCEIVER_ATTR(2), - DECLARE_TRANSCEIVER_ATTR(3), - DECLARE_TRANSCEIVER_ATTR(4), - DECLARE_TRANSCEIVER_ATTR(5), - DECLARE_TRANSCEIVER_ATTR(6), - DECLARE_TRANSCEIVER_ATTR(7), - DECLARE_TRANSCEIVER_ATTR(8), - DECLARE_TRANSCEIVER_ATTR(9), - DECLARE_TRANSCEIVER_ATTR(10), - DECLARE_TRANSCEIVER_ATTR(11), - DECLARE_TRANSCEIVER_ATTR(12), - DECLARE_TRANSCEIVER_ATTR(13), - DECLARE_TRANSCEIVER_ATTR(14), - DECLARE_TRANSCEIVER_ATTR(15), - DECLARE_TRANSCEIVER_ATTR(16), - DECLARE_TRANSCEIVER_ATTR(17), - DECLARE_TRANSCEIVER_ATTR(18), - DECLARE_TRANSCEIVER_ATTR(19), - DECLARE_TRANSCEIVER_ATTR(20), - DECLARE_TRANSCEIVER_ATTR(21), - DECLARE_TRANSCEIVER_ATTR(22), - DECLARE_TRANSCEIVER_ATTR(23), - DECLARE_TRANSCEIVER_ATTR(24), - DECLARE_TRANSCEIVER_ATTR(25), - DECLARE_TRANSCEIVER_ATTR(26), - DECLARE_TRANSCEIVER_ATTR(27), - DECLARE_TRANSCEIVER_ATTR(28), - DECLARE_TRANSCEIVER_ATTR(29), - DECLARE_TRANSCEIVER_ATTR(30), - DECLARE_TRANSCEIVER_ATTR(31), - DECLARE_TRANSCEIVER_ATTR(32), - DECLARE_TRANSCEIVER_ATTR(33), - DECLARE_TRANSCEIVER_ATTR(34), - DECLARE_TRANSCEIVER_ATTR(35), - DECLARE_TRANSCEIVER_ATTR(36), - DECLARE_TRANSCEIVER_ATTR(37), - DECLARE_TRANSCEIVER_ATTR(38), - DECLARE_TRANSCEIVER_ATTR(39), - DECLARE_TRANSCEIVER_ATTR(40), - DECLARE_TRANSCEIVER_ATTR(41), - DECLARE_TRANSCEIVER_ATTR(42), - DECLARE_TRANSCEIVER_ATTR(43), - DECLARE_TRANSCEIVER_ATTR(44), - DECLARE_TRANSCEIVER_ATTR(45), - DECLARE_TRANSCEIVER_ATTR(46), - DECLARE_TRANSCEIVER_ATTR(47), - DECLARE_TRANSCEIVER_ATTR(48), - DECLARE_TRANSCEIVER_ATTR(49), - DECLARE_TRANSCEIVER_ATTR(50), - DECLARE_TRANSCEIVER_ATTR(51), - DECLARE_TRANSCEIVER_ATTR(52), - DECLARE_TRANSCEIVER_ATTR(53), - DECLARE_TRANSCEIVER_ATTR(54), - DECLARE_TRANSCEIVER_ATTR(55), - DECLARE_TRANSCEIVER_ATTR(56), - DECLARE_TRANSCEIVER_ATTR(57), - DECLARE_TRANSCEIVER_ATTR(58), - DECLARE_TRANSCEIVER_ATTR(59), - DECLARE_TRANSCEIVER_ATTR(60), - DECLARE_TRANSCEIVER_ATTR(61), - DECLARE_TRANSCEIVER_ATTR(62), - DECLARE_TRANSCEIVER_ATTR(63), - DECLARE_TRANSCEIVER_ATTR(64), - DECLARE_TRANSCEIVER_ATTR(65), - DECLARE_TRANSCEIVER_ATTR(66), - DECLARE_TRANSCEIVER_ATTR(67), - DECLARE_TRANSCEIVER_ATTR(68), - DECLARE_TRANSCEIVER_ATTR(69), - DECLARE_TRANSCEIVER_ATTR(70), - DECLARE_TRANSCEIVER_ATTR(71), - DECLARE_TRANSCEIVER_ATTR(72), - &sensor_dev_attr_module_present_73.dev_attr.attr, - &sensor_dev_attr_module_present_74.dev_attr.attr, - &sensor_dev_attr_module_present_75.dev_attr.attr, - &sensor_dev_attr_module_present_76.dev_attr.attr, - &sensor_dev_attr_module_tx_disable_73.dev_attr.attr, - &sensor_dev_attr_module_tx_disable_74.dev_attr.attr, - &sensor_dev_attr_module_tx_disable_75.dev_attr.attr, - &sensor_dev_attr_module_tx_disable_76.dev_attr.attr, - &sensor_dev_attr_module_tx_fault_73.dev_attr.attr, - &sensor_dev_attr_module_tx_fault_74.dev_attr.attr, - &sensor_dev_attr_module_tx_fault_75.dev_attr.attr, - &sensor_dev_attr_module_tx_fault_76.dev_attr.attr, - &sensor_dev_attr_module_rx_los_73.dev_attr.attr, - &sensor_dev_attr_module_rx_los_74.dev_attr.attr, - &sensor_dev_attr_module_rx_los_75.dev_attr.attr, - &sensor_dev_attr_module_rx_los_76.dev_attr.attr, - NULL -}; - -static const struct attribute_group fpga_port_stat_group = { - .attrs = fpga_transceiver_attributes, -}; - -struct attribute_mapping { - u16 attr_base; - u16 reg; - u8 bar; - u8 revert; -}; - -// Define an array of attribute mappings -static struct attribute_mapping attribute_mappings[] = { - /* QSFP28 */ - [MODULE_PRESENT_1 ... MODULE_PRESENT_8] = {MODULE_PRESENT_1, QSFP28_P7_P0_PRESENT_REG, BAR5_NUM, 1}, - [MODULE_PRESENT_9 ... MODULE_PRESENT_16] = {MODULE_PRESENT_9, QSFP28_P15_P8_PRESENT_REG, BAR5_NUM, 1}, - [MODULE_PRESENT_17 ... MODULE_PRESENT_24] = {MODULE_PRESENT_17, QSFP28_P23_P16_PRESENT_REG, BAR5_NUM, 1}, - [MODULE_PRESENT_25 ... MODULE_PRESENT_32] = {MODULE_PRESENT_25, QSFP28_P31_P24_PRESENT_REG, BAR5_NUM, 1}, - [MODULE_PRESENT_33 ... MODULE_PRESENT_40] = {MODULE_PRESENT_33, QSFP28_P39_P32_PRESENT_REG, BAR5_NUM, 1}, - [MODULE_PRESENT_41 ... MODULE_PRESENT_48] = {MODULE_PRESENT_41, QSFP28_P47_P40_PRESENT_REG, BAR5_NUM, 1}, - /* QSFP-DD */ - [MODULE_PRESENT_49 ... MODULE_PRESENT_56] = {MODULE_PRESENT_49, QSFP_DD_P7_P0_PRESENT_REG, BAR4_NUM, 1}, - [MODULE_PRESENT_57 ... MODULE_PRESENT_60] = {MODULE_PRESENT_57, QSFP_DD_P11_P8_PRESENT_REG, BAR4_NUM, 1}, - [MODULE_PRESENT_61 ... MODULE_PRESENT_68] = {MODULE_PRESENT_61, QSFP_DD_P19_P12_PRESENT_REG, BAR4_NUM, 1}, - [MODULE_PRESENT_69 ... MODULE_PRESENT_72] = {MODULE_PRESENT_69, QSFP_DD_P23_P20_PRESENT_REG, BAR4_NUM, 1}, - /* SFP */ - [MODULE_PRESENT_73 ... MODULE_PRESENT_76] = {MODULE_PRESENT_73, SFP_P3_P0_PRESENT_REG, BAR5_NUM, 1}, - /* QSFP28 */ - [MODULE_RESET_1 ... MODULE_RESET_8] = {MODULE_RESET_1, QSFP28_P7_P0_RESET_REG, BAR5_NUM, 1}, - [MODULE_RESET_9 ... MODULE_RESET_16] = {MODULE_RESET_9, QSFP28_P15_P8_RESET_REG, BAR5_NUM, 1}, - [MODULE_RESET_17 ... MODULE_RESET_24] = {MODULE_RESET_17, QSFP28_P23_P16_RESET_REG, BAR5_NUM, 1}, - [MODULE_RESET_25 ... MODULE_RESET_32] = {MODULE_RESET_25, QSFP28_P31_P24_RESET_REG, BAR5_NUM, 1}, - [MODULE_RESET_33 ... MODULE_RESET_40] = {MODULE_RESET_33, QSFP28_P39_P32_RESET_REG, BAR5_NUM, 1}, - [MODULE_RESET_41 ... MODULE_RESET_48] = {MODULE_RESET_41, QSFP28_P47_P40_RESET_REG, BAR5_NUM, 1}, - /* QSFP-DD */ - [MODULE_RESET_49 ... MODULE_RESET_56] = {MODULE_RESET_49, QSFP_DD_P7_P0_RESET_REG, BAR4_NUM, 1}, - [MODULE_RESET_57 ... MODULE_RESET_60] = {MODULE_RESET_57, QSFP_DD_P11_P8_RESET_REG, BAR4_NUM, 1}, - [MODULE_RESET_61 ... MODULE_RESET_68] = {MODULE_RESET_61, QSFP_DD_P19_P12_RESET_REG, BAR4_NUM, 1}, - [MODULE_RESET_69 ... MODULE_RESET_72] = {MODULE_RESET_69, QSFP_DD_P23_P20_RESET_REG, BAR4_NUM, 1}, - /* QSFP28 */ - [MODULE_LPMODE_1 ... MODULE_LPMODE_8] = {MODULE_LPMODE_1, QSFP28_P7_P0_LPMODE_REG, BAR5_NUM, 0}, - [MODULE_LPMODE_9 ... MODULE_LPMODE_16] = {MODULE_LPMODE_9, QSFP28_P15_P8_LPMODE_REG, BAR5_NUM, 0}, - [MODULE_LPMODE_17 ... MODULE_LPMODE_24] = {MODULE_LPMODE_17, QSFP28_P23_P16_LPMODE_REG, BAR5_NUM, 0}, - [MODULE_LPMODE_25 ... MODULE_LPMODE_32] = {MODULE_LPMODE_25, QSFP28_P31_P24_LPMODE_REG, BAR5_NUM, 0}, - [MODULE_LPMODE_33 ... MODULE_LPMODE_40] = {MODULE_LPMODE_33, QSFP28_P39_P32_LPMODE_REG, BAR5_NUM, 0}, - [MODULE_LPMODE_41 ... MODULE_LPMODE_48] = {MODULE_LPMODE_41, QSFP28_P47_P40_LPMODE_REG, BAR5_NUM, 0}, - /* QSFP-DD */ - [MODULE_LPMODE_49 ... MODULE_LPMODE_56] = {MODULE_LPMODE_49, QSFP_DD_P7_P0_LPMODE_REG, BAR4_NUM, 0}, - [MODULE_LPMODE_57 ... MODULE_LPMODE_60] = {MODULE_LPMODE_57, QSFP_DD_P11_P8_LPMODE_REG, BAR4_NUM, 0}, - [MODULE_LPMODE_61 ... MODULE_LPMODE_68] = {MODULE_LPMODE_61, QSFP_DD_P19_P12_LPMODE_REG, BAR4_NUM, 0}, - [MODULE_LPMODE_69 ... MODULE_LPMODE_72] = {MODULE_LPMODE_69, QSFP_DD_P23_P20_LPMODE_REG, BAR4_NUM, 0}, - - /* SFP TXDIS, TXFAULT, RXLOS*/ - [MODULE_TX_DISABLE_73 ... MODULE_TX_DISABLE_76] ={MODULE_TX_DISABLE_73, SFP_P3_P0_TXDIS_REG,BAR5_NUM, 0}, - [MODULE_TX_FAULT_73 ... MODULE_TX_FAULT_76] = {MODULE_TX_FAULT_73, SFP_P3_P0_TXFAULT_REG, BAR5_NUM, 0}, - [MODULE_RX_LOS_73 ... MODULE_RX_LOS_76] = {MODULE_RX_LOS_73, SFP_P3_P0_RXLOS_REG, BAR5_NUM, 1}, -}; - -static inline unsigned int fpga_read(void __iomem *addr, u32 spi_mask) -{ - wait_spi(spi_mask, usecs_to_jiffies(20)); - return ioread8(addr); -} - -static inline void fpga_write(void __iomem *addr, u8 val, u32 spi_mask) -{ - wait_spi(spi_mask, usecs_to_jiffies(20)); - iowrite8(val, addr); -} - -static ssize_t status_read(struct device *dev, struct device_attribute *da, char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct as9947_72xkb_fpga_data *fpga_ctl = dev_get_drvdata(dev); - ssize_t ret = -EINVAL; - u16 reg; - u8 fpga_async_data, reg_val, bar; - u8 bits_shift; - - switch(attr->index) - { - case MODULE_PRESENT_1 ... MODULE_PRESENT_16: - fpga_async_data = 0x0; - break; - case MODULE_PRESENT_17 ... MODULE_PRESENT_32: - fpga_async_data = 0x20; - break; - case MODULE_PRESENT_33 ... MODULE_PRESENT_48: - fpga_async_data = 0x10; - break; - case MODULE_PRESENT_49 ... MODULE_PRESENT_60: - fpga_async_data = 0x0; - break; - case MODULE_PRESENT_61 ... MODULE_PRESENT_72: - fpga_async_data = 0x01; - break; - case MODULE_PRESENT_73 ... MODULE_PRESENT_76: - fpga_async_data = 0x10; - break; - case MODULE_LPMODE_1 ... MODULE_LPMODE_16: - fpga_async_data = 0x0; - break; - case MODULE_LPMODE_17 ... MODULE_LPMODE_32: - fpga_async_data = 0x20; - break; - case MODULE_LPMODE_33 ... MODULE_LPMODE_48: - fpga_async_data = 0x10; - break; - case MODULE_LPMODE_49 ... MODULE_LPMODE_60: - fpga_async_data = 0x0; - break; - case MODULE_LPMODE_61 ... MODULE_LPMODE_72: - fpga_async_data = 0x01; - break; - case MODULE_RESET_1 ... MODULE_RESET_16: - fpga_async_data = 0x0; - break; - case MODULE_RESET_17 ... MODULE_RESET_32: - fpga_async_data = 0x20; - break; - case MODULE_RESET_33 ... MODULE_RESET_48: - fpga_async_data = 0x10; - break; - case MODULE_RESET_49 ... MODULE_RESET_60: - fpga_async_data = 0x0; - break; - case MODULE_RESET_61 ... MODULE_RESET_72: - fpga_async_data = 0x01; - break; - case MODULE_TX_DISABLE_73 ... MODULE_RX_LOS_76: - fpga_async_data = 0x10; - break; - default: - break; - } - - reg = attribute_mappings[attr->index].reg; - bar = attribute_mappings[attr->index].bar; - - LOCK(&cpld_access_lock); - if (bar == BAR4_NUM){ - iowrite8(fpga_async_data, async_reg); - reg_val = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr4 + reg, - SPI_BUSY_MASK_CPLD1); - } - else - { - iowrite8(fpga_async_data, async_reg); - reg_val = fpga_read(fpga_ctl->pci_fpga_dev.data_base_addr5 + reg, - SPI_BUSY_MASK_CPLD2); - } - UNLOCK(&cpld_access_lock); - bits_shift = attr->index - attribute_mappings[attr->index].attr_base; - reg_val = (reg_val >> bits_shift) & 0x01; - - if (attribute_mappings[attr->index].revert) - reg_val = !reg_val; - ret = sprintf(buf, "%u\n", reg_val); - - return ret; -} - -static ssize_t status_write(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct as9947_72xkb_fpga_data *fpga_ctl = dev_get_drvdata(dev); - void __iomem *addr; - int status; - u16 reg, bar; - u8 input, fpga_async_data; - u8 reg_val, bit_mask, should_set_bit; - u32 spi_mask; - - status = kstrtou8(buf, 10, &input); - if (status) { - return status; - } - - reg = attribute_mappings[attr->index].reg; - bar = attribute_mappings[attr->index].bar; - switch(attr->index) - { - case MODULE_LPMODE_1 ... MODULE_LPMODE_16: - fpga_async_data = 0x0; - break; - case MODULE_LPMODE_17 ... MODULE_LPMODE_32: - fpga_async_data = 0x20; - break; - case MODULE_LPMODE_33 ... MODULE_LPMODE_48: - fpga_async_data = 0x10; - break; - case MODULE_LPMODE_49 ... MODULE_LPMODE_60: - fpga_async_data = 0x0; - break; - case MODULE_LPMODE_61 ... MODULE_LPMODE_72: - fpga_async_data = 0x01; - break; - case MODULE_RESET_1 ... MODULE_RESET_16: - fpga_async_data = 0x0; - break; - case MODULE_RESET_17 ... MODULE_RESET_32: - fpga_async_data = 0x20; - break; - case MODULE_RESET_33 ... MODULE_RESET_48: - fpga_async_data = 0x10; - break; - case MODULE_RESET_49 ... MODULE_RESET_60: - fpga_async_data = 0x0; - break; - case MODULE_RESET_61 ... MODULE_RESET_72: - fpga_async_data = 0x01; - break; - case MODULE_TX_DISABLE_73 ... MODULE_RX_LOS_76: - fpga_async_data = 0x10; - break; - default: - break; - } - - if (bar == BAR4_NUM){ - spi_mask = SPI_BUSY_MASK_CPLD1; - addr = fpga_ctl->pci_fpga_dev.data_base_addr4; - } - else - { - spi_mask = SPI_BUSY_MASK_CPLD2; - addr = fpga_ctl->pci_fpga_dev.data_base_addr5; - } - - bit_mask = 0x01 << (attr->index - attribute_mappings[attr->index].attr_base); - should_set_bit = attribute_mappings[attr->index].revert ? !input : input; - - LOCK(&cpld_access_lock); - iowrite8(fpga_async_data, async_reg); - reg_val = fpga_read(addr + reg, spi_mask); - if (should_set_bit) { - reg_val |= bit_mask; - } else { - reg_val &= ~bit_mask; - } - fpga_write(addr + reg, reg_val, spi_mask); - UNLOCK(&cpld_access_lock); - - return count; -} - struct _port_data { u16 offset; u16 mask; /* SPI Busy mask : 0x01 --> CPLD1, 0x02 --> CPLD2 */ @@ -1128,10 +397,6 @@ static int as9947_72xkb_pcie_fpga_stat_probe(struct platform_device *pdev) goto exit_ocores_device; } } - status = sysfs_create_group(&pdev->dev.kobj, &fpga_port_stat_group); - if (status) { - goto exit_ocores_device; - } return 0; @@ -1161,8 +426,6 @@ static int as9947_72xkb_pcie_fpga_stat_remove(struct platform_device *pdev) if (pci_is_enabled(fpga_ctl->pci_fpga_dev.pci_dev)) { int i; - - sysfs_remove_group(&pdev->dev.kobj, &fpga_port_stat_group); /* Unregister ocore_i2c device */ for (i = 0; i < PORT_NUM; i++) { platform_device_unregister(fpga_ctl->pci_fpga_dev.fpga_i2c[i]); diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sfp.c b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sfp.c new file mode 100644 index 0000000000..5f385a430c --- /dev/null +++ b/packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/x86-64-accton-as9947-72xkb-sfp.c @@ -0,0 +1,1277 @@ +/* + * Copyright (C) Willy Liu + * + * 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 "accton_ipmi_intf.h" + +#define DRVNAME "as9947_72xkb_sfp" +/* SFP */ +#define IPMI_SFP_READ_CMD 0x1C +#define IPMI_SFP_WRITE_CMD 0x1D + +#define IPMI_SFP_PRESENT_CMD 0x10 +#define IPMI_SFP_TXDIS_CMD 0x1 +#define IPMI_SFP_TXFAULT_CMD 0x12 +#define IPMI_SFP_RXLOS_CMD 0x13 +/* QSFP */ +#define IPMI_QSFP_READ_CMD 0x10 +#define IPMI_QSFP_WRITE_CMD 0x11 + +#define IPMI_QSFP_PRESENT_CMD 0x10 +#define IPMI_QSFP_RESET_CMD 0x11 +#define IPMI_QSFP_LPMODE_CMD 0x12 + +#define IPMI_DATA_MAX_LEN 128 + +#define NUM_OF_SFP 4 +#define NUM_OF_QSFP 72 +#define NUM_OF_PORT (NUM_OF_SFP + NUM_OF_QSFP) + +static ssize_t set_sfp_txdisable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_sfp(struct device *dev, struct device_attribute *da, char *buf); + +static ssize_t set_qsfp_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_qsfp_lpmode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_qsfp(struct device *dev, struct device_attribute *da, char *buf); +static int as9947_72xkb_sfp_probe(struct platform_device *pdev); +static int as9947_72xkb_sfp_remove(struct platform_device *pdev); +static ssize_t show_all(struct device *dev, struct device_attribute *da, char *buf); +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_present(void); +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_txdisable(void); +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_txfault(void); +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_rxlos(void); +static struct as9947_72xkb_sfp_data *as9947_72xkb_qsfp_update_present(void); +static struct as9947_72xkb_sfp_data *as9947_72xkb_qsfp_update_lpmode(void); +static struct as9947_72xkb_sfp_data *as9947_72xkb_qsfp_update_reset(void); + +enum module_status { + SFP_PRESENT = 0, + SFP_TXDISABLE, + SFP_TXFAULT, + SFP_RXLOS, + NUM_OF_SFP_STATUS, + + QSFP_PRESENT = 0, + QSFP_RESET, + QSFP_LPMODE, + NUM_OF_QSFP_STATUS, + + PRESENT_ALL = 0, + RXLOS_ALL, +}; + +struct ipmi_sfp_resp_data { + char sfp_valid[NUM_OF_SFP_STATUS]; /* != 0 if registers are valid */ + unsigned long sfp_last_updated[NUM_OF_SFP_STATUS]; /* In jiffies */ + unsigned char sfp_resp[NUM_OF_SFP_STATUS][NUM_OF_SFP]; /* 0: present, 1: tx-disable + 2: tx-fault, 3: rx-los */ + char qsfp_valid[NUM_OF_QSFP_STATUS]; /* != 0 if registers are valid */ + unsigned long qsfp_last_updated[NUM_OF_QSFP_STATUS]; /* In jiffies */ + unsigned char qsfp_resp[NUM_OF_QSFP_STATUS][NUM_OF_QSFP]; /* 0: present, 1: reset, + 2: low power mode */ +}; + +struct as9947_72xkb_sfp_data { + struct platform_device *pdev; + struct mutex update_lock; + struct ipmi_data ipmi; + struct ipmi_sfp_resp_data ipmi_resp; + unsigned char ipmi_tx_data[3]; +}; + +struct as9947_72xkb_sfp_data *data = NULL; + +static struct platform_driver as9947_72xkb_sfp_driver = { + .probe = as9947_72xkb_sfp_probe, + .remove = as9947_72xkb_sfp_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +#define SFP_PRESENT_ATTR_ID(port) SFP##port##_PRESENT +#define SFP_TXDISABLE_ATTR_ID(port) SFP##port##_TXDISABLE +#define SFP_TXFAULT_ATTR_ID(port) SFP##port##_TXFAULT +#define SFP_RXLOS_ATTR_ID(port) SFP##port##_RXLOS + +#define SFP_ATTR(port) \ + SFP_PRESENT_ATTR_ID(port), \ + SFP_TXDISABLE_ATTR_ID(port), \ + SFP_TXFAULT_ATTR_ID(port), \ + SFP_RXLOS_ATTR_ID(port) + +#define QSFP_PRESENT_ATTR_ID(port) QSFP##port##_PRESENT +#define QSFP_RESET_ATTR_ID(port) QSFP##port##_RESET +#define QSFP_LPMODE_ATTR_ID(port) QSFP##port##_LPMODE + +#define QSFP_ATTR(port) \ + QSFP_PRESENT_ATTR_ID(port), \ + QSFP_RESET_ATTR_ID(port), \ + QSFP_LPMODE_ATTR_ID(port) + + +enum as9947_72xkb_qsfp_sysfs_attrs { + QSFP_ATTR(1), + QSFP_ATTR(2), + QSFP_ATTR(3), + QSFP_ATTR(4), + QSFP_ATTR(5), + QSFP_ATTR(6), + QSFP_ATTR(7), + QSFP_ATTR(8), + QSFP_ATTR(9), + QSFP_ATTR(10), + QSFP_ATTR(11), + QSFP_ATTR(12), + QSFP_ATTR(13), + QSFP_ATTR(14), + QSFP_ATTR(15), + QSFP_ATTR(16), + QSFP_ATTR(17), + QSFP_ATTR(18), + QSFP_ATTR(19), + QSFP_ATTR(20), + QSFP_ATTR(21), + QSFP_ATTR(22), + QSFP_ATTR(23), + QSFP_ATTR(24), + QSFP_ATTR(25), + QSFP_ATTR(26), + QSFP_ATTR(27), + QSFP_ATTR(28), + QSFP_ATTR(29), + QSFP_ATTR(30), + QSFP_ATTR(31), + QSFP_ATTR(32), + QSFP_ATTR(33), + QSFP_ATTR(34), + QSFP_ATTR(35), + QSFP_ATTR(36), + QSFP_ATTR(37), + QSFP_ATTR(38), + QSFP_ATTR(39), + QSFP_ATTR(40), + QSFP_ATTR(41), + QSFP_ATTR(42), + QSFP_ATTR(43), + QSFP_ATTR(44), + QSFP_ATTR(45), + QSFP_ATTR(46), + QSFP_ATTR(47), + QSFP_ATTR(48), + QSFP_ATTR(49), + QSFP_ATTR(50), + QSFP_ATTR(51), + QSFP_ATTR(52), + QSFP_ATTR(53), + QSFP_ATTR(54), + QSFP_ATTR(55), + QSFP_ATTR(56), + QSFP_ATTR(57), + QSFP_ATTR(58), + QSFP_ATTR(59), + QSFP_ATTR(60), + QSFP_ATTR(61), + QSFP_ATTR(62), + QSFP_ATTR(63), + QSFP_ATTR(64), + QSFP_ATTR(65), + QSFP_ATTR(66), + QSFP_ATTR(67), + QSFP_ATTR(68), + QSFP_ATTR(69), + QSFP_ATTR(70), + QSFP_ATTR(71), + QSFP_ATTR(72), + NUM_OF_QSFP_ATTR, + NUM_OF_PER_QSFP_ATTR = (NUM_OF_QSFP_ATTR/NUM_OF_QSFP), +}; + +enum as9947_72xkb_sfp_sysfs_attrs { + SFP_ATTR(73), + SFP_ATTR(74), + SFP_ATTR(75), + SFP_ATTR(76), + NUM_OF_SFP_ATTR, + NUM_OF_PER_SFP_ATTR = (NUM_OF_SFP_ATTR/NUM_OF_SFP), +}; + +/* sfp attributes */ +#define DECLARE_SFP_SENSOR_DEVICE_ATTR(port) \ + static SENSOR_DEVICE_ATTR(module_present_##port, S_IRUGO, show_sfp, NULL, SFP##port##_PRESENT); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##port, S_IWUSR | S_IRUGO, show_sfp, set_sfp_txdisable, SFP##port##_TXDISABLE); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##port, S_IRUGO, show_sfp, NULL, SFP##port##_TXFAULT); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##port, S_IRUGO, show_sfp, NULL, SFP##port##_RXLOS) +#define DECLARE_SFP_ATTR(port) \ + &sensor_dev_attr_module_present_##port.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##port.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##port.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##port.dev_attr.attr + +/* qsfp attributes */ +#define DECLARE_QSFP_SENSOR_DEVICE_ATTR(port) \ + static SENSOR_DEVICE_ATTR(module_present_##port, S_IRUGO, show_qsfp, NULL, QSFP##port##_PRESENT); \ + static SENSOR_DEVICE_ATTR(module_reset_##port, S_IWUSR | S_IRUGO, show_qsfp, set_qsfp_reset, QSFP##port##_RESET); \ + static SENSOR_DEVICE_ATTR(module_lpmode_##port, S_IWUSR | S_IRUGO, show_qsfp, set_qsfp_lpmode, QSFP##port##_LPMODE) +#define DECLARE_QSFP_ATTR(port) \ + &sensor_dev_attr_module_present_##port.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##port.dev_attr.attr, \ + &sensor_dev_attr_module_lpmode_##port.dev_attr.attr +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_all, NULL, PRESENT_ALL); +static SENSOR_DEVICE_ATTR(module_rxlos_all, S_IRUGO, show_all, NULL, RXLOS_ALL); + +DECLARE_QSFP_SENSOR_DEVICE_ATTR(1); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(2); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(3); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(4); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(5); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(6); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(7); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(8); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(9); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(10); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(11); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(12); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(13); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(14); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(15); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(16); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(17); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(18); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(19); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(20); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(21); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(22); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(23); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(24); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(25); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(26); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(27); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(28); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(29); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(30); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(31); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(32); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(33); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(34); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(35); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(36); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(37); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(38); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(39); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(40); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(41); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(42); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(43); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(44); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(45); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(46); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(47); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(48); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(54); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(55); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(56); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(57); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(58); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(59); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(60); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(61); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(62); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(63); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(64); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(65); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(66); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(67); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(68); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(69); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(70); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(71); +DECLARE_QSFP_SENSOR_DEVICE_ATTR(72); +DECLARE_SFP_SENSOR_DEVICE_ATTR(73); +DECLARE_SFP_SENSOR_DEVICE_ATTR(74); +DECLARE_SFP_SENSOR_DEVICE_ATTR(75); +DECLARE_SFP_SENSOR_DEVICE_ATTR(76); + +static struct attribute *as9947_72xkb_sfp_attributes[] = { + /* sfp attributes */ + DECLARE_QSFP_ATTR(1), + DECLARE_QSFP_ATTR(2), + DECLARE_QSFP_ATTR(3), + DECLARE_QSFP_ATTR(4), + DECLARE_QSFP_ATTR(5), + DECLARE_QSFP_ATTR(6), + DECLARE_QSFP_ATTR(7), + DECLARE_QSFP_ATTR(8), + DECLARE_QSFP_ATTR(9), + DECLARE_QSFP_ATTR(10), + DECLARE_QSFP_ATTR(11), + DECLARE_QSFP_ATTR(12), + DECLARE_QSFP_ATTR(13), + DECLARE_QSFP_ATTR(14), + DECLARE_QSFP_ATTR(15), + DECLARE_QSFP_ATTR(16), + DECLARE_QSFP_ATTR(17), + DECLARE_QSFP_ATTR(18), + DECLARE_QSFP_ATTR(19), + DECLARE_QSFP_ATTR(20), + DECLARE_QSFP_ATTR(21), + DECLARE_QSFP_ATTR(22), + DECLARE_QSFP_ATTR(23), + DECLARE_QSFP_ATTR(24), + DECLARE_QSFP_ATTR(25), + DECLARE_QSFP_ATTR(26), + DECLARE_QSFP_ATTR(27), + DECLARE_QSFP_ATTR(28), + DECLARE_QSFP_ATTR(29), + DECLARE_QSFP_ATTR(30), + DECLARE_QSFP_ATTR(31), + DECLARE_QSFP_ATTR(32), + DECLARE_QSFP_ATTR(33), + DECLARE_QSFP_ATTR(34), + DECLARE_QSFP_ATTR(35), + DECLARE_QSFP_ATTR(36), + DECLARE_QSFP_ATTR(37), + DECLARE_QSFP_ATTR(38), + DECLARE_QSFP_ATTR(39), + DECLARE_QSFP_ATTR(40), + DECLARE_QSFP_ATTR(41), + DECLARE_QSFP_ATTR(42), + DECLARE_QSFP_ATTR(43), + DECLARE_QSFP_ATTR(44), + DECLARE_QSFP_ATTR(45), + DECLARE_QSFP_ATTR(46), + DECLARE_QSFP_ATTR(47), + DECLARE_QSFP_ATTR(48), + DECLARE_QSFP_ATTR(49), + DECLARE_QSFP_ATTR(50), + DECLARE_QSFP_ATTR(51), + DECLARE_QSFP_ATTR(52), + DECLARE_QSFP_ATTR(53), + DECLARE_QSFP_ATTR(54), + DECLARE_QSFP_ATTR(55), + DECLARE_QSFP_ATTR(56), + DECLARE_QSFP_ATTR(57), + DECLARE_QSFP_ATTR(58), + DECLARE_QSFP_ATTR(59), + DECLARE_QSFP_ATTR(60), + DECLARE_QSFP_ATTR(61), + DECLARE_QSFP_ATTR(62), + DECLARE_QSFP_ATTR(63), + DECLARE_QSFP_ATTR(64), + DECLARE_QSFP_ATTR(65), + DECLARE_QSFP_ATTR(66), + DECLARE_QSFP_ATTR(67), + DECLARE_QSFP_ATTR(68), + DECLARE_QSFP_ATTR(69), + DECLARE_QSFP_ATTR(70), + DECLARE_QSFP_ATTR(71), + DECLARE_QSFP_ATTR(72), + DECLARE_SFP_ATTR(73), + DECLARE_SFP_ATTR(74), + DECLARE_SFP_ATTR(75), + DECLARE_SFP_ATTR(76), + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rxlos_all.dev_attr.attr, + NULL +}; + +static const struct attribute_group as9947_72xkb_sfp_group = { + .attrs = as9947_72xkb_sfp_attributes, +}; + +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_present(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.sfp_last_updated[SFP_PRESENT] + HZ) && + data->ipmi_resp.sfp_valid[SFP_PRESENT]) { + return data; + } + + data->ipmi_resp.sfp_valid[SFP_PRESENT] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_SFP_PRESENT_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_SFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.sfp_resp[SFP_PRESENT], + sizeof(data->ipmi_resp.sfp_resp[SFP_PRESENT])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.sfp_last_updated[SFP_PRESENT] = jiffies; + data->ipmi_resp.sfp_valid[SFP_PRESENT] = 1; + +exit: + return data; +} + +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_txdisable(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.sfp_last_updated[SFP_TXDISABLE] + HZ * 5) && + data->ipmi_resp.sfp_valid[SFP_TXDISABLE]) { + return data; + } + + data->ipmi_resp.sfp_valid[SFP_TXDISABLE] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_SFP_TXDIS_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_SFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.sfp_resp[SFP_TXDISABLE], + sizeof(data->ipmi_resp.sfp_resp[SFP_TXDISABLE])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.sfp_last_updated[SFP_TXDISABLE] = jiffies; + data->ipmi_resp.sfp_valid[SFP_TXDISABLE] = 1; + +exit: + return data; +} + +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_txfault(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.sfp_last_updated[SFP_TXFAULT] + HZ * 5) && + data->ipmi_resp.sfp_valid[SFP_TXFAULT]) { + return data; + } + + data->ipmi_resp.sfp_valid[SFP_TXFAULT] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_SFP_TXFAULT_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_SFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.sfp_resp[SFP_TXFAULT], + sizeof(data->ipmi_resp.sfp_resp[SFP_TXFAULT])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.sfp_last_updated[SFP_TXFAULT] = jiffies; + data->ipmi_resp.sfp_valid[SFP_TXFAULT] = 1; + +exit: + return data; +} + +static struct as9947_72xkb_sfp_data *as9947_72xkb_sfp_update_rxlos(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.sfp_last_updated[SFP_RXLOS] + HZ * 5) && + data->ipmi_resp.sfp_valid[SFP_RXLOS]) { + return data; + } + + data->ipmi_resp.sfp_valid[SFP_RXLOS] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_SFP_RXLOS_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_SFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.sfp_resp[SFP_RXLOS], + sizeof(data->ipmi_resp.sfp_resp[SFP_RXLOS])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.sfp_last_updated[SFP_RXLOS] = jiffies; + data->ipmi_resp.sfp_valid[SFP_RXLOS] = 1; + +exit: + return data; +} + +static struct as9947_72xkb_sfp_data *as9947_72xkb_qsfp_update_present(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.qsfp_last_updated[QSFP_PRESENT] + HZ) && + data->ipmi_resp.qsfp_valid[QSFP_PRESENT]) { + return data; + } + + data->ipmi_resp.qsfp_valid[QSFP_PRESENT] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_QSFP_PRESENT_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_QSFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.qsfp_resp[QSFP_PRESENT], + sizeof(data->ipmi_resp.qsfp_resp[QSFP_PRESENT])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.qsfp_last_updated[QSFP_PRESENT] = jiffies; + data->ipmi_resp.qsfp_valid[QSFP_PRESENT] = 1; + +exit: + return data; +} + +static struct as9947_72xkb_sfp_data *as9947_72xkb_qsfp_update_reset(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.qsfp_last_updated[QSFP_RESET] + HZ * 5) && + data->ipmi_resp.qsfp_valid[QSFP_RESET]) { + return data; + } + + data->ipmi_resp.qsfp_valid[QSFP_RESET] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_QSFP_RESET_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_QSFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.qsfp_resp[QSFP_RESET], + sizeof(data->ipmi_resp.qsfp_resp[QSFP_RESET])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.qsfp_last_updated[QSFP_RESET] = jiffies; + data->ipmi_resp.qsfp_valid[QSFP_RESET] = 1; + +exit: + return data; +} + +static struct as9947_72xkb_sfp_data *as9947_72xkb_qsfp_update_lpmode(void) +{ + int status = 0; + + if (time_before(jiffies, data->ipmi_resp.qsfp_last_updated[QSFP_LPMODE] + HZ * 5) && + data->ipmi_resp.qsfp_valid[QSFP_LPMODE]) { + return data; + } + + data->ipmi_resp.qsfp_valid[QSFP_LPMODE] = 0; + + /* Get status from ipmi */ + data->ipmi_tx_data[0] = IPMI_QSFP_LPMODE_CMD; + status = ipmi_send_message(&data->ipmi, IPMI_QSFP_READ_CMD, + data->ipmi_tx_data, 1, + data->ipmi_resp.qsfp_resp[QSFP_LPMODE], + sizeof(data->ipmi_resp.qsfp_resp[QSFP_LPMODE])); + if (unlikely(status != 0)) { + goto exit; + } + + if (unlikely(data->ipmi.rx_result != 0)) { + status = -EIO; + goto exit; + } + + data->ipmi_resp.qsfp_last_updated[QSFP_LPMODE] = jiffies; + data->ipmi_resp.qsfp_valid[QSFP_LPMODE] = 1; + +exit: + return data; +} + +static ssize_t show_all(struct device *dev, struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u8 qsfp_values[9] = {0}; + u8 sfp_values = 0; + int i, byte, bit; + + switch (attr->index) { + case PRESENT_ALL: + { + mutex_lock(&data->update_lock); + + data = as9947_72xkb_sfp_update_present(); + if (!data->ipmi_resp.sfp_valid[SFP_PRESENT]) { + mutex_unlock(&data->update_lock); + return -EIO; + } + + data = as9947_72xkb_qsfp_update_present(); + if (!data->ipmi_resp.qsfp_valid[QSFP_PRESENT]) { + mutex_unlock(&data->update_lock); + return -EIO; + } + mutex_unlock(&data->update_lock); + /* need to check QSFP bit value */ + /* Update qsfp present status port 0-71 */ + for (i = (NUM_OF_QSFP-1); i >= 0; i--) { + /* 0~8 */ + byte = i / 8; + /* 0~7 */ + bit = i % 8; + if (data->ipmi_resp.qsfp_resp[QSFP_PRESENT][i] & 0x1) + qsfp_values[byte] |= (1 << bit); + + } + /* Update sfp present status, port 72-75 */ + for (i = (NUM_OF_SFP-1); i >= 0; i--) { + sfp_values <<= 1; + sfp_values |= (data->ipmi_resp.sfp_resp[SFP_PRESENT][i] & 0x1); + } + /* Return values 1 -> 76 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", + (unsigned int)(0xFF & qsfp_values[0]), + (unsigned int)(0xFF & qsfp_values[1]), + (unsigned int)(0xFF & qsfp_values[2]), + (unsigned int)(0xFF & qsfp_values[3]), + (unsigned int)(0xFF & qsfp_values[4]), + (unsigned int)(0xFF & qsfp_values[5]), + (unsigned int)(0xFF & qsfp_values[6]), + (unsigned int)(0xFF & qsfp_values[7]), + (unsigned int)(0xFF & qsfp_values[8]), + (unsigned int)(0x0F & sfp_values)); + } + case RXLOS_ALL: + { + mutex_lock(&data->update_lock); + + data = as9947_72xkb_sfp_update_rxlos(); + if (!data->ipmi_resp.sfp_valid[SFP_RXLOS]) { + mutex_unlock(&data->update_lock); + return -EIO; + } + + /* Update sfp rxlos status */ + for (i = (NUM_OF_SFP-1); i >= 0; i--) { + sfp_values <<= 1; + sfp_values |= (data->ipmi_resp.sfp_resp[SFP_RXLOS][i] & 0x1); + } + + mutex_unlock(&data->update_lock); + + /* Return values 1 -> 4(port 73-76 ) in order */ + return sprintf(buf, "%.2x\n", + (unsigned int)(0x0F & sfp_values)); + } + default: + break; + } + + return 0; +} + +static ssize_t show_sfp(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_SFP_ATTR; /* port id, 0 based */ + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + switch (attr->index) { + case SFP73_PRESENT: + case SFP74_PRESENT: + case SFP75_PRESENT: + case SFP76_PRESENT: + { + data = as9947_72xkb_sfp_update_present(); + if (!data->ipmi_resp.sfp_valid[SFP_PRESENT]) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp.sfp_resp[SFP_PRESENT][pid]; + break; + } + case SFP73_TXDISABLE: + case SFP74_TXDISABLE: + case SFP75_TXDISABLE: + case SFP76_TXDISABLE: + { + data = as9947_72xkb_sfp_update_txdisable(); + if (!data->ipmi_resp.sfp_valid[SFP_TXDISABLE]) { + error = -EIO; + goto exit; + } + + value = !data->ipmi_resp.sfp_resp[SFP_TXDISABLE][pid]; + break; + } + case SFP73_TXFAULT: + case SFP74_TXFAULT: + case SFP75_TXFAULT: + case SFP76_TXFAULT: + { + data = as9947_72xkb_sfp_update_txfault(); + if (!data->ipmi_resp.sfp_valid[SFP_TXFAULT]) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp.sfp_resp[SFP_TXFAULT][pid]; + break; + } + case SFP73_RXLOS: + case SFP74_RXLOS: + case SFP75_RXLOS: + case SFP76_RXLOS: + { + data = as9947_72xkb_sfp_update_rxlos(); + if (!data->ipmi_resp.sfp_valid[SFP_RXLOS]) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp.sfp_resp[SFP_RXLOS][pid]; + break; + } + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_sfp_txdisable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long disable; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_SFP_ATTR; /* port id, 0 based */ + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + disable = !disable; /* the IPMI cmd is 0 for tx-disable and 1 for tx-enable */ + + mutex_lock(&data->update_lock); + + /* Send IPMI write command */ + data->ipmi_tx_data[0] = pid + 1; /* Port ID base id for ipmi start from 1 */ + data->ipmi_tx_data[1] = IPMI_SFP_TXDIS_CMD; + data->ipmi_tx_data[2] = disable; + status = ipmi_send_message(&data->ipmi, IPMI_SFP_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 to ipmi_resp buffer to prevent from the impact of lazy update */ + data->ipmi_resp.sfp_resp[SFP_TXDISABLE][pid] = disable; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_qsfp(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_QSFP_ATTR; /* port id, 0 based */ + int value = 0; + int error = 0; + + mutex_lock(&data->update_lock); + + switch (attr->index) { + case QSFP1_PRESENT: + case QSFP2_PRESENT: + case QSFP3_PRESENT: + case QSFP4_PRESENT: + case QSFP5_PRESENT: + case QSFP6_PRESENT: + case QSFP7_PRESENT: + case QSFP8_PRESENT: + case QSFP9_PRESENT: + case QSFP10_PRESENT: + case QSFP11_PRESENT: + case QSFP12_PRESENT: + case QSFP13_PRESENT: + case QSFP14_PRESENT: + case QSFP15_PRESENT: + case QSFP16_PRESENT: + case QSFP17_PRESENT: + case QSFP18_PRESENT: + case QSFP19_PRESENT: + case QSFP20_PRESENT: + case QSFP21_PRESENT: + case QSFP22_PRESENT: + case QSFP23_PRESENT: + case QSFP24_PRESENT: + case QSFP25_PRESENT: + case QSFP26_PRESENT: + case QSFP27_PRESENT: + case QSFP28_PRESENT: + case QSFP29_PRESENT: + case QSFP30_PRESENT: + case QSFP31_PRESENT: + case QSFP32_PRESENT: + case QSFP33_PRESENT: + case QSFP34_PRESENT: + case QSFP35_PRESENT: + case QSFP36_PRESENT: + case QSFP37_PRESENT: + case QSFP38_PRESENT: + case QSFP39_PRESENT: + case QSFP40_PRESENT: + case QSFP41_PRESENT: + case QSFP42_PRESENT: + case QSFP43_PRESENT: + case QSFP44_PRESENT: + case QSFP45_PRESENT: + case QSFP46_PRESENT: + case QSFP47_PRESENT: + case QSFP48_PRESENT: + case QSFP49_PRESENT: + case QSFP50_PRESENT: + case QSFP51_PRESENT: + case QSFP52_PRESENT: + case QSFP53_PRESENT: + case QSFP54_PRESENT: + case QSFP55_PRESENT: + case QSFP56_PRESENT: + case QSFP57_PRESENT: + case QSFP58_PRESENT: + case QSFP59_PRESENT: + case QSFP60_PRESENT: + case QSFP61_PRESENT: + case QSFP62_PRESENT: + case QSFP63_PRESENT: + case QSFP64_PRESENT: + case QSFP65_PRESENT: + case QSFP66_PRESENT: + case QSFP67_PRESENT: + case QSFP68_PRESENT: + case QSFP69_PRESENT: + case QSFP70_PRESENT: + case QSFP71_PRESENT: + case QSFP72_PRESENT: + { + data = as9947_72xkb_qsfp_update_present(); + if (!data->ipmi_resp.qsfp_valid[QSFP_PRESENT]) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp.qsfp_resp[QSFP_PRESENT][pid]; + break; + } + case QSFP1_RESET: + case QSFP2_RESET: + case QSFP3_RESET: + case QSFP4_RESET: + case QSFP5_RESET: + case QSFP6_RESET: + case QSFP7_RESET: + case QSFP8_RESET: + case QSFP9_RESET: + case QSFP10_RESET: + case QSFP11_RESET: + case QSFP12_RESET: + case QSFP13_RESET: + case QSFP14_RESET: + case QSFP15_RESET: + case QSFP16_RESET: + case QSFP17_RESET: + case QSFP18_RESET: + case QSFP19_RESET: + case QSFP20_RESET: + case QSFP21_RESET: + case QSFP22_RESET: + case QSFP23_RESET: + case QSFP24_RESET: + case QSFP25_RESET: + case QSFP26_RESET: + case QSFP27_RESET: + case QSFP28_RESET: + case QSFP29_RESET: + case QSFP30_RESET: + case QSFP31_RESET: + case QSFP32_RESET: + case QSFP33_RESET: + case QSFP34_RESET: + case QSFP35_RESET: + case QSFP36_RESET: + case QSFP37_RESET: + case QSFP38_RESET: + case QSFP39_RESET: + case QSFP40_RESET: + case QSFP41_RESET: + case QSFP42_RESET: + case QSFP43_RESET: + case QSFP44_RESET: + case QSFP45_RESET: + case QSFP46_RESET: + case QSFP47_RESET: + case QSFP48_RESET: + case QSFP49_RESET: + case QSFP50_RESET: + case QSFP51_RESET: + case QSFP52_RESET: + case QSFP53_RESET: + case QSFP54_RESET: + case QSFP55_RESET: + case QSFP56_RESET: + case QSFP57_RESET: + case QSFP58_RESET: + case QSFP59_RESET: + case QSFP60_RESET: + case QSFP61_RESET: + case QSFP62_RESET: + case QSFP63_RESET: + case QSFP64_RESET: + case QSFP65_RESET: + case QSFP66_RESET: + case QSFP67_RESET: + case QSFP68_RESET: + case QSFP69_RESET: + case QSFP70_RESET: + case QSFP71_RESET: + case QSFP72_RESET: + { + data = as9947_72xkb_qsfp_update_reset(); + if (!data->ipmi_resp.qsfp_valid[QSFP_RESET]) { + error = -EIO; + goto exit; + } + + value = !data->ipmi_resp.qsfp_resp[QSFP_RESET][pid]; + break; + } + case QSFP1_LPMODE: + case QSFP2_LPMODE: + case QSFP3_LPMODE: + case QSFP4_LPMODE: + case QSFP5_LPMODE: + case QSFP6_LPMODE: + case QSFP7_LPMODE: + case QSFP8_LPMODE: + case QSFP9_LPMODE: + case QSFP10_LPMODE: + case QSFP11_LPMODE: + case QSFP12_LPMODE: + case QSFP13_LPMODE: + case QSFP14_LPMODE: + case QSFP15_LPMODE: + case QSFP16_LPMODE: + case QSFP17_LPMODE: + case QSFP18_LPMODE: + case QSFP19_LPMODE: + case QSFP20_LPMODE: + case QSFP21_LPMODE: + case QSFP22_LPMODE: + case QSFP23_LPMODE: + case QSFP24_LPMODE: + case QSFP25_LPMODE: + case QSFP26_LPMODE: + case QSFP27_LPMODE: + case QSFP28_LPMODE: + case QSFP29_LPMODE: + case QSFP30_LPMODE: + case QSFP31_LPMODE: + case QSFP32_LPMODE: + case QSFP33_LPMODE: + case QSFP34_LPMODE: + case QSFP35_LPMODE: + case QSFP36_LPMODE: + case QSFP37_LPMODE: + case QSFP38_LPMODE: + case QSFP39_LPMODE: + case QSFP40_LPMODE: + case QSFP41_LPMODE: + case QSFP42_LPMODE: + case QSFP43_LPMODE: + case QSFP44_LPMODE: + case QSFP45_LPMODE: + case QSFP46_LPMODE: + case QSFP47_LPMODE: + case QSFP48_LPMODE: + case QSFP49_LPMODE: + case QSFP50_LPMODE: + case QSFP51_LPMODE: + case QSFP52_LPMODE: + case QSFP53_LPMODE: + case QSFP54_LPMODE: + case QSFP55_LPMODE: + case QSFP56_LPMODE: + case QSFP57_LPMODE: + case QSFP58_LPMODE: + case QSFP59_LPMODE: + case QSFP60_LPMODE: + case QSFP61_LPMODE: + case QSFP62_LPMODE: + case QSFP63_LPMODE: + case QSFP64_LPMODE: + case QSFP65_LPMODE: + case QSFP66_LPMODE: + case QSFP67_LPMODE: + case QSFP68_LPMODE: + case QSFP69_LPMODE: + case QSFP70_LPMODE: + case QSFP71_LPMODE: + case QSFP72_LPMODE: + { + data = as9947_72xkb_qsfp_update_lpmode(); + if (!data->ipmi_resp.qsfp_valid[QSFP_LPMODE]) { + error = -EIO; + goto exit; + } + + value = data->ipmi_resp.qsfp_resp[QSFP_LPMODE][pid]; + break; + } + default: + error = -EINVAL; + goto exit; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", value); + +exit: + mutex_unlock(&data->update_lock); + return error; +} + +static ssize_t set_qsfp_reset(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long reset; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_QSFP_ATTR; /* port id, 0 based */ + + status = kstrtol(buf, 10, &reset); + if (status) { + return status; + } + + reset = !reset; /* the IPMI cmd is 0 for reset and 1 for out of reset */ + + mutex_lock(&data->update_lock); + + /* Send IPMI write command */ + data->ipmi_tx_data[0] = pid + 1; /* Port ID base id for ipmi start from 1 */ + data->ipmi_tx_data[1] = IPMI_QSFP_RESET_CMD; + data->ipmi_tx_data[2] = reset; + status = ipmi_send_message(&data->ipmi, IPMI_QSFP_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 to ipmi_resp buffer to prevent from the impact of lazy update */ + data->ipmi_resp.qsfp_resp[QSFP_RESET][pid] = reset; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_qsfp_lpmode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long lpmode; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + unsigned char pid = attr->index / NUM_OF_PER_QSFP_ATTR; /* port id, 0 based */ + + status = kstrtol(buf, 10, &lpmode); + if (status) { + return status; + } + + mutex_lock(&data->update_lock); + + /* Send IPMI write command */ + data->ipmi_tx_data[0] = pid + 1; /* Port ID base id for ipmi start from 1 */ + data->ipmi_tx_data[1] = IPMI_QSFP_LPMODE_CMD; + data->ipmi_tx_data[2] = lpmode; /* 0: High Power Mode, 1: Low Power Mode */ + status = ipmi_send_message(&data->ipmi, IPMI_QSFP_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 to ipmi_resp buffer to prevent from the impact of lazy update */ + data->ipmi_resp.qsfp_resp[QSFP_LPMODE][pid] = lpmode; + status = count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static int as9947_72xkb_sfp_probe(struct platform_device *pdev) +{ + int status = -1; + + /* Register sysfs hooks */ + status = sysfs_create_group(&pdev->dev.kobj, &as9947_72xkb_sfp_group); + if (status) + goto exit; + + dev_info(&pdev->dev, "device created\n"); + + return 0; + +exit: + return status; +} + +static int as9947_72xkb_sfp_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &as9947_72xkb_sfp_group); + + return 0; +} + +static int __init as9947_72xkb_sfp_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as9947_72xkb_sfp_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + + ret = platform_driver_register(&as9947_72xkb_sfp_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(&as9947_72xkb_sfp_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as9947_72xkb_sfp_exit(void) +{ + ipmi_destroy_user(data->ipmi.user); + platform_device_unregister(data->pdev); + platform_driver_unregister(&as9947_72xkb_sfp_driver); + kfree(data); +} + +MODULE_AUTHOR("Willy Liu "); +MODULE_DESCRIPTION("AS9947-72XKB sfp driver"); +MODULE_LICENSE("GPL"); + +module_init(as9947_72xkb_sfp_init); +module_exit(as9947_72xkb_sfp_exit); + diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c index ccad4d0945..2dcf58af94 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/sfpi.c @@ -29,29 +29,31 @@ #include "x86_64_accton_as9947_72xkb_int.h" #include "x86_64_accton_as9947_72xkb_log.h" +#define NUM_OF_PORT 76 +#define NUM_OF_QSFP_PORT 72 +#define NUM_OF_SFP_PORT 4 + + #define VALIDATE_SFP(_port) \ do { \ - if (_port < 73 || _port > 76) \ + if (_port < (NUM_OF_QSFP_PORT + 1) || _port > NUM_OF_PORT) \ return ONLP_STATUS_E_UNSUPPORTED; \ } while(0) #define VALIDATE_QSFP(_port) \ do { \ - if (_port < 1 || _port > 72 ) \ + if (_port < 1 || _port > NUM_OF_QSFP_PORT ) \ return ONLP_STATUS_E_UNSUPPORTED; \ } while(0) #define MODULE_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" -#define MODULE_PRESENT_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_present_%d" -#define MODULE_RXLOS_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_rx_los_%d" -#define MODULE_TXFAULT_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_tx_fault_%d" -#define MODULE_TXDISABLE_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_tx_disable_%d" -#define MODULE_RESET_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_reset_%d" -#define MODULE_LPMODE_FORMAT "/sys/devices/platform/as9947_72xkb_fpga/module_lp_mode_%d" +#define MODULE_PRESENT_FORMAT "/sys/devices/platform/as9947_72xkb_sfp/module_present_%d" +#define MODULE_RXLOS_FORMAT "/sys/devices/platform/as9947_72xkb_sfp/module_rx_los_%d" +#define MODULE_TXFAULT_FORMAT "/sys/devices/platform/as9947_72xkb_sfp/module_tx_fault_%d" +#define MODULE_TXDISABLE_FORMAT "/sys/devices/platform/as9947_72xkb_sfp/module_tx_disable_%d" +#define MODULE_RESET_FORMAT "/sys/devices/platform/as9947_72xkb_sfp/module_reset_%d" +#define MODULE_LPMODE_FORMAT "/sys/devices/platform/as9947_72xkb_sfp/module_lpmode_%d" -#define NUM_OF_PORT 76 -#define NUM_OF_QSFP_PORT 72 -#define NUM_OF_SFP_PORT 4 static const int port_bus_index[NUM_OF_PORT] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, @@ -116,7 +118,6 @@ int onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) } for (i = 73; i <= NUM_OF_PORT; i++) - { /* check present */ if (onlp_sfpi_is_present(i)) @@ -125,12 +126,17 @@ int onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", i); return ONLP_STATUS_E_INTERNAL; } - } - if (value) - AIM_BITMAP_MOD(dst, i, 1); + if (value) + AIM_BITMAP_MOD(dst, i, 1); + else + AIM_BITMAP_MOD(dst, i, 0); + + } else + { AIM_BITMAP_MOD(dst, i, 0); + } } return ONLP_STATUS_OK; diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py index c1050f906c..3096a8cdd6 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py +++ b/packages/platforms/accton/x86-64/as9947-72xkb/platform-config/r0/src/python/x86_64_accton_as9947_72xkb_r0/__init__.py @@ -83,7 +83,7 @@ def baseconfig(self): self.modprobe('optoe') self.modprobe('accton_ipmi_intf') - for m in [ 'i2c-ocores', 'fpga', 'fan', 'psu', 'thermal', 'sys', 'leds']: + for m in [ 'i2c-ocores', 'fpga', 'sfp', 'fan', 'psu', 'thermal', 'sys', 'leds']: self.insmod("x86-64-accton-as9947-72xkb-%s" % m) # QSFP From 3501440e2810355c38689e0667d7242918797ee0 Mon Sep 17 00:00:00 2001 From: Willy Liu Date: Thu, 11 Dec 2025 09:14:01 +0000 Subject: [PATCH 5/5] [ACCTON][AS9947-72XKB] Fix max speed of front fan and rear fan Signed-off-by: Willy Liu --- .../onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c index 8cce5e9d07..9e9228e445 100644 --- a/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c +++ b/packages/platforms/accton/x86-64/as9947-72xkb/onlp/builds/x86_64_accton_as9947_72xkb/module/src/fani.c @@ -48,8 +48,8 @@ enum fan_id { FAN_1_ON_PSU_2 }; -#define MAX_1U_FRONT_FAN_SPEED 28000 -#define MAX_1U_REAR_FAN_SPEED 31000 +#define MAX_1U_FRONT_FAN_SPEED 18000 +#define MAX_1U_REAR_FAN_SPEED 21500 #define MAX_2U_FRONT_FAN_SPEED 13600 #define MAX_2U_REAR_FAN_SPEED 15400 #define MAX_PSU_FAN_SPEED 25500