From c1b7904d341644a1e2cb0713b49ca2c3b52d6011 Mon Sep 17 00:00:00 2001 From: Brandon Chuang Date: Thu, 21 Jun 2018 15:26:11 +0800 Subject: [PATCH 01/22] [as4610] Add support for OOM optoe driver --- .../arm-iproc-all/arm-iproc-all.config | 4 +- ...ch_arm_boot_dts_accton_as4610_54.dts.patch | 50 +- ...latform-accton-as4610-device-drivers.patch | 3805 +++++++++-------- .../r0/builds/dtb/arm-accton-as4610-54-r0.dts | 26 +- .../r0/builds/dtb/arm-accton-as4610-54-r0.dts | 26 +- .../src/arm_accton_as4610/module/src/sfpi.c | 165 +- 6 files changed, 2041 insertions(+), 2035 deletions(-) diff --git a/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/arm-iproc-all.config b/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/arm-iproc-all.config index e70dd3b3..6d420e0f 100644 --- a/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/arm-iproc-all.config +++ b/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/arm-iproc-all.config @@ -868,7 +868,7 @@ CONFIG_EEPROM_AT25=y # CONFIG_EEPROM_93CX6 is not set # CONFIG_EEPROM_93XX46 is not set # CONFIG_EEPROM_SFF_8436 is not set -CONFIG_EEPROM_ACCTON_AS4610_SFP=y +CONFIG_EEPROM_OPTOE=y # CONFIG_CB710_CORE is not set # CONFIG_IWMC3200TOP is not set @@ -1497,7 +1497,7 @@ CONFIG_SENSORS_W83781D=y # CONFIG_SENSORS_W83L786NG is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set -CONFIG_SENSORS_ACCTON_I2C_CPLD=y +CONFIG_SENSORS_ACCTON_AS4610_CPLD=y CONFIG_SENSORS_ACCTON_AS4610_FAN=y CONFIG_SENSORS_ACCTON_AS4610_PSU=y CONFIG_SENSORS_YM2651Y=y diff --git a/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/arch_arm_boot_dts_accton_as4610_54.dts.patch b/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/arch_arm_boot_dts_accton_as4610_54.dts.patch index 7737f9ef..5d5e0485 100644 --- a/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/arch_arm_boot_dts_accton_as4610_54.dts.patch +++ b/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/arch_arm_boot_dts_accton_as4610_54.dts.patch @@ -1,6 +1,6 @@ --- /dev/null +++ b/arch/arm/boot/dts/accton_as4610_54.dts -@@ -0,0 +1,250 @@ +@@ -0,0 +1,256 @@ +/* + * Accton AS4610 54 Device Tree Source + * @@ -117,7 +117,7 @@ + cpld@1,0 { + #address-cells = <1>; + #size-cells = <1>; -+ compatible = "accton,as4610-54-cpld"; ++ compatible = "accton,as4610_54_cpld"; + label = "cpld"; + reg = <0x30>; + }; @@ -142,8 +142,8 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; -+ sfp_eeprom@50 { -+ compatible = "at,24c04"; ++ optoe@50 { ++ compatible = "optoe2"; + reg = <0x50>; + label = "port49"; + }; @@ -154,8 +154,8 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; -+ sfp_eeprom@50 { -+ compatible = "at,24c04"; ++ optoe@50 { ++ compatible = "optoe2"; + reg = <0x50>; + label = "port50"; + }; @@ -166,8 +166,8 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; -+ sfp_eeprom@50 { -+ compatible = "at,24c04"; ++ optoe@50 { ++ compatible = "optoe2"; + reg = <0x50>; + label = "port51"; + }; @@ -178,8 +178,8 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; -+ sfp_eeprom@50 { -+ compatible = "at,24c04"; ++ optoe@50 { ++ compatible = "optoe2"; + reg = <0x50>; + label = "port52"; + }; @@ -190,9 +190,10 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <4>; -+ sfp_eeprom@50 { -+ compatible = "at,24c04"; ++ optoe@50 { ++ compatible = "optoe1"; + reg = <0x50>; ++ label = "port53"; + }; + }; + @@ -201,9 +202,10 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <5>; -+ sfp_eeprom@50 { -+ compatible = "at,24c04"; ++ optoe@50 { ++ compatible = "optoe1"; + reg = <0x50>; ++ label = "port54"; + }; + }; + @@ -212,17 +214,21 @@ + #address-cells = <1>; + #size-cells = <0>; + reg = <6>; -+ psu_eeprom@50 { -+ compatible = "at,24c02"; ++ psu1_eeprom@50 { ++ compatible = "accton,as4610_psu1"; + reg = <0x50>; -+ label = "psu1_eeprom"; -+ read-only; + }; -+ psu_eeprom@51 { -+ compatible = "at,24c02"; ++ psu1_pmbus@58 { ++ compatible = "3y-power,ym1921"; ++ reg = <0x58>; ++ }; ++ psu2_eeprom@51 { ++ compatible = "accton,as4610_psu2"; + reg = <0x51>; -+ label = "psu2_eeprom"; -+ read-only; ++ }; ++ psu2_pmbus@59 { ++ compatible = "3y-power,ym1921"; ++ reg = <0x59>; + }; + }; + diff --git a/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/platform-accton-as4610-device-drivers.patch b/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/platform-accton-as4610-device-drivers.patch index 66ba4882..3964bfac 100644 --- a/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/platform-accton-as4610-device-drivers.patch +++ b/packages/base/any/kernels/3.2-lts/configs/arm-iproc-all/patches/platform-accton-as4610-device-drivers.patch @@ -1,162 +1,5 @@ Device driver patches for accton as4610 54 (fan/psu/cpld/led/sfp) -diff --git a/arch/arm/boot/dts/accton_as4610_54.dts b/arch/arm/boot/dts/accton_as4610_54.dts -index 9276c0a..8848f8c 100644 ---- a/arch/arm/boot/dts/accton_as4610_54.dts -+++ b/arch/arm/boot/dts/accton_as4610_54.dts -@@ -105,46 +105,46 @@ - }; - - i2c0: i2c@18038000 { -- compatible = "iproc-smb"; -- reg = <0x18038000 0x1000>; -+ compatible = "iproc-smb"; -+ reg = <0x18038000 0x1000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ interrupts = < 127 >; -+ clock-frequency = <400000>; -+ cpld@1,0 { - #address-cells = <1>; -- #size-cells = <0>; -- interrupts = < 127 >; -- clock-frequency = <400000>; -- cpld@1,0 { -- #address-cells = <1>; -- #size-cells = <1>; -- compatible = "accton,as4610-54-cpld"; -- label = "cpld"; -- reg = <0x30>; -- }; -+ #size-cells = <1>; -+ compatible = "accton,as4610_54_cpld"; -+ label = "cpld"; -+ reg = <0x30>; -+ }; - }; - - i2c1: i2c@1803b000 { -- compatible = "iproc-smb"; -- reg = <0x1803b000 0x1000>; -+ compatible = "iproc-smb"; -+ reg = <0x1803b000 0x1000>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ interrupts = < 128 >; -+ clock-frequency = <100000>; -+ mux@70 { -+ compatible = "ti,pca9548"; -+ reg = <0x70>; - #address-cells = <1>; - #size-cells = <0>; -- interrupts = < 128 >; -- clock-frequency = <100000>; -- mux@70 { -- compatible = "ti,pca9548"; -- reg = <0x70>; -+ deselect-on-exit; -+ -+ // SFP+ 1 -+ i2c@0 { - #address-cells = <1>; - #size-cells = <0>; -- deselect-on-exit; -- -- // SFP+ 1 -- i2c@0 { -- #address-cells = <1>; -- #size-cells = <0>; -- reg = <0>; -- sfp_eeprom@50 { -- compatible = "at,24c04"; -- reg = <0x50>; -- label = "port49"; -- }; -+ reg = <0>; -+ sfp_eeprom@50 { -+ compatible = "at,as4610_sfp1"; -+ reg = <0x50>; -+ label = "port49"; - }; -+ }; - - // SFP+ 2 - i2c@1 { -@@ -152,7 +152,7 @@ - #size-cells = <0>; - reg = <1>; - sfp_eeprom@50 { -- compatible = "at,24c04"; -+ compatible = "accton,as4610_sfp2"; - reg = <0x50>; - label = "port50"; - }; -@@ -164,7 +164,7 @@ - #size-cells = <0>; - reg = <2>; - sfp_eeprom@50 { -- compatible = "at,24c04"; -+ compatible = "accton,as4610_sfp3"; - reg = <0x50>; - label = "port51"; - }; -@@ -176,7 +176,7 @@ - #size-cells = <0>; - reg = <3>; - sfp_eeprom@50 { -- compatible = "at,24c04"; -+ compatible = "accton,as4610_sfp4"; - reg = <0x50>; - label = "port52"; - }; -@@ -188,7 +188,7 @@ - #size-cells = <0>; - reg = <4>; - sfp_eeprom@50 { -- compatible = "at,24c04"; -+ compatible = "accton,as4610_sfp5"; - reg = <0x50>; - }; - }; -@@ -199,7 +199,7 @@ - #size-cells = <0>; - reg = <5>; - sfp_eeprom@50 { -- compatible = "at,24c04"; -+ compatible = "accton,as4610_sfp6"; - reg = <0x50>; - }; - }; -@@ -209,17 +209,21 @@ - #address-cells = <1>; - #size-cells = <0>; - reg = <6>; -- psu_eeprom@50 { -- compatible = "at,24c02"; -+ psu1_eeprom@50 { -+ compatible = "accton,as4610_psu1"; - reg = <0x50>; -- label = "psu1_eeprom"; -- read-only; - }; -- psu_eeprom@51 { -- compatible = "at,24c02"; -+ psu1_pmbus@58 { -+ compatible = "3y-power,ym1921"; -+ reg = <0x58>; -+ }; -+ psu2_eeprom@51 { -+ compatible = "accton,as4610_psu2"; - reg = <0x51>; -- label = "psu2_eeprom"; -- read-only; -+ }; -+ psu2_pmbus@59 { -+ compatible = "3y-power,ym1921"; -+ reg = <0x59>; - }; - }; - diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5c984a6..df89e25 100644 --- a/drivers/hwmon/Kconfig @@ -165,18 +8,18 @@ index 5c984a6..df89e25 100644 help Support for the A/D converter on MC13783 PMIC. -+config SENSORS_ACCTON_I2C_CPLD -+ tristate "Accton i2c cpld" ++config SENSORS_ACCTON_AS4610_CPLD ++ tristate "Accton as4610 cpld" + depends on I2C + help -+ If you say yes here you get support for Accton i2c cpld. ++ If you say yes here you get support for Accton as4610 cpld. + + This driver can also be built as a module. If so, the module will -+ be called accton_i2c_cpld. ++ be called accton_as4610_cpld. + +config SENSORS_ACCTON_AS4610_FAN + tristate "Accton as4610 fan" -+ depends on I2C && SENSORS_ACCTON_I2C_CPLD ++ depends on I2C && SENSORS_ACCTON_AS4610_CPLD + help + If you say yes here you get support for Accton as4610 fan. + @@ -185,7 +28,7 @@ index 5c984a6..df89e25 100644 + +config SENSORS_ACCTON_AS4610_PSU + tristate "Accton as4610 psu" -+ depends on I2C && SENSORS_ACCTON_I2C_CPLD ++ depends on I2C && SENSORS_ACCTON_AS4610_CPLD + help + If you say yes here you get support for Accton as4610 psu. + @@ -213,7 +56,7 @@ index ff3a18e..39c9888 100644 obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o -+obj-$(CONFIG_SENSORS_ACCTON_I2C_CPLD) += accton_i2c_cpld.o ++obj-$(CONFIG_SENSORS_ACCTON_AS4610_CPLD) += accton_as4610_cpld.o +obj-$(CONFIG_SENSORS_ACCTON_AS4610_FAN) += accton_as4610_fan.o +obj-$(CONFIG_SENSORS_ACCTON_AS4610_PSU) += accton_as4610_psu.o obj-$(CONFIG_SENSORS_AD7314) += ad7314.o @@ -227,12 +70,616 @@ index ff3a18e..39c9888 100644 obj-$(CONFIG_PMBUS) += pmbus/ +diff --git a/drivers/hwmon/accton_as4610_cpld.c b/drivers/hwmon/accton_as4610_cpld.c +new file mode 100644 +index 0000000..26b3ae5 +--- /dev/null ++++ b/drivers/hwmon/accton_as4610_cpld.c +@@ -0,0 +1,598 @@ ++/* ++ * Copyright (C) Brandon Chuang ++ * ++ * This module supports the accton cpld that hold the channel select ++ * mechanism for other i2c slave devices, such as SFP. ++ * This includes the: ++ * Accton as4610_54 CPLD ++ * ++ * 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 ++ ++#define I2C_RW_RETRY_COUNT 10 ++#define I2C_RW_RETRY_INTERVAL 60 /* ms */ ++ ++static LIST_HEAD(cpld_client_list); ++static struct mutex list_lock; ++ ++struct cpld_client_node { ++ struct i2c_client *client; ++ struct list_head list; ++}; ++ ++enum cpld_type { ++ as4610_54_cpld ++}; ++ ++struct as4610_54_cpld_data { ++ enum cpld_type type; ++ struct device *hwmon_dev; ++ struct mutex update_lock; ++}; ++ ++static const struct i2c_device_id as4610_54_cpld_id[] = { ++ { "as4610_54_cpld", as4610_54_cpld }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, as4610_54_cpld_id); ++ ++#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index ++#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index ++#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index ++#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index ++ ++enum as4610_54_cpld1_sysfs_attributes { ++ CPLD_VERSION, ++ PRODUCT_ID, ++ ACCESS, ++ MODULE_PRESENT_ALL, ++ MODULE_RXLOS_ALL, ++ /* 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_TXDISABLE_ATTR_ID(1), ++ TRANSCEIVER_TXDISABLE_ATTR_ID(2), ++ TRANSCEIVER_TXDISABLE_ATTR_ID(3), ++ TRANSCEIVER_TXDISABLE_ATTR_ID(4), ++ TRANSCEIVER_RXLOS_ATTR_ID(1), ++ TRANSCEIVER_RXLOS_ATTR_ID(2), ++ TRANSCEIVER_RXLOS_ATTR_ID(3), ++ TRANSCEIVER_RXLOS_ATTR_ID(4), ++ TRANSCEIVER_TXFAULT_ATTR_ID(1), ++ TRANSCEIVER_TXFAULT_ATTR_ID(2), ++ TRANSCEIVER_TXFAULT_ATTR_ID(3), ++ TRANSCEIVER_TXFAULT_ATTR_ID(4), ++}; ++ ++/* sysfs attributes for hwmon ++ */ ++static ssize_t show_status(struct device *dev, struct device_attribute *da, ++ char *buf); ++static ssize_t show_present_all(struct device *dev, struct device_attribute *da, ++ char *buf); ++static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, ++ char *buf); ++static ssize_t access(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count); ++static ssize_t show_version(struct device *dev, struct device_attribute *da, ++ char *buf); ++static ssize_t show_product_id(struct device *dev, struct device_attribute *attr, ++ char *buf); ++static int as4610_54_cpld_read_internal(struct i2c_client *client, u8 reg); ++static int as4610_54_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); ++ ++/* transceiver attributes */ ++#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \ ++ static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index) ++#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr ++ ++#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ ++ static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ ++ static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) ++ ++#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ ++ &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ ++ &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr ++ ++static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); ++static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); ++static SENSOR_DEVICE_ATTR(product_id, S_IRUGO, show_product_id, NULL, PRODUCT_ID); ++/* transceiver attributes */ ++static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL); ++static SENSOR_DEVICE_ATTR(module_rx_los_all, S_IRUGO, show_rxlos_all, NULL, MODULE_RXLOS_ALL); ++DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1); ++DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2); ++DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3); ++DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4); ++DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5); ++DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6); ++ ++DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); ++DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); ++DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); ++DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); ++ ++static struct attribute *as4610_54_cpld_attributes[] = { ++ &sensor_dev_attr_version.dev_attr.attr, ++ &sensor_dev_attr_access.dev_attr.attr, ++ /* transceiver attributes */ ++ &sensor_dev_attr_module_present_all.dev_attr.attr, ++ &sensor_dev_attr_module_rx_los_all.dev_attr.attr, ++ DECLARE_TRANSCEIVER_PRESENT_ATTR(1), ++ DECLARE_TRANSCEIVER_PRESENT_ATTR(2), ++ DECLARE_TRANSCEIVER_PRESENT_ATTR(3), ++ DECLARE_TRANSCEIVER_PRESENT_ATTR(4), ++ DECLARE_TRANSCEIVER_PRESENT_ATTR(5), ++ DECLARE_TRANSCEIVER_PRESENT_ATTR(6), ++ DECLARE_SFP_TRANSCEIVER_ATTR(1), ++ DECLARE_SFP_TRANSCEIVER_ATTR(2), ++ DECLARE_SFP_TRANSCEIVER_ATTR(3), ++ DECLARE_SFP_TRANSCEIVER_ATTR(4), ++ NULL ++}; ++ ++static const struct attribute_group as4610_54_cpld_group = { ++ .attrs = as4610_54_cpld_attributes, ++}; ++ ++static ssize_t show_present_all(struct device *dev, struct device_attribute *da, ++ char *buf) ++{ ++ int i, status, present = 0; ++ u8 values[3] = {0}; ++ u8 regs[] = {0x2, 0x3, 0x21}; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct as4610_54_cpld_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->update_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ status = as4610_54_cpld_read_internal(client, regs[i]); ++ ++ if (status < 0) { ++ goto exit; ++ } ++ ++ switch (i) { ++ case 0: ++ present |= (status & BIT(6)) >> 6; /* port 25/49 */ ++ present |= (status & BIT(2)) >> 1; /* port 26/50 */ ++ break; ++ case 1: ++ present |= (status & BIT(6)) >> 4; /* port 27/51 */ ++ present |= (status & BIT(2)) << 1; /* port 28/52 */ ++ break; ++ case 2: ++ present |= (status & BIT(0)) << 4; /* port 29/53 */ ++ present |= (status & BIT(4)) << 1; /* port 30/54 */ ++ break; ++ default: ++ break; ++ } ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ return sprintf(buf, "%.2x\n", present); ++ ++exit: ++ mutex_unlock(&data->update_lock); ++ return status; ++} ++ ++static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, ++ char *buf) ++{ ++ int i, status, rx_los = 0; ++ u8 values[2] = {0}; ++ u8 regs[] = {0x2, 0x3}; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct as4610_54_cpld_data *data = i2c_get_clientdata(client); ++ ++ mutex_lock(&data->update_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ status = as4610_54_cpld_read_internal(client, regs[i]); ++ ++ if (status < 0) { ++ goto exit; ++ } ++ switch (i) { ++ case 0: ++ rx_los |= (status & BIT(4)) >> 4; /* port 25/49 rx_los */ ++ rx_los |= (status & BIT(0)) << 1; /* port 26/50 rx_los */ ++ break; ++ case 1: ++ rx_los |= (status & BIT(4)) >> 2; /* port 27/51 rx_los */ ++ rx_los |= (status & BIT(0)) << 3; /* port 28/52 rx_los */ ++ break; ++ default: ++ break; ++ } ++ } ++ ++ mutex_unlock(&data->update_lock); ++ ++ /* Return values 25/49 -> 28/52 in order */ ++ return sprintf(buf, "%.2x\n", rx_los); ++ ++exit: ++ mutex_unlock(&data->update_lock); ++ return status; ++} ++ ++static ssize_t show_status(struct device *dev, struct device_attribute *da, ++ char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); ++ struct i2c_client *client = to_i2c_client(dev); ++ struct as4610_54_cpld_data *data = i2c_get_clientdata(client); ++ int status = 0; ++ u8 reg = 0, mask = 0, revert = 0; ++ ++ switch (attr->index) { ++ case MODULE_PRESENT_1: ++ reg = 0x2; ++ mask = 0x40; ++ break; ++ case MODULE_PRESENT_2: ++ reg = 0x2; ++ mask = 0x4; ++ break; ++ case MODULE_PRESENT_3: ++ reg = 0x3; ++ mask = 0x40; ++ break; ++ case MODULE_PRESENT_4: ++ reg = 0x3; ++ mask = 0x4; ++ break; ++ case MODULE_PRESENT_5: ++ reg = 0x21; ++ mask = 0x1; ++ break; ++ case MODULE_PRESENT_6: ++ reg = 0x21; ++ mask = 0x10; ++ break; ++ case MODULE_TXFAULT_1: ++ reg = 0x2; ++ mask = 0x20; ++ break; ++ case MODULE_TXFAULT_2: ++ reg = 0x2; ++ mask = 0x2; ++ break; ++ case MODULE_TXFAULT_3: ++ reg = 0x3; ++ mask = 0x20; ++ break; ++ case MODULE_TXFAULT_4: ++ reg = 0x3; ++ mask = 0x2; ++ break; ++ case MODULE_RXLOS_1: ++ reg = 0x2; ++ mask = 0x10; ++ break; ++ case MODULE_RXLOS_2: ++ reg = 0x2; ++ mask = 0x1; ++ break; ++ case MODULE_RXLOS_3: ++ reg = 0x3; ++ mask = 0x10; ++ break; ++ case MODULE_RXLOS_4: ++ reg = 0x3; ++ mask = 0x1; ++ break; ++ default: ++ return 0; ++ } ++ ++ mutex_lock(&data->update_lock); ++ status = as4610_54_cpld_read_internal(client, reg); ++ if (unlikely(status < 0)) { ++ goto exit; ++ } ++ mutex_unlock(&data->update_lock); ++ ++ return sprintf(buf, "%d\n", !!(status & mask)); ++ ++exit: ++ mutex_unlock(&data->update_lock); ++ return status; ++} ++ ++static ssize_t access(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count) ++{ ++ int status; ++ u32 addr, val; ++ struct i2c_client *client = to_i2c_client(dev); ++ struct as4610_54_cpld_data *data = i2c_get_clientdata(client); ++ ++ if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { ++ return -EINVAL; ++ } ++ ++ if (addr > 0xFF || val > 0xFF) { ++ return -EINVAL; ++ } ++ ++ mutex_lock(&data->update_lock); ++ status = as4610_54_cpld_write_internal(client, addr, val); ++ if (unlikely(status < 0)) { ++ goto exit; ++ } ++ mutex_unlock(&data->update_lock); ++ return count; ++ ++exit: ++ mutex_unlock(&data->update_lock); ++ return status; ++} ++ ++static void as4610_54_cpld_add_client(struct i2c_client *client) ++{ ++ struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); ++ ++ if (!node) { ++ dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); ++ return; ++ } ++ ++ node->client = client; ++ ++ mutex_lock(&list_lock); ++ list_add(&node->list, &cpld_client_list); ++ mutex_unlock(&list_lock); ++} ++ ++static void as4610_54_cpld_remove_client(struct i2c_client *client) ++{ ++ struct list_head *list_node = NULL; ++ struct cpld_client_node *cpld_node = NULL; ++ int found = 0; ++ ++ mutex_lock(&list_lock); ++ ++ list_for_each(list_node, &cpld_client_list) ++ { ++ cpld_node = list_entry(list_node, struct cpld_client_node, list); ++ ++ if (cpld_node->client == client) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (found) { ++ list_del(list_node); ++ kfree(cpld_node); ++ } ++ ++ mutex_unlock(&list_lock); ++} ++ ++static ssize_t show_product_id(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ val = i2c_smbus_read_byte_data(client, 0x1); ++ if (val < 0) { ++ dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); ++ } ++ ++ return sprintf(buf, "%d\n", (val & 0xF)); ++} ++ ++static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int val = 0; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ val = i2c_smbus_read_byte_data(client, 0xB); ++ ++ if (val < 0) { ++ dev_dbg(&client->dev, "cpld(0x%x) reg(0xB) err %d\n", client->addr, val); ++ } ++ ++ return sprintf(buf, "%d", val); ++} ++ ++/* I2C init/probing/exit functions */ ++static int as4610_54_cpld_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); ++ struct as4610_54_cpld_data *data; ++ int ret = -ENODEV; ++ const struct attribute_group *group = NULL; ++ ++ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) ++ goto exit; ++ ++ data = kzalloc(sizeof(struct as4610_54_cpld_data), GFP_KERNEL); ++ if (!data) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ i2c_set_clientdata(client, data); ++ mutex_init(&data->update_lock); ++ data->type = id->driver_data; ++ /* Bring QSFPs out of reset */ ++ as4610_54_cpld_write_internal(client, 0x2A, 0); ++ ++ ret = sysfs_create_group(&client->dev.kobj, &as4610_54_cpld_group); ++ if (ret) { ++ goto exit_free; ++ } ++ ++ as4610_54_cpld_add_client(client); ++ return 0; ++ ++exit_free: ++ kfree(data); ++exit: ++ return ret; ++} ++ ++static int as4610_54_cpld_remove(struct i2c_client *client) ++{ ++ struct as4610_54_cpld_data *data = i2c_get_clientdata(client); ++ const struct attribute_group *group = NULL; ++ ++ as4610_54_cpld_remove_client(client); ++ ++ /* Remove sysfs hooks */ ++ sysfs_remove_group(&client->dev.kobj, &as4610_54_cpld_group); ++ kfree(data); ++ ++ return 0; ++} ++ ++static int as4610_54_cpld_read_internal(struct i2c_client *client, u8 reg) ++{ ++ int status = 0, retry = I2C_RW_RETRY_COUNT; ++ ++ while (retry) { ++ status = i2c_smbus_read_byte_data(client, reg); ++ if (unlikely(status < 0)) { ++ msleep(I2C_RW_RETRY_INTERVAL); ++ retry--; ++ continue; ++ } ++ ++ break; ++ } ++ ++ return status; ++} ++ ++static int as4610_54_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) ++{ ++ int status = 0, retry = I2C_RW_RETRY_COUNT; ++ ++ while (retry) { ++ status = i2c_smbus_write_byte_data(client, reg, value); ++ if (unlikely(status < 0)) { ++ msleep(I2C_RW_RETRY_INTERVAL); ++ retry--; ++ continue; ++ } ++ ++ break; ++ } ++ ++ return status; ++} ++ ++int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg) ++{ ++ struct list_head *list_node = NULL; ++ struct cpld_client_node *cpld_node = NULL; ++ int ret = -EPERM; ++ ++ mutex_lock(&list_lock); ++ ++ list_for_each(list_node, &cpld_client_list) ++ { ++ cpld_node = list_entry(list_node, struct cpld_client_node, list); ++ ++ if (cpld_node->client->addr == cpld_addr) { ++ ret = as4610_54_cpld_read_internal(cpld_node->client, reg); ++ break; ++ } ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(as4610_54_cpld_read); ++ ++int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) ++{ ++ struct list_head *list_node = NULL; ++ struct cpld_client_node *cpld_node = NULL; ++ int ret = -EIO; ++ ++ mutex_lock(&list_lock); ++ ++ list_for_each(list_node, &cpld_client_list) ++ { ++ cpld_node = list_entry(list_node, struct cpld_client_node, list); ++ ++ if (cpld_node->client->addr == cpld_addr) { ++ ret = as4610_54_cpld_write_internal(cpld_node->client, reg, value); ++ break; ++ } ++ } ++ ++ mutex_unlock(&list_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(as4610_54_cpld_write); ++ ++static struct i2c_driver as4610_54_cpld_driver = { ++ .driver = { ++ .name = "as4610_54_cpld", ++ .owner = THIS_MODULE, ++ }, ++ .probe = as4610_54_cpld_probe, ++ .remove = as4610_54_cpld_remove, ++ .id_table = as4610_54_cpld_id, ++}; ++ ++static int __init as4610_54_cpld_init(void) ++{ ++ mutex_init(&list_lock); ++ return i2c_add_driver(&as4610_54_cpld_driver); ++} ++ ++static void __exit as4610_54_cpld_exit(void) ++{ ++ i2c_del_driver(&as4610_54_cpld_driver); ++} ++ ++MODULE_AUTHOR("Brandon Chuang "); ++MODULE_DESCRIPTION("Accton I2C CPLD driver"); ++MODULE_LICENSE("GPL"); ++ ++module_init(as4610_54_cpld_init); ++module_exit(as4610_54_cpld_exit); ++ diff --git a/drivers/hwmon/accton_as4610_fan.c b/drivers/hwmon/accton_as4610_fan.c new file mode 100644 -index 0000000..3934bcd +index 0000000..612d5df --- /dev/null +++ b/drivers/hwmon/accton_as4610_fan.c -@@ -0,0 +1,344 @@ +@@ -0,0 +1,345 @@ +/* + * A hwmon driver for the Accton as4610 fan + * @@ -272,9 +719,10 @@ index 0000000..3934bcd +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); ++extern int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg); ++extern int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + -+/* fan related data, the index should match sysfs_fan_attributes -+ */ ++/* fan related data, the index should match sysfs_fan_attributes */ +static const u8 fan_reg[] = { + 0x2B, /* fan PWM(for all fan) */ + 0x2D, /* fan 1 speed(rpm) */ @@ -347,91 +795,91 @@ index 0000000..3934bcd + +static int as4610_fan_read_value(u8 reg) +{ -+ return accton_i2c_cpld_read(AS4610_CPLD_SLAVE_ADDR, reg); ++ return as4610_54_cpld_read(AS4610_CPLD_SLAVE_ADDR, reg); +} + +static int as4610_fan_write_value(u8 reg, u8 value) +{ -+ return accton_i2c_cpld_write(AS4610_CPLD_SLAVE_ADDR, reg, value); ++ return as4610_54_cpld_write(AS4610_CPLD_SLAVE_ADDR, reg, value); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ -+ reg_val &= FAN_DUTY_CYCLE_REG_MASK; -+ return (u32)((reg_val * 125 + 5)/10); ++ reg_val &= FAN_DUTY_CYCLE_REG_MASK; ++ return (u32)((reg_val * 125 + 5)/10); +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ -+ return ((u32)duty_cycle * 10 / 125); ++ return ((u32)duty_cycle * 10 / 125); +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ -+ /* Count Frequency is 1.515KHz= 0.66ms -+ * Count Period = 400 cycle = 400*0.66ms = 264ms -+ * R.P.M value = read value x3.79*60/2 -+ * 3.79 = 1000ms/264ms -+ * 60 = 1min =60s -+ * 2 = 1 rotation of fan has two pulses. -+ */ -+ return (u32)reg_val * 379 * 60 / 2 / 100; ++ /* Count Frequency is 1.515KHz= 0.66ms ++ * Count Period = 400 cycle = 400*0.66ms = 264ms ++ * R.P.M value = read value x3.79*60/2 ++ * 3.79 = 1000ms/264ms ++ * 60 = 1min =60s ++ * 2 = 1 rotation of fan has two pulses. ++ */ ++ return (u32)reg_val * 379 * 60 / 2 / 100; +} + +static u8 is_fan_fault(struct as4610_fan_data *data, enum fan_id id) +{ -+ u8 mask = (id == FAN1_ID) ? 0x20 : 0x10; ++ u8 mask = (id == FAN1_ID) ? 0x20 : 0x10; + -+ return !(data->reg_val[FAN_FAULT] & mask); ++ return !(data->reg_val[FAN_FAULT] & mask); +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ -+ int error, value; ++ int error, value; + -+ error = kstrtoint(buf, 10, &value); -+ if (error) -+ return error; ++ error = kstrtoint(buf, 10, &value); ++ if (error) ++ return error; + -+ if (value < 0 || value > FAN_MAX_DUTY_CYCLE) -+ return -EINVAL; ++ if (value < 0 || value > FAN_MAX_DUTY_CYCLE) ++ return -EINVAL; + -+ as4610_fan_write_value(fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); -+ return count; ++ as4610_fan_write_value(fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); ++ return count; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct as4610_fan_data *data = as4610_fan_update_device(dev); -+ ssize_t ret = 0; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); ++ struct as4610_fan_data *data = as4610_fan_update_device(dev); ++ ssize_t ret = 0; + -+ if (data->valid) { -+ switch (attr->index) { -+ case FAN_DUTY_CYCLE_PERCENTAGE: -+ { -+ u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[attr->index]); -+ ret = sprintf(buf, "%u\n", duty_cycle); -+ break; -+ } -+ case FAN1_SPEED_RPM: -+ case FAN2_SPEED_RPM: -+ ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); -+ break; -+ case FAN1_FAULT: -+ case FAN2_FAULT: -+ ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); -+ break; -+ default: -+ break; -+ } -+ } ++ if (data->valid) { ++ switch (attr->index) { ++ case FAN_DUTY_CYCLE_PERCENTAGE: ++ { ++ u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[attr->index]); ++ ret = sprintf(buf, "%u\n", duty_cycle); ++ break; ++ } ++ case FAN1_SPEED_RPM: ++ case FAN2_SPEED_RPM: ++ ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); ++ break; ++ case FAN1_FAULT: ++ case FAN2_FAULT: ++ ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); ++ break; ++ default: ++ break; ++ } ++ } + -+ return ret; ++ return ret; +} + +static const struct attribute_group as4610_fan_group = { @@ -440,73 +888,73 @@ index 0000000..3934bcd + +static struct as4610_fan_data *as4610_fan_update_device(struct device *dev) +{ -+ mutex_lock(&fan_data->update_lock); ++ mutex_lock(&fan_data->update_lock); + -+ if (time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) || -+ !fan_data->valid) { -+ int i; ++ if (time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) || ++ !fan_data->valid) { ++ int i; + -+ dev_dbg(fan_data->hwmon_dev, "Starting as4610_fan update\n"); -+ fan_data->valid = 0; ++ dev_dbg(fan_data->hwmon_dev, "Starting as4610_fan update\n"); ++ fan_data->valid = 0; + -+ /* Update fan data -+ */ -+ for (i = 0; i < ARRAY_SIZE(fan_data->reg_val); i++) { -+ int status = as4610_fan_read_value(fan_reg[i]); ++ /* Update fan data ++ */ ++ for (i = 0; i < ARRAY_SIZE(fan_data->reg_val); i++) { ++ int status = as4610_fan_read_value(fan_reg[i]); + -+ if (status < 0) { -+ fan_data->valid = 0; -+ mutex_unlock(&fan_data->update_lock); -+ dev_dbg(fan_data->hwmon_dev, "reg %d, err %d\n", fan_reg[i], status); -+ return fan_data; -+ } -+ else { -+ fan_data->reg_val[i] = status; -+ } -+ } ++ if (status < 0) { ++ fan_data->valid = 0; ++ mutex_unlock(&fan_data->update_lock); ++ dev_dbg(fan_data->hwmon_dev, "reg %d, err %d\n", fan_reg[i], status); ++ return fan_data; ++ } ++ else { ++ fan_data->reg_val[i] = status; ++ } ++ } + -+ fan_data->last_updated = jiffies; -+ fan_data->valid = 1; -+ } ++ fan_data->last_updated = jiffies; ++ fan_data->valid = 1; ++ } + -+ mutex_unlock(&fan_data->update_lock); ++ mutex_unlock(&fan_data->update_lock); + -+ return fan_data; ++ return fan_data; +} + +static int as4610_fan_probe(struct platform_device *pdev) +{ -+ int status = -1; ++ int status = -1; + -+ /* Register sysfs hooks */ -+ status = sysfs_create_group(&pdev->dev.kobj, &as4610_fan_group); -+ if (status) { -+ goto exit; ++ /* Register sysfs hooks */ ++ status = sysfs_create_group(&pdev->dev.kobj, &as4610_fan_group); ++ if (status) { ++ goto exit; + -+ } ++ } + -+ fan_data->hwmon_dev = hwmon_device_register(&pdev->dev); -+ if (IS_ERR(fan_data->hwmon_dev)) { -+ status = PTR_ERR(fan_data->hwmon_dev); -+ goto exit_remove; -+ } ++ fan_data->hwmon_dev = hwmon_device_register(&pdev->dev); ++ if (IS_ERR(fan_data->hwmon_dev)) { ++ status = PTR_ERR(fan_data->hwmon_dev); ++ goto exit_remove; ++ } + -+ dev_info(&pdev->dev, "accton_as4610_fan\n"); ++ dev_info(&pdev->dev, "accton_as4610_fan\n"); + -+ return 0; ++ return 0; + +exit_remove: -+ sysfs_remove_group(&pdev->dev.kobj, &as4610_fan_group); ++ sysfs_remove_group(&pdev->dev.kobj, &as4610_fan_group); +exit: -+ return status; ++ return status; +} + +static int as4610_fan_remove(struct platform_device *pdev) +{ -+ hwmon_device_unregister(fan_data->hwmon_dev); -+ sysfs_remove_group(&pdev->dev.kobj, &as4610_fan_group); ++ hwmon_device_unregister(fan_data->hwmon_dev); ++ sysfs_remove_group(&pdev->dev.kobj, &as4610_fan_group); + -+ return 0; ++ return 0; +} + +static const struct i2c_device_id as4610_fan_id[] = { @@ -526,48 +974,48 @@ index 0000000..3934bcd + +static int __init as4610_fan_init(void) +{ -+ int ret; ++ int ret; + -+ if (as4610_number_of_system_fan() == 0) { -+ return -ENODEV; -+ } ++ if (as4610_number_of_system_fan() == 0) { ++ return -ENODEV; ++ } + -+ ret = platform_driver_register(&as4610_fan_driver); -+ if (ret < 0) { -+ goto exit; -+ } ++ ret = platform_driver_register(&as4610_fan_driver); ++ if (ret < 0) { ++ goto exit; ++ } + -+ fan_data = kzalloc(sizeof(struct as4610_fan_data), GFP_KERNEL); -+ if (!fan_data) { -+ ret = -ENOMEM; -+ platform_driver_unregister(&as4610_fan_driver); -+ goto exit; -+ } ++ fan_data = kzalloc(sizeof(struct as4610_fan_data), GFP_KERNEL); ++ if (!fan_data) { ++ ret = -ENOMEM; ++ platform_driver_unregister(&as4610_fan_driver); ++ goto exit; ++ } + -+ mutex_init(&fan_data->update_lock); -+ fan_data->valid = 0; ++ mutex_init(&fan_data->update_lock); ++ fan_data->valid = 0; + -+ fan_data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); -+ if (IS_ERR(fan_data->pdev)) { -+ ret = PTR_ERR(fan_data->pdev); -+ platform_driver_unregister(&as4610_fan_driver); -+ kfree(fan_data); -+ goto exit; -+ } ++ fan_data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); ++ if (IS_ERR(fan_data->pdev)) { ++ ret = PTR_ERR(fan_data->pdev); ++ platform_driver_unregister(&as4610_fan_driver); ++ kfree(fan_data); ++ goto exit; ++ } + +exit: -+ return ret; ++ return ret; +} + +static void __exit as4610_fan_exit(void) +{ -+ if (!fan_data) { -+ return; -+ } ++ if (!fan_data) { ++ return; ++ } + -+ platform_device_unregister(fan_data->pdev); -+ platform_driver_unregister(&as4610_fan_driver); -+ kfree(fan_data); ++ platform_device_unregister(fan_data->pdev); ++ platform_driver_unregister(&as4610_fan_driver); ++ kfree(fan_data); +} + +late_initcall(as4610_fan_init); @@ -579,7 +1027,7 @@ index 0000000..3934bcd + diff --git a/drivers/hwmon/accton_as4610_psu.c b/drivers/hwmon/accton_as4610_psu.c new file mode 100644 -index 0000000..1f0d79d +index 0000000..68f0348 --- /dev/null +++ b/drivers/hwmon/accton_as4610_psu.c @@ -0,0 +1,286 @@ @@ -622,7 +1070,7 @@ index 0000000..1f0d79d +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); +static int as4610_psu_read_data(struct i2c_client *client, u8 command, u8 *data,int data_len); -+extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); ++extern int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ @@ -655,100 +1103,100 @@ index 0000000..1f0d79d +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); + +static struct attribute *as4610_psu_attributes[] = { -+ &sensor_dev_attr_psu_present.dev_attr.attr, -+ &sensor_dev_attr_psu_model_name.dev_attr.attr, -+ &sensor_dev_attr_psu_power_good.dev_attr.attr, -+ NULL ++ &sensor_dev_attr_psu_present.dev_attr.attr, ++ &sensor_dev_attr_psu_model_name.dev_attr.attr, ++ &sensor_dev_attr_psu_power_good.dev_attr.attr, ++ NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct as4610_psu_data *data = as4610_psu_update_device(dev); -+ u8 status = 0; ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); ++ struct as4610_psu_data *data = as4610_psu_update_device(dev); ++ u8 status = 0; + -+ if (attr->index == PSU_PRESENT) { -+ status = (data->status >> (data->index*2) & 0x1); -+ } -+ else { /* PSU_POWER_GOOD */ -+ status = (data->status >> (data->index*2 + 1) & 0x1); -+ } ++ if (attr->index == PSU_PRESENT) { ++ status = (data->status >> (data->index*2) & 0x1); ++ } ++ else { /* PSU_POWER_GOOD */ ++ status = (data->status >> (data->index*2 + 1) & 0x1); ++ } + -+ return sprintf(buf, "%d\n", status); ++ return sprintf(buf, "%d\n", status); +} + +static ssize_t show_model_name(struct device *dev, struct device_attribute *da, -+ char *buf) ++ char *buf) +{ -+ struct as4610_psu_data *data = as4610_psu_update_device(dev); ++ struct as4610_psu_data *data = as4610_psu_update_device(dev); + -+ return sprintf(buf, "%s\n", data->model_name); ++ return sprintf(buf, "%s\n", data->model_name); +} + +static const struct attribute_group as4610_psu_group = { -+ .attrs = as4610_psu_attributes, ++ .attrs = as4610_psu_attributes, +}; + +static int as4610_psu_probe(struct i2c_client *client, -+ const struct i2c_device_id *dev_id) ++ const struct i2c_device_id *dev_id) +{ -+ struct as4610_psu_data *data; -+ int status; ++ struct as4610_psu_data *data; ++ int status; + -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -+ status = -EIO; -+ goto exit; -+ } ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { ++ status = -EIO; ++ goto exit; ++ } + -+ data = kzalloc(sizeof(struct as4610_psu_data), GFP_KERNEL); -+ if (!data) { -+ status = -ENOMEM; -+ goto exit; -+ } ++ data = kzalloc(sizeof(struct as4610_psu_data), GFP_KERNEL); ++ if (!data) { ++ status = -ENOMEM; ++ goto exit; ++ } + -+ i2c_set_clientdata(client, data); -+ data->valid = 0; -+ data->index = dev_id->driver_data; -+ mutex_init(&data->update_lock); ++ i2c_set_clientdata(client, data); ++ data->valid = 0; ++ data->index = dev_id->driver_data; ++ mutex_init(&data->update_lock); + -+ dev_info(&client->dev, "chip found\n"); ++ dev_info(&client->dev, "chip found\n"); + -+ /* Register sysfs hooks */ -+ status = sysfs_create_group(&client->dev.kobj, &as4610_psu_group); -+ if (status) { -+ goto exit_free; -+ } ++ /* Register sysfs hooks */ ++ status = sysfs_create_group(&client->dev.kobj, &as4610_psu_group); ++ if (status) { ++ goto exit_free; ++ } + -+ data->hwmon_dev = hwmon_device_register(&client->dev); -+ if (IS_ERR(data->hwmon_dev)) { -+ status = PTR_ERR(data->hwmon_dev); -+ goto exit_remove; -+ } ++ data->hwmon_dev = hwmon_device_register(&client->dev); ++ if (IS_ERR(data->hwmon_dev)) { ++ status = PTR_ERR(data->hwmon_dev); ++ goto exit_remove; ++ } + -+ dev_info(&client->dev, "%s: psu '%s'\n", -+ dev_name(data->hwmon_dev), client->name); ++ dev_info(&client->dev, "%s: psu '%s'\n", ++ dev_name(data->hwmon_dev), client->name); + -+ return 0; ++ return 0; + +exit_remove: -+ sysfs_remove_group(&client->dev.kobj, &as4610_psu_group); ++ sysfs_remove_group(&client->dev.kobj, &as4610_psu_group); +exit_free: -+ kfree(data); ++ kfree(data); +exit: + -+ return status; ++ return status; +} + +static int as4610_psu_remove(struct i2c_client *client) +{ -+ struct as4610_psu_data *data = i2c_get_clientdata(client); ++ struct as4610_psu_data *data = i2c_get_clientdata(client); + -+ hwmon_device_unregister(data->hwmon_dev); -+ sysfs_remove_group(&client->dev.kobj, &as4610_psu_group); -+ kfree(data); ++ hwmon_device_unregister(data->hwmon_dev); ++ sysfs_remove_group(&client->dev.kobj, &as4610_psu_group); ++ kfree(data); + -+ return 0; ++ return 0; +} + +enum psu_index @@ -778,88 +1226,88 @@ index 0000000..1f0d79d +static int as4610_psu_read_data(struct i2c_client *client, u8 command, u8 *data, + int count) +{ -+ int status = 0; ++ int status = 0; + -+ while (count) { -+ status = i2c_smbus_read_byte_data(client, command); -+ if (unlikely(status < 0)) { -+ break; -+ } ++ while (count) { ++ status = i2c_smbus_read_byte_data(client, command); ++ if (unlikely(status < 0)) { ++ break; ++ } + -+ *data = (u8)status; -+ data += 1; -+ command += 1; -+ count -= 1; -+ } ++ *data = (u8)status; ++ data += 1; ++ command += 1; ++ count -= 1; ++ } + -+ return status; ++ return status; +} + +static struct as4610_psu_data *as4610_psu_update_device(struct device *dev) +{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct as4610_psu_data *data = i2c_get_clientdata(client); ++ struct i2c_client *client = to_i2c_client(dev); ++ struct as4610_psu_data *data = i2c_get_clientdata(client); + -+ mutex_lock(&data->update_lock); ++ mutex_lock(&data->update_lock); + -+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2) -+ || !data->valid) { -+ int status; -+ int present = 0; ++ if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ++ || !data->valid) { ++ int status; ++ int present = 0; + -+ data->valid = 0; -+ data->status = 0; -+ dev_dbg(&client->dev, "Starting as4610 update\n"); ++ data->valid = 0; ++ data->status = 0; ++ dev_dbg(&client->dev, "Starting as4610 update\n"); + -+ /* Read psu status */ -+ status = accton_i2c_cpld_read(0x30, 0x11); ++ /* Read psu status */ ++ status = as4610_54_cpld_read(0x30, 0x11); + -+ if (status < 0) { -+ dev_dbg(&client->dev, "cpld reg 0x30 err %d\n", status); -+ goto exit; -+ } -+ else { -+ data->status = status; -+ } ++ if (status < 0) { ++ dev_dbg(&client->dev, "cpld reg 0x30 err %d\n", status); ++ goto exit; ++ } ++ else { ++ data->status = status; ++ } + -+ /* Read model name */ -+ memset(data->model_name, 0, sizeof(data->model_name)); -+ present = (data->status >> (data->index*2) & 0x1); ++ /* Read model name */ ++ memset(data->model_name, 0, sizeof(data->model_name)); ++ present = (data->status >> (data->index*2) & 0x1); + -+ if (present) { -+ int len = ARRAY_SIZE(data->model_name)-1; ++ if (present) { ++ int len = ARRAY_SIZE(data->model_name)-1; + -+ status = as4610_psu_read_data(client, 0x20, data->model_name, -+ ARRAY_SIZE(data->model_name)-1); ++ status = as4610_psu_read_data(client, 0x20, data->model_name, ++ ARRAY_SIZE(data->model_name)-1); + -+ if (status < 0) { -+ data->model_name[0] = '\0'; -+ dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); -+ goto exit; -+ } -+ else { -+ data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; -+ } -+ } ++ if (status < 0) { ++ data->model_name[0] = '\0'; ++ dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); ++ goto exit; ++ } ++ else { ++ data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; ++ } ++ } + -+ data->last_updated = jiffies; -+ data->valid = 1; -+ } ++ data->last_updated = jiffies; ++ data->valid = 1; ++ } + +exit: -+ mutex_unlock(&data->update_lock); ++ mutex_unlock(&data->update_lock); + -+ return data; ++ return data; +} + +static int __init as4610_psu_init(void) +{ -+ return i2c_add_driver(&as4610_psu_driver); ++ return i2c_add_driver(&as4610_psu_driver); +} + +static void __exit as4610_psu_exit(void) +{ -+ i2c_del_driver(&as4610_psu_driver); ++ i2c_del_driver(&as4610_psu_driver); +} + +module_init(as4610_psu_init); @@ -869,297 +1317,6 @@ index 0000000..1f0d79d +MODULE_DESCRIPTION("as4610_psu driver"); +MODULE_LICENSE("GPL"); + -diff --git a/drivers/hwmon/accton_i2c_cpld.c b/drivers/hwmon/accton_i2c_cpld.c -new file mode 100644 -index 0000000..0b9762e ---- /dev/null -+++ b/drivers/hwmon/accton_i2c_cpld.c -@@ -0,0 +1,285 @@ -+/* -+ * A hwmon driver for the accton_i2c_cpld -+ * -+ * Copyright (C) 2013 Accton Technology Corporation. -+ * Brandon Chuang -+ * -+ * Based on ad7414.c -+ * Copyright 2006 Stefan Roese , DENX Software Engineering -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static LIST_HEAD(cpld_client_list); -+static struct mutex list_lock; -+ -+enum cpld_device_id { -+ as4610_30_cpld, -+ as4610_54_cpld -+}; -+ -+struct cpld_data { -+ enum cpld_device_id id; -+}; -+ -+struct cpld_client_node { -+ struct i2c_client *client; -+ struct list_head list; -+}; -+ -+/* Addresses scanned for accton_i2c_cpld -+ */ -+static const unsigned short normal_i2c[] = { 0x31, 0x35, 0x60, 0x61, 0x62, I2C_CLIENT_END }; -+ -+static u8 cpld_product_id_offset(enum cpld_device_id id) -+{ -+ switch (id) { -+ case as4610_30_cpld: -+ case as4610_54_cpld: -+ return 0x1; -+ } -+ -+ return 0; -+} -+ -+static int cpld_has_product_id(const struct i2c_device_id *dev_id) -+{ -+ return (dev_id->driver_data == as4610_30_cpld) || -+ (dev_id->driver_data == as4610_54_cpld); -+} -+ -+static ssize_t show_cpld_product_id(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ int val = 0; -+ struct i2c_client *client = to_i2c_client(dev); -+ struct cpld_data *data = i2c_get_clientdata(client); -+ -+ val = i2c_smbus_read_byte_data(client, cpld_product_id_offset(data->id)); -+ if (val < 0) { -+ dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", client->addr, cpld_product_id_offset(data->id), val); -+ } -+ -+ return sprintf(buf, "%d\n", (val & 0xF)); -+} -+ -+static u8 cpld_version_offset(enum cpld_device_id id) -+{ -+ switch (id) { -+ case as4610_30_cpld: -+ case as4610_54_cpld: -+ return 0xB; -+ } -+ -+ return 0; -+} -+ -+static ssize_t show_cpld_version(struct device *dev, struct device_attribute *attr, char *buf) -+{ -+ int val = 0; -+ struct i2c_client *client = to_i2c_client(dev); -+ struct cpld_data *data = i2c_get_clientdata(client); -+ -+ val = i2c_smbus_read_byte_data(client, cpld_version_offset(data->id)); -+ if (val < 0) { -+ dev_dbg(&client->dev, "cpld(0x%x) reg(0xB) err %d\n", client->addr, val); -+ } -+ -+ return sprintf(buf, "%d\n", val); -+} -+ -+static void accton_i2c_cpld_add_client(struct i2c_client *client, enum cpld_device_id id) -+{ -+ struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); -+ struct cpld_data *data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); -+ -+ if (!node) { -+ dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); -+ return; -+ } -+ -+ if (!data) { -+ dev_dbg(&client->dev, "Can't allocate cpld_client_data (0x%x)\n", client->addr); -+ return; -+ } -+ -+ data->id = id; -+ i2c_set_clientdata(client, data); -+ node->client = client; -+ -+ mutex_lock(&list_lock); -+ list_add(&node->list, &cpld_client_list); -+ mutex_unlock(&list_lock); -+} -+ -+static void accton_i2c_cpld_remove_client(struct i2c_client *client) -+{ -+ struct list_head *list_node = NULL; -+ struct cpld_client_node *cpld_node = NULL; -+ int found = 0; -+ -+ mutex_lock(&list_lock); -+ -+ list_for_each(list_node, &cpld_client_list) -+ { -+ cpld_node = list_entry(list_node, struct cpld_client_node, list); -+ -+ if (cpld_node->client == client) { -+ found = 1; -+ break; -+ } -+ } -+ -+ if (found) { -+ list_del(list_node); -+ kfree(cpld_node); -+ } -+ -+ mutex_unlock(&list_lock); -+} -+ -+static struct device_attribute ver = __ATTR(version, 0600, show_cpld_version, NULL); -+static struct device_attribute pid = __ATTR(product_id, 0600, show_cpld_product_id, NULL); -+ -+static int accton_i2c_cpld_probe(struct i2c_client *client, -+ const struct i2c_device_id *dev_id) -+{ -+ int status; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -+ dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr); -+ status = -EIO; -+ goto exit; -+ } -+ -+ status = sysfs_create_file(&client->dev.kobj, &ver.attr); -+ if (status) { -+ goto exit; -+ } -+ -+ if (cpld_has_product_id(dev_id)) { -+ status = sysfs_create_file(&client->dev.kobj, &pid.attr); -+ if (status) { -+ goto exit; -+ } -+ } -+ -+ dev_info(&client->dev, "chip found\n"); -+ accton_i2c_cpld_add_client(client, (enum cpld_device_id)dev_id->driver_data); -+ -+ return 0; -+ -+exit: -+ return status; -+} -+ -+static int accton_i2c_cpld_remove(struct i2c_client *client) -+{ -+ sysfs_remove_file(&client->dev.kobj, &ver.attr); -+ accton_i2c_cpld_remove_client(client); -+ -+ return 0; -+} -+ -+static const struct i2c_device_id accton_i2c_cpld_id[] = { -+ { "as4610_30_cpld", as4610_30_cpld }, -+ { "as4610_54_cpld", as4610_54_cpld }, -+ { /* LIST END */} -+}; -+MODULE_DEVICE_TABLE(i2c, accton_i2c_cpld_id); -+ -+static struct i2c_driver accton_i2c_cpld_driver = { -+ .class = I2C_CLASS_HWMON, -+ .driver = { -+ .name = "accton_i2c_cpld", -+ }, -+ .probe = accton_i2c_cpld_probe, -+ .remove = accton_i2c_cpld_remove, -+ .id_table = accton_i2c_cpld_id, -+ .address_list = normal_i2c, -+}; -+ -+int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg) -+{ -+ struct list_head *list_node = NULL; -+ struct cpld_client_node *cpld_node = NULL; -+ int ret = -EPERM; -+ -+ mutex_lock(&list_lock); -+ -+ list_for_each(list_node, &cpld_client_list) -+ { -+ cpld_node = list_entry(list_node, struct cpld_client_node, list); -+ -+ if (cpld_node->client->addr == cpld_addr) { -+ ret = i2c_smbus_read_byte_data(cpld_node->client, reg); -+ break; -+ } -+ } -+ -+ mutex_unlock(&list_lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(accton_i2c_cpld_read); -+ -+int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) -+{ -+ struct list_head *list_node = NULL; -+ struct cpld_client_node *cpld_node = NULL; -+ int ret = -EIO; -+ -+ mutex_lock(&list_lock); -+ -+ list_for_each(list_node, &cpld_client_list) -+ { -+ cpld_node = list_entry(list_node, struct cpld_client_node, list); -+ -+ if (cpld_node->client->addr == cpld_addr) { -+ ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); -+ break; -+ } -+ } -+ -+ mutex_unlock(&list_lock); -+ -+ return ret; -+} -+EXPORT_SYMBOL(accton_i2c_cpld_write); -+ -+static int __init accton_i2c_cpld_init(void) -+{ -+ mutex_init(&list_lock); -+ return i2c_add_driver(&accton_i2c_cpld_driver); -+} -+ -+static void __exit accton_i2c_cpld_exit(void) -+{ -+ i2c_del_driver(&accton_i2c_cpld_driver); -+} -+ -+MODULE_AUTHOR("Brandon Chuang "); -+MODULE_DESCRIPTION("accton_i2c_cpld driver"); -+MODULE_LICENSE("GPL"); -+ -+module_init(accton_i2c_cpld_init); -+module_exit(accton_i2c_cpld_exit); -+ diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index 8dfc678..b9eafcf 100644 --- a/drivers/hwmon/lm77.c @@ -1840,7 +1997,7 @@ index ff203a4..97d4d54 100644 +config LEDS_ACCTON_AS4610 + tristate "LED support for the Accton as4610" -+ depends on LEDS_CLASS && SENSORS_ACCTON_I2C_CPLD ++ depends on LEDS_CLASS && SENSORS_ACCTON_AS4610_CPLD + help + This option enables support for the LEDs on the Accton as4610. + Say Y to enable LEDs on the Accton as4610. @@ -1862,7 +2019,7 @@ index e4f6bf5..db2dab8 100644 obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-accton_as4610.c b/drivers/leds/leds-accton_as4610.c new file mode 100644 -index 0000000..0c4b535 +index 0000000..7a8bf34 --- /dev/null +++ b/drivers/leds/leds-accton_as4610.c @@ -0,0 +1,678 @@ @@ -1899,8 +2056,8 @@ index 0000000..0c4b535 +#include +#include + -+extern int accton_i2c_cpld_read (unsigned short cpld_addr, u8 reg); -+extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); ++extern int as4610_54_cpld_read (unsigned short cpld_addr, u8 reg); ++extern int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +extern void led_classdev_unregister(struct led_classdev *led_cdev); +extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); @@ -2016,12 +2173,12 @@ index 0000000..0c4b535 + +static int as4610_led_read_value(u8 reg) +{ -+ return accton_i2c_cpld_read(0x30, reg); ++ return as4610_54_cpld_read(0x30, reg); +} + +static int as4610_led_write_value(u8 reg, u8 value) +{ -+ return accton_i2c_cpld_write(0x30, reg, value); ++ return as4610_54_cpld_write(0x30, reg, value); +} + +static void as4610_led_update(void) @@ -2553,14 +2710,14 @@ index 7c7b208..1c62b33 100644 This driver can also be built as a module. If so, the module will be called sff_8436. + -+config EEPROM_ACCTON_AS4610_SFP -+ tristate "Accton as4610 sfp" -+ depends on I2C && SENSORS_ACCTON_I2C_CPLD ++config EEPROM_OPTOE ++ tristate "Optoe driver" ++ depends on I2C + help -+ If you say yes here you get support for Accton as4610 sfp. ++ If you say yes here you get support for Optoe. + + This driver can also be built as a module. If so, the module will -+ be called accton_as4610_sfp. ++ be called optoe. endmenu diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile @@ -2571,1290 +2728,1167 @@ index 9edd559..12f7cae 100644 obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o obj-$(CONFIG_EEPROM_SFF_8436) += sff_8436_eeprom.o -+obj-$(CONFIG_EEPROM_ACCTON_AS4610_SFP) += accton_as4610_sfp.o -diff --git a/drivers/misc/eeprom/accton_as4610_sfp.c b/drivers/misc/eeprom/accton_as4610_sfp.c ++obj-$(CONFIG_EEPROM_OPTOE) += optoe.o +diff --git a/drivers/misc/eeprom/optoe.c b/drivers/misc/eeprom/optoe.c new file mode 100644 -index 0000000..39c17ec +index 0000000..b3064f0 --- /dev/null -+++ b/drivers/misc/eeprom/accton_as4610_sfp.c -@@ -0,0 +1,1269 @@ ++++ b/drivers/misc/eeprom/optoe.c +@@ -0,0 +1,1146 @@ +/* -+ * SFP driver for accton as4610 sfp ++ * optoe.c - A driver to read and write the EEPROM on optical transceivers ++ * (SFP, QSFP and similar I2C based devices) + * -+ * Copyright (C) Brandon Chuang -+ * -+ * Based on ad7414.c -+ * Copyright 2006 Stefan Roese , DENX Software Engineering ++ * Copyright (C) 2014 Cumulus networks Inc. ++ * Copyright (C) 2017 Finisar Corp. + * + * 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 ++ * the Freeoftware Foundation; either version 2 of the License, or + * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DRIVER_NAME "as4610_sfp" /* Platform dependent */ -+ -+#define DEBUG_MODE 0 -+ -+#if (DEBUG_MODE == 1) -+ #define DEBUG_PRINT(fmt, args...) \ -+ printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) -+#else -+ #define DEBUG_PRINT(fmt, args...) -+#endif -+ -+#define NUM_OF_SFP_PORT 32 -+#define EEPROM_NAME "sfp_eeprom" -+#define EEPROM_SIZE 256 /* 256 byte eeprom */ -+#define BIT_INDEX(i) (1ULL << (i)) -+#define USE_I2C_BLOCK_READ 0 /* Platform dependent */ -+#define I2C_RW_RETRY_COUNT 3 -+#define I2C_RW_RETRY_INTERVAL 100 /* ms */ -+ -+#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) -+#define SFP_EEPROM_A2_I2C_ADDR (0xA2 >> 1) -+ -+#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 -+#define SFF8024_DEVICE_ID_SFP 0x3 -+#define SFF8024_DEVICE_ID_QSFP 0xC -+#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD -+#define SFF8024_DEVICE_ID_QSFP28 0x11 -+ -+#define SFF8472_DIAG_MON_TYPE_ADDR 92 -+#define SFF8472_DIAG_MON_TYPE_DDM_MASK 0x40 -+#define SFF8472_10G_ETH_COMPLIANCE_ADDR 0x3 -+#define SFF8472_10G_BASE_MASK 0xF0 -+ -+#define SFF8436_RX_LOS_ADDR 3 -+#define SFF8436_TX_FAULT_ADDR 4 -+#define SFF8436_TX_DISABLE_ADDR 86 -+ -+static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); -+static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf); -+static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf); -+static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); -+static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); -+static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); -+static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);; -+static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, char *buf); -+static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); -+static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); -+extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -+extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); -+ -+enum sfp_sysfs_attributes { -+ PRESENT, -+ PRESENT_ALL, -+ PORT_NUMBER, -+ PORT_TYPE, -+ DDM_IMPLEMENTED, -+ TX_FAULT, -+ TX_FAULT1, -+ TX_FAULT2, -+ TX_FAULT3, -+ TX_FAULT4, -+ TX_DISABLE, -+ TX_DISABLE1, -+ TX_DISABLE2, -+ TX_DISABLE3, -+ TX_DISABLE4, -+ RX_LOS, -+ RX_LOS1, -+ RX_LOS2, -+ RX_LOS3, -+ RX_LOS4, -+ RX_LOS_ALL -+}; -+ -+/* SFP/QSFP common attributes for sysfs */ -+static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); -+static SENSOR_DEVICE_ATTR(sfp_port_type, S_IRUGO, show_port_type, NULL, PORT_TYPE); -+static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); -+static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); -+static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS); -+static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, sfp_show_tx_rx_status, sfp_set_tx_disable, TX_DISABLE); -+static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, sfp_show_tx_rx_status, NULL, TX_FAULT); -+ -+/* QSFP attributes for sysfs */ -+static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); -+static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); -+static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); -+static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); -+static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); -+static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); -+static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); -+static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); -+static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); -+static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); -+static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); -+static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); -+static struct attribute *qsfp_attributes[] = { -+ &sensor_dev_attr_sfp_port_number.dev_attr.attr, -+ &sensor_dev_attr_sfp_port_type.dev_attr.attr, -+ &sensor_dev_attr_sfp_is_present.dev_attr.attr, -+ &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, -+ NULL -+}; -+ -+/* SFP msa attributes for sysfs */ -+static SENSOR_DEVICE_ATTR(sfp_ddm_implemented, S_IRUGO, sfp_show_ddm_implemented, NULL, DDM_IMPLEMENTED); -+static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS_ALL); -+static struct attribute *sfp_msa_attributes[] = { -+ &sensor_dev_attr_sfp_port_number.dev_attr.attr, -+ &sensor_dev_attr_sfp_port_type.dev_attr.attr, -+ &sensor_dev_attr_sfp_is_present.dev_attr.attr, -+ &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, -+ &sensor_dev_attr_sfp_ddm_implemented.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los.dev_attr.attr, -+ &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, -+ &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, -+ NULL -+}; -+ -+/* SFP ddm attributes for sysfs */ -+static struct attribute *sfp_ddm_attributes[] = { -+ NULL -+}; -+ -+/* Platform dependent +++ */ -+enum port_numbers { -+as4610_sfp1, /* Port 25 for as4610_30, Port 49 for as4610_54 */ -+as4610_sfp2, /* Port 26 for as4610_30, Port 50 for as4610_54 */ -+as4610_sfp3, /* Port 27 for as4610_30, Port 51 for as4610_54 */ -+as4610_sfp4, /* Port 28 for as4610_30, Port 52 for as4610_54 */ -+as4610_sfp5, /* Port 29 for as4610_30, Port 53 for as4610_54 */ -+as4610_sfp6, /* Port 30 for as4610_30, Port 54 for as4610_54 */ -+}; -+ -+static const struct i2c_device_id sfp_device_id[] = { -+{"as4610_sfp1", as4610_sfp1}, -+{"as4610_sfp2", as4610_sfp2}, -+{"as4610_sfp3", as4610_sfp3}, -+{"as4610_sfp4", as4610_sfp4}, -+{"as4610_sfp5", as4610_sfp5}, -+{"as4610_sfp6", as4610_sfp6}, -+{ /* LIST END */ } -+}; -+MODULE_DEVICE_TABLE(i2c, sfp_device_id); -+/* Platform dependent --- */ -+ +/* -+ * list of valid port types -+ * note OOM_PORT_TYPE_NOT_PRESENT to indicate no -+ * module is present in this port -+ */ -+typedef enum oom_driver_port_type_e { -+ OOM_DRIVER_PORT_TYPE_INVALID, -+ OOM_DRIVER_PORT_TYPE_NOT_PRESENT, -+ OOM_DRIVER_PORT_TYPE_SFP, -+ OOM_DRIVER_PORT_TYPE_SFP_PLUS, -+ OOM_DRIVER_PORT_TYPE_QSFP, -+ OOM_DRIVER_PORT_TYPE_QSFP_PLUS, -+ OOM_DRIVER_PORT_TYPE_QSFP28 -+} oom_driver_port_type_t; -+ -+enum driver_type_e { -+ DRIVER_TYPE_SFP_MSA, -+ DRIVER_TYPE_SFP_DDM, -+ DRIVER_TYPE_QSFP -+}; -+ -+/* Each client has this additional data -+ */ -+struct eeprom_data { -+ char valid; /* !=0 if registers are valid */ -+ unsigned long last_updated; /* In jiffies */ -+ struct bin_attribute bin; /* eeprom data */ -+}; -+ -+struct sfp_msa_data { -+ char valid; /* !=0 if registers are valid */ -+ unsigned long last_updated; /* In jiffies */ -+ u64 status[6]; /* bit0:port0, bit1:port1 and so on */ -+ /* index 0 => tx_fail -+ 1 => tx_disable -+ 2 => rx_loss -+ 3 => device id -+ 4 => 10G Ethernet Compliance Codes -+ to distinguish SFP or SFP+ -+ 5 => DIAGNOSTIC MONITORING TYPE */ -+ struct eeprom_data eeprom; -+}; -+ -+struct sfp_ddm_data { -+ struct eeprom_data eeprom; -+}; -+ -+struct qsfp_data { -+ char valid; /* !=0 if registers are valid */ -+ unsigned long last_updated; /* In jiffies */ -+ u8 status[3]; /* bit0:port0, bit1:port1 and so on */ -+ /* index 0 => tx_fail -+ 1 => tx_disable -+ 2 => rx_loss */ -+ -+ u8 device_id; -+ struct eeprom_data eeprom; -+}; -+ -+struct sfp_port_data { -+ struct mutex update_lock; -+ enum driver_type_e driver_type; -+ int port; /* CPLD port index */ -+ oom_driver_port_type_t port_type; -+ u64 present; /* present status, bit0:port0, bit1:port1 and so on */ -+ -+ struct sfp_msa_data *msa; -+ struct sfp_ddm_data *ddm; -+ struct qsfp_data *qsfp; -+ -+ struct i2c_client *client; -+}; -+ -+static ssize_t show_port_number(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ -+ return sprintf(buf, "sfp %d\n", data->port); -+} -+ -+/* Platform dependent +++ */ -+static struct sfp_port_data *sfp_update_present(struct i2c_client *client) -+{ -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ int i = 0; -+ int status = -1; -+ u8 regs[] = {0x2, 0x3, 0x21}; -+ -+ DEBUG_PRINT("Starting sfp present status update"); -+ mutex_lock(&data->update_lock); -+ -+ /* Read present status of port 49~54 */ -+ data->present = 0; -+ -+ for (i = 0; i < ARRAY_SIZE(regs); i++) { -+ status = accton_i2c_cpld_read(0x30, regs[i]); -+ -+ if (status < 0) { -+ DEBUG_PRINT("cpld(0x30) reg(0x%x) err %d", regs[i], status); -+ goto exit; -+ } -+ -+ DEBUG_PRINT("Present status = 0x%lx", data->present); -+ switch (i) { -+ case 0: -+ data->present |= (status & BIT_INDEX(6)) >> 6; /* port 25/49 */ -+ data->present |= (status & BIT_INDEX(2)) >> 1; /* port 26/50 */ -+ break; -+ case 1: -+ data->present |= (status & BIT_INDEX(6)) >> 4; /* port 27/51 */ -+ data->present |= (status & BIT_INDEX(2)) << 1; /* port 28/52 */ -+ break; -+ case 2: -+ data->present |= (status & BIT_INDEX(0)) << 4; /* port 29/53 */ -+ data->present |= (status & BIT_INDEX(4)) << 1; /* port 30/54 */ -+ break; -+ default: -+ break; -+ } -+ } -+ -+ DEBUG_PRINT("Present status = 0x%lx", data->present); -+exit: -+ mutex_unlock(&data->update_lock); -+ return (status < 0) ? ERR_PTR(status) : data; -+} -+ -+static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ int i = 0; -+ int status = -1; -+ u8 regs[] = {0x2, 0x3, 0x21}; -+ -+ if (time_before(jiffies, data->msa->last_updated + HZ + HZ / 2) && data->msa->valid) { -+ return data; -+ } -+ -+ DEBUG_PRINT("Starting as4610 sfp tx rx status update"); -+ mutex_lock(&data->update_lock); -+ data->msa->valid = 0; -+ memset(data->msa->status, 0, sizeof(data->msa->status)); -+ -+ /* Read status of port 49~52(SFP port) */ -+ for (i = 0; i < ARRAY_SIZE(regs); i++) { -+ status = accton_i2c_cpld_read(0x30, regs[i]); -+ -+ if (status < 0) { -+ DEBUG_PRINT("cpld(0x30) reg(0x%x) err %d", regs[i], status); -+ goto exit; -+ } -+ -+ DEBUG_PRINT("TX_FAULT = 0x%lx, TX_DISABLE = 0x%lx, TX_FAULT = 0x%lx", -+ data->msa->status[0], data->msa->status[1], data->msa->status[2]); -+ switch (i) { -+ case 0: -+ /* port 25/49 */ -+ data->msa->status[0] |= (status & BIT_INDEX(5)) >> 5; /* tx_fail */ -+ data->msa->status[2] |= (status & BIT_INDEX(4)) >> 4; /* rx_los */ -+ /* port 26/50 */ -+ data->msa->status[0] |= (status & BIT_INDEX(1)) << 0; /* tx_fail */ -+ data->msa->status[2] |= (status & BIT_INDEX(0)) << 1; /* rx_los */ -+ break; -+ case 1: -+ /* port 27/51 */ -+ data->msa->status[0] |= (status & BIT_INDEX(5)) >> 3; /* tx_fail */ -+ data->msa->status[2] |= (status & BIT_INDEX(4)) >> 2; /* rx_los */ -+ /* port 28/52 */ -+ data->msa->status[0] |= (status & BIT_INDEX(1)) << 1; /* tx_fail */ -+ data->msa->status[2] |= (status & BIT_INDEX(0)) << 2; /* rx_los */ -+ break; -+ default: -+ break; -+ } -+ } -+ -+ DEBUG_PRINT("TX_FAULT = 0x%lx, TX_DISABLE = 0x%lx, TX_FAULT = 0x%lx", -+ data->msa->status[0], data->msa->status[1], data->msa->status[2]); -+ data->msa->valid = 1; -+ data->msa->last_updated = jiffies; -+ -+exit: -+ mutex_unlock(&data->update_lock); -+ return data; -+} -+/* Platform dependent --- */ -+ -+static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, -+ const char *buf, size_t count) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ -+ if (data->driver_type == DRIVER_TYPE_QSFP) { -+ return qsfp_set_tx_disable(dev, da, buf, count); -+ } -+ -+ return 0; -+} -+ -+static int sfp_is_port_present(struct i2c_client *client, int port) -+{ -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ -+ data = sfp_update_present(client); -+ if (IS_ERR(data)) { -+ return PTR_ERR(data); -+ } -+ -+ return (data->present & BIT_INDEX(data->port)) ? 1 : 0; /* Platform dependent */ -+} -+ -+/* Platform dependent +++ */ -+static ssize_t show_present(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct i2c_client *client = to_i2c_client(dev); -+ -+ if (PRESENT_ALL == attr->index) { -+ struct sfp_port_data *data = sfp_update_present(client); -+ -+ if (IS_ERR(data)) { -+ return PTR_ERR(data); -+ } -+ -+ /* Return values 25/49 -> 30/54 in order */ -+ return sprintf(buf, "%.2x\n", (u8)(data->present)); -+ } -+ else { -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ int present = sfp_is_port_present(client, data->port); -+ -+ if (IS_ERR_VALUE(present)) { -+ return present; -+ } -+ -+ /* PRESENT */ -+ return sprintf(buf, "%d\n", present); -+ } -+} -+/* Platform dependent --- */ -+ -+static struct sfp_port_data *sfp_update_port_type(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ u8 buf = 0; -+ int status; -+ -+ mutex_lock(&data->update_lock); -+ -+ switch (data->driver_type) { -+ case DRIVER_TYPE_SFP_MSA: -+ { -+ status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); -+ if (unlikely(status < 0)) { -+ data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; -+ break; -+ } -+ -+ if (buf != SFF8024_DEVICE_ID_SFP) { -+ data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; -+ break; -+ } -+ -+ status = sfp_eeprom_read(client, SFF8472_10G_ETH_COMPLIANCE_ADDR, &buf, sizeof(buf)); -+ if (unlikely(status < 0)) { -+ data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; -+ break; -+ } -+ -+ DEBUG_PRINT("sfp port type (0x3) data = (0x%x)", buf); -+ data->port_type = buf & SFF8472_10G_BASE_MASK ? OOM_DRIVER_PORT_TYPE_SFP_PLUS : OOM_DRIVER_PORT_TYPE_SFP; -+ break; -+ } -+ case DRIVER_TYPE_QSFP: -+ { -+ status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); -+ if (unlikely(status < 0)) { -+ data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; -+ break; -+ } -+ -+ DEBUG_PRINT("qsfp port type (0x0) buf = (0x%x)", buf); -+ switch (buf) { -+ case SFF8024_DEVICE_ID_QSFP: -+ data->port_type = OOM_DRIVER_PORT_TYPE_QSFP; -+ break; -+ case SFF8024_DEVICE_ID_QSFP_PLUS: -+ data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; -+ break; -+ case SFF8024_DEVICE_ID_QSFP28: -+ data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; -+ break; -+ default: -+ data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; -+ break; -+ } -+ -+ break; -+ } -+ default: -+ break; -+ } -+ -+ mutex_unlock(&data->update_lock); -+ return data; -+} -+ -+static ssize_t show_port_type(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ int present = sfp_is_port_present(client, data->port); -+ -+ if (IS_ERR_VALUE(present)) { -+ return present; -+ } -+ -+ if (!present) { -+ return sprintf(buf, "%d\n", OOM_DRIVER_PORT_TYPE_NOT_PRESENT); -+ } -+ -+ sfp_update_port_type(dev); -+ return sprintf(buf, "%d\n", data->port_type); -+} -+ -+static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ int i, status = -1; -+ u8 buf = 0; -+ u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; -+ -+ if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { -+ return data; -+ } -+ -+ DEBUG_PRINT("Starting sfp tx rx status update"); -+ mutex_lock(&data->update_lock); -+ data->qsfp->valid = 0; -+ memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); -+ -+ /* Notify device to update tx fault/ tx disable/ rx los status */ -+ for (i = 0; i < ARRAY_SIZE(reg); i++) { -+ status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); -+ if (unlikely(status < 0)) { -+ goto exit; -+ } -+ } -+ msleep(200); -+ -+ /* Read actual tx fault/ tx disable/ rx los status */ -+ for (i = 0; i < ARRAY_SIZE(reg); i++) { -+ status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); -+ if (unlikely(status < 0)) { -+ goto exit; -+ } -+ -+ DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); -+ data->qsfp->status[i] = (buf & 0xF); -+ } -+ -+ data->qsfp->valid = 1; -+ data->qsfp->last_updated = jiffies; -+ -+exit: -+ mutex_unlock(&data->update_lock); -+ return (status < 0) ? ERR_PTR(status) : data; -+} -+ -+static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ int present; -+ u8 val = 0; -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ -+ present = sfp_is_port_present(client, data->port); -+ if (IS_ERR_VALUE(present)) { -+ return present; -+ } -+ -+ if (present == 0) { -+ /* port is not present */ -+ return -ENXIO; -+ } -+ -+ data = qsfp_update_tx_rx_status(dev); -+ if (IS_ERR(data)) { -+ return PTR_ERR(data); -+ } -+ -+ switch (attr->index) { -+ case TX_FAULT: -+ val = !!(data->qsfp->status[2] & 0xF); -+ break; -+ case TX_FAULT1: -+ case TX_FAULT2: -+ case TX_FAULT3: -+ case TX_FAULT4: -+ val = !!(data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)); -+ break; -+ case TX_DISABLE: -+ val = data->qsfp->status[1] & 0xF; -+ break; -+ case TX_DISABLE1: -+ case TX_DISABLE2: -+ case TX_DISABLE3: -+ case TX_DISABLE4: -+ val = !!(data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)); -+ break; -+ case RX_LOS: -+ val = !!(data->qsfp->status[0] & 0xF); -+ break; -+ case RX_LOS1: -+ case RX_LOS2: -+ case RX_LOS3: -+ case RX_LOS4: -+ val = !!(data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)); -+ break; -+ default: -+ break; -+ } -+ -+ return sprintf(buf, "%d\n", val); -+} -+ -+static ssize_t qsfp_set_tx_disable(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); -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ -+ status = sfp_is_port_present(client, data->port); -+ if (IS_ERR_VALUE(status)) { -+ return status; -+ } -+ -+ if (!status) { -+ /* port is not present */ -+ return -ENXIO; -+ } -+ -+ status = kstrtol(buf, 10, &disable); -+ if (status) { -+ return status; -+ } -+ -+ data = qsfp_update_tx_rx_status(dev); -+ if (IS_ERR(data)) { -+ return PTR_ERR(data); -+ } -+ -+ mutex_lock(&data->update_lock); -+ -+ if (attr->index == TX_DISABLE) { -+ data->qsfp->status[1] = disable & 0xF; -+ } -+ else {/* TX_DISABLE1 ~ TX_DISABLE4*/ -+ if (disable) { -+ data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); -+ } -+ else { -+ data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); -+ } -+ } -+ -+ DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); -+ status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); -+ if (unlikely(status < 0)) { -+ count = status; -+ } -+ -+ mutex_unlock(&data->update_lock); -+ return count; -+} -+ -+static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ int status; -+ char ddm; -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ -+ status = sfp_is_port_present(client, data->port); -+ if (IS_ERR_VALUE(status)) { -+ return status; -+ } -+ -+ if (status == 0) { -+ /* port is not present */ -+ return -ENODEV; -+ } -+ -+ status = sfp_eeprom_read(client, SFF8472_DIAG_MON_TYPE_ADDR, &ddm, sizeof(ddm)); -+ if (unlikely(status < 0)) { -+ return status; -+ } -+ -+ return sprintf(buf, "%d\n", !!(ddm & SFF8472_DIAG_MON_TYPE_DDM_MASK)); -+} -+ -+/* Platform dependent +++ */ -+static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, -+ char *buf) -+{ -+ u8 val = 0, index = 0; -+ struct i2c_client *client = to_i2c_client(dev); -+ struct sfp_port_data *data = i2c_get_clientdata(client); -+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); -+ -+ if (data->driver_type == DRIVER_TYPE_QSFP) { -+ return qsfp_show_tx_rx_status(dev, da, buf); -+ } -+ -+ data = sfp_update_tx_rx_status(dev); -+ if (IS_ERR(data)) { -+ return PTR_ERR(data); -+ } -+ -+ if(attr->index == RX_LOS_ALL) { -+ /** Return values 25/49 -> 28/52 in order */ -+ return sprintf(buf, "%.2x\n", (u8)(data->msa->status[2])); -+ } -+ -+ switch (attr->index) { -+ case TX_FAULT: -+ index = 0; -+ break; -+ case TX_DISABLE: -+ index = 1; -+ break; -+ case RX_LOS: -+ index = 2; -+ break; -+ default: -+ return 0; -+ } -+ -+ val = (data->msa->status[index] & BIT_INDEX(data->port)) ? 1 : 0; -+ return sprintf(buf, "%d\n", val); -+} -+/* Platform dependent --- */ -+static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, -+ int data_len) -+{ -+#if USE_I2C_BLOCK_READ -+ int status, retry = I2C_RW_RETRY_COUNT; -+ -+ if (data_len > I2C_SMBUS_BLOCK_MAX) { -+ data_len = I2C_SMBUS_BLOCK_MAX; -+ } -+ -+ while (retry) { -+ status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); -+ if (unlikely(status < 0)) { -+ msleep(I2C_RW_RETRY_INTERVAL); -+ retry--; -+ continue; -+ } -+ -+ break; -+ } -+ -+ if (unlikely(status < 0)) { -+ return status; -+ } -+ -+ return data_len; -+#else -+ int status, retry = I2C_RW_RETRY_COUNT; -+ -+ while (retry) { -+ status = i2c_smbus_write_byte_data(client, command, *data); -+ if (unlikely(status < 0)) { -+ msleep(I2C_RW_RETRY_INTERVAL); -+ retry--; -+ continue; -+ } -+ -+ break; -+ } -+ -+ if (unlikely(status < 0)) { -+ return status; -+ } -+ -+ return 1; ++ * Description: ++ * a) Optical transceiver EEPROM read/write transactions are just like ++ * the at24 eeproms managed by the at24.c i2c driver ++ * b) The register/memory layout is up to 256 128 byte pages defined by ++ * a "pages valid" register and switched via a "page select" ++ * register as explained in below diagram. ++ * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 ++ * bytes of address space, and always references the same ++ * location, independent of the page select register. ++ * All mapped pages are mapped into the upper 128 bytes ++ * (offset 128-255) of the i2c address. ++ * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 ++ * (A0h in the spec), and map all pages in the upper 128 bytes ++ * of that address. ++ * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data ++ * at I2C address 0x50, and 256 bytes of data at I2C address ++ * 0x51 (A2h in the spec). Page selection and paged access ++ * only apply to this second I2C address (0x51). ++ * e) The address space is presented, by the driver, as a linear ++ * address space. For devices with one I2C client at address ++ * 0x50 (eg QSFP), offset 0-127 are in the lower ++ * half of address 50/A0h/client[0]. Offset 128-255 are in ++ * page 0, 256-383 are page 1, etc. More generally, offset ++ * 'n' resides in page (n/128)-1. ('page -1' is the lower ++ * half, offset 0-127). ++ * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), ++ * the address space places offset 0-127 in the lower ++ * half of 50/A0/client[0], offset 128-255 in the upper ++ * half. Offset 256-383 is in the lower half of 51/A2/client[1]. ++ * Offset 384-511 is in page 0, in the upper half of 51/A2/... ++ * Offset 512-639 is in page 1, in the upper half of 51/A2/... ++ * Offset 'n' is in page (n/128)-3 (for n > 383) ++ * ++ * One I2c addressed (eg QSFP) Memory Map ++ * ++ * 2-Wire Serial Address: 1010000x ++ * ++ * Lower Page 00h (128 bytes) ++ * ===================== ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * | | ++ * |Page Select Byte(127)| ++ * ===================== ++ * | ++ * | ++ * | ++ * | ++ * V ++ * ------------------------------------------------------------ ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * | | | | ++ * V V V V ++ * ------------ -------------- --------------- -------------- ++ * | | | | | | | | ++ * | Upper | | Upper | | Upper | | Upper | ++ * | Page 00h | | Page 01h | | Page 02h | | Page 03h | ++ * | | | (Optional) | | (Optional) | | (Optional | ++ * | | | | | | | for Cable | ++ * | | | | | | | Assemblies) | ++ * | ID | | AST | | User | | | ++ * | Fields | | Table | | EEPROM Data | | | ++ * | | | | | | | | ++ * | | | | | | | | ++ * | | | | | | | | ++ * ------------ -------------- --------------- -------------- ++ * ++ * The SFF 8436 (QSFP) spec only defines the 4 pages described above. ++ * In anticipation of future applications and devices, this driver ++ * supports access to the full architected range, 256 pages. ++ * ++ **/ ++ ++/* #define DEBUG 1 */ ++ ++#undef EEPROM_CLASS ++#ifdef CONFIG_EEPROM_CLASS ++#define EEPROM_CLASS ++#endif ++#ifdef CONFIG_EEPROM_CLASS_MODULE ++#define EEPROM_CLASS +#endif + ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+} ++#ifdef EEPROM_CLASS ++#include ++#endif + -+static ssize_t sfp_port_write(struct sfp_port_data *data, -+ const char *buf, loff_t off, size_t count) ++#include ++ ++/* The maximum length of a port name */ ++#define MAX_PORT_NAME_LEN 20 ++ ++struct optoe_platform_data { ++ u32 byte_len; /* size (sum of all addr) */ ++ u16 page_size; /* for writes */ ++ u8 flags; ++ void *dummy1; /* backward compatibility */ ++ void *dummy2; /* backward compatibility */ ++ ++#ifdef EEPROM_CLASS ++ struct eeprom_platform_data *eeprom_data; ++#endif ++ char port_name[MAX_PORT_NAME_LEN]; ++}; ++ ++/* fundamental unit of addressing for EEPROM */ ++#define OPTOE_PAGE_SIZE 128 ++/* ++ * Single address devices (eg QSFP) have 256 pages, plus the unpaged ++ * low 128 bytes. If the device does not support paging, it is ++ * only 2 'pages' long. ++ */ ++#define OPTOE_ARCH_PAGES 256 ++#define ONE_ADDR_EEPROM_SIZE ((1 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) ++#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * OPTOE_PAGE_SIZE) ++/* ++ * Dual address devices (eg SFP) have 256 pages, plus the unpaged ++ * low 128 bytes, plus 256 bytes at 0x50. If the device does not ++ * support paging, it is 4 'pages' long. ++ */ ++#define TWO_ADDR_EEPROM_SIZE ((3 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) ++#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * OPTOE_PAGE_SIZE) ++#define TWO_ADDR_NO_0X51_SIZE (2 * OPTOE_PAGE_SIZE) ++ ++/* a few constants to find our way around the EEPROM */ ++#define OPTOE_PAGE_SELECT_REG 0x7F ++#define ONE_ADDR_PAGEABLE_REG 0x02 ++#define ONE_ADDR_NOT_PAGEABLE (1<<2) ++#define TWO_ADDR_PAGEABLE_REG 0x40 ++#define TWO_ADDR_PAGEABLE (1<<4) ++#define TWO_ADDR_0X51_REG 92 ++#define TWO_ADDR_0X51_SUPP (1<<6) ++#define OPTOE_ID_REG 0 ++#define OPTOE_READ_OP 0 ++#define OPTOE_WRITE_OP 1 ++#define OPTOE_EOF 0 /* used for access beyond end of device */ ++ ++struct optoe_data { ++ struct optoe_platform_data chip; ++ int use_smbus; ++ char port_name[MAX_PORT_NAME_LEN]; ++ ++ /* ++ * Lock protects against activities from other Linux tasks, ++ * but not from changes by other I2C masters. ++ */ ++ struct mutex lock; ++ struct bin_attribute bin; ++ struct attribute_group attr_group; ++ ++ u8 *writebuf; ++ unsigned int write_max; ++ ++ unsigned int num_addresses; ++ ++#ifdef EEPROM_CLASS ++ struct eeprom_device *eeprom_dev; ++#endif ++ ++ /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ ++ int dev_class; ++ ++ struct i2c_client *client[]; ++}; ++ ++ ++/* ++ * This parameter is to help this driver avoid blocking other drivers out ++ * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C ++ * clock, one 256 byte read takes about 1/43 second which is excessive; ++ * but the 1/170 second it takes at 400 kHz may be quite reasonable; and ++ * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. ++ * ++ * This value is forced to be a power of two so that writes align on pages. ++ */ ++static unsigned int io_limit = OPTOE_PAGE_SIZE; ++ ++/* ++ * specs often allow 5 msec for a page write, sometimes 20 msec; ++ * it's important to recover from write timeouts. ++ */ ++static unsigned int write_timeout = 25; ++ ++/* ++ * flags to distinguish one-address (QSFP family) from two-address (SFP family) ++ * If the family is not known, figure it out when the device is accessed ++ */ ++#define ONE_ADDR 1 ++#define TWO_ADDR 2 ++ ++static const struct i2c_device_id optoe_ids[] = { ++ { "optoe1", ONE_ADDR }, ++ { "optoe2", TWO_ADDR }, ++ { "sff8436", ONE_ADDR }, ++ { "24c04", TWO_ADDR }, ++ { /* END OF LIST */ } ++}; ++MODULE_DEVICE_TABLE(i2c, optoe_ids); ++ ++/*-------------------------------------------------------------------------*/ ++/* ++ * This routine computes the addressing information to be used for ++ * a given r/w request. ++ * ++ * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), ++ * the page, and the offset. ++ * ++ * Handles both single address (eg QSFP) and two address (eg SFP). ++ * For SFP, offset 0-255 are on client[0], >255 is on client[1] ++ * Offset 256-383 are on the lower half of client[1] ++ * Pages are accessible on the upper half of client[1]. ++ * Offset >383 are in 128 byte pages mapped into the upper half ++ * ++ * For QSFP, all offsets are on client[0] ++ * offset 0-127 are on the lower half of client[0] (no paging) ++ * Pages are accessible on the upper half of client[1]. ++ * Offset >127 are in 128 byte pages mapped into the upper half ++ * ++ * Callers must not read/write beyond the end of a client or a page ++ * without recomputing the client/page. Hence offset (within page) ++ * plus length must be less than or equal to 128. (Note that this ++ * routine does not have access to the length of the call, hence ++ * cannot do the validity check.) ++ * ++ * Offset within Lower Page 00h and Upper Page 00h are not recomputed ++ */ ++ ++static uint8_t optoe_translate_offset(struct optoe_data *optoe, ++ loff_t *offset, struct i2c_client **client) +{ -+ ssize_t retval = 0; ++ unsigned int page = 0; + -+ if (unlikely(!count)) { -+ return count; ++ *client = optoe->client[0]; ++ ++ /* if SFP style, offset > 255, shift to i2c addr 0x51 */ ++ if (optoe->dev_class == TWO_ADDR) { ++ if (*offset > 255) { ++ /* like QSFP, but shifted to client[1] */ ++ *client = optoe->client[1]; ++ *offset -= 256; ++ } + } + + /* -+ * Write data to chip, protecting against concurrent updates -+ * from this host, but not from other I2C masters. ++ * if offset is in the range 0-128... ++ * page doesn't matter (using lower half), return 0. ++ * offset is already correct (don't add 128 to get to paged area) + */ -+ mutex_lock(&data->update_lock); ++ if (*offset < OPTOE_PAGE_SIZE) ++ return page; ++ ++ /* note, page will always be positive since *offset >= 128 */ ++ page = (*offset >> 7)-1; ++ /* 0x80 places the offset in the top half, offset is last 7 bits */ ++ *offset = OPTOE_PAGE_SIZE + (*offset & 0x7f); ++ ++ return page; /* note also returning client and offset */ ++} ++ ++static ssize_t optoe_eeprom_read(struct optoe_data *optoe, ++ struct i2c_client *client, ++ char *buf, unsigned int offset, size_t count) ++{ ++ struct i2c_msg msg[2]; ++ u8 msgbuf[2]; ++ unsigned long timeout, read_time; ++ int status, i; ++ ++ memset(msg, 0, sizeof(msg)); ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /*smaller eeproms can work given some SMBus extension calls */ ++ if (count > I2C_SMBUS_BLOCK_MAX) ++ count = I2C_SMBUS_BLOCK_MAX; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ /* Check for odd length transaction */ ++ count = (count == 1) ? 1 : 2; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ count = 1; ++ break; ++ default: ++ /* ++ * When we have a better choice than SMBus calls, use a ++ * combined I2C message. Write address; then read up to ++ * io_limit data bytes. msgbuf is u8 and will cast to our ++ * needs. ++ */ ++ i = 0; ++ msgbuf[i++] = offset; ++ ++ msg[0].addr = client->addr; ++ msg[0].buf = msgbuf; ++ msg[0].len = i; ++ ++ msg[1].addr = client->addr; ++ msg[1].flags = I2C_M_RD; ++ msg[1].buf = buf; ++ msg[1].len = count; ++ } ++ ++ /* ++ * Reads fail if the previous write didn't complete yet. We may ++ * loop a few times until this one succeeds, waiting at least ++ * long enough for one entire page write to work. ++ */ ++ timeout = jiffies + msecs_to_jiffies(write_timeout); ++ do { ++ read_time = jiffies; ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ status = i2c_smbus_read_i2c_block_data(client, offset, ++ count, buf); ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ status = i2c_smbus_read_word_data(client, offset); ++ if (status >= 0) { ++ buf[0] = status & 0xff; ++ if (count == 2) ++ buf[1] = status >> 8; ++ status = count; ++ } ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ status = i2c_smbus_read_byte_data(client, offset); ++ if (status >= 0) { ++ buf[0] = status; ++ status = count; ++ } ++ break; ++ default: ++ status = i2c_transfer(client->adapter, msg, 2); ++ if (status == 2) ++ status = count; ++ } ++ ++ dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", ++ count, offset, status, jiffies); ++ ++ if (status == count) /* happy path */ ++ return count; ++ ++ if (status == -ENXIO) /* no module present */ ++ return status; ++ ++ /* REVISIT: at HZ=100, this is sloooow */ ++ usleep_range(1000, 2000); ++ } while (time_before(read_time, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++static ssize_t optoe_eeprom_write(struct optoe_data *optoe, ++ struct i2c_client *client, ++ const char *buf, ++ unsigned int offset, size_t count) ++{ ++ struct i2c_msg msg; ++ ssize_t status; ++ unsigned long timeout, write_time; ++ unsigned int next_page_start; ++ int i = 0; ++ ++ /* write max is at most a page ++ * (In this driver, write_max is actually one byte!) ++ */ ++ if (count > optoe->write_max) ++ count = optoe->write_max; ++ ++ /* shorten count if necessary to avoid crossing page boundary */ ++ next_page_start = roundup(offset + 1, OPTOE_PAGE_SIZE); ++ if (offset + count > next_page_start) ++ count = next_page_start - offset; ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ /*smaller eeproms can work given some SMBus extension calls */ ++ if (count > I2C_SMBUS_BLOCK_MAX) ++ count = I2C_SMBUS_BLOCK_MAX; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ /* Check for odd length transaction */ ++ count = (count == 1) ? 1 : 2; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ count = 1; ++ break; ++ default: ++ /* If we'll use I2C calls for I/O, set up the message */ ++ msg.addr = client->addr; ++ msg.flags = 0; ++ ++ /* msg.buf is u8 and casts will mask the values */ ++ msg.buf = optoe->writebuf; ++ ++ msg.buf[i++] = offset; ++ memcpy(&msg.buf[i], buf, count); ++ msg.len = i + count; ++ break; ++ } ++ ++ /* ++ * Reads fail if the previous write didn't complete yet. We may ++ * loop a few times until this one succeeds, waiting at least ++ * long enough for one entire page write to work. ++ */ ++ timeout = jiffies + msecs_to_jiffies(write_timeout); ++ do { ++ write_time = jiffies; ++ ++ switch (optoe->use_smbus) { ++ case I2C_SMBUS_I2C_BLOCK_DATA: ++ status = i2c_smbus_write_i2c_block_data(client, ++ offset, count, buf); ++ if (status == 0) ++ status = count; ++ break; ++ case I2C_SMBUS_WORD_DATA: ++ if (count == 2) { ++ status = i2c_smbus_write_word_data(client, ++ offset, (u16)((buf[0])|(buf[1] << 8))); ++ } else { ++ /* count = 1 */ ++ status = i2c_smbus_write_byte_data(client, ++ offset, buf[0]); ++ } ++ if (status == 0) ++ status = count; ++ break; ++ case I2C_SMBUS_BYTE_DATA: ++ status = i2c_smbus_write_byte_data(client, offset, ++ buf[0]); ++ if (status == 0) ++ status = count; ++ break; ++ default: ++ status = i2c_transfer(client->adapter, &msg, 1); ++ if (status == 1) ++ status = count; ++ break; ++ } ++ ++ dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", ++ count, offset, (long int) status, jiffies); ++ ++ if (status == count) ++ return count; ++ ++ /* REVISIT: at HZ=100, this is sloooow */ ++ usleep_range(1000, 2000); ++ } while (time_before(write_time, timeout)); ++ ++ return -ETIMEDOUT; ++} ++ ++ ++static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe, ++ char *buf, loff_t off, ++ size_t count, int opcode) ++{ ++ struct i2c_client *client; ++ ssize_t retval = 0; ++ uint8_t page = 0; ++ loff_t phy_offset = off; ++ int ret = 0; ++ ++ page = optoe_translate_offset(optoe, &phy_offset, &client); ++ dev_dbg(&client->dev, ++ "%s off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", ++ __func__, off, page, phy_offset, (long int) count, opcode); ++ if (page > 0) { ++ ret = optoe_eeprom_write(optoe, client, &page, ++ OPTOE_PAGE_SELECT_REG, 1); ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "Write page register for page %d failed ret:%d!\n", ++ page, ret); ++ return ret; ++ } ++ } + + while (count) { -+ ssize_t status; ++ ssize_t status; + -+ status = sfp_eeprom_write(data->client, off, buf, count); ++ if (opcode == OPTOE_READ_OP) { ++ status = optoe_eeprom_read(optoe, client, ++ buf, phy_offset, count); ++ } else { ++ status = optoe_eeprom_write(optoe, client, ++ buf, phy_offset, count); ++ } + if (status <= 0) { -+ if (retval == 0) { ++ if (retval == 0) + retval = status; -+ } + break; + } + buf += status; -+ off += status; ++ phy_offset += status; + count -= status; + retval += status; + } + -+ mutex_unlock(&data->update_lock); ++ ++ if (page > 0) { ++ /* return the page register to page 0 (why?) */ ++ page = 0; ++ ret = optoe_eeprom_write(optoe, client, &page, ++ OPTOE_PAGE_SELECT_REG, 1); ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "Restore page register to 0 failed:%d!\n", ret); ++ /* error only if nothing has been transferred */ ++ if (retval == 0) ++ retval = ret; ++ } ++ } + return retval; +} + -+ -+static ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, -+ struct bin_attribute *attr, -+ char *buf, loff_t off, size_t count) ++/* ++ * Figure out if this access is within the range of supported pages. ++ * Note this is called on every access because we don't know if the ++ * module has been replaced since the last call. ++ * If/when modules support more pages, this is the routine to update ++ * to validate and allow access to additional pages. ++ * ++ * Returns updated len for this access: ++ * - entire access is legal, original len is returned. ++ * - access begins legal but is too long, len is truncated to fit. ++ * - initial offset exceeds supported pages, return OPTOE_EOF (zero) ++ */ ++static ssize_t optoe_page_legal(struct optoe_data *optoe, ++ loff_t off, size_t len) +{ -+ int present; -+ struct sfp_port_data *data; -+ DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); -+ data = dev_get_drvdata(container_of(kobj, struct device, kobj)); ++ struct i2c_client *client = optoe->client[0]; ++ u8 regval; ++ int status; ++ size_t maxlen; + -+ present = sfp_is_port_present(data->client, data->port); -+ if (IS_ERR_VALUE(present)) { -+ return present; ++ if (off < 0) ++ return -EINVAL; ++ if (optoe->dev_class == TWO_ADDR) { ++ /* SFP case */ ++ /* if only using addr 0x50 (first 256 bytes) we're good */ ++ if ((off + len) <= TWO_ADDR_NO_0X51_SIZE) ++ return len; ++ /* if offset exceeds possible pages, we're not good */ ++ if (off >= TWO_ADDR_EEPROM_SIZE) ++ return OPTOE_EOF; ++ /* in between, are pages supported? */ ++ status = optoe_eeprom_read(optoe, client, ®val, ++ TWO_ADDR_PAGEABLE_REG, 1); ++ if (status < 0) ++ return status; /* error out (no module?) */ ++ if (regval & TWO_ADDR_PAGEABLE) { ++ /* Pages supported, trim len to the end of pages */ ++ maxlen = TWO_ADDR_EEPROM_SIZE - off; ++ } else { ++ /* pages not supported, trim len to unpaged size */ ++ if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) ++ return OPTOE_EOF; ++ ++ /* will be accessing addr 0x51, is that supported? */ ++ /* byte 92, bit 6 implies DDM support, 0x51 support */ ++ status = optoe_eeprom_read(optoe, client, ®val, ++ TWO_ADDR_0X51_REG, 1); ++ if (status < 0) ++ return status; ++ if (regval & TWO_ADDR_0X51_SUPP) { ++ /* addr 0x51 is OK */ ++ maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; ++ } else { ++ /* addr 0x51 NOT supported, trim to 256 max */ ++ if (off >= TWO_ADDR_NO_0X51_SIZE) ++ return OPTOE_EOF; ++ maxlen = TWO_ADDR_NO_0X51_SIZE - off; ++ } ++ } ++ len = (len > maxlen) ? maxlen : len; ++ dev_dbg(&client->dev, ++ "page_legal, SFP, off %lld len %ld\n", ++ off, (long int) len); ++ } else { ++ /* QSFP case */ ++ /* if no pages needed, we're good */ ++ if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) ++ return len; ++ /* if offset exceeds possible pages, we're not good */ ++ if (off >= ONE_ADDR_EEPROM_SIZE) ++ return OPTOE_EOF; ++ /* in between, are pages supported? */ ++ status = optoe_eeprom_read(optoe, client, ®val, ++ ONE_ADDR_PAGEABLE_REG, 1); ++ if (status < 0) ++ return status; /* error out (no module?) */ ++ if (regval & ONE_ADDR_NOT_PAGEABLE) { ++ /* pages not supported, trim len to unpaged size */ ++ if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) ++ return OPTOE_EOF; ++ maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; ++ } else { ++ /* Pages supported, trim len to the end of pages */ ++ maxlen = ONE_ADDR_EEPROM_SIZE - off; ++ } ++ len = (len > maxlen) ? maxlen : len; ++ dev_dbg(&client->dev, ++ "page_legal, QSFP, off %lld len %ld\n", ++ off, (long int) len); + } -+ -+ if (present == 0) { -+ /* port is not present */ -+ return -ENODEV; -+ } -+ -+ return sfp_port_write(data, buf, off, count); ++ return len; +} + -+static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, -+ int data_len) ++static ssize_t optoe_read_write(struct optoe_data *optoe, ++ char *buf, loff_t off, size_t len, int opcode) +{ -+#if USE_I2C_BLOCK_READ -+ int status, retry = I2C_RW_RETRY_COUNT; ++ struct i2c_client *client = optoe->client[0]; ++ int chunk; ++ int status = 0; ++ ssize_t retval; ++ size_t pending_len = 0, chunk_len = 0; ++ loff_t chunk_offset = 0, chunk_start_offset = 0; + -+ if (data_len > I2C_SMBUS_BLOCK_MAX) { -+ data_len = I2C_SMBUS_BLOCK_MAX; -+ } -+ -+ while (retry) { -+ status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); -+ if (unlikely(status < 0)) { -+ msleep(I2C_RW_RETRY_INTERVAL); -+ retry--; -+ continue; -+ } -+ -+ break; -+ } -+ -+ if (unlikely(status < 0)) { -+ goto abort; -+ } -+ if (unlikely(status != data_len)) { -+ status = -EIO; -+ goto abort; -+ } -+ -+ //result = data_len; -+ -+abort: -+ return status; -+#else -+ int status, retry = I2C_RW_RETRY_COUNT; -+ -+ while (retry) { -+ status = i2c_smbus_read_byte_data(client, command); -+ if (unlikely(status < 0)) { -+ msleep(I2C_RW_RETRY_INTERVAL); -+ retry--; -+ continue; -+ } -+ -+ break; -+ } -+ -+ if (unlikely(status < 0)) { -+ dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); -+ goto abort; -+ } -+ -+ *data = (u8)status; -+ status = 1; -+ -+abort: -+ return status; -+#endif -+} -+ -+static ssize_t sfp_port_read(struct sfp_port_data *data, -+ char *buf, loff_t off, size_t count) -+{ -+ ssize_t retval = 0; -+ -+ if (unlikely(!count)) { -+ DEBUG_PRINT("Count = 0, return"); -+ return count; -+ } ++ dev_dbg(&client->dev, ++ "%s: off %lld len:%ld, opcode:%s\n", ++ __func__, off, (long int) len, ++ (opcode == OPTOE_READ_OP) ? "r" : "w"); ++ if (unlikely(!len)) ++ return len; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ -+ mutex_lock(&data->update_lock); ++ mutex_lock(&optoe->lock); + -+ while (count) { -+ ssize_t status; ++ /* ++ * Confirm this access fits within the device suppored addr range ++ */ ++ status = optoe_page_legal(optoe, off, len); ++ if ((status == OPTOE_EOF) || (status < 0)) { ++ mutex_unlock(&optoe->lock); ++ return status; ++ } ++ len = status; + -+ status = sfp_eeprom_read(data->client, off, buf, count); -+ if (status <= 0) { -+ if (retval == 0) { -+ retval = status; -+ } -+ break; ++ /* ++ * For each (128 byte) chunk involved in this request, issue a ++ * separate call to sff_eeprom_update_client(), to ++ * ensure that each access recalculates the client/page ++ * and writes the page register as needed. ++ * Note that chunk to page mapping is confusing, is different for ++ * QSFP and SFP, and never needs to be done. Don't try! ++ */ ++ pending_len = len; /* amount remaining to transfer */ ++ retval = 0; /* amount transferred */ ++ for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { ++ ++ /* ++ * Compute the offset and number of bytes to be read/write ++ * ++ * 1. start at offset 0 (within the chunk), and read/write ++ * the entire chunk ++ * 2. start at offset 0 (within the chunk) and read/write less ++ * than entire chunk ++ * 3. start at an offset not equal to 0 and read/write the rest ++ * of the chunk ++ * 4. start at an offset not equal to 0 and read/write less than ++ * (end of chunk - offset) ++ */ ++ chunk_start_offset = chunk * OPTOE_PAGE_SIZE; ++ ++ if (chunk_start_offset < off) { ++ chunk_offset = off; ++ if ((off + pending_len) < (chunk_start_offset + ++ OPTOE_PAGE_SIZE)) ++ chunk_len = pending_len; ++ else ++ chunk_len = OPTOE_PAGE_SIZE - off; ++ } else { ++ chunk_offset = chunk_start_offset; ++ if (pending_len > OPTOE_PAGE_SIZE) ++ chunk_len = OPTOE_PAGE_SIZE; ++ else ++ chunk_len = pending_len; + } + ++ dev_dbg(&client->dev, ++ "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", ++ off, (long int) len, chunk_start_offset, chunk_offset, ++ (long int) chunk_len, (long int) pending_len); ++ ++ /* ++ * note: chunk_offset is from the start of the EEPROM, ++ * not the start of the chunk ++ */ ++ status = optoe_eeprom_update_client(optoe, buf, ++ chunk_offset, chunk_len, opcode); ++ if (status != chunk_len) { ++ /* This is another 'no device present' path */ ++ dev_dbg(&client->dev, ++ "o_u_c: chunk %d c_offset %lld c_len %ld failed %d!\n", ++ chunk, chunk_offset, (long int) chunk_len, status); ++ if (status > 0) ++ retval += status; ++ if (retval == 0) ++ retval = status; ++ break; ++ } + buf += status; -+ off += status; -+ count -= status; ++ pending_len -= status; + retval += status; + } ++ mutex_unlock(&optoe->lock); + -+ mutex_unlock(&data->update_lock); + return retval; -+ +} + -+static ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, ++static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ -+ int present; -+ struct sfp_port_data *data; -+ DEBUG_PRINT("offset = (%d), count = (%d)", off, count); -+ data = dev_get_drvdata(container_of(kobj, struct device, kobj)); ++ struct i2c_client *client = to_i2c_client(container_of(kobj, ++ struct device, kobj)); ++ struct optoe_data *optoe = i2c_get_clientdata(client); + -+ present = sfp_is_port_present(data->client, data->port); -+ if (IS_ERR_VALUE(present)) { -+ return present; -+ } -+ -+ if (present == 0) { -+ /* port is not present */ -+ return -ENODEV; -+ } -+ -+ return sfp_port_read(data, buf, off, count); ++ return optoe_read_write(optoe, buf, off, count, OPTOE_READ_OP); +} + -+static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) ++ ++static ssize_t optoe_bin_write(struct file *filp, struct kobject *kobj, ++ struct bin_attribute *attr, ++ char *buf, loff_t off, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(container_of(kobj, ++ struct device, kobj)); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ++ return optoe_read_write(optoe, buf, off, count, OPTOE_WRITE_OP); ++} ++ ++static int optoe_remove(struct i2c_client *client) ++{ ++ struct optoe_data *optoe; ++ int i; ++ ++ optoe = i2c_get_clientdata(client); ++ sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); ++ sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); ++ ++ for (i = 1; i < optoe->num_addresses; i++) ++ i2c_unregister_device(optoe->client[i]); ++ ++#ifdef EEPROM_CLASS ++ eeprom_device_unregister(optoe->eeprom_dev); ++#endif ++ ++ kfree(optoe->writebuf); ++ kfree(optoe); ++ return 0; ++} ++ ++static ssize_t show_dev_class(struct device *dev, ++ struct device_attribute *dattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ssize_t count; ++ ++ mutex_lock(&optoe->lock); ++ count = sprintf(buf, "%d\n", optoe->dev_class); ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++static ssize_t set_dev_class(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ int dev_class; ++ ++ /* ++ * dev_class is actually the number of i2c addresses used, thus ++ * legal values are "1" (QSFP class) and "2" (SFP class) ++ */ ++ ++ if (kstrtoint(buf, 0, &dev_class) != 0 || ++ dev_class < 1 || dev_class > 2) ++ return -EINVAL; ++ ++ mutex_lock(&optoe->lock); ++ optoe->dev_class = dev_class; ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++/* ++ * if using the EEPROM CLASS driver, we don't report a port_name, ++ * the EEPROM CLASS drive handles that. Hence all this code is ++ * only compiled if we are NOT using the EEPROM CLASS driver. ++ */ ++#ifndef EEPROM_CLASS ++ ++static ssize_t show_port_name(struct device *dev, ++ struct device_attribute *dattr, char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ ssize_t count; ++ ++ mutex_lock(&optoe->lock); ++ count = sprintf(buf, "%s\n", optoe->port_name); ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++static ssize_t set_port_name(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct optoe_data *optoe = i2c_get_clientdata(client); ++ char port_name[MAX_PORT_NAME_LEN]; ++ ++ /* no checking, this value is not used except by show_port_name */ ++ ++ if (sscanf(buf, "%19s", port_name) != 1) ++ return -EINVAL; ++ ++ mutex_lock(&optoe->lock); ++ strcpy(optoe->port_name, port_name); ++ mutex_unlock(&optoe->lock); ++ ++ return count; ++} ++ ++static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name); ++#endif /* if NOT defined EEPROM_CLASS, the common case */ ++ ++static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class); ++ ++static struct attribute *optoe_attrs[] = { ++#ifndef EEPROM_CLASS ++ &dev_attr_port_name.attr, ++#endif ++ &dev_attr_dev_class.attr, ++ NULL, ++}; ++ ++static struct attribute_group optoe_attr_group = { ++ .attrs = optoe_attrs, ++}; ++ ++static int optoe_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) +{ + int err; ++ int use_smbus = 0; ++ struct optoe_platform_data chip; ++ struct optoe_data *optoe; ++ int num_addresses = 0; ++ char port_name[MAX_PORT_NAME_LEN]; + -+ sysfs_bin_attr_init(eeprom); -+ eeprom->attr.name = EEPROM_NAME; -+ eeprom->attr.mode = S_IWUSR | S_IRUGO; -+ eeprom->read = sfp_bin_read; -+ eeprom->write = sfp_bin_write; -+ eeprom->size = EEPROM_SIZE; -+ -+ /* Create eeprom file */ -+ err = sysfs_create_bin_file(kobj, eeprom); -+ if (err) { -+ return err; ++ if (client->addr != 0x50) { ++ dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n", ++ client->addr); ++ err = -EINVAL; ++ goto exit; + } + -+ return 0; -+} -+ -+static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) -+{ -+ sysfs_remove_bin_file(kobj, eeprom); -+ return 0; -+} -+ -+static const struct attribute_group sfp_msa_group = { -+ .attrs = sfp_msa_attributes, -+}; -+ -+static int sfp_i2c_check_functionality(struct i2c_client *client) -+{ -+#if USE_I2C_BLOCK_READ -+ return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); ++ if (client->dev.platform_data) { ++ chip = *(struct optoe_platform_data *)client->dev.platform_data; ++ /* take the port name from the supplied platform data */ ++#ifdef EEPROM_CLASS ++ strncpy(port_name, chip.eeprom_data->label, MAX_PORT_NAME_LEN); +#else -+ return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); ++ memcpy(port_name, chip.port_name, MAX_PORT_NAME_LEN); +#endif -+} -+ -+static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, -+ struct sfp_msa_data **data) -+{ -+ int status; -+ struct sfp_msa_data *msa; -+ -+ if (!sfp_i2c_check_functionality(client)) { -+ status = -EIO; -+ goto exit; -+ } -+ -+ msa = kzalloc(sizeof(struct sfp_msa_data), GFP_KERNEL); -+ if (!msa) { -+ status = -ENOMEM; -+ goto exit; -+ } -+ -+ /* Register sysfs hooks */ -+ status = sysfs_create_group(&client->dev.kobj, &sfp_msa_group); -+ if (status) { -+ goto exit_free; -+ } -+ -+ /* init eeprom */ -+ status = sfp_sysfs_eeprom_init(&client->dev.kobj, &msa->eeprom.bin); -+ if (status) { -+ goto exit_remove; -+ } -+ -+ *data = msa; -+ dev_info(&client->dev, "sfp msa '%s'\n", client->name); -+ -+ return 0; -+ -+exit_remove: -+ sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); -+exit_free: -+ kfree(msa); -+exit: -+ -+ return status; -+} -+ -+static const struct attribute_group sfp_ddm_group = { -+ .attrs = sfp_ddm_attributes, -+}; -+ -+static int sfp_ddm_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, -+ struct sfp_ddm_data **data) -+{ -+ int status; -+ struct sfp_ddm_data *ddm; -+ -+ if (!sfp_i2c_check_functionality(client)) { -+ status = -EIO; -+ goto exit; -+ } -+ -+ ddm = kzalloc(sizeof(struct sfp_ddm_data), GFP_KERNEL); -+ if (!ddm) { -+ status = -ENOMEM; -+ goto exit; -+ } -+ -+ /* Register sysfs hooks */ -+ status = sysfs_create_group(&client->dev.kobj, &sfp_ddm_group); -+ if (status) { -+ goto exit_free; -+ } -+ -+ /* init eeprom */ -+ status = sfp_sysfs_eeprom_init(&client->dev.kobj, &ddm->eeprom.bin); -+ if (status) { -+ goto exit_remove; -+ } -+ -+ *data = ddm; -+ dev_info(&client->dev, "sfp ddm '%s'\n", client->name); -+ -+ return 0; -+ -+exit_remove: -+ sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); -+exit_free: -+ kfree(ddm); -+exit: -+ -+ return status; -+} -+ -+static const struct attribute_group qsfp_group = { -+ .attrs = qsfp_attributes, -+}; -+ -+static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, -+ struct qsfp_data **data) -+{ -+ int status; -+ struct qsfp_data *qsfp; -+ -+ if (!sfp_i2c_check_functionality(client)) { -+ status = -EIO; -+ goto exit; -+ } -+ -+ qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); -+ if (!qsfp) { -+ status = -ENOMEM; -+ goto exit; -+ } -+ -+ /* Register sysfs hooks */ -+ status = sysfs_create_group(&client->dev.kobj, &qsfp_group); -+ if (status) { -+ goto exit_free; -+ } -+ -+ /* init eeprom */ -+ status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); -+ if (status) { -+ goto exit_remove; -+ } -+ -+ *data = qsfp; -+ dev_info(&client->dev, "qsfp '%s'\n", client->name); -+ -+ return 0; -+ -+exit_remove: -+ sysfs_remove_group(&client->dev.kobj, &qsfp_group); -+exit_free: -+ kfree(qsfp); -+exit: -+ -+ return status; -+} -+ -+/* Platform dependent +++ */ -+static int sfp_device_probe(struct i2c_client *client, -+ const struct i2c_device_id *dev_id) -+{ -+ struct sfp_port_data *data = NULL; -+ -+ data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); -+ if (!data) { -+ return -ENOMEM; -+ } -+ -+ i2c_set_clientdata(client, data); -+ mutex_init(&data->update_lock); -+ data->port = dev_id->driver_data; -+ data->client = client; -+ -+ if (client->addr != SFP_EEPROM_A0_I2C_ADDR && -+ client->addr != SFP_EEPROM_A2_I2C_ADDR ) { -+ return -ENODEV; -+ } -+ -+ if (dev_id->driver_data >= as4610_sfp1 && dev_id->driver_data <= as4610_sfp4) { -+ if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { -+ data->driver_type = DRIVER_TYPE_SFP_MSA; -+ return sfp_msa_probe(client, dev_id, &data->msa); -+ } -+ else if (client->addr == SFP_EEPROM_A2_I2C_ADDR) { -+ data->driver_type = DRIVER_TYPE_SFP_DDM; -+ return sfp_ddm_probe(client, dev_id, &data->ddm); ++ dev_dbg(&client->dev, ++ "probe, chip provided, flags:0x%x; name: %s\n", ++ chip.flags, client->name); ++ } else { ++ if (!id->driver_data) { ++ err = -ENODEV; ++ goto exit; + } ++ dev_dbg(&client->dev, "probe, building chip\n"); ++ strcpy(port_name, "unitialized"); ++ chip.flags = 0; ++#ifdef EEPROM_CLASS ++ chip.eeprom_data = NULL; ++#endif + } -+ else if (dev_id->driver_data >= as4610_sfp5 && dev_id->driver_data <= as4610_sfp6) { -+ if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { -+ data->driver_type = DRIVER_TYPE_QSFP; -+ return qsfp_probe(client, dev_id, &data->qsfp); ++ ++ /* Use I2C operations unless we're stuck with SMBus extensions. */ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { ++ if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { ++ use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; ++ } else if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_WORD_DATA)) { ++ use_smbus = I2C_SMBUS_WORD_DATA; ++ } else if (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_READ_BYTE_DATA)) { ++ use_smbus = I2C_SMBUS_BYTE_DATA; ++ } else { ++ err = -EPFNOSUPPORT; ++ goto exit; + } + } + -+ return -ENODEV; -+} -+/* Platform dependent --- */ + -+static int sfp_msa_remove(struct i2c_client *client, struct sfp_msa_data *data) -+{ -+ sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); -+ sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); -+ kfree(data); -+ return 0; -+} ++ /* ++ * Make room for two i2c clients ++ */ ++ num_addresses = 2; + -+static int sfp_ddm_remove(struct i2c_client *client, struct sfp_ddm_data *data) -+{ -+ sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); -+ sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); -+ kfree(data); -+ return 0; -+} ++ optoe = kzalloc(sizeof(struct optoe_data) + ++ num_addresses * sizeof(struct i2c_client *), ++ GFP_KERNEL); ++ if (!optoe) { ++ err = -ENOMEM; ++ goto exit; ++ } + -+static int qfp_remove(struct i2c_client *client, struct qsfp_data *data) -+{ -+ sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); -+ sysfs_remove_group(&client->dev.kobj, &qsfp_group); -+ kfree(data); -+ return 0; -+} ++ mutex_init(&optoe->lock); + -+static int sfp_device_remove(struct i2c_client *client) -+{ -+ struct sfp_port_data *data = i2c_get_clientdata(client); ++ /* determine whether this is a one-address or two-address module */ ++ if ((strcmp(client->name, "optoe1") == 0) || ++ (strcmp(client->name, "sff8436") == 0)) { ++ /* one-address (eg QSFP) family */ ++ optoe->dev_class = ONE_ADDR; ++ chip.byte_len = ONE_ADDR_EEPROM_SIZE; ++ num_addresses = 1; ++ } else if ((strcmp(client->name, "optoe2") == 0) || ++ (strcmp(client->name, "24c04") == 0)) { ++ /* SFP family */ ++ optoe->dev_class = TWO_ADDR; ++ chip.byte_len = TWO_ADDR_EEPROM_SIZE; ++ } else { /* those were the only two choices */ ++ err = -EINVAL; ++ goto exit; ++ } + -+ switch (data->driver_type) { -+ case DRIVER_TYPE_SFP_MSA: -+ return sfp_msa_remove(client, data->msa); -+ case DRIVER_TYPE_SFP_DDM: -+ return sfp_ddm_remove(client, data->ddm); -+ case DRIVER_TYPE_QSFP: -+ return qfp_remove(client, data->qsfp); ++ dev_dbg(&client->dev, "dev_class: %d\n", optoe->dev_class); ++ optoe->use_smbus = use_smbus; ++ optoe->chip = chip; ++ optoe->num_addresses = num_addresses; ++ memcpy(optoe->port_name, port_name, MAX_PORT_NAME_LEN); ++ ++ /* ++ * Export the EEPROM bytes through sysfs, since that's convenient. ++ * By default, only root should see the data (maybe passwords etc) ++ */ ++ sysfs_bin_attr_init(&optoe->bin); ++ optoe->bin.attr.name = "eeprom"; ++ optoe->bin.attr.mode = 0444; ++ optoe->bin.read = optoe_bin_read; ++ optoe->bin.size = chip.byte_len; ++ ++ if (!use_smbus || ++ (i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || ++ i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_WORD_DATA) || ++ i2c_check_functionality(client->adapter, ++ I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { ++ /* ++ * NOTE: AN-2079 ++ * Finisar recommends that the host implement 1 byte writes ++ * only since this module only supports 32 byte page boundaries. ++ * 2 byte writes are acceptable for PE and Vout changes per ++ * Application Note AN-2071. ++ */ ++ unsigned int write_max = 1; ++ ++ optoe->bin.write = optoe_bin_write; ++ optoe->bin.attr.mode |= 0200; ++ ++ if (write_max > io_limit) ++ write_max = io_limit; ++ if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) ++ write_max = I2C_SMBUS_BLOCK_MAX; ++ optoe->write_max = write_max; ++ ++ /* buffer (data + address at the beginning) */ ++ optoe->writebuf = kmalloc(write_max + 2, GFP_KERNEL); ++ if (!optoe->writebuf) { ++ err = -ENOMEM; ++ goto exit_kfree; ++ } ++ } else { ++ dev_warn(&client->dev, ++ "cannot write due to controller restrictions."); ++ } ++ ++ optoe->client[0] = client; ++ ++ /* SFF-8472 spec requires that the second I2C address be 0x51 */ ++ if (num_addresses == 2) { ++ optoe->client[1] = i2c_new_dummy(client->adapter, 0x51); ++ if (!optoe->client[1]) { ++ dev_err(&client->dev, "address 0x51 unavailable\n"); ++ err = -EADDRINUSE; ++ goto err_struct; ++ } ++ } ++ ++ /* create the sysfs eeprom file */ ++ err = sysfs_create_bin_file(&client->dev.kobj, &optoe->bin); ++ if (err) ++ goto err_struct; ++ ++ optoe->attr_group = optoe_attr_group; ++ ++ err = sysfs_create_group(&client->dev.kobj, &optoe->attr_group); ++ if (err) { ++ dev_err(&client->dev, "failed to create sysfs attribute group.\n"); ++ goto err_struct; ++ } ++ ++#ifdef EEPROM_CLASS ++ optoe->eeprom_dev = eeprom_device_register(&client->dev, ++ chip.eeprom_data); ++ if (IS_ERR(optoe->eeprom_dev)) { ++ dev_err(&client->dev, "error registering eeprom device.\n"); ++ err = PTR_ERR(optoe->eeprom_dev); ++ goto err_sysfs_cleanup; ++ } ++#endif ++ ++ i2c_set_clientdata(client, optoe); ++ ++ dev_info(&client->dev, "%zu byte %s EEPROM, %s\n", ++ optoe->bin.size, client->name, ++ optoe->bin.write ? "read/write" : "read-only"); ++ ++ if (use_smbus == I2C_SMBUS_WORD_DATA || ++ use_smbus == I2C_SMBUS_BYTE_DATA) { ++ dev_notice(&client->dev, ++ "Falling back to %s reads, performance will suffer\n", ++ use_smbus == I2C_SMBUS_WORD_DATA ? "word" : "byte"); + } + + return 0; ++ ++#ifdef EEPROM_CLASS ++err_sysfs_cleanup: ++ sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); ++ sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); ++#endif ++ ++err_struct: ++ if (num_addresses == 2) { ++ if (optoe->client[1]) ++ i2c_unregister_device(optoe->client[1]); ++ } ++ ++ kfree(optoe->writebuf); ++exit_kfree: ++ kfree(optoe); ++exit: ++ dev_dbg(&client->dev, "probe error %d\n", err); ++ ++ return err; +} + -+/* Addresses scanned -+ */ -+static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; ++/*-------------------------------------------------------------------------*/ + -+static struct i2c_driver sfp_driver = { ++static struct i2c_driver optoe_driver = { + .driver = { -+ .name = DRIVER_NAME, ++ .name = "optoe", ++ .owner = THIS_MODULE, + }, -+ .probe = sfp_device_probe, -+ .remove = sfp_device_remove, -+ .id_table = sfp_device_id, -+ .address_list = normal_i2c, ++ .probe = optoe_probe, ++ .remove = optoe_remove, ++ .id_table = optoe_ids, +}; + -+static int __init sfp_init(void) ++static int __init optoe_init(void) +{ -+ return i2c_add_driver(&sfp_driver); -+} + -+static void __exit sfp_exit(void) ++ if (!io_limit) { ++ pr_err("optoe: io_limit must not be 0!\n"); ++ return -EINVAL; ++ } ++ ++ io_limit = rounddown_pow_of_two(io_limit); ++ return i2c_add_driver(&optoe_driver); ++} ++module_init(optoe_init); ++ ++static void __exit optoe_exit(void) +{ -+ i2c_del_driver(&sfp_driver); ++ i2c_del_driver(&optoe_driver); +} ++module_exit(optoe_exit); + -+MODULE_AUTHOR("Brandon Chuang "); -+MODULE_DESCRIPTION("accton as4610_sfp driver"); ++MODULE_DESCRIPTION("Driver for optical transceiver (SFP, QSFP, ...) EEPROMs"); ++MODULE_AUTHOR("DON BOLLINGER "); +MODULE_LICENSE("GPL"); -+ -+late_initcall(sfp_init); -+module_exit(sfp_exit); -+ diff --git a/include/linux/accton_i2c_cpld.h b/include/linux/accton_i2c_cpld.h new file mode 100644 index 0000000..9b75abd --- /dev/null -+++ b/include/linux/accton_i2c_cpld.h ++++ b/include/linux/accton_as4610_cpld.h @@ -0,0 +1,76 @@ +/* -+ * A hwmon driver for the accton_i2c_cpld ++ * A hwmon driver for the accton as4610 cpld + * + * Copyright (C) 2016 Accton Technology Corporation. + * Brandon Chuang @@ -3874,8 +3908,8 @@ index 0000000..9b75abd + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + -+extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -+extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); ++extern int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg); ++extern int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +#define AS4610_CPLD_SLAVE_ADDR 0x30 +#define AS4610_CPLD_PID_OFFSET 0x01 /* Product ID offset */ @@ -3892,7 +3926,7 @@ index 0000000..9b75abd + +static inline int as4610_product_id(void) +{ -+ int pid = accton_i2c_cpld_read(AS4610_CPLD_SLAVE_ADDR, AS4610_CPLD_PID_OFFSET); ++ int pid = as4610_54_cpld_read(AS4610_CPLD_SLAVE_ADDR, AS4610_CPLD_PID_OFFSET); + pid &= 0xF; + + if (pid < PID_AS4610_30T || pid > PID_AS4610_54T_B || pid == PID_RESERVED) { @@ -3929,4 +3963,3 @@ index 0000000..9b75abd + return nFan; +} + - diff --git a/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-30/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts b/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-30/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts index 0e7a33c0..3226b312 100644 --- a/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-30/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts +++ b/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-30/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts @@ -139,8 +139,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <0>; - sfp_eeprom@50 { - compatible = "at,as4610_sfp1"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port49"; }; @@ -151,8 +151,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <1>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp2"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port50"; }; @@ -163,8 +163,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <2>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp3"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port51"; }; @@ -175,8 +175,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <3>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp4"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port52"; }; @@ -187,9 +187,10 @@ #address-cells = <1>; #size-cells = <0>; reg = <4>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp5"; + optoe@50 { + compatible = "optoe1"; reg = <0x50>; + label = "port53"; }; }; @@ -198,9 +199,10 @@ #address-cells = <1>; #size-cells = <0>; reg = <5>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp6"; + optoe@50 { + compatible = "optoe1"; reg = <0x50>; + label = "port54"; }; }; diff --git a/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-54/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts b/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-54/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts index 0e7a33c0..3226b312 100644 --- a/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-54/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts +++ b/packages/platforms/accton/armel/arm-accton-as4610/arm-accton-as4610-54/platform-config/r0/builds/dtb/arm-accton-as4610-54-r0.dts @@ -139,8 +139,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <0>; - sfp_eeprom@50 { - compatible = "at,as4610_sfp1"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port49"; }; @@ -151,8 +151,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <1>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp2"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port50"; }; @@ -163,8 +163,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <2>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp3"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port51"; }; @@ -175,8 +175,8 @@ #address-cells = <1>; #size-cells = <0>; reg = <3>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp4"; + optoe@50 { + compatible = "optoe2"; reg = <0x50>; label = "port52"; }; @@ -187,9 +187,10 @@ #address-cells = <1>; #size-cells = <0>; reg = <4>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp5"; + optoe@50 { + compatible = "optoe1"; reg = <0x50>; + label = "port53"; }; }; @@ -198,9 +199,10 @@ #address-cells = <1>; #size-cells = <0>; reg = <5>; - sfp_eeprom@50 { - compatible = "accton,as4610_sfp6"; + optoe@50 { + compatible = "optoe1"; reg = <0x50>; + label = "port54"; }; }; diff --git a/packages/platforms/accton/armel/arm-accton-as4610/src/arm_accton_as4610/module/src/sfpi.c b/packages/platforms/accton/armel/arm-accton-as4610/src/arm_accton_as4610/module/src/sfpi.c index 7199a31a..41379f73 100644 --- a/packages/platforms/accton/armel/arm-accton-as4610/src/arm_accton_as4610/module/src/sfpi.c +++ b/packages/platforms/accton/armel/arm-accton-as4610/src/arm_accton_as4610/module/src/sfpi.c @@ -24,50 +24,31 @@ * ***********************************************************/ #include +#include #include "platform_lib.h" #include #include "arm_accton_as4610_log.h" -#define MAX_SFP_PATH 64 -static char sfp_node_path[MAX_SFP_PATH] = {0}; -#define FRONT_PORT_MUX_INDEX(port) (port-46) +#define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" +#define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/0-0030/module_present_%d" +#define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/0-0030/module_rx_los_%d" +#define MODULE_TXFAULT_FORMAT "/sys/bus/i2c/devices/0-0030/module_tx_fault_%d" +#define MODULE_PRESENT_ALL_ATTR_CPLD "/sys/bus/i2c/devices/0-0030/module_present_all" +#define MODULE_RXLOS_ALL_ATTR_CPLD "/sys/bus/i2c/devices/0-0030/module_rx_los_all" -static int -sfp_node_read_int(char *node_path, int *value, int data_len) +static int front_port_bus_index(int port) { - int ret = 0; - char buf[8]; - *value = 0; - - ret = deviceNodeReadString(node_path, buf, sizeof(buf), data_len); - - if (ret == 0) { - *value = atoi(buf); - } - - return ret; + return (platform_id == PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0) ? + (port - 22) : /* PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0 */ + (port - 46) ; /* PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0 */ } -static char* -sfp_get_port_path_addr(int port, int addr, char *node_name) +static int front_port_to_cpld_port(int port) { - int front_port_mux_id; - - if(platform_id == PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0) - front_port_mux_id = port - 22; - else /*PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0*/ - front_port_mux_id = port - 46; - - sprintf(sfp_node_path, "/sys/bus/i2c/devices/%d-00%d/%s", - front_port_mux_id, addr, node_name); - return sfp_node_path; -} - -static char* -sfp_get_port_path(int port, char *node_name) -{ - return sfp_get_port_path_addr(port, 50, node_name); + return (platform_id == PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0) ? + (port - 23) : /* PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0 */ + (port - 47) ; /* PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0 */ } /************************************************************ @@ -115,9 +96,9 @@ onlp_sfpi_is_present(int port) * Return < 0 if error. */ int present; - char* path = sfp_get_port_path(port, "sfp_is_present"); - - if (sfp_node_read_int(path, &present, 0) != 0) { + int cpld_port = front_port_to_cpld_port(port); + + if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, cpld_port) < 0) { AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -129,7 +110,6 @@ int onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) { uint32_t byte; - char* path; FILE* fp; int port; @@ -140,18 +120,18 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) else /*PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0*/ port = 48; - path = sfp_get_port_path(port, "sfp_is_present_all"); - fp = fopen(path, "r"); - + /* Read present status of each port */ + fp = fopen(MODULE_PRESENT_ALL_ATTR_CPLD, "r"); if(fp == NULL) { - AIM_LOG_ERROR("Unable to open the sfp_is_present_all device file."); + AIM_LOG_ERROR("Unable to open the module_present_all device file of CPLD."); return ONLP_STATUS_E_INTERNAL; } + int count = fscanf(fp, "%x", &byte); fclose(fp); if(count != 1) { /* Likely a CPLD read timeout. */ - AIM_LOG_ERROR("Unable to read all fields from the sfp_is_present_all device file."); + AIM_LOG_ERROR("Unable to read all fields the module_present_all device file of CPLD."); return ONLP_STATUS_E_INTERNAL; } @@ -173,7 +153,6 @@ int onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) { uint32_t byte; - char* path; FILE* fp; int port; @@ -182,16 +161,18 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) else /*PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0*/ port = 48; - path = sfp_get_port_path(port, "sfp_rx_los_all"); - fp = fopen(path, "r"); + /* Read present status of each port */ + fp = fopen(MODULE_RXLOS_ALL_ATTR_CPLD, "r"); if(fp == NULL) { - AIM_LOG_ERROR("Unable to open the sfp_rx_los_all device file."); + AIM_LOG_ERROR("Unable to open the module_rx_los_all device file of CPLD."); return ONLP_STATUS_E_INTERNAL; } + int count = fscanf(fp, "%x", &byte); fclose(fp); if(count != 1) { - AIM_LOG_ERROR("Unable to read all fields from the sfp_rx_los_all device file."); + /* Likely a CPLD read timeout. */ + AIM_LOG_ERROR("Unable to read all fields the module_rx_los_all device file of CPLD."); return ONLP_STATUS_E_INTERNAL; } @@ -212,32 +193,51 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) int onlp_sfpi_eeprom_read(int port, uint8_t data[256]) { - char* path = sfp_get_port_path(port, "sfp_eeprom"); - /* * 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 (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) { + if(onlp_file_read(data, 256, &size, PORT_EEPROM_FORMAT, front_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]) { - char* path = sfp_get_port_path_addr(port, 51, "sfp_eeprom"); - memset(data, 0, 256); + FILE* fp; + char file[64] = {0}; + + sprintf(file, PORT_EEPROM_FORMAT, front_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 (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) { - AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port); + 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; } @@ -247,45 +247,24 @@ onlp_sfpi_dom_read(int port, uint8_t data[256]) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; - - switch(control) - { - case ONLP_SFP_CONTROL_TX_DISABLE: - { - char* path = sfp_get_port_path(port, "sfp_tx_disable"); - - if (deviceNodeWriteInt(path, value, 0) != 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; - } - else { - rv = ONLP_STATUS_OK; - } - break; - } - - default: - rv = ONLP_STATUS_E_UNSUPPORTED; - break; - } - - return rv; + return ONLP_STATUS_E_UNSUPPORTED; } int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { int rv; - char* path = NULL; + int cpld_port = front_port_to_cpld_port(port); + + if (cpld_port > 4) { + return ONLP_STATUS_E_UNSUPPORTED; + } switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { - path = sfp_get_port_path(port, "sfp_rx_los"); - - if (sfp_node_read_int(path, value, 0) != 0) { + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, cpld_port) < 0) { AIM_LOG_ERROR("Unable to read rx_los status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -297,9 +276,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_FAULT: { - path = sfp_get_port_path(port, "sfp_tx_fault"); - - if (sfp_node_read_int(path, value, 0) != 0) { + if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, cpld_port) < 0) { AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -309,20 +286,6 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) break; } - case ONLP_SFP_CONTROL_TX_DISABLE: - { - path = sfp_get_port_path(port, "sfp_tx_disable"); - - if (sfp_node_read_int(path, value, 0) != 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; - } - else { - rv = ONLP_STATUS_OK; - } - break; - } - default: rv = ONLP_STATUS_E_UNSUPPORTED; } @@ -330,9 +293,9 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) return rv; } - int onlp_sfpi_denit(void) { return ONLP_STATUS_OK; } + From bde2ccb6eb7eecf52449f6e0a3014319bc706814 Mon Sep 17 00:00:00 2001 From: Brandon Chuang Date: Fri, 22 Jun 2018 15:16:29 +0800 Subject: [PATCH 02/22] Remove optoe.c under accton x86-64 folder, use the common one instead --- .../accton/x86-64/modules/builds/optoe.c | 1146 ----------------- 1 file changed, 1146 deletions(-) delete mode 100755 packages/platforms/accton/x86-64/modules/builds/optoe.c diff --git a/packages/platforms/accton/x86-64/modules/builds/optoe.c b/packages/platforms/accton/x86-64/modules/builds/optoe.c deleted file mode 100755 index b3064f02..00000000 --- a/packages/platforms/accton/x86-64/modules/builds/optoe.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* - * optoe.c - A driver to read and write the EEPROM on optical transceivers - * (SFP, QSFP and similar I2C based devices) - * - * Copyright (C) 2014 Cumulus networks Inc. - * Copyright (C) 2017 Finisar Corp. - * - * 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 Freeoftware Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* - * Description: - * a) Optical transceiver EEPROM read/write transactions are just like - * the at24 eeproms managed by the at24.c i2c driver - * b) The register/memory layout is up to 256 128 byte pages defined by - * a "pages valid" register and switched via a "page select" - * register as explained in below diagram. - * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 - * bytes of address space, and always references the same - * location, independent of the page select register. - * All mapped pages are mapped into the upper 128 bytes - * (offset 128-255) of the i2c address. - * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 - * (A0h in the spec), and map all pages in the upper 128 bytes - * of that address. - * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data - * at I2C address 0x50, and 256 bytes of data at I2C address - * 0x51 (A2h in the spec). Page selection and paged access - * only apply to this second I2C address (0x51). - * e) The address space is presented, by the driver, as a linear - * address space. For devices with one I2C client at address - * 0x50 (eg QSFP), offset 0-127 are in the lower - * half of address 50/A0h/client[0]. Offset 128-255 are in - * page 0, 256-383 are page 1, etc. More generally, offset - * 'n' resides in page (n/128)-1. ('page -1' is the lower - * half, offset 0-127). - * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), - * the address space places offset 0-127 in the lower - * half of 50/A0/client[0], offset 128-255 in the upper - * half. Offset 256-383 is in the lower half of 51/A2/client[1]. - * Offset 384-511 is in page 0, in the upper half of 51/A2/... - * Offset 512-639 is in page 1, in the upper half of 51/A2/... - * Offset 'n' is in page (n/128)-3 (for n > 383) - * - * One I2c addressed (eg QSFP) Memory Map - * - * 2-Wire Serial Address: 1010000x - * - * Lower Page 00h (128 bytes) - * ===================== - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * |Page Select Byte(127)| - * ===================== - * | - * | - * | - * | - * V - * ------------------------------------------------------------ - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * V V V V - * ------------ -------------- --------------- -------------- - * | | | | | | | | - * | Upper | | Upper | | Upper | | Upper | - * | Page 00h | | Page 01h | | Page 02h | | Page 03h | - * | | | (Optional) | | (Optional) | | (Optional | - * | | | | | | | for Cable | - * | | | | | | | Assemblies) | - * | ID | | AST | | User | | | - * | Fields | | Table | | EEPROM Data | | | - * | | | | | | | | - * | | | | | | | | - * | | | | | | | | - * ------------ -------------- --------------- -------------- - * - * The SFF 8436 (QSFP) spec only defines the 4 pages described above. - * In anticipation of future applications and devices, this driver - * supports access to the full architected range, 256 pages. - * - **/ - -/* #define DEBUG 1 */ - -#undef EEPROM_CLASS -#ifdef CONFIG_EEPROM_CLASS -#define EEPROM_CLASS -#endif -#ifdef CONFIG_EEPROM_CLASS_MODULE -#define EEPROM_CLASS -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef EEPROM_CLASS -#include -#endif - -#include - -/* The maximum length of a port name */ -#define MAX_PORT_NAME_LEN 20 - -struct optoe_platform_data { - u32 byte_len; /* size (sum of all addr) */ - u16 page_size; /* for writes */ - u8 flags; - void *dummy1; /* backward compatibility */ - void *dummy2; /* backward compatibility */ - -#ifdef EEPROM_CLASS - struct eeprom_platform_data *eeprom_data; -#endif - char port_name[MAX_PORT_NAME_LEN]; -}; - -/* fundamental unit of addressing for EEPROM */ -#define OPTOE_PAGE_SIZE 128 -/* - * Single address devices (eg QSFP) have 256 pages, plus the unpaged - * low 128 bytes. If the device does not support paging, it is - * only 2 'pages' long. - */ -#define OPTOE_ARCH_PAGES 256 -#define ONE_ADDR_EEPROM_SIZE ((1 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) -#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * OPTOE_PAGE_SIZE) -/* - * Dual address devices (eg SFP) have 256 pages, plus the unpaged - * low 128 bytes, plus 256 bytes at 0x50. If the device does not - * support paging, it is 4 'pages' long. - */ -#define TWO_ADDR_EEPROM_SIZE ((3 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) -#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * OPTOE_PAGE_SIZE) -#define TWO_ADDR_NO_0X51_SIZE (2 * OPTOE_PAGE_SIZE) - -/* a few constants to find our way around the EEPROM */ -#define OPTOE_PAGE_SELECT_REG 0x7F -#define ONE_ADDR_PAGEABLE_REG 0x02 -#define ONE_ADDR_NOT_PAGEABLE (1<<2) -#define TWO_ADDR_PAGEABLE_REG 0x40 -#define TWO_ADDR_PAGEABLE (1<<4) -#define TWO_ADDR_0X51_REG 92 -#define TWO_ADDR_0X51_SUPP (1<<6) -#define OPTOE_ID_REG 0 -#define OPTOE_READ_OP 0 -#define OPTOE_WRITE_OP 1 -#define OPTOE_EOF 0 /* used for access beyond end of device */ - -struct optoe_data { - struct optoe_platform_data chip; - int use_smbus; - char port_name[MAX_PORT_NAME_LEN]; - - /* - * Lock protects against activities from other Linux tasks, - * but not from changes by other I2C masters. - */ - struct mutex lock; - struct bin_attribute bin; - struct attribute_group attr_group; - - u8 *writebuf; - unsigned int write_max; - - unsigned int num_addresses; - -#ifdef EEPROM_CLASS - struct eeprom_device *eeprom_dev; -#endif - - /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ - int dev_class; - - struct i2c_client *client[]; -}; - - -/* - * This parameter is to help this driver avoid blocking other drivers out - * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C - * clock, one 256 byte read takes about 1/43 second which is excessive; - * but the 1/170 second it takes at 400 kHz may be quite reasonable; and - * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. - * - * This value is forced to be a power of two so that writes align on pages. - */ -static unsigned int io_limit = OPTOE_PAGE_SIZE; - -/* - * specs often allow 5 msec for a page write, sometimes 20 msec; - * it's important to recover from write timeouts. - */ -static unsigned int write_timeout = 25; - -/* - * flags to distinguish one-address (QSFP family) from two-address (SFP family) - * If the family is not known, figure it out when the device is accessed - */ -#define ONE_ADDR 1 -#define TWO_ADDR 2 - -static const struct i2c_device_id optoe_ids[] = { - { "optoe1", ONE_ADDR }, - { "optoe2", TWO_ADDR }, - { "sff8436", ONE_ADDR }, - { "24c04", TWO_ADDR }, - { /* END OF LIST */ } -}; -MODULE_DEVICE_TABLE(i2c, optoe_ids); - -/*-------------------------------------------------------------------------*/ -/* - * This routine computes the addressing information to be used for - * a given r/w request. - * - * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), - * the page, and the offset. - * - * Handles both single address (eg QSFP) and two address (eg SFP). - * For SFP, offset 0-255 are on client[0], >255 is on client[1] - * Offset 256-383 are on the lower half of client[1] - * Pages are accessible on the upper half of client[1]. - * Offset >383 are in 128 byte pages mapped into the upper half - * - * For QSFP, all offsets are on client[0] - * offset 0-127 are on the lower half of client[0] (no paging) - * Pages are accessible on the upper half of client[1]. - * Offset >127 are in 128 byte pages mapped into the upper half - * - * Callers must not read/write beyond the end of a client or a page - * without recomputing the client/page. Hence offset (within page) - * plus length must be less than or equal to 128. (Note that this - * routine does not have access to the length of the call, hence - * cannot do the validity check.) - * - * Offset within Lower Page 00h and Upper Page 00h are not recomputed - */ - -static uint8_t optoe_translate_offset(struct optoe_data *optoe, - loff_t *offset, struct i2c_client **client) -{ - unsigned int page = 0; - - *client = optoe->client[0]; - - /* if SFP style, offset > 255, shift to i2c addr 0x51 */ - if (optoe->dev_class == TWO_ADDR) { - if (*offset > 255) { - /* like QSFP, but shifted to client[1] */ - *client = optoe->client[1]; - *offset -= 256; - } - } - - /* - * if offset is in the range 0-128... - * page doesn't matter (using lower half), return 0. - * offset is already correct (don't add 128 to get to paged area) - */ - if (*offset < OPTOE_PAGE_SIZE) - return page; - - /* note, page will always be positive since *offset >= 128 */ - page = (*offset >> 7)-1; - /* 0x80 places the offset in the top half, offset is last 7 bits */ - *offset = OPTOE_PAGE_SIZE + (*offset & 0x7f); - - return page; /* note also returning client and offset */ -} - -static ssize_t optoe_eeprom_read(struct optoe_data *optoe, - struct i2c_client *client, - char *buf, unsigned int offset, size_t count) -{ - struct i2c_msg msg[2]; - u8 msgbuf[2]; - unsigned long timeout, read_time; - int status, i; - - memset(msg, 0, sizeof(msg)); - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - /*smaller eeproms can work given some SMBus extension calls */ - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; - break; - case I2C_SMBUS_WORD_DATA: - /* Check for odd length transaction */ - count = (count == 1) ? 1 : 2; - break; - case I2C_SMBUS_BYTE_DATA: - count = 1; - break; - default: - /* - * When we have a better choice than SMBus calls, use a - * combined I2C message. Write address; then read up to - * io_limit data bytes. msgbuf is u8 and will cast to our - * needs. - */ - i = 0; - msgbuf[i++] = offset; - - msg[0].addr = client->addr; - msg[0].buf = msgbuf; - msg[0].len = i; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - } - - /* - * Reads fail if the previous write didn't complete yet. We may - * loop a few times until this one succeeds, waiting at least - * long enough for one entire page write to work. - */ - timeout = jiffies + msecs_to_jiffies(write_timeout); - do { - read_time = jiffies; - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - status = i2c_smbus_read_i2c_block_data(client, offset, - count, buf); - break; - case I2C_SMBUS_WORD_DATA: - status = i2c_smbus_read_word_data(client, offset); - if (status >= 0) { - buf[0] = status & 0xff; - if (count == 2) - buf[1] = status >> 8; - status = count; - } - break; - case I2C_SMBUS_BYTE_DATA: - status = i2c_smbus_read_byte_data(client, offset); - if (status >= 0) { - buf[0] = status; - status = count; - } - break; - default: - status = i2c_transfer(client->adapter, msg, 2); - if (status == 2) - status = count; - } - - dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", - count, offset, status, jiffies); - - if (status == count) /* happy path */ - return count; - - if (status == -ENXIO) /* no module present */ - return status; - - /* REVISIT: at HZ=100, this is sloooow */ - usleep_range(1000, 2000); - } while (time_before(read_time, timeout)); - - return -ETIMEDOUT; -} - -static ssize_t optoe_eeprom_write(struct optoe_data *optoe, - struct i2c_client *client, - const char *buf, - unsigned int offset, size_t count) -{ - struct i2c_msg msg; - ssize_t status; - unsigned long timeout, write_time; - unsigned int next_page_start; - int i = 0; - - /* write max is at most a page - * (In this driver, write_max is actually one byte!) - */ - if (count > optoe->write_max) - count = optoe->write_max; - - /* shorten count if necessary to avoid crossing page boundary */ - next_page_start = roundup(offset + 1, OPTOE_PAGE_SIZE); - if (offset + count > next_page_start) - count = next_page_start - offset; - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - /*smaller eeproms can work given some SMBus extension calls */ - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; - break; - case I2C_SMBUS_WORD_DATA: - /* Check for odd length transaction */ - count = (count == 1) ? 1 : 2; - break; - case I2C_SMBUS_BYTE_DATA: - count = 1; - break; - default: - /* If we'll use I2C calls for I/O, set up the message */ - msg.addr = client->addr; - msg.flags = 0; - - /* msg.buf is u8 and casts will mask the values */ - msg.buf = optoe->writebuf; - - msg.buf[i++] = offset; - memcpy(&msg.buf[i], buf, count); - msg.len = i + count; - break; - } - - /* - * Reads fail if the previous write didn't complete yet. We may - * loop a few times until this one succeeds, waiting at least - * long enough for one entire page write to work. - */ - timeout = jiffies + msecs_to_jiffies(write_timeout); - do { - write_time = jiffies; - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - status = i2c_smbus_write_i2c_block_data(client, - offset, count, buf); - if (status == 0) - status = count; - break; - case I2C_SMBUS_WORD_DATA: - if (count == 2) { - status = i2c_smbus_write_word_data(client, - offset, (u16)((buf[0])|(buf[1] << 8))); - } else { - /* count = 1 */ - status = i2c_smbus_write_byte_data(client, - offset, buf[0]); - } - if (status == 0) - status = count; - break; - case I2C_SMBUS_BYTE_DATA: - status = i2c_smbus_write_byte_data(client, offset, - buf[0]); - if (status == 0) - status = count; - break; - default: - status = i2c_transfer(client->adapter, &msg, 1); - if (status == 1) - status = count; - break; - } - - dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", - count, offset, (long int) status, jiffies); - - if (status == count) - return count; - - /* REVISIT: at HZ=100, this is sloooow */ - usleep_range(1000, 2000); - } while (time_before(write_time, timeout)); - - return -ETIMEDOUT; -} - - -static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe, - char *buf, loff_t off, - size_t count, int opcode) -{ - struct i2c_client *client; - ssize_t retval = 0; - uint8_t page = 0; - loff_t phy_offset = off; - int ret = 0; - - page = optoe_translate_offset(optoe, &phy_offset, &client); - dev_dbg(&client->dev, - "%s off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", - __func__, off, page, phy_offset, (long int) count, opcode); - if (page > 0) { - ret = optoe_eeprom_write(optoe, client, &page, - OPTOE_PAGE_SELECT_REG, 1); - if (ret < 0) { - dev_dbg(&client->dev, - "Write page register for page %d failed ret:%d!\n", - page, ret); - return ret; - } - } - - while (count) { - ssize_t status; - - if (opcode == OPTOE_READ_OP) { - status = optoe_eeprom_read(optoe, client, - buf, phy_offset, count); - } else { - status = optoe_eeprom_write(optoe, client, - buf, phy_offset, count); - } - if (status <= 0) { - if (retval == 0) - retval = status; - break; - } - buf += status; - phy_offset += status; - count -= status; - retval += status; - } - - - if (page > 0) { - /* return the page register to page 0 (why?) */ - page = 0; - ret = optoe_eeprom_write(optoe, client, &page, - OPTOE_PAGE_SELECT_REG, 1); - if (ret < 0) { - dev_err(&client->dev, - "Restore page register to 0 failed:%d!\n", ret); - /* error only if nothing has been transferred */ - if (retval == 0) - retval = ret; - } - } - return retval; -} - -/* - * Figure out if this access is within the range of supported pages. - * Note this is called on every access because we don't know if the - * module has been replaced since the last call. - * If/when modules support more pages, this is the routine to update - * to validate and allow access to additional pages. - * - * Returns updated len for this access: - * - entire access is legal, original len is returned. - * - access begins legal but is too long, len is truncated to fit. - * - initial offset exceeds supported pages, return OPTOE_EOF (zero) - */ -static ssize_t optoe_page_legal(struct optoe_data *optoe, - loff_t off, size_t len) -{ - struct i2c_client *client = optoe->client[0]; - u8 regval; - int status; - size_t maxlen; - - if (off < 0) - return -EINVAL; - if (optoe->dev_class == TWO_ADDR) { - /* SFP case */ - /* if only using addr 0x50 (first 256 bytes) we're good */ - if ((off + len) <= TWO_ADDR_NO_0X51_SIZE) - return len; - /* if offset exceeds possible pages, we're not good */ - if (off >= TWO_ADDR_EEPROM_SIZE) - return OPTOE_EOF; - /* in between, are pages supported? */ - status = optoe_eeprom_read(optoe, client, ®val, - TWO_ADDR_PAGEABLE_REG, 1); - if (status < 0) - return status; /* error out (no module?) */ - if (regval & TWO_ADDR_PAGEABLE) { - /* Pages supported, trim len to the end of pages */ - maxlen = TWO_ADDR_EEPROM_SIZE - off; - } else { - /* pages not supported, trim len to unpaged size */ - if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) - return OPTOE_EOF; - - /* will be accessing addr 0x51, is that supported? */ - /* byte 92, bit 6 implies DDM support, 0x51 support */ - status = optoe_eeprom_read(optoe, client, ®val, - TWO_ADDR_0X51_REG, 1); - if (status < 0) - return status; - if (regval & TWO_ADDR_0X51_SUPP) { - /* addr 0x51 is OK */ - maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; - } else { - /* addr 0x51 NOT supported, trim to 256 max */ - if (off >= TWO_ADDR_NO_0X51_SIZE) - return OPTOE_EOF; - maxlen = TWO_ADDR_NO_0X51_SIZE - off; - } - } - len = (len > maxlen) ? maxlen : len; - dev_dbg(&client->dev, - "page_legal, SFP, off %lld len %ld\n", - off, (long int) len); - } else { - /* QSFP case */ - /* if no pages needed, we're good */ - if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) - return len; - /* if offset exceeds possible pages, we're not good */ - if (off >= ONE_ADDR_EEPROM_SIZE) - return OPTOE_EOF; - /* in between, are pages supported? */ - status = optoe_eeprom_read(optoe, client, ®val, - ONE_ADDR_PAGEABLE_REG, 1); - if (status < 0) - return status; /* error out (no module?) */ - if (regval & ONE_ADDR_NOT_PAGEABLE) { - /* pages not supported, trim len to unpaged size */ - if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) - return OPTOE_EOF; - maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; - } else { - /* Pages supported, trim len to the end of pages */ - maxlen = ONE_ADDR_EEPROM_SIZE - off; - } - len = (len > maxlen) ? maxlen : len; - dev_dbg(&client->dev, - "page_legal, QSFP, off %lld len %ld\n", - off, (long int) len); - } - return len; -} - -static ssize_t optoe_read_write(struct optoe_data *optoe, - char *buf, loff_t off, size_t len, int opcode) -{ - struct i2c_client *client = optoe->client[0]; - int chunk; - int status = 0; - ssize_t retval; - size_t pending_len = 0, chunk_len = 0; - loff_t chunk_offset = 0, chunk_start_offset = 0; - - dev_dbg(&client->dev, - "%s: off %lld len:%ld, opcode:%s\n", - __func__, off, (long int) len, - (opcode == OPTOE_READ_OP) ? "r" : "w"); - if (unlikely(!len)) - return len; - - /* - * Read data from chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&optoe->lock); - - /* - * Confirm this access fits within the device suppored addr range - */ - status = optoe_page_legal(optoe, off, len); - if ((status == OPTOE_EOF) || (status < 0)) { - mutex_unlock(&optoe->lock); - return status; - } - len = status; - - /* - * For each (128 byte) chunk involved in this request, issue a - * separate call to sff_eeprom_update_client(), to - * ensure that each access recalculates the client/page - * and writes the page register as needed. - * Note that chunk to page mapping is confusing, is different for - * QSFP and SFP, and never needs to be done. Don't try! - */ - pending_len = len; /* amount remaining to transfer */ - retval = 0; /* amount transferred */ - for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { - - /* - * Compute the offset and number of bytes to be read/write - * - * 1. start at offset 0 (within the chunk), and read/write - * the entire chunk - * 2. start at offset 0 (within the chunk) and read/write less - * than entire chunk - * 3. start at an offset not equal to 0 and read/write the rest - * of the chunk - * 4. start at an offset not equal to 0 and read/write less than - * (end of chunk - offset) - */ - chunk_start_offset = chunk * OPTOE_PAGE_SIZE; - - if (chunk_start_offset < off) { - chunk_offset = off; - if ((off + pending_len) < (chunk_start_offset + - OPTOE_PAGE_SIZE)) - chunk_len = pending_len; - else - chunk_len = OPTOE_PAGE_SIZE - off; - } else { - chunk_offset = chunk_start_offset; - if (pending_len > OPTOE_PAGE_SIZE) - chunk_len = OPTOE_PAGE_SIZE; - else - chunk_len = pending_len; - } - - dev_dbg(&client->dev, - "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", - off, (long int) len, chunk_start_offset, chunk_offset, - (long int) chunk_len, (long int) pending_len); - - /* - * note: chunk_offset is from the start of the EEPROM, - * not the start of the chunk - */ - status = optoe_eeprom_update_client(optoe, buf, - chunk_offset, chunk_len, opcode); - if (status != chunk_len) { - /* This is another 'no device present' path */ - dev_dbg(&client->dev, - "o_u_c: chunk %d c_offset %lld c_len %ld failed %d!\n", - chunk, chunk_offset, (long int) chunk_len, status); - if (status > 0) - retval += status; - if (retval == 0) - retval = status; - break; - } - buf += status; - pending_len -= status; - retval += status; - } - mutex_unlock(&optoe->lock); - - return retval; -} - -static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, - struct device, kobj)); - struct optoe_data *optoe = i2c_get_clientdata(client); - - return optoe_read_write(optoe, buf, off, count, OPTOE_READ_OP); -} - - -static ssize_t optoe_bin_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, - struct device, kobj)); - struct optoe_data *optoe = i2c_get_clientdata(client); - - return optoe_read_write(optoe, buf, off, count, OPTOE_WRITE_OP); -} - -static int optoe_remove(struct i2c_client *client) -{ - struct optoe_data *optoe; - int i; - - optoe = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); - sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); - - for (i = 1; i < optoe->num_addresses; i++) - i2c_unregister_device(optoe->client[i]); - -#ifdef EEPROM_CLASS - eeprom_device_unregister(optoe->eeprom_dev); -#endif - - kfree(optoe->writebuf); - kfree(optoe); - return 0; -} - -static ssize_t show_dev_class(struct device *dev, - struct device_attribute *dattr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - ssize_t count; - - mutex_lock(&optoe->lock); - count = sprintf(buf, "%d\n", optoe->dev_class); - mutex_unlock(&optoe->lock); - - return count; -} - -static ssize_t set_dev_class(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - int dev_class; - - /* - * dev_class is actually the number of i2c addresses used, thus - * legal values are "1" (QSFP class) and "2" (SFP class) - */ - - if (kstrtoint(buf, 0, &dev_class) != 0 || - dev_class < 1 || dev_class > 2) - return -EINVAL; - - mutex_lock(&optoe->lock); - optoe->dev_class = dev_class; - mutex_unlock(&optoe->lock); - - return count; -} - -/* - * if using the EEPROM CLASS driver, we don't report a port_name, - * the EEPROM CLASS drive handles that. Hence all this code is - * only compiled if we are NOT using the EEPROM CLASS driver. - */ -#ifndef EEPROM_CLASS - -static ssize_t show_port_name(struct device *dev, - struct device_attribute *dattr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - ssize_t count; - - mutex_lock(&optoe->lock); - count = sprintf(buf, "%s\n", optoe->port_name); - mutex_unlock(&optoe->lock); - - return count; -} - -static ssize_t set_port_name(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - char port_name[MAX_PORT_NAME_LEN]; - - /* no checking, this value is not used except by show_port_name */ - - if (sscanf(buf, "%19s", port_name) != 1) - return -EINVAL; - - mutex_lock(&optoe->lock); - strcpy(optoe->port_name, port_name); - mutex_unlock(&optoe->lock); - - return count; -} - -static DEVICE_ATTR(port_name, 0644, show_port_name, set_port_name); -#endif /* if NOT defined EEPROM_CLASS, the common case */ - -static DEVICE_ATTR(dev_class, 0644, show_dev_class, set_dev_class); - -static struct attribute *optoe_attrs[] = { -#ifndef EEPROM_CLASS - &dev_attr_port_name.attr, -#endif - &dev_attr_dev_class.attr, - NULL, -}; - -static struct attribute_group optoe_attr_group = { - .attrs = optoe_attrs, -}; - -static int optoe_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err; - int use_smbus = 0; - struct optoe_platform_data chip; - struct optoe_data *optoe; - int num_addresses = 0; - char port_name[MAX_PORT_NAME_LEN]; - - if (client->addr != 0x50) { - dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n", - client->addr); - err = -EINVAL; - goto exit; - } - - if (client->dev.platform_data) { - chip = *(struct optoe_platform_data *)client->dev.platform_data; - /* take the port name from the supplied platform data */ -#ifdef EEPROM_CLASS - strncpy(port_name, chip.eeprom_data->label, MAX_PORT_NAME_LEN); -#else - memcpy(port_name, chip.port_name, MAX_PORT_NAME_LEN); -#endif - dev_dbg(&client->dev, - "probe, chip provided, flags:0x%x; name: %s\n", - chip.flags, client->name); - } else { - if (!id->driver_data) { - err = -ENODEV; - goto exit; - } - dev_dbg(&client->dev, "probe, building chip\n"); - strcpy(port_name, "unitialized"); - chip.flags = 0; -#ifdef EEPROM_CLASS - chip.eeprom_data = NULL; -#endif - } - - /* Use I2C operations unless we're stuck with SMBus extensions. */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_WORD_DATA)) { - use_smbus = I2C_SMBUS_WORD_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - use_smbus = I2C_SMBUS_BYTE_DATA; - } else { - err = -EPFNOSUPPORT; - goto exit; - } - } - - - /* - * Make room for two i2c clients - */ - num_addresses = 2; - - optoe = kzalloc(sizeof(struct optoe_data) + - num_addresses * sizeof(struct i2c_client *), - GFP_KERNEL); - if (!optoe) { - err = -ENOMEM; - goto exit; - } - - mutex_init(&optoe->lock); - - /* determine whether this is a one-address or two-address module */ - if ((strcmp(client->name, "optoe1") == 0) || - (strcmp(client->name, "sff8436") == 0)) { - /* one-address (eg QSFP) family */ - optoe->dev_class = ONE_ADDR; - chip.byte_len = ONE_ADDR_EEPROM_SIZE; - num_addresses = 1; - } else if ((strcmp(client->name, "optoe2") == 0) || - (strcmp(client->name, "24c04") == 0)) { - /* SFP family */ - optoe->dev_class = TWO_ADDR; - chip.byte_len = TWO_ADDR_EEPROM_SIZE; - } else { /* those were the only two choices */ - err = -EINVAL; - goto exit; - } - - dev_dbg(&client->dev, "dev_class: %d\n", optoe->dev_class); - optoe->use_smbus = use_smbus; - optoe->chip = chip; - optoe->num_addresses = num_addresses; - memcpy(optoe->port_name, port_name, MAX_PORT_NAME_LEN); - - /* - * Export the EEPROM bytes through sysfs, since that's convenient. - * By default, only root should see the data (maybe passwords etc) - */ - sysfs_bin_attr_init(&optoe->bin); - optoe->bin.attr.name = "eeprom"; - optoe->bin.attr.mode = 0444; - optoe->bin.read = optoe_bin_read; - optoe->bin.size = chip.byte_len; - - if (!use_smbus || - (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_WORD_DATA) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { - /* - * NOTE: AN-2079 - * Finisar recommends that the host implement 1 byte writes - * only since this module only supports 32 byte page boundaries. - * 2 byte writes are acceptable for PE and Vout changes per - * Application Note AN-2071. - */ - unsigned int write_max = 1; - - optoe->bin.write = optoe_bin_write; - optoe->bin.attr.mode |= 0200; - - if (write_max > io_limit) - write_max = io_limit; - if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) - write_max = I2C_SMBUS_BLOCK_MAX; - optoe->write_max = write_max; - - /* buffer (data + address at the beginning) */ - optoe->writebuf = kmalloc(write_max + 2, GFP_KERNEL); - if (!optoe->writebuf) { - err = -ENOMEM; - goto exit_kfree; - } - } else { - dev_warn(&client->dev, - "cannot write due to controller restrictions."); - } - - optoe->client[0] = client; - - /* SFF-8472 spec requires that the second I2C address be 0x51 */ - if (num_addresses == 2) { - optoe->client[1] = i2c_new_dummy(client->adapter, 0x51); - if (!optoe->client[1]) { - dev_err(&client->dev, "address 0x51 unavailable\n"); - err = -EADDRINUSE; - goto err_struct; - } - } - - /* create the sysfs eeprom file */ - err = sysfs_create_bin_file(&client->dev.kobj, &optoe->bin); - if (err) - goto err_struct; - - optoe->attr_group = optoe_attr_group; - - err = sysfs_create_group(&client->dev.kobj, &optoe->attr_group); - if (err) { - dev_err(&client->dev, "failed to create sysfs attribute group.\n"); - goto err_struct; - } - -#ifdef EEPROM_CLASS - optoe->eeprom_dev = eeprom_device_register(&client->dev, - chip.eeprom_data); - if (IS_ERR(optoe->eeprom_dev)) { - dev_err(&client->dev, "error registering eeprom device.\n"); - err = PTR_ERR(optoe->eeprom_dev); - goto err_sysfs_cleanup; - } -#endif - - i2c_set_clientdata(client, optoe); - - dev_info(&client->dev, "%zu byte %s EEPROM, %s\n", - optoe->bin.size, client->name, - optoe->bin.write ? "read/write" : "read-only"); - - if (use_smbus == I2C_SMBUS_WORD_DATA || - use_smbus == I2C_SMBUS_BYTE_DATA) { - dev_notice(&client->dev, - "Falling back to %s reads, performance will suffer\n", - use_smbus == I2C_SMBUS_WORD_DATA ? "word" : "byte"); - } - - return 0; - -#ifdef EEPROM_CLASS -err_sysfs_cleanup: - sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); - sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); -#endif - -err_struct: - if (num_addresses == 2) { - if (optoe->client[1]) - i2c_unregister_device(optoe->client[1]); - } - - kfree(optoe->writebuf); -exit_kfree: - kfree(optoe); -exit: - dev_dbg(&client->dev, "probe error %d\n", err); - - return err; -} - -/*-------------------------------------------------------------------------*/ - -static struct i2c_driver optoe_driver = { - .driver = { - .name = "optoe", - .owner = THIS_MODULE, - }, - .probe = optoe_probe, - .remove = optoe_remove, - .id_table = optoe_ids, -}; - -static int __init optoe_init(void) -{ - - if (!io_limit) { - pr_err("optoe: io_limit must not be 0!\n"); - return -EINVAL; - } - - io_limit = rounddown_pow_of_two(io_limit); - return i2c_add_driver(&optoe_driver); -} -module_init(optoe_init); - -static void __exit optoe_exit(void) -{ - i2c_del_driver(&optoe_driver); -} -module_exit(optoe_exit); - -MODULE_DESCRIPTION("Driver for optical transceiver (SFP, QSFP, ...) EEPROMs"); -MODULE_AUTHOR("DON BOLLINGER "); -MODULE_LICENSE("GPL"); From e101c5e99c7a8e8608835b772461d0f25b52f5a3 Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Mon, 23 Jul 2018 14:07:23 +0800 Subject: [PATCH 03/22] [as5512-54x] Add support for OOM --- .../builds/x86-64-accton-as5512-54x-cpld.c | 1117 +++++++++++++++ .../builds/x86-64-accton-as5512-54x-fan.c | 13 +- .../builds/x86-64-accton-as5512-54x-leds.c | 13 +- .../builds/x86-64-accton-as5512-54x-psu.c | 22 +- .../builds/x86-64-accton-as5512-54x-sfp.c | 1237 ----------------- .../onlp/builds/src/module/src/sfpi.c | 261 ++-- .../x86_64_accton_as5512_54x_r0/__init__.py | 34 +- 7 files changed, 1303 insertions(+), 1394 deletions(-) create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-cpld.c delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-sfp.c diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-cpld.c b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-cpld.c new file mode 100644 index 00000000..ba36420c --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-cpld.c @@ -0,0 +1,1117 @@ +/* + * Copyright (C) Brandon Chuang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as5512_54x CPLD1/CPLD2/CPLD3 + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as5512_54x_cpld1, + as5512_54x_cpld2, + as5512_54x_cpld3 +}; + +struct as5512_54x_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; +}; + +static const struct i2c_device_id as5512_54x_cpld_id[] = { + { "as5512_54x_cpld1", as5512_54x_cpld1 }, + { "as5512_54x_cpld2", as5512_54x_cpld2 }, + { "as5512_54x_cpld3", as5512_54x_cpld3 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as5512_54x_cpld_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index + +enum as5512_54x_cpld1_sysfs_attributes { + CPLD_VERSION, + ACCESS, + MODULE_PRESENT_ALL, + MODULE_RXLOS_ALL, + /* 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_TXDISABLE_ATTR_ID(1), + TRANSCEIVER_TXDISABLE_ATTR_ID(2), + TRANSCEIVER_TXDISABLE_ATTR_ID(3), + TRANSCEIVER_TXDISABLE_ATTR_ID(4), + TRANSCEIVER_TXDISABLE_ATTR_ID(5), + TRANSCEIVER_TXDISABLE_ATTR_ID(6), + TRANSCEIVER_TXDISABLE_ATTR_ID(7), + TRANSCEIVER_TXDISABLE_ATTR_ID(8), + TRANSCEIVER_TXDISABLE_ATTR_ID(9), + TRANSCEIVER_TXDISABLE_ATTR_ID(10), + TRANSCEIVER_TXDISABLE_ATTR_ID(11), + TRANSCEIVER_TXDISABLE_ATTR_ID(12), + TRANSCEIVER_TXDISABLE_ATTR_ID(13), + TRANSCEIVER_TXDISABLE_ATTR_ID(14), + TRANSCEIVER_TXDISABLE_ATTR_ID(15), + TRANSCEIVER_TXDISABLE_ATTR_ID(16), + TRANSCEIVER_TXDISABLE_ATTR_ID(17), + TRANSCEIVER_TXDISABLE_ATTR_ID(18), + TRANSCEIVER_TXDISABLE_ATTR_ID(19), + TRANSCEIVER_TXDISABLE_ATTR_ID(20), + TRANSCEIVER_TXDISABLE_ATTR_ID(21), + TRANSCEIVER_TXDISABLE_ATTR_ID(22), + TRANSCEIVER_TXDISABLE_ATTR_ID(23), + TRANSCEIVER_TXDISABLE_ATTR_ID(24), + TRANSCEIVER_TXDISABLE_ATTR_ID(25), + TRANSCEIVER_TXDISABLE_ATTR_ID(26), + TRANSCEIVER_TXDISABLE_ATTR_ID(27), + TRANSCEIVER_TXDISABLE_ATTR_ID(28), + TRANSCEIVER_TXDISABLE_ATTR_ID(29), + TRANSCEIVER_TXDISABLE_ATTR_ID(30), + TRANSCEIVER_TXDISABLE_ATTR_ID(31), + TRANSCEIVER_TXDISABLE_ATTR_ID(32), + TRANSCEIVER_TXDISABLE_ATTR_ID(33), + TRANSCEIVER_TXDISABLE_ATTR_ID(34), + TRANSCEIVER_TXDISABLE_ATTR_ID(35), + TRANSCEIVER_TXDISABLE_ATTR_ID(36), + TRANSCEIVER_TXDISABLE_ATTR_ID(37), + TRANSCEIVER_TXDISABLE_ATTR_ID(38), + TRANSCEIVER_TXDISABLE_ATTR_ID(39), + TRANSCEIVER_TXDISABLE_ATTR_ID(40), + TRANSCEIVER_TXDISABLE_ATTR_ID(41), + TRANSCEIVER_TXDISABLE_ATTR_ID(42), + TRANSCEIVER_TXDISABLE_ATTR_ID(43), + TRANSCEIVER_TXDISABLE_ATTR_ID(44), + TRANSCEIVER_TXDISABLE_ATTR_ID(45), + TRANSCEIVER_TXDISABLE_ATTR_ID(46), + TRANSCEIVER_TXDISABLE_ATTR_ID(47), + TRANSCEIVER_TXDISABLE_ATTR_ID(48), + TRANSCEIVER_RXLOS_ATTR_ID(1), + TRANSCEIVER_RXLOS_ATTR_ID(2), + TRANSCEIVER_RXLOS_ATTR_ID(3), + TRANSCEIVER_RXLOS_ATTR_ID(4), + TRANSCEIVER_RXLOS_ATTR_ID(5), + TRANSCEIVER_RXLOS_ATTR_ID(6), + TRANSCEIVER_RXLOS_ATTR_ID(7), + TRANSCEIVER_RXLOS_ATTR_ID(8), + TRANSCEIVER_RXLOS_ATTR_ID(9), + TRANSCEIVER_RXLOS_ATTR_ID(10), + TRANSCEIVER_RXLOS_ATTR_ID(11), + TRANSCEIVER_RXLOS_ATTR_ID(12), + TRANSCEIVER_RXLOS_ATTR_ID(13), + TRANSCEIVER_RXLOS_ATTR_ID(14), + TRANSCEIVER_RXLOS_ATTR_ID(15), + TRANSCEIVER_RXLOS_ATTR_ID(16), + TRANSCEIVER_RXLOS_ATTR_ID(17), + TRANSCEIVER_RXLOS_ATTR_ID(18), + TRANSCEIVER_RXLOS_ATTR_ID(19), + TRANSCEIVER_RXLOS_ATTR_ID(20), + TRANSCEIVER_RXLOS_ATTR_ID(21), + TRANSCEIVER_RXLOS_ATTR_ID(22), + TRANSCEIVER_RXLOS_ATTR_ID(23), + TRANSCEIVER_RXLOS_ATTR_ID(24), + TRANSCEIVER_RXLOS_ATTR_ID(25), + TRANSCEIVER_RXLOS_ATTR_ID(26), + TRANSCEIVER_RXLOS_ATTR_ID(27), + TRANSCEIVER_RXLOS_ATTR_ID(28), + TRANSCEIVER_RXLOS_ATTR_ID(29), + TRANSCEIVER_RXLOS_ATTR_ID(30), + TRANSCEIVER_RXLOS_ATTR_ID(31), + TRANSCEIVER_RXLOS_ATTR_ID(32), + TRANSCEIVER_RXLOS_ATTR_ID(33), + TRANSCEIVER_RXLOS_ATTR_ID(34), + TRANSCEIVER_RXLOS_ATTR_ID(35), + TRANSCEIVER_RXLOS_ATTR_ID(36), + TRANSCEIVER_RXLOS_ATTR_ID(37), + TRANSCEIVER_RXLOS_ATTR_ID(38), + TRANSCEIVER_RXLOS_ATTR_ID(39), + TRANSCEIVER_RXLOS_ATTR_ID(40), + TRANSCEIVER_RXLOS_ATTR_ID(41), + TRANSCEIVER_RXLOS_ATTR_ID(42), + TRANSCEIVER_RXLOS_ATTR_ID(43), + TRANSCEIVER_RXLOS_ATTR_ID(44), + TRANSCEIVER_RXLOS_ATTR_ID(45), + TRANSCEIVER_RXLOS_ATTR_ID(46), + TRANSCEIVER_RXLOS_ATTR_ID(47), + TRANSCEIVER_RXLOS_ATTR_ID(48), + TRANSCEIVER_TXFAULT_ATTR_ID(1), + TRANSCEIVER_TXFAULT_ATTR_ID(2), + TRANSCEIVER_TXFAULT_ATTR_ID(3), + TRANSCEIVER_TXFAULT_ATTR_ID(4), + TRANSCEIVER_TXFAULT_ATTR_ID(5), + TRANSCEIVER_TXFAULT_ATTR_ID(6), + TRANSCEIVER_TXFAULT_ATTR_ID(7), + TRANSCEIVER_TXFAULT_ATTR_ID(8), + TRANSCEIVER_TXFAULT_ATTR_ID(9), + TRANSCEIVER_TXFAULT_ATTR_ID(10), + TRANSCEIVER_TXFAULT_ATTR_ID(11), + TRANSCEIVER_TXFAULT_ATTR_ID(12), + TRANSCEIVER_TXFAULT_ATTR_ID(13), + TRANSCEIVER_TXFAULT_ATTR_ID(14), + TRANSCEIVER_TXFAULT_ATTR_ID(15), + TRANSCEIVER_TXFAULT_ATTR_ID(16), + TRANSCEIVER_TXFAULT_ATTR_ID(17), + TRANSCEIVER_TXFAULT_ATTR_ID(18), + TRANSCEIVER_TXFAULT_ATTR_ID(19), + TRANSCEIVER_TXFAULT_ATTR_ID(20), + TRANSCEIVER_TXFAULT_ATTR_ID(21), + TRANSCEIVER_TXFAULT_ATTR_ID(22), + TRANSCEIVER_TXFAULT_ATTR_ID(23), + TRANSCEIVER_TXFAULT_ATTR_ID(24), + TRANSCEIVER_TXFAULT_ATTR_ID(25), + TRANSCEIVER_TXFAULT_ATTR_ID(26), + TRANSCEIVER_TXFAULT_ATTR_ID(27), + TRANSCEIVER_TXFAULT_ATTR_ID(28), + TRANSCEIVER_TXFAULT_ATTR_ID(29), + TRANSCEIVER_TXFAULT_ATTR_ID(30), + TRANSCEIVER_TXFAULT_ATTR_ID(31), + TRANSCEIVER_TXFAULT_ATTR_ID(32), + TRANSCEIVER_TXFAULT_ATTR_ID(33), + TRANSCEIVER_TXFAULT_ATTR_ID(34), + TRANSCEIVER_TXFAULT_ATTR_ID(35), + TRANSCEIVER_TXFAULT_ATTR_ID(36), + TRANSCEIVER_TXFAULT_ATTR_ID(37), + TRANSCEIVER_TXFAULT_ATTR_ID(38), + TRANSCEIVER_TXFAULT_ATTR_ID(39), + TRANSCEIVER_TXFAULT_ATTR_ID(40), + TRANSCEIVER_TXFAULT_ATTR_ID(41), + TRANSCEIVER_TXFAULT_ATTR_ID(42), + TRANSCEIVER_TXFAULT_ATTR_ID(43), + TRANSCEIVER_TXFAULT_ATTR_ID(44), + TRANSCEIVER_TXFAULT_ATTR_ID(45), + TRANSCEIVER_TXFAULT_ATTR_ID(46), + TRANSCEIVER_TXFAULT_ATTR_ID(47), + TRANSCEIVER_TXFAULT_ATTR_ID(48), +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as5512_54x_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as5512_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/* transceiver attributes */ +#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index) +#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr + +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); +/* transceiver attributes */ +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL); +static SENSOR_DEVICE_ATTR(module_rx_los_all, S_IRUGO, show_rxlos_all, NULL, MODULE_RXLOS_ALL); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(33); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(34); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(35); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(36); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(37); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(38); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(39); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(40); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(41); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(42); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(43); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(44); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(45); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(46); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(47); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(48); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(54); + +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); + +static struct attribute *as5512_54x_cpld1_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as5512_54x_cpld1_group = { + .attrs = as5512_54x_cpld1_attributes, +}; + +static struct attribute *as5512_54x_cpld2_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rx_los_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(1), + DECLARE_TRANSCEIVER_PRESENT_ATTR(2), + DECLARE_TRANSCEIVER_PRESENT_ATTR(3), + DECLARE_TRANSCEIVER_PRESENT_ATTR(4), + DECLARE_TRANSCEIVER_PRESENT_ATTR(5), + DECLARE_TRANSCEIVER_PRESENT_ATTR(6), + DECLARE_TRANSCEIVER_PRESENT_ATTR(7), + DECLARE_TRANSCEIVER_PRESENT_ATTR(8), + DECLARE_TRANSCEIVER_PRESENT_ATTR(9), + DECLARE_TRANSCEIVER_PRESENT_ATTR(10), + DECLARE_TRANSCEIVER_PRESENT_ATTR(11), + DECLARE_TRANSCEIVER_PRESENT_ATTR(12), + DECLARE_TRANSCEIVER_PRESENT_ATTR(13), + DECLARE_TRANSCEIVER_PRESENT_ATTR(14), + DECLARE_TRANSCEIVER_PRESENT_ATTR(15), + DECLARE_TRANSCEIVER_PRESENT_ATTR(16), + DECLARE_TRANSCEIVER_PRESENT_ATTR(17), + DECLARE_TRANSCEIVER_PRESENT_ATTR(18), + DECLARE_TRANSCEIVER_PRESENT_ATTR(19), + DECLARE_TRANSCEIVER_PRESENT_ATTR(20), + DECLARE_TRANSCEIVER_PRESENT_ATTR(21), + DECLARE_TRANSCEIVER_PRESENT_ATTR(22), + DECLARE_TRANSCEIVER_PRESENT_ATTR(23), + DECLARE_TRANSCEIVER_PRESENT_ATTR(24), + DECLARE_SFP_TRANSCEIVER_ATTR(1), + DECLARE_SFP_TRANSCEIVER_ATTR(2), + DECLARE_SFP_TRANSCEIVER_ATTR(3), + DECLARE_SFP_TRANSCEIVER_ATTR(4), + DECLARE_SFP_TRANSCEIVER_ATTR(5), + DECLARE_SFP_TRANSCEIVER_ATTR(6), + DECLARE_SFP_TRANSCEIVER_ATTR(7), + DECLARE_SFP_TRANSCEIVER_ATTR(8), + DECLARE_SFP_TRANSCEIVER_ATTR(9), + DECLARE_SFP_TRANSCEIVER_ATTR(10), + DECLARE_SFP_TRANSCEIVER_ATTR(11), + DECLARE_SFP_TRANSCEIVER_ATTR(12), + DECLARE_SFP_TRANSCEIVER_ATTR(13), + DECLARE_SFP_TRANSCEIVER_ATTR(14), + DECLARE_SFP_TRANSCEIVER_ATTR(15), + DECLARE_SFP_TRANSCEIVER_ATTR(16), + DECLARE_SFP_TRANSCEIVER_ATTR(17), + DECLARE_SFP_TRANSCEIVER_ATTR(18), + DECLARE_SFP_TRANSCEIVER_ATTR(19), + DECLARE_SFP_TRANSCEIVER_ATTR(20), + DECLARE_SFP_TRANSCEIVER_ATTR(21), + DECLARE_SFP_TRANSCEIVER_ATTR(22), + DECLARE_SFP_TRANSCEIVER_ATTR(23), + DECLARE_SFP_TRANSCEIVER_ATTR(24), + NULL +}; + +static const struct attribute_group as5512_54x_cpld2_group = { + .attrs = as5512_54x_cpld2_attributes, +}; + +static struct attribute *as5512_54x_cpld3_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rx_los_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(25), + DECLARE_TRANSCEIVER_PRESENT_ATTR(26), + DECLARE_TRANSCEIVER_PRESENT_ATTR(27), + DECLARE_TRANSCEIVER_PRESENT_ATTR(28), + DECLARE_TRANSCEIVER_PRESENT_ATTR(29), + DECLARE_TRANSCEIVER_PRESENT_ATTR(30), + DECLARE_TRANSCEIVER_PRESENT_ATTR(31), + DECLARE_TRANSCEIVER_PRESENT_ATTR(32), + DECLARE_TRANSCEIVER_PRESENT_ATTR(33), + DECLARE_TRANSCEIVER_PRESENT_ATTR(34), + DECLARE_TRANSCEIVER_PRESENT_ATTR(35), + DECLARE_TRANSCEIVER_PRESENT_ATTR(36), + DECLARE_TRANSCEIVER_PRESENT_ATTR(37), + DECLARE_TRANSCEIVER_PRESENT_ATTR(38), + DECLARE_TRANSCEIVER_PRESENT_ATTR(39), + DECLARE_TRANSCEIVER_PRESENT_ATTR(40), + DECLARE_TRANSCEIVER_PRESENT_ATTR(41), + DECLARE_TRANSCEIVER_PRESENT_ATTR(42), + DECLARE_TRANSCEIVER_PRESENT_ATTR(43), + DECLARE_TRANSCEIVER_PRESENT_ATTR(44), + DECLARE_TRANSCEIVER_PRESENT_ATTR(45), + DECLARE_TRANSCEIVER_PRESENT_ATTR(46), + DECLARE_TRANSCEIVER_PRESENT_ATTR(47), + DECLARE_TRANSCEIVER_PRESENT_ATTR(48), + DECLARE_TRANSCEIVER_PRESENT_ATTR(49), + DECLARE_TRANSCEIVER_PRESENT_ATTR(50), + DECLARE_TRANSCEIVER_PRESENT_ATTR(51), + DECLARE_TRANSCEIVER_PRESENT_ATTR(52), + DECLARE_TRANSCEIVER_PRESENT_ATTR(53), + DECLARE_TRANSCEIVER_PRESENT_ATTR(54), + DECLARE_SFP_TRANSCEIVER_ATTR(25), + DECLARE_SFP_TRANSCEIVER_ATTR(26), + DECLARE_SFP_TRANSCEIVER_ATTR(27), + DECLARE_SFP_TRANSCEIVER_ATTR(28), + DECLARE_SFP_TRANSCEIVER_ATTR(29), + DECLARE_SFP_TRANSCEIVER_ATTR(30), + DECLARE_SFP_TRANSCEIVER_ATTR(31), + DECLARE_SFP_TRANSCEIVER_ATTR(32), + DECLARE_SFP_TRANSCEIVER_ATTR(33), + DECLARE_SFP_TRANSCEIVER_ATTR(34), + DECLARE_SFP_TRANSCEIVER_ATTR(35), + DECLARE_SFP_TRANSCEIVER_ATTR(36), + DECLARE_SFP_TRANSCEIVER_ATTR(37), + DECLARE_SFP_TRANSCEIVER_ATTR(38), + DECLARE_SFP_TRANSCEIVER_ATTR(39), + DECLARE_SFP_TRANSCEIVER_ATTR(40), + DECLARE_SFP_TRANSCEIVER_ATTR(41), + DECLARE_SFP_TRANSCEIVER_ATTR(42), + DECLARE_SFP_TRANSCEIVER_ATTR(43), + DECLARE_SFP_TRANSCEIVER_ATTR(44), + DECLARE_SFP_TRANSCEIVER_ATTR(45), + DECLARE_SFP_TRANSCEIVER_ATTR(46), + DECLARE_SFP_TRANSCEIVER_ATTR(47), + DECLARE_SFP_TRANSCEIVER_ATTR(48), + NULL +}; + +static const struct attribute_group as5512_54x_cpld3_group = { + .attrs = as5512_54x_cpld3_attributes, +}; + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status, num_regs = 0; + u8 values[4] = {0}; + u8 regs[] = {0x6, 0x7, 0x8, 0x14}; + struct i2c_client *client = to_i2c_client(dev); + struct as5512_54x_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + num_regs = (data->type == as5512_54x_cpld2) ? 3 : 4; + + for (i = 0; i < num_regs; i++) { + status = as5512_54x_cpld_read_internal(client, regs[i]); + + if (status < 0) { + goto exit; + } + + values[i] = ~(u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values 1 -> 54 in order */ + if (data->type == as5512_54x_cpld2) { + status = sprintf(buf, "%.2x %.2x %.2x\n", + values[0], values[1], values[2]); + } + else { /* as5512_54x_cpld3 */ + values[3] &= 0x3F; + status = sprintf(buf, "%.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], values[3]); + } + + return status; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[3] = {0}; + u8 regs[] = {0xF, 0x10, 0x11}; + struct i2c_client *client = to_i2c_client(dev); + struct as5512_54x_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + status = as5512_54x_cpld_read_internal(client, regs[i]); + + if (status < 0) { + goto exit; + } + + values[i] = (u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values 1 -> 24 in order */ + return sprintf(buf, "%.2x %.2x %.2x\n", values[0], values[1], values[2]); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as5512_54x_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, revert = 0; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_8: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_16: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_24: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_PRESENT_17); + break; + case MODULE_PRESENT_25 ... MODULE_PRESENT_32: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_PRESENT_25); + break; + case MODULE_PRESENT_33 ... MODULE_PRESENT_40: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_PRESENT_33); + break; + case MODULE_PRESENT_41 ... MODULE_PRESENT_48: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_PRESENT_41); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_54: + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + break; + case MODULE_TXFAULT_1 ... MODULE_TXFAULT_8: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_TXFAULT_1); + break; + case MODULE_TXFAULT_9 ... MODULE_TXFAULT_16: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_TXFAULT_9); + break; + case MODULE_TXFAULT_17 ... MODULE_TXFAULT_24: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXFAULT_17); + break; + case MODULE_TXFAULT_25 ... MODULE_TXFAULT_32: + reg = 0x9; + mask = 0x1 << (attr->index - MODULE_TXFAULT_25); + break; + case MODULE_TXFAULT_33 ... MODULE_TXFAULT_40: + reg = 0xA; + mask = 0x1 << (attr->index - MODULE_TXFAULT_33); + break; + case MODULE_TXFAULT_41 ... MODULE_TXFAULT_48: + reg = 0xB; + mask = 0x1 << (attr->index - MODULE_TXFAULT_41); + break; + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_32: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXDISABLE_33 ... MODULE_TXDISABLE_40: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_33); + break; + case MODULE_TXDISABLE_41 ... MODULE_TXDISABLE_48: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); + break; + case MODULE_RXLOS_1 ... MODULE_RXLOS_8: + reg = 0xF; + mask = 0x1 << (attr->index - MODULE_RXLOS_1); + break; + case MODULE_RXLOS_9 ... MODULE_RXLOS_16: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_RXLOS_9); + break; + case MODULE_RXLOS_17 ... MODULE_RXLOS_24: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_RXLOS_17); + break; + case MODULE_RXLOS_25 ... MODULE_RXLOS_32: + reg = 0xF; + mask = 0x1 << (attr->index - MODULE_RXLOS_25); + break; + case MODULE_RXLOS_33 ... MODULE_RXLOS_40: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_RXLOS_33); + break; + case MODULE_RXLOS_41 ... MODULE_RXLOS_48: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_RXLOS_41); + break; + default: + return 0; + } + + if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_54) { + revert = 1; + } + + mutex_lock(&data->update_lock); + status = as5512_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as5512_54x_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_32: + reg = 0xC; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXDISABLE_33 ... MODULE_TXDISABLE_40: + reg = 0xD; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_33); + break; + case MODULE_TXDISABLE_41 ... MODULE_TXDISABLE_48: + reg = 0xE; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); + break; + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5512_54x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update tx_disable status */ + if (disable) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5512_54x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as5512_54x_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as5512_54x_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as5512_54x_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as5512_54x_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d", val); +} + +/* + * I2C init/probing/exit functions + */ +static int as5512_54x_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as5512_54x_cpld_data *data; + int ret = -ENODEV; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as5512_54x_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) { + case as5512_54x_cpld1: + group = &as5512_54x_cpld1_group; + break; + case as5512_54x_cpld2: + group = &as5512_54x_cpld2_group; + break; + case as5512_54x_cpld3: + group = &as5512_54x_cpld3_group; + break; + default: + break; + } + + if (group) { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as5512_54x_cpld_add_client(client); + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as5512_54x_cpld_remove(struct i2c_client *client) +{ + struct as5512_54x_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as5512_54x_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) { + case as5512_54x_cpld1: + group = &as5512_54x_cpld1_group; + break; + case as5512_54x_cpld2: + group = &as5512_54x_cpld2_group; + break; + case as5512_54x_cpld3: + group = &as5512_54x_cpld3_group; + break; + default: + break; + } + + if (group) { + sysfs_remove_group(&client->dev.kobj, group); + } + + kfree(data); + + return 0; +} + +static int as5512_54x_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as5512_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as5512_54x_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5512_54x_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5512_54x_cpld_read); + +int as5512_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5512_54x_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5512_54x_cpld_write); + +static struct i2c_driver as5512_54x_cpld_driver = { + .driver = { + .name = "as5512_54x_cpld", + .owner = THIS_MODULE, + }, + .probe = as5512_54x_cpld_probe, + .remove = as5512_54x_cpld_remove, + .id_table = as5512_54x_cpld_id, +}; + +static int __init as5512_54x_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as5512_54x_cpld_driver); +} + +static void __exit as5512_54x_cpld_exit(void) +{ + i2c_del_driver(&as5512_54x_cpld_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton I2C CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as5512_54x_cpld_init); +module_exit(as5512_54x_cpld_exit); + diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-fan.c b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-fan.c index 67e3dd66..9f2bbf59 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-fan.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-fan.c @@ -131,8 +131,8 @@ static ssize_t fan_set_duty_cycle(struct device *dev, static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); +extern int as5512_54x_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5512_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); /*******************/ @@ -269,12 +269,12 @@ static const struct attribute_group accton_as5512_54x_fan_group = { static int accton_as5512_54x_fan_read_value(u8 reg) { - return accton_i2c_cpld_read(0x60, reg); + return as5512_54x_cpld_read(0x60, reg); } static int accton_as5512_54x_fan_write_value(u8 reg, u8 value) { - return accton_i2c_cpld_write(0x60, reg, value); + return as5512_54x_cpld_write(0x60, reg, value); } static void accton_as5512_54x_fan_update_device(struct device *dev) @@ -405,11 +405,6 @@ static int __init accton_as5512_54x_fan_init(void) { int ret; - extern int platform_accton_as5512_54x(void); - if(!platform_accton_as5512_54x()) { - return -ENODEV; - } - ret = platform_driver_register(&accton_as5512_54x_fan_driver); if (ret < 0) { goto exit; diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-leds.c b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-leds.c index 43160557..02eb3d7e 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-leds.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-leds.c @@ -29,8 +29,8 @@ #include #include -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); +extern int as5512_54x_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5512_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); #define DRVNAME "as5512_54x_led" @@ -168,12 +168,12 @@ static u8 led_light_mode_to_reg_val(enum led_type type, static int accton_as5512_54x_led_read_value(u8 reg) { - return accton_i2c_cpld_read(0x60, reg); + return as5512_54x_cpld_read(0x60, reg); } static int accton_as5512_54x_led_write_value(u8 reg, u8 value) { - return accton_i2c_cpld_write(0x60, reg, value); + return as5512_54x_cpld_write(0x60, reg, value); } static void accton_as5512_54x_led_update(void) @@ -411,11 +411,6 @@ static int __init accton_as5512_54x_led_init(void) { int ret; - extern int platform_accton_as5512_54x(void); - if(!platform_accton_as5512_54x()) { - return -ENODEV; - } - ret = platform_driver_register(&accton_as5512_54x_led_driver); if (ret < 0) { goto exit; diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-psu.c b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-psu.c index 66d61f3c..fb5e02ca 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-psu.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-psu.c @@ -36,7 +36,7 @@ static ssize_t show_index(struct device *dev, struct device_attribute *da, char static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); static int as5512_54x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5512_54x_cpld_read(unsigned short cpld_addr, u8 reg); /* Addresses scanned */ @@ -253,7 +253,7 @@ static struct as5512_54x_psu_data *as5512_54x_psu_update_device(struct device *d } /* Read psu status */ - status = accton_i2c_cpld_read(0x60, 0x2); + status = as5512_54x_cpld_read(0x60, 0x2); if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); @@ -271,25 +271,9 @@ static struct as5512_54x_psu_data *as5512_54x_psu_update_device(struct device *d return data; } -static int __init as5512_54x_psu_init(void) -{ - extern int platform_accton_as5512_54x(void); - if(!platform_accton_as5512_54x()) { - return -ENODEV; - } - - return i2c_add_driver(&as5512_54x_psu_driver); -} - -static void __exit as5512_54x_psu_exit(void) -{ - i2c_del_driver(&as5512_54x_psu_driver); -} +module_i2c_driver(as5512_54x_psu_driver); MODULE_AUTHOR("Brandon Chuang "); MODULE_DESCRIPTION("accton as5512_54x_psu driver"); MODULE_LICENSE("GPL"); -module_init(as5512_54x_psu_init); -module_exit(as5512_54x_psu_exit); - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-sfp.c b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-sfp.c deleted file mode 100644 index d89e71d0..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/modules/builds/x86-64-accton-as5512-54x-sfp.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* - * SFP driver for accton as5512_54x sfp - * - * Copyright (C) Brandon Chuang - * - * Based on ad7414.c - * Copyright 2006 Stefan Roese , DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "as5512_54x_sfp" - -#define DEBUG_MODE 0 - -#if (DEBUG_MODE == 1) - #define DEBUG_PRINT(fmt, args...) \ - printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) -#else - #define DEBUG_PRINT(fmt, args...) -#endif - -#define NUM_OF_SFP_PORT 54 -#define EEPROM_NAME "sfp_eeprom" -#define EEPROM_SIZE 256 /* 256 byte eeprom */ -#define BIT_INDEX(i) (1ULL << (i)) -#define USE_I2C_BLOCK_READ 1 -#define I2C_RW_RETRY_COUNT 3 -#define I2C_RW_RETRY_INTERVAL 100 /* ms */ - -#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) -#define SFP_EEPROM_A2_I2C_ADDR (0xA2 >> 1) - -#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 -#define SFF8024_DEVICE_ID_SFP 0x3 -#define SFF8024_DEVICE_ID_QSFP 0xC -#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD -#define SFF8024_DEVICE_ID_QSFP28 0x11 - -#define SFF8472_DIAG_MON_TYPE_ADDR 92 -#define SFF8472_DIAG_MON_TYPE_DDM_MASK 0x40 -#define SFF8472_10G_ETH_COMPLIANCE_ADDR 0x3 -#define SFF8472_10G_BASE_MASK 0xF0 - -#define SFF8436_RX_LOS_ADDR 3 -#define SFF8436_TX_FAULT_ADDR 4 -#define SFF8436_TX_DISABLE_ADDR 86 - -static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); -static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); - -/* Addresses scanned - */ -static const unsigned short normal_i2c[] = { SFP_EEPROM_A0_I2C_ADDR, SFP_EEPROM_A2_I2C_ADDR, I2C_CLIENT_END }; - -#define CPLD_PORT_TO_FRONT_PORT(port) (port+1) - -enum port_numbers { -sfp1, sfp2, sfp3, sfp4, sfp5, sfp6, sfp7, sfp8, -sfp9, sfp10, sfp11, sfp12, sfp13, sfp14, sfp15, sfp16, -sfp17, sfp18, sfp19, sfp20, sfp21, sfp22, sfp23, sfp24, -sfp25, sfp26, sfp27, sfp28, sfp29, sfp30, sfp31, sfp32, -sfp33, sfp34, sfp35, sfp36, sfp37, sfp38, sfp39, sfp40, -sfp41, sfp42, sfp43, sfp44, sfp45, sfp46, sfp47, sfp48, -sfp49, sfp50, sfp51, sfp52, sfp53, sfp54 -}; - -static const struct i2c_device_id sfp_device_id[] = { -{ "sfp1", sfp1 }, { "sfp2", sfp2 }, { "sfp3", sfp3 }, { "sfp4", sfp4 }, -{ "sfp5", sfp5 }, { "sfp6", sfp6 }, { "sfp7", sfp7 }, { "sfp8", sfp8 }, -{ "sfp9", sfp9 }, { "sfp10", sfp10 }, { "sfp11", sfp11 }, { "sfp12", sfp12 }, -{ "sfp13", sfp13 }, { "sfp14", sfp14 }, { "sfp15", sfp15 }, { "sfp16", sfp16 }, -{ "sfp17", sfp17 }, { "sfp18", sfp18 }, { "sfp19", sfp19 }, { "sfp20", sfp20 }, -{ "sfp21", sfp21 }, { "sfp22", sfp22 }, { "sfp23", sfp23 }, { "sfp24", sfp24 }, -{ "sfp25", sfp25 }, { "sfp26", sfp26 }, { "sfp27", sfp27 }, { "sfp28", sfp28 }, -{ "sfp29", sfp29 }, { "sfp30", sfp30 }, { "sfp31", sfp31 }, { "sfp32", sfp32 }, -{ "sfp33", sfp33 }, { "sfp34", sfp34 }, { "sfp35", sfp35 }, { "sfp36", sfp36 }, -{ "sfp37", sfp37 }, { "sfp38", sfp38 }, { "sfp39", sfp39 }, { "sfp40", sfp40 }, -{ "sfp41", sfp41 }, { "sfp42", sfp42 }, { "sfp43", sfp43 }, { "sfp44", sfp44 }, -{ "sfp45", sfp45 }, { "sfp46", sfp46 }, { "sfp47", sfp47 }, { "sfp48", sfp48 }, -{ "sfp49", sfp49 }, { "sfp50", sfp50 }, { "sfp51", sfp51 }, { "sfp52", sfp52 }, -{ "sfp53", sfp53 }, { "sfp54", sfp54 }, -{ /* LIST END */ } -}; -MODULE_DEVICE_TABLE(i2c, sfp_device_id); - -/* - * list of valid port types - * note OOM_PORT_TYPE_NOT_PRESENT to indicate no - * module is present in this port - */ -typedef enum oom_driver_port_type_e { - OOM_DRIVER_PORT_TYPE_INVALID, - OOM_DRIVER_PORT_TYPE_NOT_PRESENT, - OOM_DRIVER_PORT_TYPE_SFP, - OOM_DRIVER_PORT_TYPE_SFP_PLUS, - OOM_DRIVER_PORT_TYPE_QSFP, - OOM_DRIVER_PORT_TYPE_QSFP_PLUS, - OOM_DRIVER_PORT_TYPE_QSFP28 -} oom_driver_port_type_t; - -enum driver_type_e { - DRIVER_TYPE_SFP_MSA, - DRIVER_TYPE_SFP_DDM, - DRIVER_TYPE_QSFP -}; - -/* Each client has this additional data - */ -struct eeprom_data { - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - struct bin_attribute bin; /* eeprom data */ -}; - -struct sfp_msa_data { - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u64 status[6]; /* bit0:port0, bit1:port1 and so on */ - /* index 0 => tx_fail - 1 => tx_disable - 2 => rx_loss - 3 => device id - 4 => 10G Ethernet Compliance Codes - to distinguish SFP or SFP+ - 5 => DIAGNOSTIC MONITORING TYPE */ - struct eeprom_data eeprom; -}; - -struct sfp_ddm_data { - struct eeprom_data eeprom; -}; - -struct qsfp_data { - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 status[3]; /* bit0:port0, bit1:port1 and so on */ - /* index 0 => tx_fail - 1 => tx_disable - 2 => rx_loss */ - - u8 device_id; - struct eeprom_data eeprom; -}; - -struct sfp_port_data { - struct mutex update_lock; - enum driver_type_e driver_type; - int port; /* CPLD port index */ - oom_driver_port_type_t port_type; - u64 present; /* present status, bit0:port0, bit1:port1 and so on */ - - struct sfp_msa_data *msa; - struct sfp_ddm_data *ddm; - struct qsfp_data *qsfp; - - struct i2c_client *client; -}; - -enum sfp_sysfs_attributes { - PRESENT, - PRESENT_ALL, - PORT_NUMBER, - PORT_TYPE, - DDM_IMPLEMENTED, - TX_FAULT, - TX_FAULT1, - TX_FAULT2, - TX_FAULT3, - TX_FAULT4, - TX_DISABLE, - TX_DISABLE1, - TX_DISABLE2, - TX_DISABLE3, - TX_DISABLE4, - RX_LOS, - RX_LOS1, - RX_LOS2, - RX_LOS3, - RX_LOS4, - RX_LOS_ALL -}; - -static ssize_t show_port_number(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); -} - -static struct sfp_port_data* sfp_update_present(struct i2c_client *client) -{ - int i = 0, j = 0, status = -1; - u8 reg; - unsigned short cpld_addr; - struct sfp_port_data *data = i2c_get_clientdata(client); - - DEBUG_PRINT("Starting sfp present status update"); - mutex_lock(&data->update_lock); - data->present = 0; - - /* Read present status of port 1~48(SFP port) */ - for (i = 0; i < 2; i++) { - for (j = 0; j < 3; j++) { - cpld_addr = 0x61+i; - reg = 0x6+j; - status = accton_i2c_cpld_read(cpld_addr, reg); - - if (unlikely(status < 0)) { - data = ERR_PTR(status); - dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); - goto exit; - } - - DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); - data->present |= (u64)status << ((i*24) + (j%3)*8); - } - } - - /* Read present status of port 49-54(QSFP port) */ - cpld_addr = 0x62; - reg = 0x14; - status = accton_i2c_cpld_read(cpld_addr, reg); - - if (unlikely(status < 0)) { - data = ERR_PTR(status); - dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); - goto exit; - } - else { - data->present |= (u64)status << 48; - } - - DEBUG_PRINT("Present status = 0x%lx", data->present); -exit: - mutex_unlock(&data->update_lock); - return data; -} - -static struct sfp_port_data* sfp_update_tx_rx_status(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - int i = 0, j = 0; - int status = -1; - - if (time_before(jiffies, data->msa->last_updated + HZ + HZ / 2) && data->msa->valid) { - return data; - } - - DEBUG_PRINT("Starting as5512_54x sfp tx rx status update"); - mutex_lock(&data->update_lock); - data->msa->valid = 0; - memset(data->msa->status, 0, sizeof(data->msa->status)); - - /* Read status of port 1~48(SFP port) */ - for (i = 0; i < 2; i++) { - for (j = 0; j < 9; j++) { - u8 reg; - unsigned short cpld_addr; - reg = 0x9+j; - cpld_addr = 0x61+i; - - status = accton_i2c_cpld_read(cpld_addr, reg); - if (unlikely(status < 0)) { - data = ERR_PTR(status); - dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); - goto exit; - } - - data->msa->status[j/3] |= (u64)status << ((i*24) + (j%3)*8); - } - } - - data->msa->valid = 1; - data->msa->last_updated = jiffies; - -exit: - mutex_unlock(&data->update_lock); - return data; -} - -static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - unsigned short cpld_addr = 0; - u8 cpld_reg = 0, cpld_val = 0, cpld_bit = 0; - long disable; - int error; - - error = kstrtol(buf, 10, &disable); - if (error) { - return error; - } - - mutex_lock(&data->update_lock); - - if(data->port < 24) { - cpld_addr = 0x61; - cpld_reg = 0xC + data->port / 8; - cpld_bit = 1 << (data->port % 8); - } - else { /* port 24 ~ 48 */ - cpld_addr = 0x62; - cpld_reg = 0xC + (data->port - 24) / 8; - cpld_bit = 1 << (data->port % 8); - } - - /* Read current status */ - cpld_val = accton_i2c_cpld_read(cpld_addr, cpld_reg); - - /* Update tx_disable status */ - if (disable) { - data->msa->status[1] |= BIT_INDEX(data->port); - cpld_val |= cpld_bit; - } - else { - data->msa->status[1] &= ~BIT_INDEX(data->port); - cpld_val &= ~cpld_bit; - } - - accton_i2c_cpld_write(cpld_addr, cpld_reg, cpld_val); - mutex_unlock(&data->update_lock); - return count; -} - -static int sfp_is_port_present(struct i2c_client *client, int port) -{ - struct sfp_port_data *data = i2c_get_clientdata(client); - - data = sfp_update_present(client); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - return (data->present & BIT_INDEX(data->port)) ? 0 : 1; -} - -static ssize_t show_present(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - - if (PRESENT_ALL == attr->index) { - int i; - u8 values[7] = {0}; - struct sfp_port_data *data = sfp_update_present(client); - - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - for (i = 0; i < ARRAY_SIZE(values); i++) { - values[i] = ~(u8)(data->present >> (i * 8)); - } - - /* Return values 1 -> 54 in order */ - return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", - values[0], values[1], values[2], - values[3], values[4], values[5], - values[6] & 0x3F); - } - else { - struct sfp_port_data *data = i2c_get_clientdata(client); - int present = sfp_is_port_present(client, data->port); - - if (IS_ERR_VALUE(present)) { - return present; - } - - /* PRESENT */ - return sprintf(buf, "%d\n", present); - } -} - -static struct sfp_port_data *sfp_update_port_type(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - u8 buf = 0; - int status; - - mutex_lock(&data->update_lock); - - switch (data->driver_type) { - case DRIVER_TYPE_SFP_MSA: - { - status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - if (buf != SFF8024_DEVICE_ID_SFP) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - status = sfp_eeprom_read(client, SFF8472_10G_ETH_COMPLIANCE_ADDR, &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - DEBUG_PRINT("sfp port type (0x3) data = (0x%x)", buf); - data->port_type = buf & SFF8472_10G_BASE_MASK ? OOM_DRIVER_PORT_TYPE_SFP_PLUS : OOM_DRIVER_PORT_TYPE_SFP; - break; - } - case DRIVER_TYPE_QSFP: - { - status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - DEBUG_PRINT("qsfp port type (0x0) buf = (0x%x)", buf); - switch (buf) { - case SFF8024_DEVICE_ID_QSFP: - data->port_type = OOM_DRIVER_PORT_TYPE_QSFP; - break; - case SFF8024_DEVICE_ID_QSFP_PLUS: - data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; - break; - case SFF8024_DEVICE_ID_QSFP28: - data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; - break; - default: - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - break; - } - default: - break; - } - - mutex_unlock(&data->update_lock); - return data; -} - -static ssize_t show_port_type(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - int present = sfp_is_port_present(client, data->port); - - if (IS_ERR_VALUE(present)) { - return present; - } - - if (!present) { - return sprintf(buf, "%d\n", OOM_DRIVER_PORT_TYPE_NOT_PRESENT); - } - - sfp_update_port_type(dev); - return sprintf(buf, "%d\n", data->port_type); -} - -static struct sfp_port_data* qsfp_update_tx_rx_status(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - int i, status = -1; - u8 buf = 0; - u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; - - if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { - return data; - } - - DEBUG_PRINT("Starting sfp tx rx status update"); - mutex_lock(&data->update_lock); - data->qsfp->valid = 0; - memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); - - /* Notify device to update tx fault/ tx disable/ rx los status */ - for (i = 0; i < ARRAY_SIZE(reg); i++) { - status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data = ERR_PTR(status); - goto exit; - } - } - msleep(200); - - /* Read actual tx fault/ tx disable/ rx los status */ - for (i = 0; i < ARRAY_SIZE(reg); i++) { - status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data = ERR_PTR(status); - goto exit; - } - - DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); - data->qsfp->status[i] = (buf & 0xF); - } - - data->qsfp->valid = 1; - data->qsfp->last_updated = jiffies; - -exit: - mutex_unlock(&data->update_lock); - return data; -} - -static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, - char *buf) -{ - int status; - u8 val = 0; - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - - status = sfp_is_port_present(client, data->port); - if (IS_ERR_VALUE(status)) { - return status; - } - - data = qsfp_update_tx_rx_status(dev); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - switch (attr->index) { - case TX_FAULT1: - case TX_FAULT2: - case TX_FAULT3: - case TX_FAULT4: - val = (data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)) ? 1 : 0; - break; - case TX_DISABLE1: - case TX_DISABLE2: - case TX_DISABLE3: - case TX_DISABLE4: - val = (data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)) ? 1 : 0; - break; - case RX_LOS1: - case RX_LOS2: - case RX_LOS3: - case RX_LOS4: - val = (data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)) ? 1 : 0; - break; - default: - break; - } - - return sprintf(buf, "%d\n", val); -} - -static ssize_t qsfp_set_tx_disable(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); - struct sfp_port_data *data = NULL; - - status = kstrtol(buf, 10, &disable); - if (status) { - return status; - } - - data = qsfp_update_tx_rx_status(dev); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - mutex_lock(&data->update_lock); - - if (disable) { - data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); - } - else { - data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); - } - - DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); - status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); - if (unlikely(status < 0)) { - count = status; - } - - mutex_unlock(&data->update_lock); - return count; -} - -static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, - char *buf) -{ - int status; - char ddm; - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - - status = sfp_is_port_present(client, data->port); - if (IS_ERR_VALUE(status)) { - return status; - } - - status = sfp_eeprom_read(client, SFF8472_DIAG_MON_TYPE_ADDR, &ddm, sizeof(ddm)); - if (unlikely(status < 0)) { - return status; - } - - return sprintf(buf, "%d\n", (ddm & SFF8472_DIAG_MON_TYPE_DDM_MASK) ? 1 : 0); -} - -static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, - char *buf) -{ - u8 val = 0, index = 0; - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct sfp_port_data *data = sfp_update_tx_rx_status(dev); - - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - if(attr->index == RX_LOS_ALL) { - int i = 0; - u8 values[6] = {0}; - - for (i = 0; i < ARRAY_SIZE(values); i++) { - values[i] = (u8)(data->msa->status[2] >> (i * 8)); - } - - /** Return values 1 -> 48 in order */ - return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x\n", - values[0], values[1], values[2], - values[3], values[4], values[5]); - } - - switch (attr->index) { - case TX_FAULT: - index = 0; - break; - case TX_DISABLE: - index = 1; - break; - case RX_LOS: - index = 2; - break; - default: - break; - } - - val = (data->msa->status[index] & BIT_INDEX(data->port)) ? 1 : 0; - return sprintf(buf, "%d\n", val); -} - -/* SFP/QSFP common attributes for sysfs */ -static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); -static SENSOR_DEVICE_ATTR(sfp_port_type, S_IRUGO, show_port_type, NULL, PORT_TYPE); -static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); -static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); - -/* QSFP attributes for sysfs */ -static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); -static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); -static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); -static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); -static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); -static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); -static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); -static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); -static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); -static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); -static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); -static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); -static struct attribute *qsfp_attributes[] = { - &sensor_dev_attr_sfp_port_number.dev_attr.attr, - &sensor_dev_attr_sfp_port_type.dev_attr.attr, - &sensor_dev_attr_sfp_is_present.dev_attr.attr, - &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, - NULL -}; - -/* SFP msa attributes for sysfs */ -static SENSOR_DEVICE_ATTR(sfp_ddm_implemented, S_IRUGO, sfp_show_ddm_implemented, NULL, DDM_IMPLEMENTED); -static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS); -static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS_ALL); -static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, sfp_show_tx_rx_status, sfp_set_tx_disable, TX_DISABLE); -static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, sfp_show_tx_rx_status, NULL, TX_FAULT); -static struct attribute *sfp_msa_attributes[] = { - &sensor_dev_attr_sfp_port_number.dev_attr.attr, - &sensor_dev_attr_sfp_port_type.dev_attr.attr, - &sensor_dev_attr_sfp_is_present.dev_attr.attr, - &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, - &sensor_dev_attr_sfp_ddm_implemented.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, - NULL -}; - -/* SFP ddm attributes for sysfs */ -static struct attribute *sfp_ddm_attributes[] = { - NULL -}; - -static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, - int data_len) -{ -#if USE_I2C_BLOCK_READ - int status, retry = I2C_RW_RETRY_COUNT; - - if (data_len > I2C_SMBUS_BLOCK_MAX) { - data_len = I2C_SMBUS_BLOCK_MAX; - } - - while (retry) { - status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - return status; - } - - return data_len; -#else - int status, retry = I2C_RW_RETRY_COUNT; - - while (retry) { - status = i2c_smbus_write_byte_data(client, command, *data); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - return status; - } - - return 1; -#endif - - -} - -static ssize_t sfp_port_write(struct sfp_port_data *data, - const char *buf, loff_t off, size_t count) -{ - ssize_t retval = 0; - - if (unlikely(!count)) { - return count; - } - - /* - * Write data to chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&data->update_lock); - - while (count) { - ssize_t status; - - status = sfp_eeprom_write(data->client, 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 ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct sfp_port_data *data; - DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); - data = dev_get_drvdata(container_of(kobj, struct device, kobj)); - return sfp_port_write(data, buf, off, count); -} - -static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, - int data_len) -{ -#if USE_I2C_BLOCK_READ - int status, retry = I2C_RW_RETRY_COUNT; - - if (data_len > I2C_SMBUS_BLOCK_MAX) { - data_len = I2C_SMBUS_BLOCK_MAX; - } - - while (retry) { - status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - goto abort; - } - if (unlikely(status != data_len)) { - status = -EIO; - goto abort; - } - - //result = data_len; - -abort: - return status; -#else - int status, retry = I2C_RW_RETRY_COUNT; - - while (retry) { - status = i2c_smbus_read_byte_data(client, command); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, result); - goto abort; - } - - *data = (u8)status; - status = 1; - -abort: - return status; -#endif -} - -static ssize_t sfp_port_read(struct sfp_port_data *data, - char *buf, loff_t off, size_t count) -{ - ssize_t retval = 0; - - if (unlikely(!count)) { - DEBUG_PRINT("Count = 0, return"); - return count; - } - - /* - * Read data from chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&data->update_lock); - - while (count) { - ssize_t status; - - status = sfp_eeprom_read(data->client, 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 ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct sfp_port_data *data; - DEBUG_PRINT("offset = (%d), count = (%d)", off, count); - data = dev_get_drvdata(container_of(kobj, struct device, kobj)); - return sfp_port_read(data, buf, off, count); -} - -static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) -{ - int err; - - sysfs_bin_attr_init(eeprom); - eeprom->attr.name = EEPROM_NAME; - eeprom->attr.mode = S_IWUSR | S_IRUGO; - eeprom->read = sfp_bin_read; - eeprom->write = sfp_bin_write; - eeprom->size = EEPROM_SIZE; - - /* Create eeprom file */ - err = sysfs_create_bin_file(kobj, eeprom); - if (err) { - return err; - } - - return 0; -} - -static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) -{ - sysfs_remove_bin_file(kobj, eeprom); - return 0; -} - -static const struct attribute_group sfp_msa_group = { - .attrs = sfp_msa_attributes, -}; - -static int sfp_i2c_check_functionality(struct i2c_client *client) -{ -#if USE_I2C_BLOCK_READ - return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); -#else - return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); -#endif -} - -static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, - struct sfp_msa_data **data) -{ - int status; - struct sfp_msa_data *msa; - - if (!sfp_i2c_check_functionality(client)) { - status = -EIO; - goto exit; - } - - msa = kzalloc(sizeof(struct sfp_msa_data), GFP_KERNEL); - if (!msa) { - status = -ENOMEM; - goto exit; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &sfp_msa_group); - if (status) { - goto exit_free; - } - - /* init eeprom */ - status = sfp_sysfs_eeprom_init(&client->dev.kobj, &msa->eeprom.bin); - if (status) { - goto exit_remove; - } - - *data = msa; - dev_info(&client->dev, "sfp msa '%s'\n", client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); -exit_free: - kfree(msa); -exit: - - return status; -} - -static const struct attribute_group sfp_ddm_group = { - .attrs = sfp_ddm_attributes, -}; - -static int sfp_ddm_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, - struct sfp_ddm_data **data) -{ - int status; - struct sfp_ddm_data *ddm; - - if (!sfp_i2c_check_functionality(client)) { - status = -EIO; - goto exit; - } - - ddm = kzalloc(sizeof(struct sfp_ddm_data), GFP_KERNEL); - if (!ddm) { - status = -ENOMEM; - goto exit; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &sfp_ddm_group); - if (status) { - goto exit_free; - } - - /* init eeprom */ - status = sfp_sysfs_eeprom_init(&client->dev.kobj, &ddm->eeprom.bin); - if (status) { - goto exit_remove; - } - - *data = ddm; - dev_info(&client->dev, "sfp ddm '%s'\n", client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); -exit_free: - kfree(ddm); -exit: - - return status; -} - -static const struct attribute_group qsfp_group = { - .attrs = qsfp_attributes, -}; - -static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, - struct qsfp_data **data) -{ - int status; - struct qsfp_data *qsfp; - - if (!sfp_i2c_check_functionality(client)) { - status = -EIO; - goto exit; - } - - qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); - if (!qsfp) { - status = -ENOMEM; - goto exit; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &qsfp_group); - if (status) { - goto exit_free; - } - - /* init eeprom */ - status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); - if (status) { - goto exit_remove; - } - - /* Bring QSFPs out of reset */ - accton_i2c_cpld_write(0x62, 0x15, 0x3F); - - *data = qsfp; - dev_info(&client->dev, "qsfp '%s'\n", client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &qsfp_group); -exit_free: - kfree(qsfp); -exit: - - return status; -} - -static int sfp_device_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct sfp_port_data *data = NULL; - - data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); - if (!data) { - return -ENOMEM; - } - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->port = dev_id->driver_data; - data->client = client; - - if (dev_id->driver_data >= sfp1 && dev_id->driver_data <= sfp48) { - if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { - data->driver_type = DRIVER_TYPE_SFP_MSA; - return sfp_msa_probe(client, dev_id, &data->msa); - } - else if (client->addr == SFP_EEPROM_A2_I2C_ADDR) { - data->driver_type = DRIVER_TYPE_SFP_DDM; - return sfp_ddm_probe(client, dev_id, &data->ddm); - } - } - else { /* sfp49 ~ sfp54 */ - if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { - data->driver_type = DRIVER_TYPE_QSFP; - return qsfp_probe(client, dev_id, &data->qsfp); - } - } - - return -ENODEV; -} - -static int sfp_msa_remove(struct i2c_client *client, struct sfp_msa_data *data) -{ - sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); - sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); - kfree(data); - return 0; -} - -static int sfp_ddm_remove(struct i2c_client *client, struct sfp_ddm_data *data) -{ - sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); - sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); - kfree(data); - return 0; -} - -static int qfp_remove(struct i2c_client *client, struct qsfp_data *data) -{ - sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); - sysfs_remove_group(&client->dev.kobj, &qsfp_group); - kfree(data); - return 0; -} - -static int sfp_device_remove(struct i2c_client *client) -{ - struct sfp_port_data *data = i2c_get_clientdata(client); - - switch (data->driver_type) { - case DRIVER_TYPE_SFP_MSA: - return sfp_msa_remove(client, data->msa); - case DRIVER_TYPE_SFP_DDM: - return sfp_ddm_remove(client, data->ddm); - case DRIVER_TYPE_QSFP: - return qfp_remove(client, data->qsfp); - } - - return 0; -} - -static struct i2c_driver sfp_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = sfp_device_probe, - .remove = sfp_device_remove, - .id_table = sfp_device_id, - .address_list = normal_i2c, -}; - -static int __init sfp_init(void) -{ - extern int platform_accton_as5512_54x(void); - if(!platform_accton_as5512_54x()) { - return -ENODEV; - } - - return i2c_add_driver(&sfp_driver); -} - -static void __exit sfp_exit(void) -{ - i2c_del_driver(&sfp_driver); -} - -MODULE_AUTHOR("Brandon Chuang "); -MODULE_DESCRIPTION("accton as5512_54x_sfp driver"); -MODULE_LICENSE("GPL"); - -module_init(sfp_init); -module_exit(sfp_exit); - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/onlp/builds/src/module/src/sfpi.c b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/onlp/builds/src/module/src/sfpi.c index 141b8645..f4c59343 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/onlp/builds/src/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/onlp/builds/src/module/src/sfpi.c @@ -24,58 +24,53 @@ * ***********************************************************/ #include - -#include /* For O_RDWR && open */ -#include -#include -#include -#include - -#include "platform_lib.h" - -#define MAX_SFP_PATH 64 -static char sfp_node_path[MAX_SFP_PATH] = {0}; +#include +#include +#include "x86_64_accton_as5512_54x_int.h" +#include "x86_64_accton_as5512_54x_log.h" #define MUX_START_INDEX 2 -#define NUM_OF_SFP_PORT 54 -static const int sfp_mux_index[NUM_OF_SFP_PORT] = { - 0, 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, -52, 50, 48, 53, 51, 49 -}; -#define FRONT_PORT_TO_MUX_INDEX(port) (sfp_mux_index[port]+MUX_START_INDEX) +#define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" +#define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/0-00%d/module_present_%d" +#define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/0-00%d/module_rx_los_%d" +#define MODULE_TXFAULT_FORMAT "/sys/bus/i2c/devices/0-00%d/module_tx_fault_%d" +#define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/0-00%d/module_tx_disable_%d" +#define MODULE_PRESENT_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/0-0061/module_present_all" +#define MODULE_PRESENT_ALL_ATTR_CPLD3 "/sys/bus/i2c/devices/0-0062/module_present_all" +#define MODULE_RXLOS_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/0-0061/module_rx_los_all" +#define MODULE_RXLOS_ALL_ATTR_CPLD3 "/sys/bus/i2c/devices/0-0062/module_rx_los_all" -static int -sfp_node_read_int(char *node_path, int *value, int data_len) +static int front_port_bus_index(int port) { - int ret = 0; - char buf[8] = {0}; - *value = 0; + int rport = 0; - ret = deviceNodeReadString(node_path, buf, sizeof(buf), data_len); - - if (ret == 0) { - *value = atoi(buf); + switch (port) + { + case 48: + rport = 52; + break; + case 49: + rport = 50; + break; + case 50: + rport = 48; + break; + case 51: + rport = 53; + break; + case 52: + rport = 51; + break; + case 53: + rport = 49; + break; + default: + rport = port; + break; } - return ret; -} - -static char* -sfp_get_port_path_addr(int port, int addr, char *node_name) -{ - sprintf(sfp_node_path, "/sys/bus/i2c/devices/%d-00%d/%s", - FRONT_PORT_TO_MUX_INDEX(port), addr, - node_name); - return sfp_node_path; -} - -static char* -sfp_get_port_path(int port, char *node_name) -{ - return sfp_get_port_path_addr(port, 50, node_name); + return (rport + MUX_START_INDEX); } /************************************************************ @@ -114,10 +109,10 @@ onlp_sfpi_is_present(int port) * Return < 0 if error. */ int present; - char* path = sfp_get_port_path(port, "sfp_is_present"); - - if (sfp_node_read_int(path, &present, 0) != 0) { - AIM_LOG_INFO("Unable to read present status from port(%d)\r\n", port); + int addr = (port < 24) ? 61 : 62; + + if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -128,29 +123,35 @@ int onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) { uint32_t bytes[7]; - char* path; FILE* fp; - path = sfp_get_port_path(0, "sfp_is_present_all"); - fp = fopen(path, "r"); - + /* Read present status of port 0~23 */ + fp = fopen(MODULE_PRESENT_ALL_ATTR_CPLD2, "r"); if(fp == NULL) { - AIM_LOG_ERROR("Unable to open the sfp_is_present_all device file."); + AIM_LOG_ERROR("Unable to open the module_present_all device file of CPLD2."); return ONLP_STATUS_E_INTERNAL; } - int count = fscanf(fp, "%x %x %x %x %x %x %x", - bytes+0, - bytes+1, - bytes+2, - bytes+3, - bytes+4, - bytes+5, - bytes+6 - ); + + int count = fscanf(fp, "%x %x %x", bytes+0, bytes+1, bytes+2); fclose(fp); - if(count != AIM_ARRAYSIZE(bytes)) { + if(count != 3) { /* Likely a CPLD read timeout. */ - AIM_LOG_ERROR("Unable to read all fields from the sfp_is_present_all device file."); + AIM_LOG_ERROR("Unable to read all fields the module_present_all device file of CPLD2."); + return ONLP_STATUS_E_INTERNAL; + } + + /* Read present status of port 24~53 */ + fp = fopen(MODULE_PRESENT_ALL_ATTR_CPLD3, "r"); + if(fp == NULL) { + AIM_LOG_ERROR("Unable to open the module_present_all device file of CPLD3."); + return ONLP_STATUS_E_INTERNAL; + } + + count = fscanf(fp, "%x %x %x %x", bytes+3, bytes+4, bytes+5, bytes+6); + fclose(fp); + if(count != 4) { + /* Likely a CPLD read timeout. */ + AIM_LOG_ERROR("Unable to read all fields the module_present_all device file of CPLD3."); return ONLP_STATUS_E_INTERNAL; } @@ -177,33 +178,39 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) int onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) { - uint32_t bytes[7]; - char* path; + uint32_t bytes[6]; + uint32_t *ptr = bytes; FILE* fp; - path = sfp_get_port_path(0, "sfp_rx_los_all"); - fp = fopen(path, "r"); + /* Read present status of port 0~23 */ + int addr, i = 0; - if(fp == NULL) { - AIM_LOG_ERROR("Unable to open the sfp_rx_los_all device file."); - return ONLP_STATUS_E_INTERNAL; - } - int count = fscanf(fp, "%x %x %x %x %x %x", - bytes+0, - bytes+1, - bytes+2, - bytes+3, - bytes+4, - bytes+5 - ); - fclose(fp); - if(count != 6) { - AIM_LOG_ERROR("Unable to read all fields from the sfp_rx_los_all device file."); - return ONLP_STATUS_E_INTERNAL; + for (addr = 61; addr <= 62; addr++) { + if (addr == 61) { + fp = fopen(MODULE_RXLOS_ALL_ATTR_CPLD2, "r"); + } + else { + fp = fopen(MODULE_RXLOS_ALL_ATTR_CPLD3, "r"); + } + + if(fp == NULL) { + AIM_LOG_ERROR("Unable to open the module_rx_los_all device file of CPLD(0x%d)", addr); + return ONLP_STATUS_E_INTERNAL; + } + + int count = fscanf(fp, "%x %x %x", ptr+0, ptr+1, ptr+2); + fclose(fp); + if(count != 3) { + /* Likely a CPLD read timeout. */ + AIM_LOG_ERROR("Unable to read all fields from the module_rx_los_all device file of CPLD(0x%d)", addr); + return ONLP_STATUS_E_INTERNAL; + } + + ptr += count; } /* Convert to 64 bit integer in port order */ - int i = 0; + i = 0; uint64_t rx_los_all = 0 ; for(i = 5; i >= 0; i--) { rx_los_all <<= 8; @@ -222,18 +229,22 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) int onlp_sfpi_eeprom_read(int port, uint8_t data[256]) { - char* path = sfp_get_port_path(port, "sfp_eeprom"); - /* * 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 (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) { - AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port); + if(onlp_file_read(data, 256, &size, PORT_EEPROM_FORMAT, front_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; } @@ -243,17 +254,60 @@ onlp_sfpi_eeprom_read(int port, uint8_t data[256]) int onlp_sfpi_dom_read(int port, uint8_t data[256]) { - char* path = sfp_get_port_path_addr(port, 51, "sfp_eeprom"); - memset(data, 0, 256); + FILE* fp; + char file[64] = {0}; + + sprintf(file, PORT_EEPROM_FORMAT, front_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 (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) { - AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port); + 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 = front_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 = front_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 = front_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 = front_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) { @@ -263,13 +317,13 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) return ONLP_STATUS_E_UNSUPPORTED; } + int addr = (port < 24) ? 61 : 62; + switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: { - char* path = sfp_get_port_path(port, "sfp_tx_disable"); - - if (deviceNodeWriteInt(path, value, 0) != 0) { + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -291,19 +345,18 @@ int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { int rv; - char* path = NULL; if (port < 0 || port >= 48) { return ONLP_STATUS_E_UNSUPPORTED; } + int addr = (port < 24) ? 61 : 62; + switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { - path = sfp_get_port_path(port, "sfp_rx_los"); - - if (sfp_node_read_int(path, value, 0) != 0) { + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -315,9 +368,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_FAULT: { - path = sfp_get_port_path(port, "sfp_tx_fault"); - - if (sfp_node_read_int(path, value, 0) != 0) { + if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -329,9 +380,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_DISABLE: { - path = sfp_get_port_path(port, "sfp_tx_disable"); - - if (sfp_node_read_int(path, value, 0) != 0) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/python/x86_64_accton_as5512_54x_r0/__init__.py b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/python/x86_64_accton_as5512_54x_r0/__init__.py index 5f00ee18..3e920af3 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/python/x86_64_accton_as5512_54x_r0/__init__.py +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5512-54x/platform-config/r0/src/python/x86_64_accton_as5512_54x_r0/__init__.py @@ -8,10 +8,10 @@ class OnlPlatform_x86_64_accton_as5512_54x_r0(OnlPlatformAccton, SYS_OBJECT_ID=".5512.54.1" def baseconfig(self): - + self.insmod('optoe') self.insmod('cpr_4011_4mxx') - self.insmod('accton_i2c_cpld') - self.insmod_platform() + for m in [ 'cpld', 'fan', 'psu', 'leds' ]: + self.insmod("x86-64-accton-as5512-54x-%s.ko" % m) ########### initialize I2C bus 0 ########### @@ -30,23 +30,29 @@ class OnlPlatform_x86_64_accton_as5512_54x_r0(OnlPlatformAccton, # initialize CPLDs self.new_i2c_devices( [ - ('accton_i2c_cpld', 0x60, 0), - ('accton_i2c_cpld', 0x61, 0), - ('accton_i2c_cpld', 0x62, 0), + ('as5512_54x_cpld1', 0x60, 0), + ('as5512_54x_cpld2', 0x61, 0), + ('as5512_54x_cpld3', 0x62, 0), ] ) # initialize SFP devices for port in range(1, 49): - self.new_i2c_device('sfp%d' % port, 0x50, port+1) - self.new_i2c_device('sfp%d' % port, 0x51, port+1) + self.new_i2c_device('optoe2', 0x50, port+1) + subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port, port+1), shell=True) # Initialize QSFP devices - self.new_i2c_device('sfp51', 0x50, 50) - self.new_i2c_device('sfp54', 0x50, 51) - self.new_i2c_device('sfp50', 0x50, 52) - self.new_i2c_device('sfp53', 0x50, 53) - self.new_i2c_device('sfp49', 0x50, 54) - self.new_i2c_device('sfp52', 0x50, 55) + self.new_i2c_device('optoe1', 0x50, 50) + self.new_i2c_device('optoe1', 0x50, 51) + self.new_i2c_device('optoe1', 0x50, 52) + self.new_i2c_device('optoe1', 0x50, 53) + self.new_i2c_device('optoe1', 0x50, 54) + self.new_i2c_device('optoe1', 0x50, 55) + subprocess.call('echo port51 > /sys/bus/i2c/devices/50-0050/port_name', shell=True) + subprocess.call('echo port54 > /sys/bus/i2c/devices/51-0050/port_name', shell=True) + subprocess.call('echo port50 > /sys/bus/i2c/devices/52-0050/port_name', shell=True) + subprocess.call('echo port53 > /sys/bus/i2c/devices/53-0050/port_name', shell=True) + subprocess.call('echo port49 > /sys/bus/i2c/devices/54-0050/port_name', shell=True) + subprocess.call('echo port52 > /sys/bus/i2c/devices/55-0050/port_name', shell=True) ########### initialize I2C bus 1 ########### self.new_i2c_devices( From 3bc5f49ab823e0d3b556c156fe0e298d8b577a78 Mon Sep 17 00:00:00 2001 From: Ohad Oz Date: Mon, 23 Jul 2018 21:01:15 +0000 Subject: [PATCH 04/22] Add patches from upstream kernels - backport 4.17 - 4.19 --- .../configs/x86_64-all/x86_64-all.config | 1 + ...ort-patchwork-from-kernels-4.17-4.19.patch | 3063 +++++++++++++++++ .../base/any/kernels/4.9-lts/patches/series | 1 + 3 files changed, 3065 insertions(+) create mode 100644 packages/base/any/kernels/4.9-lts/patches/0013-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch diff --git a/packages/base/any/kernels/4.9-lts/configs/x86_64-all/x86_64-all.config b/packages/base/any/kernels/4.9-lts/configs/x86_64-all/x86_64-all.config index 423e0d63..db1ad67e 100644 --- a/packages/base/any/kernels/4.9-lts/configs/x86_64-all/x86_64-all.config +++ b/packages/base/any/kernels/4.9-lts/configs/x86_64-all/x86_64-all.config @@ -2435,6 +2435,7 @@ CONFIG_SENSORS_MAX6620=y # CONFIG_SENSORS_MAX6697 is not set # CONFIG_SENSORS_MAX31790 is not set # CONFIG_SENSORS_MCP3021 is not set +CONFIG_SENSORS_MLXREG_FAN=y # CONFIG_SENSORS_ADCXX is not set # CONFIG_SENSORS_LM63 is not set # CONFIG_SENSORS_LM70 is not set diff --git a/packages/base/any/kernels/4.9-lts/patches/0013-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch b/packages/base/any/kernels/4.9-lts/patches/0013-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch new file mode 100644 index 00000000..5c0c5d91 --- /dev/null +++ b/packages/base/any/kernels/4.9-lts/patches/0013-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch @@ -0,0 +1,3063 @@ +From 54f7d08c9337a82e79142fcdab2b6fa5bcf5843e Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 18 Jul 2018 16:27:08 +0000 +Subject: [patch bacport patchwork 1/1] Mellanox backport patchwork from + kerenls 4.17-4.19 + +Signed-off-by: Vadim Pasternak +--- + drivers/hwmon/Kconfig | 12 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/mlxreg-fan.c | 489 ++++++++++++ + drivers/platform/mellanox/Kconfig | 9 +- + drivers/platform/mellanox/Makefile | 7 +- + drivers/platform/mellanox/mlxreg-hotplug.c | 306 ++++---- + drivers/platform/mellanox/mlxreg-io.c | 118 +-- + drivers/platform/x86/mlx-platform.c | 1106 +++++++++++++++++++--------- + 8 files changed, 1482 insertions(+), 566 deletions(-) + create mode 100644 drivers/hwmon/mlxreg-fan.c + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 45cef3d..9014151 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -907,6 +907,18 @@ config SENSORS_MCP3021 + This driver can also be built as a module. If so, the module + will be called mcp3021. + ++config SENSORS_MLXREG_FAN ++ tristate "Mellanox Mellanox FAN driver" ++ depends on MELLANOX_PLATFORM ++ select THERMAL ++ select REGMAP ++ help ++ This option enables support for the FAN control on the Mellanox ++ Ethernet and InfiniBand switches. The driver can be activated by the ++ platform device add call. Say Y to enable these. To compile this ++ driver as a module, choose 'M' here: the module will be called ++ mlxreg-fan. ++ + config SENSORS_MENF21BMC_HWMON + tristate "MEN 14F021P00 BMC Hardware Monitoring" + depends on MFD_MENF21BMC +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index aecf4ba..4ff1b63 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -122,6 +122,7 @@ obj-$(CONFIG_SENSORS_MAX6697) += max6697.o + obj-$(CONFIG_SENSORS_MAX31790) += max31790.o + obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o + obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o ++obj-$(CONFIG_SENSORS_MLXREG_FAN) += mlxreg-fan.o + obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o + obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o + obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o +diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c +new file mode 100644 +index 0000000..de46577 +--- /dev/null ++++ b/drivers/hwmon/mlxreg-fan.c +@@ -0,0 +1,489 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) ++// ++// Copyright (c) 2018 Mellanox Technologies. All rights reserved. ++// Copyright (c) 2018 Vadim Pasternak ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MLXREG_FAN_MAX_TACHO 12 ++#define MLXREG_FAN_MAX_STATE 10 ++#define MLXREG_FAN_MIN_DUTY 51 /* 20% */ ++#define MLXREG_FAN_MAX_DUTY 255 /* 100% */ ++/* ++ * Minimum and maximum FAN allowed speed in percent: from 20% to 100%. Values ++ * MLXREG_FAN_MAX_STATE + x, where x is between 2 and 10 are used for ++ * setting FAN speed dynamic minimum. For example, if value is set to 14 (40%) ++ * cooling levels vector will be set to 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10 to ++ * introduce PWM speed in percent: 40, 40, 40, 40, 40, 50, 60. 70, 80, 90, 100. ++ */ ++#define MLXREG_FAN_SPEED_MIN (MLXREG_FAN_MAX_STATE + 2) ++#define MLXREG_FAN_SPEED_MAX (MLXREG_FAN_MAX_STATE * 2) ++#define MLXREG_FAN_SPEED_MIN_LEVEL 2 /* 20 percent */ ++#define MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF 44 ++#define MLXREG_FAN_TACHO_DIVIDER_DEF 1132 ++/* ++ * FAN datasheet defines the formula for RPM calculations as RPM = 15/t-high. ++ * The logic in a programmable device measures the time t-high by sampling the ++ * tachometer every t-sample (with the default value 11.32 uS) and increment ++ * a counter (N) as long as the pulse has not change: ++ * RPM = 15 / (t-sample * (K + Regval)), where: ++ * Regval: is the value read from the programmable device register; ++ * - 0xff - represents tachometer fault; ++ * - 0xfe - represents tachometer minimum value , which is 4444 RPM; ++ * - 0x00 - represents tachometer maximum value , which is 300000 RPM; ++ * K: is 44 and it represents the minimum allowed samples per pulse; ++ * N: is equal K + Regval; ++ * In order to calculate RPM from the register value the following formula is ++ * used: RPM = 15 / ((Regval + K) * 11.32) * 10^(-6)), which in the ++ * default case is modified to: ++ * RPM = 15000000 * 100 / ((Regval + 44) * 1132); ++ * - for Regval 0x00, RPM will be 15000000 * 100 / (44 * 1132) = 30115; ++ * - for Regval 0xfe, RPM will be 15000000 * 100 / ((254 + 44) * 1132) = 4446; ++ * In common case the formula is modified to: ++ * RPM = 15000000 * 100 / ((Regval + samples) * divider). ++ */ ++#define MLXREG_FAN_GET_RPM(rval, d, s) (DIV_ROUND_CLOSEST(15000000 * 100, \ ++ ((rval) + (s)) * (d))) ++#define MLXREG_FAN_GET_FAULT(val, mask) (!!((val) ^ (mask))) ++#define MLXREG_FAN_PWM_DUTY2STATE(duty) (DIV_ROUND_CLOSEST((duty) * \ ++ MLXREG_FAN_MAX_STATE, \ ++ MLXREG_FAN_MAX_DUTY)) ++#define MLXREG_FAN_PWM_STATE2DUTY(stat) (DIV_ROUND_CLOSEST((stat) * \ ++ MLXREG_FAN_MAX_DUTY, \ ++ MLXREG_FAN_MAX_STATE)) ++ ++/* ++ * struct mlxreg_fan_tacho - tachometer data (internal use): ++ * ++ * @connected: indicates if tachometer is connected; ++ * @reg: register offset; ++ * @mask: fault mask; ++ */ ++struct mlxreg_fan_tacho { ++ bool connected; ++ u32 reg; ++ u32 mask; ++}; ++ ++/* ++ * struct mlxreg_fan_pwm - PWM data (internal use): ++ * ++ * @connected: indicates if PWM is connected; ++ * @reg: register offset; ++ */ ++struct mlxreg_fan_pwm { ++ bool connected; ++ u32 reg; ++}; ++ ++/* ++ * struct mlxreg_fan - private data (internal use): ++ * ++ * @dev: basic device; ++ * @regmap: register map of parent device; ++ * @tacho: tachometer data; ++ * @pwm: PWM data; ++ * @samples: minimum allowed samples per pulse; ++ * @divider: divider value for tachometer RPM calculation; ++ * @cooling: cooling device levels; ++ * @cdev: cooling device; ++ */ ++struct mlxreg_fan { ++ struct device *dev; ++ void *regmap; ++ struct mlxreg_core_platform_data *pdata; ++ struct mlxreg_fan_tacho tacho[MLXREG_FAN_MAX_TACHO]; ++ struct mlxreg_fan_pwm pwm; ++ int samples; ++ int divider; ++ u8 cooling_levels[MLXREG_FAN_MAX_STATE + 1]; ++ struct thermal_cooling_device *cdev; ++}; ++ ++static int ++mlxreg_fan_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, ++ int channel, long *val) ++{ ++ struct mlxreg_fan *fan = dev_get_drvdata(dev); ++ struct mlxreg_fan_tacho *tacho; ++ u32 regval; ++ int err; ++ ++ switch (type) { ++ case hwmon_fan: ++ tacho = &fan->tacho[channel]; ++ switch (attr) { ++ case hwmon_fan_input: ++ err = regmap_read(fan->regmap, tacho->reg, ®val); ++ if (err) ++ return err; ++ ++ *val = MLXREG_FAN_GET_RPM(regval, fan->divider, ++ fan->samples); ++ break; ++ ++ case hwmon_fan_fault: ++ err = regmap_read(fan->regmap, tacho->reg, ®val); ++ if (err) ++ return err; ++ ++ *val = MLXREG_FAN_GET_FAULT(regval, tacho->mask); ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ break; ++ ++ case hwmon_pwm: ++ switch (attr) { ++ case hwmon_pwm_input: ++ err = regmap_read(fan->regmap, fan->pwm.reg, ®val); ++ if (err) ++ return err; ++ ++ *val = regval; ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static int ++mlxreg_fan_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, ++ int channel, long val) ++{ ++ struct mlxreg_fan *fan = dev_get_drvdata(dev); ++ ++ switch (type) { ++ case hwmon_pwm: ++ switch (attr) { ++ case hwmon_pwm_input: ++ if (val < MLXREG_FAN_MIN_DUTY || ++ val > MLXREG_FAN_MAX_DUTY) ++ return -EINVAL; ++ return regmap_write(fan->regmap, fan->pwm.reg, val); ++ default: ++ return -EOPNOTSUPP; ++ } ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ ++static umode_t ++mlxreg_fan_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, ++ int channel) ++{ ++ switch (type) { ++ case hwmon_fan: ++ if (!(((struct mlxreg_fan *)data)->tacho[channel].connected)) ++ return 0; ++ ++ switch (attr) { ++ case hwmon_fan_input: ++ case hwmon_fan_fault: ++ return 0444; ++ default: ++ break; ++ } ++ break; ++ ++ case hwmon_pwm: ++ if (!(((struct mlxreg_fan *)data)->pwm.connected)) ++ return 0; ++ ++ switch (attr) { ++ case hwmon_pwm_input: ++ return 0644; ++ default: ++ break; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++static const u32 mlxreg_fan_hwmon_fan_config[] = { ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ HWMON_F_INPUT | HWMON_F_FAULT, ++ 0 ++}; ++ ++static const struct hwmon_channel_info mlxreg_fan_hwmon_fan = { ++ .type = hwmon_fan, ++ .config = mlxreg_fan_hwmon_fan_config, ++}; ++ ++static const u32 mlxreg_fan_hwmon_pwm_config[] = { ++ HWMON_PWM_INPUT, ++ 0 ++}; ++ ++static const struct hwmon_channel_info mlxreg_fan_hwmon_pwm = { ++ .type = hwmon_pwm, ++ .config = mlxreg_fan_hwmon_pwm_config, ++}; ++ ++static const struct hwmon_channel_info *mlxreg_fan_hwmon_info[] = { ++ &mlxreg_fan_hwmon_fan, ++ &mlxreg_fan_hwmon_pwm, ++ NULL ++}; ++ ++static const struct hwmon_ops mlxreg_fan_hwmon_hwmon_ops = { ++ .is_visible = mlxreg_fan_is_visible, ++ .read = mlxreg_fan_read, ++ .write = mlxreg_fan_write, ++}; ++ ++static const struct hwmon_chip_info mlxreg_fan_hwmon_chip_info = { ++ .ops = &mlxreg_fan_hwmon_hwmon_ops, ++ .info = mlxreg_fan_hwmon_info, ++}; ++ ++static int mlxreg_fan_get_max_state(struct thermal_cooling_device *cdev, ++ unsigned long *state) ++{ ++ *state = MLXREG_FAN_MAX_STATE; ++ return 0; ++} ++ ++static int mlxreg_fan_get_cur_state(struct thermal_cooling_device *cdev, ++ unsigned long *state) ++ ++{ ++ struct mlxreg_fan *fan = cdev->devdata; ++ u32 regval; ++ int err; ++ ++ err = regmap_read(fan->regmap, fan->pwm.reg, ®val); ++ if (err) { ++ dev_err(fan->dev, "Failed to query PWM duty\n"); ++ return err; ++ } ++ ++ *state = MLXREG_FAN_PWM_DUTY2STATE(regval); ++ ++ return 0; ++} ++ ++static int mlxreg_fan_set_cur_state(struct thermal_cooling_device *cdev, ++ unsigned long state) ++ ++{ ++ struct mlxreg_fan *fan = cdev->devdata; ++ unsigned long cur_state; ++ u32 regval; ++ int i; ++ int err; ++ ++ /* ++ * Verify if this request is for changing allowed FAN dynamical ++ * minimum. If it is - update cooling levels accordingly and update ++ * state, if current state is below the newly requested minimum state. ++ * For example, if current state is 5, and minimal state is to be ++ * changed from 4 to 6, fan->cooling_levels[0 to 5] will be changed all ++ * from 4 to 6. And state 5 (fan->cooling_levels[4]) should be ++ * overwritten. ++ */ ++ if (state >= MLXREG_FAN_SPEED_MIN && state <= MLXREG_FAN_SPEED_MAX) { ++ state -= MLXREG_FAN_MAX_STATE; ++ for (i = 0; i < state; i++) ++ fan->cooling_levels[i] = state; ++ for (i = state; i <= MLXREG_FAN_MAX_STATE; i++) ++ fan->cooling_levels[i] = i; ++ ++ err = regmap_read(fan->regmap, fan->pwm.reg, ®val); ++ if (err) { ++ dev_err(fan->dev, "Failed to query PWM duty\n"); ++ return err; ++ } ++ ++ cur_state = MLXREG_FAN_PWM_DUTY2STATE(regval); ++ if (state < cur_state) ++ return 0; ++ ++ state = cur_state; ++ } ++ ++ if (state > MLXREG_FAN_MAX_STATE) ++ return -EINVAL; ++ ++ /* Normalize the state to the valid speed range. */ ++ state = fan->cooling_levels[state]; ++ err = regmap_write(fan->regmap, fan->pwm.reg, ++ MLXREG_FAN_PWM_STATE2DUTY(state)); ++ if (err) { ++ dev_err(fan->dev, "Failed to write PWM duty\n"); ++ return err; ++ } ++ return 0; ++} ++ ++static const struct thermal_cooling_device_ops mlxreg_fan_cooling_ops = { ++ .get_max_state = mlxreg_fan_get_max_state, ++ .get_cur_state = mlxreg_fan_get_cur_state, ++ .set_cur_state = mlxreg_fan_set_cur_state, ++}; ++ ++static int mlxreg_fan_config(struct mlxreg_fan *fan, ++ struct mlxreg_core_platform_data *pdata) ++{ ++ struct mlxreg_core_data *data = pdata->data; ++ bool configured = false; ++ int tacho_num = 0, i; ++ ++ fan->samples = MLXREG_FAN_TACHO_SAMPLES_PER_PULSE_DEF; ++ fan->divider = MLXREG_FAN_TACHO_DIVIDER_DEF; ++ for (i = 0; i < pdata->counter; i++, data++) { ++ if (strnstr(data->label, "tacho", sizeof(data->label))) { ++ if (tacho_num == MLXREG_FAN_MAX_TACHO) { ++ dev_err(fan->dev, "too many tacho entries: %s\n", ++ data->label); ++ return -EINVAL; ++ } ++ fan->tacho[tacho_num].reg = data->reg; ++ fan->tacho[tacho_num].mask = data->mask; ++ fan->tacho[tacho_num++].connected = true; ++ } else if (strnstr(data->label, "pwm", sizeof(data->label))) { ++ if (fan->pwm.connected) { ++ dev_err(fan->dev, "duplicate pwm entry: %s\n", ++ data->label); ++ return -EINVAL; ++ } ++ fan->pwm.reg = data->reg; ++ fan->pwm.connected = true; ++ } else if (strnstr(data->label, "conf", sizeof(data->label))) { ++ if (configured) { ++ dev_err(fan->dev, "duplicate conf entry: %s\n", ++ data->label); ++ return -EINVAL; ++ } ++ /* Validate that conf parameters are not zeros. */ ++ if (!data->mask || !data->bit) { ++ dev_err(fan->dev, "invalid conf entry params: %s\n", ++ data->label); ++ return -EINVAL; ++ } ++ fan->samples = data->mask; ++ fan->divider = data->bit; ++ configured = true; ++ } else { ++ dev_err(fan->dev, "invalid label: %s\n", data->label); ++ return -EINVAL; ++ } ++ } ++ ++ /* Init cooling levels per PWM state. */ ++ for (i = 0; i < MLXREG_FAN_SPEED_MIN_LEVEL; i++) ++ fan->cooling_levels[i] = MLXREG_FAN_SPEED_MIN_LEVEL; ++ for (i = MLXREG_FAN_SPEED_MIN_LEVEL; i <= MLXREG_FAN_MAX_STATE; i++) ++ fan->cooling_levels[i] = i; ++ ++ return 0; ++} ++ ++static int mlxreg_fan_probe(struct platform_device *pdev) ++{ ++ struct mlxreg_core_platform_data *pdata; ++ struct mlxreg_fan *fan; ++ struct device *hwm; ++ int err; ++ ++ pdata = dev_get_platdata(&pdev->dev); ++ if (!pdata) { ++ dev_err(&pdev->dev, "Failed to get platform data.\n"); ++ return -EINVAL; ++ } ++ ++ fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); ++ if (!fan) ++ return -ENOMEM; ++ ++ fan->dev = &pdev->dev; ++ fan->regmap = pdata->regmap; ++ platform_set_drvdata(pdev, fan); ++ ++ err = mlxreg_fan_config(fan, pdata); ++ if (err) ++ return err; ++ ++ hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", ++ fan, ++ &mlxreg_fan_hwmon_chip_info, ++ NULL); ++ if (IS_ERR(hwm)) { ++ dev_err(&pdev->dev, "Failed to register hwmon device\n"); ++ return PTR_ERR(hwm); ++ } ++ ++ if (IS_REACHABLE(CONFIG_THERMAL)) { ++ fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, ++ &mlxreg_fan_cooling_ops); ++ if (IS_ERR(fan->cdev)) { ++ dev_err(&pdev->dev, "Failed to register cooling device\n"); ++ return PTR_ERR(fan->cdev); ++ } ++ } ++ ++ return 0; ++} ++ ++static int mlxreg_fan_remove(struct platform_device *pdev) ++{ ++ struct mlxreg_fan *fan = platform_get_drvdata(pdev); ++ ++ if (IS_REACHABLE(CONFIG_THERMAL)) ++ thermal_cooling_device_unregister(fan->cdev); ++ ++ return 0; ++} ++ ++static struct platform_driver mlxreg_fan_driver = { ++ .driver = { ++ .name = "mlxreg-fan", ++ }, ++ .probe = mlxreg_fan_probe, ++ .remove = mlxreg_fan_remove, ++}; ++ ++module_platform_driver(mlxreg_fan_driver); ++ ++MODULE_AUTHOR("Vadim Pasternak "); ++MODULE_DESCRIPTION("Mellanox FAN driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:mlxreg-fan"); +diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig +index 5c6dc29..cd8a908 100644 +--- a/drivers/platform/mellanox/Kconfig ++++ b/drivers/platform/mellanox/Kconfig +@@ -1,3 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 + # + # Platform support for Mellanox hardware + # +@@ -23,13 +24,13 @@ config MLXREG_HOTPLUG + cables and fans on the wide range Mellanox IB and Ethernet systems. + + config MLXREG_IO +- tristate "Mellanox platform register driver support" ++ tristate "Mellanox platform register access driver support" + depends on REGMAP + depends on HWMON +- ---help--- ++ help + This driver allows access to Mellanox programmable device register +- space trough sysfs interface. The set of registers for sysfs access +- are defined per system type bases and includes the registers related ++ space through sysfs interface. The sets of registers for sysfs access ++ are defined per system type bases and include the registers related + to system resets operation, system reset causes monitoring and some + kinds of mux selection. + +diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile +index b9a2692..57074d9c 100644 +--- a/drivers/platform/mellanox/Makefile ++++ b/drivers/platform/mellanox/Makefile +@@ -1,2 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for linux/drivers/platform/mellanox ++# Mellanox Platform-Specific Drivers ++# + obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o +-obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o ++obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o +diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c +index 5c13591..4761211 100644 +--- a/drivers/platform/mellanox/mlxreg-hotplug.c ++++ b/drivers/platform/mellanox/mlxreg-hotplug.c +@@ -1,6 +1,6 @@ + /* +- * Copyright (c) 2017 Mellanox Technologies. All rights reserved. +- * Copyright (c) 2017 Vadim Pasternak ++ * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved. ++ * Copyright (c) 2016-2018 Vadim Pasternak + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -50,12 +51,9 @@ + #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 + + /* ASIC health parameters. */ ++#define MLXREG_HOTPLUG_DOWN_MASK 0x00 + #define MLXREG_HOTPLUG_HEALTH_MASK 0x02 +-#define MLXREG_HOTPLUG_RST_CNTR 3 +- +-#define MLXREG_HOTPLUG_PROP_OKAY "okay" +-#define MLXREG_HOTPLUG_PROP_DISABLED "disabled" +-#define MLXREG_HOTPLUG_PROP_STATUS "status" ++#define MLXREG_HOTPLUG_RST_CNTR 2 + + #define MLXREG_HOTPLUG_ATTRS_MAX 24 + #define MLXREG_HOTPLUG_NOT_ASSERT 3 +@@ -63,11 +61,14 @@ + /** + * struct mlxreg_hotplug_priv_data - platform private data: + * @irq: platform device interrupt number; ++ * @dev: basic device; + * @pdev: platform device; + * @plat: platform data; +- * @dwork: delayed work template; ++ * @regmap: register map handle; ++ * @dwork_irq: delayed work template; + * @lock: spin lock; + * @hwmon: hwmon device; ++ * @kobj: hwmon kobject for notification; + * @mlxreg_hotplug_attr: sysfs attributes array; + * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array; + * @group: sysfs attribute group; +@@ -75,6 +76,7 @@ + * @cell: location of top aggregation interrupt register; + * @mask: top aggregation interrupt common mask; + * @aggr_cache: last value of aggregation register status; ++ * @after_probe: flag indication probing completion; + * @not_asserted: number of entries in workqueue with no signal assertion; + */ + struct mlxreg_hotplug_priv_data { +@@ -84,9 +86,9 @@ struct mlxreg_hotplug_priv_data { + struct mlxreg_hotplug_platform_data *plat; + struct regmap *regmap; + struct delayed_work dwork_irq; +- struct delayed_work dwork; + spinlock_t lock; /* sync with interrupt */ + struct device *hwmon; ++ struct kobject *kobj; + struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1]; + struct sensor_device_attribute_2 + mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX]; +@@ -99,70 +101,37 @@ struct mlxreg_hotplug_priv_data { + u8 not_asserted; + }; + +-#if defined(CONFIG_OF_DYNAMIC) +-/** +- * struct mlxreg_hotplug_device_en - Open Firmware property for enabling device +- * +- * @name - property name; +- * @value - property value string; +- * @length - length of proprty value string; +- * +- * The structure is used for the devices, which require some dynamic +- * selection operation allowing access to them. +- */ +-static struct property mlxreg_hotplug_device_en = { +- .name = MLXREG_HOTPLUG_PROP_STATUS, +- .value = MLXREG_HOTPLUG_PROP_OKAY, +- .length = sizeof(MLXREG_HOTPLUG_PROP_OKAY), +-}; +- +-/** +- * struct mlxreg_hotplug_device_dis - Open Firmware property for disabling +- * device +- * +- * @name - property name; +- * @value - property value string; +- * @length - length of proprty value string; +- * +- * The structure is used for the devices, which require some dynamic +- * selection operation disallowing access to them. +- */ +-static struct property mlxreg_hotplug_device_dis = { +- .name = MLXREG_HOTPLUG_PROP_STATUS, +- .value = MLXREG_HOTPLUG_PROP_DISABLED, +- .length = sizeof(MLXREG_HOTPLUG_PROP_DISABLED), +-}; +- +-static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data) ++static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, ++ struct mlxreg_core_data *data) + { +- return of_update_property(data->np, &mlxreg_hotplug_device_en); +-} ++ struct mlxreg_core_hotplug_platform_data *pdata; + +-static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data) +-{ +- of_update_property(data->np, &mlxreg_hotplug_device_dis); +- of_node_clear_flag(data->np, OF_POPULATED); +-} +-#else +-static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data) +-{ +- return 0; +-} ++ /* Notify user by sending hwmon uevent. */ ++ kobject_uevent(priv->kobj, KOBJ_CHANGE); + +-static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data) +-{ +-} +-#endif ++ /* ++ * Return if adapter number is negative. It could be in case hotplug ++ * event is not associated with hotplug device. ++ */ ++ if (data->hpdev.nr < 0) ++ return 0; + +-static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data) +-{ +- data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); +- if (!data->hpdev.adapter) ++ pdata = dev_get_platdata(&priv->pdev->dev); ++ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + ++ pdata->shift_nr); ++ if (!data->hpdev.adapter) { ++ dev_err(priv->dev, "Failed to get adapter for bus %d\n", ++ data->hpdev.nr + pdata->shift_nr); + return -EFAULT; ++ } + + data->hpdev.client = i2c_new_device(data->hpdev.adapter, + data->hpdev.brdinfo); + if (!data->hpdev.client) { ++ dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", ++ data->hpdev.brdinfo->type, data->hpdev.nr + ++ pdata->shift_nr, data->hpdev.brdinfo->addr); ++ + i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; + return -EFAULT; +@@ -171,8 +140,13 @@ static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data) + return 0; + } + +-static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) ++static void ++mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv, ++ struct mlxreg_core_data *data) + { ++ /* Notify user by sending hwmon uevent. */ ++ kobject_uevent(priv->kobj, KOBJ_CHANGE); ++ + if (data->hpdev.client) { + i2c_unregister_device(data->hpdev.client); + data->hpdev.client = NULL; +@@ -184,28 +158,6 @@ static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) + } + } + +-static int mlxreg_hotplug_dev_enable(struct mlxreg_core_data *data) +-{ +- int err; +- +- /* Enable and create device. */ +- if (data->np) +- err = mlxreg_hotplug_of_device_create(data); +- else +- err = mlxreg_hotplug_device_create(data); +- +- return err; +-} +- +-static void mlxreg_hotplug_dev_disable(struct mlxreg_core_data *data) +-{ +- /* Disable and unregister platform device. */ +- if (data->np) +- mlxreg_hotplug_of_device_destroy(data); +- else +- mlxreg_hotplug_device_destroy(data); +-} +- + static ssize_t mlxreg_hotplug_attr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +@@ -281,7 +233,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) + } + } + +- priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * ++ priv->group.attrs = devm_kcalloc(&priv->pdev->dev, ++ num_attrs, + sizeof(struct attribute *), + GFP_KERNEL); + if (!priv->group.attrs) +@@ -320,12 +273,12 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, + 0); + if (ret) +- goto access_error; ++ goto out; + + /* Read status. */ + ret = regmap_read(priv->regmap, item->reg, ®val); + if (ret) +- goto access_error; ++ goto out; + + /* Set asserted bits and save last status. */ + regval &= item->mask; +@@ -336,14 +289,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, + data = item->data + bit; + if (regval & BIT(bit)) { + if (item->inversed) +- mlxreg_hotplug_dev_disable(data); ++ mlxreg_hotplug_device_destroy(priv, data); + else +- mlxreg_hotplug_dev_enable(data); ++ mlxreg_hotplug_device_create(priv, data); + } else { + if (item->inversed) +- mlxreg_hotplug_dev_enable(data); ++ mlxreg_hotplug_device_create(priv, data); + else +- mlxreg_hotplug_dev_disable(data); ++ mlxreg_hotplug_device_destroy(priv, data); + } + } + +@@ -351,18 +304,15 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, + 0); + if (ret) +- goto access_error; ++ goto out; + + /* Unmask event. */ + ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, + item->mask); +- if (ret) +- goto access_error; + +- return; +- +-access_error: +- dev_err(priv->dev, "Failed to complete workqueue.\n"); ++ out: ++ if (ret) ++ dev_err(priv->dev, "Failed to complete workqueue.\n"); + } + + static void +@@ -371,53 +321,83 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, + { + struct mlxreg_core_data *data = item->data; + u32 regval; +- int i, ret; ++ int i, ret = 0; + + for (i = 0; i < item->count; i++, data++) { + /* Mask event. */ + ret = regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_MASK_OFF, 0); + if (ret) +- goto access_error; ++ goto out; + + /* Read status. */ + ret = regmap_read(priv->regmap, data->reg, ®val); + if (ret) +- goto access_error; ++ goto out; + + regval &= data->mask; +- item->cache = regval; ++ /* ++ * ASIC health indication is provided through two bits. Bits ++ * value 0x2 indicates that ASIC reached the good health, value ++ * 0x0 indicates ASIC the bad health or dormant state and value ++ * 0x2 indicates the booting state. During ASIC reset it should ++ * pass the following states: dormant -> booting -> good. ++ * The transition from dormant to booting state and from ++ * booting to good state are indicated by ASIC twice, so actual ++ * sequence for getting to the steady state after reset is: ++ * dormant -> booting -> booting -> good -> good. It is ++ * possible that due to some hardware noise, the transition ++ * sequence will look like: dormant -> booting -> [ booting -> ++ * good -> dormant -> booting ] -> good -> good. ++ */ + if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { +- if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || ++ if ((++data->health_cntr == MLXREG_HOTPLUG_RST_CNTR) || + !priv->after_probe) { +- mlxreg_hotplug_dev_enable(data); ++ /* ++ * ASIC is in steady state. Connect associated ++ * device, if configured. ++ */ ++ mlxreg_hotplug_device_create(priv, data); + data->attached = true; + } + } else { + if (data->attached) { +- mlxreg_hotplug_dev_disable(data); ++ /* ++ * ASIC health is dropped after ASIC has been ++ * in steady state. Disconnect associated ++ * device, if it has been connected. ++ */ ++ mlxreg_hotplug_device_destroy(priv, data); + data->attached = false; + data->health_cntr = 0; ++ } else if (regval == MLXREG_HOTPLUG_DOWN_MASK && ++ item->cache == MLXREG_HOTPLUG_HEALTH_MASK) { ++ /* ++ * Decrease counter, if health has been dropped ++ * before ASIC reaches the steady state, like: ++ * good -> dormant -> booting. ++ */ ++ data->health_cntr--; + } + } ++ item->cache = regval; + + /* Acknowledge event. */ + ret = regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_EVENT_OFF, 0); + if (ret) +- goto access_error; ++ goto out; + + /* Unmask event. */ + ret = regmap_write(priv->regmap, data->reg + + MLXREG_HOTPLUG_MASK_OFF, data->mask); + if (ret) +- goto access_error; ++ goto out; + } + +- return; +- +-access_error: +- dev_err(priv->dev, "Failed to complete workqueue.\n"); ++ out: ++ if (ret) ++ dev_err(priv->dev, "Failed to complete workqueue.\n"); + } + + /* +@@ -449,32 +429,38 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, + */ + static void mlxreg_hotplug_work_handler(struct work_struct *work) + { +- struct mlxreg_hotplug_priv_data *priv = container_of(work, +- struct mlxreg_hotplug_priv_data, dwork_irq.work); + struct mlxreg_core_hotplug_platform_data *pdata; ++ struct mlxreg_hotplug_priv_data *priv; + struct mlxreg_core_item *item; +- unsigned long flags; + u32 regval, aggr_asserted; +- int i; +- int ret; ++ unsigned long flags; ++ int i, ret; + ++ priv = container_of(work, struct mlxreg_hotplug_priv_data, ++ dwork_irq.work); + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; ++ + /* Mask aggregation event. */ + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, 0); + if (ret < 0) +- goto access_error; ++ goto out; + + /* Read aggregation status. */ + ret = regmap_read(priv->regmap, pdata->cell, ®val); + if (ret) +- goto access_error; ++ goto out; + + regval &= pdata->mask; + aggr_asserted = priv->aggr_cache ^ regval; + priv->aggr_cache = regval; + ++ /* ++ * Handler is invoked, but no assertion is detected at top aggregation ++ * status level. Set aggr_asserted to mask value to allow handler extra ++ * run over all relevant signals to recover any missed signal. ++ */ + if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { + priv->not_asserted = 0; + aggr_asserted = pdata->mask; +@@ -492,47 +478,40 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) + } + } + +- if (aggr_asserted) { +- spin_lock_irqsave(&priv->lock, flags); ++ spin_lock_irqsave(&priv->lock, flags); + +- /* +- * It is possible, that some signals have been inserted, while +- * interrupt has been masked by mlxreg_hotplug_work_handler. +- * In this case such signals will be missed. In order to handle +- * these signals delayed work is canceled and work task +- * re-scheduled for immediate execution. It allows to handle +- * missed signals, if any. In other case work handler just +- * validates that no new signals have been received during +- * masking. +- */ +- cancel_delayed_work(&priv->dwork_irq); +- schedule_delayed_work(&priv->dwork_irq, 0); ++ /* ++ * It is possible, that some signals have been inserted, while ++ * interrupt has been masked by mlxreg_hotplug_work_handler. In this ++ * case such signals will be missed. In order to handle these signals ++ * delayed work is canceled and work task re-scheduled for immediate ++ * execution. It allows to handle missed signals, if any. In other case ++ * work handler just validates that no new signals have been received ++ * during masking. ++ */ ++ cancel_delayed_work(&priv->dwork_irq); ++ schedule_delayed_work(&priv->dwork_irq, 0); + +- spin_unlock_irqrestore(&priv->lock, flags); ++ spin_unlock_irqrestore(&priv->lock, flags); + +- return; +- } ++ return; + + unmask_event: + priv->not_asserted++; + /* Unmask aggregation event (no need acknowledge). */ + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); +- if (ret) +- goto access_error; + +- return; +- +-access_error: +- dev_err(priv->dev, "Failed to complete workqueue.\n"); ++ out: ++ if (ret) ++ dev_err(priv->dev, "Failed to complete workqueue.\n"); + } + + static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) + { + struct mlxreg_core_hotplug_platform_data *pdata; + struct mlxreg_core_item *item; +- int i; +- int ret; ++ int i, ret; + + pdata = dev_get_platdata(&priv->pdev->dev); + item = pdata->items; +@@ -542,7 +521,7 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) + ret = regmap_write(priv->regmap, item->reg + + MLXREG_HOTPLUG_EVENT_OFF, 0); + if (ret) +- goto access_error; ++ goto out; + + /* Set group initial status as mask and unmask group event. */ + if (item->inversed) { +@@ -551,7 +530,7 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) + MLXREG_HOTPLUG_MASK_OFF, + item->mask); + if (ret) +- goto access_error; ++ goto out; + } + } + +@@ -559,7 +538,7 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) + ret = regmap_write(priv->regmap, pdata->cell + + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); + if (ret) +- goto access_error; ++ goto out; + + /* Keep low aggregation initial status as zero and unmask events. */ + if (pdata->cell_low) { +@@ -567,21 +546,16 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv) + MLXREG_HOTPLUG_AGGR_MASK_OFF, + pdata->mask_low); + if (ret) +- goto access_error; ++ goto out; + } + + /* Invoke work handler for initializing hot plug devices setting. */ + mlxreg_hotplug_work_handler(&priv->dwork_irq.work); + ++ out: ++ if (ret) ++ dev_err(priv->dev, "Failed to set interrupts.\n"); + enable_irq(priv->irq); +- +- return 0; +- +-access_error: +- dev_err(priv->dev, "Failed to set interrupts.\n"); +- +- enable_irq(priv->irq); +- + return ret; + } + +@@ -619,14 +593,15 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) + /* Remove all the attached devices in group. */ + count = item->count; + for (j = 0; j < count; j++, data++) +- mlxreg_hotplug_dev_disable(data); ++ mlxreg_hotplug_device_destroy(priv, data); + } + } + + static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) + { +- struct mlxreg_hotplug_priv_data *priv = +- (struct mlxreg_hotplug_priv_data *)dev; ++ struct mlxreg_hotplug_priv_data *priv; ++ ++ priv = (struct mlxreg_hotplug_priv_data *)dev; + + /* Schedule work task for immediate execution.*/ + schedule_delayed_work(&priv->dwork_irq, 0); +@@ -683,10 +658,6 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) + disable_irq(priv->irq); + spin_lock_init(&priv->lock); + INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); +- /* Perform initial interrupts setup. */ +- mlxreg_hotplug_set_irq(priv); +- +- priv->after_probe = true; + dev_set_drvdata(&pdev->dev, priv); + + err = mlxreg_hotplug_attr_init(priv); +@@ -703,6 +674,11 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) + PTR_ERR(priv->hwmon)); + return PTR_ERR(priv->hwmon); + } ++ priv->kobj = &priv->hwmon->kobj; ++ ++ /* Perform initial interrupts setup. */ ++ mlxreg_hotplug_set_irq(priv); ++ priv->after_probe = true; + + return 0; + } +diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c +index f7434ca..c192dfe 100644 +--- a/drivers/platform/mellanox/mlxreg-io.c ++++ b/drivers/platform/mellanox/mlxreg-io.c +@@ -1,3 +1,11 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Mellanox register access driver ++ * ++ * Copyright (C) 2018 Mellanox Technologies ++ * Copyright (C) 2018 Vadim Pasternak ++ */ ++ + #include + #include + #include +@@ -33,6 +41,54 @@ struct mlxreg_io_priv_data { + const struct attribute_group *groups[2]; + }; + ++static int ++mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val, ++ bool rw_flag, u32 *regval) ++{ ++ int ret; ++ ++ ret = regmap_read(regmap, data->reg, regval); ++ if (ret) ++ goto access_error; ++ ++ /* ++ * There are three kinds of attributes: single bit, full register's ++ * bits and bit sequence. For the first kind field mask indicates which ++ * bits are not related and field bit is set zero. For the second kind ++ * field mask is set to zero and field bit is set with all bits one. ++ * No special handling for such kind of attributes - pass value as is. ++ * For the third kind, field mask indicates which bits are related and ++ * field bit is set to the first bit number (from 1 to 32) is the bit ++ * sequence. ++ */ ++ if (!data->bit) { ++ /* Single bit. */ ++ if (rw_flag) { ++ /* For show: expose effective bit value as 0 or 1. */ ++ *regval = !!(*regval & ~data->mask); ++ } else { ++ /* For store: set effective bit value. */ ++ *regval &= data->mask; ++ if (in_val) ++ *regval |= ~data->mask; ++ } ++ } else if (data->mask) { ++ /* Bit sequence. */ ++ if (rw_flag) { ++ /* For show: mask and shift right. */ ++ *regval = ror32(*regval & data->mask, (data->bit - 1)); ++ } else { ++ /* For store: shift to the position and mask. */ ++ in_val = rol32(in_val, data->bit - 1) & data->mask; ++ /* Clear relevant bits and set them to new value. */ ++ *regval = (*regval & ~data->mask) | in_val; ++ } ++ } ++ ++access_error: ++ return ret; ++} ++ + static ssize_t + mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, + char *buf) +@@ -43,13 +99,10 @@ mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, + u32 regval = 0; + int ret; + +- ret = regmap_read(priv->pdata->regmap, data->reg, ®val); ++ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, ®val); + if (ret) + goto access_error; + +- if (!data->bit) +- regval = !!(regval & ~data->mask); +- + return sprintf(buf, "%u\n", regval); + + access_error: +@@ -63,25 +116,22 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, + struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + struct mlxreg_core_data *data = priv->pdata->data + index; +- u32 val, regval; ++ u32 input_val, regval; + int ret; + +- ret = kstrtou32(buf, MLXREG_IO_ATT_SIZE, &val); ++ if (len > MLXREG_IO_ATT_SIZE) ++ return -EINVAL; ++ ++ /* Convert buffer to input value. */ ++ ret = kstrtou32(buf, len, &input_val); + if (ret) + return ret; + +- ret = regmap_read(priv->pdata->regmap, data->reg, ®val); ++ ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false, ++ ®val); + if (ret) + goto access_error; + +- regval &= data->mask; +- +- val = !!val; +- if (val) +- regval |= ~data->mask; +- else +- regval &= data->mask; +- + ret = regmap_write(priv->pdata->regmap, data->reg, regval); + if (ret) + goto access_error; +@@ -93,6 +143,11 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, + return ret; + } + ++static struct device_attribute mlxreg_io_devattr_rw = { ++ .show = mlxreg_io_attr_show, ++ .store = mlxreg_io_attr_store, ++}; ++ + static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) + { + int i; +@@ -107,6 +162,8 @@ static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) + for (i = 0; i < priv->pdata->counter; i++) { + priv->mlxreg_io_attr[i] = + &priv->mlxreg_io_dev_attr[i].dev_attr.attr; ++ memcpy(&priv->mlxreg_io_dev_attr[i].dev_attr, ++ &mlxreg_io_devattr_rw, sizeof(struct device_attribute)); + + /* Set attribute name as a label. */ + priv->mlxreg_io_attr[i]->name = +@@ -121,31 +178,6 @@ static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) + + priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode = + priv->pdata->data[i].mode; +- switch (priv->pdata->data[i].mode) { +- case 0200: +- priv->mlxreg_io_dev_attr[i].dev_attr.store = +- mlxreg_io_attr_store; +- break; +- +- case 0444: +- priv->mlxreg_io_dev_attr[i].dev_attr.show = +- mlxreg_io_attr_show; +- break; +- +- case 0644: +- priv->mlxreg_io_dev_attr[i].dev_attr.show = +- mlxreg_io_attr_show; +- priv->mlxreg_io_dev_attr[i].dev_attr.store = +- mlxreg_io_attr_store; +- break; +- +- default: +- dev_err(&priv->pdev->dev, "Bad access mode %u for attribute %s.\n", +- priv->pdata->data[i].mode, +- priv->mlxreg_io_attr[i]->name); +- return -EINVAL; +- } +- + priv->mlxreg_io_dev_attr[i].dev_attr.attr.name = + priv->mlxreg_io_attr[i]->name; + priv->mlxreg_io_dev_attr[i].index = i; +@@ -184,7 +216,9 @@ static int mlxreg_io_probe(struct platform_device *pdev) + } + + priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, +- "mlxreg_io", priv, priv->groups); ++ "mlxreg_io", ++ priv, ++ priv->groups); + if (IS_ERR(priv->hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", + PTR_ERR(priv->hwmon)); +@@ -207,5 +241,5 @@ module_platform_driver(mlxreg_io_driver); + + MODULE_AUTHOR("Vadim Pasternak "); + MODULE_DESCRIPTION("Mellanox regmap I/O access driver"); +-MODULE_LICENSE("Dual BSD/GPL"); ++MODULE_LICENSE("GPL"); + MODULE_ALIAS("platform:mlxreg-io"); +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index e03f03f..e1f9fce 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -47,34 +47,52 @@ + /* LPC bus IO offsets */ + #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 + #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 +-#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF 0x00 +-#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF 0x01 +-#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF 0x1d +-#define MLXPLAT_CPLD_LPC_REG_LED1_OFF 0x20 +-#define MLXPLAT_CPLD_LPC_REG_LED2_OFF 0x21 +-#define MLXPLAT_CPLD_LPC_REG_LED3_OFF 0x22 +-#define MLXPLAT_CPLD_LPC_REG_LED4_OFF 0x23 +-#define MLXPLAT_CPLD_LPC_REG_LED5_OFF 0x24 +-#define MLXPLAT_CPLD_LPC_REG_GP1_OFF 0x30 +-#define MLXPLAT_CPLD_LPC_REG_WP1_OFF 0x31 +-#define MLXPLAT_CPLD_LPC_REG_GP2_OFF 0x32 +-#define MLXPLAT_CPLD_LPC_REG_WP2_OFF 0x33 +-#define MLXPLAT_CPLD_LPC_REG_AGGR_OFF 0x3a +-#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF 0x3b +-#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF 0x40 +-#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF 0x41 +-#define MLXPLAT_CPLD_LPC_REG_PSU_OFF 0x58 +-#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF 0x59 +-#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF 0x5a +-#define MLXPLAT_CPLD_LPC_REG_PWR_OFF 0x64 +-#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF 0x65 +-#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF 0x66 +-#define MLXPLAT_CPLD_LPC_REG_FAN_OFF 0x88 +-#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF 0x89 +-#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF 0x8a ++#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 ++#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 ++#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d ++#define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 ++#define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 ++#define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 ++#define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 ++#define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 ++#define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 ++#define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 ++#define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 ++#define MLXPLAT_CPLD_LPC_REG_WP2_OFFSET 0x33 ++#define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 ++#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a ++#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b ++#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 ++#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 ++#define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 ++#define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 ++#define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 ++#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 ++#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 ++#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a ++#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64 ++#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET 0x65 ++#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET 0x66 ++#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 ++#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 ++#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a ++#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 ++#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 ++#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 ++#define MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET 0xe6 ++#define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET 0xe7 ++#define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET 0xe8 ++#define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET 0xe9 ++#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xea ++#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xeb ++#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xec ++#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xed ++#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xee ++#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xef + #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 + #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb + #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda ++ + #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL + #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ + MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ +@@ -84,17 +102,20 @@ + MLXPLAT_CPLD_LPC_PIO_OFFSET) + + /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ ++#define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 + #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 + #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 + #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 +-#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ ++#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ ++ MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ + MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) ++#define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 + #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 +-#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 +-#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 ++#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 + #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) ++#define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) + #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) + #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) +@@ -119,6 +140,10 @@ + #define MLXPLAT_CPLD_NR_NONE -1 + #define MLXPLAT_CPLD_PSU_DEFAULT_NR 10 + #define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4 ++#define MLXPLAT_CPLD_FAN1_DEFAULT_NR 11 ++#define MLXPLAT_CPLD_FAN2_DEFAULT_NR 12 ++#define MLXPLAT_CPLD_FAN3_DEFAULT_NR 13 ++#define MLXPLAT_CPLD_FAN4_DEFAULT_NR 14 + + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device +@@ -126,6 +151,7 @@ + * @pdev_hotplug - hotplug platform devices + * @pdev_led - led platform devices + * @pdev_io_regs - register access platform devices ++ * @pdev_fan - FAN platform devices + */ + struct mlxplat_priv { + struct platform_device *pdev_i2c; +@@ -133,6 +159,7 @@ struct mlxplat_priv { + struct platform_device *pdev_hotplug; + struct platform_device *pdev_led; + struct platform_device *pdev_io_regs; ++ struct platform_device *pdev_fan; + }; + + /* Regions for LPC I2C controller and LPC base register space */ +@@ -194,6 +221,15 @@ static struct i2c_board_info mlxplat_mlxcpld_psu[] = { + }, + }; + ++static struct i2c_board_info mlxplat_mlxcpld_ng_psu[] = { ++ { ++ I2C_BOARD_INFO("24c32", 0x51), ++ }, ++ { ++ I2C_BOARD_INFO("24c32", 0x50), ++ }, ++}; ++ + static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { + { + I2C_BOARD_INFO("dps460", 0x59), +@@ -222,14 +258,14 @@ static struct i2c_board_info mlxplat_mlxcpld_fan[] = { + static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { + { + .label = "psu1", +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, + }, + { + .label = "psu2", +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, +@@ -239,14 +275,14 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = { + static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { + { + .label = "pwr1", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, + }, + { + .label = "pwr2", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, +@@ -256,31 +292,40 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = { + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { + { + .label = "fan1", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0], +- .hpdev.nr = 11, ++ .hpdev.nr = MLXPLAT_CPLD_FAN1_DEFAULT_NR, + }, + { + .label = "fan2", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1], +- .hpdev.nr = 12, ++ .hpdev.nr = MLXPLAT_CPLD_FAN2_DEFAULT_NR, + }, + { + .label = "fan3", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(2), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2], +- .hpdev.nr = 13, ++ .hpdev.nr = MLXPLAT_CPLD_FAN3_DEFAULT_NR, + }, + { + .label = "fan4", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(3), + .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3], +- .hpdev.nr = 14, ++ .hpdev.nr = MLXPLAT_CPLD_FAN4_DEFAULT_NR, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_asic_items_data[] = { ++ { ++ .label = "asic1", ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + }; + +@@ -288,7 +333,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { + { + .data = mlxplat_mlxcpld_default_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), + .inversed = 1, +@@ -297,7 +342,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { + { + .data = mlxplat_mlxcpld_default_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), + .inversed = 0, +@@ -306,127 +351,92 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { + { + .data = mlxplat_mlxcpld_default_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_fan), + .inversed = 1, + .health = false, + }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, + }; + + static + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { + .items = mlxplat_mlxcpld_default_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), +- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, +-}; +- +-/* Platform hotplug MSN21xx system family data */ +-static struct i2c_board_info mlxplat_mlxcpld_msn21xx_pwr[] = { +- { +- I2C_BOARD_INFO("holder", 0x59), +- }, +- { +- I2C_BOARD_INFO("holder", 0x58), +- }, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + + static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { + { + .label = "pwr1", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), +- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[0], +- .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "pwr2", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), +- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[1], +- .hpdev.nr = MLXPLAT_CPLD_PSU_DEFAULT_NR, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + }; + ++/* Platform hotplug MSN21xx system family data */ + static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { + { + .data = mlxplat_mlxcpld_msn21xx_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_pwr_items_data), + .inversed = 0, + .health = false, + }, +-}; +- +-static +-struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { +- .items = mlxplat_mlxcpld_msn21xx_items, +- .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), +- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, +- .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, +- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, +- .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, +-}; +- +-/* Platform hotplug MSN201x system family data */ +-static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { +- { +- .label = "pwr1", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, +- .mask = BIT(0), +- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[0], +- .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, +- }, +- { +- .label = "pwr2", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, +- .mask = BIT(1), +- .hpdev.brdinfo = &mlxplat_mlxcpld_msn21xx_pwr[1], +- .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, +- }, +-}; +- +-static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { + { +- .data = mlxplat_mlxcpld_msn201x_pwr_items_data, +- .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, +- .mask = MLXPLAT_CPLD_PWR_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, +- .health = false, ++ .health = true, + }, + }; + + static +-struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { + .items = mlxplat_mlxcpld_msn21xx_items, +- .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), +- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, +- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + +-/* Platform hotplug next generation system family data */ +-static struct i2c_board_info mlxplat_mlxcpld_ng_fan = { +- I2C_BOARD_INFO("holder", 0x50), +-}; +- +-static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { ++/* Platform hotplug msn274x system family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_psu_items_data[] = { + { + .label = "psu1", +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + { + .label = "psu2", +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, +@@ -436,173 +446,246 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { + static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_pwr_items_data[] = { + { + .label = "pwr1", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + { + .label = "pwr2", +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + }; + +-static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { ++static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { + { + .label = "fan1", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(0), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 11, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "fan2", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(1), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 12, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "fan3", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(2), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 13, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "fan4", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(3), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 14, +- }, +- { +- .label = "fan5", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, +- .mask = BIT(4), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 15, +- }, +- { +- .label = "fan6", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, +- .mask = BIT(5), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 16, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + }; + +-static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { ++static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { + { +- .data = mlxplat_mlxcpld_default_ng_psu_items_data, ++ .data = mlxplat_mlxcpld_msn274x_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_psu_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_ng_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), + .inversed = 0, + .health = false, + }, + { +- .data = mlxplat_mlxcpld_default_ng_fan_items_data, ++ .data = mlxplat_mlxcpld_msn274x_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data), + .inversed = 1, + .health = false, + }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, + }; + + static +-struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { +- .items = mlxplat_mlxcpld_default_ng_items, +- .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), +- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { ++ .items = mlxplat_mlxcpld_msn274x_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + +-static struct mlxreg_core_data mlxplat_mlxcpld_msn274x_fan_items_data[] = { ++/* Platform hotplug MSN201x system family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_msn201x_pwr_items_data[] = { ++ { ++ .label = "pwr1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "pwr2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { ++ { ++ .data = mlxplat_mlxcpld_msn201x_pwr_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_pwr_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, ++}; ++ ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn201x_data = { ++ .items = mlxplat_mlxcpld_msn21xx_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn201x_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, ++}; ++ ++/* Platform hotplug next generation system family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_psu_items_data[] = { ++ { ++ .label = "psu1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(0), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[0], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++ { ++ .label = "psu2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = BIT(1), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_ng_psu[1], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = { + { + .label = "fan1", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(0), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 11, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "fan2", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(1), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 12, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "fan3", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(2), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 13, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "fan4", +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = BIT(3), +- .hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan, +- .hpdev.nr = 14, ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan5", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(4), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "fan6", ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = BIT(5), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + }; + +-static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { ++static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { + { + .data = mlxplat_mlxcpld_default_ng_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_psu), ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_ng_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_pwr_items_data), + .inversed = 0, + .health = false, + }, + { +- .data = mlxplat_mlxcpld_msn274x_fan_items_data, ++ .data = mlxplat_mlxcpld_default_ng_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF, +- .mask = MLXPLAT_CPLD_FAN_MASK, +- .count = ARRAY_SIZE(mlxplat_mlxcpld_msn274x_fan_items_data), ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_NG_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), + .inversed = 1, + .health = false, + }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, + }; + + static +-struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { +- .items = mlxplat_mlxcpld_msn274x_items, ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_ng_data = { ++ .items = mlxplat_mlxcpld_default_ng_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_items), +- .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFF, ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, +- .cell_low = MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + +@@ -610,62 +693,62 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn274x_data = { + static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { + { + .label = "status:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "psu:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan1:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan1:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan2:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan2:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan3:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan3:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan4:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan4:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + }; +@@ -679,47 +762,47 @@ static struct mlxreg_core_platform_data mlxplat_default_led_data = { + static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { + { + .label = "status:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "fan:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "psu1:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "psu1:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "psu2:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu2:red", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "uid:blue", +- .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + }; +@@ -733,82 +816,82 @@ static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = { + static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = { + { + .label = "status:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "psu:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "psu:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan1:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan1:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan2:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan2:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan3:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan3:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan4:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan4:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan5:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan5:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "fan6:green", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + { + .label = "fan6:orange", +- .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFF, ++ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + }, + }; +@@ -818,26 +901,303 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), + }; + ++/* Platform register access default */ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { ++ { ++ .label = "cpld1_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "cpld2_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_long_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_short_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_aux_pwr_or_ref", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_main_pwr_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_sw_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_fw_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_hotswap_or_wd", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_asic_thermal", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, ++ { ++ .label = "psu1_on", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0200, ++ }, ++ { ++ .label = "psu2_on", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0200, ++ }, ++ { ++ .label = "pwr_cycle", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0200, ++ }, ++ { ++ .label = "pwr_down", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0200, ++ }, ++ { ++ .label = "select_iio", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0644, ++ }, ++ { ++ .label = "asic_health", ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .bit = 1, ++ .mode = 0444, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { ++ .data = mlxplat_mlxcpld_default_regs_io_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), ++}; ++ ++/* Platform register access MSN21xx, MSN201x, MSN274x systems families data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { ++ { ++ .label = "cpld1_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "cpld2_version", ++ .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, ++ .bit = GENMASK(7, 0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_long_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_short_pb", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_aux_pwr_or_ref", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_sw_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_main_pwr_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_asic_thermal", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "reset_hotswap_or_halt", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "psu1_on", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0200, ++ }, ++ { ++ .label = "psu2_on", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0200, ++ }, ++ { ++ .label = "pwr_cycle", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(2), ++ .mode = 0200, ++ }, ++ { ++ .label = "pwr_down", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(3), ++ .mode = 0200, ++ }, ++ { ++ .label = "asic_health", ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .bit = 1, ++ .mode = 0444, ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_msn21xx_regs_io_data = { ++ .data = mlxplat_mlxcpld_msn21xx_regs_io_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data), ++}; ++ ++/* Platform FAN default */ ++static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { ++ { ++ .label = "pwm1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, ++ }, ++ { ++ .label = "tacho1", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho2", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho3", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho4", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho5", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho6", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho7", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho8", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho9", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho10", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho11", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++ { ++ .label = "tacho12", ++ .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, ++ .mask = GENMASK(7, 0), ++ }, ++}; ++ ++static struct mlxreg_core_platform_data mlxplat_default_fan_data = { ++ .data = mlxplat_mlxcpld_default_fan_data, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), ++}; ++ + static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +- case MLXPLAT_CPLD_LPC_REG_LED1_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED2_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED3_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED4_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED5_OFF: +- case MLXPLAT_CPLD_LPC_REG_GP1_OFF: +- case MLXPLAT_CPLD_LPC_REG_WP1_OFF: +- case MLXPLAT_CPLD_LPC_REG_GP2_OFF: +- case MLXPLAT_CPLD_LPC_REG_WP2_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: ++ case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: + return true; + } + return false; +@@ -846,31 +1206,48 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +- case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF: +- case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF: +- case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED1_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED2_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED3_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED4_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED5_OFF: +- case MLXPLAT_CPLD_LPC_REG_GP1_OFF: +- case MLXPLAT_CPLD_LPC_REG_WP1_OFF: +- case MLXPLAT_CPLD_LPC_REG_GP2_OFF: +- case MLXPLAT_CPLD_LPC_REG_WP2_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: ++ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: + return true; + } + return false; +@@ -879,54 +1256,82 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +- case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF: +- case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF: +- case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED1_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED2_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED3_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED4_OFF: +- case MLXPLAT_CPLD_LPC_REG_LED5_OFF: +- case MLXPLAT_CPLD_LPC_REG_GP1_OFF: +- case MLXPLAT_CPLD_LPC_REG_GP2_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF: +- case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF: +- case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF: ++ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: + return true; + } + return false; + } + + static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { +- { MLXPLAT_CPLD_LPC_REG_WP1_OFF, 0x00 }, +- { MLXPLAT_CPLD_LPC_REG_WP2_OFF, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, ++}; ++ ++struct mlxplat_mlxcpld_regmap_context { ++ void __iomem *base; + }; + ++static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx; ++ + static int + mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val) + { +- *val = ioread8(context + reg); ++ struct mlxplat_mlxcpld_regmap_context *ctx = context; ++ ++ *val = ioread8(ctx->base + reg); + return 0; + } + + static int + mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val) + { +- iowrite8(val, context + reg); ++ struct mlxplat_mlxcpld_regmap_context *ctx = context; ++ ++ iowrite8(val, ctx->base + reg); + return 0; + } + +-const struct regmap_config mlxplat_mlxcpld_regmap_config = { ++static const struct regmap_config mlxplat_mlxcpld_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 255, +@@ -944,46 +1349,11 @@ static struct resource mlxplat_mlxcpld_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"), + }; + +-static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { +- { "cpld1_version", MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF, 0x00, +- GENMASK(7, 0), 0444 }, +- { "cpld2_version", MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF, 0x00, +- GENMASK(7, 0), 0444 }, +- { "cause_long_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(0), 0x00, 0444 }, +- { "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(1), 0x00, 0444 }, +- { "cause_aux_pwr_or_refresh", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(2), 0x00, 0444 }, +- { "cause_main_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(3), 0x00, 0444 }, +- { "cause_sw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(4), 0x00, 0444 }, +- { "cause_fw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(5), 0x00, 0444 }, +- { "cause_hotswap_or_wd", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(6), 0x00, 0444 }, +- { "cause_asic_thermal", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF, +- GENMASK(7, 0) & ~BIT(7), 0x00, 0444 }, +- { "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0), +- 0x00, 0200 }, +- { "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1), +- 0x00, 0200 }, +- { "pwr_cycle", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(2), +- 0x00, 0200 }, +- { "select_iio", MLXPLAT_CPLD_LPC_REG_GP2_OFF, GENMASK(7, 0) & ~BIT(6), +- 0x00, 0644 }, +-}; +- +-static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { +- .data = mlxplat_mlxcpld_default_regs_io_data, +- .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), +-}; +- + static struct platform_device *mlxplat_dev; + static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; + static struct mlxreg_core_platform_data *mlxplat_led; + static struct mlxreg_core_platform_data *mlxplat_regs_io; ++static struct mlxreg_core_platform_data *mlxplat_fan; + + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) + { +@@ -1016,7 +1386,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; +- mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + + return 1; + }; +@@ -1034,12 +1404,12 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_data; +- mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + + return 1; + }; + +-static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) ++static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + { + int i; + +@@ -1048,16 +1418,16 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_msn21xx_channels); + } +- mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; + mlxplat_hotplug->deferred_nr = + mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_ng_led_data; +- mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; + + return 1; + }; + +-static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) ++static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) + { + int i; + +@@ -1066,11 +1436,11 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_msn21xx_channels); + } +- mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_msn21xx_led_data; +- mlxplat_regs_io = &mlxplat_default_regs_io_data; ++ mlxplat_fan = &mlxplat_default_fan_data; + + return 1; + }; +@@ -1222,8 +1592,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) + static int __init mlxplat_init(void) + { + struct mlxplat_priv *priv; +- void __iomem *base; +- int i, j, nr, err = 0; ++ int i, j, nr, err; + + if (!dmi_check_system(mlxplat_dmi_table)) + return -ENODEV; +@@ -1267,29 +1636,21 @@ static int __init mlxplat_init(void) + } + } + +- base = devm_ioport_map(&mlxplat_dev->dev, ++ mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, + mlxplat_lpc_resources[1].start, 1); +- if (!base) { ++ if (!mlxplat_mlxcpld_regmap_ctx.base) { + err = -ENOMEM; + goto fail_platform_mux_register; + } + + mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, +- base, &mlxplat_mlxcpld_regmap_config); ++ &mlxplat_mlxcpld_regmap_ctx, ++ &mlxplat_mlxcpld_regmap_config); + if (IS_ERR(mlxplat_hotplug->regmap)) { + err = PTR_ERR(mlxplat_hotplug->regmap); + goto fail_platform_mux_register; + } + +- /* Set default registers. */ +- for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { +- err = regmap_write(mlxplat_hotplug->regmap, +- mlxplat_mlxcpld_regmap_default[j].reg, +- mlxplat_mlxcpld_regmap_default[j].def); +- if (err) +- goto fail_platform_mux_register; +- } +- + priv->pdev_hotplug = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-hotplug", + PLATFORM_DEVID_NONE, +@@ -1301,6 +1662,16 @@ static int __init mlxplat_init(void) + goto fail_platform_mux_register; + } + ++ /* Set default registers. */ ++ for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { ++ err = regmap_write(mlxplat_hotplug->regmap, ++ mlxplat_mlxcpld_regmap_default[j].reg, ++ mlxplat_mlxcpld_regmap_default[j].def); ++ if (err) ++ goto fail_platform_mux_register; ++ } ++ ++ /* Add LED driver. */ + mlxplat_led->regmap = mlxplat_hotplug->regmap; + priv->pdev_led = platform_device_register_resndata( + &mlxplat_dev->dev, "leds-mlxreg", +@@ -1311,24 +1682,48 @@ static int __init mlxplat_init(void) + goto fail_platform_hotplug_register; + } + +- mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; +- priv->pdev_io_regs = platform_device_register_resndata( +- &mlxplat_dev->dev, "mlxreg-io", +- PLATFORM_DEVID_NONE, NULL, 0, +- mlxplat_regs_io, sizeof(*mlxplat_regs_io)); +- if (IS_ERR(priv->pdev_io_regs)) { +- err = PTR_ERR(priv->pdev_io_regs); +- goto fail_platform_led_register; ++ /* Add registers io access driver. */ ++ if (mlxplat_regs_io) { ++ mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; ++ priv->pdev_io_regs = platform_device_register_resndata( ++ &mlxplat_dev->dev, "mlxreg-io", ++ PLATFORM_DEVID_NONE, NULL, 0, ++ mlxplat_regs_io, ++ sizeof(*mlxplat_regs_io)); ++ if (IS_ERR(priv->pdev_io_regs)) { ++ err = PTR_ERR(priv->pdev_io_regs); ++ goto fail_platform_led_register; ++ } ++ } ++ ++ /* Add FAN driver. */ ++ if (mlxplat_fan) { ++ mlxplat_fan->regmap = mlxplat_hotplug->regmap; ++ priv->pdev_fan = platform_device_register_resndata( ++ &mlxplat_dev->dev, "mlxreg-fan", ++ PLATFORM_DEVID_NONE, NULL, 0, ++ mlxplat_fan, ++ sizeof(*mlxplat_fan)); ++ if (IS_ERR(priv->pdev_io_regs)) { ++ err = PTR_ERR(priv->pdev_io_regs); ++ goto fail_platform_io_regs_register; ++ } + } + + /* Sync registers with hardware. */ + regcache_mark_dirty(mlxplat_hotplug->regmap); + err = regcache_sync(mlxplat_hotplug->regmap); + if (err) +- goto fail_platform_led_register; ++ goto fail_platform_fan_register; + + return 0; + ++fail_platform_fan_register: ++ if (mlxplat_fan) ++ platform_device_unregister(priv->pdev_fan); ++fail_platform_io_regs_register: ++ if (mlxplat_regs_io) ++ platform_device_unregister(priv->pdev_io_regs); + fail_platform_led_register: + platform_device_unregister(priv->pdev_led); + fail_platform_hotplug_register: +@@ -1349,7 +1744,10 @@ static void __exit mlxplat_exit(void) + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + int i; + +- platform_device_unregister(priv->pdev_io_regs); ++ if (priv->pdev_fan) ++ platform_device_unregister(priv->pdev_fan); ++ if (priv->pdev_io_regs) ++ platform_device_unregister(priv->pdev_io_regs); + platform_device_unregister(priv->pdev_led); + platform_device_unregister(priv->pdev_hotplug); + +-- +2.1.4 + diff --git a/packages/base/any/kernels/4.9-lts/patches/series b/packages/base/any/kernels/4.9-lts/patches/series index 1d79cd29..bcbed8ca 100644 --- a/packages/base/any/kernels/4.9-lts/patches/series +++ b/packages/base/any/kernels/4.9-lts/patches/series @@ -13,3 +13,4 @@ driver-support-intel-igb-bcm5461-phy.patch 0012-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch driver-i2c-i2c-core.patch driver-add-the-support-max6620.patch +0013-Mellanox-backport-patchwork-from-kernels-4.17-4.19.patch From f53b90acac2a13c2430ee5f346140653a80bf2a2 Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Tue, 31 Jul 2018 13:59:16 +0800 Subject: [PATCH 05/22] [as5916-54xk] Add support for OOM --- .../builds/x86-64-accton-as5916-54xk-cpld.c | 1098 ++++++++++++++ .../builds/x86-64-accton-as5916-54xk-leds.c | 8 +- .../builds/x86-64-accton-as5916-54xk-psu.c | 4 +- .../builds/x86-64-accton-as5916-54xk-sfp.c | 1315 ----------------- .../onlp/builds/src/module/src/sfpi.c | 238 +-- .../x86_64_accton_as5916_54xk_r1/__init__.py | 16 +- 6 files changed, 1267 insertions(+), 1412 deletions(-) create mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-cpld.c delete mode 100644 packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-sfp.c diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-cpld.c b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-cpld.c new file mode 100644 index 00000000..0ec59ad4 --- /dev/null +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-cpld.c @@ -0,0 +1,1098 @@ +/* + * Copyright (C) Brandon Chuang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as5916_54xk CPLD1/CPLD2 + * + * 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 + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as5916_54xk_cpld1, + as5916_54xk_cpld2 +}; + +struct as5916_54xk_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; +}; + +static const struct i2c_device_id as5916_54xk_cpld_id[] = { + { "as5916_54xk_cpld1", as5916_54xk_cpld1 }, + { "as5916_54xk_cpld2", as5916_54xk_cpld2 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as5916_54xk_cpld_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index + +enum as5916_54xk_cpld1_sysfs_attributes { + CPLD_VERSION, + ACCESS, + MODULE_PRESENT_ALL, + MODULE_RXLOS_ALL, + /* 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_TXDISABLE_ATTR_ID(1), + TRANSCEIVER_TXDISABLE_ATTR_ID(2), + TRANSCEIVER_TXDISABLE_ATTR_ID(3), + TRANSCEIVER_TXDISABLE_ATTR_ID(4), + TRANSCEIVER_TXDISABLE_ATTR_ID(5), + TRANSCEIVER_TXDISABLE_ATTR_ID(6), + TRANSCEIVER_TXDISABLE_ATTR_ID(7), + TRANSCEIVER_TXDISABLE_ATTR_ID(8), + TRANSCEIVER_TXDISABLE_ATTR_ID(9), + TRANSCEIVER_TXDISABLE_ATTR_ID(10), + TRANSCEIVER_TXDISABLE_ATTR_ID(11), + TRANSCEIVER_TXDISABLE_ATTR_ID(12), + TRANSCEIVER_TXDISABLE_ATTR_ID(13), + TRANSCEIVER_TXDISABLE_ATTR_ID(14), + TRANSCEIVER_TXDISABLE_ATTR_ID(15), + TRANSCEIVER_TXDISABLE_ATTR_ID(16), + TRANSCEIVER_TXDISABLE_ATTR_ID(17), + TRANSCEIVER_TXDISABLE_ATTR_ID(18), + TRANSCEIVER_TXDISABLE_ATTR_ID(19), + TRANSCEIVER_TXDISABLE_ATTR_ID(20), + TRANSCEIVER_TXDISABLE_ATTR_ID(21), + TRANSCEIVER_TXDISABLE_ATTR_ID(22), + TRANSCEIVER_TXDISABLE_ATTR_ID(23), + TRANSCEIVER_TXDISABLE_ATTR_ID(24), + TRANSCEIVER_TXDISABLE_ATTR_ID(25), + TRANSCEIVER_TXDISABLE_ATTR_ID(26), + TRANSCEIVER_TXDISABLE_ATTR_ID(27), + TRANSCEIVER_TXDISABLE_ATTR_ID(28), + TRANSCEIVER_TXDISABLE_ATTR_ID(29), + TRANSCEIVER_TXDISABLE_ATTR_ID(30), + TRANSCEIVER_TXDISABLE_ATTR_ID(31), + TRANSCEIVER_TXDISABLE_ATTR_ID(32), + TRANSCEIVER_TXDISABLE_ATTR_ID(33), + TRANSCEIVER_TXDISABLE_ATTR_ID(34), + TRANSCEIVER_TXDISABLE_ATTR_ID(35), + TRANSCEIVER_TXDISABLE_ATTR_ID(36), + TRANSCEIVER_TXDISABLE_ATTR_ID(37), + TRANSCEIVER_TXDISABLE_ATTR_ID(38), + TRANSCEIVER_TXDISABLE_ATTR_ID(39), + TRANSCEIVER_TXDISABLE_ATTR_ID(40), + TRANSCEIVER_TXDISABLE_ATTR_ID(41), + TRANSCEIVER_TXDISABLE_ATTR_ID(42), + TRANSCEIVER_TXDISABLE_ATTR_ID(43), + TRANSCEIVER_TXDISABLE_ATTR_ID(44), + TRANSCEIVER_TXDISABLE_ATTR_ID(45), + TRANSCEIVER_TXDISABLE_ATTR_ID(46), + TRANSCEIVER_TXDISABLE_ATTR_ID(47), + TRANSCEIVER_TXDISABLE_ATTR_ID(48), + TRANSCEIVER_RXLOS_ATTR_ID(1), + TRANSCEIVER_RXLOS_ATTR_ID(2), + TRANSCEIVER_RXLOS_ATTR_ID(3), + TRANSCEIVER_RXLOS_ATTR_ID(4), + TRANSCEIVER_RXLOS_ATTR_ID(5), + TRANSCEIVER_RXLOS_ATTR_ID(6), + TRANSCEIVER_RXLOS_ATTR_ID(7), + TRANSCEIVER_RXLOS_ATTR_ID(8), + TRANSCEIVER_RXLOS_ATTR_ID(9), + TRANSCEIVER_RXLOS_ATTR_ID(10), + TRANSCEIVER_RXLOS_ATTR_ID(11), + TRANSCEIVER_RXLOS_ATTR_ID(12), + TRANSCEIVER_RXLOS_ATTR_ID(13), + TRANSCEIVER_RXLOS_ATTR_ID(14), + TRANSCEIVER_RXLOS_ATTR_ID(15), + TRANSCEIVER_RXLOS_ATTR_ID(16), + TRANSCEIVER_RXLOS_ATTR_ID(17), + TRANSCEIVER_RXLOS_ATTR_ID(18), + TRANSCEIVER_RXLOS_ATTR_ID(19), + TRANSCEIVER_RXLOS_ATTR_ID(20), + TRANSCEIVER_RXLOS_ATTR_ID(21), + TRANSCEIVER_RXLOS_ATTR_ID(22), + TRANSCEIVER_RXLOS_ATTR_ID(23), + TRANSCEIVER_RXLOS_ATTR_ID(24), + TRANSCEIVER_RXLOS_ATTR_ID(25), + TRANSCEIVER_RXLOS_ATTR_ID(26), + TRANSCEIVER_RXLOS_ATTR_ID(27), + TRANSCEIVER_RXLOS_ATTR_ID(28), + TRANSCEIVER_RXLOS_ATTR_ID(29), + TRANSCEIVER_RXLOS_ATTR_ID(30), + TRANSCEIVER_RXLOS_ATTR_ID(31), + TRANSCEIVER_RXLOS_ATTR_ID(32), + TRANSCEIVER_RXLOS_ATTR_ID(33), + TRANSCEIVER_RXLOS_ATTR_ID(34), + TRANSCEIVER_RXLOS_ATTR_ID(35), + TRANSCEIVER_RXLOS_ATTR_ID(36), + TRANSCEIVER_RXLOS_ATTR_ID(37), + TRANSCEIVER_RXLOS_ATTR_ID(38), + TRANSCEIVER_RXLOS_ATTR_ID(39), + TRANSCEIVER_RXLOS_ATTR_ID(40), + TRANSCEIVER_RXLOS_ATTR_ID(41), + TRANSCEIVER_RXLOS_ATTR_ID(42), + TRANSCEIVER_RXLOS_ATTR_ID(43), + TRANSCEIVER_RXLOS_ATTR_ID(44), + TRANSCEIVER_RXLOS_ATTR_ID(45), + TRANSCEIVER_RXLOS_ATTR_ID(46), + TRANSCEIVER_RXLOS_ATTR_ID(47), + TRANSCEIVER_RXLOS_ATTR_ID(48), + TRANSCEIVER_TXFAULT_ATTR_ID(1), + TRANSCEIVER_TXFAULT_ATTR_ID(2), + TRANSCEIVER_TXFAULT_ATTR_ID(3), + TRANSCEIVER_TXFAULT_ATTR_ID(4), + TRANSCEIVER_TXFAULT_ATTR_ID(5), + TRANSCEIVER_TXFAULT_ATTR_ID(6), + TRANSCEIVER_TXFAULT_ATTR_ID(7), + TRANSCEIVER_TXFAULT_ATTR_ID(8), + TRANSCEIVER_TXFAULT_ATTR_ID(9), + TRANSCEIVER_TXFAULT_ATTR_ID(10), + TRANSCEIVER_TXFAULT_ATTR_ID(11), + TRANSCEIVER_TXFAULT_ATTR_ID(12), + TRANSCEIVER_TXFAULT_ATTR_ID(13), + TRANSCEIVER_TXFAULT_ATTR_ID(14), + TRANSCEIVER_TXFAULT_ATTR_ID(15), + TRANSCEIVER_TXFAULT_ATTR_ID(16), + TRANSCEIVER_TXFAULT_ATTR_ID(17), + TRANSCEIVER_TXFAULT_ATTR_ID(18), + TRANSCEIVER_TXFAULT_ATTR_ID(19), + TRANSCEIVER_TXFAULT_ATTR_ID(20), + TRANSCEIVER_TXFAULT_ATTR_ID(21), + TRANSCEIVER_TXFAULT_ATTR_ID(22), + TRANSCEIVER_TXFAULT_ATTR_ID(23), + TRANSCEIVER_TXFAULT_ATTR_ID(24), + TRANSCEIVER_TXFAULT_ATTR_ID(25), + TRANSCEIVER_TXFAULT_ATTR_ID(26), + TRANSCEIVER_TXFAULT_ATTR_ID(27), + TRANSCEIVER_TXFAULT_ATTR_ID(28), + TRANSCEIVER_TXFAULT_ATTR_ID(29), + TRANSCEIVER_TXFAULT_ATTR_ID(30), + TRANSCEIVER_TXFAULT_ATTR_ID(31), + TRANSCEIVER_TXFAULT_ATTR_ID(32), + TRANSCEIVER_TXFAULT_ATTR_ID(33), + TRANSCEIVER_TXFAULT_ATTR_ID(34), + TRANSCEIVER_TXFAULT_ATTR_ID(35), + TRANSCEIVER_TXFAULT_ATTR_ID(36), + TRANSCEIVER_TXFAULT_ATTR_ID(37), + TRANSCEIVER_TXFAULT_ATTR_ID(38), + TRANSCEIVER_TXFAULT_ATTR_ID(39), + TRANSCEIVER_TXFAULT_ATTR_ID(40), + TRANSCEIVER_TXFAULT_ATTR_ID(41), + TRANSCEIVER_TXFAULT_ATTR_ID(42), + TRANSCEIVER_TXFAULT_ATTR_ID(43), + TRANSCEIVER_TXFAULT_ATTR_ID(44), + TRANSCEIVER_TXFAULT_ATTR_ID(45), + TRANSCEIVER_TXFAULT_ATTR_ID(46), + TRANSCEIVER_TXFAULT_ATTR_ID(47), + TRANSCEIVER_TXFAULT_ATTR_ID(48), +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as5916_54xk_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as5916_54xk_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/* transceiver attributes */ +#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index) +#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr + +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); +/* transceiver attributes */ +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL); +static SENSOR_DEVICE_ATTR(module_rx_los_all, S_IRUGO, show_rxlos_all, NULL, MODULE_RXLOS_ALL); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(33); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(34); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(35); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(36); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(37); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(38); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(39); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(40); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(41); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(42); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(43); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(44); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(45); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(46); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(47); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(48); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(54); + +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(33); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(34); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(35); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(36); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(37); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(38); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(39); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(40); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(41); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(42); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(43); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(44); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(45); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); + +static struct attribute *as5916_54xk_cpld1_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rx_los_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(1), + DECLARE_TRANSCEIVER_PRESENT_ATTR(2), + DECLARE_TRANSCEIVER_PRESENT_ATTR(3), + DECLARE_TRANSCEIVER_PRESENT_ATTR(4), + DECLARE_TRANSCEIVER_PRESENT_ATTR(5), + DECLARE_TRANSCEIVER_PRESENT_ATTR(6), + DECLARE_TRANSCEIVER_PRESENT_ATTR(7), + DECLARE_TRANSCEIVER_PRESENT_ATTR(8), + DECLARE_TRANSCEIVER_PRESENT_ATTR(9), + DECLARE_TRANSCEIVER_PRESENT_ATTR(10), + DECLARE_TRANSCEIVER_PRESENT_ATTR(11), + DECLARE_TRANSCEIVER_PRESENT_ATTR(12), + DECLARE_TRANSCEIVER_PRESENT_ATTR(13), + DECLARE_TRANSCEIVER_PRESENT_ATTR(14), + DECLARE_TRANSCEIVER_PRESENT_ATTR(15), + DECLARE_TRANSCEIVER_PRESENT_ATTR(16), + DECLARE_TRANSCEIVER_PRESENT_ATTR(17), + DECLARE_TRANSCEIVER_PRESENT_ATTR(18), + DECLARE_TRANSCEIVER_PRESENT_ATTR(19), + DECLARE_TRANSCEIVER_PRESENT_ATTR(20), + DECLARE_TRANSCEIVER_PRESENT_ATTR(21), + DECLARE_TRANSCEIVER_PRESENT_ATTR(22), + DECLARE_TRANSCEIVER_PRESENT_ATTR(23), + DECLARE_TRANSCEIVER_PRESENT_ATTR(24), + DECLARE_SFP_TRANSCEIVER_ATTR(1), + DECLARE_SFP_TRANSCEIVER_ATTR(2), + DECLARE_SFP_TRANSCEIVER_ATTR(3), + DECLARE_SFP_TRANSCEIVER_ATTR(4), + DECLARE_SFP_TRANSCEIVER_ATTR(5), + DECLARE_SFP_TRANSCEIVER_ATTR(6), + DECLARE_SFP_TRANSCEIVER_ATTR(7), + DECLARE_SFP_TRANSCEIVER_ATTR(8), + DECLARE_SFP_TRANSCEIVER_ATTR(9), + DECLARE_SFP_TRANSCEIVER_ATTR(10), + DECLARE_SFP_TRANSCEIVER_ATTR(11), + DECLARE_SFP_TRANSCEIVER_ATTR(12), + DECLARE_SFP_TRANSCEIVER_ATTR(13), + DECLARE_SFP_TRANSCEIVER_ATTR(14), + DECLARE_SFP_TRANSCEIVER_ATTR(15), + DECLARE_SFP_TRANSCEIVER_ATTR(16), + DECLARE_SFP_TRANSCEIVER_ATTR(17), + DECLARE_SFP_TRANSCEIVER_ATTR(18), + DECLARE_SFP_TRANSCEIVER_ATTR(19), + DECLARE_SFP_TRANSCEIVER_ATTR(20), + DECLARE_SFP_TRANSCEIVER_ATTR(21), + DECLARE_SFP_TRANSCEIVER_ATTR(22), + DECLARE_SFP_TRANSCEIVER_ATTR(23), + DECLARE_SFP_TRANSCEIVER_ATTR(24), + NULL +}; + +static const struct attribute_group as5916_54xk_cpld1_group = { + .attrs = as5916_54xk_cpld1_attributes, +}; + +static struct attribute *as5916_54xk_cpld2_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + &sensor_dev_attr_module_rx_los_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(25), + DECLARE_TRANSCEIVER_PRESENT_ATTR(26), + DECLARE_TRANSCEIVER_PRESENT_ATTR(27), + DECLARE_TRANSCEIVER_PRESENT_ATTR(28), + DECLARE_TRANSCEIVER_PRESENT_ATTR(29), + DECLARE_TRANSCEIVER_PRESENT_ATTR(30), + DECLARE_TRANSCEIVER_PRESENT_ATTR(31), + DECLARE_TRANSCEIVER_PRESENT_ATTR(32), + DECLARE_TRANSCEIVER_PRESENT_ATTR(33), + DECLARE_TRANSCEIVER_PRESENT_ATTR(34), + DECLARE_TRANSCEIVER_PRESENT_ATTR(35), + DECLARE_TRANSCEIVER_PRESENT_ATTR(36), + DECLARE_TRANSCEIVER_PRESENT_ATTR(37), + DECLARE_TRANSCEIVER_PRESENT_ATTR(38), + DECLARE_TRANSCEIVER_PRESENT_ATTR(39), + DECLARE_TRANSCEIVER_PRESENT_ATTR(40), + DECLARE_TRANSCEIVER_PRESENT_ATTR(41), + DECLARE_TRANSCEIVER_PRESENT_ATTR(42), + DECLARE_TRANSCEIVER_PRESENT_ATTR(43), + DECLARE_TRANSCEIVER_PRESENT_ATTR(44), + DECLARE_TRANSCEIVER_PRESENT_ATTR(45), + DECLARE_TRANSCEIVER_PRESENT_ATTR(46), + DECLARE_TRANSCEIVER_PRESENT_ATTR(47), + DECLARE_TRANSCEIVER_PRESENT_ATTR(48), + DECLARE_TRANSCEIVER_PRESENT_ATTR(49), + DECLARE_TRANSCEIVER_PRESENT_ATTR(50), + DECLARE_TRANSCEIVER_PRESENT_ATTR(51), + DECLARE_TRANSCEIVER_PRESENT_ATTR(52), + DECLARE_TRANSCEIVER_PRESENT_ATTR(53), + DECLARE_TRANSCEIVER_PRESENT_ATTR(54), + DECLARE_SFP_TRANSCEIVER_ATTR(25), + DECLARE_SFP_TRANSCEIVER_ATTR(26), + DECLARE_SFP_TRANSCEIVER_ATTR(27), + DECLARE_SFP_TRANSCEIVER_ATTR(28), + DECLARE_SFP_TRANSCEIVER_ATTR(29), + DECLARE_SFP_TRANSCEIVER_ATTR(30), + DECLARE_SFP_TRANSCEIVER_ATTR(31), + DECLARE_SFP_TRANSCEIVER_ATTR(32), + DECLARE_SFP_TRANSCEIVER_ATTR(33), + DECLARE_SFP_TRANSCEIVER_ATTR(34), + DECLARE_SFP_TRANSCEIVER_ATTR(35), + DECLARE_SFP_TRANSCEIVER_ATTR(36), + DECLARE_SFP_TRANSCEIVER_ATTR(37), + DECLARE_SFP_TRANSCEIVER_ATTR(38), + DECLARE_SFP_TRANSCEIVER_ATTR(39), + DECLARE_SFP_TRANSCEIVER_ATTR(40), + DECLARE_SFP_TRANSCEIVER_ATTR(41), + DECLARE_SFP_TRANSCEIVER_ATTR(42), + DECLARE_SFP_TRANSCEIVER_ATTR(43), + DECLARE_SFP_TRANSCEIVER_ATTR(44), + DECLARE_SFP_TRANSCEIVER_ATTR(45), + DECLARE_SFP_TRANSCEIVER_ATTR(46), + DECLARE_SFP_TRANSCEIVER_ATTR(47), + DECLARE_SFP_TRANSCEIVER_ATTR(48), + NULL +}; + +static const struct attribute_group as5916_54xk_cpld2_group = { + .attrs = as5916_54xk_cpld2_attributes, +}; + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status, num_regs = 0; + u8 values[4] = {0}; + u8 regs[] = {0x10, 0x11, 0x12, 0x52}; + struct i2c_client *client = to_i2c_client(dev); + struct as5916_54xk_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + num_regs = (data->type == as5916_54xk_cpld1) ? 3 : 4; + + for (i = 0; i < num_regs; i++) { + status = as5916_54xk_cpld_read_internal(client, regs[i]); + + if (status < 0) { + goto exit; + } + + values[i] = ~(u8)status; + } + + mutex_unlock(&data->update_lock); + + if (data->type == as5916_54xk_cpld1) { + status = sprintf(buf, "%.2x %.2x %.2x\n", + values[0], values[1], values[2]); + } + else { /* as5916_54xk_cpld2 */ + values[3] &= 0x3F; + status = sprintf(buf, "%.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], values[3]); + } + + return status; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[3] = {0}; + u8 regs[] = {0x30, 0x32, 0x34}; + struct i2c_client *client = to_i2c_client(dev); + struct as5916_54xk_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + status = as5916_54xk_cpld_read_internal(client, regs[i]); + + if (status < 0) { + goto exit; + } + + values[i] = (u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values 1 -> 24 in order */ + return sprintf(buf, "%.2x %.2x %.2x\n", values[0], values[1], values[2]); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as5916_54xk_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, revert = 0; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_8: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_16: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_24: + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_17); + break; + case MODULE_PRESENT_25 ... MODULE_PRESENT_32: + reg = 0x10; + mask = 0x1 << (attr->index - MODULE_PRESENT_25); + break; + case MODULE_PRESENT_33 ... MODULE_PRESENT_40: + reg = 0x11; + mask = 0x1 << (attr->index - MODULE_PRESENT_33); + break; + case MODULE_PRESENT_41 ... MODULE_PRESENT_48: + reg = 0x12; + mask = 0x1 << (attr->index - MODULE_PRESENT_41); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_54: + reg = 0x52; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + break; + case MODULE_TXFAULT_1 ... MODULE_TXFAULT_8: + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_TXFAULT_1); + break; + case MODULE_TXFAULT_9 ... MODULE_TXFAULT_16: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_TXFAULT_9); + break; + case MODULE_TXFAULT_17 ... MODULE_TXFAULT_24: + reg = 0x18; + mask = 0x1 << (attr->index - MODULE_TXFAULT_17); + break; + case MODULE_TXFAULT_25 ... MODULE_TXFAULT_32: + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_TXFAULT_25); + break; + case MODULE_TXFAULT_33 ... MODULE_TXFAULT_40: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_TXFAULT_33); + break; + case MODULE_TXFAULT_41 ... MODULE_TXFAULT_48: + reg = 0x18; + mask = 0x1 << (attr->index - MODULE_TXFAULT_41); + break; + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0x20; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0x22; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0x24; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_32: + reg = 0x20; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXDISABLE_33 ... MODULE_TXDISABLE_40: + reg = 0x22; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_33); + break; + case MODULE_TXDISABLE_41 ... MODULE_TXDISABLE_48: + reg = 0x24; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); + break; + case MODULE_RXLOS_1 ... MODULE_RXLOS_8: + reg = 0x30; + mask = 0x1 << (attr->index - MODULE_RXLOS_1); + break; + case MODULE_RXLOS_9 ... MODULE_RXLOS_16: + reg = 0x32; + mask = 0x1 << (attr->index - MODULE_RXLOS_9); + break; + case MODULE_RXLOS_17 ... MODULE_RXLOS_24: + reg = 0x34; + mask = 0x1 << (attr->index - MODULE_RXLOS_17); + break; + case MODULE_RXLOS_25 ... MODULE_RXLOS_32: + reg = 0x30; + mask = 0x1 << (attr->index - MODULE_RXLOS_25); + break; + case MODULE_RXLOS_33 ... MODULE_RXLOS_40: + reg = 0x32; + mask = 0x1 << (attr->index - MODULE_RXLOS_33); + break; + case MODULE_RXLOS_41 ... MODULE_RXLOS_48: + reg = 0x34; + mask = 0x1 << (attr->index - MODULE_RXLOS_41); + break; + default: + return 0; + } + + if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_54) { + revert = 1; + } + + mutex_lock(&data->update_lock); + status = as5916_54xk_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as5916_54xk_cpld_data *data = i2c_get_clientdata(client); + long disable; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_TXDISABLE_1 ... MODULE_TXDISABLE_8: + reg = 0x20; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_1); + break; + case MODULE_TXDISABLE_9 ... MODULE_TXDISABLE_16: + reg = 0x22; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_9); + break; + case MODULE_TXDISABLE_17 ... MODULE_TXDISABLE_24: + reg = 0x24; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_17); + break; + case MODULE_TXDISABLE_25 ... MODULE_TXDISABLE_32: + reg = 0x20; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_25); + break; + case MODULE_TXDISABLE_33 ... MODULE_TXDISABLE_40: + reg = 0x22; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_33); + break; + case MODULE_TXDISABLE_41 ... MODULE_TXDISABLE_48: + reg = 0x24; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); + break; + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5916_54xk_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update tx_disable status */ + if (disable) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5916_54xk_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as5916_54xk_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as5916_54xk_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as5916_54xk_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as5916_54xk_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d", val); +} + +/* + * I2C init/probing/exit functions + */ +static int as5916_54xk_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as5916_54xk_cpld_data *data; + int ret = -ENODEV; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as5916_54xk_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) { + case as5916_54xk_cpld1: + group = &as5916_54xk_cpld1_group; + break; + case as5916_54xk_cpld2: + group = &as5916_54xk_cpld2_group; + break; + default: + break; + } + + if (group) { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as5916_54xk_cpld_add_client(client); + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as5916_54xk_cpld_remove(struct i2c_client *client) +{ + struct as5916_54xk_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as5916_54xk_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) { + case as5916_54xk_cpld1: + group = &as5916_54xk_cpld1_group; + break; + case as5916_54xk_cpld2: + group = &as5916_54xk_cpld2_group; + break; + default: + break; + } + + if (group) { + sysfs_remove_group(&client->dev.kobj, group); + } + + kfree(data); + + return 0; +} + +static int as5916_54xk_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as5916_54xk_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as5916_54xk_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5916_54xk_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5916_54xk_cpld_read); + +int as5916_54xk_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5916_54xk_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5916_54xk_cpld_write); + +static struct i2c_driver as5916_54xk_cpld_driver = { + .driver = { + .name = "as5916_54xk_cpld", + .owner = THIS_MODULE, + }, + .probe = as5916_54xk_cpld_probe, + .remove = as5916_54xk_cpld_remove, + .id_table = as5916_54xk_cpld_id, +}; + +static int __init as5916_54xk_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as5916_54xk_cpld_driver); +} + +static void __exit as5916_54xk_cpld_exit(void) +{ + i2c_del_driver(&as5916_54xk_cpld_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton I2C CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as5916_54xk_cpld_init); +module_exit(as5916_54xk_cpld_exit); + diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-leds.c b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-leds.c index f155e970..078e005a 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-leds.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-leds.c @@ -38,8 +38,8 @@ #define DEBUG_PRINT(fmt, args...) #endif -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); +extern int as5916_54xk_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5916_54xk_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); struct accton_as5916_54xk_led_data { struct platform_device *pdev; @@ -157,12 +157,12 @@ static u8 led_light_mode_to_reg_val(enum led_type type, static int accton_as5916_54xk_led_read_value(u8 reg) { - return accton_i2c_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); + return as5916_54xk_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); } static int accton_as5916_54xk_led_write_value(u8 reg, u8 value) { - return accton_i2c_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); + return as5916_54xk_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); } static void accton_as5916_54xk_led_update(void) diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-psu.c b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-psu.c index a2737499..f89fc298 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-psu.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-psu.c @@ -37,7 +37,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf); static int as5916_54xk_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5916_54xk_cpld_read(unsigned short cpld_addr, u8 reg); /* Addresses scanned */ @@ -234,7 +234,7 @@ static struct as5916_54xk_psu_data *as5916_54xk_psu_update_device(struct device dev_dbg(&client->dev, "Starting as5916_54xk update\n"); /* Read psu status */ - status = accton_i2c_cpld_read(0x60, 0x2); + status = as5916_54xk_cpld_read(0x60, 0x2); if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-sfp.c b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-sfp.c deleted file mode 100644 index c606e5c2..00000000 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/modules/builds/x86-64-accton-as5916-54xk-sfp.c +++ /dev/null @@ -1,1315 +0,0 @@ -/* - * SFP driver for accton as5916_54xk sfp - * - * Copyright (C) Brandon Chuang - * - * Based on ad7414.c - * Copyright 2006 Stefan Roese , DENX Software Engineering - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "as5916_54xk_sfp" /* Platform dependent */ - -#define DEBUG_MODE 0 - -#if (DEBUG_MODE == 1) - #define DEBUG_PRINT(fmt, args...) \ - printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) -#else - #define DEBUG_PRINT(fmt, args...) -#endif - -#define NUM_OF_SFP_PORT 54 -#define EEPROM_NAME "sfp_eeprom" -#define EEPROM_SIZE 256 /* 256 byte eeprom */ -#define BIT_INDEX(i) (1ULL << (i)) -#define USE_I2C_BLOCK_READ 1 /* Platform dependent */ -#define I2C_RW_RETRY_COUNT 3 -#define I2C_RW_RETRY_INTERVAL 100 /* ms */ - -#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) -#define SFP_EEPROM_A2_I2C_ADDR (0xA2 >> 1) - -#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 -#define SFF8024_DEVICE_ID_SFP 0x3 -#define SFF8024_DEVICE_ID_QSFP 0xC -#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD -#define SFF8024_DEVICE_ID_QSFP28 0x11 - -#define SFF8472_DIAG_MON_TYPE_ADDR 92 -#define SFF8472_DIAG_MON_TYPE_DDM_MASK 0x40 -#define SFF8472_10G_ETH_COMPLIANCE_ADDR 0x3 -#define SFF8472_10G_BASE_MASK 0xF0 - -#define SFF8436_RX_LOS_ADDR 3 -#define SFF8436_TX_FAULT_ADDR 4 -#define SFF8436_TX_DISABLE_ADDR 86 - -/* Platform dependent +++ */ -#define I2C_ADDR_CPLD1 0x60 -#define I2C_ADDR_CPLD2 0x62 -/* Platform dependent --- */ - -static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); -static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);; -static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); -static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); -extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); -extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); - -enum sfp_sysfs_attributes { - PRESENT, - PRESENT_ALL, - PORT_NUMBER, - PORT_TYPE, - DDM_IMPLEMENTED, - TX_FAULT, - TX_FAULT1, - TX_FAULT2, - TX_FAULT3, - TX_FAULT4, - TX_DISABLE, - TX_DISABLE1, - TX_DISABLE2, - TX_DISABLE3, - TX_DISABLE4, - RX_LOS, - RX_LOS1, - RX_LOS2, - RX_LOS3, - RX_LOS4, - RX_LOS_ALL -}; - -/* SFP/QSFP common attributes for sysfs */ -static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); -static SENSOR_DEVICE_ATTR(sfp_port_type, S_IRUGO, show_port_type, NULL, PORT_TYPE); -static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); -static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); -static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS); -static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, sfp_show_tx_rx_status, sfp_set_tx_disable, TX_DISABLE); -static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, sfp_show_tx_rx_status, NULL, TX_FAULT); - -/* QSFP attributes for sysfs */ -static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); -static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); -static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); -static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); -static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); -static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); -static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); -static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); -static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); -static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); -static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); -static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); -static struct attribute *qsfp_attributes[] = { - &sensor_dev_attr_sfp_port_number.dev_attr.attr, - &sensor_dev_attr_sfp_port_type.dev_attr.attr, - &sensor_dev_attr_sfp_is_present.dev_attr.attr, - &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, - NULL -}; - -/* SFP msa attributes for sysfs */ -static SENSOR_DEVICE_ATTR(sfp_ddm_implemented, S_IRUGO, sfp_show_ddm_implemented, NULL, DDM_IMPLEMENTED); -static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS_ALL); -static struct attribute *sfp_msa_attributes[] = { - &sensor_dev_attr_sfp_port_number.dev_attr.attr, - &sensor_dev_attr_sfp_port_type.dev_attr.attr, - &sensor_dev_attr_sfp_is_present.dev_attr.attr, - &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, - &sensor_dev_attr_sfp_ddm_implemented.dev_attr.attr, - &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los.dev_attr.attr, - &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, - &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, - NULL -}; - -/* SFP ddm attributes for sysfs */ -static struct attribute *sfp_ddm_attributes[] = { - NULL -}; - -/* Platform dependent +++ */ -#define CPLD_PORT_TO_FRONT_PORT(port) (port+1) - -enum port_numbers { -as5916_54xk_sfp1, as5916_54xk_sfp2, as5916_54xk_sfp3, as5916_54xk_sfp4, as5916_54xk_sfp5, as5916_54xk_sfp6, as5916_54xk_sfp7, as5916_54xk_sfp8, -as5916_54xk_sfp9, as5916_54xk_sfp10, as5916_54xk_sfp11, as5916_54xk_sfp12, as5916_54xk_sfp13, as5916_54xk_sfp14, as5916_54xk_sfp15, as5916_54xk_sfp16, -as5916_54xk_sfp17, as5916_54xk_sfp18, as5916_54xk_sfp19, as5916_54xk_sfp20, as5916_54xk_sfp21, as5916_54xk_sfp22, as5916_54xk_sfp23, as5916_54xk_sfp24, -as5916_54xk_sfp25, as5916_54xk_sfp26, as5916_54xk_sfp27, as5916_54xk_sfp28, as5916_54xk_sfp29, as5916_54xk_sfp30, as5916_54xk_sfp31, as5916_54xk_sfp32, -as5916_54xk_sfp33, as5916_54xk_sfp34, as5916_54xk_sfp35, as5916_54xk_sfp36, as5916_54xk_sfp37, as5916_54xk_sfp38, as5916_54xk_sfp39, as5916_54xk_sfp40, -as5916_54xk_sfp41, as5916_54xk_sfp42, as5916_54xk_sfp43, as5916_54xk_sfp44, as5916_54xk_sfp45, as5916_54xk_sfp46, as5916_54xk_sfp47, as5916_54xk_sfp48, -as5916_54xk_sfp49, as5916_54xk_sfp50, as5916_54xk_sfp51, as5916_54xk_sfp52, as5916_54xk_sfp53, as5916_54xk_sfp54 -}; - -static const struct i2c_device_id sfp_device_id[] = { -{ "as5916_54xk_sfp1", as5916_54xk_sfp1 }, { "as5916_54xk_sfp2", as5916_54xk_sfp2 }, { "as5916_54xk_sfp3", as5916_54xk_sfp3 }, { "as5916_54xk_sfp4", as5916_54xk_sfp4 }, -{ "as5916_54xk_sfp5", as5916_54xk_sfp5 }, { "as5916_54xk_sfp6", as5916_54xk_sfp6 }, { "as5916_54xk_sfp7", as5916_54xk_sfp7 }, { "as5916_54xk_sfp8", as5916_54xk_sfp8 }, -{ "as5916_54xk_sfp9", as5916_54xk_sfp9 }, { "as5916_54xk_sfp10", as5916_54xk_sfp10 }, { "as5916_54xk_sfp11", as5916_54xk_sfp11 }, { "as5916_54xk_sfp12", as5916_54xk_sfp12 }, -{ "as5916_54xk_sfp13", as5916_54xk_sfp13 }, { "as5916_54xk_sfp14", as5916_54xk_sfp14 }, { "as5916_54xk_sfp15", as5916_54xk_sfp15 }, { "as5916_54xk_sfp16", as5916_54xk_sfp16 }, -{ "as5916_54xk_sfp17", as5916_54xk_sfp17 }, { "as5916_54xk_sfp18", as5916_54xk_sfp18 }, { "as5916_54xk_sfp19", as5916_54xk_sfp19 }, { "as5916_54xk_sfp20", as5916_54xk_sfp20 }, -{ "as5916_54xk_sfp21", as5916_54xk_sfp21 }, { "as5916_54xk_sfp22", as5916_54xk_sfp22 }, { "as5916_54xk_sfp23", as5916_54xk_sfp23 }, { "as5916_54xk_sfp24", as5916_54xk_sfp24 }, -{ "as5916_54xk_sfp25", as5916_54xk_sfp25 }, { "as5916_54xk_sfp26", as5916_54xk_sfp26 }, { "as5916_54xk_sfp27", as5916_54xk_sfp27 }, { "as5916_54xk_sfp28", as5916_54xk_sfp28 }, -{ "as5916_54xk_sfp29", as5916_54xk_sfp29 }, { "as5916_54xk_sfp30", as5916_54xk_sfp30 }, { "as5916_54xk_sfp31", as5916_54xk_sfp31 }, { "as5916_54xk_sfp32", as5916_54xk_sfp32 }, -{ "as5916_54xk_sfp33", as5916_54xk_sfp33 }, { "as5916_54xk_sfp34", as5916_54xk_sfp34 }, { "as5916_54xk_sfp35", as5916_54xk_sfp35 }, { "as5916_54xk_sfp36", as5916_54xk_sfp36 }, -{ "as5916_54xk_sfp37", as5916_54xk_sfp37 }, { "as5916_54xk_sfp38", as5916_54xk_sfp38 }, { "as5916_54xk_sfp39", as5916_54xk_sfp39 }, { "as5916_54xk_sfp40", as5916_54xk_sfp40 }, -{ "as5916_54xk_sfp41", as5916_54xk_sfp41 }, { "as5916_54xk_sfp42", as5916_54xk_sfp42 }, { "as5916_54xk_sfp43", as5916_54xk_sfp43 }, { "as5916_54xk_sfp44", as5916_54xk_sfp44 }, -{ "as5916_54xk_sfp45", as5916_54xk_sfp45 }, { "as5916_54xk_sfp46", as5916_54xk_sfp46 }, { "as5916_54xk_sfp47", as5916_54xk_sfp47 }, { "as5916_54xk_sfp48", as5916_54xk_sfp48 }, -{ "as5916_54xk_sfp49", as5916_54xk_sfp49 }, { "as5916_54xk_sfp50", as5916_54xk_sfp50 }, { "as5916_54xk_sfp51", as5916_54xk_sfp51 }, { "as5916_54xk_sfp52", as5916_54xk_sfp52 }, -{ "as5916_54xk_sfp53", as5916_54xk_sfp53 }, { "as5916_54xk_sfp54", as5916_54xk_sfp54 }, -{ /* LIST END */ } -}; -MODULE_DEVICE_TABLE(i2c, sfp_device_id); -/* Platform dependent --- */ - -/* - * list of valid port types - * note OOM_PORT_TYPE_NOT_PRESENT to indicate no - * module is present in this port - */ -typedef enum oom_driver_port_type_e { - OOM_DRIVER_PORT_TYPE_INVALID, - OOM_DRIVER_PORT_TYPE_NOT_PRESENT, - OOM_DRIVER_PORT_TYPE_SFP, - OOM_DRIVER_PORT_TYPE_SFP_PLUS, - OOM_DRIVER_PORT_TYPE_QSFP, - OOM_DRIVER_PORT_TYPE_QSFP_PLUS, - OOM_DRIVER_PORT_TYPE_QSFP28 -} oom_driver_port_type_t; - -enum driver_type_e { - DRIVER_TYPE_SFP_MSA, - DRIVER_TYPE_SFP_DDM, - DRIVER_TYPE_QSFP -}; - -/* Each client has this additional data - */ -struct eeprom_data { - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - struct bin_attribute bin; /* eeprom data */ -}; - -struct sfp_msa_data { - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u64 status[6]; /* bit0:port0, bit1:port1 and so on */ - /* index 0 => tx_fail - 1 => tx_disable - 2 => rx_loss - 3 => device id - 4 => 10G Ethernet Compliance Codes - to distinguish SFP or SFP+ - 5 => DIAGNOSTIC MONITORING TYPE */ - struct eeprom_data eeprom; -}; - -struct sfp_ddm_data { - struct eeprom_data eeprom; -}; - -struct qsfp_data { - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 status[3]; /* bit0:port0, bit1:port1 and so on */ - /* index 0 => tx_fail - 1 => tx_disable - 2 => rx_loss */ - - u8 device_id; - struct eeprom_data eeprom; -}; - -struct sfp_port_data { - struct mutex update_lock; - enum driver_type_e driver_type; - int port; /* CPLD port index */ - oom_driver_port_type_t port_type; - u64 present; /* present status, bit0:port0, bit1:port1 and so on */ - - struct sfp_msa_data *msa; - struct sfp_ddm_data *ddm; - struct qsfp_data *qsfp; - - struct i2c_client *client; -}; - -static ssize_t show_port_number(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); -} - -/* Platform dependent +++ */ -static struct sfp_port_data *sfp_update_present(struct i2c_client *client) -{ - int i = 0, j = 0, status = -1; - u8 reg; - unsigned short cpld_addr; - struct sfp_port_data *data = i2c_get_clientdata(client); - - DEBUG_PRINT("Starting sfp present status update"); - mutex_lock(&data->update_lock); - data->present = 0; - - /* Read present status of port 1~48(SFP port) */ - for (i = 0; i < 2; i++) { - for (j = 0; j < 3; j++) { - cpld_addr = I2C_ADDR_CPLD1 + i*2; - reg = 0x10+j; - status = accton_i2c_cpld_read(cpld_addr, reg); - - if (unlikely(status < 0)) { - dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); - goto exit; - } - - DEBUG_PRINT("Present status = 0x%lx\r\n", data->present); - data->present |= (u64)status << ((i*24) + (j%3)*8); - } - } - - /* Read present status of port 49-52(QSFP port) */ - cpld_addr = I2C_ADDR_CPLD2; - reg = 0x52; - status = accton_i2c_cpld_read(cpld_addr, reg); - - if (unlikely(status < 0)) { - dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, reg, status); - goto exit; - } - else { - data->present |= (u64)(status & 0x3F) << 48; - } - - DEBUG_PRINT("Present status = 0x%lx", data->present); -exit: - mutex_unlock(&data->update_lock); - return (status < 0) ? ERR_PTR(status) : data; -} - -static struct sfp_port_data* sfp_update_tx_rx_status(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - int i = 0, j = 0; - int status = -1; - u8 tx_rx_regs[] = {0x14, 0x16, 0x18, 0x20, 0x22, 0x24, 0x30, 0x32, 0x34}; - - if (time_before(jiffies, data->msa->last_updated + HZ + HZ / 2) && data->msa->valid) { - return data; - } - - DEBUG_PRINT("Starting as5916_54xk sfp tx rx status update"); - mutex_lock(&data->update_lock); - data->msa->valid = 0; - memset(data->msa->status, 0, sizeof(data->msa->status)); - - /* Read status of port 1~48(SFP port) */ - for (i = 0; i < 2; i++) { - for (j = 0; j < ARRAY_SIZE(tx_rx_regs); j++) { - unsigned short cpld_addr = I2C_ADDR_CPLD1 + i*2; - - status = accton_i2c_cpld_read(cpld_addr, tx_rx_regs[j]); - if (unlikely(status < 0)) { - dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", cpld_addr, tx_rx_regs[i], status); - goto exit; - } - - data->msa->status[j/3] |= (u64)status << ((i*24) + (j%3)*8); - } - } - - data->msa->valid = 1; - data->msa->last_updated = jiffies; - -exit: - mutex_unlock(&data->update_lock); - return (status < 0) ? ERR_PTR(status) : data; -} - -static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - unsigned short cpld_addr = 0; - u8 cpld_reg = 0, cpld_val = 0, cpld_bit = 0; - long disable; - int error; - u8 tx_disable_regs[] = {0x20, 0x22, 0x24}; - - if (data->driver_type == DRIVER_TYPE_QSFP) { - return qsfp_set_tx_disable(dev, da, buf, count); - } - - error = kstrtol(buf, 10, &disable); - if (error) { - return error; - } - - mutex_lock(&data->update_lock); - - if(data->port < 24) { - cpld_addr = I2C_ADDR_CPLD1; - cpld_reg = tx_disable_regs[data->port / 8]; - cpld_bit = 1 << (data->port % 8); - } - else { /* port 24 ~ 48 */ - cpld_addr = I2C_ADDR_CPLD2; - cpld_reg = tx_disable_regs[(data->port - 24) / 8]; - cpld_bit = 1 << (data->port % 8); - } - - /* Read current status */ - cpld_val = accton_i2c_cpld_read(cpld_addr, cpld_reg); - - /* Update tx_disable status */ - if (disable) { - data->msa->status[1] |= BIT_INDEX(data->port); - cpld_val |= cpld_bit; - } - else { - data->msa->status[1] &= ~BIT_INDEX(data->port); - cpld_val &= ~cpld_bit; - } - - accton_i2c_cpld_write(cpld_addr, cpld_reg, cpld_val); - mutex_unlock(&data->update_lock); - return count; -} - -static int sfp_is_port_present(struct i2c_client *client, int port) -{ - struct sfp_port_data *data = i2c_get_clientdata(client); - - data = sfp_update_present(client); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - return !(data->present & BIT_INDEX(data->port)); /* Platform dependent */ -} - -static ssize_t show_present(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - - if (PRESENT_ALL == attr->index) { - int i; - u8 values[7] = {0}; - struct sfp_port_data *data = sfp_update_present(client); - - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - for (i = 0; i < ARRAY_SIZE(values); i++) { - values[i] = ~(u8)(data->present >> (i * 8)); - } - - /* Return values 1 -> 54 in order */ - return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", - values[0], values[1], values[2], - values[3], values[4], values[5], - values[6] & 0x3F); - } - else { - struct sfp_port_data *data = i2c_get_clientdata(client); - int present = sfp_is_port_present(client, data->port); - - if (IS_ERR_VALUE(present)) { - return present; - } - - /* PRESENT */ - return sprintf(buf, "%d\n", present); - } -} -/* Platform dependent --- */ - -static struct sfp_port_data *sfp_update_port_type(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - u8 buf = 0; - int status; - - mutex_lock(&data->update_lock); - - switch (data->driver_type) { - case DRIVER_TYPE_SFP_MSA: - { - status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - if (buf != SFF8024_DEVICE_ID_SFP) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - status = sfp_eeprom_read(client, SFF8472_10G_ETH_COMPLIANCE_ADDR, &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - DEBUG_PRINT("sfp port type (0x3) data = (0x%x)", buf); - data->port_type = buf & SFF8472_10G_BASE_MASK ? OOM_DRIVER_PORT_TYPE_SFP_PLUS : OOM_DRIVER_PORT_TYPE_SFP; - break; - } - case DRIVER_TYPE_QSFP: - { - status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); - if (unlikely(status < 0)) { - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - DEBUG_PRINT("qsfp port type (0x0) buf = (0x%x)", buf); - switch (buf) { - case SFF8024_DEVICE_ID_QSFP: - data->port_type = OOM_DRIVER_PORT_TYPE_QSFP; - break; - case SFF8024_DEVICE_ID_QSFP_PLUS: - data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; - break; - case SFF8024_DEVICE_ID_QSFP28: - data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; - break; - default: - data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; - break; - } - - break; - } - default: - break; - } - - mutex_unlock(&data->update_lock); - return data; -} - -static ssize_t show_port_type(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - int present = sfp_is_port_present(client, data->port); - - if (IS_ERR_VALUE(present)) { - return present; - } - - if (!present) { - return sprintf(buf, "%d\n", OOM_DRIVER_PORT_TYPE_NOT_PRESENT); - } - - sfp_update_port_type(dev); - return sprintf(buf, "%d\n", data->port_type); -} - -static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - int i, status = -1; - u8 buf = 0; - u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; - - if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { - return data; - } - - DEBUG_PRINT("Starting sfp tx rx status update"); - mutex_lock(&data->update_lock); - data->qsfp->valid = 0; - memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); - - /* Notify device to update tx fault/ tx disable/ rx los status */ - for (i = 0; i < ARRAY_SIZE(reg); i++) { - status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); - if (unlikely(status < 0)) { - goto exit; - } - } - msleep(200); - - /* Read actual tx fault/ tx disable/ rx los status */ - for (i = 0; i < ARRAY_SIZE(reg); i++) { - status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); - if (unlikely(status < 0)) { - goto exit; - } - - DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); - data->qsfp->status[i] = (buf & 0xF); - } - - data->qsfp->valid = 1; - data->qsfp->last_updated = jiffies; - -exit: - mutex_unlock(&data->update_lock); - return (status < 0) ? ERR_PTR(status) : data; -} - -static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, - char *buf) -{ - int present; - u8 val = 0; - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - - present = sfp_is_port_present(client, data->port); - if (IS_ERR_VALUE(present)) { - return present; - } - - if (present == 0) { - /* port is not present */ - return -ENXIO; - } - - data = qsfp_update_tx_rx_status(dev); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - switch (attr->index) { - case TX_FAULT: - val = !!(data->qsfp->status[2] & 0xF); - break; - case TX_FAULT1: - case TX_FAULT2: - case TX_FAULT3: - case TX_FAULT4: - val = !!(data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)); - break; - case TX_DISABLE: - val = data->qsfp->status[1] & 0xF; - break; - case TX_DISABLE1: - case TX_DISABLE2: - case TX_DISABLE3: - case TX_DISABLE4: - val = !!(data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)); - break; - case RX_LOS: - val = !!(data->qsfp->status[0] & 0xF); - break; - case RX_LOS1: - case RX_LOS2: - case RX_LOS3: - case RX_LOS4: - val = !!(data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)); - break; - default: - break; - } - - return sprintf(buf, "%d\n", val); -} - -static ssize_t qsfp_set_tx_disable(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); - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - - status = sfp_is_port_present(client, data->port); - if (IS_ERR_VALUE(status)) { - return status; - } - - if (!status) { - /* port is not present */ - return -ENXIO; - } - - status = kstrtol(buf, 10, &disable); - if (status) { - return status; - } - - data = qsfp_update_tx_rx_status(dev); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - mutex_lock(&data->update_lock); - - if (attr->index == TX_DISABLE) { - data->qsfp->status[1] = disable & 0xF; - } - else {/* TX_DISABLE1 ~ TX_DISABLE4*/ - if (disable) { - data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); - } - else { - data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); - } - } - - DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); - status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); - if (unlikely(status < 0)) { - count = status; - } - - mutex_unlock(&data->update_lock); - return count; -} - -static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, - char *buf) -{ - int status; - char ddm; - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - - status = sfp_is_port_present(client, data->port); - if (IS_ERR_VALUE(status)) { - return status; - } - - if (status == 0) { - /* port is not present */ - return -ENODEV; - } - - status = sfp_eeprom_read(client, SFF8472_DIAG_MON_TYPE_ADDR, &ddm, sizeof(ddm)); - if (unlikely(status < 0)) { - return status; - } - - return sprintf(buf, "%d\n", !!(ddm & SFF8472_DIAG_MON_TYPE_DDM_MASK)); -} - -/* Platform dependent +++ */ -static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, - char *buf) -{ - u8 val = 0, index = 0; - struct i2c_client *client = to_i2c_client(dev); - struct sfp_port_data *data = i2c_get_clientdata(client); - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - - if (data->driver_type == DRIVER_TYPE_QSFP) { - return qsfp_show_tx_rx_status(dev, da, buf); - } - - data = sfp_update_tx_rx_status(dev); - if (IS_ERR(data)) { - return PTR_ERR(data); - } - - if(attr->index == RX_LOS_ALL) { - int i = 0; - u8 values[6] = {0}; - - for (i = 0; i < ARRAY_SIZE(values); i++) { - values[i] = (u8)(data->msa->status[2] >> (i * 8)); - } - - /** Return values 1 -> 48 in order */ - return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x\n", - values[0], values[1], values[2], - values[3], values[4], values[5]); - } - - switch (attr->index) { - case TX_FAULT: - index = 0; - break; - case TX_DISABLE: - index = 1; - break; - case RX_LOS: - index = 2; - break; - default: - return 0; - } - - val = !!(data->msa->status[index] & BIT_INDEX(data->port)); - return sprintf(buf, "%d\n", val); -} -/* Platform dependent --- */ -static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, - int data_len) -{ -#if USE_I2C_BLOCK_READ - int status, retry = I2C_RW_RETRY_COUNT; - - if (data_len > I2C_SMBUS_BLOCK_MAX) { - data_len = I2C_SMBUS_BLOCK_MAX; - } - - while (retry) { - status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - return status; - } - - return data_len; -#else - int status, retry = I2C_RW_RETRY_COUNT; - - while (retry) { - status = i2c_smbus_write_byte_data(client, command, *data); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - return status; - } - - return 1; -#endif - - -} - -static ssize_t sfp_port_write(struct sfp_port_data *data, - const char *buf, loff_t off, size_t count) -{ - ssize_t retval = 0; - - if (unlikely(!count)) { - return count; - } - - /* - * Write data to chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&data->update_lock); - - while (count) { - ssize_t status; - - status = sfp_eeprom_write(data->client, 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 ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - int present; - struct sfp_port_data *data; - DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); - data = dev_get_drvdata(container_of(kobj, struct device, kobj)); - - present = sfp_is_port_present(data->client, data->port); - if (IS_ERR_VALUE(present)) { - return present; - } - - if (present == 0) { - /* port is not present */ - return -ENODEV; - } - - return sfp_port_write(data, buf, off, count); -} - -static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, - int data_len) -{ -#if USE_I2C_BLOCK_READ - int status, retry = I2C_RW_RETRY_COUNT; - - if (data_len > I2C_SMBUS_BLOCK_MAX) { - data_len = I2C_SMBUS_BLOCK_MAX; - } - - while (retry) { - status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - goto abort; - } - if (unlikely(status != data_len)) { - status = -EIO; - goto abort; - } - - //result = data_len; - -abort: - return status; -#else - int status, retry = I2C_RW_RETRY_COUNT; - - while (retry) { - status = i2c_smbus_read_byte_data(client, command); - if (unlikely(status < 0)) { - msleep(I2C_RW_RETRY_INTERVAL); - retry--; - continue; - } - - break; - } - - if (unlikely(status < 0)) { - dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); - goto abort; - } - - *data = (u8)status; - status = 1; - -abort: - return status; -#endif -} - -static ssize_t sfp_port_read(struct sfp_port_data *data, - char *buf, loff_t off, size_t count) -{ - ssize_t retval = 0; - - if (unlikely(!count)) { - DEBUG_PRINT("Count = 0, return"); - return count; - } - - /* - * Read data from chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&data->update_lock); - - while (count) { - ssize_t status; - - status = sfp_eeprom_read(data->client, 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 ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - int present; - struct sfp_port_data *data; - DEBUG_PRINT("offset = (%d), count = (%d)", off, count); - data = dev_get_drvdata(container_of(kobj, struct device, kobj)); - - present = sfp_is_port_present(data->client, data->port); - if (IS_ERR_VALUE(present)) { - return present; - } - - if (present == 0) { - /* port is not present */ - return -ENODEV; - } - - return sfp_port_read(data, buf, off, count); -} - -static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) -{ - int err; - - sysfs_bin_attr_init(eeprom); - eeprom->attr.name = EEPROM_NAME; - eeprom->attr.mode = S_IWUSR | S_IRUGO; - eeprom->read = sfp_bin_read; - eeprom->write = sfp_bin_write; - eeprom->size = EEPROM_SIZE; - - /* Create eeprom file */ - err = sysfs_create_bin_file(kobj, eeprom); - if (err) { - return err; - } - - return 0; -} - -static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) -{ - sysfs_remove_bin_file(kobj, eeprom); - return 0; -} - -static const struct attribute_group sfp_msa_group = { - .attrs = sfp_msa_attributes, -}; - -static int sfp_i2c_check_functionality(struct i2c_client *client) -{ -#if USE_I2C_BLOCK_READ - return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); -#else - return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); -#endif -} - -static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, - struct sfp_msa_data **data) -{ - int status; - struct sfp_msa_data *msa; - - if (!sfp_i2c_check_functionality(client)) { - status = -EIO; - goto exit; - } - - msa = kzalloc(sizeof(struct sfp_msa_data), GFP_KERNEL); - if (!msa) { - status = -ENOMEM; - goto exit; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &sfp_msa_group); - if (status) { - goto exit_free; - } - - /* init eeprom */ - status = sfp_sysfs_eeprom_init(&client->dev.kobj, &msa->eeprom.bin); - if (status) { - goto exit_remove; - } - - *data = msa; - dev_info(&client->dev, "sfp msa '%s'\n", client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); -exit_free: - kfree(msa); -exit: - - return status; -} - -static const struct attribute_group sfp_ddm_group = { - .attrs = sfp_ddm_attributes, -}; - -static int sfp_ddm_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, - struct sfp_ddm_data **data) -{ - int status; - struct sfp_ddm_data *ddm; - - if (!sfp_i2c_check_functionality(client)) { - status = -EIO; - goto exit; - } - - ddm = kzalloc(sizeof(struct sfp_ddm_data), GFP_KERNEL); - if (!ddm) { - status = -ENOMEM; - goto exit; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &sfp_ddm_group); - if (status) { - goto exit_free; - } - - /* init eeprom */ - status = sfp_sysfs_eeprom_init(&client->dev.kobj, &ddm->eeprom.bin); - if (status) { - goto exit_remove; - } - - *data = ddm; - dev_info(&client->dev, "sfp ddm '%s'\n", client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); -exit_free: - kfree(ddm); -exit: - - return status; -} - -static const struct attribute_group qsfp_group = { - .attrs = qsfp_attributes, -}; - -static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, - struct qsfp_data **data) -{ - int status; - struct qsfp_data *qsfp; - - if (!sfp_i2c_check_functionality(client)) { - status = -EIO; - goto exit; - } - - qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); - if (!qsfp) { - status = -ENOMEM; - goto exit; - } - - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &qsfp_group); - if (status) { - goto exit_free; - } - - /* init eeprom */ - status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); - if (status) { - goto exit_remove; - } - - *data = qsfp; - dev_info(&client->dev, "qsfp '%s'\n", client->name); - - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &qsfp_group); -exit_free: - kfree(qsfp); -exit: - - return status; -} - -/* Platform dependent +++ */ -static int sfp_device_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct sfp_port_data *data = NULL; - - data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); - if (!data) { - return -ENOMEM; - } - - i2c_set_clientdata(client, data); - mutex_init(&data->update_lock); - data->port = dev_id->driver_data; - data->client = client; - - if (dev_id->driver_data >= as5916_54xk_sfp1 && dev_id->driver_data <= as5916_54xk_sfp48) { - if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { - data->driver_type = DRIVER_TYPE_SFP_MSA; - return sfp_msa_probe(client, dev_id, &data->msa); - } - else if (client->addr == SFP_EEPROM_A2_I2C_ADDR) { - data->driver_type = DRIVER_TYPE_SFP_DDM; - return sfp_ddm_probe(client, dev_id, &data->ddm); - } - } - else { /* as5916_54xk_sfp49 ~ as5916_54xk_sfp54 */ - if (client->addr == SFP_EEPROM_A0_I2C_ADDR) { - data->driver_type = DRIVER_TYPE_QSFP; - return qsfp_probe(client, dev_id, &data->qsfp); - } - } - - return -ENODEV; -} -/* Platform dependent --- */ - -static int sfp_msa_remove(struct i2c_client *client, struct sfp_msa_data *data) -{ - sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); - sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); - kfree(data); - return 0; -} - -static int sfp_ddm_remove(struct i2c_client *client, struct sfp_ddm_data *data) -{ - sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); - sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); - kfree(data); - return 0; -} - -static int qfp_remove(struct i2c_client *client, struct qsfp_data *data) -{ - sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); - sysfs_remove_group(&client->dev.kobj, &qsfp_group); - kfree(data); - return 0; -} - -static int sfp_device_remove(struct i2c_client *client) -{ - struct sfp_port_data *data = i2c_get_clientdata(client); - - switch (data->driver_type) { - case DRIVER_TYPE_SFP_MSA: - return sfp_msa_remove(client, data->msa); - case DRIVER_TYPE_SFP_DDM: - return sfp_ddm_remove(client, data->ddm); - case DRIVER_TYPE_QSFP: - return qfp_remove(client, data->qsfp); - } - - return 0; -} - -/* Addresses scanned - */ -static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; - -static struct i2c_driver sfp_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = sfp_device_probe, - .remove = sfp_device_remove, - .id_table = sfp_device_id, - .address_list = normal_i2c, -}; - -static int __init sfp_init(void) -{ - return i2c_add_driver(&sfp_driver); -} - -static void __exit sfp_exit(void) -{ - i2c_del_driver(&sfp_driver); -} - -MODULE_AUTHOR("Brandon Chuang "); -MODULE_DESCRIPTION("accton as5916_54xk_sfp driver"); -MODULE_LICENSE("GPL"); - -late_initcall(sfp_init); -module_exit(sfp_exit); - - diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/onlp/builds/src/module/src/sfpi.c b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/onlp/builds/src/module/src/sfpi.c index f4d29904..4f7abdd1 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/onlp/builds/src/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/onlp/builds/src/module/src/sfpi.c @@ -24,17 +24,21 @@ * ***********************************************************/ #include +#include #include -#include "platform_lib.h" - +#include "x86_64_accton_as5916_54xk_int.h" #include "x86_64_accton_as5916_54xk_log.h" -#define NUM_OF_SFP_PORT 54 -#define MAX_PORT_PATH 64 +#define PORT_BUS_INDEX(port) (port+33) -#define SFP_PORT_FORMAT "/sys/bus/i2c/devices/%d-0050/%s" -#define SFP_PORT_DOM_FORMAT "/sys/bus/i2c/devices/%d-0051/%s" -#define SFP_BUS_INDEX(port) (port+33) +#define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" +#define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_present_%d" +#define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_rx_los_%d" +#define MODULE_TXFAULT_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_fault_%d" +#define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_disable_%d" +#define MODULE_PRESENT_ALL_ATTR "/sys/bus/i2c/devices/%d-00%d/module_present_all" +#define MODULE_RXLOS_ALL_ATTR_CPLD1 "/sys/bus/i2c/devices/11-0060/module_rx_los_all" +#define MODULE_RXLOS_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/12-0062/module_rx_los_all" /************************************************************ * @@ -56,7 +60,7 @@ onlp_sfpi_bitmap_get(onlp_sfp_bitmap_t* bmap) */ int p; - for(p = 0; p < NUM_OF_SFP_PORT; p++) { + for(p = 0; p < 54; p++) { AIM_BITMAP_SET(bmap, p); } @@ -72,7 +76,12 @@ onlp_sfpi_is_present(int port) * Return < 0 if error. */ int present; - if (onlp_file_read_int(&present, SFP_PORT_FORMAT, SFP_BUS_INDEX(port), "sfp_is_present") < 0) { + int bus, addr; + + addr = (port < 24) ? 60 : 62; + bus = (addr == 60) ? 11 : 12; + + if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, bus, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -83,31 +92,45 @@ onlp_sfpi_is_present(int port) int onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) { - uint32_t bytes[7]; - char path[MAX_PORT_PATH] = {0}; + uint32_t bytes[7], *ptr = NULL; FILE* fp; + int addr; - sprintf(path, SFP_PORT_FORMAT, SFP_BUS_INDEX(0), "sfp_is_present_all"); - fp = fopen(path, "r"); + ptr = bytes; - if(fp == NULL) { - AIM_LOG_ERROR("Unable to open the sfp_is_present_all device file."); - return ONLP_STATUS_E_INTERNAL; - } - int count = fscanf(fp, "%x %x %x %x %x %x %x", - bytes+0, - bytes+1, - bytes+2, - bytes+3, - bytes+4, - bytes+5, - bytes+6 - ); - fclose(fp); - if(count != AIM_ARRAYSIZE(bytes)) { - /* Likely a CPLD read timeout. */ - AIM_LOG_ERROR("Unable to read all fields from the sfp_is_present_all device file."); - return ONLP_STATUS_E_INTERNAL; + for (addr = 60; addr <= 62; addr+=2) { + /* Read present status of port 0~53 */ + int count = 0; + char file[64] = {0}; + int bus = (addr == 60) ? 11 : 12; + + sprintf(file, MODULE_PRESENT_ALL_ATTR, bus, addr); + fp = fopen(file, "r"); + if(fp == NULL) { + AIM_LOG_ERROR("Unable to open the module_present_all device file of CPLD(0x%d).", addr); + return ONLP_STATUS_E_INTERNAL; + } + + if (addr == 60) { /* CPLD1 */ + count = fscanf(fp, "%x %x %x", ptr+0, ptr+1, ptr+2); + fclose(fp); + if(count != 3) { + /* Likely a CPLD read timeout. */ + AIM_LOG_ERROR("Unable to read all fields the module_present_all device file of CPLD(0x%d).", addr); + return ONLP_STATUS_E_INTERNAL; + } + } + else { /* CPLD2 */ + count = fscanf(fp, "%x %x %x %x", ptr+0, ptr+1, ptr+2, ptr+3); + fclose(fp); + if(count != 4) { + /* Likely a CPLD read timeout. */ + AIM_LOG_ERROR("Unable to read all fields the module_present_all device file of CPLD(0x%d).", addr); + return ONLP_STATUS_E_INTERNAL; + } + } + + ptr += count; } /* Mask out non-existant QSFP ports */ @@ -130,64 +153,44 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) return ONLP_STATUS_OK; } -int -onlp_sfpi_eeprom_read(int port, uint8_t data[256]) -{ - int size = 0; - if(onlp_file_read(data, 256, &size, SFP_PORT_FORMAT, SFP_BUS_INDEX(port), "sfp_eeprom") == ONLP_STATUS_OK) { - if(size == 256) { - return ONLP_STATUS_OK; - } - } - - return ONLP_STATUS_E_INTERNAL; -} - -int -onlp_sfpi_dom_read(int port, uint8_t data[256]) -{ - int size = 0; - if(onlp_file_read(data, 256, &size, SFP_PORT_DOM_FORMAT, SFP_BUS_INDEX(port), "sfp_eeprom") == ONLP_STATUS_OK) { - if(size == 256) { - return ONLP_STATUS_OK; - } - } - - return ONLP_STATUS_E_INTERNAL; -} - int onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) { uint32_t bytes[6]; - char path[MAX_PORT_PATH] = {0}; + uint32_t *ptr = bytes; FILE* fp; - sprintf(path, SFP_PORT_FORMAT, SFP_BUS_INDEX(0), "sfp_rx_los_all"); - fp = fopen(path, "r"); + /* Read present status of port 0~23 */ + int addr, i = 0; - if(fp == NULL) { - AIM_LOG_ERROR("Unable to open the sfp_rx_los_all device file."); - return ONLP_STATUS_E_INTERNAL; - } - int count = fscanf(fp, "%x %x %x %x %x %x", - bytes+0, - bytes+1, - bytes+2, - bytes+3, - bytes+4, - bytes+5 - ); - fclose(fp); - if(count != 6) { - AIM_LOG_ERROR("Unable to read all fields from the sfp_rx_los_all device file."); - return ONLP_STATUS_E_INTERNAL; + for (addr = 60; addr <= 62; addr+=2) { + if (addr == 60) { + fp = fopen(MODULE_RXLOS_ALL_ATTR_CPLD1, "r"); + } + else { + fp = fopen(MODULE_RXLOS_ALL_ATTR_CPLD2, "r"); + } + + if(fp == NULL) { + AIM_LOG_ERROR("Unable to open the module_rx_los_all device file of CPLD(0x%d)", addr); + return ONLP_STATUS_E_INTERNAL; + } + + int count = fscanf(fp, "%x %x %x", ptr+0, ptr+1, ptr+2); + fclose(fp); + if(count != 3) { + /* Likely a CPLD read timeout. */ + AIM_LOG_ERROR("Unable to read all fields from the module_rx_los_all device file of CPLD(0x%d)", addr); + return ONLP_STATUS_E_INTERNAL; + } + + ptr += count; } /* Convert to 64 bit integer in port order */ - int i = 0; + i = 0; uint64_t rx_los_all = 0 ; - for(i = 5; i >= 0; i--) { + for(i = AIM_ARRAYSIZE(bytes)-1; i >= 0; i--) { rx_los_all <<= 8; rx_los_all |= bytes[i]; } @@ -201,16 +204,77 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst) 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, PORT_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, PORT_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_control_set(int port, onlp_sfp_control_t control, int value) { int rv; + if (port < 0 || port >= 48) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + int addr = (port < 24) ? 60 : 62; + int bus = (addr == 60) ? 11 : 12; + switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: { - if (onlp_file_write_int(value, SFP_PORT_FORMAT, SFP_BUS_INDEX(port), "sfp_tx_disable") != 0) { + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -233,12 +297,19 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { int rv; + if (port < 0 || port >= 48) { + return ONLP_STATUS_E_UNSUPPORTED; + } + + int addr = (port < 24) ? 60 : 62; + int bus = (addr == 60) ? 11 : 12; + switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { - if (onlp_file_read_int(value, SFP_PORT_FORMAT, SFP_BUS_INDEX(port), "sfp_rx_los") < 0) { - AIM_LOG_ERROR("Unable to read rx_los status from port(%d)\r\n", port); + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } else { @@ -249,7 +320,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_FAULT: { - if (onlp_file_read_int(value, SFP_PORT_FORMAT, SFP_BUS_INDEX(port), "sfp_tx_fault") < 0) { + if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, bus, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -261,7 +332,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_DISABLE: { - if (onlp_file_read_int(value, SFP_PORT_FORMAT, SFP_BUS_INDEX(port), "sfp_tx_disable") < 0) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } @@ -278,7 +349,6 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) return rv; } - int onlp_sfpi_denit(void) { diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/platform-config/r1/src/python/x86_64_accton_as5916_54xk_r1/__init__.py b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/platform-config/r1/src/python/x86_64_accton_as5916_54xk_r1/__init__.py index da17b4ea..dc4b3fe0 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/platform-config/r1/src/python/x86_64_accton_as5916_54xk_r1/__init__.py +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xk/platform-config/r1/src/python/x86_64_accton_as5916_54xk_r1/__init__.py @@ -8,9 +8,9 @@ class OnlPlatform_x86_64_accton_as5916_54xk_r1(OnlPlatformAccton, SYS_OBJECT_ID=".5916.54" def baseconfig(self): - self.insmod("accton_i2c_cpld") + self.insmod('optoe') self.insmod("ym2651y") - for m in [ "sfp", "psu", "fan", "leds" ]: + for m in [ "cpld", "psu", "fan", "leds" ]: self.insmod("x86-64-accton-as5916-54xk-%s" % m) ########### initialize I2C bus 0 ########### @@ -30,8 +30,8 @@ class OnlPlatform_x86_64_accton_as5916_54xk_r1(OnlPlatformAccton, ('lm75', 0x4b, 10), # initialize CPLDs - ('accton_i2c_cpld', 0x60, 11), - ('accton_i2c_cpld', 0x62, 12), + ('as5916_54xk_cpld1', 0x60, 11), + ('as5916_54xk_cpld2', 0x62, 12), # initialize multiplexer (PCA9548) ('pca9548', 0x74, 2), @@ -61,12 +61,14 @@ class OnlPlatform_x86_64_accton_as5916_54xk_r1(OnlPlatformAccton, # initialize SFP devices for port in range(1, 49): - self.new_i2c_device('as5916_54xk_sfp%d' % port, 0x50, port+32) - self.new_i2c_device('as5916_54xk_sfp%d' % port, 0x51, port+32) + self.new_i2c_device('optoe2', 0x50, port+32) # initialize QSFP devices for port in range(49, 55): - self.new_i2c_device('as5916_54xk_sfp%d' % port, 0x50, port+32) + self.new_i2c_device('optoe1', 0x50, port+32) + + for port in range(1, 55): + subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port, port+32), shell=True) return True From 3a19c91ef18c643547e19eafa55efc05595797a9 Mon Sep 17 00:00:00 2001 From: "charlie.hsu" Date: Thu, 2 Aug 2018 13:58:51 +0800 Subject: [PATCH 06/22] [Quanta][LY8] modify port name initial method 1. initial port_name in user-space(python) 2. change OOM driver to common module --- .../quanta/x86-64/modules/builds/optoe.c | 1154 ----------------- .../modules/builds/quanta_platform_ly8.c | 141 +- .../x86_64_quanta_ly8_rangeley_r0/__init__.py | 10 + 3 files changed, 64 insertions(+), 1241 deletions(-) delete mode 100644 packages/platforms/quanta/x86-64/modules/builds/optoe.c mode change 100644 => 100755 packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/modules/builds/quanta_platform_ly8.c mode change 100644 => 100755 packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/python/x86_64_quanta_ly8_rangeley_r0/__init__.py diff --git a/packages/platforms/quanta/x86-64/modules/builds/optoe.c b/packages/platforms/quanta/x86-64/modules/builds/optoe.c deleted file mode 100644 index 27d7ffbd..00000000 --- a/packages/platforms/quanta/x86-64/modules/builds/optoe.c +++ /dev/null @@ -1,1154 +0,0 @@ -/* - * optoe.c - A driver to read and write the EEPROM on optical transceivers - * (SFP, QSFP and similar I2C based devices) - * - * Copyright (C) 2014 Cumulus networks Inc. - * Copyright (C) 2017 Finisar Corp. - * Copyright (C) 2017 Quanta - * - * 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 Freeoftware Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* - * Description: - * a) Optical transceiver EEPROM read/write transactions are just like - * the at24 eeproms managed by the at24.c i2c driver - * b) The register/memory layout is up to 256 128 byte pages defined by - * a "pages valid" register and switched via a "page select" - * register as explained in below diagram. - * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 - * bytes of address space, and always references the same - * location, independent of the page select register. - * All mapped pages are mapped into the upper 128 bytes - * (offset 128-255) of the i2c address. - * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 - * (A0h in the spec), and map all pages in the upper 128 bytes - * of that address. - * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data - * at I2C address 0x50, and 256 bytes of data at I2C address - * 0x51 (A2h in the spec). Page selection and paged access - * only apply to this second I2C address (0x51). - * e) The address space is presented, by the driver, as a linear - * address space. For devices with one I2C client at address - * 0x50 (eg QSFP), offset 0-127 are in the lower - * half of address 50/A0h/client[0]. Offset 128-255 are in - * page 0, 256-383 are page 1, etc. More generally, offset - * 'n' resides in page (n/128)-1. ('page -1' is the lower - * half, offset 0-127). - * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), - * the address space places offset 0-127 in the lower - * half of 50/A0/client[0], offset 128-255 in the upper - * half. Offset 256-383 is in the lower half of 51/A2/client[1]. - * Offset 384-511 is in page 0, in the upper half of 51/A2/... - * Offset 512-639 is in page 1, in the upper half of 51/A2/... - * Offset 'n' is in page (n/128)-3 (for n > 383) - * - * One I2c addressed (eg QSFP) Memory Map - * - * 2-Wire Serial Address: 1010000x - * - * Lower Page 00h (128 bytes) - * ===================== - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * | | - * |Page Select Byte(127)| - * ===================== - * | - * | - * | - * | - * V - * ------------------------------------------------------------ - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * | | | | - * V V V V - * ------------ -------------- --------------- -------------- - * | | | | | | | | - * | Upper | | Upper | | Upper | | Upper | - * | Page 00h | | Page 01h | | Page 02h | | Page 03h | - * | | | (Optional) | | (Optional) | | (Optional | - * | | | | | | | for Cable | - * | | | | | | | Assemblies) | - * | ID | | AST | | User | | | - * | Fields | | Table | | EEPROM Data | | | - * | | | | | | | | - * | | | | | | | | - * | | | | | | | | - * ------------ -------------- --------------- -------------- - * - * The SFF 8436 (QSFP) spec only defines the 4 pages described above. - * In anticipation of future applications and devices, this driver - * supports access to the full architected range, 256 pages. - * - **/ - -/* #define DEBUG 1 */ - -#undef EEPROM_CLASS -#ifdef CONFIG_EEPROM_CLASS -#define EEPROM_CLASS -#endif -#ifdef CONFIG_EEPROM_CLASS_MODULE -#define EEPROM_CLASS -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef EEPROM_CLASS -#include -#endif - -#include - -/* - * The optoe driver is for read/write access to the EEPROM on standard - * I2C based optical transceivers (SFP, QSFP, etc) - * - * While based on the at24 driver, it eliminates code that supports other - * types of I2C EEPROMs, and adds support for pages accessed through the - * page-select register at offset 127. - */ - -struct optoe_platform_data { - u32 byte_len; /* size (sum of all addr) */ - u16 page_size; /* for writes */ - u8 flags; - - void (*setup)(struct memory_accessor *, void *context); - void *context; -#ifdef EEPROM_CLASS - struct eeprom_platform_data *eeprom_data; /* extra data for the eeprom_class */ -#endif - int oom_port_name; -}; - -/* fundamental unit of addressing for EEPROM */ -#define OPTOE_PAGE_SIZE 128 -/* - * Single address devices (eg QSFP) have 256 pages, plus the unpaged - * low 128 bytes. If the device does not support paging, it is - * only 2 'pages' long. - */ -#define OPTOE_ARCH_PAGES 256 -#define ONE_ADDR_EEPROM_SIZE ((1 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) -#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * OPTOE_PAGE_SIZE) -/* - * Dual address devices (eg SFP) have 256 pages, plus the unpaged - * low 128 bytes, plus 256 bytes at 0x50. If the device does not - * support paging, it is 4 'pages' long. - */ -#define TWO_ADDR_EEPROM_SIZE ((3 + OPTOE_ARCH_PAGES) * OPTOE_PAGE_SIZE) -#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * OPTOE_PAGE_SIZE) - -/* a few constants to find our way around the EEPROM */ -#define OPTOE_PAGE_SELECT_REG 0x7F -#define ONE_ADDR_PAGEABLE_REG 0x02 -#define ONE_ADDR_NOT_PAGEABLE (1<<2) -#define TWO_ADDR_PAGEABLE_REG 0x40 -#define TWO_ADDR_PAGEABLE (1<<4) -#define OPTOE_ID_REG 0 - -/* The maximum length of a port name */ -#define MAX_PORT_NAME_LEN 20 -struct optoe_data { - struct optoe_platform_data chip; - struct memory_accessor macc; - int use_smbus; - char port_name[MAX_PORT_NAME_LEN]; - - /* - * Lock protects against activities from other Linux tasks, - * but not from changes by other I2C masters. - */ - struct mutex lock; - struct bin_attribute bin; - struct attribute_group attr_group; - - u8 *writebuf; - unsigned write_max; - - unsigned num_addresses; - -#ifdef EEPROM_CLASS - struct eeprom_device *eeprom_dev; -#endif - - /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ - int dev_class; - - struct i2c_client *client[]; -}; - -typedef enum optoe_opcode { - OPTOE_READ_OP = 0, - OPTOE_WRITE_OP = 1 -} optoe_opcode_e; - -/* - * This parameter is to help this driver avoid blocking other drivers out - * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C - * clock, one 256 byte read takes about 1/43 second which is excessive; - * but the 1/170 second it takes at 400 kHz may be quite reasonable; and - * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. - * - * This value is forced to be a power of two so that writes align on pages. - */ -static unsigned io_limit = OPTOE_PAGE_SIZE; - -/* - * specs often allow 5 msec for a page write, sometimes 20 msec; - * it's important to recover from write timeouts. - */ -static unsigned write_timeout = 25; - -/* - * flags to distinguish one-address (QSFP family) from two-address (SFP family) - * If the family is not known, figure it out when the device is accessed - */ -#define ONE_ADDR 1 -#define TWO_ADDR 2 - -static const struct i2c_device_id optoe_ids[] = { - { "optoe1", ONE_ADDR }, - { "optoe2", TWO_ADDR }, - { "sff8436", ONE_ADDR }, - { "24c04", TWO_ADDR }, - { /* END OF LIST */ } -}; -MODULE_DEVICE_TABLE(i2c, optoe_ids); - -/*-------------------------------------------------------------------------*/ -/* - * This routine computes the addressing information to be used for - * a given r/w request. - * - * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), - * the page, and the offset. - * - * Handles both single address (eg QSFP) and two address (eg SFP). - * For SFP, offset 0-255 are on client[0], >255 is on client[1] - * Offset 256-383 are on the lower half of client[1] - * Pages are accessible on the upper half of client[1]. - * Offset >383 are in 128 byte pages mapped into the upper half - * - * For QSFP, all offsets are on client[0] - * offset 0-127 are on the lower half of client[0] (no paging) - * Pages are accessible on the upper half of client[1]. - * Offset >127 are in 128 byte pages mapped into the upper half - * - * Callers must not read/write beyond the end of a client or a page - * without recomputing the client/page. Hence offset (within page) - * plus length must be less than or equal to 128. (Note that this - * routine does not have access to the length of the call, hence - * cannot do the validity check.) - * - * Offset within Lower Page 00h and Upper Page 00h are not recomputed - */ - -static uint8_t optoe_translate_offset(struct optoe_data *optoe, - loff_t *offset, struct i2c_client **client) -{ - unsigned page = 0; - - *client = optoe->client[0]; - - /* if SFP style, offset > 255, shift to i2c addr 0x51 */ - if (optoe->dev_class == TWO_ADDR) { - if (*offset > 255) { - /* like QSFP, but shifted to client[1] */ - *client = optoe->client[1]; - *offset -= 256; - } - } - - /* - * if offset is in the range 0-128... - * page doesn't matter (using lower half), return 0. - * offset is already correct (don't add 128 to get to paged area) - */ - if (*offset < OPTOE_PAGE_SIZE) - return page; - - /* note, page will always be positive since *offset >= 128 */ - page = (*offset >> 7)-1; - /* 0x80 places the offset in the top half, offset is last 7 bits */ - *offset = OPTOE_PAGE_SIZE + (*offset & 0x7f); - - return page; /* note also returning client and offset */ -} - -static ssize_t optoe_eeprom_read(struct optoe_data *optoe, - struct i2c_client *client, - char *buf, unsigned offset, size_t count) -{ - struct i2c_msg msg[2]; - u8 msgbuf[2]; - unsigned long timeout, read_time; - int status, i; - - memset(msg, 0, sizeof(msg)); - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - /*smaller eeproms can work given some SMBus extension calls */ - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; - break; - case I2C_SMBUS_WORD_DATA: - /* Check for odd length transaction */ - count = (count == 1) ? 1 : 2; - break; - case I2C_SMBUS_BYTE_DATA: - count = 1; - break; - default: - /* - * When we have a better choice than SMBus calls, use a - * combined I2C message. Write address; then read up to - * io_limit data bytes. msgbuf is u8 and will cast to our - * needs. - */ - i = 0; - msgbuf[i++] = offset; - - msg[0].addr = client->addr; - msg[0].buf = msgbuf; - msg[0].len = i; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].buf = buf; - msg[1].len = count; - } - - /* - * Reads fail if the previous write didn't complete yet. We may - * loop a few times until this one succeeds, waiting at least - * long enough for one entire page write to work. - */ - timeout = jiffies + msecs_to_jiffies(write_timeout); - do { - read_time = jiffies; - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - status = i2c_smbus_read_i2c_block_data(client, offset, - count, buf); - break; - case I2C_SMBUS_WORD_DATA: - status = i2c_smbus_read_word_data(client, offset); - if (status >= 0) { - buf[0] = status & 0xff; - if (count == 2) - buf[1] = status >> 8; - status = count; - } - break; - case I2C_SMBUS_BYTE_DATA: - status = i2c_smbus_read_byte_data(client, offset); - if (status >= 0) { - buf[0] = status; - status = count; - } - break; - default: - status = i2c_transfer(client->adapter, msg, 2); - if (status == 2) - status = count; - } - - dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", - count, offset, status, jiffies); - - if (status == count) /* happy path */ - return count; - - if (status == -ENXIO) /* no module present */ - return status; - - /* REVISIT: at HZ=100, this is sloooow */ - msleep(1); - } while (time_before(read_time, timeout)); - - return -ETIMEDOUT; -} - -static ssize_t optoe_eeprom_write(struct optoe_data *optoe, - struct i2c_client *client, - const char *buf, - unsigned offset, size_t count) -{ - struct i2c_msg msg; - ssize_t status; - unsigned long timeout, write_time; - unsigned next_page_start; - int i = 0; - - /* write max is at most a page - * (In this driver, write_max is actually one byte!) - */ - if (count > optoe->write_max) - count = optoe->write_max; - - /* shorten count if necessary to avoid crossing page boundary */ - next_page_start = roundup(offset + 1, OPTOE_PAGE_SIZE); - if (offset + count > next_page_start) - count = next_page_start - offset; - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - /*smaller eeproms can work given some SMBus extension calls */ - if (count > I2C_SMBUS_BLOCK_MAX) - count = I2C_SMBUS_BLOCK_MAX; - break; - case I2C_SMBUS_WORD_DATA: - /* Check for odd length transaction */ - count = (count == 1) ? 1 : 2; - break; - case I2C_SMBUS_BYTE_DATA: - count = 1; - break; - default: - /* If we'll use I2C calls for I/O, set up the message */ - msg.addr = client->addr; - msg.flags = 0; - - /* msg.buf is u8 and casts will mask the values */ - msg.buf = optoe->writebuf; - - msg.buf[i++] = offset; - memcpy(&msg.buf[i], buf, count); - msg.len = i + count; - break; - } - - /* - * Reads fail if the previous write didn't complete yet. We may - * loop a few times until this one succeeds, waiting at least - * long enough for one entire page write to work. - */ - timeout = jiffies + msecs_to_jiffies(write_timeout); - do { - write_time = jiffies; - - switch (optoe->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - status = i2c_smbus_write_i2c_block_data(client, - offset, count, buf); - if (status == 0) - status = count; - break; - case I2C_SMBUS_WORD_DATA: - if (count == 2) { - status = i2c_smbus_write_word_data(client, - offset, (u16)((buf[0])|(buf[1] << 8))); - } else { - /* count = 1 */ - status = i2c_smbus_write_byte_data(client, - offset, buf[0]); - } - if (status == 0) - status = count; - break; - case I2C_SMBUS_BYTE_DATA: - status = i2c_smbus_write_byte_data(client, offset, - buf[0]); - if (status == 0) - status = count; - break; - default: - status = i2c_transfer(client->adapter, &msg, 1); - if (status == 1) - status = count; - break; - } - - dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", - count, offset, (long int) status, jiffies); - - if (status == count) - return count; - - /* REVISIT: at HZ=100, this is sloooow */ - msleep(1); - } while (time_before(write_time, timeout)); - - return -ETIMEDOUT; -} - - -static ssize_t optoe_eeprom_update_client(struct optoe_data *optoe, - char *buf, loff_t off, - size_t count, optoe_opcode_e opcode) -{ - struct i2c_client *client; - ssize_t retval = 0; - uint8_t page = 0; - loff_t phy_offset = off; - int ret = 0; - - page = optoe_translate_offset(optoe, &phy_offset, &client); - dev_dbg(&client->dev, - "optoe_eeprom_update_client off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", - off, page, phy_offset, (long int) count, opcode); - if (page > 0) { - ret = optoe_eeprom_write(optoe, client, &page, - OPTOE_PAGE_SELECT_REG, 1); - if (ret < 0) { - dev_dbg(&client->dev, - "Write page register for page %d failed ret:%d!\n", - page, ret); - return ret; - } - } - - while (count) { - ssize_t status; - - if (opcode == OPTOE_READ_OP) { - status = optoe_eeprom_read(optoe, client, - buf, phy_offset, count); - } else { - status = optoe_eeprom_write(optoe, client, - buf, phy_offset, count); - } - if (status <= 0) { - if (retval == 0) - retval = status; - break; - } - buf += status; - phy_offset += status; - count -= status; - retval += status; - } - - - if (page > 0) { - /* return the page register to page 0 (why?) */ - page = 0; - ret = optoe_eeprom_write(optoe, client, &page, - OPTOE_PAGE_SELECT_REG, 1); - if (ret < 0) { - dev_err(&client->dev, - "Restore page register to 0 failed:%d!\n", ret); - /* error only if nothing has been transferred */ - if (retval == 0) retval = ret; - } - } - return retval; -} - -/* - * Figure out if this access is within the range of supported pages. - * Note this is called on every access because we don't know if the - * module has been replaced since the last call. - * If/when modules support more pages, this is the routine to update - * to validate and allow access to additional pages. - * - * Returns updated len for this access: - * - entire access is legal, original len is returned. - * - access begins legal but is too long, len is truncated to fit. - * - initial offset exceeds supported pages, return -EINVAL - */ -static ssize_t optoe_page_legal(struct optoe_data *optoe, - loff_t off, size_t len) -{ - struct i2c_client *client = optoe->client[0]; - u8 regval; - int status; - size_t maxlen; - - if (off < 0) return -EINVAL; - if (optoe->dev_class == TWO_ADDR) { - /* SFP case */ - /* if no pages needed, we're good */ - if ((off + len) <= TWO_ADDR_EEPROM_UNPAGED_SIZE) return len; - /* if offset exceeds possible pages, we're not good */ - if (off >= TWO_ADDR_EEPROM_SIZE) return -EINVAL; - /* in between, are pages supported? */ - status = optoe_eeprom_read(optoe, client, ®val, - TWO_ADDR_PAGEABLE_REG, 1); - if (status < 0) return status; /* error out (no module?) */ - if (regval & TWO_ADDR_PAGEABLE) { - /* Pages supported, trim len to the end of pages */ - maxlen = TWO_ADDR_EEPROM_SIZE - off; - } else { - /* pages not supported, trim len to unpaged size */ - if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) return -EINVAL; - maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; - } - len = (len > maxlen) ? maxlen : len; - dev_dbg(&client->dev, - "page_legal, SFP, off %lld len %ld\n", - off, (long int) len); - } else { - /* QSFP case */ - /* if no pages needed, we're good */ - if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) return len; - /* if offset exceeds possible pages, we're not good */ - if (off >= ONE_ADDR_EEPROM_SIZE) return -EINVAL; - /* in between, are pages supported? */ - status = optoe_eeprom_read(optoe, client, ®val, - ONE_ADDR_PAGEABLE_REG, 1); - if (status < 0) return status; /* error out (no module?) */ - if (regval & ONE_ADDR_NOT_PAGEABLE) { - /* pages not supported, trim len to unpaged size */ - if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) return -EINVAL; - maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; - } else { - /* Pages supported, trim len to the end of pages */ - maxlen = ONE_ADDR_EEPROM_SIZE - off; - } - len = (len > maxlen) ? maxlen : len; - dev_dbg(&client->dev, - "page_legal, QSFP, off %lld len %ld\n", - off, (long int) len); - } - return len; -} - -static ssize_t optoe_read_write(struct optoe_data *optoe, - char *buf, loff_t off, size_t len, optoe_opcode_e opcode) -{ - struct i2c_client *client = optoe->client[0]; - int chunk; - int status = 0; - ssize_t retval; - size_t pending_len = 0, chunk_len = 0; - loff_t chunk_offset = 0, chunk_start_offset = 0; - - dev_dbg(&client->dev, - "optoe_read_write: off %lld len:%ld, opcode:%s\n", - off, (long int) len, (opcode == OPTOE_READ_OP) ? "r": "w"); - if (unlikely(!len)) - return len; - - /* - * Read data from chip, protecting against concurrent updates - * from this host, but not from other I2C masters. - */ - mutex_lock(&optoe->lock); - - /* - * Confirm this access fits within the device suppored addr range - */ - status = optoe_page_legal(optoe, off, len); - if (status < 0) { - goto err; - } - len = status; - - /* - * For each (128 byte) chunk involved in this request, issue a - * separate call to sff_eeprom_update_client(), to - * ensure that each access recalculates the client/page - * and writes the page register as needed. - * Note that chunk to page mapping is confusing, is different for - * QSFP and SFP, and never needs to be done. Don't try! - */ - pending_len = len; /* amount remaining to transfer */ - retval = 0; /* amount transferred */ - for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { - - /* - * Compute the offset and number of bytes to be read/write - * - * 1. start at offset 0 (within the chunk), and read/write - * the entire chunk - * 2. start at offset 0 (within the chunk) and read/write less - * than entire chunk - * 3. start at an offset not equal to 0 and read/write the rest - * of the chunk - * 4. start at an offset not equal to 0 and read/write less than - * (end of chunk - offset) - */ - chunk_start_offset = chunk * OPTOE_PAGE_SIZE; - - if (chunk_start_offset < off) { - chunk_offset = off; - if ((off + pending_len) < (chunk_start_offset + - OPTOE_PAGE_SIZE)) - chunk_len = pending_len; - else - chunk_len = OPTOE_PAGE_SIZE - off; - } else { - chunk_offset = chunk_start_offset; - if (pending_len > OPTOE_PAGE_SIZE) - chunk_len = OPTOE_PAGE_SIZE; - else - chunk_len = pending_len; - } - - dev_dbg(&client->dev, - "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", - off, (long int) len, chunk_start_offset, chunk_offset, - (long int) chunk_len, (long int) pending_len); - - /* - * note: chunk_offset is from the start of the EEPROM, - * not the start of the chunk - */ - status = optoe_eeprom_update_client(optoe, buf, - chunk_offset, chunk_len, opcode); - if (status != chunk_len) { - /* This is another 'no device present' path */ - dev_dbg(&client->dev, - "optoe_update_client for chunk %d chunk_offset %lld chunk_len %ld failed %d!\n", - chunk, chunk_offset, (long int) chunk_len, status); - goto err; - } - buf += status; - pending_len -= status; - retval += status; - } - mutex_unlock(&optoe->lock); - - return retval; - -err: - mutex_unlock(&optoe->lock); - - return status; -} - -static ssize_t optoe_bin_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, - struct device, kobj)); - struct optoe_data *optoe = i2c_get_clientdata(client); - - return optoe_read_write(optoe, buf, off, count, OPTOE_READ_OP); -} - - -static ssize_t optoe_bin_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct i2c_client *client = to_i2c_client(container_of(kobj, - struct device, kobj)); - struct optoe_data *optoe = i2c_get_clientdata(client); - - return optoe_read_write(optoe, buf, off, count, OPTOE_WRITE_OP); -} -/*-------------------------------------------------------------------------*/ - -/* - * This lets other kernel code access the eeprom data. For example, it - * might hold a board's Ethernet address, or board-specific calibration - * data generated on the manufacturing floor. - */ - -static ssize_t optoe_macc_read(struct memory_accessor *macc, - char *buf, off_t offset, size_t count) -{ - struct optoe_data *optoe = container_of(macc, - struct optoe_data, macc); - - return optoe_read_write(optoe, buf, offset, count, OPTOE_READ_OP); -} - -static ssize_t optoe_macc_write(struct memory_accessor *macc, - const char *buf, off_t offset, size_t count) -{ - struct optoe_data *optoe = container_of(macc, - struct optoe_data, macc); - - return optoe_read_write(optoe, (char *) buf, offset, - count, OPTOE_WRITE_OP); -} - -/*-------------------------------------------------------------------------*/ - -static int optoe_remove(struct i2c_client *client) -{ - struct optoe_data *optoe; - int i; - - optoe = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); - sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); - - for (i = 1; i < optoe->num_addresses; i++) - i2c_unregister_device(optoe->client[i]); - -#ifdef EEPROM_CLASS - eeprom_device_unregister(optoe->eeprom_dev); -#endif - - kfree(optoe->writebuf); - kfree(optoe); - return 0; -} - -static ssize_t show_port_name(struct device *dev, - struct device_attribute *dattr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - ssize_t count; - - mutex_lock(&optoe->lock); - count = sprintf(buf, "%s\n", optoe->port_name); - mutex_unlock(&optoe->lock); - - return count; -} - -static ssize_t set_port_name(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - char port_name[MAX_PORT_NAME_LEN]; - - /* no checking, this value is not used except by show_port_name */ - - if (sscanf(buf, "%19s", port_name) != 1) - return -EINVAL; - - mutex_lock(&optoe->lock); - strcpy(optoe->port_name, port_name); - mutex_unlock(&optoe->lock); - - return count; -} - -static DEVICE_ATTR(port_name, S_IRUGO | S_IWUSR, - show_port_name, set_port_name); - -static ssize_t show_dev_class(struct device *dev, - struct device_attribute *dattr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - ssize_t count; - - mutex_lock(&optoe->lock); - count = sprintf(buf, "%d\n", optoe->dev_class); - mutex_unlock(&optoe->lock); - - return count; -} - -static ssize_t set_dev_class(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct optoe_data *optoe = i2c_get_clientdata(client); - int dev_class; - - /* - * dev_class is actually the number of sfp ports used, thus - * legal values are "1" (QSFP class) and "2" (SFP class) - */ - if (sscanf(buf, "%d", &dev_class) != 1 || - dev_class < 1 || dev_class > 2) - return -EINVAL; - - mutex_lock(&optoe->lock); - optoe->dev_class = dev_class; - mutex_unlock(&optoe->lock); - - return count; -} - -static DEVICE_ATTR(dev_class, S_IRUGO | S_IWUSR, - show_dev_class, set_dev_class); - -static struct attribute *optoe_attrs[] = { - &dev_attr_port_name.attr, - &dev_attr_dev_class.attr, - NULL, -}; - -static struct attribute_group optoe_attr_group = { - .attrs = optoe_attrs, -}; - -static int optoe_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err; - int use_smbus = 0; - struct optoe_platform_data chip; - struct optoe_data *optoe; - int num_addresses = 0; - int i = 0; - - if (client->addr != 0x50) { - dev_dbg(&client->dev, "probe, bad i2c addr: 0x%x\n", - client->addr); - err = -EINVAL; - goto exit; - } - - if (client->dev.platform_data) { - chip = *(struct optoe_platform_data *)client->dev.platform_data; - dev_dbg(&client->dev, "probe, chip provided, flags:0x%x; name: %s\n", chip.flags, client->name); - } else { - if (!id->driver_data) { - err = -ENODEV; - goto exit; - } - dev_dbg(&client->dev, "probe, building chip\n"); - chip.flags = 0; - chip.setup = NULL; - chip.context = NULL; -#ifdef EEPROM_CLASS - chip.eeprom_data = NULL; -#endif - } - - /* Use I2C operations unless we're stuck with SMBus extensions. */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_WORD_DATA)) { - use_smbus = I2C_SMBUS_WORD_DATA; - } else if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA)) { - use_smbus = I2C_SMBUS_BYTE_DATA; - } else { - err = -EPFNOSUPPORT; - goto exit; - } - } - - - /* - * Make room for two i2c clients - */ - num_addresses = 2; - - optoe = kzalloc(sizeof(struct optoe_data) + - num_addresses * sizeof(struct i2c_client *), - GFP_KERNEL); - if (!optoe) { - err = -ENOMEM; - goto exit; - } - - mutex_init(&optoe->lock); - - /* determine whether this is a one-address or two-address module */ - if ((strcmp(client->name, "optoe1") == 0) || - (strcmp(client->name, "sff8436") == 0)) { - /* one-address (eg QSFP) family */ - optoe->dev_class = ONE_ADDR; - chip.byte_len = ONE_ADDR_EEPROM_SIZE; - num_addresses = 1; - } else if ((strcmp(client->name, "optoe2") == 0) || - (strcmp(client->name, "24c04") == 0)) { - /* SFP family */ - optoe->dev_class = TWO_ADDR; - chip.byte_len = TWO_ADDR_EEPROM_SIZE; - } else { /* those were the only two choices */ - err = -EINVAL; - goto exit; - } - - dev_dbg(&client->dev, "dev_class: %d\n", optoe->dev_class); - optoe->use_smbus = use_smbus; - optoe->chip = chip; - optoe->num_addresses = num_addresses; - - /* - * Use platform data to initial port name. - * Original port name is unitialized: strcpy(optoe->port_name, "unitialized"); - */ - sprintf(optoe->port_name, "%d", chip.oom_port_name); - - /* - * Export the EEPROM bytes through sysfs, since that's convenient. - * By default, only root should see the data (maybe passwords etc) - */ - sysfs_bin_attr_init(&optoe->bin); - optoe->bin.attr.name = "eeprom"; - optoe->bin.attr.mode = S_IRUGO; - optoe->bin.read = optoe_bin_read; - optoe->bin.size = chip.byte_len; - - optoe->macc.read = optoe_macc_read; - - if (!use_smbus || - (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_WORD_DATA) || - i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { - /* - * NOTE: AN-2079 - * Finisar recommends that the host implement 1 byte writes - * only since this module only supports 32 byte page boundaries. - * 2 byte writes are acceptable for PE and Vout changes per - * Application Note AN-2071. - */ - unsigned write_max = 1; - - optoe->macc.write = optoe_macc_write; - - optoe->bin.write = optoe_bin_write; - optoe->bin.attr.mode |= S_IWUSR; - - if (write_max > io_limit) - write_max = io_limit; - if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) - write_max = I2C_SMBUS_BLOCK_MAX; - optoe->write_max = write_max; - - /* buffer (data + address at the beginning) */ - optoe->writebuf = kmalloc(write_max + 2, GFP_KERNEL); - if (!optoe->writebuf) { - err = -ENOMEM; - goto exit_kfree; - } - } else { - dev_warn(&client->dev, - "cannot write due to controller restrictions."); - } - - optoe->client[0] = client; - - /* use a dummy I2C device for two-address chips */ - for (i = 1; i < num_addresses; i++) { - optoe->client[i] = i2c_new_dummy(client->adapter, - client->addr + i); - if (!optoe->client[i]) { - dev_err(&client->dev, "address 0x%02x unavailable\n", - client->addr + i); - err = -EADDRINUSE; - goto err_struct; - } - } - - /* create the sysfs eeprom file */ - err = sysfs_create_bin_file(&client->dev.kobj, &optoe->bin); - if (err) - goto err_struct; - - optoe->attr_group = optoe_attr_group; - - err = sysfs_create_group(&client->dev.kobj, &optoe->attr_group); - if (err) { - dev_err(&client->dev, "failed to create sysfs attribute group.\n"); - goto err_struct; - } -#ifdef EEPROM_CLASS - optoe->eeprom_dev = eeprom_device_register(&client->dev, - chip.eeprom_data); - if (IS_ERR(optoe->eeprom_dev)) { - dev_err(&client->dev, "error registering eeprom device.\n"); - err = PTR_ERR(optoe->eeprom_dev); - goto err_sysfs_cleanup; - } -#endif - - i2c_set_clientdata(client, optoe); - - dev_info(&client->dev, "%zu byte %s EEPROM, %s\n", - optoe->bin.size, client->name, - optoe->bin.write ? "read/write" : "read-only"); - - if (use_smbus == I2C_SMBUS_WORD_DATA || - use_smbus == I2C_SMBUS_BYTE_DATA) { - dev_notice(&client->dev, "Falling back to %s reads, " - "performance will suffer\n", use_smbus == - I2C_SMBUS_WORD_DATA ? "word" : "byte"); - } - - if (chip.setup) - chip.setup(&optoe->macc, chip.context); - - return 0; - -#ifdef EEPROM_CLASS -err_sysfs_cleanup: - sysfs_remove_group(&client->dev.kobj, &optoe->attr_group); - sysfs_remove_bin_file(&client->dev.kobj, &optoe->bin); -#endif - -err_struct: - for (i = 1; i < num_addresses; i++) { - if (optoe->client[i]) - i2c_unregister_device(optoe->client[i]); - } - - kfree(optoe->writebuf); -exit_kfree: - kfree(optoe); -exit: - dev_dbg(&client->dev, "probe error %d\n", err); - - return err; -} - -/*-------------------------------------------------------------------------*/ - -static struct i2c_driver optoe_driver = { - .driver = { - .name = "optoe", - .owner = THIS_MODULE, - }, - .probe = optoe_probe, - .remove = optoe_remove, - .id_table = optoe_ids, -}; - -static int __init optoe_init(void) -{ - - if (!io_limit) { - pr_err("optoe: io_limit must not be 0!\n"); - return -EINVAL; - } - - io_limit = rounddown_pow_of_two(io_limit); - return i2c_add_driver(&optoe_driver); -} -module_init(optoe_init); - -static void __exit optoe_exit(void) -{ - i2c_del_driver(&optoe_driver); -} -module_exit(optoe_exit); - -MODULE_DESCRIPTION("Driver for optical transceiver (SFP, QSFP, ...) EEPROMs"); -MODULE_AUTHOR("Jonathan Tsai "); -MODULE_LICENSE("GPL"); diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/modules/builds/quanta_platform_ly8.c b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/modules/builds/quanta_platform_ly8.c old mode 100644 new mode 100755 index d7e12b68..66018dde --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/modules/builds/quanta_platform_ly8.c +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/modules/builds/quanta_platform_ly8.c @@ -78,7 +78,6 @@ struct i2c_init_data { int busno; int gpio_base; char name[I2C_NAME_SIZE]; - int oom_port_name; }; static struct i2c_init_data quanta_ly8_i2c_init_data[] = { @@ -99,54 +98,54 @@ static struct i2c_init_data quanta_ly8_i2c_init_data[] = { { .parent_bus = (0x10 + 0), .type = i2c_type_pca9554, .addr = 0x25, .name = "PCA9554(PCA9698INT)\0" }, { .parent_bus = (0x10 + 0), .type = i2c_type_pca9555, .addr = 0x24, .name = "PCA9555_3(FAN)\0" }, { .parent_bus = (0x10 + 0), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555_4(QSFP_EN)\0" }, - { .parent_bus = (0x20 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_1_EEPROM\0", .oom_port_name = 1 }, - { .parent_bus = (0x20 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_2_EEPROM\0", .oom_port_name = 2 }, - { .parent_bus = (0x20 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_3_EEPROM\0", .oom_port_name = 3 }, - { .parent_bus = (0x20 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_4_EEPROM\0", .oom_port_name = 4 }, - { .parent_bus = (0x20 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_5_EEPROM\0", .oom_port_name = 5 }, - { .parent_bus = (0x20 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_6_EEPROM\0", .oom_port_name = 6 }, - { .parent_bus = (0x20 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_7_EEPROM\0", .oom_port_name = 7 }, - { .parent_bus = (0x20 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_8_EEPROM\0", .oom_port_name = 8 }, - { .parent_bus = (0x28 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_9_EEPROM\0", .oom_port_name = 9 }, - { .parent_bus = (0x28 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_10_EEPROM\0", .oom_port_name = 10 }, - { .parent_bus = (0x28 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_11_EEPROM\0", .oom_port_name = 11 }, - { .parent_bus = (0x28 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_12_EEPROM\0", .oom_port_name = 12 }, - { .parent_bus = (0x28 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_13_EEPROM\0", .oom_port_name = 13 }, - { .parent_bus = (0x28 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_14_EEPROM\0", .oom_port_name = 14 }, - { .parent_bus = (0x28 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_15_EEPROM\0", .oom_port_name = 15 }, - { .parent_bus = (0x28 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_16_EEPROM\0", .oom_port_name = 16 }, - { .parent_bus = (0x30 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_17_EEPROM\0", .oom_port_name = 17 }, - { .parent_bus = (0x30 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_18_EEPROM\0", .oom_port_name = 18 }, - { .parent_bus = (0x30 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_19_EEPROM\0", .oom_port_name = 19 }, - { .parent_bus = (0x30 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_20_EEPROM\0", .oom_port_name = 20 }, - { .parent_bus = (0x30 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_21_EEPROM\0", .oom_port_name = 21 }, - { .parent_bus = (0x30 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_22_EEPROM\0", .oom_port_name = 22 }, - { .parent_bus = (0x30 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_23_EEPROM\0", .oom_port_name = 23 }, - { .parent_bus = (0x30 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_24_EEPROM\0", .oom_port_name = 24 }, - { .parent_bus = (0x38 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_25_EEPROM\0", .oom_port_name = 25 }, - { .parent_bus = (0x38 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_26_EEPROM\0", .oom_port_name = 26 }, - { .parent_bus = (0x38 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_27_EEPROM\0", .oom_port_name = 27 }, - { .parent_bus = (0x38 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_28_EEPROM\0", .oom_port_name = 28 }, - { .parent_bus = (0x38 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_29_EEPROM\0", .oom_port_name = 29 }, - { .parent_bus = (0x38 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_30_EEPROM\0", .oom_port_name = 30 }, - { .parent_bus = (0x38 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_31_EEPROM\0", .oom_port_name = 31 }, - { .parent_bus = (0x38 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_32_EEPROM\0", .oom_port_name = 32 }, - { .parent_bus = (0x40 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_33_EEPROM\0", .oom_port_name = 33 }, - { .parent_bus = (0x40 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_34_EEPROM\0", .oom_port_name = 34 }, - { .parent_bus = (0x40 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_35_EEPROM\0", .oom_port_name = 35 }, - { .parent_bus = (0x40 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_36_EEPROM\0", .oom_port_name = 36 }, - { .parent_bus = (0x40 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_37_EEPROM\0", .oom_port_name = 37 }, - { .parent_bus = (0x40 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_38_EEPROM\0", .oom_port_name = 38 }, - { .parent_bus = (0x40 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_39_EEPROM\0", .oom_port_name = 39 }, - { .parent_bus = (0x40 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_40_EEPROM\0", .oom_port_name = 40 }, - { .parent_bus = (0x48 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_41_EEPROM\0", .oom_port_name = 41 }, - { .parent_bus = (0x48 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_42_EEPROM\0", .oom_port_name = 42 }, - { .parent_bus = (0x48 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_43_EEPROM\0", .oom_port_name = 43 }, - { .parent_bus = (0x48 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_44_EEPROM\0", .oom_port_name = 44 }, - { .parent_bus = (0x48 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_45_EEPROM\0", .oom_port_name = 45 }, - { .parent_bus = (0x48 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_46_EEPROM\0", .oom_port_name = 46 }, - { .parent_bus = (0x48 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_47_EEPROM\0", .oom_port_name = 47 }, - { .parent_bus = (0x48 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_48_EEPROM\0", .oom_port_name = 48 }, + { .parent_bus = (0x20 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_1_EEPROM\0" }, + { .parent_bus = (0x20 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_2_EEPROM\0" }, + { .parent_bus = (0x20 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_3_EEPROM\0" }, + { .parent_bus = (0x20 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_4_EEPROM\0" }, + { .parent_bus = (0x20 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_5_EEPROM\0" }, + { .parent_bus = (0x20 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_6_EEPROM\0" }, + { .parent_bus = (0x20 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_7_EEPROM\0" }, + { .parent_bus = (0x20 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_8_EEPROM\0" }, + { .parent_bus = (0x28 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_9_EEPROM\0" }, + { .parent_bus = (0x28 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_10_EEPROM\0" }, + { .parent_bus = (0x28 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_11_EEPROM\0" }, + { .parent_bus = (0x28 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_12_EEPROM\0" }, + { .parent_bus = (0x28 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_13_EEPROM\0" }, + { .parent_bus = (0x28 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_14_EEPROM\0" }, + { .parent_bus = (0x28 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_15_EEPROM\0" }, + { .parent_bus = (0x28 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_16_EEPROM\0" }, + { .parent_bus = (0x30 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_17_EEPROM\0" }, + { .parent_bus = (0x30 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_18_EEPROM\0" }, + { .parent_bus = (0x30 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_19_EEPROM\0" }, + { .parent_bus = (0x30 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_20_EEPROM\0" }, + { .parent_bus = (0x30 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_21_EEPROM\0" }, + { .parent_bus = (0x30 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_22_EEPROM\0" }, + { .parent_bus = (0x30 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_23_EEPROM\0" }, + { .parent_bus = (0x30 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_24_EEPROM\0" }, + { .parent_bus = (0x38 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_25_EEPROM\0" }, + { .parent_bus = (0x38 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_26_EEPROM\0" }, + { .parent_bus = (0x38 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_27_EEPROM\0" }, + { .parent_bus = (0x38 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_28_EEPROM\0" }, + { .parent_bus = (0x38 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_29_EEPROM\0" }, + { .parent_bus = (0x38 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_30_EEPROM\0" }, + { .parent_bus = (0x38 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_31_EEPROM\0" }, + { .parent_bus = (0x38 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_32_EEPROM\0" }, + { .parent_bus = (0x40 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_33_EEPROM\0" }, + { .parent_bus = (0x40 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_34_EEPROM\0" }, + { .parent_bus = (0x40 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_35_EEPROM\0" }, + { .parent_bus = (0x40 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_36_EEPROM\0" }, + { .parent_bus = (0x40 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_37_EEPROM\0" }, + { .parent_bus = (0x40 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_38_EEPROM\0" }, + { .parent_bus = (0x40 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_39_EEPROM\0" }, + { .parent_bus = (0x40 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_40_EEPROM\0" }, + { .parent_bus = (0x48 + 0), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_41_EEPROM\0" }, + { .parent_bus = (0x48 + 1), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_42_EEPROM\0" }, + { .parent_bus = (0x48 + 2), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_43_EEPROM\0" }, + { .parent_bus = (0x48 + 3), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_44_EEPROM\0" }, + { .parent_bus = (0x48 + 4), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_45_EEPROM\0" }, + { .parent_bus = (0x48 + 5), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_46_EEPROM\0" }, + { .parent_bus = (0x48 + 6), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_47_EEPROM\0" }, + { .parent_bus = (0x48 + 7), .type = i2c_type_optoe2_SFP, .addr = 0x50, .name = "SFP_48_EEPROM\0" }, { .parent_bus = (0x10 + 3), .type = i2c_type_pca9698, .addr = 0x23, .name = "PCA9698(SFP_1-8)\0" }, { .parent_bus = (0x10 + 3), .type = i2c_type_pca9698, .addr = 0x21, .name = "PCA9698(SFP_9-16)\0" }, @@ -156,10 +155,10 @@ static struct i2c_init_data quanta_ly8_i2c_init_data[] = { { .parent_bus = (0x10 + 4), .type = i2c_type_pca9698, .addr = 0x25, .name = "PCA9698(SFP_41-48)\0" }, { .parent_bus = (0x10 + 5), .type = i2c_type_pca9548, .addr = 0x76, .busno = 0x50, .name = "PCA9548_8\0" }, - { .parent_bus = (0x50 + 0), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_1_EEPROM\0", .oom_port_name = 49 }, - { .parent_bus = (0x50 + 1), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_2_EEPROM\0", .oom_port_name = 50 }, - { .parent_bus = (0x50 + 2), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_3_EEPROM\0", .oom_port_name = 51 }, - { .parent_bus = (0x50 + 3), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_4_EEPROM\0", .oom_port_name = 52 }, + { .parent_bus = (0x50 + 0), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_1_EEPROM\0" }, + { .parent_bus = (0x50 + 1), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_2_EEPROM\0" }, + { .parent_bus = (0x50 + 2), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_3_EEPROM\0" }, + { .parent_bus = (0x50 + 3), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QSFP_4_EEPROM\0" }, { .parent_bus = (0x10 + 5), .type = i2c_type_pca9555, .addr = 0x24, .name = "PCA9555_1(LED)\0" }, { .parent_bus = (0x10 + 6), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555_2(QSFP)\0" }, @@ -167,8 +166,8 @@ static struct i2c_init_data quanta_ly8_i2c_init_data[] = { /* QSFP+ DB */ { .parent_bus = (0x10 + 7), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555(QDB)\0" }, { .parent_bus = (0x10 + 7), .type = i2c_type_pca9546, .addr = 0x76, .busno = 0x58, .name = "PCA9546(QDB)\0" }, - { .parent_bus = (0x58 + 0), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QDB_QSFP_1_EEPROM\0", .oom_port_name = 53 }, - { .parent_bus = (0x58 + 1), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QDB_QSFP_2_EEPROM\0", .oom_port_name = 54 }, + { .parent_bus = (0x58 + 0), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QDB_QSFP_1_EEPROM\0" }, + { .parent_bus = (0x58 + 1), .type = i2c_type_optoe1_QSFP, .addr = 0x50, .name = "QDB_QSFP_2_EEPROM\0" }, { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x72, .busno = 0x18, .name = "PCA9546\0" }, { .parent_bus = (0x18 + 0), .type = i2c_type_emerson700, .addr = 0x6f, .name = "PSU_1\0" }, /* RPSU 1 */ @@ -249,31 +248,9 @@ static inline struct pca953x_platform_data *pca953x_platform_data_get(int type, return &platform_data; } -struct optoe_platform_data { - u32 byte_len; /* size (sum of all addr) */ - u16 page_size; /* for writes */ - u8 flags; - - void (*setup)(struct memory_accessor *, void *context); - void *context; - - int oom_port_name; -}; - -static inline struct optoe_platform_data *optoe_platform_data_get(int port_name) { - static struct optoe_platform_data platform_data; - - platform_data = (struct optoe_platform_data) { - .oom_port_name = port_name, - }; - - return &platform_data; -} - static inline struct i2c_board_info *i2c_board_info_get(struct i2c_init_data data) { struct pca954x_platform_data *mux_platform_data; struct pca953x_platform_data *gpio_platform_data; - struct optoe_platform_data *oom_platform_data; static struct i2c_board_info board_info; switch(data.type) { @@ -303,16 +280,6 @@ static inline struct i2c_board_info *i2c_board_info_get(struct i2c_init_data dat break; case i2c_type_optoe1_QSFP: case i2c_type_optoe2_SFP: - oom_platform_data = optoe_platform_data_get(data.oom_port_name); - if(oom_platform_data == NULL) { - return (struct i2c_board_info *) NULL; - } - - board_info = (struct i2c_board_info) { - .platform_data = oom_platform_data, - }; - break; - case i2c_type_rtc: case i2c_type_spd: case i2c_type_24c02: diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/python/x86_64_quanta_ly8_rangeley_r0/__init__.py b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/python/x86_64_quanta_ly8_rangeley_r0/__init__.py old mode 100644 new mode 100755 index 268c0d5f..ef3c38e2 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/python/x86_64_quanta_ly8_rangeley_r0/__init__.py +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly8-rangeley/platform-config/r0/src/python/x86_64_quanta_ly8_rangeley_r0/__init__.py @@ -25,4 +25,14 @@ class OnlPlatform_x86_64_quanta_ly8_rangeley_r0(OnlPlatformQuanta, os.system("ln -snf /dev/rtc1 /dev/rtc") os.system("hwclock --hctosys") + #SFP for 1~48 port + #QSFP for 49~52 port + for port_number in range(1,53): + bus_number = port_number + 31 + os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) + + #QDB QSFP 53~54port + os.system("echo 53 >/sys/bus/i2c/devices/88-0050/port_name") + os.system("echo 54 >/sys/bus/i2c/devices/89-0050/port_name") + return True From 850c82cc1adb24fc6e1b167eb772a00c3e9b79e6 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Thu, 16 Aug 2018 14:23:20 +0800 Subject: [PATCH 07/22] Modify sysi to read eeprom via word_data due to block_data get error for some eeprom hw. --- .../onlp/builds/src/module/src/sysi.c | 24 +++++++++++++------ .../x86_64_accton_as5916_54xks_r0/__init__.py | 2 -- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/onlp/builds/src/module/src/sysi.c b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/onlp/builds/src/module/src/sysi.c index d01d1dc9..21e6daf1 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/onlp/builds/src/module/src/sysi.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/onlp/builds/src/module/src/sysi.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -55,17 +56,26 @@ onlp_sysi_platform_get(void) int onlp_sysi_onie_data_get(uint8_t** data, int* size) { + int ret = ONLP_STATUS_OK; + int i = 0; 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; + + for (i = 0; i < 128; i++) { + ret = onlp_i2c_readw(0, 0x56, i*2, ONLP_I2C_F_FORCE); + if (ret < 0) { + aim_free(rdata); + *size = 0; + return ret; } + + rdata[i*2] = ret & 0xff; + rdata[i*2+1] = (ret >> 8) & 0xff; } - aim_free(rdata); - *size = 0; - return ONLP_STATUS_E_INTERNAL; + *size = 256; + *data = rdata; + + return ONLP_STATUS_OK; } int diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/platform-config/r0/src/python/x86_64_accton_as5916_54xks_r0/__init__.py b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/platform-config/r0/src/python/x86_64_accton_as5916_54xks_r0/__init__.py index d723aa4a..5dd206e8 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/platform-config/r0/src/python/x86_64_accton_as5916_54xks_r0/__init__.py +++ b/packages/platforms/accton/x86-64/x86-64-accton-as5916-54xks/platform-config/r0/src/python/x86_64_accton_as5916_54xks_r0/__init__.py @@ -54,8 +54,6 @@ class OnlPlatform_x86_64_accton_as5916_54xks_r0(OnlPlatformAccton, ('pca9548', 0x75, 30), ('pca9548', 0x75, 31), - # initiate IDPROM - ('24c02', 0x56, 0), ] ) From cc3223856487d351f12b1959b471bc2310f7c7a4 Mon Sep 17 00:00:00 2001 From: Jostar Yang Date: Tue, 28 Aug 2018 16:31:21 +0800 Subject: [PATCH 08/22] 1. Let csp9250 support kernel-4.14. 2. Remove not need debug log --- .../x86-64/x86-64-accton-csp9250/modules/PKG.yml | 2 +- .../modules/builds/x86-64-accton-csp9250-leds.c | 4 ---- .../modules/builds/x86-64-accton-csp9250-sfp.c | 13 +------------ .../r0/src/lib/x86-64-accton-csp9250-r0.yml | 2 +- 4 files changed, 3 insertions(+), 18 deletions(-) diff --git a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/PKG.yml b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/PKG.yml index 3f59762e..d857a900 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/PKG.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/PKG.yml @@ -1 +1 @@ -!include $ONL_TEMPLATES/platform-modules.yml VENDOR=accton BASENAME=x86-64-accton-csp9250 ARCH=amd64 KERNELS="onl-kernel-3.16-lts-x86-64-all:amd64" +!include $ONL_TEMPLATES/platform-modules.yml VENDOR=accton BASENAME=x86-64-accton-csp9250 ARCH=amd64 KERNELS="onl-kernel-4.14-lts-x86-64-all:amd64" diff --git a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-leds.c b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-leds.c index f3a2f878..c6237ccd 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-leds.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-leds.c @@ -33,10 +33,6 @@ extern int csp9250_i2c_cpld_read (unsigned short cpld_addr, u8 reg); extern int csp9250_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); -extern void led_classdev_unregister(struct led_classdev *led_cdev); -extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); -extern void led_classdev_resume(struct led_classdev *led_cdev); -extern void led_classdev_suspend(struct led_classdev *led_cdev); #define DRVNAME "accton_csp9250_led" diff --git a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-sfp.c b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-sfp.c index d13bf7c9..1a3f1775 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-sfp.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/modules/builds/x86-64-accton-csp9250-sfp.c @@ -1005,9 +1005,8 @@ static ssize_t sfp_port_read(struct sfp_port_data *data, char *buf, loff_t off, size_t count) { ssize_t retval = 0; - printk("acc trace %s:%d\n", __FUNCTION__, __LINE__); + if (unlikely(!count)) { - printk("acc trace %s:%d\n", __FUNCTION__, __LINE__); DEBUG_PRINT("Count = 0, return"); return count; } @@ -1017,7 +1016,6 @@ static ssize_t sfp_port_read(struct sfp_port_data *data, * from this host, but not from other I2C masters. */ mutex_lock(&data->update_lock); - printk("acc trace %s:%d, off=0x%x,data->client->addr=0x%x\n", __FUNCTION__, __LINE__, off,data->client->addr); while (count) { ssize_t status; @@ -1026,7 +1024,6 @@ static ssize_t sfp_port_read(struct sfp_port_data *data, if (retval == 0) { retval = status; } - printk("acc trace %s:%d\n", __FUNCTION__, __LINE__); break; } @@ -1049,13 +1046,10 @@ static ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, struct sfp_port_data *data; DEBUG_PRINT("offset = (%d), count = (%d)", off, count); data = dev_get_drvdata(container_of(kobj, struct device, kobj)); - printk("acc trace %s:%d, data->port=%d\n", __FUNCTION__, __LINE__, data->port); - printk("offset = (%d), count = (%d)", off, count); present = sfp_is_port_present(data->client, data->port); if (IS_ERR_VALUE(present)) { return present; } - printk("Acc trace %s:%d, present=%d\n", __FUNCTION__, __LINE__, present); if (present == 0) { /* port is not present */ return -ENODEV; @@ -1331,11 +1325,6 @@ static struct i2c_driver sfp_driver = { static int __init csp9250_sfp_init(void) { - //extern int platform_accton_csp9250(void); - //if(!platform_accton_csp9250()) { - // return -ENODEV; - //} - printk("Acc trace %s\n", __FUNCTION__); return i2c_add_driver(&sfp_driver); } diff --git a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/platform-config/r0/src/lib/x86-64-accton-csp9250-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/platform-config/r0/src/lib/x86-64-accton-csp9250-r0.yml index 8425af5c..5ff7bf95 100755 --- a/packages/platforms/accton/x86-64/x86-64-accton-csp9250/platform-config/r0/src/lib/x86-64-accton-csp9250-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-csp9250/platform-config/r0/src/lib/x86-64-accton-csp9250-r0.yml @@ -12,7 +12,7 @@ x86-64-accton-csp9250-r0: serial: >- console=tty0 kernel: - <<: *kernel-3-16 + <<: *kernel-4-14 args: >- console=tty0, From b0553f7e0c561ab0411aef15aaf18838c9c6f138 Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Wed, 29 Aug 2018 18:27:36 +0000 Subject: [PATCH 09/22] Initialize the SFP bitmap in presence_bitmap_get(). --- packages/base/any/onlp/src/onlp/module/src/sfp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/base/any/onlp/src/onlp/module/src/sfp.c b/packages/base/any/onlp/src/onlp/module/src/sfp.c index de7c64ff..33c176ca 100644 --- a/packages/base/any/onlp/src/onlp/module/src/sfp.c +++ b/packages/base/any/onlp/src/onlp/module/src/sfp.c @@ -110,6 +110,7 @@ ONLP_LOCKED_API1(onlp_sfp_is_present, int, port); static int onlp_sfp_presence_bitmap_get_locked__(onlp_sfp_bitmap_t* dst) { + onlp_sfp_bitmap_t_init(dst); int rv = onlp_sfpi_presence_bitmap_get(dst); if(rv == ONLP_STATUS_E_UNSUPPORTED) { From 4d5d8832e046c85d352854a3bcc71694ad95b814 Mon Sep 17 00:00:00 2001 From: Zi Zhou Date: Wed, 5 Sep 2018 10:45:14 -0700 Subject: [PATCH 10/22] add i2c-ismt parameters to read JDSU PLRXPL-VI-S24-22 SFP EEPROM properly --- .../platform-config/r0/src/lib/x86-64-accton-as7312-54x-r0.yml | 2 ++ .../platform-config/r0/src/lib/x86-64-accton-as7312-54xs-r0.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7312-54x/platform-config/r0/src/lib/x86-64-accton-as7312-54x-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7312-54x/platform-config/r0/src/lib/x86-64-accton-as7312-54x-r0.yml index cc11bcf6..45051486 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7312-54x/platform-config/r0/src/lib/x86-64-accton-as7312-54x-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7312-54x/platform-config/r0/src/lib/x86-64-accton-as7312-54x-r0.yml @@ -23,6 +23,8 @@ x86-64-accton-as7312-54x-r0: args: >- nopat console=ttyS1,115200n8 + i2c-ismt.bus_speed=100 + i2c-ismt.delay=100 ##network ## interfaces: diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7312-54xs/platform-config/r0/src/lib/x86-64-accton-as7312-54xs-r0.yml b/packages/platforms/accton/x86-64/x86-64-accton-as7312-54xs/platform-config/r0/src/lib/x86-64-accton-as7312-54xs-r0.yml index d649eb5c..a1d10a4b 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7312-54xs/platform-config/r0/src/lib/x86-64-accton-as7312-54xs-r0.yml +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7312-54xs/platform-config/r0/src/lib/x86-64-accton-as7312-54xs-r0.yml @@ -23,6 +23,8 @@ x86-64-accton-as7312-54xs-r0: args: >- nopat console=ttyS1,115200n8 + i2c-ismt.bus_speed=100 + i2c-ismt.delay=100 ##network ## interfaces: From e9409f1295faabd7fb77a9ddc478b20d6c4c40a3 Mon Sep 17 00:00:00 2001 From: Sergey Popovich Date: Mon, 6 Aug 2018 16:00:22 +0300 Subject: [PATCH 11/22] platforms: netberg: Correct vendor-config enterprise number According to IANA assignments for enterprise Netberg company has number 50424, not 47294. Correct this to match one in ONIE. Signed-off-by: Sergey Popovich --- .../netberg/vendor-config/src/python/netberg/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platforms/netberg/vendor-config/src/python/netberg/__init__.py b/packages/platforms/netberg/vendor-config/src/python/netberg/__init__.py index 96061bb8..ce64a2e9 100755 --- a/packages/platforms/netberg/vendor-config/src/python/netberg/__init__.py +++ b/packages/platforms/netberg/vendor-config/src/python/netberg/__init__.py @@ -4,4 +4,4 @@ from onl.platform.base import * class OnlPlatformNetberg(OnlPlatformBase): MANUFACTURER='Netberg' - PRIVATE_ENTERPRISE_NUMBER=47294 + PRIVATE_ENTERPRISE_NUMBER=50424 From 6d394e7418b6ff9f4eb0a4de16da9d871a9899fb Mon Sep 17 00:00:00 2001 From: Sergey Popovich Date: Mon, 6 Aug 2018 16:03:54 +0300 Subject: [PATCH 12/22] platforms: netberg: Update hardware monitor driver Following enhancements come with this change: o New ASTERION board o New/updated sysfs interface to: + detect rxlos (rxlos1..rxlos4) + set tx_disable (tx_disable1..tx_disable4) + detect tx_fault (tx_fault1..tx_fault4) + read/update sfp_copper eeprom Signed-off-by: Sergey Popovich --- .../x86-64/modules/builds/hardware_monitor.c | 2523 +++++++++++++++-- 1 file changed, 2220 insertions(+), 303 deletions(-) diff --git a/packages/platforms/netberg/x86-64/modules/builds/hardware_monitor.c b/packages/platforms/netberg/x86-64/modules/builds/hardware_monitor.c index fa3e711e..179f8047 100755 --- a/packages/platforms/netberg/x86-64/modules/builds/hardware_monitor.c +++ b/packages/platforms/netberg/x86-64/modules/builds/hardware_monitor.c @@ -25,8 +25,11 @@ enum platform_type { #define W83795ADG_VENDOR_ID 0x5CA3 #define W83795ADG_CHIP_ID 0x79 -#define W83795ADG_TEMP_COUNT 2 -#define W83795ADG_FAN_COUNT 8 +#define W83795ADG_NUM2 2 +#define W83795ADG_NUM8 8 + +#define W83795ADG_TEMP_COUNT 4 +#define W83795ADG_FAN_COUNT 10 #define W83795ADG_FAN_SPEED_FACTOR 1350000 /* 1.35 * 10^6 */ #define W83795ADG_FAN_POLES_NUMBER 4 #define W83795ADG_VSEN_COUNT 7 @@ -44,6 +47,7 @@ enum platform_type { /* Bank 0*/ #define W83795ADG_REG_CONFIG 0x01 /* Configuration Register */ #define W83795ADG_REG_TEMP_CTRL2 0x05 /* Temperature Monitoring Control Register */ +#define W83795ADG_REG_FANIN_CTRL2 0x07 /* FANIN CTRL2. FANIN Monitoring Control Register */ #define W83795ADG_REG_VSEN1 0x10 /* VSEN1 voltage readout high byte */ #define W83795ADG_REG_VSEN2 0x11 /* VSEN2 voltage readout high byte */ #define W83795ADG_REG_VSEN3 0x12 /* VSEN3 voltage readout high byte */ @@ -87,6 +91,8 @@ enum platform_type { #define CPLD_REG_LED 0x44 /* FAN LED */ +#define CPLD_REG_MUX 0x4A /* I2C MUX control Register */ + /* 9548 Channel Index */ #define PCA9548_CH00 0 #define PCA9548_CH01 1 @@ -195,6 +201,7 @@ typedef enum /* QSFP */ #define QSFP_COUNT 64 #define QSFP_DATA_SIZE 256 +#define SFP_COPPER_DATA_SIZE 512 #define EEPROM_DATA_SIZE 256 @@ -310,9 +317,10 @@ SFP_PORT_DATA_t sfpPortData_78F[] = { static struct i2c_client qsfpDataA0_client; static struct i2c_client qsfpDataA2_client; +static struct i2c_client SfpCopperData_client; /* i2c bus 0 */ -static struct i2c_client pca9535pwr_client; +static struct i2c_client pca9535pwr_client_bus0; static struct i2c_client cpld_client; static struct i2c_client pca9548_client_bus0; static struct i2c_client pca9535_client_bus0[4]; @@ -324,15 +332,15 @@ static struct i2c_client psu_mcu_client_bus0; /* i2c bus 1 */ static struct i2c_client pca9548_client[4]; -static struct i2c_client pca9535pwr_client_bus1[6]; +static struct i2c_client pca9535pwr_client[6]; static struct i2c_client eeprom_client; -static struct i2c_client eeprom_client_2; static struct i2c_client psu_eeprom_client; static struct i2c_client psu_mcu_client; static unsigned int FanErr[W83795ADG_FAN_COUNT] = {0}; static unsigned int FanDir = 0; +static unsigned int FanDir2 = 0; static unsigned int isBMCSupport = 0; static unsigned int platformBuildRev = 0xffff; @@ -344,9 +352,12 @@ static char platformPsuABS = 0; unsigned int SFPPortAbsStatus[QSFP_COUNT]; unsigned int SFPPortRxLosStatus[QSFP_COUNT]; +unsigned int SFPPortTxFaultStatus[QSFP_COUNT]; char SFPPortDataValid[QSFP_COUNT]; char SFPPortTxDisable[QSFP_COUNT]; +static struct i2c_client cpld_client_bus1; + struct i2c_bus0_hardware_monitor_data { struct device *hwmon_dev; struct attribute_group hwmon_group; @@ -405,16 +416,27 @@ struct i2c_bus1_hardware_monitor_data { unsigned short qsfpPortAbsStatus[4]; char qsfpPortDataA0[QSFP_COUNT][QSFP_DATA_SIZE]; char qsfpPortDataA2[QSFP_COUNT][QSFP_DATA_SIZE]; + char SfpCopperPortData[QSFP_COUNT][SFP_COPPER_DATA_SIZE]; unsigned short qsfpPortDataValid[4]; unsigned short sfpPortTxDisable[3]; unsigned short sfpPortRateSelect[3]; unsigned short sfpPortRxLosStatus[4]; + unsigned short sfpPortTxFaultStatus[4]; unsigned short fanAbs[2]; unsigned short fanDir[2]; unsigned short systemLedStatus; unsigned short frontLedStatus; + unsigned char sfpPortDataValidAst[64]; + unsigned char sfpPortAbsRxLosStatus[24]; + unsigned char qsfpPortAbsStatusAst[16]; + unsigned char sfpPortRateSelectAst[12]; + unsigned char sfpPortTxDisableAst[6]; + + char qsfpPortTxDisableData[QSFP_COUNT]; + char qsfpPortTxDisableDataUpdate[QSFP_COUNT]; + struct i2c_client *sfpPortClient[QSFP_COUNT]; }; /* Addresses to scan */ @@ -460,6 +482,12 @@ static fanControlTable_t fanControlTable[] = {62, 70, 85}, /* temperature threshold (going to up) */ {58, 66, 70}, /* temperature threshold (going to down) */ {0x70, 0xB7, 0xFF} /* fan rpm : 8000, 13000, 16000 */ + }, + /* Asterion */ + { + {70, 75, 80}, /* temperature threshold (going to up) */ + {60, 65, 70}, /* temperature threshold (going to down) */ + {0x8B, 0xD1, 0xFF} /* fan rpm : 12000, 18000, 22000 */ } }; @@ -483,6 +511,12 @@ static fanControlTable_t fanControlTable_B2F[] = {58, 63, 80}, /* temperature threshold (going to up) */ {54, 60, 63}, /* temperature threshold (going to down) */ {0x6F, 0xB7, 0xFF} /* fan rpm : 8000, 13000, 16000 */ + }, + /* Asterion */ + { + {70, 75, 80}, /* temperature threshold (going to up) */ + {60, 65, 70}, /* temperature threshold (going to down) */ + {0x8B, 0xD1, 0xFF} /* fan rpm : 12000, 18000, 22000 */ } }; @@ -508,6 +542,39 @@ static int i2c_device_byte_write(const struct i2c_client *client, unsigned char } #endif +#define BIT_INDEX(i) (1ULL << (i)) +#define SFF8436_RX_LOS_ADDR 3 +#define SFF8436_TX_FAULT_ADDR 4 +#define SFF8436_TX_DISABLE_ADDR 86 + +#define I2C_RW_RETRY_COUNT 3 +#define I2C_RW_RETRY_INTERVAL 100 /* ms */ + +enum port_sysfs_attributes { + PRESENT, + RX_LOS, + RX_LOS1, + RX_LOS2, + RX_LOS3, + RX_LOS4, + TX_DISABLE, + TX_DISABLE1, + TX_DISABLE2, + TX_DISABLE3, + TX_DISABLE4, + TX_FAULT, + TX_FAULT1, + TX_FAULT2, + TX_FAULT3, + TX_FAULT4, + EEPROM_A0_PAGE, + EEPROM_A2_PAGE, + SFP_COPPER, + LAST_ATTRIBUTE +}; + +static struct mutex portStatusLock; + static int i2c_device_word_write(const struct i2c_client *client, unsigned char command, unsigned short value) { unsigned int retry = 10; @@ -531,21 +598,8 @@ static int i2c_device_word_write(const struct i2c_client *client, unsigned char return ret; } -int qsfpDataRead(struct i2c_client *client, char *buf) +int eepromDataBlockRead(struct i2c_client *client, char *buf) { -#if 0 - unsigned int index; - int value; - - for (index=0; index> 8; + buf[index*2] = value & 0x00ff; + } + return 0; } int eepromDataRead(struct i2c_client *client, char *buf) @@ -601,6 +710,13 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) fanErr = 0; for (i=0; i= W83795ADG_NUM8) && (data->modelId != ASTERION_WITH_BMC) && (data->modelId != ASTERION_WITHOUT_BMC)) + { + FanErr[i] = 0; + continue; + } + fanSpeed = 0; /* Choose W83795ADG bank 0 */ i2c_smbus_write_byte_data(client, W83795ADG_REG_BANK, 0x00); @@ -625,9 +741,9 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) if (data->hwRev == 0x00) /* Proto */ { if (fanErr == 1) - i2c_smbus_write_byte_data(&pca9535pwr_client, PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x80); + i2c_smbus_write_byte_data(&pca9535pwr_client_bus0, PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x80); else - i2c_smbus_write_byte_data(&pca9535pwr_client, PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x00); + i2c_smbus_write_byte_data(&pca9535pwr_client_bus0, PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x00); } else if (data->hwRev == 0x02) /* Beta */ { @@ -648,6 +764,10 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) /* Get Remote Temp */ for (i=0; i= W83795ADG_NUM2) && (data->modelId != ASTERION_WITH_BMC) && (data->modelId != ASTERION_WITHOUT_BMC)) + break; + MNTRTD = (int) i2c_smbus_read_byte_data(client, (W83795ADG_REG_TR1+i)); MNTTD = (int) i2c_smbus_read_byte_data(client, W83795ADG_REG_VR_LSB); /* temperature is negative */ @@ -672,6 +792,9 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) maxTemp = data->macTemp; for (i=0; i= W83795ADG_NUM2) && (data->modelId != ASTERION_WITH_BMC) && (data->modelId != ASTERION_WITHOUT_BMC)) + break; + if (data->remoteTempInt[i] > maxTemp) maxTemp = data->remoteTempInt[i]; } @@ -705,11 +828,20 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) else fanTable = &(fanControlTable_B2F[2]); break; + + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + if (FanDir2 != 0) + fanTable = &(fanControlTable[3]); + else + fanTable = &(fanControlTable_B2F[3]); + break; } if (fanErr) { fanDuty = fanTable->fanDutySet[2]; + LastTemp = 0; } else { @@ -748,8 +880,8 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) fanDuty = fanTable->fanDutySet[2]; } } + LastTemp = maxTemp; } - LastTemp = maxTemp; if ((fanDuty!=0)&&(data->fanDuty!=fanDuty)) { @@ -792,9 +924,11 @@ static int i2c_bus0_hardware_monitor_update_thread(void *p) { port_status = i2c_smbus_read_word_data(&(pca9535_client_bus0[j]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); port = ((j*2)+(i*8)); + SFPPortTxFaultStatus[port] = (PCA9553_TEST_BIT(port_status, 0)==0); SFPPortAbsStatus[port] = (PCA9553_TEST_BIT(port_status, 1)==0); SFPPortRxLosStatus[port] = (PCA9553_TEST_BIT(port_status, 2)==0); port++; + SFPPortTxFaultStatus[port] = (PCA9553_TEST_BIT(port_status, 6)==0); SFPPortAbsStatus[port] = (PCA9553_TEST_BIT(port_status, 7)==0); SFPPortRxLosStatus[port] = (PCA9553_TEST_BIT(port_status, 8)==0); } @@ -919,9 +1053,10 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) struct i2c_client *client = p; struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); int i, ret; - unsigned short value, fanErr; + unsigned short value, value2, fanErr, fanErr2; unsigned int step = 0; unsigned char qsfpPortData[QSFP_DATA_SIZE]; + unsigned char SfpCopperPortData[SFP_COPPER_DATA_SIZE]; unsigned short port_status; int j, port; @@ -944,7 +1079,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) /* QSFP Port */ for (i=0; i<2; i++) - data->qsfpPortAbsStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + data->qsfpPortAbsStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); step = 1; break; @@ -964,7 +1099,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) ret = i2c_smbus_write_byte(&(pca9548_client[0]), (1<=0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + if (data->qsfpPortTxDisableDataUpdate[i] == 1) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[i], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[i] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i][0]), qsfpPortData, QSFP_DATA_SIZE); @@ -976,8 +1116,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) else { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); + data->qsfpPortTxDisableDataUpdate[i] = 1; } } } @@ -986,8 +1126,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) for (i=0; i<8; i++) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); + data->qsfpPortTxDisableDataUpdate[i] = 1; } } @@ -1009,7 +1149,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) ret = i2c_smbus_write_byte(&(pca9548_client[1]), (1<<(i-8))); if (ret>=0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + if (data->qsfpPortTxDisableDataUpdate[i] == 1) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[i], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[i] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i][0]), qsfpPortData, QSFP_DATA_SIZE); @@ -1021,8 +1166,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) else { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); + data->qsfpPortTxDisableDataUpdate[i] = 1; } } } @@ -1031,8 +1176,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) for (i=8; i<16; i++) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); + data->qsfpPortTxDisableDataUpdate[i] = 1; } } @@ -1054,7 +1199,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) ret = i2c_smbus_write_byte(&(pca9548_client[2]), (1<=0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + if (data->qsfpPortTxDisableDataUpdate[i+16] == 1) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[i+16], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[i+16] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+16][0]), qsfpPortData, QSFP_DATA_SIZE); @@ -1066,8 +1216,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) else { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); + data->qsfpPortTxDisableDataUpdate[i+16] = 1; } } } @@ -1076,8 +1226,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) for (i=0; i<8; i++) { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); + data->qsfpPortTxDisableDataUpdate[i+16] = 1; } } @@ -1099,7 +1249,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) ret = i2c_smbus_write_byte(&(pca9548_client[3]), (1<<(i-8))); if (ret>=0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + if (data->qsfpPortTxDisableDataUpdate[i+16] == 1) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[i+16], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[i+16] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+16][0]), qsfpPortData, QSFP_DATA_SIZE); @@ -1111,8 +1266,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) else { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); + data->qsfpPortTxDisableDataUpdate[i+16] = 1; } } } @@ -1121,8 +1276,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) for (i=8; i<16; i++) { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); + data->qsfpPortTxDisableDataUpdate[i+16] = 1; } } @@ -1140,7 +1295,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) value = 0xcccc; fanErr = 0; - for (i=0; ifrontLedStatus); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->frontLedStatus); } /* FAN Status */ - value = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + value = i2c_smbus_read_word_data(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); data->fanAbs[0] = (value&0x4444); data->fanDir[0] = (value&0x8888); FanDir = data->fanDir[0]; @@ -1245,7 +1400,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) /* SFP Port */ for (i=0; i<4; i++) - data->qsfpPortAbsStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + data->qsfpPortAbsStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); /* Turn on PCA9548#1 channel 1 on I2C-bus1 */ ret = i2c_smbus_write_byte(&(pca9548_client[1]), (1<sfpPortRxLosStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + for (i=0; i<3; i++) + data->sfpPortRxLosStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + + /* Turn on PCA9548#1 channel 2 on I2C-bus1 */ + ret = i2c_smbus_write_byte(&(pca9548_client[1]), (1<sfpPortTxFaultStatus[i] = i2c_smbus_read_word_data(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); step = 1; break; @@ -1276,16 +1440,19 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { if (PCA9553_TEST_BIT(data->qsfpPortDataValid[0], i) == 0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i][0]), qsfpPortData, QSFP_DATA_SIZE); PCA9553_SET_BIT(data->qsfpPortDataValid[0], i); } } - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte(&(pca9548_client[0]), 0x00); } @@ -1293,6 +1460,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); } } @@ -1303,6 +1471,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); } } @@ -1327,16 +1496,19 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { if (PCA9553_TEST_BIT(data->qsfpPortDataValid[0], i) == 0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i][0]), qsfpPortData, QSFP_DATA_SIZE); PCA9553_SET_BIT(data->qsfpPortDataValid[0], i); } } - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte(&(pca9548_client[0]), 0x00); } @@ -1344,6 +1516,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); } } @@ -1354,6 +1527,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[0], i); } } @@ -1378,16 +1552,19 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { if (PCA9553_TEST_BIT(data->qsfpPortDataValid[1], i) == 0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+16][0]), qsfpPortData, QSFP_DATA_SIZE); PCA9553_SET_BIT(data->qsfpPortDataValid[1], i); } } - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i+16][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i+16][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte(&(pca9548_client[0]), 0x00); } @@ -1395,6 +1572,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+16][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); } } @@ -1405,6 +1583,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+16][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); } } @@ -1429,16 +1608,19 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { if (PCA9553_TEST_BIT(data->qsfpPortDataValid[1], i) == 0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+16][0]), qsfpPortData, QSFP_DATA_SIZE); PCA9553_SET_BIT(data->qsfpPortDataValid[1], i); } } - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i+16][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i+16][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte(&(pca9548_client[0]), 0x00); } @@ -1446,6 +1628,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+16][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); } } @@ -1456,6 +1639,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+16][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+16][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+16][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[1], i); } } @@ -1480,16 +1664,19 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { if (PCA9553_TEST_BIT(data->qsfpPortDataValid[2], i) == 0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+32][0]), qsfpPortData, QSFP_DATA_SIZE); PCA9553_SET_BIT(data->qsfpPortDataValid[2], i); } } - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i+32][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i+32][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte(&(pca9548_client[0]), 0x00); } @@ -1497,6 +1684,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+32][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+32][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+32][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[2], i); } } @@ -1507,6 +1695,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+32][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+32][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+32][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[2], i); } } @@ -1531,16 +1720,19 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { if (PCA9553_TEST_BIT(data->qsfpPortDataValid[2], i) == 0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+32][0]), qsfpPortData, QSFP_DATA_SIZE); PCA9553_SET_BIT(data->qsfpPortDataValid[2], i); } } - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i+32][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i+32][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte(&(pca9548_client[0]), 0x00); } @@ -1548,6 +1740,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+32][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+32][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+32][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[2], i); } } @@ -1558,6 +1751,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i+32][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i+32][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i+32][0]), 0, SFP_COPPER_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[2], i); } } @@ -1580,7 +1774,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) ret = i2c_smbus_write_byte(&(pca9548_client[0]), (1<=0) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + if (data->qsfpPortTxDisableDataUpdate[i+48] == 1) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[i+48], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[i+48] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i+48][0]), qsfpPortData, QSFP_DATA_SIZE); @@ -1592,8 +1791,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) else { memset(&(data->qsfpPortDataA0[i+48][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i+48][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[3], i); + data->qsfpPortTxDisableDataUpdate[i+48] = 1; } } } @@ -1602,8 +1801,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) for (i=0; i<6; i++) { memset(&(data->qsfpPortDataA0[i+48][0]), 0, QSFP_DATA_SIZE); - memset(&(data->qsfpPortDataA2[i+48][0]), 0, QSFP_DATA_SIZE); PCA9553_CLEAR_BIT(data->qsfpPortDataValid[3], i); + data->qsfpPortTxDisableDataUpdate[i+48] = 1; } } @@ -1625,7 +1824,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) value = 0xcccc; fanErr = 0; - for (i=0; ifrontLedStatus); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->frontLedStatus); /* FAN Status */ - value = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + value = i2c_smbus_read_word_data(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); data->fanAbs[0] = (value&0x4444); data->fanDir[0] = (value&0x8888); FanDir = data->fanDir[0]; @@ -1722,11 +1921,13 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) for (j=0; j<4; j++) { - port_status = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[j]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + port_status = i2c_smbus_read_word_data(&(pca9535pwr_client[j]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); port = ((j*2)+40); + SFPPortTxFaultStatus[port] = (PCA9553_TEST_BIT(port_status, 0)==0); SFPPortAbsStatus[port] = (PCA9553_TEST_BIT(port_status, 1)==0); SFPPortRxLosStatus[port] = (PCA9553_TEST_BIT(port_status, 2)==0); port++; + SFPPortTxFaultStatus[port] = (PCA9553_TEST_BIT(port_status, 6)==0); SFPPortAbsStatus[port] = (PCA9553_TEST_BIT(port_status, 7)==0); SFPPortRxLosStatus[port] = (PCA9553_TEST_BIT(port_status, 8)==0); } @@ -1741,7 +1942,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) break; fanErr = 0; - for (i=0; ifrontLedStatus); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->frontLedStatus); i2c_smbus_write_byte_data(client, 0, 0x00); step = 2; @@ -1795,11 +1996,11 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) if (ret < 0) break; - value = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + value = i2c_smbus_read_word_data(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); SFPPortAbsStatus[48] = (PCA9553_TEST_BIT(value, 9)==0); SFPPortAbsStatus[49] = (PCA9553_TEST_BIT(value, 4)==0); SFPPortAbsStatus[51] = (PCA9553_TEST_BIT(value, 14)==0); - value = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[1]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + value = i2c_smbus_read_word_data(&(pca9535pwr_client[1]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); SFPPortAbsStatus[50] = (PCA9553_TEST_BIT(value, 4)==0); SFPPortAbsStatus[52] = (PCA9553_TEST_BIT(value, 14)==0); SFPPortAbsStatus[53] = (PCA9553_TEST_BIT(value, 9)==0); @@ -1815,7 +2016,7 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) value = 0xcccc; fanErr = 0; - for (i=0; ifanAbs[0] = (value&0x4444); data->fanDir[0] = (value&0x8888); FanDir = data->fanDir[0]; @@ -1864,7 +2065,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) i2c_smbus_write_byte_data(&(pca9548_client[0]), 0, sfpPortData_78F[i].portMaskBitForPCA9548_2TO5); if ((SFPPortDataValid[i] == 0)||(i>=48)) { - ret = qsfpDataRead(&qsfpDataA0_client,qsfpPortData); + if ((i>=48)&&(data->qsfpPortTxDisableDataUpdate[i] == 1)) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[i], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[i] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); if (ret>=0) { memcpy(&(data->qsfpPortDataA0[i][0]), qsfpPortData, QSFP_DATA_SIZE); @@ -1873,9 +2079,12 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) } if (i<48) { - ret = qsfpDataRead(&qsfpDataA2_client,qsfpPortData); + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); if (ret>=0) memcpy(&(data->qsfpPortDataA2[i][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); } i2c_smbus_write_byte_data(&(pca9548_client[0]), 0, 0x00); i2c_smbus_write_byte_data(&(pca9548_client[1]), 0, 0x00); @@ -1884,6 +2093,8 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) { memset(&(data->qsfpPortDataA0[i][0]), 0, QSFP_DATA_SIZE); memset(&(data->qsfpPortDataA2[i][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i][0]), 0, SFP_COPPER_DATA_SIZE); + data->qsfpPortTxDisableDataUpdate[i] = 1; SFPPortDataValid[i] = 0; } } @@ -1898,6 +2109,345 @@ static int i2c_bus1_hardware_monitor_update_thread(void *p) case ASTERION_WITH_BMC: case ASTERION_WITHOUT_BMC: + switch (step) + { + case 0: + /* Turn on PCA9548#0 channel 0 on I2C-bus1 */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH00)); + if (ret < 0) + break; + + /* SFP Port 0~23, SFP Port - RXLOS */ + for (i = 0; i < 10; i++) + data->sfpPortAbsRxLosStatus[i] = i2c_smbus_read_byte_data(&(cpld_client_bus1), (0x20 + i)); + + data->sfpPortAbsRxLosStatus[10] = i2c_smbus_read_byte_data(&(cpld_client_bus1), 0x30); + data->sfpPortAbsRxLosStatus[11] = i2c_smbus_read_byte_data(&(cpld_client_bus1), 0x31); + + /* Turn on PCA9548#0 channel 1 on I2C-bus1 */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH01)); + if (ret < 0) + break; + + /* SFP Port 24~47, SFP Port - RXLOS */ + for (i = 0; i < 10; i++) + data->sfpPortAbsRxLosStatus[i + 12] = i2c_smbus_read_byte_data(&(cpld_client_bus1), 0x20 + i); + + data->sfpPortAbsRxLosStatus[22] = i2c_smbus_read_byte_data(&(cpld_client_bus1), 0x30); + data->sfpPortAbsRxLosStatus[23] = i2c_smbus_read_byte_data(&(cpld_client_bus1), 0x31); + + /* Turn on PCA9548#0 channel 2 on I2C-bus1 */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH02)); + if (ret < 0) + break; + + /* QSFP Port 48~63 */ + for (i = 0; i < 16; i++) + data->qsfpPortAbsStatusAst[i] = i2c_smbus_read_byte_data(&(cpld_client_bus1), (0x20 + i)); + + step = 1; + break; + + case 1: + /* Turn on PCA9548#0 channel 0 on I2C-bus1 */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH00)); + if (ret < 0) + break; + + for (i = 0; i < 12; i++) /* SFP 0,2,4 ... 22 */ + { + if ((data->sfpPortAbsRxLosStatus[i] & 0x02) == 0) /* present */ + { + ret = i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, (0x01 + (i * 2))); + + if (ret >= 0) + { + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); + + if (ret >= 0) + { + memcpy(&(data->qsfpPortDataA0[i * 2][0]), qsfpPortData, QSFP_DATA_SIZE); + data->sfpPortDataValidAst[i * 2] = 1; + } + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); + memcpy(&(data->qsfpPortDataA2[i * 2][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[i * 2][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); + } + i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, 0x00); + } + else + { + memset(&(data->qsfpPortDataA0[i * 2][0]), 0, QSFP_DATA_SIZE); + memset(&(data->qsfpPortDataA2[i * 2][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[i * 2][0]), 0, SFP_COPPER_DATA_SIZE); + data->sfpPortDataValidAst[i * 2] = 0; + } + } + + for (i = 0; i < 12; i++) /* SFP 1,3,5 ... 23 */ + { + if ((data->sfpPortAbsRxLosStatus[i] & 0x20) == 0) /* present */ + { + ret = i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, (0x02 + (i * 2))); + if (ret >= 0) + { + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); + if (ret >= 0) + { + memcpy(&(data->qsfpPortDataA0[1 + (i * 2)][0]), qsfpPortData, QSFP_DATA_SIZE); + data->sfpPortDataValidAst[1 + (i * 2)] = 1; + } + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); + if (ret >= 0) + memcpy(&(data->qsfpPortDataA2[1 + (i * 2)][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[1 + (i * 2)][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); + } + i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, 0x00); + } + else + { + memset(&(data->qsfpPortDataA0[1 + (i * 2)][0]), 0, QSFP_DATA_SIZE); + memset(&(data->qsfpPortDataA2[1 + (i * 2)][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[1 + (i * 2)][0]), 0, SFP_COPPER_DATA_SIZE); + data->sfpPortDataValidAst[1 + (i * 2)] = 0; + } + } + + step = 2; + break; + + case 2: + /* Turn on PCA9548#0 channel 1 on I2C-bus1 */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH01)); + if (ret < 0) + break; + + for (i = 0; i < 12; i++) /* SFP 24,26,28 ... 46 */ + { + if ((data->sfpPortAbsRxLosStatus[i + 12] & 0x02) == 0) /* present */ + { + ret = i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, (0x01 + (i * 2))); + if (ret >= 0) + { + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); + if (ret >= 0) + { + memcpy(&(data->qsfpPortDataA0[(i +12) * 2][0]), qsfpPortData, QSFP_DATA_SIZE); + data->sfpPortDataValidAst[(i + 12) * 2] = 1; + } + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); + if (ret >= 0) + memcpy(&(data->qsfpPortDataA2[(i + 12) * 2][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[(i + 12) * 2][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); + } + i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, 0x00); + } + else + { + memset(&(data->qsfpPortDataA0[(i + 12) * 2][0]), 0, QSFP_DATA_SIZE); + memset(&(data->qsfpPortDataA2[(i + 12) * 2][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[(i + 12) * 2][0]), 0, SFP_COPPER_DATA_SIZE); + data->sfpPortDataValidAst[(i + 12) * 2] = 0; + } + } + + for (i = 0; i < 12; i++) /* SFP 25,27,29 ... 47 */ + { + if ((data->sfpPortAbsRxLosStatus[i + 12] & 0x20) == 0) /* present */ + { + ret = i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, (0x02 + (i * 2))); + if (ret >= 0) + { + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); + if (ret >= 0) + { + memcpy(&(data->qsfpPortDataA0[1 + ((i + 12) * 2)][0]), qsfpPortData, QSFP_DATA_SIZE); + data->sfpPortDataValidAst[1 + ((i + 12) * 2)] = 1; + } + ret = eepromDataBlockRead(&qsfpDataA2_client,qsfpPortData); + if (ret >= 0) + memcpy(&(data->qsfpPortDataA2[1 + ((i + 12) * 2)][0]), qsfpPortData, QSFP_DATA_SIZE); + ret = eepromDataWordRead(&SfpCopperData_client,SfpCopperPortData); + if (ret>=0) + memcpy(&(data->SfpCopperPortData[1 + ((i + 12) * 2)][0]), SfpCopperPortData, SFP_COPPER_DATA_SIZE); + } + i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, 0x00); + } + else + { + memset(&(data->qsfpPortDataA0[1 + ((i + 12) * 2)][0]), 0, QSFP_DATA_SIZE); + memset(&(data->qsfpPortDataA2[1 + ((i + 12) * 2)][0]), 0, QSFP_DATA_SIZE); + memset(&(data->SfpCopperPortData[1 + ((i + 12) * 2)][0]), 0, SFP_COPPER_DATA_SIZE); + data->sfpPortDataValidAst[1 + ((i + 12) * 2)] = 0; + } + } + + step = 3; + break; + + case 3: + /* Turn on PCA9548#0 channel 2 on I2C-bus1 */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH02)); + if (ret < 0) + break; + + for (i = 0; i < 16; i++) /* QSFP 48~63 */ + { + if ((data->qsfpPortAbsStatusAst[i] & 0x02) == 0) /* present */ + { + ret = i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, (0x01 + i)); + if (ret >= 0) + { + if (data->qsfpPortTxDisableDataUpdate[48 + i] == 1) + { + eepromDataByteWrite(&qsfpDataA0_client, SFF8436_TX_DISABLE_ADDR, &data->qsfpPortTxDisableData[48 + i], sizeof(char)); + data->qsfpPortTxDisableDataUpdate[48 + i] = 0; + } + ret = eepromDataBlockRead(&qsfpDataA0_client,qsfpPortData); + if (ret >= 0) + { + memcpy(&(data->qsfpPortDataA0[48 + i][0]), qsfpPortData, QSFP_DATA_SIZE); + data->sfpPortDataValidAst[48 + i] = 1; + } + } + i2c_smbus_write_byte_data(&(cpld_client_bus1), CPLD_REG_MUX, 0x00); + } + else + { + memset(&(data->qsfpPortDataA0[48 + i][0]), 0, QSFP_DATA_SIZE); + data->sfpPortDataValidAst[48 + i] = 0; + data->qsfpPortTxDisableDataUpdate[48 + i] = 1; + } + } + + step = 4; + break; + + case 4: + /* Turn on PCA9548#0 channel 3 on I2C-bus1 : FAN Status */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH03)); + if (ret < 0) + break; + + value = 0xcccc; + fanErr = 0; + for (i = 0; i < W83795ADG_NUM8; i++) + { + if (FanErr[i] == 1) + fanErr |= (0x1 << i); + } + + if (fanErr & 0x03) + value |= 0x0001; + else + value |= 0x0002; + + if (fanErr & 0x0c) + value |= 0x0010; + else + value |= 0x0020; + + if (fanErr & 0x30) + value |= 0x0100; + else + value |= 0x0200; + + if (fanErr & 0xc0) + value |= 0x1000; + else + value |= 0x2000; + + ret = i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, value); + if (ret < 0) + break; + + /* FAN Status */ + value = i2c_smbus_read_word_data(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + data->fanAbs[0] = (value & 0x4444); + data->fanDir[0] = (value & 0x8888); + FanDir = data->fanDir[0]; + + fanErr2 = 0; + for (i = W83795ADG_NUM8; i < W83795ADG_FAN_COUNT; i++) + { + if (FanErr[i] == 1) + fanErr2 |= (0x1 << (i - 8)); + } + + if (fanErr2 & 0x03) + value2 = 0x0010; + else + value2 = 0x0020; + + ret = i2c_device_word_write(&(pca9535pwr_client[1]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, value2); + if (ret < 0) + break; + + /* FAN Status */ + value2 = i2c_smbus_read_word_data(&(pca9535pwr_client[1]), PCA9553_COMMAND_BYTE_REG_INPUT_PORT_0); + + data->fanAbs[1] = (value2 & 0x0040); + data->fanDir[1] = (value2 & 0x0080); + FanDir2 = data->fanDir[1]; + + /* Turn on PCA9548#0 channel 4 on I2C-bus1 : System LED */ + ret = i2c_smbus_write_byte(client, (1 << PCA9548_CH04)); + if (ret < 0) + break; + + data->frontLedStatus |= 0x00ff; + if (fanErr == 0 && fanErr2 == 0) + data->frontLedStatus &= (~0x0010); /* FAN_LED_G# */ + else + data->frontLedStatus &= (~0x0020); /* FAN_LED_Y# */ + + if ((platformPsuABS & 0x01) == 0x00) /* PSU1 Present */ + { + if (platformPsuPG & 0x04) /* PSU1_PG_LDC Power Goodasserted */ + data->frontLedStatus &= (~0x0001); /* PSU1_LED_G# */ + else + data->frontLedStatus &= (~0x0002); /* PSU1_LED_Y# */ + } + if ((platformPsuABS & 0x02) == 0x00) /* PSU2 Present */ + { + if (platformPsuPG & 0x08) /* PSU2_PG_LDC Power Goodasserted */ + data->frontLedStatus &= (~0x0004); /* PSU2_LED_G# */ + else + data->frontLedStatus &= (~0x0008); /* PSU2_LED_Y# */ + } + + switch (data->systemLedStatus) + { + default: + case 0: /* Booting */ + break; + + case 1: /* Critical*/ + data->frontLedStatus &= (~0x0080); /* SYS_LED_Y# */ + break; + + case 2: /* Normal */ + data->frontLedStatus &= (~0x0040); /* SYS_LED_G# */ + break; + } + + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->frontLedStatus); + + step = 0; + break; + + default: + step = 0; + break; + } + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x33, 0x00); + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x33, 0xff); break; default: @@ -1960,10 +2510,27 @@ static ssize_t show_psu_pg_sen(struct device *dev, struct device_attribute *deva value = data->psuPG; mutex_unlock(&data->lock); - if (attr->index == 0) - value &= 0x08; - else - value &= 0x10; + switch(platformModelId) + { + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + if (attr->index == 0) + value &= 0x04; + else + value &= 0x08; + } + break; + + default: + { + if (attr->index == 0) + value &= 0x08; + else + value &= 0x10; + } + break; + } return sprintf(buf, "%d\n", value?1:0); } @@ -2183,8 +2750,6 @@ static ssize_t set_rov(struct device *dev, struct device_attribute *devattr, con { case HURACAN_WITH_BMC: case HURACAN_WITHOUT_BMC: - case ASTERION_WITH_BMC: - case ASTERION_WITHOUT_BMC: case HURACAN_A_WITH_BMC: case HURACAN_A_WITHOUT_BMC: { @@ -2219,6 +2784,8 @@ static ssize_t set_rov(struct device *dev, struct device_attribute *devattr, con case SESTO_WITH_BMC: case SESTO_WITHOUT_BMC: + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: { /* - 4'b0000 = 1.2000V -> 0x47 @@ -2363,6 +2930,8 @@ static SENSOR_DEVICE_ATTR(fan10_duty, S_IRUGO, show_fan_duty, NULL, 9); static SENSOR_DEVICE_ATTR(remote_temp1, S_IRUGO, show_remote_temp, NULL, 0); static SENSOR_DEVICE_ATTR(remote_temp2, S_IRUGO, show_remote_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(remote_temp3, S_IRUGO, show_remote_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(remote_temp4, S_IRUGO, show_remote_temp, NULL, 3); static SENSOR_DEVICE_ATTR(vsen1, S_IRUGO, show_voltage_sen, NULL, 0); static SENSOR_DEVICE_ATTR(vsen2, S_IRUGO, show_voltage_sen, NULL, 1); @@ -2507,6 +3076,8 @@ static struct attribute *i2c_bus0_hardware_monitor_attr_asterion[] = { &sensor_dev_attr_remote_temp1.dev_attr.attr, &sensor_dev_attr_remote_temp2.dev_attr.attr, + &sensor_dev_attr_remote_temp3.dev_attr.attr, + &sensor_dev_attr_remote_temp4.dev_attr.attr, &sensor_dev_attr_vsen1.dev_attr.attr, &sensor_dev_attr_vsen2.dev_attr.attr, @@ -2520,7 +3091,8 @@ static struct attribute *i2c_bus0_hardware_monitor_attr_asterion[] = { static ssize_t show_port_abs(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client_bus1[0])); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client[0])); + struct i2c_bus1_hardware_monitor_data *dataAst = i2c_get_clientdata(&(cpld_client_bus1)); int rc = 0; switch(platformModelId) @@ -2530,6 +3102,34 @@ static ssize_t show_port_abs(struct device *dev, struct device_attribute *devatt rc = ((SFPPortAbsStatus[attr->index]==1)&&(SFPPortDataValid[attr->index]==1)); break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + unsigned char qsfpPortAbsAst = 0, index = 0, bit = 0; + unsigned char sfpPortDataValidAst = 0; + + if (attr->index < 48) + { + index = (attr->index / 2); + bit = ((attr->index & 0x01) ? 5 : 1); + mutex_lock(&dataAst->lock); + qsfpPortAbsAst = dataAst->sfpPortAbsRxLosStatus[index]; + sfpPortDataValidAst = dataAst->sfpPortDataValidAst[attr->index]; + mutex_unlock(&dataAst->lock); + rc = ((PCA9553_TEST_BIT(qsfpPortAbsAst, bit) ? 0 : 1)&&sfpPortDataValidAst); + } + else + { + index = (attr->index % 48); + mutex_lock(&dataAst->lock); + qsfpPortAbsAst = dataAst->qsfpPortAbsStatusAst[index]; + sfpPortDataValidAst = dataAst->sfpPortDataValidAst[attr->index]; + mutex_unlock(&dataAst->lock); + rc = ((PCA9553_TEST_BIT(qsfpPortAbsAst, 1) ? 0 : 1)&&sfpPortDataValidAst); + } + } + break; + default: { unsigned short qsfpPortAbs=0, index=0, bit=0; @@ -2552,7 +3152,7 @@ static ssize_t show_port_abs(struct device *dev, struct device_attribute *devatt static ssize_t show_port_rxlos(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client_bus1[0])); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client[0])); int rc = 0; switch(platformModelId) @@ -2576,6 +3176,20 @@ static ssize_t show_port_rxlos(struct device *dev, struct device_attribute *deva } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + unsigned char qsfpPortRxLos = 0, index = 0, bit = 0; + + index = (attr->index / 2); + bit = ((attr->index & 0x01) ? 4 : 0); + mutex_lock(&data->lock); + qsfpPortRxLos = data->sfpPortAbsRxLosStatus[index]; + mutex_unlock(&data->lock); + rc = (PCA9553_TEST_BIT(qsfpPortRxLos, bit) ? 1 : 0); + } + break; + default: break; } @@ -2586,8 +3200,7 @@ static ssize_t show_port_rxlos(struct device *dev, struct device_attribute *deva static ssize_t show_port_data_a0(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&qsfpDataA0_client); unsigned char qsfpPortData[QSFP_DATA_SIZE]; ssize_t count = 0; @@ -2605,8 +3218,7 @@ static ssize_t show_port_data_a0(struct device *dev, struct device_attribute *de static ssize_t show_port_data_a2(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&qsfpDataA2_client); unsigned char qsfpPortData[QSFP_DATA_SIZE]; ssize_t count = 0; @@ -2621,6 +3233,24 @@ static ssize_t show_port_data_a2(struct device *dev, struct device_attribute *de return count; } +static ssize_t show_port_sfp_copper(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&SfpCopperData_client); + unsigned char SfpCopperPortData[SFP_COPPER_DATA_SIZE]; + ssize_t count = 0; + + memset(SfpCopperPortData, 0, SFP_COPPER_DATA_SIZE); + mutex_lock(&data->lock); + memcpy(SfpCopperPortData, &(data->SfpCopperPortData[attr->index][0]), SFP_COPPER_DATA_SIZE); + mutex_unlock(&data->lock); + + count = SFP_COPPER_DATA_SIZE; + memcpy(buf, (char *)SfpCopperPortData, SFP_COPPER_DATA_SIZE); + + return count; +} + static ssize_t show_fan_abs(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -2721,7 +3351,7 @@ static ssize_t show_eeprom(struct device *dev, struct device_attribute *devattr, case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - if ((platformBuildRev == 0x01)&&(platformHwRev == 0x03)) /* PVT */ + if (platformHwRev == 0x03) /* PVT */ { struct i2c_client *client = to_i2c_client(dev); struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); @@ -2729,8 +3359,8 @@ static ssize_t show_eeprom(struct device *dev, struct device_attribute *devattr, mutex_lock(&data->lock); /* Turn on PCA9548#1 channel 2 on I2C-bus1 */ i2c_smbus_write_byte(client, 0x04); - i2c_smbus_write_byte_data(&eeprom_client_2, 0x00, 0x00); - ret = eepromDataRead(&eeprom_client_2, &(eepromData[0])); + i2c_smbus_write_byte_data(&eeprom_client, 0x00, 0x00); + ret = eepromDataRead(&eeprom_client, &(eepromData[0])); i2c_smbus_write_byte(client, 0x00); mutex_unlock(&data->lock); } @@ -2815,7 +3445,7 @@ static ssize_t show_psu_eeprom(struct device *dev, struct device_attribute *deva else /* Turn on PCA9548 channel 6 on I2C-bus1 */ i2c_smbus_write_byte(client, 0x40); - ret = qsfpDataRead(&psu_eeprom_client, &(eepromData[0])); + ret = eepromDataBlockRead(&psu_eeprom_client, &(eepromData[0])); i2c_smbus_write_byte(client, 0x00); mutex_unlock(&data->lock); } @@ -2835,7 +3465,7 @@ static ssize_t show_psu_eeprom(struct device *dev, struct device_attribute *deva else /* Turn on PCA9548#1 channel 6 on I2C-bus1 */ i2c_smbus_write_byte(&(pca9548_client[1]), 0x40); - ret = qsfpDataRead(&psu_eeprom_client, &(eepromData[0])); + ret = eepromDataBlockRead(&psu_eeprom_client, &(eepromData[0])); i2c_smbus_write_byte(&(pca9548_client[1]), 0x00); mutex_unlock(&data->lock); } @@ -2844,18 +3474,35 @@ static ssize_t show_psu_eeprom(struct device *dev, struct device_attribute *deva case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + /* + Because the write ability of EEPROM with 0xAx address on I2C bus 0 (I801 bus) is blocked by BIOS, + it does not support I2C block read, it supports byte read only. + The PSUs will be moved to I2C bus 1 (iSMT bus) in PVT rev2. + */ + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + ret = eepromDataBlockRead(&psu_eeprom_client, &(eepromData[0])); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - ret = qsfpDataRead(&psu_eeprom_client_bus0, &(eepromData[0])); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + ret = eepromDataByteRead(&psu_eeprom_client_bus0, &(eepromData[0])); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; @@ -2883,6 +3530,8 @@ static ssize_t show_psu_vout(struct device *dev, struct device_attribute *devatt ssize_t count = 0; unsigned int temp = 0; unsigned int psu_present = 0; + unsigned char valueE = 0; + unsigned short valueY = 0; index = (attr->index&0x1); if (index&0x01) /* PSU 2 */ @@ -2944,36 +3593,70 @@ static ssize_t show_psu_vout(struct device *dev, struct device_attribute *devatt case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + valueN = i2c_smbus_read_byte_data(&psu_mcu_client, 0x20); + valueV = (unsigned int)i2c_smbus_read_word_data(&psu_mcu_client, 0x8B); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - valueN = i2c_smbus_read_byte_data(&psu_mcu_client_bus0, 0x20); - valueV = (unsigned int)i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8B); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + valueN = i2c_smbus_read_byte_data(&psu_mcu_client_bus0, 0x20); + valueV = (unsigned int)i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8B); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; default: break; } - if (valueN & 0x10) + + if (valueN == 0xff) { - valueN = 0xF0 + (valueN & 0x0F); - valueN = (~valueN) +1; - temp = (unsigned int)(1<> 11); + valueE = valueV + 1; + temp = (unsigned int)(1 << valueE); + if (temp) + count = sprintf(buf, "%d.%04d\n", valueY >> valueE, ((valueY % temp) * 10000) / temp); + } + else + { + valueN = (((valueV) >> 11) & 0x0F); + count = sprintf(buf, "%d\n", (valueY*(1<lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + value = i2c_smbus_read_word_data(&psu_mcu_client, 0x8C); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8C); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8C); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; @@ -3165,18 +3860,30 @@ static ssize_t show_psu_temp_1(struct device *dev, struct device_attribute *deva case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + value = i2c_smbus_read_word_data(&psu_mcu_client, 0x8D); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8D); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8D); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; @@ -3235,8 +3942,6 @@ static ssize_t show_psu_temp_2(struct device *dev, struct device_attribute *deva { case HURACAN_WITH_BMC: case HURACAN_WITHOUT_BMC: - case ASTERION_WITH_BMC: - case ASTERION_WITHOUT_BMC: case HURACAN_A_WITH_BMC: case HURACAN_A_WITHOUT_BMC: { @@ -3276,21 +3981,37 @@ static ssize_t show_psu_temp_2(struct device *dev, struct device_attribute *deva case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + value = i2c_smbus_read_word_data(&psu_mcu_client, 0x8E); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8E); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x8E); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + break; + default: break; } @@ -3384,18 +4105,30 @@ static ssize_t show_psu_fan_speed(struct device *dev, struct device_attribute *d case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + value = i2c_smbus_read_word_data(&psu_mcu_client, 0x90); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x90); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x90); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; @@ -3479,18 +4212,30 @@ static ssize_t show_psu_pout(struct device *dev, struct device_attribute *devatt case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + value = i2c_smbus_read_word_data(&psu_mcu_client, 0x96); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x96); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x96); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; @@ -3549,8 +4294,6 @@ static ssize_t show_psu_pin(struct device *dev, struct device_attribute *devattr { case HURACAN_WITH_BMC: case HURACAN_WITHOUT_BMC: - case ASTERION_WITH_BMC: - case ASTERION_WITHOUT_BMC: case HURACAN_A_WITH_BMC: case HURACAN_A_WITHOUT_BMC: { @@ -3590,21 +4333,37 @@ static ssize_t show_psu_pin(struct device *dev, struct device_attribute *devattr case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); - - mutex_lock(&data_bus0->lock); - if (index) - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ + { + mutex_lock(&data->lock); + if (index) + i2c_smbus_write_byte(client, 0x20); /* Turn on PCA9548 channel 5 on I2C-bus1 */ + else + i2c_smbus_write_byte(client, 0x10); /* Turn on PCA9548 channel 4 on I2C-bus1 */ + value = i2c_smbus_read_word_data(&psu_mcu_client, 0x97); + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } else - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x97); - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); + { + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if (index) + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + else + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + value = i2c_smbus_read_word_data(&psu_mcu_client_bus0, 0x97); + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); + } } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + break; + default: break; } @@ -3715,7 +4474,6 @@ static ssize_t set_psu_power_off(struct device *dev, struct device_attribute *de case NCIIX_WITH_BMC: case NCIIX_WITHOUT_BMC: { - struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); /* Setting the ON_OFF_CONFIG Command (02h) to type 9 (SW : turn-on/off by operation command). I2C Command: B2 02 19 59 @@ -3729,23 +4487,48 @@ static ssize_t set_psu_power_off(struct device *dev, struct device_attribute *de */ unsigned short cmd_data_2 = 0x2900; - mutex_lock(&data_bus0->lock); - if ((platformPsuABS&0x01)==0x00) /* PSU1 Present */ + if ((platformBuildRev > 0x01) && (platformHwRev == 0x03)) /* PVT rev2*/ { - /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); - i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x02, cmd_data_1); - i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x01, cmd_data_2); + mutex_lock(&data->lock); + if ((platformPsuABS & 0x01) == 0x00) /* PSU1 Present */ + { + /* Turn on PCA9548#0 channel 4 on I2C-bus1 */ + i2c_smbus_write_byte(client, 0x10); + i2c_smbus_write_word_data(&psu_mcu_client, 0x02, cmd_data_1); + i2c_smbus_write_word_data(&psu_mcu_client, 0x01, cmd_data_2); + } + if ((platformPsuABS & 0x02) == 0x00) /* PSU2 Present */ + { + /* Turn on PCA9548#0 channel 5 on I2C-bus1 */ + i2c_smbus_write_byte(client, 0x20); + i2c_smbus_write_word_data(&psu_mcu_client, 0x02, cmd_data_1); + i2c_smbus_write_word_data(&psu_mcu_client, 0x01, cmd_data_2); + } + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); } - if ((platformPsuABS&0x02)==0x00) /* PSU2 Present */ + else { - /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ - i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); - i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x02, cmd_data_1); - i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x01, cmd_data_2); + struct i2c_bus0_hardware_monitor_data *data_bus0 = i2c_get_clientdata(&psu_eeprom_client_bus0); + + mutex_lock(&data_bus0->lock); + if ((platformPsuABS & 0x01) == 0x00) /* PSU1 Present */ + { + /* Turn on PCA9548#0 channel 1 on I2C-bus0 */ + i2c_smbus_write_byte(&pca9548_client_bus0, 0x02); + i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x02, cmd_data_1); + i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x01, cmd_data_2); + } + if ((platformPsuABS & 0x02) == 0x00) /* PSU2 Present */ + { + /* Turn on PCA9548#0 channel 2 on I2C-bus0 */ + i2c_smbus_write_byte(&pca9548_client_bus0, 0x04); + i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x02, cmd_data_1); + i2c_smbus_write_word_data(&psu_mcu_client_bus0, 0x01, cmd_data_2); + } + i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); + mutex_unlock(&data_bus0->lock); } - i2c_smbus_write_byte(&pca9548_client_bus0, 0x00); - mutex_unlock(&data_bus0->lock); } break; @@ -3776,6 +4559,108 @@ static ssize_t set_system_led(struct device *dev, struct device_attribute *devat return count; } +static ssize_t show_fan_led(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + unsigned int temp; + unsigned int frontLedStatus; + + mutex_lock(&data->lock); + frontLedStatus = (unsigned int)data->frontLedStatus; + switch(platformModelId) + { + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + if (!(frontLedStatus & 0x0010)) + temp = 2; /* Normal */ + else if (!(frontLedStatus & 0x0020)) + temp = 1; /* Critical */ + else + temp = 0; /* Booting */ + } + break; + default: + { + if (!(frontLedStatus & 0x0008)) + temp = 2; /* Normal */ + else if (!(frontLedStatus & 0x0004)) + temp = 1; /* Critical */ + else + temp = 0; /* Booting */ + } + break; + } + mutex_unlock(&data->lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_psu_led(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + unsigned int temp; + unsigned int frontLedStatus; + + mutex_lock(&data->lock); + frontLedStatus = (unsigned int)data->frontLedStatus; + switch(platformModelId) + { + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + if (attr->index == 0) + { + if (!(frontLedStatus & 0x0001)) + temp = 2; /* Normal */ + else if (!(frontLedStatus & 0x0002)) + temp = 1; /* Critical */ + else + temp = 0; /* Booting */ + } + else + { + if (!(frontLedStatus & 0x0004)) + temp = 2; /* Normal */ + else if (!(frontLedStatus & 0x0008)) + temp = 1; /* Critical */ + else + temp = 0; /* Booting */ + } + } + break; + default: + { + if (attr->index == 0) + { + if (!(frontLedStatus & 0x0002)) + temp = 2; /* Normal */ + else if (!(frontLedStatus & 0x0001)) + temp = 1; /* Critical */ + else + temp = 0; /* Booting */ + } + else + { + if (!(frontLedStatus & 0x0020)) + temp = 2; /* Normal */ + else if (!(frontLedStatus & 0x0010)) + temp = 1; /* Critical */ + else + temp = 0; /* Booting */ + } + } + break; + } + + mutex_unlock(&data->lock); + + return sprintf(buf, "%d\n", temp); +} + static ssize_t show_port_tx_disable(struct device *dev, struct device_attribute *devattr, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -3786,8 +4671,7 @@ static ssize_t show_port_tx_disable(struct device *dev, struct device_attribute case SESTO_WITH_BMC: case SESTO_WITHOUT_BMC: { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client[0])); unsigned short index=0, bit=0; index = (attr->index/16); @@ -3805,6 +4689,19 @@ static ssize_t show_port_tx_disable(struct device *dev, struct device_attribute } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client[0])); + unsigned short bit = 0; + + bit = (attr->index % 8); + mutex_lock(&data->lock); + rc = (PCA9553_TEST_BIT(data->sfpPortTxDisableAst[attr->index / 8], bit) ? 1 : 0); + mutex_unlock(&data->lock); + } + break; + default: break; } @@ -3816,14 +4713,17 @@ static ssize_t show_port_tx_disable(struct device *dev, struct device_attribute static ssize_t set_port_tx_disable(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); - struct i2c_client *client = to_i2c_client(dev); - struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + struct i2c_client *client, pca9548Client; + struct i2c_bus1_hardware_monitor_data *data; long temp; if (kstrtol(buf, 10, &temp)) return -EINVAL; temp = clamp_val(temp, 0, 1); + pca9548Client = pca9548_client[1]; + client = &pca9548Client; + data = i2c_get_clientdata(client); switch(platformModelId) { case SESTO_WITH_BMC: @@ -3840,7 +4740,7 @@ static ssize_t set_port_tx_disable(struct device *dev, struct device_attribute * else PCA9553_CLEAR_BIT(data->sfpPortTxDisable[index], bit); i2c_smbus_write_byte(&(pca9548_client[1]), (1<sfpPortTxDisable[index]); + i2c_device_word_write(&(pca9535pwr_client[index]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortTxDisable[index]); i2c_smbus_write_byte(&(pca9548_client[1]), 0x00); mutex_unlock(&data->lock); } @@ -3851,17 +4751,18 @@ static ssize_t set_port_tx_disable(struct device *dev, struct device_attribute * { unsigned short value = 0; + pca9548Client.addr = 0x70; SFPPortTxDisable[attr->index] = (temp&0x1); if ((attr->index/8) == 5) /* SFP+ 40~47 */ { mutex_lock(&data->lock); i2c_smbus_write_byte(client, sfpPortData_78F[attr->index].portMaskIOsForPCA9548_0); - value = i2c_smbus_read_word_data(&(pca9535pwr_client_bus1[sfpPortData_78F[attr->index].i2cAddrForPCA9535]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0); + value = i2c_smbus_read_word_data(&(pca9535pwr_client[sfpPortData_78F[attr->index].i2cAddrForPCA9535]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0); if (temp==1) PCA9553_SET_BIT(value, sfpPortData_78F[attr->index].portMaskBitForTxEnPin); else PCA9553_CLEAR_BIT(value, sfpPortData_78F[attr->index].portMaskBitForTxEnPin); - i2c_device_word_write(&(pca9535pwr_client_bus1[sfpPortData_78F[attr->index].i2cAddrForPCA9535]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, value); + i2c_device_word_write(&(pca9535pwr_client[sfpPortData_78F[attr->index].i2cAddrForPCA9535]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, value); i2c_smbus_write_byte(client, 0x00); mutex_unlock(&data->lock); } @@ -3883,6 +4784,37 @@ static ssize_t set_port_tx_disable(struct device *dev, struct device_attribute * } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + unsigned short index = 0, bit = 0; + + pca9548Client.addr = 0x72; + index = (attr->index / 8); + bit = (attr->index % 8); + + mutex_lock(&data->lock); + if (temp == 1) + PCA9553_SET_BIT(data->sfpPortTxDisableAst[index], bit); + else + PCA9553_CLEAR_BIT(data->sfpPortTxDisableAst[index], bit); + + if (index < 3) + { + i2c_smbus_write_byte(client, (1 << PCA9548_CH00)); + i2c_smbus_write_byte_data(&(cpld_client_bus1), (0x40 + index), data->sfpPortTxDisableAst[index]); + } + else + { + i2c_smbus_write_byte(client, (1 << PCA9548_CH01)); + i2c_smbus_write_byte_data(&(cpld_client_bus1), (0x40 + (index - 3)), data->sfpPortTxDisableAst[index]); + } + + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } + break; + default: break; } @@ -3912,6 +4844,20 @@ static ssize_t show_port_rate_select(struct device *dev, struct device_attribute } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + struct i2c_client *client = to_i2c_client(dev); + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); + unsigned short index = 0; + + index = (attr->index % 4); + mutex_lock(&data->lock); + rc = (PCA9553_TEST_BIT(data->sfpPortRateSelectAst[attr->index / 4], (index * 2)) ? 1 : 0); + mutex_unlock(&data->lock); + } + break; + default: break; } @@ -3950,15 +4896,15 @@ static ssize_t set_port_rate_select(struct device *dev, struct device_attribute switch(index) { case 0: - i2c_device_word_write(&(pca9535pwr_client_bus1[0]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[0]); + i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[0]); break; case 1: - i2c_device_word_write(&(pca9535pwr_client_bus1[1]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[1]); + i2c_device_word_write(&(pca9535pwr_client[1]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[1]); break; case 2: - i2c_device_word_write(&(pca9535pwr_client_bus1[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[2]); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[2]); break; default: @@ -3968,15 +4914,15 @@ static ssize_t set_port_rate_select(struct device *dev, struct device_attribute switch(index) { case 0: - i2c_device_word_write(&(pca9535pwr_client_bus1[0]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[0]); + i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[0]); break; case 1: - i2c_device_word_write(&(pca9535pwr_client_bus1[1]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[1]); + i2c_device_word_write(&(pca9535pwr_client[1]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[1]); break; case 2: - i2c_device_word_write(&(pca9535pwr_client_bus1[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[2]); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->sfpPortRateSelect[2]); break; default: @@ -3987,6 +4933,97 @@ static ssize_t set_port_rate_select(struct device *dev, struct device_attribute } break; + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + unsigned short index = 0, bit = 0; + + index = (attr->index / 4); + bit = (attr->index % 4); + + mutex_lock(&data->lock); + if (attr->index >= 0 && attr->index < 24) + { + /* Turn on PCA9548#0 channel 0 on I2C-bus1 - RX_RS, TX_RS */ + i2c_smbus_write_byte(client, (1 << PCA9548_CH00)); + + if (temp == 1) + { + PCA9553_SET_BIT(data->sfpPortRateSelectAst[index], (bit * 2)); + PCA9553_SET_BIT(data->sfpPortRateSelectAst[index], (bit * 2 + 1)); + } + else + { + PCA9553_CLEAR_BIT(data->sfpPortRateSelectAst[index], (bit * 2)); + PCA9553_CLEAR_BIT(data->sfpPortRateSelectAst[index], (bit * 2 + 1)); + } + + switch(index) + { + case 0: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x8, data->sfpPortRateSelectAst[index]); + break; + case 1: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x9, data->sfpPortRateSelectAst[index]); + break; + case 2: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x10, data->sfpPortRateSelectAst[index]); + break; + case 3: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x11, data->sfpPortRateSelectAst[index]); + break; + case 4: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x12, data->sfpPortRateSelectAst[index]); + break; + case 5: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x13, data->sfpPortRateSelectAst[index]); + break; + } + } + else + { + /* Turn on PCA9548#0 channel 1 on I2C-bus1 - RX_RS, TX_RS */ + i2c_smbus_write_byte(client, (1 << PCA9548_CH01)); + + if (temp == 1) + { + PCA9553_SET_BIT(data->sfpPortRateSelectAst[index], (bit * 2)); + PCA9553_SET_BIT(data->sfpPortRateSelectAst[index], (bit * 2 + 1)); + } + else + { + PCA9553_CLEAR_BIT(data->sfpPortRateSelectAst[index], (bit * 2)); + PCA9553_CLEAR_BIT(data->sfpPortRateSelectAst[index], (bit * 2 + 1)); + } + + switch(index) + { + case 6: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x8, data->sfpPortRateSelectAst[index]); + break; + case 7: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x9, data->sfpPortRateSelectAst[index]); + break; + case 8: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x10, data->sfpPortRateSelectAst[index]); + break; + case 9: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x11, data->sfpPortRateSelectAst[index]); + break; + case 10: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x12, data->sfpPortRateSelectAst[index]); + break; + case 11: + i2c_smbus_write_byte_data(&(cpld_client_bus1), 0x13, data->sfpPortRateSelectAst[index]); + break; + } + } + + i2c_smbus_write_byte(client, 0x00); + mutex_unlock(&data->lock); + } + break; + default: break; } @@ -3994,8 +5031,62 @@ static ssize_t set_port_rate_select(struct device *dev, struct device_attribute return count; } +static ssize_t show_port_tx_fault(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int rc = 0; + + switch(platformModelId) + { + case SESTO_WITH_BMC: + case SESTO_WITHOUT_BMC: + { + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client[0])); + unsigned short index = 0, bit = 0; + + index = (attr->index / 16); + bit = (attr->index % 16); + mutex_lock(&data->lock); + rc = (PCA9553_TEST_BIT(data->sfpPortTxFaultStatus[index], bit) ? 1 : 0); + mutex_unlock(&data->lock); + } + break; + + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + { + rc = (SFPPortTxFaultStatus[attr->index] ? 0 : 1); + } + break; + + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&(pca9535pwr_client[0])); + unsigned char qsfpPortRxLos = 0, index = 0, bit = 0; + + index = (attr->index / 2); + bit = ((attr->index & 0x01) ? 7 : 3); + mutex_lock(&data->lock); + qsfpPortRxLos = data->sfpPortAbsRxLosStatus[index]; + mutex_unlock(&data->lock); + rc = (PCA9553_TEST_BIT(qsfpPortRxLos, bit) ? 1 : 0); + } + break; + + default: + break; + } + + + return sprintf(buf, "%d\n", rc); +} + static DEVICE_ATTR(eeprom, S_IRUGO, show_eeprom, NULL); static DEVICE_ATTR(system_led, S_IWUSR, NULL, set_system_led); +static DEVICE_ATTR(fan_led, S_IRUGO, show_fan_led, NULL); +static SENSOR_DEVICE_ATTR(psu1_led, S_IRUGO, show_psu_led, NULL, 0); +static SENSOR_DEVICE_ATTR(psu2_led, S_IRUGO, show_psu_led, NULL, 1); static SENSOR_DEVICE_ATTR(port_1_data_a0, S_IRUGO, show_port_data_a0, NULL, 0); static SENSOR_DEVICE_ATTR(port_2_data_a0, S_IRUGO, show_port_data_a0, NULL, 1); @@ -4127,6 +5218,71 @@ static SENSOR_DEVICE_ATTR(port_62_data_a2, S_IRUGO, show_port_data_a2, NULL, 61) static SENSOR_DEVICE_ATTR(port_63_data_a2, S_IRUGO, show_port_data_a2, NULL, 62); static SENSOR_DEVICE_ATTR(port_64_data_a2, S_IRUGO, show_port_data_a2, NULL, 63); +static SENSOR_DEVICE_ATTR(port_1_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 0); +static SENSOR_DEVICE_ATTR(port_2_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 1); +static SENSOR_DEVICE_ATTR(port_3_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 2); +static SENSOR_DEVICE_ATTR(port_4_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 3); +static SENSOR_DEVICE_ATTR(port_5_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 4); +static SENSOR_DEVICE_ATTR(port_6_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 5); +static SENSOR_DEVICE_ATTR(port_7_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 6); +static SENSOR_DEVICE_ATTR(port_8_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 7); +static SENSOR_DEVICE_ATTR(port_9_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 8); +static SENSOR_DEVICE_ATTR(port_10_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 9); +static SENSOR_DEVICE_ATTR(port_11_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 10); +static SENSOR_DEVICE_ATTR(port_12_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 11); +static SENSOR_DEVICE_ATTR(port_13_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 12); +static SENSOR_DEVICE_ATTR(port_14_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 13); +static SENSOR_DEVICE_ATTR(port_15_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 14); +static SENSOR_DEVICE_ATTR(port_16_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 15); +static SENSOR_DEVICE_ATTR(port_17_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 16); +static SENSOR_DEVICE_ATTR(port_18_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 17); +static SENSOR_DEVICE_ATTR(port_19_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 18); +static SENSOR_DEVICE_ATTR(port_20_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 19); +static SENSOR_DEVICE_ATTR(port_21_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 20); +static SENSOR_DEVICE_ATTR(port_22_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 21); +static SENSOR_DEVICE_ATTR(port_23_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 22); +static SENSOR_DEVICE_ATTR(port_24_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 23); +static SENSOR_DEVICE_ATTR(port_25_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 24); +static SENSOR_DEVICE_ATTR(port_26_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 25); +static SENSOR_DEVICE_ATTR(port_27_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 26); +static SENSOR_DEVICE_ATTR(port_28_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 27); +static SENSOR_DEVICE_ATTR(port_29_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 28); +static SENSOR_DEVICE_ATTR(port_30_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 29); +static SENSOR_DEVICE_ATTR(port_31_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 30); +static SENSOR_DEVICE_ATTR(port_32_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 31); +static SENSOR_DEVICE_ATTR(port_33_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 32); +static SENSOR_DEVICE_ATTR(port_34_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 33); +static SENSOR_DEVICE_ATTR(port_35_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 34); +static SENSOR_DEVICE_ATTR(port_36_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 35); +static SENSOR_DEVICE_ATTR(port_37_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 36); +static SENSOR_DEVICE_ATTR(port_38_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 37); +static SENSOR_DEVICE_ATTR(port_39_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 38); +static SENSOR_DEVICE_ATTR(port_40_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 39); +static SENSOR_DEVICE_ATTR(port_41_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 40); +static SENSOR_DEVICE_ATTR(port_42_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 41); +static SENSOR_DEVICE_ATTR(port_43_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 42); +static SENSOR_DEVICE_ATTR(port_44_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 43); +static SENSOR_DEVICE_ATTR(port_45_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 44); +static SENSOR_DEVICE_ATTR(port_46_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 45); +static SENSOR_DEVICE_ATTR(port_47_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 46); +static SENSOR_DEVICE_ATTR(port_48_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 47); +static SENSOR_DEVICE_ATTR(port_49_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 48); +static SENSOR_DEVICE_ATTR(port_50_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 49); +static SENSOR_DEVICE_ATTR(port_51_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 50); +static SENSOR_DEVICE_ATTR(port_52_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 51); +static SENSOR_DEVICE_ATTR(port_53_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 52); +static SENSOR_DEVICE_ATTR(port_54_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 53); +static SENSOR_DEVICE_ATTR(port_55_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 54); +static SENSOR_DEVICE_ATTR(port_56_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 55); +static SENSOR_DEVICE_ATTR(port_57_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 56); +static SENSOR_DEVICE_ATTR(port_58_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 57); +static SENSOR_DEVICE_ATTR(port_59_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 58); +static SENSOR_DEVICE_ATTR(port_60_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 59); +static SENSOR_DEVICE_ATTR(port_61_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 60); +static SENSOR_DEVICE_ATTR(port_62_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 61); +static SENSOR_DEVICE_ATTR(port_63_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 62); +static SENSOR_DEVICE_ATTR(port_64_sfp_copper, S_IRUGO, show_port_sfp_copper, NULL, 63); + static SENSOR_DEVICE_ATTR(port_1_abs, S_IRUGO, show_port_abs, NULL, 0); static SENSOR_DEVICE_ATTR(port_2_abs, S_IRUGO, show_port_abs, NULL, 1); static SENSOR_DEVICE_ATTR(port_3_abs, S_IRUGO, show_port_abs, NULL, 2); @@ -4375,6 +5531,9 @@ static DEVICE_ATTR(psu_power_off, S_IWUSR, NULL, set_psu_power_off); static struct attribute *i2c_bus1_hardware_monitor_attr_huracan[] = { &dev_attr_eeprom.attr, &dev_attr_system_led.attr, + &dev_attr_fan_led.attr, + &sensor_dev_attr_psu1_led.dev_attr.attr, + &sensor_dev_attr_psu2_led.dev_attr.attr, &sensor_dev_attr_port_1_data_a0.dev_attr.attr, &sensor_dev_attr_port_2_data_a0.dev_attr.attr, @@ -4442,6 +5601,39 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_huracan[] = { &sensor_dev_attr_port_31_data_a2.dev_attr.attr, &sensor_dev_attr_port_32_data_a2.dev_attr.attr, + &sensor_dev_attr_port_1_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_2_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_3_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_4_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_5_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_6_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_7_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_8_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_9_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_10_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_11_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_12_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_13_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_14_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_15_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_16_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_17_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_18_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_19_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_20_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_21_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_22_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_23_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_24_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_25_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_26_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_27_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_28_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_29_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_30_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_31_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_32_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_1_abs.dev_attr.attr, &sensor_dev_attr_port_2_abs.dev_attr.attr, &sensor_dev_attr_port_3_abs.dev_attr.attr, @@ -4512,6 +5704,9 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_huracan[] = { static struct attribute *i2c_bus1_hardware_monitor_attr_sesto[] = { &dev_attr_eeprom.attr, &dev_attr_system_led.attr, + &dev_attr_fan_led.attr, + &sensor_dev_attr_psu1_led.dev_attr.attr, + &sensor_dev_attr_psu2_led.dev_attr.attr, &sensor_dev_attr_port_1_data_a0.dev_attr.attr, &sensor_dev_attr_port_2_data_a0.dev_attr.attr, @@ -4623,6 +5818,61 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_sesto[] = { &sensor_dev_attr_port_53_data_a2.dev_attr.attr, &sensor_dev_attr_port_54_data_a2.dev_attr.attr, + &sensor_dev_attr_port_1_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_2_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_3_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_4_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_5_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_6_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_7_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_8_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_9_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_10_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_11_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_12_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_13_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_14_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_15_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_16_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_17_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_18_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_19_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_20_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_21_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_22_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_23_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_24_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_25_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_26_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_27_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_28_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_29_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_30_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_31_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_32_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_33_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_34_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_35_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_36_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_37_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_38_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_39_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_40_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_41_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_42_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_43_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_44_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_45_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_46_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_47_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_48_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_49_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_50_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_51_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_52_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_53_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_54_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_1_abs.dev_attr.attr, &sensor_dev_attr_port_2_abs.dev_attr.attr, &sensor_dev_attr_port_3_abs.dev_attr.attr, @@ -4862,6 +6112,9 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_sesto[] = { static struct attribute *i2c_bus1_hardware_monitor_attr_nc2x[] = { &dev_attr_eeprom.attr, &dev_attr_system_led.attr, + &dev_attr_fan_led.attr, + &sensor_dev_attr_psu1_led.dev_attr.attr, + &sensor_dev_attr_psu2_led.dev_attr.attr, &sensor_dev_attr_port_1_data_a0.dev_attr.attr, &sensor_dev_attr_port_2_data_a0.dev_attr.attr, @@ -4973,6 +6226,61 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_nc2x[] = { &sensor_dev_attr_port_53_data_a2.dev_attr.attr, &sensor_dev_attr_port_54_data_a2.dev_attr.attr, + &sensor_dev_attr_port_1_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_2_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_3_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_4_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_5_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_6_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_7_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_8_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_9_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_10_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_11_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_12_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_13_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_14_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_15_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_16_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_17_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_18_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_19_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_20_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_21_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_22_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_23_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_24_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_25_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_26_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_27_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_28_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_29_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_30_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_31_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_32_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_33_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_34_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_35_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_36_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_37_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_38_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_39_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_40_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_41_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_42_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_43_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_44_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_45_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_46_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_47_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_48_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_49_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_50_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_51_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_52_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_53_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_54_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_1_abs.dev_attr.attr, &sensor_dev_attr_port_2_abs.dev_attr.attr, &sensor_dev_attr_port_3_abs.dev_attr.attr, @@ -5163,6 +6471,9 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_nc2x[] = { static struct attribute *i2c_bus1_hardware_monitor_attr_asterion[] = { &dev_attr_eeprom.attr, &dev_attr_system_led.attr, + &dev_attr_fan_led.attr, + &sensor_dev_attr_psu1_led.dev_attr.attr, + &sensor_dev_attr_psu2_led.dev_attr.attr, &sensor_dev_attr_port_1_data_a0.dev_attr.attr, &sensor_dev_attr_port_2_data_a0.dev_attr.attr, @@ -5294,6 +6605,71 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_asterion[] = { &sensor_dev_attr_port_63_data_a2.dev_attr.attr, &sensor_dev_attr_port_64_data_a2.dev_attr.attr, + &sensor_dev_attr_port_1_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_2_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_3_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_4_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_5_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_6_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_7_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_8_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_9_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_10_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_11_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_12_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_13_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_14_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_15_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_16_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_17_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_18_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_19_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_20_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_21_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_22_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_23_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_24_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_25_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_26_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_27_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_28_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_29_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_30_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_31_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_32_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_33_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_34_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_35_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_36_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_37_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_38_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_39_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_40_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_41_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_42_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_43_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_44_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_45_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_46_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_47_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_48_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_49_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_50_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_51_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_52_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_53_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_54_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_55_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_56_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_57_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_58_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_59_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_60_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_61_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_62_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_63_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_64_sfp_copper.dev_attr.attr, + &sensor_dev_attr_port_1_abs.dev_attr.attr, &sensor_dev_attr_port_2_abs.dev_attr.attr, &sensor_dev_attr_port_3_abs.dev_attr.attr, @@ -5524,30 +6900,415 @@ static struct attribute *i2c_bus1_hardware_monitor_attr_asterion[] = { &sensor_dev_attr_psu1_vout.dev_attr.attr, &sensor_dev_attr_psu1_iout.dev_attr.attr, &sensor_dev_attr_psu1_temp_1.dev_attr.attr, - &sensor_dev_attr_psu1_temp_2.dev_attr.attr, &sensor_dev_attr_psu1_fan_speed.dev_attr.attr, &sensor_dev_attr_psu1_pout.dev_attr.attr, - &sensor_dev_attr_psu1_pin.dev_attr.attr, &sensor_dev_attr_psu2_vout.dev_attr.attr, &sensor_dev_attr_psu2_iout.dev_attr.attr, &sensor_dev_attr_psu2_temp_1.dev_attr.attr, - &sensor_dev_attr_psu2_temp_2.dev_attr.attr, &sensor_dev_attr_psu2_fan_speed.dev_attr.attr, &sensor_dev_attr_psu2_pout.dev_attr.attr, - &sensor_dev_attr_psu2_pin.dev_attr.attr, &dev_attr_psu_power_off.attr, NULL }; +static int is_port_present(struct i2c_bus1_hardware_monitor_data *data, int port) +{ + int rc = 0; + + switch(platformModelId) + { + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + rc = ((SFPPortAbsStatus[port] == 1) && (SFPPortDataValid[port] == 1)); + break; + + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + { + unsigned char qsfpPortAbsAst = 0, index = 0, bit = 0; + unsigned char sfpPortDataValidAst = 0; + + if (port < 48) + { + index = (port / 2); + bit = ((port & 0x01) ? 5 : 1); + qsfpPortAbsAst = data->sfpPortAbsRxLosStatus[index]; + sfpPortDataValidAst = data->sfpPortDataValidAst[port]; + rc = ((PCA9553_TEST_BIT(qsfpPortAbsAst, bit) ? 0 : 1) && (sfpPortDataValidAst)); + } + else + { + index = (port % 48); + qsfpPortAbsAst = data->qsfpPortAbsStatusAst[index]; + sfpPortDataValidAst = data->sfpPortDataValidAst[port]; + rc = ((PCA9553_TEST_BIT(qsfpPortAbsAst, 1) ? 0 : 1) && (sfpPortDataValidAst)); + } + } + break; + + default: + { + unsigned short qsfpPortAbs = 0, index = 0, bit = 0; + unsigned short qsfpPortDataValid = 0; + + index = (port / 16); + bit = (port % 16); + qsfpPortAbs = data->qsfpPortAbsStatus[index]; + qsfpPortDataValid = data->qsfpPortDataValid[index]; + rc = ((PCA9553_TEST_BIT(qsfpPortAbs, bit) ? 0 : 1) && (PCA9553_TEST_BIT(qsfpPortDataValid, bit))); + } + break; + } + + return rc; +} + +static ssize_t get_qsfp_port_tx_rx_status(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&qsfpDataA0_client); + unsigned char qsfpPortData[QSFP_DATA_SIZE]; + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int index = (client->addr - 1); + int val = 0; + + memset(qsfpPortData, 0, QSFP_DATA_SIZE); + + mutex_lock(&data->lock); + if (is_port_present(data, index) == 1) + memcpy(qsfpPortData, &(data->qsfpPortDataA0[index][0]), QSFP_DATA_SIZE); + else + { + qsfpPortData[SFF8436_RX_LOS_ADDR] = qsfpPortData[SFF8436_TX_FAULT_ADDR] = 0xF; + qsfpPortData[SFF8436_TX_DISABLE_ADDR] = data->qsfpPortTxDisableData[index]; + } + mutex_unlock(&data->lock); + + switch (attr->index) + { + case RX_LOS: + val = (qsfpPortData[SFF8436_RX_LOS_ADDR] & 0xF); + break; + case RX_LOS1: + case RX_LOS2: + case RX_LOS3: + case RX_LOS4: + val = (qsfpPortData[SFF8436_RX_LOS_ADDR] & BIT_INDEX(attr->index - RX_LOS1)); + break; + + case TX_DISABLE: + val = (qsfpPortData[SFF8436_TX_DISABLE_ADDR] & 0xF); + break; + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + val = (qsfpPortData[SFF8436_TX_DISABLE_ADDR] & BIT_INDEX(attr->index - TX_DISABLE1)); + break; + + case TX_FAULT: + val = (qsfpPortData[SFF8436_TX_FAULT_ADDR] & 0xF); + break; + case TX_FAULT1: + case TX_FAULT2: + case TX_FAULT3: + case TX_FAULT4: + val = (qsfpPortData[SFF8436_TX_FAULT_ADDR] & BIT_INDEX(attr->index - TX_FAULT1)); + break; + + default: + break; + } + return sprintf(buf, "%d\n", ((val) ? 1 : 0)); +} + +static ssize_t get_port_status(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int status = LAST_ATTRIBUTE; + ssize_t count = 0; + + mutex_lock(&portStatusLock); + + status = attr->index; + + /* common status */ + switch (status) + { + case PRESENT: + attr->index = (client->addr - 1); + count = show_port_abs(dev, devattr, buf); + attr->index = status; + mutex_unlock(&portStatusLock); + return count; + + case EEPROM_A0_PAGE: + attr->index = (client->addr - 1); + count = show_port_data_a0(dev, devattr, buf); + attr->index = status; + mutex_unlock(&portStatusLock); + return count; + + case EEPROM_A2_PAGE: + attr->index = (client->addr - 1); + count = show_port_data_a2(dev, devattr, buf); + attr->index = status; + mutex_unlock(&portStatusLock); + return count; + + case SFP_COPPER: + attr->index = (client->addr - 1); + count = show_port_sfp_copper(dev, devattr, buf); + attr->index = status; + mutex_unlock(&portStatusLock); + return count; + + default: + break; + } + + /* status for QSFP ports */ + if (strncmp(client->name, "qsfp", strlen("qsfp")) == 0) + { + count = get_qsfp_port_tx_rx_status(dev, devattr, buf); + mutex_unlock(&portStatusLock); + return count; + } + + /* status for SFP+ ports */ + attr->index = (client->addr - 1); + switch (status) + { + case RX_LOS: + case RX_LOS1: + case RX_LOS2: + case RX_LOS3: + case RX_LOS4: + count = show_port_rxlos(dev, devattr, buf); + break; + + case TX_DISABLE: + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + count = show_port_tx_disable(dev, devattr, buf); + break; + + case TX_FAULT: + case TX_FAULT1: + case TX_FAULT2: + case TX_FAULT3: + case TX_FAULT4: + count = show_port_tx_fault(dev, devattr, buf); + break; + + default: + count = sprintf(buf, "0\n"); + break; + } + attr->index = status; + mutex_unlock(&portStatusLock); + return count; +} + +static ssize_t set_qsfp_port_tx_status(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&qsfpDataA0_client); + unsigned char qsfpPortData[QSFP_DATA_SIZE]; + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int index = (client->addr - 1); + long disable; + + if (kstrtol(buf, 10, &disable)) + return -EINVAL; + disable = clamp_val(disable, 0, 1); + + memset(qsfpPortData, 0, QSFP_DATA_SIZE); + + mutex_lock(&data->lock); + memcpy(qsfpPortData, &(data->qsfpPortDataA0[index][0]), QSFP_DATA_SIZE); + switch (attr->index) + { + case TX_DISABLE: + if (disable == 1) + data->qsfpPortTxDisableData[index] = (qsfpPortData[SFF8436_TX_DISABLE_ADDR] |0xF); + else + data->qsfpPortTxDisableData[index] = (qsfpPortData[SFF8436_TX_DISABLE_ADDR] & 0xF0); + data->qsfpPortTxDisableDataUpdate[index] = 1; + break; + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + if (disable == 1) + data->qsfpPortTxDisableData[index] = (qsfpPortData[SFF8436_TX_DISABLE_ADDR] | (1 << (attr->index - TX_DISABLE1))); + else + data->qsfpPortTxDisableData[index] = (qsfpPortData[SFF8436_TX_DISABLE_ADDR] & ~(1 << (attr->index - TX_DISABLE1))); + data->qsfpPortTxDisableDataUpdate[index] = 1; + break; + + default: + break; + } + mutex_unlock(&data->lock); + return count; +} + +static ssize_t set_port_tx_status(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int status = LAST_ATTRIBUTE; + + mutex_lock(&portStatusLock); + + /* status for QSFP ports */ + if (strncmp(client->name, "qsfp", strlen("qsfp")) == 0) + { + set_qsfp_port_tx_status(dev, devattr, buf, count); + mutex_unlock(&portStatusLock); + return count; + } + + /* status for SFP+ ports */ + status = attr->index; + attr->index = (client->addr - 1); + switch (status) + { + case TX_DISABLE: + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + set_port_tx_disable(dev, devattr, buf, count); + break; + + default: + break; + } + attr->index = status; + mutex_unlock(&portStatusLock); + return count; +} + +static ssize_t set_port_sfp_copper(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + + /* QSFP ports */ + if (strncmp(client->name, "qsfp", strlen("qsfp")) == 0) + { + return count; + } + /* SFP+ ports */ + else + { + struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(&SfpCopperData_client); + int index = (client->addr - 1); + long value; + + if ((platformModelId != NCIIX_WITH_BMC) && (platformModelId != NCIIX_WITHOUT_BMC)) + return count; + + if (kstrtol(buf, 10, &value)) + return -EINVAL; + + mutex_lock(&data->lock); + if (SFPPortAbsStatus[index]) /*present*/ + { + i2c_smbus_write_byte_data(&(pca9548_client[1]), 0, sfpPortData_78F[index].portMaskBitForPCA9548_1); + i2c_smbus_write_byte_data(&(pca9548_client[0]), 0, sfpPortData_78F[index].portMaskBitForPCA9548_2TO5); + i2c_device_word_write(&SfpCopperData_client, + (unsigned char)((value >> 16) & 0xff), + (unsigned short)(value & 0xffff)); + i2c_smbus_write_byte_data(&(pca9548_client[0]), 0, 0x00); + i2c_smbus_write_byte_data(&(pca9548_client[1]), 0, 0x00); + } + mutex_unlock(&data->lock); + } + + return count; +} + +static SENSOR_DEVICE_ATTR(abs, S_IRUGO, get_port_status, NULL, PRESENT); +static SENSOR_DEVICE_ATTR(rxlos, S_IRUGO, get_port_status, NULL, RX_LOS); +static SENSOR_DEVICE_ATTR(rxlos1, S_IRUGO, get_port_status, NULL, RX_LOS1); +static SENSOR_DEVICE_ATTR(rxlos2, S_IRUGO, get_port_status, NULL, RX_LOS2); +static SENSOR_DEVICE_ATTR(rxlos3, S_IRUGO, get_port_status, NULL, RX_LOS3); +static SENSOR_DEVICE_ATTR(rxlos4, S_IRUGO, get_port_status, NULL, RX_LOS4); +static SENSOR_DEVICE_ATTR(tx_disable, S_IWUSR | S_IRUGO, get_port_status, set_port_tx_status, TX_DISABLE); +static SENSOR_DEVICE_ATTR(tx_disable1, S_IWUSR | S_IRUGO, get_port_status, set_port_tx_status, TX_DISABLE1); +static SENSOR_DEVICE_ATTR(tx_disable2, S_IWUSR | S_IRUGO, get_port_status, set_port_tx_status, TX_DISABLE2); +static SENSOR_DEVICE_ATTR(tx_disable3, S_IWUSR | S_IRUGO, get_port_status, set_port_tx_status, TX_DISABLE3); +static SENSOR_DEVICE_ATTR(tx_disable4, S_IWUSR | S_IRUGO, get_port_status, set_port_tx_status, TX_DISABLE4); +static SENSOR_DEVICE_ATTR(tx_fault, S_IRUGO, get_port_status, NULL, TX_FAULT); +static SENSOR_DEVICE_ATTR(tx_fault1, S_IRUGO, get_port_status, NULL, TX_FAULT1); +static SENSOR_DEVICE_ATTR(tx_fault2, S_IRUGO, get_port_status, NULL, TX_FAULT2); +static SENSOR_DEVICE_ATTR(tx_fault3, S_IRUGO, get_port_status, NULL, TX_FAULT3); +static SENSOR_DEVICE_ATTR(tx_fault4, S_IRUGO, get_port_status, NULL, TX_FAULT4); +static SENSOR_DEVICE_ATTR(data_a0, S_IRUGO, get_port_status, NULL, EEPROM_A0_PAGE); +static SENSOR_DEVICE_ATTR(data_a2, S_IRUGO, get_port_status, NULL, EEPROM_A2_PAGE); +static SENSOR_DEVICE_ATTR(sfp_copper, S_IWUSR | S_IRUGO, get_port_status, set_port_sfp_copper, SFP_COPPER); + +static struct attribute *sfp_attributes[] = { + &sensor_dev_attr_abs.dev_attr.attr, + &sensor_dev_attr_rxlos.dev_attr.attr, + &sensor_dev_attr_rxlos1.dev_attr.attr, + &sensor_dev_attr_rxlos2.dev_attr.attr, + &sensor_dev_attr_rxlos3.dev_attr.attr, + &sensor_dev_attr_rxlos4.dev_attr.attr, + &sensor_dev_attr_tx_disable.dev_attr.attr, + &sensor_dev_attr_tx_disable1.dev_attr.attr, + &sensor_dev_attr_tx_disable2.dev_attr.attr, + &sensor_dev_attr_tx_disable3.dev_attr.attr, + &sensor_dev_attr_tx_disable4.dev_attr.attr, + &sensor_dev_attr_tx_fault.dev_attr.attr, + &sensor_dev_attr_tx_fault1.dev_attr.attr, + &sensor_dev_attr_tx_fault2.dev_attr.attr, + &sensor_dev_attr_tx_fault3.dev_attr.attr, + &sensor_dev_attr_tx_fault4.dev_attr.attr, + &sensor_dev_attr_data_a0.dev_attr.attr, + &sensor_dev_attr_data_a2.dev_attr.attr, + &sensor_dev_attr_sfp_copper.dev_attr.attr, + NULL +}; + +static const struct attribute_group sfp_group = { + .attrs = sfp_attributes, +}; + +static struct i2c_client *sfpPortDeviceCreate(struct i2c_adapter *adap, int port, const char *sfpType) +{ + struct i2c_client *client = NULL; + int status; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!client) + return NULL; + + client->adapter = adap; + client->addr = (port + 1); + sprintf(client->name, "%s_%03d", sfpType, (port + 1)); + client->dev.parent = &client->adapter->dev; + dev_set_name(&client->dev, "port_%03d", (port + 1)); + status = device_register(&client->dev); + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &sfp_group); + return client; +} + static void i2c_bus0_devices_client_address_init(struct i2c_client *client) { int index; - pca9535pwr_client = *client; - pca9535pwr_client.addr = 0x27; + pca9535pwr_client_bus0 = *client; + pca9535pwr_client_bus0.addr = 0x27; cpld_client = *client; cpld_client.addr = 0x33; @@ -5635,7 +7396,7 @@ static void i2c_bus0_hardware_monitor_hw_default_config(struct i2c_client *clien /* Get device id */ data->dviceId= i2c_smbus_read_byte_data(client, W83795ADG_REG_DEVICE_ID); - /* set FANCTL8 ¡V FANCTL1 output mode control to PWM output duty cycle mode. */ + /* set FANCTL8 - FANCTL1 output mode control to PWM output duty cycle mode. */ i2c_smbus_write_byte_data(client, W83795ADG_REG_FOMC, 0x00); i2c_smbus_write_byte_data(client, W83795ADG_REG_F1OV, 0xff); i2c_smbus_write_byte_data(client, W83795ADG_REG_F2OV, 0xff); @@ -5644,6 +7405,10 @@ static void i2c_bus0_hardware_monitor_hw_default_config(struct i2c_client *clien i2c_smbus_write_byte_data(client, W83795ADG_REG_BANK, 0x00); /* Enable TR1~TR4 thermistor temperature monitoring */ i2c_smbus_write_byte_data(client, W83795ADG_REG_TEMP_CTRL2, 0xff); + + /* set FANCTL2 to enable FANIN9 and FANIN10 monitoring */ + i2c_smbus_write_byte_data(client, W83795ADG_REG_FANIN_CTRL2, 0x03); + /* Enable monitoring operations */ configByte |= 0x01; i2c_smbus_write_byte_data(client, W83795ADG_REG_CONFIG, configByte); @@ -5732,10 +7497,10 @@ static void i2c_bus0_hardware_monitor_hw_default_config(struct i2c_client *clien default: /* set default value for IO expander #0 */ - i2c_smbus_write_word_data(&pca9535pwr_client, PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); + i2c_smbus_write_word_data(&pca9535pwr_client_bus0, PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); /* set input-1/output-0 mode for IO expander #0 */ - i2c_smbus_write_word_data(&pca9535pwr_client, PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_smbus_write_word_data(&pca9535pwr_client, PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xff7f); + i2c_smbus_write_word_data(&pca9535pwr_client_bus0, PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_smbus_write_word_data(&pca9535pwr_client_bus0, PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xff7f); break; } @@ -5754,27 +7519,47 @@ static void i2c_bus1_devices_client_address_init(struct i2c_client *client) for (index=0; index<6; index++) { - pca9535pwr_client_bus1[index] = *client; - pca9535pwr_client_bus1[index].addr = (0x20+index); + pca9535pwr_client[index] = *client; + pca9535pwr_client[index].addr = (0x20+index); } + cpld_client_bus1 = *client; + cpld_client_bus1.addr = 0x33; + qsfpDataA0_client = *client; qsfpDataA0_client.addr = 0x50; qsfpDataA2_client = *client; qsfpDataA2_client.addr = 0x51; - eeprom_client = *client; - eeprom_client.addr = 0x54; + SfpCopperData_client = *client; + SfpCopperData_client.addr = 0x56; - eeprom_client_2 = *client; - eeprom_client_2.addr = 0x56; + switch(platformModelId) + { + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + eeprom_client = *client; + eeprom_client.addr = 0x56; - psu_eeprom_client = *client; - psu_eeprom_client.addr = 0x50; + psu_eeprom_client = *client; + psu_eeprom_client.addr = 0x51; - psu_mcu_client = *client; - psu_mcu_client.addr = 0x58; + psu_mcu_client = *client; + psu_mcu_client.addr = 0x59; + break; + + default: + eeprom_client = *client; + eeprom_client.addr = 0x54; + + psu_eeprom_client = *client; + psu_eeprom_client.addr = 0x50; + + psu_mcu_client = *client; + psu_mcu_client.addr = 0x58; + break; + } } static void i2c_bus1_io_expander_default_set(struct i2c_client *client) @@ -5793,8 +7578,8 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #1-4 on channel 4 */ for (i=0; i<4; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); } /* Turn on PCA9548 channel 5 on I2C-bus1 */ @@ -5804,27 +7589,27 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #1-2 on channel 5 */ for (i=0; i<2; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); } /* RST#(Module Reset) = 1 */ /* set input-1/output-0 mode for IO expander #3-4 on channel 5 */ for (i=2; i<4; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0xffff); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0xffff); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); } /* MODSEL# (Module Select) = 0 */ /* set input-1/output-0 mode for IO expander #5-6 on channel 5 */ for (i=4; i<6; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); } if (isBMCSupport == 0) @@ -5833,30 +7618,30 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) i2c_smbus_write_byte(client, (1<frontLedStatus); - i2c_device_word_write(&(pca9535pwr_client_bus1[2]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[2]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->frontLedStatus); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); } } @@ -5875,8 +7660,8 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #1-4 on channel 0 */ for (i=0; i<4; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); } /* Turn on PCA9548#1 channel 1 on I2C-bus1 - RXLOS */ @@ -5884,8 +7669,8 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #1-3 on channel 1 */ for (i=0; i<3; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); } /* Turn on PCA9548#1 channel 2 on I2C-bus1 - TXFAULT */ @@ -5893,8 +7678,8 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #1-3 on channel 2 */ for (i=0; i<3; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); } /* Turn on PCA9548#1 channel 3 on I2C-bus1 - TX_RS = 1, LPMODE = 0, MODSEL = 0 */ @@ -5902,22 +7687,22 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #1-4 on channel 3 */ for (i=0; i<3; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0xffff); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0xffff); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); } - i2c_device_word_write(&(pca9535pwr_client_bus1[3]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[3]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[3]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[3]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[3]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[3]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); /* Turn on PCA9548#1 channel 4 on I2C-bus1 - RX _RS = 1 */ i2c_smbus_write_byte(&(pca9548_client[1]), (1<frontLedStatus); - i2c_device_word_write(&(pca9535pwr_client_bus1[2]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[2]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, data->frontLedStatus); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); /* Turn off PCA9548#0 all channels on I2C-bus1 */ i2c_smbus_write_byte(client, 0x00); } @@ -5979,17 +7764,17 @@ static void i2c_bus1_io_expander_default_set(struct i2c_client *client) /* set input-1/output-0 mode for IO expander #20-23 on channel 0 : SFP+ 40-47 : TXEN = 0, RX_RS = 0, TX_RS = 0 */ for (i=0; i<4; i++) { - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); - i2c_device_word_write(&(pca9535pwr_client_bus1[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xf1c7); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[i]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xf1c7); } /* Turn on PCA9548#1 channel 1 on I2C-bus1 */ i2c_smbus_write_byte(client, (1<frontLedStatus); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[2]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0x0000); + + /* Turn on PCA9548#0 channel 5 on I2C-bus1 */ + i2c_smbus_write_byte(client, (1 << PCA9548_CH05)); + /* PSU Status */ + /* set input-1/output-0 mode for IO expander #1 on channel 5 */ + i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_OUTPUT_PORT_0, 0x0000); + i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_POLARITY_INVERSION_0, 0x0000); +/* If the PSU_PWROFF pin of IO expander is output mode, the power cycling of CPLD cannot work.*/ +#if 0 + i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffbb); +#else + i2c_device_word_write(&(pca9535pwr_client[0]), PCA9553_COMMAND_BYTE_REG_CONFIGURATION_0, 0xffff); +#endif + + /* Turn off PCA9548#0 all channels on I2C-bus1 */ + i2c_smbus_write_byte(client, 0x00); break; default: @@ -6213,6 +8034,69 @@ static int w83795adg_hardware_monitor_probe(struct i2c_client *client, } else { + struct i2c_adapter *adap = to_i2c_adapter(&client->dev); + int port; + + for (port = 0; port < QSFP_COUNT; port++) + data->qsfpPortTxDisableDataUpdate[port] = 1; + mutex_init(&portStatusLock); + switch (platformModelId) + { + case HURACAN_WITH_BMC: + case HURACAN_WITHOUT_BMC: + case HURACAN_A_WITH_BMC: + case HURACAN_A_WITHOUT_BMC: + /* QSFP ports */ + for (port = 0; port < 32; port++) + { + data->sfpPortClient[port] = sfpPortDeviceCreate(adap, port, "qsfp"); + if (!data->sfpPortClient[port]) + return -ENOMEM; + } + break; + + case SESTO_WITH_BMC: + case SESTO_WITHOUT_BMC: + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + /* SFP+ ports */ + for (port = 0; port < 48; port++) + { + data->sfpPortClient[port] = sfpPortDeviceCreate(adap, port, "sfp"); + if (!data->sfpPortClient[port]) + return -ENOMEM; + } + /* QSFP ports */ + for (port = 48; port < 54; port++) + { + data->sfpPortClient[port] = sfpPortDeviceCreate(adap, port, "qsfp"); + if (!data->sfpPortClient[port]) + return -ENOMEM; + } + break; + + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + /* SFP+ ports */ + for (port = 0; port < 48; port++) + { + data->sfpPortClient[port] = sfpPortDeviceCreate(adap, port, "sfp"); + if (!data->sfpPortClient[port]) + return -ENOMEM; + } + /* QSFP ports */ + for (port = 48; port < 64; port++) + { + data->sfpPortClient[port] = sfpPortDeviceCreate(adap, port, "qsfp"); + if (!data->sfpPortClient[port]) + return -ENOMEM; + } + break; + + default: + break; + } + init_completion(&data->auto_update_stop); data->auto_update = kthread_run(i2c_bus1_hardware_monitor_update_thread, client, dev_name(data->hwmon_dev)); if (IS_ERR(data->auto_update)) { @@ -6249,16 +8133,35 @@ static int w83795adg_hardware_monitor_remove(struct i2c_client *client) i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_LED_0x44, 0x00); #endif + mutex_destroy(&client->dev.mutex); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->hwmon_group); + mutex_destroy(&data->lock); } else if(client->adapter->nr == 0x1) { + int port; + struct i2c_client *c; struct i2c_bus1_hardware_monitor_data *data = i2c_get_clientdata(client); kthread_stop(data->auto_update); wait_for_completion(&data->auto_update_stop); + for (port = 0; port < QSFP_COUNT; port ++) + { + c = data->sfpPortClient[port]; + if (c) + { + sysfs_remove_group(&c->dev.kobj, &sfp_group); + mutex_destroy(&c->dev.mutex); + device_del(&c->dev); + kfree(c); + } + } + mutex_destroy(&portStatusLock); + + mutex_destroy(&client->dev.mutex); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->hwmon_group); + mutex_destroy(&data->lock); } return 0; } @@ -6284,8 +8187,22 @@ static void w83795adg_hardware_monitor_shutdown(struct i2c_client *client) i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_LED_0x44, 0x00); #endif /* reset MAC */ - i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x30, 0x6e); - i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x30, 0x6f); + switch(platformModelId) + { + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x30, 0x3e); + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x30, 0x3f); + /* reset CPLD 2, 3 and 4 */ + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x35, 0xfd); /* assert RST_CPLD2_3_4 */ + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x35, 0xff); + break; + + default: + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x30, 0x6e); + i2c_smbus_write_byte_data(&cpld_client, CPLD_REG_RESET_0x30, 0x6f); + break; + } hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->hwmon_group); From 6dd61ba65aad63ca2e6dc4e70d306e76bdadd461 Mon Sep 17 00:00:00 2001 From: Sergey Popovich Date: Mon, 6 Aug 2018 21:53:29 +0300 Subject: [PATCH 13/22] platforms: netberg: Add Aurora 420 switch It is very similar to Aurora 420, even onlp shared object part from Aurora 620 considered as example when porting support for 420 (see the diff between 620 and 420 to find differences if necessary). Main difference in onlp is that we have four LEDs (1 SYS STAT, 2 PSU and 1 for FAN), 7 thermal (4 for two PSU, 1 for MAC, 1 for front and 1 for rear) and 6 fans (4 for board, 2 for PSU). New 420, as well as 620 and 720 requires upstream ONIE to install correctly. Install and boot tested with ONIE "master-201805301609". Signed-off-by: Sergey Popovich --- .../.gitignore | 2 + .../Makefile | 1 + .../modules/Makefile | 1 + .../modules/PKG.yml | 1 + .../onlp/Makefile | 1 + .../onlp/PKG.yml | 1 + .../onlp/builds/Makefile | 2 + .../onlp/builds/lib/Makefile | 45 ++ .../onlp/builds/onlpdump/Makefile | 45 ++ .../.gitignore | 1 + .../.module | 1 + .../Makefile | 9 + .../x86_64_netberg_aurora_420_rangeley.yml | 119 +++++ .../x86_64_netberg_aurora_420_rangeley.x | 14 + ...86_64_netberg_aurora_420_rangeley_config.h | 137 ++++++ .../x86_64_netberg_aurora_420_rangeley_dox.h | 26 + ...6_64_netberg_aurora_420_rangeley_porting.h | 87 ++++ .../module/make.mk | 10 + .../module/src/Makefile | 9 + .../module/src/fani.c | 234 +++++++++ .../module/src/ledi.c | 221 +++++++++ .../module/src/make.mk | 9 + .../module/src/psui.c | 201 ++++++++ .../module/src/sfpi.c | 451 ++++++++++++++++++ .../module/src/sysi.c | 98 ++++ .../module/src/thermali.c | 173 +++++++ ...86_64_netberg_aurora_420_rangeley_config.c | 80 ++++ ...x86_64_netberg_aurora_420_rangeley_enums.c | 10 + .../x86_64_netberg_aurora_420_rangeley_int.h | 271 +++++++++++ .../x86_64_netberg_aurora_420_rangeley_log.c | 18 + .../x86_64_netberg_aurora_420_rangeley_log.h | 12 + ...86_64_netberg_aurora_420_rangeley_module.c | 24 + .../x86_64_netberg_aurora_420_rangeley_ucli.c | 50 ++ .../platform-config/Makefile | 1 + .../platform-config/r0/Makefile | 1 + .../platform-config/r0/PKG.yml | 1 + .../x86-64-netberg-aurora-420-rangeley-r0.yml | 30 ++ .../__init__.py | 12 + 38 files changed, 2409 insertions(+) create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/.gitignore create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/PKG.yml create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/PKG.yml create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/lib/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/onlpdump/Makefile create mode 100644 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.gitignore create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.module create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/Makefile create mode 100644 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/auto/x86_64_netberg_aurora_420_rangeley.yml create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley.x create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_config.h create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_dox.h create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_porting.h create mode 100644 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/make.mk create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/fani.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/ledi.c create mode 100644 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/make.mk create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/psui.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sfpi.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sysi.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/thermali.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_config.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_enums.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_int.h create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.h create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_module.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_ucli.c create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/Makefile create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/PKG.yml create mode 100755 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/lib/x86-64-netberg-aurora-420-rangeley-r0.yml create mode 100644 packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/python/x86_64_netberg_aurora_420_rangeley_r0/__init__.py diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/.gitignore b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/.gitignore new file mode 100755 index 00000000..ec93c180 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/.gitignore @@ -0,0 +1,2 @@ +*x86*64*netberg*aurora*420*rangeley*.mk +onlpdump.mk diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/Makefile new file mode 100755 index 00000000..003238cf --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/Makefile new file mode 100755 index 00000000..003238cf --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/PKG.yml b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/PKG.yml new file mode 100755 index 00000000..b3df78e4 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/modules/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/no-platform-modules.yml ARCH=amd64 VENDOR=netberg BASENAME=x86-64-netberg-aurora-420-rangeley diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/Makefile new file mode 100755 index 00000000..003238cf --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/PKG.yml b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/PKG.yml new file mode 100755 index 00000000..85e495fc --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/onlp-platform-any.yml PLATFORM=x86-64-netberg-aurora-420-rangeley ARCH=amd64 TOOLCHAIN=x86_64-linux-gnu diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/Makefile new file mode 100755 index 00000000..e7437cb2 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/Makefile @@ -0,0 +1,2 @@ +FILTER=src +include $(ONL)/make/subdirs.mk diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/lib/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/lib/Makefile new file mode 100755 index 00000000..b7174f7d --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/lib/Makefile @@ -0,0 +1,45 @@ +############################################################ +# +# +# Copyright 2014 BigSwitch Networks, Inc. +# +# 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 $(ONL)/make/config.amd64.mk + +MODULE := libonlp-x86-64-netberg-aurora-420-rangeley +include $(BUILDER)/standardinit.mk + +DEPENDMODULES := AIM IOF x86_64_netberg_aurora_420_rangeley onlplib +DEPENDMODULE_HEADERS := sff + +include $(BUILDER)/dependmodules.mk + +SHAREDLIB := libonlp-x86-64-netberg-aurora-420-rangeley.so +$(SHAREDLIB)_TARGETS := $(ALL_TARGETS) +include $(BUILDER)/so.mk +.DEFAULT_GOAL := $(SHAREDLIB) + +GLOBAL_CFLAGS += -I$(onlp_BASEDIR)/module/inc +GLOBAL_CFLAGS += -DAIM_CONFIG_INCLUDE_MODULES_INIT=1 +GLOBAL_CFLAGS += -fPIC +GLOBAL_LINK_LIBS += -lpthread + +include $(BUILDER)/targets.mk + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/onlpdump/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/onlpdump/Makefile new file mode 100755 index 00000000..b88bedd8 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/onlpdump/Makefile @@ -0,0 +1,45 @@ +############################################################ +# +# +# Copyright 2014 BigSwitch Networks, Inc. +# +# 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 $(ONL)/make/config.amd64.mk + +.DEFAULT_GOAL := onlpdump + +MODULE := onlpdump +include $(BUILDER)/standardinit.mk + +DEPENDMODULES := AIM IOF onlp x86_64_netberg_aurora_420_rangeley onlplib onlp_platform_defaults sff cjson cjson_util timer_wheel OS + +include $(BUILDER)/dependmodules.mk + +BINARY := onlpdump +$(BINARY)_LIBRARIES := $(LIBRARY_TARGETS) +include $(BUILDER)/bin.mk + +GLOBAL_CFLAGS += -DAIM_CONFIG_AIM_MAIN_FUNCTION=onlpdump_main +GLOBAL_CFLAGS += -DAIM_CONFIG_INCLUDE_MODULES_INIT=1 +GLOBAL_CFLAGS += -DAIM_CONFIG_INCLUDE_MAIN=1 +GLOBAL_LINK_LIBS += -lpthread -lm + +include $(BUILDER)/targets.mk diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.gitignore b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.gitignore new file mode 100644 index 00000000..c81d16be --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.gitignore @@ -0,0 +1 @@ +*.mk diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.module b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.module new file mode 100755 index 00000000..d3df16ce --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/.module @@ -0,0 +1 @@ +name: x86_64_netberg_aurora_420_rangeley diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/Makefile new file mode 100755 index 00000000..e0be8a99 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/Makefile @@ -0,0 +1,9 @@ +############################################################################### +# +# +# +############################################################################### +include $(ONL)/make/config.mk +MODULE := x86_64_netberg_aurora_420_rangeley +AUTOMODULE := x86_64_netberg_aurora_420_rangeley +include $(BUILDER)/definemodule.mk diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/auto/x86_64_netberg_aurora_420_rangeley.yml b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/auto/x86_64_netberg_aurora_420_rangeley.yml new file mode 100644 index 00000000..c9e72b4f --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/auto/x86_64_netberg_aurora_420_rangeley.yml @@ -0,0 +1,119 @@ +############################################################################### +# +# x86_64_netberg_aurora_420_rangeley Autogeneration Definitions. +# +############################################################################### + +cdefs: &cdefs +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING: + doc: "Include or exclude logging." + default: 1 +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT: + doc: "Default enabled log options." + default: AIM_LOG_OPTIONS_DEFAULT +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT: + doc: "Default enabled log bits." + default: AIM_LOG_BITS_DEFAULT +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT: + doc: "Default enabled custom log bits." + default: 0 +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB: + doc: "Default all porting macros to use the C standard libraries." + default: 1 +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS: + doc: "Include standard library headers for stdlib porting macros." + default: X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI: + doc: "Include generic uCli support." + default: 0 +- X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD: + doc: "RPM Threshold at which the fan is considered to have failed." + default: 3000 + +definitions: + cdefs: + X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_HEADER: + defs: *cdefs + basename: x86_64_netberg_aurora_420_rangeley_config + + enum: &enums + + fan_id: + members: + - FAN1 : 1 + - FAN2 : 2 + - FAN3 : 3 + - FAN4 : 4 + - FAN5 : 5 + - FAN6 : 6 + - FAN7 : 7 + - FAN8 : 8 + - FAN9 : 9 + - FAN10 : 10 + + fan_oid: + members: + - FAN1 : ONLP_FAN_ID_CREATE(1) + - FAN2 : ONLP_FAN_ID_CREATE(2) + - FAN3 : ONLP_FAN_ID_CREATE(3) + - FAN4 : ONLP_FAN_ID_CREATE(4) + - FAN5 : ONLP_FAN_ID_CREATE(5) + - FAN6 : ONLP_FAN_ID_CREATE(6) + - FAN7 : ONLP_FAN_ID_CREATE(7) + - FAN8 : ONLP_FAN_ID_CREATE(8) + - FAN9 : ONLP_FAN_ID_CREATE(9) + - FAN10 : ONLP_FAN_ID_CREATE(10) + + psu_id: + members: + - PSU1 : 1 + - PSU2 : 2 + + psu_oid: + members: + - PSU1 : ONLP_PSU_ID_CREATE(1) + - PSU2 : ONLP_PSU_ID_CREATE(2) + + thermal_id: + members: + - THERMAL1 : 1 + - THERMAL2 : 2 + - THERMAL3 : 3 + - THERMAL4 : 4 + - THERMAL5 : 5 + - THERMAL6 : 6 + - THERMAL7 : 7 + + thermal_oid: + members: + - THERMAL1 : ONLP_THERMAL_ID_CREATE(1) + - THERMAL2 : ONLP_THERMAL_ID_CREATE(2) + - THERMAL3 : ONLP_THERMAL_ID_CREATE(3) + - THERMAL4 : ONLP_THERMAL_ID_CREATE(4) + - THERMAL5 : ONLP_THERMAL_ID_CREATE(5) + - THERMAL6 : ONLP_THERMAL_ID_CREATE(6) + - THERMAL7 : ONLP_THERMAL_ID_CREATE(7) + + led_id: + members: + - STAT : 1 + - FAN : 2 + - PSU1 : 3 + - PSU2 : 4 + + led_oid: + members: + - STAT : ONLP_LED_ID_CREATE(1) + - FAN : ONLP_LED_ID_CREATE(2) + - PSU1 : ONLP_LED_ID_CREATE(3) + - PSU2 : ONLP_LED_ID_CREATE(4) + + portingmacro: + X86_64_NETBERG_AURORA_420_RANGELEY: + macros: + - memset + - memcpy + - strncpy + - vsnprintf + - snprintf + - strlen diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley.x b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley.x new file mode 100755 index 00000000..7be4645d --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley.x @@ -0,0 +1,14 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.xmacro(ALL).define> */ +/* */ + +/* <--auto.start.xenum(ALL).define> */ +/* */ + + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_config.h b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_config.h new file mode 100755 index 00000000..6a506e23 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_config.h @@ -0,0 +1,137 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_netberg_aurora_420_rangeley Configuration Header + * + * @addtogroup x86_64_netberg_aurora_420_rangeley-config + * @{ + * + *****************************************************************************/ +#ifndef __X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_H__ +#define __X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_H__ + +#ifdef GLOBAL_INCLUDE_CUSTOM_CONFIG +#include +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_INCLUDE_CUSTOM_CONFIG +#include +#endif + +/* */ +#include +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING + * + * Include or exclude logging. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING 1 +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT + * + * Default enabled log options. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT AIM_LOG_OPTIONS_DEFAULT +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT + * + * Default enabled log bits. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT AIM_LOG_BITS_DEFAULT +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT + * + * Default enabled custom log bits. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT 0 +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB + * + * Default all porting macros to use the C standard libraries. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB 1 +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + * + * Include standard library headers for stdlib porting macros. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI + * + * Include generic uCli support. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI 0 +#endif + +/** + * X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD + * + * RPM Threshold at which the fan is considered to have failed. */ + + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD +#define X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD 3000 +#endif + + + +/** + * All compile time options can be queried or displayed + */ + +/** Configuration settings structure. */ +typedef struct x86_64_netberg_aurora_420_rangeley_config_settings_s { + /** name */ + const char* name; + /** value */ + const char* value; +} x86_64_netberg_aurora_420_rangeley_config_settings_t; + +/** Configuration settings table. */ +/** x86_64_netberg_aurora_420_rangeley_config_settings table. */ +extern x86_64_netberg_aurora_420_rangeley_config_settings_t x86_64_netberg_aurora_420_rangeley_config_settings[]; + +/** + * @brief Lookup a configuration setting. + * @param setting The name of the configuration option to lookup. + */ +const char* x86_64_netberg_aurora_420_rangeley_config_lookup(const char* setting); + +/** + * @brief Show the compile-time configuration. + * @param pvs The output stream. + */ +int x86_64_netberg_aurora_420_rangeley_config_show(struct aim_pvs_s* pvs); + +/* */ + +#include "x86_64_netberg_aurora_420_rangeley_porting.h" + +#endif /* __X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_H__ */ +/* @} */ diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_dox.h b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_dox.h new file mode 100755 index 00000000..d37fea93 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_dox.h @@ -0,0 +1,26 @@ +/**************************************************************************//** + * + * x86_64_netberg_aurora_420_rangeley Doxygen Header + * + *****************************************************************************/ +#ifndef __X86_64_NETBERG_AURORA_420_RANGELEY_DOX_H__ +#define __X86_64_NETBERG_AURORA_420_RANGELEY_DOX_H__ + +/** + * @defgroup x86_64_netberg_aurora_420_rangeley x86_64_netberg_aurora_420_rangeley - x86_64_netberg_aurora_420_rangeley Description + * + +The documentation overview for this module should go here. + + * + * @{ + * + * @defgroup x86_64_netberg_aurora_420_rangeley-x86_64_netberg_aurora_420_rangeley Public Interface + * @defgroup x86_64_netberg_aurora_420_rangeley-config Compile Time Configuration + * @defgroup x86_64_netberg_aurora_420_rangeley-porting Porting Macros + * + * @} + * + */ + +#endif /* __X86_64_NETBERG_AURORA_420_RANGELEY_DOX_H__ */ diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_porting.h b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_porting.h new file mode 100755 index 00000000..79f2983a --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/inc/x86_64_netberg_aurora_420_rangeley/x86_64_netberg_aurora_420_rangeley_porting.h @@ -0,0 +1,87 @@ +/**************************************************************************//** + * + * @file + * @brief x86_64_netberg_aurora_420_rangeley Porting Macros. + * + * @addtogroup x86_64_netberg_aurora_420_rangeley-porting + * @{ + * + *****************************************************************************/ +#ifndef __X86_64_NETBERG_AURORA_420_RANGELEY_PORTING_H__ +#define __X86_64_NETBERG_AURORA_420_RANGELEY_PORTING_H__ + + +/* */ +#if X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS == 1 +#include +#include +#include +#include +#include +#endif + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_MEMSET + #if defined(GLOBAL_MEMSET) + #define X86_64_NETBERG_AURORA_420_RANGELEY_MEMSET GLOBAL_MEMSET + #elif X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB == 1 + #define X86_64_NETBERG_AURORA_420_RANGELEY_MEMSET memset + #else + #error The macro X86_64_NETBERG_AURORA_420_RANGELEY_MEMSET is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_MEMCPY + #if defined(GLOBAL_MEMCPY) + #define X86_64_NETBERG_AURORA_420_RANGELEY_MEMCPY GLOBAL_MEMCPY + #elif X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB == 1 + #define X86_64_NETBERG_AURORA_420_RANGELEY_MEMCPY memcpy + #else + #error The macro X86_64_NETBERG_AURORA_420_RANGELEY_MEMCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_STRNCPY + #if defined(GLOBAL_STRNCPY) + #define X86_64_NETBERG_AURORA_420_RANGELEY_STRNCPY GLOBAL_STRNCPY + #elif X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB == 1 + #define X86_64_NETBERG_AURORA_420_RANGELEY_STRNCPY strncpy + #else + #error The macro X86_64_NETBERG_AURORA_420_RANGELEY_STRNCPY is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_VSNPRINTF + #if defined(GLOBAL_VSNPRINTF) + #define X86_64_NETBERG_AURORA_420_RANGELEY_VSNPRINTF GLOBAL_VSNPRINTF + #elif X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB == 1 + #define X86_64_NETBERG_AURORA_420_RANGELEY_VSNPRINTF vsnprintf + #else + #error The macro X86_64_NETBERG_AURORA_420_RANGELEY_VSNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_SNPRINTF + #if defined(GLOBAL_SNPRINTF) + #define X86_64_NETBERG_AURORA_420_RANGELEY_SNPRINTF GLOBAL_SNPRINTF + #elif X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB == 1 + #define X86_64_NETBERG_AURORA_420_RANGELEY_SNPRINTF snprintf + #else + #error The macro X86_64_NETBERG_AURORA_420_RANGELEY_SNPRINTF is required but cannot be defined. + #endif +#endif + +#ifndef X86_64_NETBERG_AURORA_420_RANGELEY_STRLEN + #if defined(GLOBAL_STRLEN) + #define X86_64_NETBERG_AURORA_420_RANGELEY_STRLEN GLOBAL_STRLEN + #elif X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB == 1 + #define X86_64_NETBERG_AURORA_420_RANGELEY_STRLEN strlen + #else + #error The macro X86_64_NETBERG_AURORA_420_RANGELEY_STRLEN is required but cannot be defined. + #endif +#endif + +/* */ + + +#endif /* __X86_64_NETBERG_AURORA_420_RANGELEY_PORTING_H__ */ +/* @} */ diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/make.mk b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/make.mk new file mode 100644 index 00000000..dea3e533 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/make.mk @@ -0,0 +1,10 @@ +############################################################################### +# +# +# +############################################################################### +THIS_DIR := $(dir $(lastword $(MAKEFILE_LIST))) +x86_64_netberg_aurora_420_rangeley_INCLUDES := -I $(THIS_DIR)inc +x86_64_netberg_aurora_420_rangeley_INTERNAL_INCLUDES := -I $(THIS_DIR)src +x86_64_netberg_aurora_420_rangeley_DEPENDMODULE_ENTRIES := init:x86_64_netberg_aurora_420_rangeley ucli:x86_64_netberg_aurora_420_rangeley + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/Makefile new file mode 100755 index 00000000..ef9d70ed --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/Makefile @@ -0,0 +1,9 @@ +############################################################################### +# +# Local source generation targets. +# +############################################################################### + +ucli: + @../../../../tools/uclihandlers.py x86_64_netberg_aurora_420_rangeley_ucli.c + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/fani.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/fani.c new file mode 100755 index 00000000..4cc75804 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/fani.c @@ -0,0 +1,234 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include + +#include "x86_64_netberg_aurora_420_rangeley_int.h" +#include "x86_64_netberg_aurora_420_rangeley_log.h" + +#include + + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_FAN(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static int +sys_fan_info_get__(onlp_fan_info_t* info, int id) +{ + int value = 0; + int rv; + + rv = onlp_file_read_int(&value, SYS_HWMON2_PREFIX "/fan%d_abs", ((id/2)+1)); + if (rv != ONLP_STATUS_OK) + return rv; + + if (value == 0) + { + info->status = ONLP_FAN_STATUS_FAILED; + } + else + { + info->status = ONLP_FAN_STATUS_PRESENT; + + rv = onlp_file_read_int(&value, SYS_HWMON2_PREFIX "/fan%d_dir", ((id/2)+1)); + if (rv != ONLP_STATUS_OK) + return rv; + + if (value == 1) + { + info->status |= ONLP_FAN_STATUS_B2F; + info->caps |= ONLP_FAN_CAPS_B2F; + } + else + { + info->status |= ONLP_FAN_STATUS_F2B; + info->caps |= ONLP_FAN_CAPS_F2B; + } + + rv = onlp_file_read_int(&(info->rpm), SYS_HWMON1_PREFIX "/fan%d_rpm", (id+1)); + if (rv == ONLP_STATUS_E_INTERNAL) + return rv; + + if (rv == ONLP_STATUS_E_MISSING) + { + info->status &= ~1; + return 0; + } + + if (info->rpm <= X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD) + info->status |= ONLP_FAN_STATUS_FAILED; + + + rv = onlp_file_read_int(&(info->percentage), SYS_HWMON1_PREFIX "/fan%d_duty", (id+1)); + if (rv == ONLP_STATUS_E_INTERNAL) + return rv; + + if (rv == ONLP_STATUS_E_MISSING) + { + info->status &= ~1; + return 0; + } + } + return 0; +} + +static int +psu_fan_info_get__(onlp_fan_info_t* info, int id) +{ + return onlp_file_read_int(&(info->rpm), SYS_HWMON2_PREFIX "/psu%d_fan_speed", id); +} + +/* Onboard Fans */ +static onlp_fan_info_t fans__[] = { + { }, /* Not used */ + { { FAN_OID_FAN1, "Fan1_rotor1", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN2, "Fan1_rotor2", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN3, "Fan2_rotor1", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN4, "Fan2_rotor2", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN5, "Fan3_rotor1", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN6, "Fan3_rotor2", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN7, "Fan4_rotor1", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN8, "Fan4_rotor2", 0}, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN9, "PSU-1 Fan", 0 }, ONLP_FAN_STATUS_PRESENT }, + { { FAN_OID_FAN10, "PSU-2 Fan", 0 }, ONLP_FAN_STATUS_PRESENT }, +}; + +/* + * 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 fid; + + VALIDATE(id); + + memset(info, 0, sizeof(onlp_fan_info_t)); + fid = ONLP_OID_ID_GET(id); + *info = fans__[fid]; + + info->caps |= ONLP_FAN_CAPS_GET_RPM; + + switch(fid) + { + case FAN_ID_FAN1: + case FAN_ID_FAN2: + case FAN_ID_FAN3: + case FAN_ID_FAN4: + case FAN_ID_FAN5: + case FAN_ID_FAN6: + case FAN_ID_FAN7: + case FAN_ID_FAN8: + return sys_fan_info_get__(info, (fid - 1)); + break; + + case FAN_ID_FAN9: + case FAN_ID_FAN10: + return psu_fan_info_get__(info, (fid - FAN_ID_FAN9 + 1)); + break; + + default: + return ONLP_STATUS_E_INVALID; + break; + } + + return ONLP_STATUS_E_INVALID; +} + +/* + * This function sets the speed of the given fan in RPM. + * + * This function will only be called if the fan supprots the RPM_SET + * capability. + * + * It is optional if you have no fans at all with this feature. + */ +int +onlp_fani_rpm_set(onlp_oid_t id, int rpm) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + + +/* + * 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) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * This function sets the fan speed of the given OID as per + * the predefined ONLP fan speed modes: off, slow, normal, fast, max. + * + * Interpretation of these modes is up to the platform. + * + */ +int +onlp_fani_mode_set(onlp_oid_t id, onlp_fan_mode_t mode) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * This function sets the fan direction of the given OID. + * + * This function is only relevant if the fan OID supports both direction + * capabilities. + * + * This function is optional unless the functionality is available. + */ +int +onlp_fani_dir_set(onlp_oid_t id, onlp_fan_dir_t dir) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * Generic fan ioctl. Optional. + */ +int +onlp_fani_ioctl(onlp_oid_t id, va_list vargs) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/ledi.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/ledi.c new file mode 100755 index 00000000..2b482315 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/ledi.c @@ -0,0 +1,221 @@ +/************************************************************ + * + * + * 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 "x86_64_netberg_aurora_420_rangeley_int.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_LED(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +/* LED related data + */ +enum led_light_mode { /*must be the same with the definition @ kernel driver */ + LED_MODE_OFF = 0, + LED_MODE_AMBER, + LED_MODE_GREEN, +}; + +int led_light_map_mode[][2] = +{ + {LED_MODE_OFF, ONLP_LED_MODE_OFF}, + {LED_MODE_AMBER, ONLP_LED_MODE_ORANGE}, + {LED_MODE_GREEN, ONLP_LED_MODE_GREEN}, +}; + +/* + * Get the information for the given LED OID. + */ +static onlp_led_info_t linfo[] = +{ + { }, /* Not used */ + { + { LED_OID_LED1, "Chassis LED 1 (STAT LED)", 0 }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_ORANGE | ONLP_LED_CAPS_GREEN, + ONLP_LED_MODE_OFF, + }, + { + { LED_OID_LED2, "Chassis LED 2 (FAN LED)", 0 }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_ORANGE | ONLP_LED_CAPS_GREEN, + ONLP_LED_MODE_OFF, + }, + { + { LED_OID_LED3, "Chassis LED 3 (PSU1 LED)", 0 }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_ORANGE | ONLP_LED_CAPS_GREEN, + ONLP_LED_MODE_OFF, + }, + { + { LED_OID_LED4, "Chassis LED 4 (PSU2 LED)", 0 }, + ONLP_LED_STATUS_PRESENT, + ONLP_LED_CAPS_ON_OFF | ONLP_LED_CAPS_ORANGE | ONLP_LED_CAPS_GREEN, + ONLP_LED_MODE_OFF, + }, +}; + +static int conver_led_light_mode_to_driver(int led_ligth_mode) +{ + int i, nsize = sizeof(led_light_map_mode)/sizeof(led_light_map_mode[0]); + for(i=0; i + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include +#include "x86_64_netberg_aurora_420_rangeley_int.h" +#include "x86_64_netberg_aurora_420_rangeley_log.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_PSU(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static onlp_psu_info_t psus__[] = { + { }, /* Not used */ + { + { + PSU_OID_PSU1, + "PSU-1", + 0, + { + FAN_OID_FAN9, + }, + } + }, + { + { + PSU_OID_PSU2, + "PSU-2", + 0, + { + FAN_OID_FAN10, + }, + } + }, +}; + +/* + * This function will be called prior to any other onlp_psui functions. + */ +int +onlp_psui_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_psui_info_get(onlp_oid_t id, onlp_psu_info_t* info) +{ + int rv; + int pid; + uint8_t data[256]; + int value = -1; + int len; + double dvalue; + int i; + + VALIDATE(id); + + memset(info, 0, sizeof(onlp_psu_info_t)); + pid = ONLP_OID_ID_GET(id); + *info = psus__[pid]; + + rv = onlp_file_read_int(&value, SYS_HWMON1_PREFIX "/psu%d_abs", pid); + if (rv != ONLP_STATUS_OK) + return rv; + if (value == 0) + { + info->status = ONLP_PSU_STATUS_UNPLUGGED; + return ONLP_STATUS_OK; + } + + /* PSU is present. */ + info->status = ONLP_PSU_STATUS_PRESENT; + + memset(data, 0, sizeof(data)); + rv = onlp_file_read(data, sizeof(data), &len, SYS_HWMON2_PREFIX "/psu%d_eeprom", pid); + if (rv == ONLP_STATUS_OK) + { + i = 11; + + /* Manufacturer Name */ + len = (data[i]&0x0f); + i++; + i += len; + + /* Product Name */ + len = (data[i]&0x0f); + i++; + memcpy(info->model, (char *) &(data[i]), len); + i += len; + + /* Product part,model number */ + len = (data[i]&0x0f); + i++; + i += len; + + /* Product Version */ + len = (data[i]&0x0f); + i++; + i += len; + + /* Product Serial Number */ + len = (data[i]&0x0f); + i++; + memcpy(info->serial, (char *) &(data[i]), len); + } + else + { + strcpy(info->model, "Missing"); + strcpy(info->serial, "Missing"); + } + + info->caps |= ONLP_PSU_CAPS_AC; + +#if 0 + /* PSU is powered. */ + rv = onlp_file_read_int(&value, SYS_HWMON1_PREFIX "/psu%d_pg", pid); + if (rv != ONLP_STATUS_OK) + return rv; + if (value == 0) + { + info->status |= ONLP_PSU_STATUS_FAILED; + return ONLP_STATUS_OK; + } +#endif + + memset(data, 0, sizeof(data)); + rv = onlp_file_read(data, sizeof(data), &len, SYS_HWMON2_PREFIX "/psu%d_iout", pid); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)data); + if (dvalue > 0.0) + { + info->caps |= ONLP_PSU_CAPS_IOUT; + info->miout = (int)(dvalue * 1000); + } + } + + memset(data, 0, sizeof(data)); + rv = onlp_file_read(data, sizeof(data), &len, SYS_HWMON2_PREFIX "/psu%d_vout", pid); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)data); + if (dvalue > 0.0) + { + info->caps |= ONLP_PSU_CAPS_VOUT; + info->mvout = (int)(dvalue * 1000); + } + } + + memset(data, 0, sizeof(data)); + rv = onlp_file_read(data, sizeof(data), &len, SYS_HWMON2_PREFIX "/psu%d_pin", pid); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)data); + if (dvalue > 0.0) + { + info->caps |= ONLP_PSU_CAPS_PIN; + info->mpin = (int)(dvalue * 1000); + } + } + + memset(data, 0, sizeof(data)); + rv = onlp_file_read(data, sizeof(data), &len, SYS_HWMON2_PREFIX "/psu%d_pout", pid); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)data); + if (dvalue > 0.0) + { + info->caps |= ONLP_PSU_CAPS_POUT; + info->mpout = (int)(dvalue * 1000); + } + } + + return ONLP_STATUS_OK; +} + +/* + * This is an optional generic ioctl() interface. + * Its purpose is to allow future expansion and + * custom functionality that is not otherwise exposed + * in the standard interface. + * + * The semantics of this function are platform specific. + * This function is completely optional. + */ +int +onlp_psui_ioctl(onlp_oid_t pid, va_list vargs) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sfpi.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sfpi.c new file mode 100755 index 00000000..5aaf3760 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sfpi.c @@ -0,0 +1,451 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * + * 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. + * + * + ************************************************************ + * + * SFPI Interface for the Aurora 420 Platform + * + ***********************************************************/ +#include +#include +#include +#include +#include +#include "x86_64_netberg_aurora_420_rangeley_int.h" +#include "x86_64_netberg_aurora_420_rangeley_log.h" + +#include +#include + +/* Model ID Definition */ +typedef enum +{ + HURACAN_WITH_BMC = 0x0, + HURACAN_WITHOUT_BMC, + CABRERAIII_WITH_BMC, + CABRERAIII_WITHOUT_BMC, + SESTO_WITH_BMC, + SESTO_WITHOUT_BMC, + NCIIX_WITH_BMC, + NCIIX_WITHOUT_BMC, + ASTERION_WITH_BMC, + ASTERION_WITHOUT_BMC, + HURACAN_A_WITH_BMC, + HURACAN_A_WITHOUT_BMC, + + MODEL_ID_LAST +} modelId_t; + +static int +onlp_board_model_id_get(void) +{ + static int board_model_id = MODEL_ID_LAST; + + if (board_model_id == MODEL_ID_LAST) + { + if (onlp_file_read_int(&board_model_id, SYS_HWMON1_PREFIX "/board_model_id") != ONLP_STATUS_OK) + return 0; + } + + return board_model_id; +} + +/* + * This function will be called prior to all other onlp_sfpi_* functions. + */ +int +onlp_sfpi_init(void) +{ + return ONLP_STATUS_OK; +} + +/* + * This function should populate the give bitmap with + * all valid, SFP-capable port numbers. + * + * Only port numbers in this bitmap will be queried by the the + * ONLP framework. + * + * No SFPI functions will be called with ports that are + * not in this bitmap. You can ignore all error checking + * on the incoming ports defined in this interface. + */ +int +onlp_sfpi_bitmap_get(onlp_sfp_bitmap_t* bmap) +{ + int p; + int total_port = 0; + int board_model_id = onlp_board_model_id_get(); + + switch (board_model_id) + { + case HURACAN_WITH_BMC: + case HURACAN_WITHOUT_BMC: + case HURACAN_A_WITH_BMC: + case HURACAN_A_WITHOUT_BMC: + total_port = 32; + break; + + case SESTO_WITH_BMC: + case SESTO_WITHOUT_BMC: + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + total_port = 54; + break; + + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + total_port = 64; + break; + + default: + break; + } + + AIM_BITMAP_CLR_ALL(bmap); + for(p = 0; p < total_port; p++) + AIM_BITMAP_SET(bmap, p); + + return ONLP_STATUS_OK; +} + +/* + * This function should return whether an SFP is inserted on the given + * port. + * + * Returns 1 if the SFP is present. + * Returns 0 if the SFP is not present. + * Returns ONLP_E_* if there was an error determining the status. + */ +int +onlp_sfpi_is_present(int port) +{ + int value = 0; + + onlp_file_read_int(&value, SYS_HWMON2_PREFIX "/port_%d_abs", (port+1)); + return value; +} + +int +onlp_sfpi_port_map(int port, int* rport) +{ + int board_model_id = onlp_board_model_id_get(); + + switch (board_model_id) + { + case HURACAN_WITH_BMC: + case HURACAN_WITHOUT_BMC: + case HURACAN_A_WITH_BMC: + case HURACAN_A_WITHOUT_BMC: + /* odd <=> even */ + if (port & 0x1) + *rport = (port - 1); + else + *rport = (port + 1); + break; + + default: + *rport = port; break; + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +int +onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* bmap) +{ + int p; + int total_port = 0; + int board_model_id = onlp_board_model_id_get(); + + switch (board_model_id) + { + case HURACAN_WITH_BMC: + case HURACAN_WITHOUT_BMC: + case HURACAN_A_WITH_BMC: + case HURACAN_A_WITHOUT_BMC: + total_port = 32; + break; + + case SESTO_WITH_BMC: + case SESTO_WITHOUT_BMC: + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + total_port = 54; + break; + + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + total_port = 64; + break; + + default: + break; + } + + AIM_BITMAP_CLR_ALL(bmap); + for(p = 0; p < total_port; p++) + AIM_BITMAP_SET(bmap, p); + + return ONLP_STATUS_OK; +} + +/* + * This function reads the SFPs idrom and returns in + * in the data buffer provided. + */ +int +onlp_sfpi_eeprom_read(int port, uint8_t data[256]) +{ + int rv = ONLP_STATUS_OK; + char fname[128]; + + memset(data, 0, 256); + memset(fname, 0, sizeof(fname)); + sprintf(fname, SYS_HWMON2_PREFIX "/port_%d_data_a0", (port+1)); + rv = onlplib_sfp_eeprom_read_file(fname, data); + if (rv != ONLP_STATUS_OK) + AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port); + + return rv; +} + +int +onlp_sfpi_dom_read(int port, uint8_t data[256]) +{ + int rv = ONLP_STATUS_OK; + char fname[128]; + + memset(data, 0, 256); + memset(fname, 0, sizeof(fname)); + sprintf(fname, SYS_HWMON2_PREFIX "/port_%d_data_a2", (port+1)); + rv = onlplib_sfp_eeprom_read_file(fname, data); + if (rv != ONLP_STATUS_OK) + AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port); + + return rv; +} + +/* + * Manually enable or disable the given SFP. + * + */ +int +onlp_sfpi_enable_set(int port, int enable) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * Returns whether the SFP is currently enabled or disabled. + */ +int +onlp_sfpi_enable_get(int port, int* enable) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * If the platform requires any setup or equalizer modifications + * based on the actual SFP that was inserted then that custom + * setup should be performed here. + * + * After a new SFP is detected by the ONLP framework this + * function will be called to perform the (optional) setup. + */ +int +onlp_sfpi_post_insert(int port, sff_info_t* sff_info) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * Return the current status of the SFP. + * See onlp_sfp_status_t; + */ +int +onlp_sfpi_status_get(int port, uint32_t* status) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +int onlp_sfpi_control_supported(int port, onlp_sfp_control_t control, int* supported) +{ + if (supported == NULL) + return ONLP_STATUS_E_PARAM; + + *supported = 0; + switch (control) + { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_RX_LOS: + case ONLP_SFP_CONTROL_TX_FAULT: + { + int board_model_id = onlp_board_model_id_get(); + + switch (board_model_id) + { + case HURACAN_WITH_BMC: + case HURACAN_WITHOUT_BMC: + case HURACAN_A_WITH_BMC: + case HURACAN_A_WITHOUT_BMC: + case SESTO_WITH_BMC: + case SESTO_WITHOUT_BMC: + case NCIIX_WITH_BMC: + case NCIIX_WITHOUT_BMC: + case ASTERION_WITH_BMC: + case ASTERION_WITHOUT_BMC: + *supported = 1; + break; + + default: + break; + } + } + break; + + default: + break; + } + + return ONLP_STATUS_OK; +} + +int +onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) +{ + int rv = ONLP_STATUS_OK; + int supported = 0; + + if ((onlp_sfpi_control_supported(port, control, &supported) == ONLP_STATUS_OK) && (supported == 0)) + return ONLP_STATUS_E_UNSUPPORTED; + + switch (control) + { + case ONLP_SFP_CONTROL_TX_DISABLE: + rv = onlp_file_write_int(value, SYS_HWMON2_PREFIX "/port_%d_tx_disable", (port+1)); + break; + + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + break; + } + return rv; +} + +int +onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) +{ + int rv = ONLP_STATUS_OK; + int supported = 0; + + if (value == NULL) + return ONLP_STATUS_E_PARAM; + + if ((onlp_sfpi_control_supported(port, control, &supported) == ONLP_STATUS_OK) && (supported == 0)) + return ONLP_STATUS_E_UNSUPPORTED; + + *value = 0; + switch (control) + { + case ONLP_SFP_CONTROL_RX_LOS: + rv = onlp_file_read_int(value, SYS_HWMON2_PREFIX "/port_%d_rxlos", (port+1)); + break; + + case ONLP_SFP_CONTROL_TX_DISABLE: + rv = onlp_file_read_int(value, SYS_HWMON2_PREFIX "/port_%d_tx_disable", (port+1)); + break; + + case ONLP_SFP_CONTROL_TX_FAULT: + rv = onlp_file_read_int(value, SYS_HWMON2_PREFIX "/port_%d_tx_fault", (port+1)); + break; + + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + break; + } + return rv; +} + +int +onlp_sfpi_dev_readw(int port, uint8_t devaddr, uint8_t addr) +{ + int value = 0; + char fname[128]; + char data[512]; + + memset(data, 0, 512); + memset(fname, 0, sizeof(fname)); + sprintf(fname, SYS_HWMON2_PREFIX "/port_%d_sfp_copper", (port+1)); + + int fd = open(fname, O_RDONLY); + if (fd < 0) { + AIM_LOG_INFO("Unable to read devaddr(0xAC) from port(%d)\r\n", port); + return value; + } + + int nrd = read(fd, data, 512); + close(fd); + + if (nrd != 512) { + AIM_LOG_INTERNAL("Failed to read EEPROM file '%s'", fname); + return value; + } + + value = (((data[addr*2 + 1] & 0xff) << 8) | (data[addr*2] & 0xff)) & 0xffff; + + return value; +} + +int +onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) +{ + int rv = ONLP_STATUS_OK; + int data = 0; + + data = ((addr << 16) | (value & 0xffff)) & 0x00ffffff; + rv = onlp_file_write_int(data, SYS_HWMON2_PREFIX "/port_%d_sfp_copper", (port+1)); + + return rv; +} + +/* + * This is a generic ioctl interface. + */ +int +onlp_sfpi_ioctl(int port, va_list vargs) +{ + return ONLP_STATUS_E_UNSUPPORTED; +} + +/* + * De-initialize the SFPI subsystem. + */ +int +onlp_sfpi_denit(void) +{ + return ONLP_STATUS_OK; +} + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sysi.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sysi.c new file mode 100755 index 00000000..7e044c3b --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/sysi.c @@ -0,0 +1,98 @@ +/************************************************************ + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "x86_64_netberg_aurora_420_rangeley_int.h" +#include "x86_64_netberg_aurora_420_rangeley_log.h" + +/* + * This is the first function called by the ONLP framework. + * + * It should return the name of your platform driver. + * + * If the name of your platform driver is the same as the + * current platform then this driver will be used. + * + * If the name of the driver is different from the current + * platform, or the driver is capable of supporting multiple + * platform variants, see onlp_sysi_platform_set() below. + */ +const char* +onlp_sysi_platform_get(void) +{ + return "x86-64-netberg-aurora-420-rangeley-r0"; +} + +/* + * This is the first function the ONLP framework will call + * after it has validated the the platform is supported using the mechanisms + * described above. + * + * If this function does not return ONL_STATUS_OK + * then platform initialization is aborted. + */ +int +onlp_sysi_init(void) +{ + return ONLP_STATUS_OK; +} + +int +onlp_sysi_onie_info_get(onlp_onie_info_t* onie) +{ + int rv; + uint8_t data[256]; + int len; + + memset(data, 0, sizeof(data)); + rv = onlp_file_read(data, sizeof(data), &len, SYS_HWMON2_PREFIX "/eeprom"); + if (rv == ONLP_STATUS_OK) + { + rv = onlp_onie_decode(onie, (uint8_t*)data, sizeof(data)); + if(rv >= 0) + { + onie->platform_name = aim_strdup("x86-64-netberg-aurora-420-rangeley-r0"); + } + } + return rv; +} + +int +onlp_sysi_oids_get(onlp_oid_t* table, int max) +{ + onlp_oid_t* e = table; + memset(table, 0, max*sizeof(onlp_oid_t)); + int i; + int n_thermal=7, n_fan=10, n_led=4; + + /* 2 PSUs */ + *e++ = ONLP_PSU_ID_CREATE(1); + *e++ = ONLP_PSU_ID_CREATE(2); + + /* LEDs Item */ + for (i=1; i<=n_led; i++) + { + *e++ = ONLP_LED_ID_CREATE(i); + } + + /* THERMALs Item */ + for (i=1; i<=n_thermal; i++) + { + *e++ = ONLP_THERMAL_ID_CREATE(i); + } + + /* Fans Item */ + for (i=1; i<=n_fan; i++) + { + *e++ = ONLP_FAN_ID_CREATE(i); + } + + return 0; +} + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/thermali.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/thermali.c new file mode 100755 index 00000000..e3241013 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/thermali.c @@ -0,0 +1,173 @@ +/************************************************************ + * + * + * Copyright 2014 Big Switch Networks, Inc. + * + * Licensed under the Eclipse Public License, Version 1.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.eclipse.org/legal/epl-v10.html + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + * + * + ************************************************************ + * + * + * + ***********************************************************/ +#include +#include +#include "x86_64_netberg_aurora_420_rangeley_int.h" +#include "x86_64_netberg_aurora_420_rangeley_log.h" + +#define VALIDATE(_id) \ + do { \ + if(!ONLP_OID_IS_THERMAL(_id)) { \ + return ONLP_STATUS_E_INVALID; \ + } \ + } while(0) + +static int +sys_thermal_info_get__(onlp_thermal_info_t* info, int id) +{ + int rv; + + if (id == THERMAL_ID_THERMAL3) + { + rv = onlp_file_read_int(&info->mcelsius, SYS_HWMON1_PREFIX "/mac_temp"); + info->mcelsius *= 1000; + } + else + { + uint8_t buffer[64]; + double dvalue; + int len; + + memset(buffer, 0, sizeof(buffer)); + rv = onlp_file_read(buffer, sizeof(buffer), &len, SYS_HWMON1_PREFIX "/remote_temp%d", id); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)buffer); + info->mcelsius = (int)(dvalue * 1000); + } + } + + if(rv == ONLP_STATUS_E_INTERNAL) + return rv; + + if(rv == ONLP_STATUS_E_MISSING) + { + info->status &= ~(ONLP_THERMAL_STATUS_PRESENT); + return ONLP_STATUS_OK; + } + + return ONLP_STATUS_OK; +} + +static int +psu1_thermal_info_get__(onlp_thermal_info_t* info, int id) +{ + int rv; + uint8_t buffer[64]; + double dvalue; + int len; + + memset(buffer, 0, sizeof(buffer)); + rv = onlp_file_read(buffer, sizeof(buffer), &len, SYS_HWMON2_PREFIX "/psu1_temp_%d", id); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)buffer); + info->mcelsius = (int)(dvalue * 1000); + } + return rv; +} + +static int +psu2_thermal_info_get__(onlp_thermal_info_t* info, int id) +{ + int rv; + uint8_t buffer[64]; + double dvalue; + int len; + + memset(buffer, 0, sizeof(buffer)); + rv = onlp_file_read(buffer, sizeof(buffer), &len, SYS_HWMON2_PREFIX "/psu2_temp_%d", id); + if (rv == ONLP_STATUS_OK) + { + dvalue = atof((const char *)buffer); + info->mcelsius = (int)(dvalue * 1000); + } + return rv; +} + +static onlp_thermal_info_t temps__[] = +{ + { }, /* Not used */ + { { THERMAL_OID_THERMAL1, "Chassis Thermal 1 (Front of MAC)", 0}, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, + { { THERMAL_OID_THERMAL2, "Chassis Thermal 2 (Rear of MAC)", 0}, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, + { { THERMAL_OID_THERMAL3, "Chassis Thermal 3 (MAC)", 0}, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, + + { { THERMAL_OID_THERMAL4, "PSU-1 Thermal 1", PSU_OID_PSU1 }, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, + { { THERMAL_OID_THERMAL5, "PSU-1 Thermal 2", PSU_OID_PSU1 }, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, + + { { THERMAL_OID_THERMAL6, "PSU-2 Thermal 1", PSU_OID_PSU2 }, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, + { { THERMAL_OID_THERMAL7, "PSU-2 Thermal 2", PSU_OID_PSU2 }, ONLP_THERMAL_STATUS_PRESENT, ONLP_THERMAL_CAPS_GET_TEMPERATURE, 0}, +}; + + +/* + * 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; + + VALIDATE(id); + + memset(info, 0, sizeof(onlp_thermal_info_t)); + tid = ONLP_OID_ID_GET(id); + *info = temps__[tid]; + + switch(tid) + { + case THERMAL_ID_THERMAL1: + case THERMAL_ID_THERMAL2: + case THERMAL_ID_THERMAL3: + return sys_thermal_info_get__(info, tid); + + case THERMAL_ID_THERMAL4: + case THERMAL_ID_THERMAL5: + return psu1_thermal_info_get__(info, (tid - THERMAL_ID_THERMAL4 + 1)); + + case THERMAL_ID_THERMAL6: + case THERMAL_ID_THERMAL7: + return psu2_thermal_info_get__(info, (tid - THERMAL_ID_THERMAL6 + 1)); + } + + return ONLP_STATUS_E_INVALID; +} + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_config.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_config.c new file mode 100755 index 00000000..94ef2e10 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_config.c @@ -0,0 +1,80 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* */ +#define __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(_x) #_x +#define __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(_x) __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(_x) +x86_64_netberg_aurora_420_rangeley_config_settings_t x86_64_netberg_aurora_420_rangeley_config_settings[] = +{ +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_LOGGING(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_STDLIB(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_PORTING_INCLUDE_STDLIB_HEADERS(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif +#ifdef X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD + { __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD), __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE(X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD) }, +#else +{ X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_SYSFAN_RPM_FAILURE_THRESHOLD(__x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME), "__undefined__" }, +#endif + { NULL, NULL } +}; +#undef __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_VALUE +#undef __x86_64_netberg_aurora_420_rangeley_config_STRINGIFY_NAME + +const char* +x86_64_netberg_aurora_420_rangeley_config_lookup(const char* setting) +{ + int i; + for(i = 0; x86_64_netberg_aurora_420_rangeley_config_settings[i].name; i++) { + if(!strcmp(x86_64_netberg_aurora_420_rangeley_config_settings[i].name, setting)) { + return x86_64_netberg_aurora_420_rangeley_config_settings[i].value; + } + } + return NULL; +} + +int +x86_64_netberg_aurora_420_rangeley_config_show(struct aim_pvs_s* pvs) +{ + int i; + for(i = 0; x86_64_netberg_aurora_420_rangeley_config_settings[i].name; i++) { + aim_printf(pvs, "%s = %s\n", x86_64_netberg_aurora_420_rangeley_config_settings[i].name, x86_64_netberg_aurora_420_rangeley_config_settings[i].value); + } + return i; +} + +/* */ diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_enums.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_enums.c new file mode 100755 index 00000000..1df7f4cd --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_enums.c @@ -0,0 +1,10 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +/* <--auto.start.enum(ALL).source> */ +/* */ + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_int.h b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_int.h new file mode 100755 index 00000000..3067638c --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_int.h @@ -0,0 +1,271 @@ +/**************************************************************************//** + * + * x86_64_netberg_aurora_420_rangeley Internal Header + * + *****************************************************************************/ +#ifndef __X86_64_NETBERG_AURORA_420_RANGELEY_INT_H__ +#define __X86_64_NETBERG_AURORA_420_RANGELEY_INT_H__ + +#include +#include + +/* */ +/** fan_id */ +typedef enum fan_id_e { + FAN_ID_FAN1 = 1, + FAN_ID_FAN2 = 2, + FAN_ID_FAN3 = 3, + FAN_ID_FAN4 = 4, + FAN_ID_FAN5 = 5, + FAN_ID_FAN6 = 6, + FAN_ID_FAN7 = 7, + FAN_ID_FAN8 = 8, + FAN_ID_FAN9 = 9, + FAN_ID_FAN10 = 10, +} fan_id_t; + +/** Enum names. */ +const char* fan_id_name(fan_id_t e); + +/** Enum values. */ +int fan_id_value(const char* str, fan_id_t* e, int substr); + +/** Enum descriptions. */ +const char* fan_id_desc(fan_id_t e); + +/** Enum validator. */ +int fan_id_valid(fan_id_t e); + +/** validator */ +#define FAN_ID_VALID(_e) \ + (fan_id_valid((_e))) + +/** fan_id_map table. */ +extern aim_map_si_t fan_id_map[]; +/** fan_id_desc_map table. */ +extern aim_map_si_t fan_id_desc_map[]; + +/** fan_oid */ +typedef enum fan_oid_e { + FAN_OID_FAN1 = ONLP_FAN_ID_CREATE(1), + FAN_OID_FAN2 = ONLP_FAN_ID_CREATE(2), + FAN_OID_FAN3 = ONLP_FAN_ID_CREATE(3), + FAN_OID_FAN4 = ONLP_FAN_ID_CREATE(4), + FAN_OID_FAN5 = ONLP_FAN_ID_CREATE(5), + FAN_OID_FAN6 = ONLP_FAN_ID_CREATE(6), + FAN_OID_FAN7 = ONLP_FAN_ID_CREATE(7), + FAN_OID_FAN8 = ONLP_FAN_ID_CREATE(8), + FAN_OID_FAN9 = ONLP_FAN_ID_CREATE(9), + FAN_OID_FAN10 = ONLP_FAN_ID_CREATE(10), +} fan_oid_t; + +/** Enum names. */ +const char* fan_oid_name(fan_oid_t e); + +/** Enum values. */ +int fan_oid_value(const char* str, fan_oid_t* e, int substr); + +/** Enum descriptions. */ +const char* fan_oid_desc(fan_oid_t e); + +/** Enum validator. */ +int fan_oid_valid(fan_oid_t e); + +/** validator */ +#define FAN_OID_VALID(_e) \ + (fan_oid_valid((_e))) + +/** fan_oid_map table. */ +extern aim_map_si_t fan_oid_map[]; +/** fan_oid_desc_map table. */ +extern aim_map_si_t fan_oid_desc_map[]; + +/** led_id */ +typedef enum led_id_e { + LED_ID_LED1 = 1, + LED_ID_LED2 = 2, + LED_ID_LED3 = 3, + LED_ID_LED4 = 4, +} led_id_t; + +/** Enum names. */ +const char* led_id_name(led_id_t e); + +/** Enum values. */ +int led_id_value(const char* str, led_id_t* e, int substr); + +/** Enum descriptions. */ +const char* led_id_desc(led_id_t e); + +/** Enum validator. */ +int led_id_valid(led_id_t e); + +/** validator */ +#define LED_ID_VALID(_e) \ + (led_id_valid((_e))) + +/** led_id_map table. */ +extern aim_map_si_t led_id_map[]; +/** led_id_desc_map table. */ +extern aim_map_si_t led_id_desc_map[]; + +/** led_oid */ +typedef enum led_oid_e { + LED_OID_LED1 = ONLP_LED_ID_CREATE(1), + LED_OID_LED2 = ONLP_LED_ID_CREATE(2), + LED_OID_LED3 = ONLP_LED_ID_CREATE(3), + LED_OID_LED4 = ONLP_LED_ID_CREATE(4), +} led_oid_t; + +/** Enum names. */ +const char* led_oid_name(led_oid_t e); + +/** Enum values. */ +int led_oid_value(const char* str, led_oid_t* e, int substr); + +/** Enum descriptions. */ +const char* led_oid_desc(led_oid_t e); + +/** Enum validator. */ +int led_oid_valid(led_oid_t e); + +/** validator */ +#define LED_OID_VALID(_e) \ + (led_oid_valid((_e))) + +/** led_oid_map table. */ +extern aim_map_si_t led_oid_map[]; +/** led_oid_desc_map table. */ +extern aim_map_si_t led_oid_desc_map[]; + +/** psu_id */ +typedef enum psu_id_e { + PSU_ID_PSU1 = 1, + PSU_ID_PSU2 = 2, +} psu_id_t; + +/** Enum names. */ +const char* psu_id_name(psu_id_t e); + +/** Enum values. */ +int psu_id_value(const char* str, psu_id_t* e, int substr); + +/** Enum descriptions. */ +const char* psu_id_desc(psu_id_t e); + +/** Enum validator. */ +int psu_id_valid(psu_id_t e); + +/** validator */ +#define PSU_ID_VALID(_e) \ + (psu_id_valid((_e))) + +/** psu_id_map table. */ +extern aim_map_si_t psu_id_map[]; +/** psu_id_desc_map table. */ +extern aim_map_si_t psu_id_desc_map[]; + +/** psu_oid */ +typedef enum psu_oid_e { + PSU_OID_PSU1 = ONLP_PSU_ID_CREATE(1), + PSU_OID_PSU2 = ONLP_PSU_ID_CREATE(2), +} psu_oid_t; + +/** Enum names. */ +const char* psu_oid_name(psu_oid_t e); + +/** Enum values. */ +int psu_oid_value(const char* str, psu_oid_t* e, int substr); + +/** Enum descriptions. */ +const char* psu_oid_desc(psu_oid_t e); + +/** Enum validator. */ +int psu_oid_valid(psu_oid_t e); + +/** validator */ +#define PSU_OID_VALID(_e) \ + (psu_oid_valid((_e))) + +/** psu_oid_map table. */ +extern aim_map_si_t psu_oid_map[]; +/** psu_oid_desc_map table. */ +extern aim_map_si_t psu_oid_desc_map[]; + +/** thermal_id */ +typedef enum thermal_id_e { + THERMAL_ID_THERMAL1 = 1, + THERMAL_ID_THERMAL2 = 2, + THERMAL_ID_THERMAL3 = 3, + THERMAL_ID_THERMAL4 = 4, + THERMAL_ID_THERMAL5 = 5, + THERMAL_ID_THERMAL6 = 6, + THERMAL_ID_THERMAL7 = 7, +} thermal_id_t; + +/** Enum names. */ +const char* thermal_id_name(thermal_id_t e); + +/** Enum values. */ +int thermal_id_value(const char* str, thermal_id_t* e, int substr); + +/** Enum descriptions. */ +const char* thermal_id_desc(thermal_id_t e); + +/** Enum validator. */ +int thermal_id_valid(thermal_id_t e); + +/** validator */ +#define THERMAL_ID_VALID(_e) \ + (thermal_id_valid((_e))) + +/** thermal_id_map table. */ +extern aim_map_si_t thermal_id_map[]; +/** thermal_id_desc_map table. */ +extern aim_map_si_t thermal_id_desc_map[]; + +/** thermal_oid */ +typedef enum thermal_oid_e { + THERMAL_OID_THERMAL1 = ONLP_THERMAL_ID_CREATE(1), + THERMAL_OID_THERMAL2 = ONLP_THERMAL_ID_CREATE(2), + THERMAL_OID_THERMAL3 = ONLP_THERMAL_ID_CREATE(3), + THERMAL_OID_THERMAL4 = ONLP_THERMAL_ID_CREATE(4), + THERMAL_OID_THERMAL5 = ONLP_THERMAL_ID_CREATE(5), + THERMAL_OID_THERMAL6 = ONLP_THERMAL_ID_CREATE(6), + THERMAL_OID_THERMAL7 = ONLP_THERMAL_ID_CREATE(7), +} thermal_oid_t; + +/** Enum names. */ +const char* thermal_oid_name(thermal_oid_t e); + +/** Enum values. */ +int thermal_oid_value(const char* str, thermal_oid_t* e, int substr); + +/** Enum descriptions. */ +const char* thermal_oid_desc(thermal_oid_t e); + +/** Enum validator. */ +int thermal_oid_valid(thermal_oid_t e); + +/** validator */ +#define THERMAL_OID_VALID(_e) \ + (thermal_oid_valid((_e))) + +/** thermal_oid_map table. */ +extern aim_map_si_t thermal_oid_map[]; +/** thermal_oid_desc_map table. */ +extern aim_map_si_t thermal_oid_desc_map[]; +/* */ + +/* psu info table */ +struct psu_info_s { + char path[PATH_MAX]; + int present; + int busno; + int addr; +}; + +#define SYS_HWMON1_PREFIX "/sys/class/hwmon/hwmon1/device" +#define SYS_HWMON2_PREFIX "/sys/class/hwmon/hwmon2/device" + +#endif /* __X86_64_NETBERG_AURORA_420_RANGELEY_INT_H__ */ diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.c new file mode 100755 index 00000000..c465bdec --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.c @@ -0,0 +1,18 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_netberg_aurora_420_rangeley_log.h" +/* + * x86_64_netberg_aurora_420_rangeley log struct. + */ +AIM_LOG_STRUCT_DEFINE( + X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_OPTIONS_DEFAULT, + X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_BITS_DEFAULT, + NULL, /* Custom log map */ + X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_LOG_CUSTOM_BITS_DEFAULT + ); + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.h b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.h new file mode 100755 index 00000000..e3724e3f --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_log.h @@ -0,0 +1,12 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#ifndef __X86_64_NETBERG_AURORA_420_RANGELEY_LOG_H__ +#define __X86_64_NETBERG_AURORA_420_RANGELEY_LOG_H__ + +#define AIM_LOG_MODULE_NAME x86_64_netberg_aurora_420_rangeley +#include + +#endif /* __X86_64_NETBERG_AURORA_420_RANGELEY_LOG_H__ */ diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_module.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_module.c new file mode 100755 index 00000000..1924d1a6 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_module.c @@ -0,0 +1,24 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#include "x86_64_netberg_aurora_420_rangeley_log.h" + +static int +datatypes_init__(void) +{ +#define X86_64_NETBERG_AURORA_420_RANGELEY_ENUMERATION_ENTRY(_enum_name, _desc) AIM_DATATYPE_MAP_REGISTER(_enum_name, _enum_name##_map, _desc, AIM_LOG_INTERNAL); +#include + return 0; +} + +void __x86_64_netberg_aurora_420_rangeley_module_init__(void) +{ + AIM_LOG_STRUCT_REGISTER(); + datatypes_init__(); +} + +int __onlp_platform_version__ = 1; diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_ucli.c b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_ucli.c new file mode 100755 index 00000000..5bfdc4cd --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/onlp/builds/src/x86_64_netberg_aurora_420_rangeley/module/src/x86_64_netberg_aurora_420_rangeley_ucli.c @@ -0,0 +1,50 @@ +/**************************************************************************//** + * + * + * + *****************************************************************************/ +#include + +#if X86_64_NETBERG_AURORA_420_RANGELEY_CONFIG_INCLUDE_UCLI == 1 + +#include +#include +#include + +static ucli_status_t +x86_64_netberg_aurora_420_rangeley_ucli_ucli__config__(ucli_context_t* uc) +{ + UCLI_HANDLER_MACRO_MODULE_CONFIG(x86_64_netberg_aurora_420_rangeley) +} + +/* */ +/* */ + +static ucli_module_t +x86_64_netberg_aurora_420_rangeley_ucli_module__ = + { + "x86_64_netberg_aurora_420_rangeley_ucli", + NULL, + x86_64_netberg_aurora_420_rangeley_ucli_ucli_handlers__, + NULL, + NULL, + }; + +ucli_node_t* +x86_64_netberg_aurora_420_rangeley_ucli_node_create(void) +{ + ucli_node_t* n; + ucli_module_init(&x86_64_netberg_aurora_420_rangeley_ucli_module__); + n = ucli_node_create("x86_64_netberg_aurora_420_rangeley", NULL, &x86_64_netberg_aurora_420_rangeley_ucli_module__); + ucli_node_subnode_add(n, ucli_module_log_node_create("x86_64_netberg_aurora_420_rangeley")); + return n; +} + +#else +void* +x86_64_netberg_aurora_420_rangeley_ucli_node_create(void) +{ + return NULL; +} +#endif + diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/Makefile new file mode 100755 index 00000000..003238cf --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/Makefile b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/Makefile new file mode 100755 index 00000000..003238cf --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/Makefile @@ -0,0 +1 @@ +include $(ONL)/make/pkg.mk \ No newline at end of file diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/PKG.yml b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/PKG.yml new file mode 100755 index 00000000..ad4b02d5 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/PKG.yml @@ -0,0 +1 @@ +!include $ONL_TEMPLATES/platform-config-platform.yml ARCH=amd64 VENDOR=netberg BASENAME=x86-64-netberg-aurora-420-rangeley REVISION=r0 diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/lib/x86-64-netberg-aurora-420-rangeley-r0.yml b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/lib/x86-64-netberg-aurora-420-rangeley-r0.yml new file mode 100755 index 00000000..ad855b37 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/lib/x86-64-netberg-aurora-420-rangeley-r0.yml @@ -0,0 +1,30 @@ +--- + +###################################################################### +# +# platform-config for AURORA 420 +# +###################################################################### + +x86-64-netberg-aurora-420-rangeley-r0: + + grub: + + serial: >- + --port=0x2f8 + --speed=115200 + --word=8 + --parity=no + --stop=1 + + kernel: + <<: *kernel-3-16 + + args: >- + console=ttyS1,115200n8 + + ##network: + ## interfaces: + ## ma1: + ## name: ~ + ## syspath: pci0000:00/0000:00:14.0 diff --git a/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/python/x86_64_netberg_aurora_420_rangeley_r0/__init__.py b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/python/x86_64_netberg_aurora_420_rangeley_r0/__init__.py new file mode 100644 index 00000000..94949cd7 --- /dev/null +++ b/packages/platforms/netberg/x86-64/x86-64-netberg-aurora-420-rangeley/platform-config/r0/src/python/x86_64_netberg_aurora_420_rangeley_r0/__init__.py @@ -0,0 +1,12 @@ +from onl.platform.base import * +from onl.platform.netberg import * + +class OnlPlatform_x86_64_netberg_aurora_420_rangeley_r0(OnlPlatformNetberg, + OnlPlatformPortConfig_48x10_6x40): + PLATFORM='x86-64-netberg-aurora-420-rangeley-r0' + MODEL="AURORA420" + SYS_OBJECT_ID=".420.1" + + def baseconfig(self): + self.insmod("hardware_monitor") + return True From f5dd66b4aa3608dcbe43306dfb0120d0f7087f6d Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Wed, 12 Sep 2018 13:49:12 +0800 Subject: [PATCH 14/22] [oom] Correct a panic inducing defect which is triggered on a read (or write) --- packages/base/any/kernels/modules/optoe.c | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/base/any/kernels/modules/optoe.c b/packages/base/any/kernels/modules/optoe.c index b3064f02..c22b92a2 100644 --- a/packages/base/any/kernels/modules/optoe.c +++ b/packages/base/any/kernels/modules/optoe.c @@ -660,6 +660,7 @@ static ssize_t optoe_read_write(struct optoe_data *optoe, ssize_t retval; size_t pending_len = 0, chunk_len = 0; loff_t chunk_offset = 0, chunk_start_offset = 0; + loff_t chunk_end_offset = 0; dev_dbg(&client->dev, "%s: off %lld len:%ld, opcode:%s\n", @@ -699,30 +700,30 @@ static ssize_t optoe_read_write(struct optoe_data *optoe, /* * Compute the offset and number of bytes to be read/write * - * 1. start at offset 0 (within the chunk), and read/write - * the entire chunk - * 2. start at offset 0 (within the chunk) and read/write less - * than entire chunk - * 3. start at an offset not equal to 0 and read/write the rest + * 1. start at an offset not equal to 0 (within the chunk) + * and read/write less than the rest of the chunk + * 2. start at an offset not equal to 0 and read/write the rest * of the chunk - * 4. start at an offset not equal to 0 and read/write less than - * (end of chunk - offset) + * 3. start at offset 0 (within the chunk) and read/write less + * than entire chunk + * 4. start at offset 0 (within the chunk), and read/write + * the entire chunk */ chunk_start_offset = chunk * OPTOE_PAGE_SIZE; + chunk_end_offset = chunk_start_offset + OPTOE_PAGE_SIZE; if (chunk_start_offset < off) { chunk_offset = off; - if ((off + pending_len) < (chunk_start_offset + - OPTOE_PAGE_SIZE)) + if ((off + pending_len) < chunk_end_offset) chunk_len = pending_len; else - chunk_len = OPTOE_PAGE_SIZE - off; + chunk_len = chunk_end_offset - off; } else { chunk_offset = chunk_start_offset; - if (pending_len > OPTOE_PAGE_SIZE) - chunk_len = OPTOE_PAGE_SIZE; - else + if (pending_len < OPTOE_PAGE_SIZE) chunk_len = pending_len; + else + chunk_len = OPTOE_PAGE_SIZE; } dev_dbg(&client->dev, From 0aac34fe7c23368c327fe4ccfa8e82fb43d25575 Mon Sep 17 00:00:00 2001 From: Kiran Poola Date: Thu, 13 Sep 2018 11:01:16 -0700 Subject: [PATCH 15/22] Latest bigcode Support for PIM null register message in PPE --- sm/bigcode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sm/bigcode b/sm/bigcode index 3a0ca236..59b58a4c 160000 --- a/sm/bigcode +++ b/sm/bigcode @@ -1 +1 @@ -Subproject commit 3a0ca236ecba75278dffa31c7c4c91a9be2285f4 +Subproject commit 59b58a4c8b7fb59060e4d76a2872458bb806ed5f From 45b9562676d7922dc34ea4fe586b7ae0a09326bf Mon Sep 17 00:00:00 2001 From: SnDream Date: Tue, 18 Sep 2018 19:55:33 +0800 Subject: [PATCH 16/22] Fix typo --- packages/base/any/onlp/src/onlp/module/src/onlp_locks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/base/any/onlp/src/onlp/module/src/onlp_locks.h b/packages/base/any/onlp/src/onlp/module/src/onlp_locks.h index 7a3c92e1..66184704 100644 --- a/packages/base/any/onlp/src/onlp/module/src/onlp_locks.h +++ b/packages/base/any/onlp/src/onlp/module/src/onlp_locks.h @@ -206,7 +206,7 @@ void onlp_api_unlock(void); ONLP_API_T1(_name); \ ONLP_LOCKED_API_NAME(_name) (_v1, _v2, _v3); \ ONLP_API_UNLOCK(); \ - ONLP_API_T2_(name); \ + ONLP_API_T2(name); \ } #define ONLP_LOCKED_VAPI4(_name, _t1, _v1, _t2, _v2, _t3, _v3, _t4, _v4) \ From 4f5655060df6fce2c9ded4160a5717a4663d492d Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 20 Sep 2018 18:14:08 -0700 Subject: [PATCH 17/22] Fixed shell invocation bug in onie-sysinfo --- .../all/vendor-config-onl/src/python/onl/install/ShellApp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py index fcf7f93d..2f28476f 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py @@ -242,8 +242,10 @@ class OnieSysinfoApp(SubprocessMixin, object): with InitrdContext(initrd=initrd, log=self.log) as ctx: cmd = ['onie-sysinfo',] cmd.extend(self.args) + self.log.info("foo!") + cmd = 'IFS=;' + " ".join(cmd) cmd = ('chroot', ctx.dir, - '/bin/sh', '-c', 'IFS=;' + " ".join(cmd)) + '/bin/sh', '-c', cmd,) try: self.output = self.check_output(cmd) ret = 0 From 2cd5d8afe2deae8847a10c3cac2b3c023024f0fe Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 20 Sep 2018 18:15:07 -0700 Subject: [PATCH 18/22] Cleanups for execute method - support tuple arguments - send stdout/stderr output to the logger --- .../src/python/onl/util/__init__.py | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/util/__init__.py b/packages/base/all/vendor-config-onl/src/python/onl/util/__init__.py index c085b3f2..f625f2b5 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/util/__init__.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/util/__init__.py @@ -1,18 +1,49 @@ import subprocess +import logging class OnlServiceMixin(object): - def _execute(self, cmd, root=False, ex=True): - self.logger.debug("Executing: %s" % cmd) + + def _execute(self, cmd, + root=False, ex=True, + logLevel=logging.DEBUG): + self.logger.log(logLevel, "Executing: %s", cmd) + + if isinstance(cmd, basestring): + shell = True + else: + shell = False + if root is True and os.getuid() != 0: - cmd = "sudo " + cmd + if isinstance(cmd, basestring): + cmd = "sudo " + cmd + else: + cmd = ['sudo',] + list(cmd) + try: - subprocess.check_call(cmd, shell=True) - except Exception, e: + pipe = subprocess.Popen(cmd, shell=shell, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + except OSError as e: if ex: - self.logger.error("Command failed: %s" % e) + self.logger.error("Command did not start: %s (%s)", + str(e), str(e.child_traceback),) raise else: - return e.returncode + return -1 + + out, _ = pipe.communicate() + code = pipe.wait() + + lvl = logging.WARN if code else logLevel + out = (out or "").rstrip() + for line in out.splitlines(False): + self.logger.log(lvl, ">>> %s", line) + + if ex and code: + self.logger.error("Command failed with code %s", code) + raise subprocess.CalledProcessError(code, cmd) + + return code def _raise(self, msg, klass): self.logger.critical(msg) From 8ac2f0330bd59164fba4b4fd7c5dc088eb6b2ecf Mon Sep 17 00:00:00 2001 From: "Carl D. Roth" Date: Thu, 20 Sep 2018 18:15:35 -0700 Subject: [PATCH 19/22] Cleanup mount point usage - cut down on nested mount invocations --- .../src/python/onl/pki/__init__.py | 96 ++++++++++++------- 1 file changed, 62 insertions(+), 34 deletions(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/pki/__init__.py b/packages/base/all/vendor-config-onl/src/python/onl/pki/__init__.py index eec0f7fc..35c891bc 100755 --- a/packages/base/all/vendor-config-onl/src/python/onl/pki/__init__.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/pki/__init__.py @@ -8,11 +8,8 @@ import sys import os import argparse import logging -import tempfile import shutil -import subprocess import tempfile -import yaml from onl.mounts import OnlMountManager, OnlMountContextReadOnly, OnlMountContextReadWrite from onl.sysconfig import sysconfig from onl.util import * @@ -50,39 +47,70 @@ class OnlPki(OnlServiceMixin): self.init_cert(force=force) def init_key(self, force=False): - with OnlPkiContextReadOnly(self.logger): - if not os.path.exists(self.kpath) or force: - self.logger.info("Generating private key...") - cmd = "openssl genrsa -out %s %s" % (self.kpath, sysconfig.pki.key.len) - with OnlPkiContextReadWrite(self.logger): - if not os.path.isdir(self.CONFIG_PKI_DIR): - os.makedirs(self.CONFIG_PKI_DIR) - self._execute(cmd) - self.init_cert(force=True) - else: - self.logger.info("Using existing private key.") + need_key = False + need_cert = False + + if force: + need_key = True + else: + with OnlPkiContextReadOnly(self.logger): + if not os.path.exists(self.kpath): + need_key = True + + if need_key: + self.logger.info("Generating private key...") + cmd = ('openssl', 'genrsa', + '-out', self.kpath, + str(sysconfig.pki.key.len),) + with OnlPkiContextReadWrite(self.logger): + if not os.path.isdir(self.CONFIG_PKI_DIR): + os.makedirs(self.CONFIG_PKI_DIR) + self._execute(cmd, logLevel=logging.INFO) + need_cert = True + else: + self.logger.info("Using existing private key.") + + if need_cert: + self.init_cert(force=True) def init_cert(self, force=False): - with OnlPkiContextReadOnly(self.logger): - if not os.path.exists(self.cpath) or force: - self.logger.info("Generating self-signed certificate...") - csr = tempfile.NamedTemporaryFile(prefix="pki-", suffix=".csr", delete=False) - csr.close() - fields = [ "%s=%s" % (k, v) for k,v in sysconfig.pki.cert.csr.fields.iteritems() ] - subject = "/" + "/".join(fields) - self.logger.debug("Subject: '%s'", subject) - self.logger.debug("CSR: %s", csr.name) - with OnlPkiContextReadWrite(self.logger): - if not os.path.isdir(self.CONFIG_PKI_DIR): - os.makedirs(self.CONFIG_PKI_DIR) - self._execute("""openssl req -new -batch -subj "%s" -key %s -out %s""" % ( - subject, self.kpath, csr.name)) - self._execute("""openssl x509 -req -days %s -sha256 -in %s -signkey %s -out %s""" % ( - sysconfig.pki.cert.csr.cdays, - csr.name, self.kpath, self.cpath)) - os.unlink(csr.name) - else: - self.logger.info("Using existing certificate.") + need_cert = False + + if force: + need_cert = True + else: + with OnlPkiContextReadOnly(self.logger): + if not os.path.exists(self.cpath): + need_cert = True + + if need_cert: + self.logger.info("Generating self-signed certificate...") + csr = tempfile.NamedTemporaryFile(prefix="pki-", suffix=".csr", delete=False) + csr.close() + fields = [ "%s=%s" % (k, v) for k,v in sysconfig.pki.cert.csr.fields.iteritems() ] + subject = "/" + "/".join(fields) + self.logger.debug("Subject: '%s'", subject) + self.logger.debug("CSR: %s", csr.name) + with OnlPkiContextReadWrite(self.logger): + if not os.path.isdir(self.CONFIG_PKI_DIR): + os.makedirs(self.CONFIG_PKI_DIR) + self._execute(('openssl', 'req', + '-new', '-batch', + '-subj', subject, + '-key', self.kpath, + '-out', csr.name,), + logLevel=logging.INFO) + self._execute(('openssl', 'x509', + '-req', + '-days', str(sysconfig.pki.cert.csr.cdays), + '-sha256', + '-in', csr.name, + '-signkey', self.kpath, + '-out', self.cpath,), + logLevel=logging.INFO) + os.unlink(csr.name) + else: + self.logger.info("Using existing certificate.") @staticmethod def main(): From 1808b4fca308aded228c071e7ec7ecaf238cc6ea Mon Sep 17 00:00:00 2001 From: Zi Zhou Date: Fri, 28 Sep 2018 15:36:35 -0700 Subject: [PATCH 20/22] change kernel config to suppport DELL FPGA opencore i2c driver --- .../configs/x86_64-all/x86_64-all.config | 84 ++++++++++++------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config b/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config index ad3795fc..90872b8f 100755 --- a/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config +++ b/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config @@ -37,6 +37,7 @@ CONFIG_ZONE_DMA32=y CONFIG_AUDIT_ARCH=y CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_HAVE_INTEL_TXT=y CONFIG_X86_64_SMP=y CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_FIX_EARLYCON_MEM=y @@ -557,6 +558,7 @@ CONFIG_ARCH_ENABLE_THP_MIGRATION=y CONFIG_PHYS_ADDR_T_64BIT=y CONFIG_BOUNCE=y CONFIG_VIRT_TO_BUS=y +CONFIG_MMU_NOTIFIER=y CONFIG_KSM=y CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y @@ -1706,12 +1708,12 @@ CONFIG_PATA_SCH=y # CONFIG_PATA_LEGACY is not set CONFIG_MD=y CONFIG_BLK_DEV_MD=y -# CONFIG_MD_AUTODETECT is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID10 is not set -# CONFIG_MD_RAID456 is not set +CONFIG_MD_AUTODETECT=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=y +CONFIG_MD_RAID456=y # CONFIG_MD_MULTIPATH is not set # CONFIG_MD_FAULTY is not set # CONFIG_BCACHE is not set @@ -1719,19 +1721,25 @@ CONFIG_BLK_DEV_DM_BUILTIN=y CONFIG_BLK_DEV_DM=y # CONFIG_DM_MQ_DEFAULT is not set # CONFIG_DM_DEBUG is not set +CONFIG_DM_BUFIO=y +# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set +CONFIG_DM_BIO_PRISON=y +CONFIG_DM_PERSISTENT_DATA=y CONFIG_DM_CRYPT=y -# CONFIG_DM_SNAPSHOT is not set -# CONFIG_DM_THIN_PROVISIONING is not set +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_THIN_PROVISIONING=y # CONFIG_DM_CACHE is not set # CONFIG_DM_ERA is not set -# CONFIG_DM_MIRROR is not set -# CONFIG_DM_RAID is not set +CONFIG_DM_MIRROR=y +# CONFIG_DM_LOG_USERSPACE is not set +CONFIG_DM_RAID=y # CONFIG_DM_ZERO is not set # CONFIG_DM_MULTIPATH is not set # CONFIG_DM_DELAY is not set -# CONFIG_DM_UEVENT is not set +CONFIG_DM_UEVENT=y # CONFIG_DM_FLAKEY is not set -# CONFIG_DM_VERITY is not set +CONFIG_DM_VERITY=y +# CONFIG_DM_VERITY_FEC is not set # CONFIG_DM_SWITCH is not set # CONFIG_DM_LOG_WRITES is not set # CONFIG_DM_INTEGRITY is not set @@ -1757,9 +1765,10 @@ CONFIG_MACVLAN=y CONFIG_MACVTAP=y # CONFIG_VXLAN is not set # CONFIG_MACSEC is not set -# CONFIG_NETCONSOLE is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set +CONFIG_NETCONSOLE=y +# CONFIG_NETCONSOLE_DYNAMIC is not set +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y CONFIG_TUN=y CONFIG_TAP=y # CONFIG_TUN_VNET_CROSS_LE is not set @@ -2203,7 +2212,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y # CONFIG_SERIAL_8250_FSL is not set -# CONFIG_SERIAL_8250_DW is not set +CONFIG_SERIAL_8250_DW=y # CONFIG_SERIAL_8250_RT288X is not set CONFIG_SERIAL_8250_LPSS=y CONFIG_SERIAL_8250_MID=y @@ -2270,7 +2279,7 @@ CONFIG_DEVPORT=y # I2C support # CONFIG_I2C=y -# CONFIG_ACPI_I2C_OPREGION is not set +CONFIG_ACPI_I2C_OPREGION=y CONFIG_I2C_BOARDINFO=y CONFIG_I2C_COMPAT=y CONFIG_I2C_CHARDEV=y @@ -2327,11 +2336,11 @@ CONFIG_I2C_PIIX4=y # CONFIG_I2C_DESIGNWARE_PCI is not set # CONFIG_I2C_EMEV2 is not set # CONFIG_I2C_GPIO is not set -# CONFIG_I2C_OCORES is not set +CONFIG_I2C_OCORES=y CONFIG_I2C_PCA_PLATFORM=y # CONFIG_I2C_PXA_PCI is not set # CONFIG_I2C_SIMTEC is not set -# CONFIG_I2C_XILINX is not set +CONFIG_I2C_XILINX=y # # External I2C/SMBus adapter drivers @@ -2804,6 +2813,7 @@ CONFIG_MFD_CORE=y CONFIG_LPC_ICH=y CONFIG_LPC_SCH=y # CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_BXTWC is not set # CONFIG_INTEL_SOC_PMIC_CHTWC is not set CONFIG_MFD_INTEL_LPSS=y CONFIG_MFD_INTEL_LPSS_ACPI=y @@ -3411,15 +3421,16 @@ CONFIG_SYNC_FILE=y # CONFIG_SW_SYNC is not set # CONFIG_AUXDISPLAY is not set CONFIG_UIO=y -# CONFIG_UIO_CIF is not set -# CONFIG_UIO_PDRV_GENIRQ is not set -# CONFIG_UIO_DMEM_GENIRQ is not set +CONFIG_UIO_CIF=y +CONFIG_UIO_PDRV_GENIRQ=y +CONFIG_UIO_DMEM_GENIRQ=y # CONFIG_UIO_AEC is not set # CONFIG_UIO_SERCOS3 is not set -# CONFIG_UIO_PCI_GENERIC is not set +CONFIG_UIO_PCI_GENERIC=y # CONFIG_UIO_NETX is not set # CONFIG_UIO_PRUSS is not set # CONFIG_UIO_MF624 is not set +# CONFIG_VFIO is not set CONFIG_VIRT_DRIVERS=y CONFIG_VIRTIO=y @@ -3463,9 +3474,10 @@ CONFIG_X86_PLATFORM_DEVICES=y # CONFIG_INTEL_RST is not set # CONFIG_INTEL_SMARTCONNECT is not set # CONFIG_PVPANIC is not set -# CONFIG_INTEL_PMC_IPC is not set +CONFIG_INTEL_PMC_IPC=y # CONFIG_SURFACE_PRO3_BUTTON is not set -# CONFIG_INTEL_PUNIT_IPC is not set +CONFIG_INTEL_PUNIT_IPC=y +CONFIG_INTEL_TELEMETRY=y # CONFIG_MLX_PLATFORM is not set # CONFIG_MLX_CPLD_PLATFORM is not set # CONFIG_INTEL_TURBO_MAX_3 is not set @@ -3500,14 +3512,21 @@ CONFIG_CLKBLD_I8253=y CONFIG_MAILBOX=y CONFIG_PCC=y # CONFIG_ALTERA_MBOX is not set +CONFIG_IOMMU_API=y CONFIG_IOMMU_SUPPORT=y # # Generic IOMMU Pagetable Support # -# CONFIG_AMD_IOMMU is not set -# CONFIG_INTEL_IOMMU is not set -# CONFIG_IRQ_REMAP is not set +CONFIG_IOMMU_IOVA=y +CONFIG_AMD_IOMMU=y +CONFIG_AMD_IOMMU_V2=y +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +CONFIG_IRQ_REMAP=y # # Remoteproc drivers @@ -4017,6 +4036,7 @@ CONFIG_PROVIDE_OHCI1394_DMA_INIT=y # CONFIG_INTERVAL_TREE_TEST is not set # CONFIG_PERCPU_TEST is not set # CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ASYNC_RAID6_TEST is not set # CONFIG_TEST_HEXDUMP is not set # CONFIG_TEST_STRING_HELPERS is not set # CONFIG_TEST_KSTRTOX is not set @@ -4095,6 +4115,7 @@ CONFIG_SECURITY_NETWORK=y CONFIG_PAGE_TABLE_ISOLATION=y # CONFIG_SECURITY_NETWORK_XFRM is not set # CONFIG_SECURITY_PATH is not set +# CONFIG_INTEL_TXT is not set CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y # CONFIG_HARDENED_USERCOPY is not set # CONFIG_FORTIFY_SOURCE is not set @@ -4112,6 +4133,12 @@ CONFIG_INTEGRITY_AUDIT=y # CONFIG_EVM is not set CONFIG_DEFAULT_SECURITY_DAC=y CONFIG_DEFAULT_SECURITY="" +CONFIG_XOR_BLOCKS=y +CONFIG_ASYNC_CORE=y +CONFIG_ASYNC_MEMCPY=y +CONFIG_ASYNC_XOR=y +CONFIG_ASYNC_PQ=y +CONFIG_ASYNC_RAID6_RECOV=y CONFIG_CRYPTO=y # @@ -4301,6 +4328,7 @@ CONFIG_BINARY_PRINTF=y # # Library routines # +CONFIG_RAID6_PQ=y CONFIG_BITREVERSE=y # CONFIG_HAVE_ARCH_BITREVERSE is not set CONFIG_RATIONAL=y From 5806f03c7267c41f7605699d555e582df8626911 Mon Sep 17 00:00:00 2001 From: Zi Zhou Date: Mon, 1 Oct 2018 09:10:23 -0700 Subject: [PATCH 21/22] kernel config cleanup --- .../4.14-lts/configs/x86_64-all/x86_64-all.config | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config b/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config index 90872b8f..8aa3ce13 100755 --- a/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config +++ b/packages/base/any/kernels/4.14-lts/configs/x86_64-all/x86_64-all.config @@ -1708,8 +1708,8 @@ CONFIG_PATA_SCH=y # CONFIG_PATA_LEGACY is not set CONFIG_MD=y CONFIG_BLK_DEV_MD=y -CONFIG_MD_AUTODETECT=y -CONFIG_MD_LINEAR=y +# CONFIG_MD_AUTODETECT is not set +# CONFIG_MD_LINEAR is not set CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_MD_RAID10=y @@ -1765,10 +1765,9 @@ CONFIG_MACVLAN=y CONFIG_MACVTAP=y # CONFIG_VXLAN is not set # CONFIG_MACSEC is not set -CONFIG_NETCONSOLE=y -# CONFIG_NETCONSOLE_DYNAMIC is not set -CONFIG_NETPOLL=y -CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set CONFIG_TUN=y CONFIG_TAP=y # CONFIG_TUN_VNET_CROSS_LE is not set @@ -2212,7 +2211,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_DETECT_IRQ=y CONFIG_SERIAL_8250_RSA=y # CONFIG_SERIAL_8250_FSL is not set -CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_DW is not set # CONFIG_SERIAL_8250_RT288X is not set CONFIG_SERIAL_8250_LPSS=y CONFIG_SERIAL_8250_MID=y From fcd317b51bf9922e4454387a82ae0894c6a592de Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Mon, 1 Oct 2018 21:34:36 +0000 Subject: [PATCH 22/22] Remove debug message. --- .../all/vendor-config-onl/src/python/onl/install/ShellApp.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py index 2f28476f..4b363e73 100644 --- a/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py +++ b/packages/base/all/vendor-config-onl/src/python/onl/install/ShellApp.py @@ -242,7 +242,6 @@ class OnieSysinfoApp(SubprocessMixin, object): with InitrdContext(initrd=initrd, log=self.log) as ctx: cmd = ['onie-sysinfo',] cmd.extend(self.args) - self.log.info("foo!") cmd = 'IFS=;' + " ".join(cmd) cmd = ('chroot', ctx.dir, '/bin/sh', '-c', cmd,)