From e217354c6e783db404dbe450835928b80dd97e2e Mon Sep 17 00:00:00 2001 From: y7zhou Date: Tue, 10 Dec 2024 11:57:56 -0500 Subject: [PATCH 1/4] [H5-64D]Add driver for SysFPGA, cpupld and swpld2/3, psu, eeprom --- ixr7220h5-64d/modules/Makefile | 3 + ixr7220h5-64d/modules/cpupld.c | 418 +++++++ ixr7220h5-64d/modules/dni_psu.c | 501 +++++++++ ixr7220h5-64d/modules/eeprom_fru.c | 530 +++++++++ ixr7220h5-64d/modules/eeprom_tlv.c | 623 +++++++++++ ixr7220h5-64d/modules/fpga.c | 196 ++++ ixr7220h5-64d/modules/fpga.h | 93 ++ ixr7220h5-64d/modules/fpga_attr.c | 159 +++ ixr7220h5-64d/modules/fpga_attr.h | 35 + ixr7220h5-64d/modules/fpga_gpio.c | 101 ++ ixr7220h5-64d/modules/fpga_gpio.h | 7 + ixr7220h5-64d/modules/fpga_i2c.c | 534 +++++++++ ixr7220h5-64d/modules/fpga_i2c.h | 38 + ixr7220h5-64d/modules/fpga_reg.c | 43 + ixr7220h5-64d/modules/fpga_reg.h | 6 + ixr7220h5-64d/modules/swpld2.c | 1669 ++++++++++++++++++++++++++++ ixr7220h5-64d/modules/swpld3.c | 1564 ++++++++++++++++++++++++++ 17 files changed, 6520 insertions(+) create mode 100644 ixr7220h5-64d/modules/cpupld.c create mode 100644 ixr7220h5-64d/modules/dni_psu.c create mode 100644 ixr7220h5-64d/modules/eeprom_fru.c create mode 100644 ixr7220h5-64d/modules/eeprom_tlv.c create mode 100644 ixr7220h5-64d/modules/fpga.c create mode 100644 ixr7220h5-64d/modules/fpga.h create mode 100644 ixr7220h5-64d/modules/fpga_attr.c create mode 100644 ixr7220h5-64d/modules/fpga_attr.h create mode 100644 ixr7220h5-64d/modules/fpga_gpio.c create mode 100644 ixr7220h5-64d/modules/fpga_gpio.h create mode 100644 ixr7220h5-64d/modules/fpga_i2c.c create mode 100644 ixr7220h5-64d/modules/fpga_i2c.h create mode 100644 ixr7220h5-64d/modules/fpga_reg.c create mode 100644 ixr7220h5-64d/modules/fpga_reg.h create mode 100644 ixr7220h5-64d/modules/swpld2.c create mode 100644 ixr7220h5-64d/modules/swpld3.c diff --git a/ixr7220h5-64d/modules/Makefile b/ixr7220h5-64d/modules/Makefile index e69de29..2bba394 100644 --- a/ixr7220h5-64d/modules/Makefile +++ b/ixr7220h5-64d/modules/Makefile @@ -0,0 +1,3 @@ +SYSFPGA_NAME = sys_fpga +obj-m := $(SYSFPGA_NAME).o cpupld.o swpld2.o swpld3.o dni_psu.o eeprom_fru.o eeprom_tlv.o +$(SYSFPGA_NAME)-y := fpga.o fpga_attr.o fpga_gpio.o fpga_i2c.o fpga_reg.o diff --git a/ixr7220h5-64d/modules/cpupld.c b/ixr7220h5-64d/modules/cpupld.c new file mode 100644 index 0000000..4ddb10f --- /dev/null +++ b/ixr7220h5-64d/modules/cpupld.c @@ -0,0 +1,418 @@ +// * CPLD driver for Nokia-7220-IXR-H5-64D Router +// * +// * Copyright (C) 2024 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * 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. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "cpupld" + +// REGISTERS ADDRESS MAP +#define SCRATCH_REG 0x00 +#define CODE_REV_REG 0x01 +#define BOARD_INFO_REG 0x02 +#define BIOS_CTRL_REG1 0x05 +#define BIOS_CTRL_REG2 0x06 +#define WATCHDOG_REG 0x07 +#define PERIF_WP_REG 0x09 +#define PWR_CTRL_REG1 0x0A +#define PWR_CTRL_REG2 0x0B +#define PWR_CTRL_REG3 0x0C +#define PWR_STATUS_REG1 0x0D +#define PWR_STATUS_REG2 0x0E +#define PWR_STATUS_REG3 0x0F +#define BOARD_STATUS_REG 0x10 +#define BOARD_CTRL_REG1 0x18 +#define BOARD_CTRL_REG2 0x19 +#define RST_PLD_REG 0x20 +#define RST_CTRLMSK_REG1 0x21 +#define RST_CTRL_REG1 0x22 +#define RST_CTRLMSK_REG2 0x23 +#define RST_CTRL_REG2 0x24 +#define RST_CTRLMSK_REG3 0x25 +#define RST_CTRL_REG3 0x26 +#define RST_CAUSE_REG 0x28 +#define CPU_INT_CLR_REG 0x30 +#define CPU_INT_MSK_REG 0x31 +#define CPU_INT_REG 0x38 +#define HITLESS_REG 0x40 +#define PWR_SEQ_REG 0x80 +#define CODE_DAY_REG 0xF0 +#define CODE_MONTH_REG 0xF1 +#define CODE_YEAR_REG 0xF2 +#define TEST_CODE_REV_REG 0xF3 + + +// REG BIT FIELD POSITION or MASK +#define BOARD_INFO_REG_VER_MSK 0x7 + +#define WATCHDOG_REG_WD_PUNCH 0x0 +#define WATCHDOG_REG_WD_EN 0x3 +#define WATCHDOG_REG_WD_TIMER 0x4 + +#define HITLESS_REG_EN 0x0 + +static const unsigned short cpld_address_list[] = {0x40, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; + int reset_cause; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_err(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + mutex_unlock(&data->update_lock); + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_err(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_code_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_REV_REG); + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_board_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, BOARD_INFO_REG) & BOARD_INFO_REG_VER_MSK; + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_watchdog(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + u8 reg_val; + int ret; + val = cpld_i2c_read(data, WATCHDOG_REG); + + switch (sda->index) { + case WATCHDOG_REG_WD_PUNCH: + case WATCHDOG_REG_WD_EN: + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); + case WATCHDOG_REG_WD_TIMER: + reg_val = (val>>sda->index) & 0x7; + switch (reg_val) { + case 0b000: + ret = 5; + break; + case 0b001: + ret = 10; + break; + case 0b010: + ret = 30; + break; + case 0b011: + ret = 60; + break; + case 0b100: + ret = 180; + break; + case 0b101: + ret = 240; + break; + case 0b110: + ret = 360; + break; + case 0b111: + ret = 480; + break; + default: + ret = 0; + break; + } + return sprintf(buf, "%d: %d seconds\n", reg_val, ret); + default: + return sprintf(buf, "Error: Wrong bitwise(%d) to set!\n", sda->index); + } + +} + +static ssize_t set_watchdog(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + + switch (sda->index) { + case WATCHDOG_REG_WD_PUNCH: + case WATCHDOG_REG_WD_EN: + if (usr_val > 1) { + return -EINVAL; + } + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, WATCHDOG_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, WATCHDOG_REG, (reg_val | usr_val)); + break; + case WATCHDOG_REG_WD_TIMER: + if (usr_val > 7) { + return -EINVAL; + } + mask = (~(7 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, WATCHDOG_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, WATCHDOG_REG, (reg_val | usr_val)); + break; + default: + return sprintf(buf, "Error: Wrong bitwise(%d) to set!\n", sda->index); + } + + return count; +} + +static ssize_t show_rst_cause(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%02x\n", data->reset_cause); +} + +static ssize_t show_hitless(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + val = cpld_i2c_read(data, HITLESS_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_code_day(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_DAY_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_code_month(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_MONTH_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_code_year(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_YEAR_REG); + return sprintf(buf, "%d\n", val); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); +static SENSOR_DEVICE_ATTR(code_ver, S_IRUGO, show_code_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(board_ver, S_IRUGO, show_board_ver, NULL, 0); + +static SENSOR_DEVICE_ATTR(wd_punch, S_IRUGO | S_IWUSR, show_watchdog, set_watchdog, WATCHDOG_REG_WD_PUNCH); +static SENSOR_DEVICE_ATTR(wd_enable, S_IRUGO | S_IWUSR, show_watchdog, set_watchdog, WATCHDOG_REG_WD_EN); +static SENSOR_DEVICE_ATTR(wd_timer, S_IRUGO | S_IWUSR, show_watchdog, set_watchdog, WATCHDOG_REG_WD_TIMER); +static SENSOR_DEVICE_ATTR(reset_cause, S_IRUGO, show_rst_cause, NULL, 0); + +static SENSOR_DEVICE_ATTR(hitless_en, S_IRUGO, show_hitless, NULL, HITLESS_REG_EN); +static SENSOR_DEVICE_ATTR(code_day, S_IRUGO, show_code_day, NULL, 0); +static SENSOR_DEVICE_ATTR(code_month, S_IRUGO, show_code_month, NULL, 0); +static SENSOR_DEVICE_ATTR(code_year, S_IRUGO, show_code_year, NULL, 0); + +static struct attribute *cpupld_attributes[] = { + &sensor_dev_attr_scratch.dev_attr.attr, + &sensor_dev_attr_code_ver.dev_attr.attr, + &sensor_dev_attr_board_ver.dev_attr.attr, + + &sensor_dev_attr_wd_punch.dev_attr.attr, + &sensor_dev_attr_wd_enable.dev_attr.attr, + &sensor_dev_attr_wd_timer.dev_attr.attr, + &sensor_dev_attr_reset_cause.dev_attr.attr, + + &sensor_dev_attr_hitless_en.dev_attr.attr, + &sensor_dev_attr_code_day.dev_attr.attr, + &sensor_dev_attr_code_month.dev_attr.attr, + &sensor_dev_attr_code_year.dev_attr.attr, + NULL +}; + +static const struct attribute_group cpupld_group = { + .attrs = cpupld_attributes, +}; + +static int cpupld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct cpld_data *data = NULL; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia CPUCPLD chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &cpupld_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + data->reset_cause = cpld_i2c_read(data, RST_CAUSE_REG); + cpld_i2c_write(data, RST_CAUSE_REG, 0); + + return 0; + +exit: + return status; +} + +static void cpupld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &cpupld_group); + kfree(data); +} + +static const struct of_device_id cpupld_of_ids[] = { + { + .compatible = "nokia,cpupld", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, cpupld_of_ids); + +static const struct i2c_device_id cpupld_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cpupld_ids); + +static struct i2c_driver cpupld_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(cpupld_of_ids), + }, + .probe = cpupld_probe, + .remove = cpupld_remove, + .id_table = cpupld_ids, + .address_list = cpld_address_list, +}; + +static int __init cpupld_init(void) +{ + return i2c_add_driver(&cpupld_driver); +} + +static void __exit cpupld_exit(void) +{ + i2c_del_driver(&cpupld_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(cpupld_init); +module_exit(cpupld_exit); + diff --git a/ixr7220h5-64d/modules/dni_psu.c b/ixr7220h5-64d/modules/dni_psu.c new file mode 100644 index 0000000..d8cb410 --- /dev/null +++ b/ixr7220h5-64d/modules/dni_psu.c @@ -0,0 +1,501 @@ +#include +// An hwmon driver for delta PSU +// +// Copyright (C) 2024 Delta Network Technology Corporation +// Copyright (C) 2024 Nokia Corporation. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PSU parameter */ +#define PSU_REG_RW_VOUT_MODE (0x20) +#define PSU_REG_RO_FAN_STATUS (0x81) +#define PSU_REG_RO_FAN_SPEED (0x90) +#define PSU_REG_RO_VIN (0x88) +#define PSU_REG_RO_VOUT (0x8b) +#define PSU_REG_RO_IIN (0x89) +#define PSU_REG_RO_IOUT (0x8c) +#define PSU_REG_RO_POUT (0x96) +#define PSU_REG_RO_PIN (0x97) +#define PSU_REG_RO_TEMP1 (0x8d) +#define PSU_REG_RO_TEMP2 (0x8e) +#define PSU_REG_RO_TEMP3 (0x8f) +#define PSU_REG_RO_MFR_MODEL (0x9a) +#define PSU_REG_RO_MFR_SERIAL (0x9e) +#define PSU_MFR_MODELNAME_LENGTH (11) +#define PSU_MFR_SERIALNUM_LENGTH (20) +#define PSU_DRIVER_NAME "dni_psu" + +/* fan in PSU */ +#define PSU_FAN_NUMBER (1) +#define PSU_FAN1_FAULT_BIT (7) + +/* thermal in PSU */ +#define PSU_THERMAL_NUMBER (3) + +/* Address scanned */ +static const unsigned short normal_i2c[] = { 0x58, 0x59, I2C_CLIENT_END }; + +/* This is additional data */ +struct psu_data +{ + struct device *hwmon_dev; + struct mutex update_lock; + char valid; + unsigned long last_updated; /* In jiffies */ + /* Registers value */ + u8 vout_mode; + u16 v_in; + u16 v_out; + u16 i_in; + u16 i_out; + u16 p_in; + u16 p_out; + u16 temp_input[PSU_THERMAL_NUMBER]; + u8 fan_fault; + u16 fan_speed[PSU_FAN_NUMBER]; + u8 mfr_model[PSU_MFR_MODELNAME_LENGTH+1]; + u8 mfr_serial[PSU_MFR_SERIALNUM_LENGTH+1]; +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask); +static int calculate_return_value(int value); +static ssize_t for_vin(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_iin(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_iout(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_pin(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_pout(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp1(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp2(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_temp3(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_speed(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf); +static int psu_read_byte(struct i2c_client *client, u8 reg); +static int psu_read_word(struct i2c_client *client, u8 reg); +static int psu_read_block(struct i2c_client *client, u8 command, u8 *data); +static struct psu_data *psu_update_device(struct device *dev, u8 reg); +static ssize_t for_serial(struct device *dev, struct device_attribute *dev_attr, char *buf); +static ssize_t for_model(struct device *dev, struct device_attribute *dev_attr, char *buf); + +enum psu_sysfs_attributes +{ + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_FAN1_FAULT, + PSU_FAN1_DUTY_CYCLE, + PSU_FAN1_SPEED, + PSU_MFR_MODEL, + PSU_MFR_SERIAL, +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static int calculate_return_value(int value) +{ + int multiplier = 1000; + int exponent = 0, mantissa = 0; + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + + return (exponent >= 0) ? (mantissa << exponent) * multiplier : (mantissa * multiplier) / (1 << -exponent); + +} + +static ssize_t for_vin(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_VIN); + + return sprintf(buf, "%d\n", calculate_return_value(data->v_in)); +} + +static ssize_t for_iin(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_IIN); + + + return sprintf(buf, "%d\n", calculate_return_value(data->i_in)); +} + +static ssize_t for_iout(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_IOUT); + + return sprintf(buf, "%d\n", calculate_return_value(data->i_out)); +} + +static ssize_t for_pin(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_PIN); + + return sprintf(buf, "%d\n", calculate_return_value(data->p_in)); +} + +static ssize_t for_pout(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_POUT); + + return sprintf(buf, "%d\n", calculate_return_value(data->p_out)); +} + +static ssize_t for_temp1(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_TEMP1); + + return sprintf(buf, "%d\n", calculate_return_value(data->temp_input[0])); +} + +static ssize_t for_temp2(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_TEMP2); + + return sprintf(buf, "%d\n", calculate_return_value(data->temp_input[1])); +} + +static ssize_t for_temp3(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_TEMP3); + + return sprintf(buf, "%d\n", calculate_return_value(data->temp_input[2])); +} + +static ssize_t for_fan_speed(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_FAN_SPEED); + + return sprintf(buf, "%d\n", calculate_return_value(data->fan_speed[0])/1000); +} + +static ssize_t for_vout_data(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = psu_update_device(dev, PSU_REG_RW_VOUT_MODE); + int exponent = 0, mantissa = 0; + int multiplier = 1000; + + data = psu_update_device(dev, PSU_REG_RO_VOUT); + mdelay(30); + exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + mantissa = data->v_out; + + return (exponent > 0) ? sprintf(buf, "%d\n", \ + mantissa * (1 << exponent)) : \ + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t for_fan_fault(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr); + struct psu_data *data = psu_update_device(dev, PSU_REG_RO_FAN_STATUS); + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? PSU_FAN1_FAULT_BIT : (PSU_FAN1_FAULT_BIT - (attr->index - PSU_FAN1_FAULT)); + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t for_serial(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = dev_get_drvdata(dev); + + if (!data->valid) + return 0; + + return sprintf(buf, "%s\n", data->mfr_serial); +} + +static ssize_t for_model(struct device *dev, struct device_attribute *dev_attr, char *buf) +{ + struct psu_data *data = dev_get_drvdata(dev); + + if (!data->valid) + return 0; + + return sprintf(buf, "%s\n", data->mfr_model); +} + +static int psu_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int psu_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int psu_read_block(struct i2c_client *client, u8 command, u8 *data) +{ + int result = i2c_smbus_read_block_data(client, command, data); + if (unlikely(result < 0)) + goto abort; + + result = 0; +abort: + return result; +} + +struct reg_data_byte +{ + u8 reg; + u8 *value; +}; + +struct reg_data_word +{ + u8 reg; + u16 *value; +}; + +static struct psu_data *psu_update_device(struct device *dev, u8 reg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated)) + { + int i, status; + + struct reg_data_byte regs_byte[] = { + {PSU_REG_RW_VOUT_MODE, &data->vout_mode}, + {PSU_REG_RO_FAN_STATUS, &data->fan_fault} + }; + + struct reg_data_word regs_word[] = { + {PSU_REG_RO_VIN, &data->v_in}, + {PSU_REG_RO_VOUT, &data->v_out}, + {PSU_REG_RO_IIN, &data->i_in}, + {PSU_REG_RO_IOUT, &data->i_out}, + {PSU_REG_RO_POUT, &data->p_out}, + {PSU_REG_RO_PIN, &data->p_in}, + {PSU_REG_RO_TEMP1, &(data->temp_input[0])}, + {PSU_REG_RO_TEMP2, &(data->temp_input[1])}, + {PSU_REG_RO_TEMP3, &(data->temp_input[2])}, + {PSU_REG_RO_FAN_SPEED, &(data->fan_speed[0])}, + }; + + //dev_info(&client->dev, "start data update\n"); + + /* one milliseconds from now */ + data->last_updated = jiffies + HZ / 1000; + + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) + { + if (reg != regs_byte[i].reg) + continue; + + status = psu_read_byte(client, regs_byte[i].reg); + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + } + else + { + *(regs_byte[i].value) = status; + } + break; + } + + for (i = 0; i < ARRAY_SIZE(regs_word); i++) + { + if (reg != regs_word[i].reg) + continue; + + status = psu_read_word(client, regs_word[i].reg); + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", regs_word[i].reg, status); + *(regs_word[i].value) = 0; + } + else + { + *(regs_word[i].value) = status; + } + break; + } + + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +/* sysfs attributes for hwmon */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, for_vin, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, for_vout_data, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, for_iin, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, for_iout, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, for_pin, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, for_pout, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, for_temp1, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, for_temp2, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, for_temp3, NULL, PSU_TEMP3_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, for_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, for_fan_speed, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, for_model, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, for_serial, NULL, PSU_MFR_SERIAL); + +static struct attribute *psu_attributes[] = { + &sensor_dev_attr_psu_v_in.dev_attr.attr, + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_in.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_in.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_mfr_model.dev_attr.attr, + &sensor_dev_attr_psu_mfr_serial.dev_attr.attr, + NULL +}; + +static const struct attribute_group psu_group = { + .attrs = psu_attributes, +}; + +static int psu_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)) + { + dev_info(&client->dev, "i2c_check_functionality failed!!!\n"); + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &psu_group); + if (status) + { + dev_info(&client->dev, "sysfs_create_group failed!!!\n"); + goto exit_sysfs_create_group; + } + + data->hwmon_dev = hwmon_device_register_with_groups(&client->dev, PSU_DRIVER_NAME, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) + { + dev_info(&client->dev, "hwmon_device_register failed!!!\n"); + status = PTR_ERR(data->hwmon_dev); + goto exit_hwmon_device_register; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + // PSU mfr_model + status = psu_read_block(client, PSU_REG_RO_MFR_MODEL, data->mfr_model); + data->mfr_model[ARRAY_SIZE(data->mfr_model) - 1] = '\0'; + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", PSU_REG_RO_MFR_MODEL, status); + data->mfr_model[1] = '\0'; + } + // PSU mfr_serial + status = psu_read_block(client, PSU_REG_RO_MFR_SERIAL, data->mfr_serial); + data->mfr_serial[ARRAY_SIZE(data->mfr_serial) - 1] = '\0'; + if (status < 0) + { + dev_info(&client->dev, "reg %d, err %d\n", PSU_REG_RO_MFR_SERIAL, status); + data->mfr_serial[1] = '\0'; + } + + return 0; + +exit_hwmon_device_register: + sysfs_remove_group(&client->dev.kobj, &psu_group); +exit_sysfs_create_group: + kfree(data); +exit: + return status; +} + +static void psu_remove(struct i2c_client *client) +{ + struct psu_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &psu_group); + kfree(data); + + return; +} + +static const struct i2c_device_id psu_id[] = { + { PSU_DRIVER_NAME, 0 }, + { PSU_DRIVER_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, psu_id); + +/* This is the driver that will be inserted */ +static struct i2c_driver psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = PSU_DRIVER_NAME, + }, + .probe = psu_probe, + .remove = psu_remove, + .id_table = psu_id, + .address_list = normal_i2c, +}; + +static int __init dni_psu_init(void) +{ + return i2c_add_driver(&psu_driver); +} + +static void __exit dni_psu_exit(void) +{ + i2c_del_driver(&psu_driver); +} + +MODULE_AUTHOR("DNI SW5"); +MODULE_DESCRIPTION("DNI PSU Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.0.2"); + +module_init(dni_psu_init); +module_exit(dni_psu_exit); + diff --git a/ixr7220h5-64d/modules/eeprom_fru.c b/ixr7220h5-64d/modules/eeprom_fru.c new file mode 100644 index 0000000..9d3c935 --- /dev/null +++ b/ixr7220h5-64d/modules/eeprom_fru.c @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * eeprom_fru.c - NOKIA EEPROM FRU Sysfs driver + * + * + * Copyright (C) 2024 Nokia Corporation. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * 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. + * see + */ + +#include +#include +#include +#include + +#define EEPROM_NAME "eeprom_fru" +#define FIELD_LEN_MAX 255 +#define VERBOSE 0 +static unsigned int debug = 0; +module_param_named(debug, debug, uint, 0); +MODULE_PARM_DESC(debug, "Debug enable(default to 0)"); + +static unsigned int read_eeprom_max_len = 176; +module_param_named(read_eeprom_max_len, read_eeprom_max_len, uint, 0); +MODULE_PARM_DESC(read_eeprom_max_len, "read_eeprom_max_len(default to 176)"); + +#define FRU_END_OF_FIELDS 0xc1 +#define BUF2STR_MAXIMUM_OUTPUT_SIZE (3*1024 + 1) +struct fru_header { + u8 version; + union { + struct { + u8 internal; + u8 chassis; + u8 board; + u8 product; + u8 multi; + } offset; + u8 offsets[5]; + }; + u8 pad; + u8 checksum; +}; + +struct at24_data { + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + struct i2c_client *client; + char part_number[FIELD_LEN_MAX + 1]; + char product_version[FIELD_LEN_MAX + 1]; + char serial_number[FIELD_LEN_MAX + 1]; +#if VERBOSE + char mfg_name[FIELD_LEN_MAX+1]; + char product_name[FIELD_LEN_MAX + 1]; + char extra[3][FIELD_LEN_MAX + 1]; +#endif +}; + +u8 fru_calc_checksum(void *area, size_t len) +{ + u8 checksum = 0; + u8 * data = area; + size_t i; + + for (i = 0; i < len - 1; i++) + checksum += data[i]; + + return -checksum; +} + +int fru_checksum_is_valid(void *area, size_t len) +{ + u8 * data = area; + /* Checksum is valid when the stored checksum equals calculated */ + return data[len - 1] == fru_calc_checksum(area, len); +} + +const char * buf2str_extended(const u8 *buf, int len, const char *sep) +{ + static char str[BUF2STR_MAXIMUM_OUTPUT_SIZE] = {0}; + char *cur; + int i; + int sz; + int left; + int sep_len; + + if (!buf) { + snprintf(str, sizeof(str), ""); + return (const char *)str; + } + cur = str; + left = sizeof(str); + if (sep) { + sep_len = strlen(sep); + } else { + sep_len = 0; + } + for (i = 0; i < len; i++) { + /* may return more than 2, depending on locale */ + sz = snprintf(cur, left, "%2.2x", buf[i]); + if (sz >= left) { + /* buffer overflow, truncate */ + break; + } + cur += sz; + left -= sz; + /* do not write separator after last byte */ + if (sep && i != (len - 1)) { + if (sep_len >= left) { + break; + } + strncpy(cur, sep, left - sz); + cur += sep_len; + left -= sep_len; + } + } + *cur = '\0'; + + return (const char *)str; +} + +const char * buf2str(const u8 *buf, int len) +{ + return buf2str_extended(buf, len, NULL); +} + +char * get_fru_area_str(struct device *dev, u8 * data, u32 * offset) +{ + static const char bcd_plus[] = "0123456789 -.:,_"; + char * str; + int len, off, size, i, j, k, typecode, char_idx; + union { + u32 bits; + char chars[4]; + } u; + + size = 0; + off = *offset; + + /* bits 6:7 contain format */ + typecode = ((data[off] & 0xC0) >> 6); + + /* bits 0:5 contain length */ + len = data[off++]; + len &= 0x3f; + + switch (typecode) { + case 0: /* 00b: binary/unspecified */ + case 1: /* 01b: BCD plus */ + /* hex dump or BCD -> 2x length */ + size = (len * 2); + break; + case 2: /* 10b: 6-bit ASCII */ + /* 4 chars per group of 1-3 bytes, round up to 4 bytes boundary */ + size = (len / 3 + 1) * 4; + break; + case 3: /* 11b: 8-bit ASCII */ + /* no length adjustment */ + size = len; + break; + } + + if (size < 1) { + *offset = off; + return NULL; + } + str = devm_kzalloc(dev, size+1, GFP_KERNEL); + if (!str) + return NULL; + + if (size == 0) { + str[0] = '\0'; + *offset = off; + return str; + } + + switch (typecode) { + case 0: /* Binary */ + strncpy(str, buf2str(&data[off], len), size); + break; + + case 1: /* BCD plus */ + for (k = 0; k < size; k++) + str[k] = bcd_plus[((data[off + k / 2] >> ((k % 2) ? 0 : 4)) & 0x0f)]; + str[k] = '\0'; + break; + + case 2: /* 6-bit ASCII */ + for (i = j = 0; i < len; i += 3) { + u.bits = 0; + k = ((len - i) < 3 ? (len - i) : 3); + + memcpy((void *)&u.bits, &data[off+i], k); + char_idx = 0; + for (k=0; k<4; k++) { + str[j++] = ((u.chars[char_idx] & 0x3f) + 0x20); + u.bits >>= 6; + } + } + str[j] = '\0'; + break; + + case 3: + memcpy(str, &data[off], size); + str[size] = '\0'; + break; + } + + off += len; + *offset = off; + + return str; +} + +static int decode_fru_product_info_area(struct i2c_client *client, u8 * raw_data, u32 offset) +{ + char * fru_area; + u8 * fru_data; + u32 fru_len, i; + u8 * tmp = raw_data + offset; + struct device *dev = &client->dev; + struct at24_data *at24 = i2c_get_clientdata(client); + fru_len = 0; + + /* read enough to check length field */ + fru_len = 8 * tmp[1]; + + if (fru_len == 0) { + return -EINVAL; + } + fru_data = devm_kzalloc(dev, fru_len, GFP_KERNEL); + + if (!fru_data) + return -ENOMEM; + + memcpy(fru_data, raw_data+offset, fru_len); + + struct fru_product_info_area_field { + char name[64]; + char * p; + }; + + const struct fru_product_info_area_field fru_fields[] = { + {"Product Area Format Version", NULL}, + {"Product Area Length", NULL}, + {"Language Code", NULL}, +#if VERBOSE + {"Manufacturer Name", at24->mfg_name}, + {"Product Name", at24->product_name}, +#else + {"Manufacturer Name", NULL}, + {"Product Name", NULL}, +#endif + {"Product Part/Model Number", at24->part_number}, + {"Product Version", at24->product_version}, + {"Product Serial Number", at24->serial_number}, + {"Asset Tag", NULL}, + {"FRU File ID", NULL}, +#if VERBOSE + {"Product Extra 1", at24->extra[0]}, + {"Product Extra 2", at24->extra[1]}, + {"Product Extra 3", at24->extra[2]} +#else + {"Product Extra 1", NULL}, + {"Product Extra 2", NULL}, + {"Product Extra 3", NULL} +#endif + }; + + /* Check area checksum */ + if(debug && !fru_checksum_is_valid(fru_data, fru_len)) { + dev_warn(dev, "Invalid eeprom checksum.\n"); + return -EINVAL; + } + + i = 3; + int j = 0; + for(; j < ARRAY_SIZE(fru_fields); j++) + { + if(j < 3) { + if(debug) { + dev_info(dev, "%s: %x\n", fru_fields[j].name, fru_data[j]); + } + continue; + } + fru_area = get_fru_area_str(dev, fru_data, &i); + if(fru_area && fru_fields[j].p) { + if (strlen(fru_area) > 0) { + if(debug) { + dev_info(dev, "%s: %s\n", fru_fields[j].name, fru_area); + } + int len = strlen(fru_area); + if( len > FIELD_LEN_MAX) { + len = FIELD_LEN_MAX; + } + strncpy(fru_fields[j].p, fru_area, len); + } + } + } + return 0; +} + +int decode_eeprom(struct i2c_client *client) +{ + int ret; + + u8 * raw_data = kzalloc(read_eeprom_max_len, GFP_KERNEL); + if (!raw_data) { + return -ENOMEM; + } + + // i2c_smbus initiate eeprom chip's internel "CURRENT ADDRESS" for reading + ret = i2c_smbus_write_word_data(client, 0, 0); + msleep(1); + for (int i = 0; i < read_eeprom_max_len; i++) { + raw_data[i]= i2c_smbus_read_byte(client); + } + + struct fru_header header; + memset(&header, 0, sizeof(struct fru_header)); + + if(debug) { + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, raw_data, read_eeprom_max_len, true); + } + + /* According to IPMI Platform Management FRU Information Storage Definition v1.0 */ + memcpy(&header, raw_data, 8); +#if VERBOSE + if (header.version != 1) { + struct device *dev = &client->dev; + dev_err(dev, "Unknown FRU header version 0x%02x", header.version); + kfree(raw_data); + return -1; + } +#endif + /* + * Only process Product Info Area + */ + if ((header.offset.product*8) >= sizeof(struct fru_header)) + decode_fru_product_info_area(client, raw_data, header.offset.product*8); + + kfree(raw_data); + return 0; +} + +static ssize_t trigger_read_eeprom(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + if(!strncmp(buf,"1", count-1)) { + struct at24_data *data = dev_get_drvdata(dev); + decode_eeprom(data->client); + } + return count; +} + +static ssize_t show_part_number(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->part_number); +} + +static ssize_t show_serial_number(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->serial_number); +} + +static ssize_t show_product_version(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->product_version); +} + +#if VERBOSE +static ssize_t show_mfg_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->mfg_name); +} + +static ssize_t show_product_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->product_name); +} + +static ssize_t show_extra1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->extra[0]); +} + +static ssize_t show_extra2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->extra[1]); +} + +static ssize_t show_extra3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->extra[2]); +} +#endif + +// sysfs attributes +static SENSOR_DEVICE_ATTR(read_eeprom, S_IWUSR, NULL, trigger_read_eeprom, 0); +static SENSOR_DEVICE_ATTR(part_number, S_IRUGO, show_part_number, NULL, 0); +static SENSOR_DEVICE_ATTR(serial_number, S_IRUGO, show_serial_number, NULL, 0); +static SENSOR_DEVICE_ATTR(product_version, S_IRUGO, show_product_version, NULL, 0); + +#if VERBOSE +static SENSOR_DEVICE_ATTR(mfg_name, S_IRUGO, show_mfg_name, NULL, 0); +static SENSOR_DEVICE_ATTR(product_name, S_IRUGO, show_product_name, NULL, 0); +static SENSOR_DEVICE_ATTR(extra1, S_IRUGO, show_extra1, NULL, 0); +static SENSOR_DEVICE_ATTR(extra2, S_IRUGO, show_extra2, NULL, 0); +static SENSOR_DEVICE_ATTR(extra3, S_IRUGO, show_extra3, NULL, 0); +#endif + +static struct attribute *eeprom_attributes[] = { + &sensor_dev_attr_read_eeprom.dev_attr.attr, + &sensor_dev_attr_part_number.dev_attr.attr, + &sensor_dev_attr_serial_number.dev_attr.attr, + &sensor_dev_attr_product_version.dev_attr.attr, +#if VERBOSE + &sensor_dev_attr_mfg_name.dev_attr.attr, + &sensor_dev_attr_product_name.dev_attr.attr, + &sensor_dev_attr_extra1.dev_attr.attr, + &sensor_dev_attr_extra2.dev_attr.attr, + &sensor_dev_attr_extra3.dev_attr.attr, +#endif + NULL +}; + +static const struct attribute_group eeprom_group = { + .attrs = eeprom_attributes, +}; + +static int eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct at24_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)) { + dev_info(&client->dev, "i2c_check_functionality failed!\n"); + status = -EIO; + return status; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + return status; + } + + mutex_init(&data->lock); + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "eeprom chip found\n"); + /* Create sysfs entries */ + status = sysfs_create_group(&client->dev.kobj, &eeprom_group); + if (status) { + dev_err(dev, "Cannot create sysfs\n"); + kfree(data); + return status; + } + data->client = client; + decode_eeprom(client); + return status; +} + +static void eeprom_remove(struct i2c_client *client) +{ + struct at24_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &eeprom_group); + kfree(data); + return; +} + +static const struct i2c_device_id eeprom_id[] = { + { EEPROM_NAME, 0 }, + { EEPROM_NAME, 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, eeprom_id); + +/* Address scanned */ +static const unsigned short normal_i2c[] = { 0x50, 0x51, I2C_CLIENT_END }; + +/* This is the driver that will be inserted */ +static struct i2c_driver eeprom_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = EEPROM_NAME, + }, + .probe = eeprom_probe, + .remove = eeprom_remove, + .id_table = eeprom_id, + .address_list = normal_i2c, +}; + +static int __init eeprom_init(void) +{ + return i2c_add_driver(&eeprom_driver); +} + +static void __exit eeprom_exit(void) +{ + i2c_del_driver(&eeprom_driver); +} + +MODULE_DESCRIPTION("NOKIA EEPROM FRU Sysfs driver"); +MODULE_AUTHOR("Nokia"); +MODULE_LICENSE("GPL"); + +module_init(eeprom_init); +module_exit(eeprom_exit); \ No newline at end of file diff --git a/ixr7220h5-64d/modules/eeprom_tlv.c b/ixr7220h5-64d/modules/eeprom_tlv.c new file mode 100644 index 0000000..d86640d --- /dev/null +++ b/ixr7220h5-64d/modules/eeprom_tlv.c @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * eeprom_tlv.c - NOKIA EEPROM TLV Sysfs driver + * + * + * Copyright (C) 2024 Nokia Corporation. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * 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. + * see + */ + +#include +#include +#include +#include + +#define EEPROM_NAME "eeprom_tlv" +#define FIELD_LEN_MAX 255 +#define VERBOSE 0 +static unsigned int debug = 0; +module_param_named(debug, debug, uint, 0); +MODULE_PARM_DESC(debug, "Debug enable(default to 0)"); + +static unsigned int read_eeprom_max_len = 96; +module_param_named(read_eeprom_max_len, read_eeprom_max_len, uint, 0); +MODULE_PARM_DESC(read_eeprom_max_len, "read_eeprom_max_len(default to 96)"); + +/** + * The TLV Types. + */ +#define ONIE_TLV_CODE_PRODUCT_NAME 0x21 +#define ONIE_TLV_CODE_PART_NUMBER 0x22 +#define ONIE_TLV_CODE_SERIAL_NUMBER 0x23 +#define ONIE_TLV_CODE_MAC_BASE 0x24 +#define ONIE_TLV_CODE_MANUF_DATE 0x25 +#define ONIE_TLV_CODE_DEVICE_VERSION 0x26 +#define ONIE_TLV_CODE_LABEL_REVISION 0x27 +#define ONIE_TLV_CODE_PLATFORM_NAME 0x28 +#define ONIE_TLV_CODE_ONIE_VERSION 0x29 +#define ONIE_TLV_CODE_MAC_SIZE 0x2A +#define ONIE_TLV_CODE_MANUF_NAME 0x2B +#define ONIE_TLV_CODE_MANUF_COUNTRY 0x2C +#define ONIE_TLV_CODE_VENDOR_NAME 0x2D +#define ONIE_TLV_CODE_DIAG_VERSION 0x2E +#define ONIE_TLV_CODE_SERVICE_TAG 0x2F +#define ONIE_TLV_CODE_UNDEFINED 0xFC +#define ONIE_TLV_CODE_VENDOR_EXT 0xFD +#define ONIE_TLV_CODE_CRC_32 0xFE +#define ONIE_TLV_TYPE_INVALID 0xFF + +#define ONIE_TLV_INFO_ID_STRING "TlvInfo" +#define ONIE_TLV_INFO_VERSION 0x01 +#define ONIE_TLV_INFO_MAX_LEN 2048 +#define ONIE_TLV_TOTAL_LEN_MAX (ONIE_TLV_INFO_MAX_LEN - sizeof(onie_tlvinfo_header_t)) + +#define MAC_LEN 6 +#define DATE_LEN 19 +#define VER_LEN 1 +#define COUNTRY_CODE_LEN 2 + + +/** + * ONIE TLV EEPROM Header + */ +typedef struct __attribute__((__packed__)) onie_tlvinfo_header_s +{ + char signature[8]; /* 0x00 - 0x07 EEPROM Tag "TlvInfo" */ + u8 version; /* 0x08 Structure version */ + u16 totallen; /* 0x09 - 0x0A Length of all data which follows */ +} onie_tlvinfo_header_t; + +/** + * ONIE TLV Entry + */ +typedef struct __attribute__((__packed__)) onie_tlvinfo_tlv_s +{ + u8 type; + u8 length; + u8 value[0]; +} onie_tlvinfo_tlv_t; + +struct at24_data { + /* + * Lock protects against activities from other Linux tasks, + * but not from changes by other I2C masters. + */ + struct mutex lock; + struct i2c_client *client; + char part_number[FIELD_LEN_MAX + 1]; + char serial_number[FIELD_LEN_MAX + 1]; +#if VERBOSE + char product_name[FIELD_LEN_MAX + 1]; + char base_mac[MAC_LEN + 1]; + char mfg_date[DATE_LEN + 1]; + char device_version[VER_LEN + 1]; + char label_version[FIELD_LEN_MAX + 1]; + char platform_name[FIELD_LEN_MAX + 1]; + char onie_version[FIELD_LEN_MAX + 1]; + u16 mac_size; + char mfg_name[FIELD_LEN_MAX + 1]; + char mfg_country[COUNTRY_CODE_LEN + 1]; + char vendor_name[FIELD_LEN_MAX + 1]; + char diag_version[FIELD_LEN_MAX + 1]; + char service_tag[FIELD_LEN_MAX + 1]; + char vendor_ext[FIELD_LEN_MAX + 1]; + u32 crc; +#endif +}; + +inline char * onie_tag_to_field_name(u8 tag) +{ + switch (tag) + { + case ONIE_TLV_CODE_PART_NUMBER: + return "part_number"; + case ONIE_TLV_CODE_SERIAL_NUMBER: + return "serial_number"; +#if VERBOSE + case ONIE_TLV_CODE_PRODUCT_NAME: + return "product_name"; + case ONIE_TLV_CODE_MAC_BASE: + return "base_mac"; + case ONIE_TLV_CODE_MANUF_DATE: + return "mfg_date"; + case ONIE_TLV_CODE_DEVICE_VERSION: + return "device_version"; + case ONIE_TLV_CODE_LABEL_REVISION: + return "label_version"; + case ONIE_TLV_CODE_PLATFORM_NAME: + return "platform_name"; + case ONIE_TLV_CODE_ONIE_VERSION: + return "onie_version"; + case ONIE_TLV_CODE_MAC_SIZE: + return "mac_size"; + case ONIE_TLV_CODE_MANUF_NAME: + return "mfg_name"; + case ONIE_TLV_CODE_MANUF_COUNTRY: + return "mfg_country"; + case ONIE_TLV_CODE_VENDOR_NAME: + return "vendor_name"; + case ONIE_TLV_CODE_DIAG_VERSION: + return "diag_version"; + case ONIE_TLV_CODE_SERVICE_TAG: + return "service_tag"; + case ONIE_TLV_CODE_VENDOR_EXT: + return "vendor_ext"; + case ONIE_TLV_CODE_CRC_32: + return "crc"; +#endif + default: + return "unknown"; + } +} + +static u32 TlvBigEndianToInteger(const u8 *buff, u8 len) +{ + u32 value = 0; + for(int i = 0; i < len; ++i) + { + value = value << 8; + value |= (buff[i] & 0xFF); + } + return value; +} + +int tlv_decode(struct i2c_client *client, const u8 *buffer, const u32 length) +{ + struct device *dev = &client->dev; + struct at24_data *at24 = i2c_get_clientdata(client); + u32 offset = 0, L = 0; + if (!buffer || length <= 0) + { + return -1; + } + + for (; offset < length;) + { + u8 T = *(u8 *)(buffer + offset); + offset += 1; + + if (T == ONIE_TLV_TYPE_INVALID) + { + continue; + } + + L = TlvBigEndianToInteger(buffer + offset, 1); + offset += 1; + + char sbuf[FIELD_LEN_MAX + 1] ={0}; + if(L > FIELD_LEN_MAX) { + L = FIELD_LEN_MAX; + } + + memcpy(sbuf, buffer + offset, L); + if(debug) { + switch(T) + { + case ONIE_TLV_CODE_MAC_BASE: + dev_info(dev, "Tag 0x%x [%s] [%x:%x]: %pM", T, onie_tag_to_field_name(T), offset, L, sbuf); + break; + case ONIE_TLV_CODE_MAC_SIZE: + dev_info(dev, "Tag 0x%x [%s] [%x:%x]: 0x%02x", T, onie_tag_to_field_name(T), offset, L, *(u32 *)sbuf); + break; + case ONIE_TLV_CODE_CRC_32: + dev_info(dev, "Tag 0x%x [%s] [%x:%x]: 0x%08x", T, onie_tag_to_field_name(T), offset, L, *(u32 *)sbuf); + break; + default: + dev_info(dev, "Tag 0x%x [%s] [%x:%x]: %s", T, onie_tag_to_field_name(T), offset, L, sbuf); + break; + } + } + + int len = strlen(sbuf); + if( len > FIELD_LEN_MAX) { + len = FIELD_LEN_MAX; + } + + switch(T) + { + case ONIE_TLV_CODE_PART_NUMBER: + strncpy(at24->part_number, sbuf, len); + break; + case ONIE_TLV_CODE_SERIAL_NUMBER: + strncpy(at24->serial_number, sbuf, len); + break; +#if VERBOSE + case ONIE_TLV_CODE_PRODUCT_NAME: + strncpy(at24->product_name, sbuf, len); + break; + case ONIE_TLV_CODE_MAC_BASE: + if( len > MAC_LEN) { + len = MAC_LEN; + } + strncpy(at24->base_mac, sbuf, len); + break; + case ONIE_TLV_CODE_MANUF_DATE: + if( len > DATE_LEN) { + len = DATE_LEN; + } + strncpy(at24->mfg_date, sbuf, len); + break; + case ONIE_TLV_CODE_DEVICE_VERSION: + if( len > VER_LEN) { + len = VER_LEN; + } + strncpy(at24->device_version, sbuf, len); + break; + case ONIE_TLV_CODE_LABEL_REVISION: + strncpy(at24->label_version, sbuf, len); + break; + case ONIE_TLV_CODE_PLATFORM_NAME: + strncpy(at24->platform_name, sbuf, len); + break; + case ONIE_TLV_CODE_ONIE_VERSION: + strncpy(at24->onie_version, sbuf, len); + break; + case ONIE_TLV_CODE_MAC_SIZE: + at24->mac_size = *(u16*)sbuf; + break; + case ONIE_TLV_CODE_MANUF_NAME: + strncpy(at24->mfg_name, sbuf, len); + break; + case ONIE_TLV_CODE_MANUF_COUNTRY: + if( len > COUNTRY_CODE_LEN) { + len = COUNTRY_CODE_LEN; + } + strncpy(at24->mfg_country, sbuf, len); + break; + case ONIE_TLV_CODE_VENDOR_NAME: + strncpy(at24->vendor_name, sbuf, len); + break; + case ONIE_TLV_CODE_DIAG_VERSION: + strncpy(at24->diag_version, sbuf, len); + break; + case ONIE_TLV_CODE_SERVICE_TAG: + strncpy(at24->service_tag, sbuf, len); + break; + case ONIE_TLV_CODE_VENDOR_EXT: + strncpy(at24->vendor_ext, sbuf, len); + break; + case ONIE_TLV_CODE_CRC_32: + at24->crc = *(u32*)sbuf; + break; +#endif + default: + break; + } + + // Cannot parse if length field of TLV entry exceeds the total length of the buffer + if (offset + L > length) + { + dev_err(dev, "Tag 0x%x with length %x exceeds total buffer length %x", T, L, length); + return false; + } + if (L <= 0) + { + continue; + } + + offset += L; +#if VERBOSE + // CRC32 should always be the last TLV entry + if (T == ONIE_TLV_CODE_CRC_32) + { + if(debug) { + dev_info(dev,"Found CRC TLV entry at offset %u, done decoding", offset); + } + break; + } +#endif + } + + return true; +} + +static inline __u16 bswap_16(__u16 x) { + return (__u16)((x >> 8) | (x << 8)); +} + +int decode_onie_eeprom(struct i2c_client *client, u8 * raw_data) +{ + struct device *dev = &client->dev; + onie_tlvinfo_header_t *eeprom_hdr = (onie_tlvinfo_header_t *)raw_data; + onie_tlvinfo_tlv_t *eeprom_tlv = (onie_tlvinfo_tlv_t *)&raw_data[sizeof(onie_tlvinfo_header_t)]; + + int len = bswap_16(eeprom_hdr->totallen); + if(debug) { + dev_info(dev, "len:%d\n", len); + } + if (len <= ONIE_TLV_TOTAL_LEN_MAX) + { + if (!tlv_decode(client, (u8 *)eeprom_tlv, len)) + { + dev_err(dev, "Failed to decode onie eeprom"); + return -1; + } + return 0; + } + + dev_err(dev, "Onie eeprom header is not valid"); + return 0; +} + +int decode_eeprom(struct i2c_client *client) +{ + u8 * raw_data = kzalloc(read_eeprom_max_len, GFP_KERNEL); + if (!raw_data) { + return -ENOMEM; + } + + // i2c_smbus initiate eeprom chip's internel "CURRENT ADDRESS" for reading + i2c_smbus_write_byte(client,0); + msleep(1); + + for (int i = 0; i < read_eeprom_max_len; i++) { + raw_data[i]= i2c_smbus_read_byte(client); + } + + if(debug) { + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 16, 1, raw_data, read_eeprom_max_len, true); + } + + if(!strncmp(raw_data,"TlvInfo", 7)) { + decode_onie_eeprom(client, raw_data); + } + + kfree(raw_data); + return 0; +} + +static ssize_t trigger_read_eeprom(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + if(!strncmp(buf,"1", count-1)) { + struct at24_data *data = dev_get_drvdata(dev); + decode_eeprom(data->client); + } + return count; +} + +static ssize_t show_part_number(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->part_number); +} + +static ssize_t show_serial_number(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->serial_number); +} + +#if VERBOSE +static ssize_t show_product_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->product_name); +} + +static ssize_t show_base_mac(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%pM\n", data->base_mac); +} + +static ssize_t show_mfg_date(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->mfg_date); +} + +static ssize_t show_device_version(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->device_version); +} + +static ssize_t show_label_version(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->label_version); +} + +static ssize_t show_platform_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->platform_name); +} + +static ssize_t show_onie_version(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->onie_version); +} + +static ssize_t show_mac_size(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%02x\n", data->mac_size); +} + +static ssize_t show_mfg_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->mfg_name); +} + +static ssize_t show_mfg_country(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->mfg_country); +} + +static ssize_t show_vendor_name(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->vendor_name); +} + +static ssize_t show_diag_version(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->diag_version); +} + +static ssize_t show_service_tag(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->service_tag); +} + +static ssize_t show_vendor_ext(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "%s\n", data->vendor_ext); +} + +static ssize_t show_crc(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct at24_data *data = dev_get_drvdata(dev); + return sprintf(buf, "0x%08x\n", data->crc); +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(product_name, S_IRUGO, show_product_name, NULL, 0); +static SENSOR_DEVICE_ATTR(base_mac, S_IRUGO, show_base_mac, NULL, 0); +static SENSOR_DEVICE_ATTR(mfg_date, S_IRUGO, show_mfg_date, NULL, 0); +static SENSOR_DEVICE_ATTR(device_version, S_IRUGO, show_device_version, NULL, 0); +static SENSOR_DEVICE_ATTR(label_version, S_IRUGO, show_label_version, NULL, 0); +static SENSOR_DEVICE_ATTR(platform_name, S_IRUGO, show_platform_name, NULL, 0); +static SENSOR_DEVICE_ATTR(onie_version, S_IRUGO, show_onie_version, NULL, 0); +static SENSOR_DEVICE_ATTR(mac_size, S_IRUGO, show_mac_size, NULL, 0); +static SENSOR_DEVICE_ATTR(mfg_name, S_IRUGO, show_mfg_name, NULL, 0); +static SENSOR_DEVICE_ATTR(mfg_country, S_IRUGO, show_mfg_country, NULL, 0); +static SENSOR_DEVICE_ATTR(vendor_name, S_IRUGO, show_vendor_name, NULL, 0); +static SENSOR_DEVICE_ATTR(diag_version, S_IRUGO, show_diag_version, NULL, 0); +static SENSOR_DEVICE_ATTR(service_tag, S_IRUGO, show_service_tag, NULL, 0); +static SENSOR_DEVICE_ATTR(vendor_ext, S_IRUGO, show_vendor_ext, NULL, 0); +static SENSOR_DEVICE_ATTR(crc, S_IRUGO, show_crc, NULL, 0); +#endif + +static SENSOR_DEVICE_ATTR(read_eeprom, S_IWUSR, NULL, trigger_read_eeprom, 0); +static SENSOR_DEVICE_ATTR(part_number, S_IRUGO, show_part_number, NULL, 0); +static SENSOR_DEVICE_ATTR(serial_number, S_IRUGO, show_serial_number, NULL, 0); + +static struct attribute *eeprom_attributes[] = { + &sensor_dev_attr_read_eeprom.dev_attr.attr, + &sensor_dev_attr_part_number.dev_attr.attr, + &sensor_dev_attr_serial_number.dev_attr.attr, +#if VERBOSE + &sensor_dev_attr_product_name.dev_attr.attr, + &sensor_dev_attr_base_mac.dev_attr.attr, + &sensor_dev_attr_mfg_date.dev_attr.attr, + &sensor_dev_attr_device_version.dev_attr.attr, + &sensor_dev_attr_label_version.dev_attr.attr, + &sensor_dev_attr_platform_name.dev_attr.attr, + &sensor_dev_attr_onie_version.dev_attr.attr, + &sensor_dev_attr_mac_size.dev_attr.attr, + &sensor_dev_attr_mfg_name.dev_attr.attr, + &sensor_dev_attr_mfg_country.dev_attr.attr, + &sensor_dev_attr_vendor_name.dev_attr.attr, + &sensor_dev_attr_diag_version.dev_attr.attr, + &sensor_dev_attr_service_tag.dev_attr.attr, + &sensor_dev_attr_vendor_ext.dev_attr.attr, + &sensor_dev_attr_crc.dev_attr.attr, +#endif + NULL +}; + +static const struct attribute_group eeprom_group = { + .attrs = eeprom_attributes, +}; + +static int eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct at24_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)) + { + dev_info(&client->dev, "i2c_check_functionality failed!\n"); + status = -EIO; + return status; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + { + status = -ENOMEM; + return status; + } + + mutex_init(&data->lock); + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "eeprom chip found\n"); + /* Create sysfs entries */ + status = sysfs_create_group(&client->dev.kobj, &eeprom_group); + if (status) { + dev_err(dev, "Cannot create sysfs\n"); + kfree(data); + return status; + } + data->client = client; + decode_eeprom(client); + return status; +} + +static void eeprom_remove(struct i2c_client *client) +{ + struct at24_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &eeprom_group); + kfree(data); + return; +} + +static const struct i2c_device_id eeprom_id[] = { + { EEPROM_NAME, 0 }, + { EEPROM_NAME, 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, eeprom_id); + +/* Address scanned */ +static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; + +/* This is the driver that will be inserted */ +static struct i2c_driver eeprom_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = EEPROM_NAME, + }, + .probe = eeprom_probe, + .remove = eeprom_remove, + .id_table = eeprom_id, + .address_list = normal_i2c, +}; + +static int __init eeprom_init(void) +{ + return i2c_add_driver(&eeprom_driver); +} + +static void __exit eeprom_exit(void) +{ + i2c_del_driver(&eeprom_driver); +} + +MODULE_DESCRIPTION("NOKIA EEPROM TLV Sysfs driver"); +MODULE_AUTHOR("Nokia"); +MODULE_LICENSE("GPL"); + +module_init(eeprom_init); +module_exit(eeprom_exit); diff --git a/ixr7220h5-64d/modules/fpga.c b/ixr7220h5-64d/modules/fpga.c new file mode 100644 index 0000000..e42ef00 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga.c @@ -0,0 +1,196 @@ +// FPGA driver +// +// Copyright (C) 2024 Nokia Corporation. +// Copyright (C) 2024 Delta Networks, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// 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. +// see + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fpga.h" +#include "fpga_attr.h" +#include "fpga_gpio.h" +#include "fpga_i2c.h" +#include "fpga_reg.h" + +#define FPGA_PCA9548 +#define FPGA_GPIO +#define FPGA_ATTR + +#if 0 +struct file_operations fpga_fileops = { + .owner = THIS_MODULE, + .read = fpga_read, + .write = fpga_write, + .mmap = fpga_mmap, + /*.ioctl = fpga_ioctl,*/ + // .open = fpga_open, + .release = fpga_close, +}; +#endif + +static int sys_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct fpga_dev *fpga; + int error = -1; + int ret; + + dev_info(&dev->dev, "probe"); + + ret = pci_request_regions(dev, "sys-fpga"); + if (ret) + { + printk(KERN_ERR "Failed to request PCI region.\n"); + return ret; + } + + // enabling the device + ret = pci_enable_device(dev); + if (ret) + { + printk(KERN_ERR "Failed to enable PCI device.\n"); + return ret; + } + + if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) + { + printk(KERN_ERR "Incorrect BAR configuration.\n"); + ret = -ENODEV; + goto fail_map_bars; + } + + fpga = kzalloc(sizeof(struct fpga_dev), GFP_KERNEL); + if (!fpga) + { + dev_warn(&dev->dev, "Couldn't allocate memory for fpga!\n"); + return -ENOMEM; + } + fpga->dev = dev; + fpga->buffer = kmalloc(BUF_SIZE * sizeof(char), GFP_KERNEL); + if (!fpga->buffer) + { + dev_warn(&dev->dev, "Couldn't allocate memory for buffer!\n"); + return -ENOMEM; + } +#ifdef FPGA_GPIO + /* init gpiodev */ + ret = gpiodev_init(dev, fpga); + if (ret) + { + dev_err(&dev->dev, "Couldn't create gpiodev!\n"); + return ret; + } +#endif + + ret = i2c_adapter_init(dev, fpga); + if (ret) + { + dev_err(&dev->dev, "Couldn't create i2c_adapter!\n"); + goto out_release_region; + } +#ifdef FPGA_ATTR + /* init fpga attr */ + ret = fpga_attr_init(dev, fpga); + if (ret) + { + dev_err(&dev->dev, "Couldn't init fpga attr!\n"); + return ret; + } +#endif + return 0; + +fail_map_bars: + pci_disable_device(dev); +out_release_region: + release_region(fpga->pci_base, fpga->pci_size); + +out_kfree: + kfree((fpga)); + return error; +} + +static void sys_fpga_remove(struct pci_dev *dev) +{ + /* release fpga-i2c */ + int i = 0; + struct fpga_dev *fpga = pci_get_drvdata(dev); + printk(KERN_INFO "fpga = 0x%x\n", fpga); + + for (i = 0; i < num_i2c_adapter; i++) + { + i2c_del_adapter(&(fpga->i2c + i)->adapter); + printk(KERN_INFO "remove - FPGA-I2C-%d\n", i); + } +#ifdef FPGA_GPIO + /* remove gpio */ + gpiodev_exit(dev); +#endif + /* release pci */ + pci_disable_device(dev); + pci_release_regions(dev); + /*release attribute */ +#ifdef FPGA_ATTR + fpga_attr_exit(); +#endif + kfree(fpga); + printk(KERN_INFO "Goodbye\n"); +} + +enum chiptype +{ + LATTICE +}; + +static const struct of_device_id sys_fpga_of_match[] = { + {.compatible = "sys-fpga,fpga-i2c"}, + {/* sentinel */}}; + +static const struct pci_device_id sys_fpga_ids[] = { + {PCI_DEVICE(0x1204, 0x9c1d)}, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, sys_fpga_ids); + +static struct pci_driver sys_fpga_driver = { + .name = "sys-fpga", + .id_table = sys_fpga_ids, + .probe = sys_fpga_probe, + .remove = sys_fpga_remove, +}; + +static int sys_fpga_init(void) +{ + printk(KERN_INFO "sys-fpga-init\n"); + return pci_register_driver(&sys_fpga_driver); +} + +static void sys_fpga_exit(void) +{ + pci_unregister_driver(&sys_fpga_driver); + printk(KERN_INFO "sys-fpga-exit\n"); +} + +MODULE_AUTHOR("amos.lin@deltaww.com"); +MODULE_DESCRIPTION("Sys-FPGA Driver"); +MODULE_LICENSE("GPL"); + +module_init(sys_fpga_init); +module_exit(sys_fpga_exit); diff --git a/ixr7220h5-64d/modules/fpga.h b/ixr7220h5-64d/modules/fpga.h new file mode 100644 index 0000000..8d75a29 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga.h @@ -0,0 +1,93 @@ +#ifndef __FGPA_H__ +#define __FGPA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FPGA_I2C_BUSNUM 5 +#define FPGA_I2C_MUX_DIS 0 +#define FPGA_I2C_MUX_EN 1 + +#define FPGA_JTAG_MUX_REG 0x100 +#define FPGA_JTAG_CTRL0_REG 0x104 +#define FPGA_JTAG_CTRL1_REG 0x108 +#define FPGA_JTAG_CTRL2_REG 0x10C + +typedef struct fpga_i2c +{ + char name[50]; + int bus; + int offset; + int mux_en; + int mux_addr; + int num_ch; +} fpga_i2c_s; + +typedef struct fpga_gpio +{ + int num; + char name[50]; + int reg; + int bit; +} fpga_gpio_s; + +struct i2c_bus_dev +{ + struct i2c_adapter adapter; + int offset; + int busnum; + int mux_ch; + int mux_en; + void *__iomem bar; +}; + +struct fpga_gpio_chip +{ + struct gpio_chip gpio_chip; + struct mutex lock; + void *__iomem bar; + u32 registers; + /* + * Since the registers are chained, every byte sent will make + * the previous byte shift to the next register in the + * chain. Thus, the first byte sent will end up in the last + * register at the end of the transfer. So, to have a logical + * numbering, store the bytes in reverse order. + */ + u8 buffer[0]; +}; + +struct fpga_dev +{ + char name[64]; + struct pci_dev *dev; + struct i2c_bus_dev *i2c; + struct fpga_gpio_chip *gpio; + int pci_base; + int pci_size; + struct semaphore sem; + char *buffer; +}; + +static const size_t BUF_SIZE = PAGE_SIZE; +static struct pci_driver sys_fpga_driver; + +#endif /* __FGPA_H__ */ \ No newline at end of file diff --git a/ixr7220h5-64d/modules/fpga_attr.c b/ixr7220h5-64d/modules/fpga_attr.c new file mode 100644 index 0000000..3911b30 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_attr.c @@ -0,0 +1,159 @@ +// FPGA driver +// +// Copyright (C) 2024 Nokia Corporation. +// Copyright (C) 2024 Delta Networks, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// 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. +// see + +#include +#include +#include +#include +#include "fpga.h" +#include "fpga_attr.h" +#include "fpga_reg.h" + +static struct kobject *sys_fpga; +struct attribute **attrs; +struct attribute_group attr_grp; +void *__iomem bar; + +struct mutex fpga_attr_lock; + +static ssize_t sys_fpga_reg_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + fpga_sysfs_attr_st *fpga_container = TO_FPGA_SYSFS_ATTR(attr); + sys_fpga_reg_st *fpga_reg = fpga_container->fpga_reg; + int offset = fpga_reg->offset; + int bit_offset = fpga_reg->bit_offset; + int n_bits = fpga_reg->n_bits; + unsigned int val, val_mask, reg_val; + + if (!fpga_reg->show) { + return -EOPNOTSUPP; + } + + if (fpga_reg->show != I2C_DEV_ATTR_SHOW_DEFAULT) { + return fpga_reg->show(dev, attr, buf); + } + + mutex_lock(&fpga_attr_lock); + + val_mask = ((unsigned long long)1 << (n_bits)) - 1; + reg_val = ioread32(bar + offset); + val = (reg_val >> bit_offset) & val_mask; + + mutex_unlock(&fpga_attr_lock); + + return scnprintf(buf, PAGE_SIZE, "%#x\n", val); +} + +static ssize_t sys_fpga_reg_store(struct device *dev, + struct device_attribute *attr, char *buf, + size_t count) +{ + int err; + fpga_sysfs_attr_st *fpga_container = TO_FPGA_SYSFS_ATTR(attr); + sys_fpga_reg_st *fpga_reg = fpga_container->fpga_reg; + int offset = fpga_reg->offset; + int bit_offset = fpga_reg->bit_offset; + int n_bits = fpga_reg->n_bits; + unsigned int val; + int req_val; + unsigned int req_val_mask; + unsigned int max = (((unsigned long long)1<store) { + return -EOPNOTSUPP; + } + + if (fpga_reg->store != I2C_DEV_ATTR_STORE_DEFAULT) { + return fpga_reg->store(dev, attr, buf, count); + } + + if (sscanf(buf, "%i", &req_val) <= 0) { + return -EINVAL; + } + if (req_val > max) + { + printk(KERN_ERR "maximum data is = 0x%x, but input data is 0x%x\n", max, req_val); + return -EINVAL; + } + + mutex_lock(&fpga_attr_lock); + + req_val_mask = max; + req_val &= req_val_mask; + val = ioread32(bar + offset); + + /* mask out all bits for the value requested */ + val &= ~(req_val_mask << bit_offset); + val |= req_val << bit_offset; + iowrite32(val, bar + offset); + + mutex_unlock(&fpga_attr_lock); + //return sprintf(buf, "%d\n", val); + return count; + +} + +int fpga_attr_create(void) +{ + fpga_sysfs_attr_st *fpga_container; + int i; + int len = sizeof(sys_fpga_reg_table)/sizeof(sys_fpga_reg_st); + + fpga_container = kzalloc(sizeof(fpga_sysfs_attr_st) * len ,GFP_KERNEL); + + attrs = kzalloc(sizeof(struct attribute *) * len+1 ,GFP_KERNEL); + + for(i = 0; i < len; i++, fpga_container++) + { + fpga_container->dev_attr.attr.name = sys_fpga_reg_table[i].name; + fpga_container->dev_attr.attr.mode = 0660; + fpga_container->dev_attr.show = (void *)sys_fpga_reg_show; + fpga_container->dev_attr.store = (void *)sys_fpga_reg_store; + attrs[i] = &fpga_container->dev_attr.attr; + fpga_container->fpga_reg = &sys_fpga_reg_table[i]; + } + + attr_grp.attrs = attrs; + + return 0; +} + +int fpga_attr_init(struct pci_dev *dev, struct fpga_dev *fpga) +{ + int error; + bar = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + sys_fpga = kobject_create_and_add("sys_fpga", kernel_kobj); + if (!sys_fpga) + return -ENOMEM; + fpga_attr_create(); + + mutex_init(&fpga_attr_lock); + error = sysfs_create_group(sys_fpga,&attr_grp); + if (error) + { + kobject_put(sys_fpga); + pr_info("failed to create the sys_fpga_reg file " + "in /sys/kernel/sys_fpga\n"); + } + return 0; +} +int fpga_attr_exit(void) +{ + kobject_put(sys_fpga); + return 0; +} + diff --git a/ixr7220h5-64d/modules/fpga_attr.h b/ixr7220h5-64d/modules/fpga_attr.h new file mode 100644 index 0000000..2f54801 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_attr.h @@ -0,0 +1,35 @@ +#ifndef __FGPA_ATTR_H__ +#define __FGPA_ATTR_H__ + +typedef ssize_t (*i2c_dev_attr_show_fn)(struct device *dev, + struct device_attribute *attr, + char *buf); +typedef ssize_t (*i2c_dev_attr_store_fn)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +#define I2C_DEV_ATTR_SHOW_DEFAULT (i2c_dev_attr_show_fn)(1) +#define I2C_DEV_ATTR_STORE_DEFAULT (i2c_dev_attr_store_fn)(1) + +typedef struct sys_fpga_reg_st_ { + const char *name; + const char *help; + i2c_dev_attr_show_fn show; + i2c_dev_attr_store_fn store; + int offset; + int bit_offset; + int n_bits; +} sys_fpga_reg_st; + +typedef struct fpga_sysfs_attr_st_{ + struct device_attribute dev_attr; + const sys_fpga_reg_st *fpga_reg; +} fpga_sysfs_attr_st; + +#define TO_FPGA_SYSFS_ATTR(_attr) \ + container_of(_attr, fpga_sysfs_attr_st, dev_attr) + +int fpga_attr_init(struct pci_dev *dev, struct fpga_dev *fpga); +int fpga_attr_exit(void); + +#endif /* __FGPA_ATTR_H__ */ \ No newline at end of file diff --git a/ixr7220h5-64d/modules/fpga_gpio.c b/ixr7220h5-64d/modules/fpga_gpio.c new file mode 100644 index 0000000..9230b2b --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_gpio.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include +#include "fpga.h" +#include "fpga_gpio.h" + + +fpga_gpio_s fpga_gpio_info[] = { + {0, "ENABLE JTAG_0", FPGA_JTAG_MUX_REG, 8}, + {1, "ENABLE JTAG_1", FPGA_JTAG_MUX_REG, 9}, + {2, "ENABLE JTAG_2", FPGA_JTAG_MUX_REG, 10}, + {3, "JTAG_0 FPGA_CPU_JTAG_TDI", FPGA_JTAG_CTRL0_REG, 3}, + {4, "JTAG_0 FPGA_CPU_JTAG_TDO", FPGA_JTAG_CTRL0_REG, 2}, + {5, "JTAG_0 FPGA_CPU_JTAG_TMS", FPGA_JTAG_CTRL0_REG, 1}, + {6, "JTAG_0 FPGA_CPU_JTAG_TCK", FPGA_JTAG_CTRL0_REG, 0}, + {7, "JTAG_1 FPGA_MB_JTAG_TDI", FPGA_JTAG_CTRL1_REG, 3}, + {8, "JTAG_1 FPGA_MB_JTAG_TDO", FPGA_JTAG_CTRL1_REG, 2}, + {9, "JTAG_1 FPGA_MB_JTAG_TMS", FPGA_JTAG_CTRL1_REG, 1}, + {10, "JTAG_1 FPGA_MB_JTAG_TCK", FPGA_JTAG_CTRL1_REG, 0}, + {11, "JTAG_2 FPGA_MB_JTAG_TRST_N", FPGA_JTAG_CTRL2_REG, 4}, + {12, "JTAG_2 FPGA_MB_JTAG_TDI", FPGA_JTAG_CTRL2_REG, 3}, + {13, "JTAG_2 FPGA_MB_JTAG_TDO", FPGA_JTAG_CTRL2_REG, 2}, + {14, "JTAG_2 FPGA_MB_JTAG_TMS", FPGA_JTAG_CTRL2_REG, 1}, + {15, "JTAG_2 FPGA_MB_JTAG_TCK", FPGA_JTAG_CTRL2_REG, 0}, +}; + +static int fpga_gpio_get(struct gpio_chip *gc, unsigned gpio) +{ + struct fpga_gpio_chip *chip = gpiochip_get_data(gc); + int rdata; + int ret; + int reg = fpga_gpio_info[gpio].reg; + int bit = fpga_gpio_info[gpio].bit; + + mutex_lock(&chip->lock); + //ret = (chip->buffer[bank] >> pin) & 0x1; + rdata = ioread32(chip->bar + reg); + ret = (rdata >> bit) & 0x1; + //printk(KERN_INFO "gpio = 0x%x chip->bar = 0x%x value = 0x%x", gpio, chip->bar, rdata); + + mutex_unlock(&chip->lock); + + return ret; +} + +static void fpga_gpio_set(struct gpio_chip *gc, + unsigned gpio, int val) +{ + struct fpga_gpio_chip *chip = gpiochip_get_data(gc); + int rdata, wdata; + int reg = fpga_gpio_info[gpio].reg; + int bit = fpga_gpio_info[gpio].bit; + + mutex_lock(&chip->lock); + + rdata = ioread32(chip->bar + reg); + + if (val) + wdata = rdata | (1 << bit); + else + wdata = rdata & ~(1 << bit); + + iowrite32(wdata, chip->bar + reg); + + mutex_unlock(&chip->lock); +} + +int gpiodev_init(struct pci_dev *dev, struct fpga_dev *fpga) +{ + char name[20] = "fpga-gpio chip"; + int err; + fpga->gpio = kzalloc(sizeof(struct fpga_gpio_chip), GFP_KERNEL); + if (!fpga->gpio) + return -ENOMEM; + + fpga->gpio->bar = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + fpga->gpio->gpio_chip.base = -1; + fpga->gpio->gpio_chip.label = name; + fpga->gpio->gpio_chip.owner = THIS_MODULE; + fpga->gpio->gpio_chip.ngpio = 32; + fpga->gpio->gpio_chip.parent = &dev->dev; //(struct devices) fpga + + fpga->gpio->gpio_chip.get = fpga_gpio_get; + fpga->gpio->gpio_chip.set = fpga_gpio_set; + err = gpiochip_add_data(&fpga->gpio->gpio_chip, fpga->gpio); + if (err) + { + printk(KERN_INFO "GPIO registering failed "); + return err; + } + return 0; +} + +void gpiodev_exit(struct pci_dev *dev) +{ + struct fpga_dev *fpga = pci_get_drvdata(dev); + gpiochip_remove(&fpga->gpio->gpio_chip); +} diff --git a/ixr7220h5-64d/modules/fpga_gpio.h b/ixr7220h5-64d/modules/fpga_gpio.h new file mode 100644 index 0000000..6891e81 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_gpio.h @@ -0,0 +1,7 @@ +#ifndef __FGPA_GPIO_H__ +#define __FGPA_GPIO_H__ + +int gpiodev_init(struct pci_dev *dev, struct fpga_dev *fpga); +void gpiodev_exit(struct pci_dev *dev); + +#endif /* __FGPA_GPIO_H__ */ \ No newline at end of file diff --git a/ixr7220h5-64d/modules/fpga_i2c.c b/ixr7220h5-64d/modules/fpga_i2c.c new file mode 100644 index 0000000..bcaa559 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_i2c.c @@ -0,0 +1,534 @@ +#include +#include +#include +#include +#include "fpga.h" +#include "fpga_gpio.h" +#include "fpga_i2c.h" + +int num_i2c_adapter; + +fpga_i2c_s fpga_i2c_info[] = { + {"FPGA SMBUS - PORT_0" , 0, DELTA_I2C_BASE(2), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_1" , 1, DELTA_I2C_BASE(3), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_2" , 2, DELTA_I2C_BASE(4), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_3" , 3, DELTA_I2C_BASE(5), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_4" , 4, DELTA_I2C_BASE(6), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_5" , 5, DELTA_I2C_BASE(7), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_6" , 6, DELTA_I2C_BASE(8), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_7" , 7, DELTA_I2C_BASE(9), FPGA_I2C_MUX_DIS, 0x00, 0}, + {"FPGA SMBUS - PORT_8" , 8, DELTA_I2C_BASE(10), FPGA_I2C_MUX_DIS, 0x00, 0}, +// {"FPGA SMBUS - PORT_9" , 9, DELTA_I2C_BASE(9), FPGA_I2C_MUX_DIS, 0x00, 0}, +// {"FPGA SMBUS - 1588 DPLL" , 10, DELTA_DPLL_I2C_BASE, FPGA_I2C_MUX_DIS, 0x00, 0}, +// {"FPGA SMBUS - 1588 FPGA" , 11, DELTA_FPGA_I2C_BASE, FPGA_I2C_MUX_DIS, 0x00, 0}, +}; + +static int delta_wait_i2c_complete(struct i2c_bus_dev *i2c); +static void delta_fpga_i2c_data_reg_set(struct i2c_bus_dev *i2c, int addr, int data); +static void delta_fpga_i2c_addr_reg_set(struct i2c_bus_dev *i2c, int data); +static void delta_fpga_i2c_conf_reg_set(struct i2c_bus_dev *i2c, int data); +static void delta_fpga_i2c_ctrl_set(struct i2c_bus_dev *i2c, int data); +static int delta_fpga_i2c_ctrl_get(struct i2c_bus_dev *i2c); + +static int dni_fpga_i2c_read(struct i2c_bus_dev *i2c, int addr, int raddr, int rsize, uint8_t *readout, int dsize); +static int dni_fpga_i2c_write(struct i2c_bus_dev *i2c, int addr, int raddr, int rsize, uint8_t *data, int dsize); +static int io_read(struct i2c_bus_dev *i2c, int offset); +static void io_write(struct i2c_bus_dev *i2c, int offset, int data); + +struct mutex fpga_i2c_lock; + +static s32 dni_fpga_i2c_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, int size, + union i2c_smbus_data *data) +{ + struct i2c_bus_dev *i2c = adap->algo_data; + int len; + uint8_t i2c_data; + int rv = 0; + + mutex_lock(&fpga_i2c_lock); + // printk(KERN_INFO "size=%d, read_write=%d addr=0x%x command=0x%x fpga_bus=%d \n",size,read_write,addr,command,i2c->busnum); + switch (size) + { + + case I2C_SMBUS_QUICK: + // printk(KERN_INFO "I2C_SMBUS_QUICK"); + rv = dni_fpga_i2c_write(i2c, addr, command, 0, &i2c_data, 0); + goto done; + break; + case I2C_SMBUS_BYTE: + // printk(KERN_INFO "I2C_SMBUS_BYTE"); + if (read_write == I2C_SMBUS_WRITE) + { + rv = dni_fpga_i2c_write(i2c, addr, command, 1, &i2c_data, 0); + goto done; + } + else + { + rv = dni_fpga_i2c_read(i2c, addr, command, 1, &data->byte, 1); + goto done; + } + + break; + case I2C_SMBUS_BYTE_DATA: + if (&data->byte == NULL) + { + mutex_unlock(&fpga_i2c_lock); + return -1; + } + if (read_write == I2C_SMBUS_WRITE) + { + rv = dni_fpga_i2c_write(i2c, addr, command, 1, &data->byte, 1); + goto done; + } + else + { + rv = dni_fpga_i2c_read(i2c, addr, command, 1, &data->byte, 1); + goto done; + } + break; + case I2C_SMBUS_WORD_DATA: + if (&data->word == NULL) + { + mutex_unlock(&fpga_i2c_lock); + return -1; + } + if (read_write == I2C_SMBUS_WRITE) + { + /* TODO: not verify */ + rv = dni_fpga_i2c_write(i2c, addr, command, 1, (uint8_t *)&data->word, 2); + // printk(KERN_INFO "I2C_FUNC_SMBUS_WORD_DATA write"); + goto done; + } + else + { + rv = dni_fpga_i2c_read(i2c, addr, command, 1, (uint8_t *)&data->word, 2); + goto done; + } + break; + + case I2C_SMBUS_BLOCK_DATA: + if (&data->block[1] == NULL) + { + mutex_unlock(&fpga_i2c_lock); + return -1; + } + if (read_write == I2C_SMBUS_WRITE) + { + + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); + rv = dni_fpga_i2c_write(i2c, addr, command, 1, &data->block[0], len + 1); + goto done; + } + else + { + // dni_fpga_i2c_read(i2c, addr, command, 1, &data->byte, 1); + // len = min_t(u8, data->byte, I2C_SMBUS_BLOCK_MAX); + len = I2C_SMBUS_BLOCK_MAX; + rv = dni_fpga_i2c_read(i2c, addr, command, 1, &data->block[0], len + 1); + goto done; + } + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (&data->block[1] == NULL) + { + mutex_unlock(&fpga_i2c_lock); + return -1; + } + if (read_write == I2C_SMBUS_WRITE) + { + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); + rv = dni_fpga_i2c_write(i2c, addr, command, 1, &data->block[1], len); + goto done; + } + else + { + len = min_t(u8, data->block[0], I2C_SMBUS_BLOCK_MAX); + rv = dni_fpga_i2c_read(i2c, addr, command, 1, &data->block[1], len); + goto done; + } + break; + case I2C_SMBUS_PROC_CALL: + + break; + case I2C_SMBUS_BLOCK_PROC_CALL: + break; + } + + mutex_unlock(&fpga_i2c_lock); + return -1; +done: + mutex_unlock(&fpga_i2c_lock); + return rv; + +} + +static int delta_wait_i2c_complete(struct i2c_bus_dev *i2c) +{ + unsigned long timeout = 0; + uint64_t status; + + while ((status = delta_fpga_i2c_ctrl_get(i2c)) & I2C_TRANS_ENABLE) + { + if (timeout > DELTA_I2C_WAIT_BUS_TIMEOUT) + { + printk(KERN_INFO "i2c wait for complete timeout: time=%lu us status=0x%llx", timeout, status); + return -ETIMEDOUT; + } + udelay(100); + timeout += 100; + } + + return 0; +} + +static void delta_fpga_i2c_data_reg_set(struct i2c_bus_dev *i2c, int addr, int data) +{ + + uint64_t hi_cmd, lo_cmd, i2c_cmd; + int offset; + hi_cmd = 0; + lo_cmd = data; + i2c_cmd = (hi_cmd << 32) | lo_cmd; + offset = DELTA_I2C_DATA(i2c->offset) + addr; + io_write(i2c, offset, i2c_cmd); +} + +static void delta_fpga_i2c_addr_reg_set(struct i2c_bus_dev *i2c, int data) +{ + uint64_t hi_cmd, lo_cmd, i2c_cmd; + int offset; + hi_cmd = 0; + lo_cmd = data; + i2c_cmd = (hi_cmd << 32) | lo_cmd; + offset = DELTA_I2C_ADDR(i2c->offset); + io_write(i2c, offset, i2c_cmd); +} +#ifdef FPGA_PCA9548 +static void delta_fpga_i2c_conf_reg_set(struct i2c_bus_dev *i2c, int data) +{ + uint64_t hi_cmd, lo_cmd, i2c_cmd; + int offset; + if (ch == 2) + { + hi_cmd = 0; + lo_cmd = (data << 25) | 0x5A; //100Khz + i2c_cmd = (hi_cmd << 32) | lo_cmd; + offset = DELTA_I2C_CONF(i2c->offset); + io_write(i2c, offset, i2c_cmd); + } +} +#endif +static void delta_fpga_i2c_ctrl_set(struct i2c_bus_dev *i2c, int data) +{ + uint64_t hi_cmd, lo_cmd, i2c_cmd; + int offset; + hi_cmd = 0; + lo_cmd = data; + i2c_cmd = (hi_cmd << 32) | lo_cmd; + offset = DELTA_I2C_CTRL(i2c->offset); + io_write(i2c, offset, i2c_cmd); +} + +static int delta_fpga_i2c_ctrl_get(struct i2c_bus_dev *i2c) +{ + int offset; + offset = DELTA_I2C_CTRL(i2c->offset); + return io_read(i2c, offset); +} + + +static int dni_fpga_i2c_write(struct i2c_bus_dev *i2c, int addr, int raddr, int rsize, uint8_t *data, int dsize) +{ + int status; + uint32_t ctrl_data, addr_data, rw_data; + + int rv = -1; + int offset, i; + int four_byte, one_byte; + + four_byte = dsize / 4; + one_byte = dsize % 4; + + if (i2c->mux_en == FPGA_I2C_MUX_EN) + { + if (addr < 0x50 || addr > 0x58) + goto fail; + } + + for (i = 0; i < four_byte; i++) + { + offset = i * 4; + rw_data = (data[i * 4 + 3] << 24) | (data[i * 4 + 2] << 16) | (data[i * 4 + 1] << 8) | data[i * 4 + 0]; + delta_fpga_i2c_data_reg_set(i2c, offset, rw_data); + } + // printk(KERN_INFO "four_byte : rw_data = 0x%lx",rw_data); + rw_data = 0; + for (i = 0; i < one_byte; i++) + { + rw_data |= (data[four_byte * 4 + i] << (i * 8)); + } + offset = four_byte * 4; + delta_fpga_i2c_data_reg_set(i2c, offset, rw_data); + + // printk(KERN_INFO "one_byte : rw_data = 0x%lx",rw_data); + + /* Set address register */ + if (rsize == 0) + addr_data = 0; + else if (rsize == 1) + { + addr = addr + (raddr / 0x100); + addr_data = (raddr & 0xff); + } + else if (rsize == 2) + addr_data = (raddr & 0xffff); + delta_fpga_i2c_addr_reg_set(i2c, addr_data); +#ifdef FPGA_PCA9548 + delta_fpga_i2c_conf_reg_set(i2c, ch, 0x70); +#endif + ctrl_data = 0; + /* Set ctrl reg */ + ctrl_data |= ((addr & 0x7f) << DELTA_FPGA_I2C_SLAVE_OFFSET); + ctrl_data |= ((rsize & 0x3) << DELTA_FPGA_I2C_REG_LEN_OFFSET); + ctrl_data |= ((dsize & 0x1ff) << DELTA_FPGA_I2C_DATA_LEN_OFFSET); + ctrl_data |= 1 << DELTA_FPGA_I2C_RW_OFFSET; + ctrl_data |= 1 << DELTA_FPGA_I2C_START_OFFSET; +#ifdef FPGA_PCA9548 + if (i2c->mux_en == FPGA_I2C_MUX_EN) + { + ctrl_data |= ((i2c->mux_ch & 0x7) << DELTA_FPGA_I2C_CH_SEL_OFFSET); + ctrl_data |= ((1 & 0x1) << DELTA_FPGA_I2C_CH_EN_OFFSET); + } +#endif + /* check rsize */ + if (rsize > 2) + { + return -1; + } + + delta_fpga_i2c_ctrl_set(i2c, ctrl_data); + /* wait for i2c transaction completion */ + if (delta_wait_i2c_complete(i2c)) + { + printk(KERN_INFO "i2c transaction completion timeout"); + rv = -EBUSY; + return rv; + } + /* check status */ + //DNI_LOG_INFO("check i2c transaction status ..."); + status = io_read(i2c, DELTA_I2C_CTRL(i2c->offset)); + // udelay(500); + if ((status & I2C_TRANS_FAIL)) + { + // printk(KERN_INFO "I2C read failed: status=0x%lx", status); + rv = -EIO; /* i2c transfer error */ + goto fail; + } + return 0; +fail: + + return rv; +} + +static int dni_fpga_i2c_read(struct i2c_bus_dev *i2c, int addr, int raddr, int rsize, uint8_t *readout, int dsize) +{ + int status; + uint32_t ctrl_data, addr_data, rw_data; + int offset; + int rv = -1; + int i; + + if (i2c->mux_en == FPGA_I2C_MUX_EN) + { + if (addr < 0x50 || addr > 0x58) + goto fail; + } + + /* Set address register */ + if (rsize == 0) + addr_data = 0; + else if (rsize == 1) + { + addr = addr + (raddr / 0x100); + addr_data = (raddr & 0xff); + } + else if (rsize == 2) + addr_data = (raddr & 0xffff); + delta_fpga_i2c_addr_reg_set(i2c, addr_data); +#ifdef FPGA_PCA9548 + delta_fpga_i2c_conf_reg_set(i2c, ch, 0x70); +#endif + ctrl_data = 0; + /* Set ctrl reg */ + ctrl_data |= ((addr & 0x7f) << DELTA_FPGA_I2C_SLAVE_OFFSET); + ctrl_data |= ((rsize & 0x3) << DELTA_FPGA_I2C_REG_LEN_OFFSET); + ctrl_data |= ((dsize & 0x1ff) << DELTA_FPGA_I2C_DATA_LEN_OFFSET); + ctrl_data |= 0 << DELTA_FPGA_I2C_RW_OFFSET; + ctrl_data |= 1 << DELTA_FPGA_I2C_START_OFFSET; +#ifdef FPGA_PCA9548 + if (i2c->mux_en == FPGA_I2C_MUX_EN) + { + ctrl_data |= ((i2c->mux_ch & 0x7) << DELTA_FPGA_I2C_CH_SEL_OFFSET); + ctrl_data |= ((1 & 0x1) << DELTA_FPGA_I2C_CH_EN_OFFSET); + } +#endif + /* check rsize */ + if (rsize > 2) + { + goto fail; + } + + delta_fpga_i2c_ctrl_set(i2c, ctrl_data); + /* wait for i2c transaction completion */ + if (delta_wait_i2c_complete(i2c)) + { + printk(KERN_ERR "i2c transaction completion timeout"); + rv = -EBUSY; + goto fail; + } + /* check status */ + //DNI_LOG_INFO("check i2c transaction status ...\n"); + udelay(100); + status = io_read(i2c, DELTA_I2C_CTRL(i2c->offset)); + if ((status & I2C_TRANS_FAIL)) + { + //printk(KERN_ERR "I2C read failed:addr_data=0x%lx, ctrl_data=0x%lx, status=0x%lx ",addr_data, ctrl_data ,status); + rv = -EIO; /* i2c transfer error */ + goto fail; + } + + for (i = 1; i <= dsize; i++) + { + if ((i - 1) % 4 == 0) + { + offset = DELTA_I2C_DATA(i2c->offset) + (i - 1); + rw_data = io_read(i2c, offset); + } + readout[i - 1] = (uint8_t)(rw_data >> (((i - 1) % 4) * 8)); + } + return 0; +fail: + return -1; +} + +static int io_read(struct i2c_bus_dev *i2c, int offset) +{ + return ioread32(i2c->bar + offset); +} +static void io_write(struct i2c_bus_dev *i2c, int offset, int data) +{ + iowrite32(data, i2c->bar + offset); +} + +static u32 dni_fpga_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC; +} + +static const struct i2c_algorithm smbus_algorithm = { + .smbus_xfer = dni_fpga_i2c_access, + .functionality = dni_fpga_i2c_func, +}; + +int i2c_adapter_init(struct pci_dev *dev, struct fpga_dev *fpga) +{ + int pci_base, pci_size; + int i, j, error, bus = 0; + int num_i2c_master; + + num_i2c_master = sizeof(fpga_i2c_info) / sizeof(fpga_i2c_s); + for (i = 0; i < num_i2c_master; i++) + { + num_i2c_adapter++; + if (fpga_i2c_info[i].mux_en == FPGA_I2C_MUX_EN) + num_i2c_adapter += fpga_i2c_info[i].num_ch; + } + pci_base = pci_resource_start(dev, 0); + pci_size = pci_resource_len(dev, 0); + + fpga->i2c = kzalloc(sizeof(struct i2c_bus_dev) * num_i2c_adapter, GFP_KERNEL); + + if (!fpga) + return -ENOMEM; + + pci_set_drvdata(dev, fpga); + printk(KERN_INFO "fpga = 0x%x, pci_size = 0x%x \n", fpga, pci_size); + mutex_init(&fpga_i2c_lock); + /* Create PCIE device */ + for (i = 0; i < num_i2c_master; i++) + { + fpga->dev = dev; + fpga->pci_base = pci_base; + fpga->pci_size = pci_size; + + (fpga->i2c + bus)->bar = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + + printk(KERN_INFO "BAR0 Register[0x%x] = 0x%x\n", + (fpga->i2c + bus)->bar, ioread32((fpga->i2c + bus)->bar)); + /* Create I2C adapter */ + printk(KERN_INFO "dev-%d, pci_base = 0x%x, dev_offset = 0x%x", i, fpga->pci_base, fpga_i2c_info[i].offset); + (fpga->i2c + bus)->adapter.owner = THIS_MODULE; + snprintf((fpga->i2c + bus)->adapter.name, sizeof((fpga->i2c + bus)->adapter.name), + fpga_i2c_info[i].name, i); + (fpga->i2c + bus)->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + (fpga->i2c + bus)->adapter.algo = &smbus_algorithm; + (fpga->i2c + bus)->adapter.algo_data = fpga->i2c + bus; + /* set up the sysfs linkage to our parent device */ + (fpga->i2c + bus)->adapter.dev.parent = &dev->dev; + /* set i2c adapter number */ + // (fpga->i2c+bus)->adapter.nr = i+10; + /* set up the busnum */ + (fpga->i2c + bus)->busnum = i; + (fpga->i2c + bus)->offset = fpga_i2c_info[i].offset; + /* set up i2c mux */ + (fpga->i2c + bus)->mux_ch = 0; + (fpga->i2c + bus)->mux_en = FPGA_I2C_MUX_DIS; + + // error = i2c_add_numbered_adapter(&(fpga->i2c+bus)->adapter); + error = i2c_add_adapter(&(fpga->i2c + bus)->adapter); + if (error) + goto out_release_region; + + bus++; + if (fpga_i2c_info[i].mux_en == FPGA_I2C_MUX_EN) + { + for (j = 0; j < fpga_i2c_info[i].num_ch; j++) + { + (fpga->i2c + bus)->bar = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + + printk(KERN_INFO "BAR0 Register[0x%x] = 0x%x\n", + (fpga->i2c + bus)->bar, ioread32((fpga->i2c + bus)->bar)); + + /* Create I2C adapter */ + printk(KERN_INFO "dev-%d, pci_base = 0x%x, dev_offset = 0x%x", i, fpga->pci_base, fpga_i2c_info[i].offset); + (fpga->i2c + bus)->adapter.owner = THIS_MODULE; + snprintf((fpga->i2c + bus)->adapter.name, sizeof((fpga->i2c + bus)->adapter.name), + fpga_i2c_info[i].name, i, j); + (fpga->i2c + bus)->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + (fpga->i2c + bus)->adapter.algo = &smbus_algorithm; + (fpga->i2c + bus)->adapter.algo_data = fpga->i2c + bus; + /* set up the sysfs linkage to our parent device */ + (fpga->i2c + bus)->adapter.dev.parent = &dev->dev; + /* set i2c adapter number */ + // (fpga->i2c+bus)->adapter.nr = i+10; + /* set up the busnum */ + (fpga->i2c + bus)->busnum = i; + /* set up i2c mux */ + (fpga->i2c + bus)->mux_ch = j; + (fpga->i2c + bus)->mux_en = FPGA_I2C_MUX_EN; + error = i2c_add_adapter(&(fpga->i2c + bus)->adapter); + if (error) + goto out_release_region; + bus++; + } + } + } + return 0; +out_release_region: + return error; +} diff --git a/ixr7220h5-64d/modules/fpga_i2c.h b/ixr7220h5-64d/modules/fpga_i2c.h new file mode 100644 index 0000000..30308d9 --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_i2c.h @@ -0,0 +1,38 @@ +#ifndef __FGPA_I2C_H__ +#define __FGPA_I2C_H__ + +#include "fpga.h" + +extern int num_i2c_adapter; +int i2c_adapter_init(struct pci_dev *dev, struct fpga_dev *fpga); + +#define DELTA_I2C_WAIT_BUS_TIMEOUT 100000 /* 100000us = 100ms */ +#define DELTA_I2C_OFFSET 0x1000 +#define DELTA_I2C_BASE(s) ((DELTA_I2C_OFFSET) + ((0x300) * (s))) +#define DELTA_I2C_CONF(s) ((s) + 0x0 ) +#define DELTA_I2C_ADDR(s) ((s) + 0x8 ) +#define DELTA_I2C_CTRL(s) ((s) + 0x4 ) +#define DELTA_I2C_DATA(s) ((s) + 0x100 ) + +#define DELTA_DPLL_I2C_BASE 0x300 +#define DELTA_FPGA_I2C_BASE 0x600 + +#define DELTA_I2C_GRABBER_OFFSET 0x1000 +#define DELTA_I2C_GRABBER_CONF(s) ((DELTA_I2C_GRABBER_OFFSET) + ((0x300) * (s))) +#define DELTA_I2C_GRABBER_ADDR(s) ((DELTA_I2C_GRABBER_OFFSET) + ((0x300) * (s)) + 0x8) +#define DELTA_I2C_GRABBER_CTRL(s) ((DELTA_I2C_GRABBER_OFFSET) + ((0x300) * (s)) + 0x4) +#define DELTA_I2C_GRABBER_DATA(s) ((DELTA_I2C_GRABBER_OFFSET) + ((0x300) * (s)) + 0x100) + +#define I2C_BUS_READY 0x4 +#define I2C_TRANS_FAIL 0x2 +#define I2C_TRANS_ENABLE 0x1 +#define DELTA_FPGA_I2C_START_OFFSET 0 +#define DELTA_FPGA_I2C_RW_OFFSET 3 +#define DELTA_FPGA_I2C_REG_LEN_OFFSET 8 +#define DELTA_FPGA_I2C_CH_SEL_OFFSET 10 +#define DELTA_FPGA_I2C_CH_EN_OFFSET 13 +#define DELTA_FPGA_I2C_DATA_LEN_OFFSET 15 +#define DELTA_FPGA_I2C_SLAVE_OFFSET 25 + + +#endif /* __FGPA_I2C_H__ */ \ No newline at end of file diff --git a/ixr7220h5-64d/modules/fpga_reg.c b/ixr7220h5-64d/modules/fpga_reg.c new file mode 100644 index 0000000..abad16f --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_reg.c @@ -0,0 +1,43 @@ +// FPGA driver +// +// Copyright (C) 2024 Nokia Corporation. +// Copyright (C) 2024 Delta Networks, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// 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. +// see + +#include +#include +#include "fpga.h" +#include "fpga_attr.h" +#include "fpga_reg.h" + +const sys_fpga_reg_st sys_fpga_reg_table[19] = { + { "scratch", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x00, 0, 32 }, + { "code_ver", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x04, 0, 8 }, + { "code_day", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x08, 8, 8 }, + { "code_month", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x08, 16, 8 }, + { "code_year", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x08, 24, 8 }, + { "board_ver", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x0C, 0, 3 }, + { "sys_pwr", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x1c, 2, 1 }, + { "psu1_pres", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x20, 16, 1 }, + { "psu2_pres", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x20, 20, 1 }, + { "psu1_ok", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x20, 17, 1 }, + { "psu2_ok", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x20, 21, 1 }, + { "led_sys", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x84, 0, 3 }, + { "led_fan", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x88, 0, 3 }, + { "led_psu1", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x8c, 0, 3 }, + { "led_psu2", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0x90, 0, 3 }, + { "fan1_led", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0xa0, 12, 3 }, + { "fan2_led", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0xa0, 8, 3 }, + { "fan3_led", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0xa0, 4, 3 }, + { "fan4_led", NULL, I2C_DEV_ATTR_SHOW_DEFAULT, I2C_DEV_ATTR_STORE_DEFAULT, 0xa0, 0, 3 }, +}; diff --git a/ixr7220h5-64d/modules/fpga_reg.h b/ixr7220h5-64d/modules/fpga_reg.h new file mode 100644 index 0000000..7a2765a --- /dev/null +++ b/ixr7220h5-64d/modules/fpga_reg.h @@ -0,0 +1,6 @@ +#ifndef __FGPA_REG_H__ +#define __FGPA_REG_H__ + +extern const sys_fpga_reg_st sys_fpga_reg_table[19]; + +#endif /* __FGPA_REG_H__ */ diff --git a/ixr7220h5-64d/modules/swpld2.c b/ixr7220h5-64d/modules/swpld2.c new file mode 100644 index 0000000..f2f92ae --- /dev/null +++ b/ixr7220h5-64d/modules/swpld2.c @@ -0,0 +1,1669 @@ +// * CPLD driver for Nokia-7220-IXR-H5-64D Router +// * +// * Copyright (C) 2024 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * 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. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "swpld2" + +// REGISTERS ADDRESS MAP +#define SCRATCH_REG 0x00 +#define CODE_REV_REG 0x01 +#define BOARD_REV_REG 0x02 +#define BOARD_CFG_REG 0x03 +#define LED_TEST_REG 0x08 +#define RST_PLD_REG 0x10 +#define RST_MSK_REG 0x11 +#define RST_CTRL_REG 0x12 +#define INT_CLR_REG 0x20 +#define INT_MSK_REG 0x21 +#define INT_REG 0x22 +#define PLD_INT_REG 0x23 +#define SFP_INT_REG 0x24 +#define QSFP_PRS_INT_REG0 0x28 +#define QSFP_PRS_INT_REG1 0x29 +#define QSFP_PRS_INT_REG2 0x2A +#define QSFP_PRS_INT_REG3 0x2B +#define QSFP_INT_EVT_REG0 0x2C +#define QSFP_INT_EVT_REG1 0x2D +#define QSFP_INT_EVT_REG2 0x2E +#define QSFP_INT_EVT_REG3 0x2F +#define QSFP_RST_REG0 0x30 +#define QSFP_RST_REG1 0x31 +#define QSFP_RST_REG2 0x32 +#define QSFP_RST_REG3 0x33 +#define QSFP_LPMODE_REG0 0x34 +#define QSFP_LPMODE_REG1 0x35 +#define QSFP_LPMODE_REG2 0x36 +#define QSFP_LPMODE_REG3 0x37 +#define QSFP_MODSEL_REG0 0x38 +#define QSFP_MODSEL_REG1 0x39 +#define QSFP_MODSEL_REG2 0x3A +#define QSFP_MODSEL_REG3 0x3B +#define QSFP_MODPRS_REG0 0x3C +#define QSFP_MODPRS_REG1 0x3D +#define QSFP_MODPRS_REG2 0x3E +#define QSFP_MODPRS_REG3 0x3F +#define QSFP_INT_STAT_REG0 0x40 +#define QSFP_INT_STAT_REG1 0x41 +#define QSFP_INT_STAT_REG2 0x42 +#define QSFP_INT_STAT_REG3 0x43 +#define SFP_CTRL_REG 0x44 +#define SFP_STAT_REG 0x45 +#define QSFP_LED_REG1 0x90 +#define QSFP_BRKNUM_REG1 0xD0 +#define CODE_DAY_REG 0xF0 +#define CODE_MONTH_REG 0xF1 +#define CODE_YEAR_REG 0xF2 +#define TEST_CODE_REV_REG 0xF3 + +// REG BIT FIELD POSITION or MASK +#define BOARD_REV_REG_VER_MSK 0x7 + +#define LED_TEST_REG_AMB 0x0 +#define LED_TEST_REG_GRN 0x1 +#define LED_TEST_REG_BLINK 0x3 +#define LED_TEST_REG_SRC_SEL 0x7 + +#define RST_PLD_REG_SOFT_RST 0x0 + +#define SFP0_TX_EN 0x0 +#define SFP0_LED 0x2 +#define SFP1_TX_EN 0x4 +#define SFP1_LED 0x6 + +#define SFP0_PRS 0x0 +#define SFP0_RX_LOS 0x1 +#define SFP0_TX_FAULT 0x2 +#define SFP1_PRS 0x4 +#define SFP1_RX_LOS 0x5 +#define SFP1_TX_FAULT 0x6 + +// common index of each qsfp modules +#define QSFP01_INDEX 0x0 +#define QSFP02_INDEX 0x1 +#define QSFP03_INDEX 0x2 +#define QSFP04_INDEX 0x3 +#define QSFP05_INDEX 0x4 +#define QSFP06_INDEX 0x5 +#define QSFP07_INDEX 0x6 +#define QSFP08_INDEX 0x7 +#define QSFP09_INDEX 0x0 +#define QSFP10_INDEX 0x1 +#define QSFP11_INDEX 0x2 +#define QSFP12_INDEX 0x3 +#define QSFP13_INDEX 0x4 +#define QSFP14_INDEX 0x5 +#define QSFP15_INDEX 0x6 +#define QSFP16_INDEX 0x7 +#define QSFP33_INDEX 0x0 +#define QSFP34_INDEX 0x1 +#define QSFP35_INDEX 0x2 +#define QSFP36_INDEX 0x3 +#define QSFP37_INDEX 0x4 +#define QSFP38_INDEX 0x5 +#define QSFP39_INDEX 0x6 +#define QSFP40_INDEX 0x7 +#define QSFP41_INDEX 0x0 +#define QSFP42_INDEX 0x1 +#define QSFP43_INDEX 0x2 +#define QSFP44_INDEX 0x3 +#define QSFP45_INDEX 0x4 +#define QSFP46_INDEX 0x5 +#define QSFP47_INDEX 0x6 +#define QSFP48_INDEX 0x7 + +static const unsigned short cpld_address_list[] = {0x41, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; + int reset_list[32]; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_err(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + mutex_unlock(&data->update_lock); + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_err(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static void dump_reg(struct cpld_data *data) +{ + struct i2c_client *client = data->client; + u8 val0 = 0; + u8 val1 = 0; + u8 val2 = 0; + u8 val3 = 0; + + + val0 = cpld_i2c_read(data, QSFP_RST_REG0); + val1 = cpld_i2c_read(data, QSFP_RST_REG1); + val2 = cpld_i2c_read(data, QSFP_RST_REG2); + val3 = cpld_i2c_read(data, QSFP_RST_REG3); + dev_info(&client->dev, "[SWPLD2]QSFP_RESET_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, QSFP_LPMODE_REG0); + val1 = cpld_i2c_read(data, QSFP_LPMODE_REG1); + val2 = cpld_i2c_read(data, QSFP_LPMODE_REG2); + val3 = cpld_i2c_read(data, QSFP_LPMODE_REG3); + dev_info(&client->dev, "[SWPLD2]QSFP_LPMODE_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, QSFP_MODSEL_REG0); + val1 = cpld_i2c_read(data, QSFP_MODSEL_REG1); + val2 = cpld_i2c_read(data, QSFP_MODSEL_REG2); + val3 = cpld_i2c_read(data, QSFP_MODSEL_REG3); + dev_info(&client->dev, "[SWPLD2]QSFP_MODSEL_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, QSFP_MODPRS_REG0); + val1 = cpld_i2c_read(data, QSFP_MODPRS_REG1); + val2 = cpld_i2c_read(data, QSFP_MODPRS_REG2); + val3 = cpld_i2c_read(data, QSFP_MODPRS_REG3); + dev_info(&client->dev, "[SWPLD2]QSFP_MODPRES_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_code_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_REV_REG); + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_board_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, BOARD_REV_REG) & BOARD_REV_REG_VER_MSK; + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_led_test(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + val = cpld_i2c_read(data, LED_TEST_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_led_test(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, LED_TEST_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, LED_TEST_REG, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_rst(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + val = cpld_i2c_read(data, RST_PLD_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_rst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, RST_PLD_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, RST_PLD_REG, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG0); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG1); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG2); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG2, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG3); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG3, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG0); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG1); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG2); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG2, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG3); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG3, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG0); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG1); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG2); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG2, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG3); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG3, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_prs0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_qsfp_prs1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_qsfp_prs2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_qsfp_prs3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + if (sda->index == 1) + val = cpld_i2c_read(data, QSFP_MODPRS_REG0); + if (sda->index == 2) + val = cpld_i2c_read(data, QSFP_MODPRS_REG1); + if (sda->index == 3) + val = cpld_i2c_read(data, QSFP_MODPRS_REG2); + if (sda->index == 4) + val = cpld_i2c_read(data, QSFP_MODPRS_REG3); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_sfp_ctrl_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + u8 reg_val = 0; + + val = cpld_i2c_read(data, SFP_CTRL_REG); + + switch (sda->index) { + case SFP0_TX_EN: + case SFP1_TX_EN: + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); + case SFP0_LED: + case SFP1_LED: + reg_val = (val>>sda->index) & 0x3; + return sprintf(buf, "%d\n", reg_val); + default: + return sprintf(buf, "Error: Wrong bitwise(%d) to set!\n", sda->index); + } +} + +static ssize_t set_sfp_ctrl_reg(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + + switch (sda->index) { + case SFP0_TX_EN: + case SFP1_TX_EN: + if (usr_val > 1) { + return -EINVAL; + } + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, SFP_CTRL_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, SFP_CTRL_REG, (reg_val | usr_val)); + break; + case SFP0_LED: + case SFP1_LED: + if (usr_val > 3) { + return -EINVAL; + } + mask = (~(3 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, SFP_CTRL_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, SFP_CTRL_REG, (reg_val | usr_val)); + break; + default: + sprintf(buf, "Error: Wrong bitwise(%d) to set!\n", sda->index); + } + + return count; +} + +static ssize_t show_sfp_stat_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, SFP_STAT_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_code_day(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_DAY_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_code_month(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_MONTH_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_code_year(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_YEAR_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_qsfp_reset(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + + return sprintf(buf, "%d\n", data->reset_list[sda->index]); +} + +static ssize_t set_qsfp_reset(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + data->reset_list[sda->index] = usr_val; + return count; +} + +static ssize_t show_qsfp_led(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val1 = 0; + u8 val2 = 0; + + val1 = cpld_i2c_read(data, QSFP_LED_REG1 + sda->index * 2); + val2 = cpld_i2c_read(data, QSFP_LED_REG1 + sda->index * 2 + 1); + + return sprintf(buf, "0x%02x%02x\n", val2, val1); +} + +static ssize_t set_qsfp_led(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u16 usr_val = 0; + u8 val = 0; + + int ret = kstrtou16(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFFFF) { + return -EINVAL; + } + + val = usr_val & 0xFF; + cpld_i2c_write(data, QSFP_LED_REG1 + sda->index*2, val); + val = (usr_val & 0xFF00) >> 8; + cpld_i2c_write(data, QSFP_LED_REG1 + sda->index*2 + 1, val); + + return count; +} + +static ssize_t show_qsfp_brknum(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + int reg_index; + int bit_index; + + reg_index = QSFP_BRKNUM_REG1 + (int)(sda->index/2); + val = cpld_i2c_read(data, reg_index); + bit_index = sda->index%2 * 4; + + return sprintf(buf, "0x%x\n", val>>bit_index & 0xF); +} + +static ssize_t set_qsfp_brknum(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + int reg_index; + int bit_index; + + reg_index = QSFP_BRKNUM_REG1 + (int)(sda->index/2); + bit_index = sda->index%2 * 4; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xF) { + return -EINVAL; + } + + mask = (~(7 << bit_index)) & 0xFF; + reg_val = cpld_i2c_read(data, reg_index); + reg_val = reg_val & mask; + usr_val = usr_val << bit_index; + cpld_i2c_write(data, reg_index, (reg_val | usr_val)); + + return count; +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); +static SENSOR_DEVICE_ATTR(code_ver, S_IRUGO, show_code_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(board_ver, S_IRUGO, show_board_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(led_test_amb, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_AMB); +static SENSOR_DEVICE_ATTR(led_test_grn, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_GRN); +static SENSOR_DEVICE_ATTR(led_test_blink, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_BLINK); +static SENSOR_DEVICE_ATTR(led_test_src_sel, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_SRC_SEL); +static SENSOR_DEVICE_ATTR(rst_pld_soft, S_IRUGO | S_IWUSR, show_rst, set_rst, RST_PLD_REG_SOFT_RST); + +static SENSOR_DEVICE_ATTR(port_1_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP01_INDEX); +static SENSOR_DEVICE_ATTR(port_2_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP02_INDEX); +static SENSOR_DEVICE_ATTR(port_3_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP03_INDEX); +static SENSOR_DEVICE_ATTR(port_4_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP04_INDEX); +static SENSOR_DEVICE_ATTR(port_5_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP05_INDEX); +static SENSOR_DEVICE_ATTR(port_6_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP06_INDEX); +static SENSOR_DEVICE_ATTR(port_7_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP07_INDEX); +static SENSOR_DEVICE_ATTR(port_8_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP08_INDEX); +static SENSOR_DEVICE_ATTR(port_9_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP09_INDEX); +static SENSOR_DEVICE_ATTR(port_10_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP10_INDEX); +static SENSOR_DEVICE_ATTR(port_11_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP11_INDEX); +static SENSOR_DEVICE_ATTR(port_12_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP12_INDEX); +static SENSOR_DEVICE_ATTR(port_13_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP13_INDEX); +static SENSOR_DEVICE_ATTR(port_14_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP14_INDEX); +static SENSOR_DEVICE_ATTR(port_15_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP15_INDEX); +static SENSOR_DEVICE_ATTR(port_16_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP16_INDEX); +static SENSOR_DEVICE_ATTR(port_33_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP33_INDEX); +static SENSOR_DEVICE_ATTR(port_34_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP34_INDEX); +static SENSOR_DEVICE_ATTR(port_35_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP35_INDEX); +static SENSOR_DEVICE_ATTR(port_36_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP36_INDEX); +static SENSOR_DEVICE_ATTR(port_37_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP37_INDEX); +static SENSOR_DEVICE_ATTR(port_38_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP38_INDEX); +static SENSOR_DEVICE_ATTR(port_39_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP39_INDEX); +static SENSOR_DEVICE_ATTR(port_40_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP40_INDEX); +static SENSOR_DEVICE_ATTR(port_41_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP41_INDEX); +static SENSOR_DEVICE_ATTR(port_42_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP42_INDEX); +static SENSOR_DEVICE_ATTR(port_43_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP43_INDEX); +static SENSOR_DEVICE_ATTR(port_44_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP44_INDEX); +static SENSOR_DEVICE_ATTR(port_45_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP45_INDEX); +static SENSOR_DEVICE_ATTR(port_46_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP46_INDEX); +static SENSOR_DEVICE_ATTR(port_47_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP47_INDEX); +static SENSOR_DEVICE_ATTR(port_48_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP48_INDEX); + +static SENSOR_DEVICE_ATTR(port_1_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP01_INDEX); +static SENSOR_DEVICE_ATTR(port_2_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP02_INDEX); +static SENSOR_DEVICE_ATTR(port_3_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP03_INDEX); +static SENSOR_DEVICE_ATTR(port_4_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP04_INDEX); +static SENSOR_DEVICE_ATTR(port_5_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP05_INDEX); +static SENSOR_DEVICE_ATTR(port_6_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP06_INDEX); +static SENSOR_DEVICE_ATTR(port_7_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP07_INDEX); +static SENSOR_DEVICE_ATTR(port_8_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP08_INDEX); +static SENSOR_DEVICE_ATTR(port_9_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP09_INDEX); +static SENSOR_DEVICE_ATTR(port_10_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP10_INDEX); +static SENSOR_DEVICE_ATTR(port_11_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP11_INDEX); +static SENSOR_DEVICE_ATTR(port_12_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP12_INDEX); +static SENSOR_DEVICE_ATTR(port_13_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP13_INDEX); +static SENSOR_DEVICE_ATTR(port_14_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP14_INDEX); +static SENSOR_DEVICE_ATTR(port_15_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP15_INDEX); +static SENSOR_DEVICE_ATTR(port_16_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP16_INDEX); +static SENSOR_DEVICE_ATTR(port_33_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP33_INDEX); +static SENSOR_DEVICE_ATTR(port_34_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP34_INDEX); +static SENSOR_DEVICE_ATTR(port_35_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP35_INDEX); +static SENSOR_DEVICE_ATTR(port_36_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP36_INDEX); +static SENSOR_DEVICE_ATTR(port_37_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP37_INDEX); +static SENSOR_DEVICE_ATTR(port_38_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP38_INDEX); +static SENSOR_DEVICE_ATTR(port_39_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP39_INDEX); +static SENSOR_DEVICE_ATTR(port_40_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP40_INDEX); +static SENSOR_DEVICE_ATTR(port_41_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP41_INDEX); +static SENSOR_DEVICE_ATTR(port_42_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP42_INDEX); +static SENSOR_DEVICE_ATTR(port_43_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP43_INDEX); +static SENSOR_DEVICE_ATTR(port_44_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP44_INDEX); +static SENSOR_DEVICE_ATTR(port_45_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP45_INDEX); +static SENSOR_DEVICE_ATTR(port_46_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP46_INDEX); +static SENSOR_DEVICE_ATTR(port_47_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP47_INDEX); +static SENSOR_DEVICE_ATTR(port_48_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP48_INDEX); + +static SENSOR_DEVICE_ATTR(port_1_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP01_INDEX); +static SENSOR_DEVICE_ATTR(port_2_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP02_INDEX); +static SENSOR_DEVICE_ATTR(port_3_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP03_INDEX); +static SENSOR_DEVICE_ATTR(port_4_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP04_INDEX); +static SENSOR_DEVICE_ATTR(port_5_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP05_INDEX); +static SENSOR_DEVICE_ATTR(port_6_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP06_INDEX); +static SENSOR_DEVICE_ATTR(port_7_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP07_INDEX); +static SENSOR_DEVICE_ATTR(port_8_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP08_INDEX); +static SENSOR_DEVICE_ATTR(port_9_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP09_INDEX); +static SENSOR_DEVICE_ATTR(port_10_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP10_INDEX); +static SENSOR_DEVICE_ATTR(port_11_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP11_INDEX); +static SENSOR_DEVICE_ATTR(port_12_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP12_INDEX); +static SENSOR_DEVICE_ATTR(port_13_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP13_INDEX); +static SENSOR_DEVICE_ATTR(port_14_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP14_INDEX); +static SENSOR_DEVICE_ATTR(port_15_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP15_INDEX); +static SENSOR_DEVICE_ATTR(port_16_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP16_INDEX); +static SENSOR_DEVICE_ATTR(port_33_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP33_INDEX); +static SENSOR_DEVICE_ATTR(port_34_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP34_INDEX); +static SENSOR_DEVICE_ATTR(port_35_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP35_INDEX); +static SENSOR_DEVICE_ATTR(port_36_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP36_INDEX); +static SENSOR_DEVICE_ATTR(port_37_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP37_INDEX); +static SENSOR_DEVICE_ATTR(port_38_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP38_INDEX); +static SENSOR_DEVICE_ATTR(port_39_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP39_INDEX); +static SENSOR_DEVICE_ATTR(port_40_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP40_INDEX); +static SENSOR_DEVICE_ATTR(port_41_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP41_INDEX); +static SENSOR_DEVICE_ATTR(port_42_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP42_INDEX); +static SENSOR_DEVICE_ATTR(port_43_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP43_INDEX); +static SENSOR_DEVICE_ATTR(port_44_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP44_INDEX); +static SENSOR_DEVICE_ATTR(port_45_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP45_INDEX); +static SENSOR_DEVICE_ATTR(port_46_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP46_INDEX); +static SENSOR_DEVICE_ATTR(port_47_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP47_INDEX); +static SENSOR_DEVICE_ATTR(port_48_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP48_INDEX); + +static SENSOR_DEVICE_ATTR(port_1_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP01_INDEX); +static SENSOR_DEVICE_ATTR(port_2_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP02_INDEX); +static SENSOR_DEVICE_ATTR(port_3_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP03_INDEX); +static SENSOR_DEVICE_ATTR(port_4_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP04_INDEX); +static SENSOR_DEVICE_ATTR(port_5_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP05_INDEX); +static SENSOR_DEVICE_ATTR(port_6_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP06_INDEX); +static SENSOR_DEVICE_ATTR(port_7_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP07_INDEX); +static SENSOR_DEVICE_ATTR(port_8_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP08_INDEX); +static SENSOR_DEVICE_ATTR(port_9_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP09_INDEX); +static SENSOR_DEVICE_ATTR(port_10_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP10_INDEX); +static SENSOR_DEVICE_ATTR(port_11_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP11_INDEX); +static SENSOR_DEVICE_ATTR(port_12_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP12_INDEX); +static SENSOR_DEVICE_ATTR(port_13_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP13_INDEX); +static SENSOR_DEVICE_ATTR(port_14_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP14_INDEX); +static SENSOR_DEVICE_ATTR(port_15_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP15_INDEX); +static SENSOR_DEVICE_ATTR(port_16_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP16_INDEX); +static SENSOR_DEVICE_ATTR(port_33_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP33_INDEX); +static SENSOR_DEVICE_ATTR(port_34_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP34_INDEX); +static SENSOR_DEVICE_ATTR(port_35_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP35_INDEX); +static SENSOR_DEVICE_ATTR(port_36_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP36_INDEX); +static SENSOR_DEVICE_ATTR(port_37_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP37_INDEX); +static SENSOR_DEVICE_ATTR(port_38_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP38_INDEX); +static SENSOR_DEVICE_ATTR(port_39_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP39_INDEX); +static SENSOR_DEVICE_ATTR(port_40_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP40_INDEX); +static SENSOR_DEVICE_ATTR(port_41_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP41_INDEX); +static SENSOR_DEVICE_ATTR(port_42_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP42_INDEX); +static SENSOR_DEVICE_ATTR(port_43_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP43_INDEX); +static SENSOR_DEVICE_ATTR(port_44_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP44_INDEX); +static SENSOR_DEVICE_ATTR(port_45_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP45_INDEX); +static SENSOR_DEVICE_ATTR(port_46_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP46_INDEX); +static SENSOR_DEVICE_ATTR(port_47_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP47_INDEX); +static SENSOR_DEVICE_ATTR(port_48_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP48_INDEX); + +static SENSOR_DEVICE_ATTR(modprs_reg1, S_IRUGO, show_modprs_reg, NULL, 1); +static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 2); +static SENSOR_DEVICE_ATTR(modprs_reg3, S_IRUGO, show_modprs_reg, NULL, 3); +static SENSOR_DEVICE_ATTR(modprs_reg4, S_IRUGO, show_modprs_reg, NULL, 4); + +static SENSOR_DEVICE_ATTR(port_65_tx_fault, S_IRUGO, show_sfp_stat_reg, NULL, SFP0_TX_FAULT); +static SENSOR_DEVICE_ATTR(port_65_rx_los, S_IRUGO, show_sfp_stat_reg, NULL, SFP0_RX_LOS); +static SENSOR_DEVICE_ATTR(port_65_prs, S_IRUGO, show_sfp_stat_reg, NULL, SFP0_PRS); +static SENSOR_DEVICE_ATTR(port_66_tx_fault, S_IRUGO, show_sfp_stat_reg, NULL, SFP1_TX_FAULT); +static SENSOR_DEVICE_ATTR(port_66_rx_los, S_IRUGO, show_sfp_stat_reg, NULL, SFP1_RX_LOS); +static SENSOR_DEVICE_ATTR(port_66_prs, S_IRUGO, show_sfp_stat_reg, NULL, SFP1_PRS); +static SENSOR_DEVICE_ATTR(port_65_tx_en, S_IRUGO | S_IWUSR, show_sfp_ctrl_reg, set_sfp_ctrl_reg, SFP0_TX_EN); +static SENSOR_DEVICE_ATTR(port_65_led, S_IRUGO | S_IWUSR, show_sfp_ctrl_reg, set_sfp_ctrl_reg, SFP0_LED); +static SENSOR_DEVICE_ATTR(port_66_tx_en, S_IRUGO | S_IWUSR, show_sfp_ctrl_reg, set_sfp_ctrl_reg, SFP1_TX_EN); +static SENSOR_DEVICE_ATTR(port_66_led, S_IRUGO | S_IWUSR, show_sfp_ctrl_reg, set_sfp_ctrl_reg, SFP1_LED); + +static SENSOR_DEVICE_ATTR(code_day, S_IRUGO, show_code_day, NULL, 0); +static SENSOR_DEVICE_ATTR(code_month, S_IRUGO, show_code_month, NULL, 0); +static SENSOR_DEVICE_ATTR(code_year, S_IRUGO, show_code_year, NULL, 0); + +static SENSOR_DEVICE_ATTR(port_1_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 0); +static SENSOR_DEVICE_ATTR(port_2_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 1); +static SENSOR_DEVICE_ATTR(port_3_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 2); +static SENSOR_DEVICE_ATTR(port_4_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 3); +static SENSOR_DEVICE_ATTR(port_5_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 4); +static SENSOR_DEVICE_ATTR(port_6_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 5); +static SENSOR_DEVICE_ATTR(port_7_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 6); +static SENSOR_DEVICE_ATTR(port_8_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 7); +static SENSOR_DEVICE_ATTR(port_9_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 8); +static SENSOR_DEVICE_ATTR(port_10_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 9); +static SENSOR_DEVICE_ATTR(port_11_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 10); +static SENSOR_DEVICE_ATTR(port_12_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 11); +static SENSOR_DEVICE_ATTR(port_13_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 12); +static SENSOR_DEVICE_ATTR(port_14_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 13); +static SENSOR_DEVICE_ATTR(port_15_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 14); +static SENSOR_DEVICE_ATTR(port_16_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 15); +static SENSOR_DEVICE_ATTR(port_33_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 16); +static SENSOR_DEVICE_ATTR(port_34_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 17); +static SENSOR_DEVICE_ATTR(port_35_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 18); +static SENSOR_DEVICE_ATTR(port_36_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 19); +static SENSOR_DEVICE_ATTR(port_37_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 20); +static SENSOR_DEVICE_ATTR(port_38_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 21); +static SENSOR_DEVICE_ATTR(port_39_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 22); +static SENSOR_DEVICE_ATTR(port_40_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 23); +static SENSOR_DEVICE_ATTR(port_41_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 24); +static SENSOR_DEVICE_ATTR(port_42_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 25); +static SENSOR_DEVICE_ATTR(port_43_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 26); +static SENSOR_DEVICE_ATTR(port_44_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 27); +static SENSOR_DEVICE_ATTR(port_45_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 28); +static SENSOR_DEVICE_ATTR(port_46_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 29); +static SENSOR_DEVICE_ATTR(port_47_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 30); +static SENSOR_DEVICE_ATTR(port_48_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 31); + +static SENSOR_DEVICE_ATTR(port_1_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 0); +static SENSOR_DEVICE_ATTR(port_2_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 1); +static SENSOR_DEVICE_ATTR(port_3_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 2); +static SENSOR_DEVICE_ATTR(port_4_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 3); +static SENSOR_DEVICE_ATTR(port_5_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 4); +static SENSOR_DEVICE_ATTR(port_6_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 5); +static SENSOR_DEVICE_ATTR(port_7_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 6); +static SENSOR_DEVICE_ATTR(port_8_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 7); +static SENSOR_DEVICE_ATTR(port_9_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 8); +static SENSOR_DEVICE_ATTR(port_10_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 9); +static SENSOR_DEVICE_ATTR(port_11_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 10); +static SENSOR_DEVICE_ATTR(port_12_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 11); +static SENSOR_DEVICE_ATTR(port_13_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 12); +static SENSOR_DEVICE_ATTR(port_14_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 13); +static SENSOR_DEVICE_ATTR(port_15_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 14); +static SENSOR_DEVICE_ATTR(port_16_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 15); +static SENSOR_DEVICE_ATTR(port_33_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 16); +static SENSOR_DEVICE_ATTR(port_34_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 17); +static SENSOR_DEVICE_ATTR(port_35_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 18); +static SENSOR_DEVICE_ATTR(port_36_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 19); +static SENSOR_DEVICE_ATTR(port_37_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 20); +static SENSOR_DEVICE_ATTR(port_38_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 21); +static SENSOR_DEVICE_ATTR(port_39_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 22); +static SENSOR_DEVICE_ATTR(port_40_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 23); +static SENSOR_DEVICE_ATTR(port_41_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 24); +static SENSOR_DEVICE_ATTR(port_42_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 25); +static SENSOR_DEVICE_ATTR(port_43_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 26); +static SENSOR_DEVICE_ATTR(port_44_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 27); +static SENSOR_DEVICE_ATTR(port_45_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 28); +static SENSOR_DEVICE_ATTR(port_46_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 29); +static SENSOR_DEVICE_ATTR(port_47_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 30); +static SENSOR_DEVICE_ATTR(port_48_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 31); + +static SENSOR_DEVICE_ATTR(port_1_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 0); +static SENSOR_DEVICE_ATTR(port_2_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 1); +static SENSOR_DEVICE_ATTR(port_3_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 2); +static SENSOR_DEVICE_ATTR(port_4_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 3); +static SENSOR_DEVICE_ATTR(port_5_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 4); +static SENSOR_DEVICE_ATTR(port_6_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 5); +static SENSOR_DEVICE_ATTR(port_7_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 6); +static SENSOR_DEVICE_ATTR(port_8_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 7); +static SENSOR_DEVICE_ATTR(port_9_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 8); +static SENSOR_DEVICE_ATTR(port_10_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 9); +static SENSOR_DEVICE_ATTR(port_11_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 10); +static SENSOR_DEVICE_ATTR(port_12_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 11); +static SENSOR_DEVICE_ATTR(port_13_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 12); +static SENSOR_DEVICE_ATTR(port_14_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 13); +static SENSOR_DEVICE_ATTR(port_15_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 14); +static SENSOR_DEVICE_ATTR(port_16_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 15); +static SENSOR_DEVICE_ATTR(port_33_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 16); +static SENSOR_DEVICE_ATTR(port_34_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 17); +static SENSOR_DEVICE_ATTR(port_35_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 18); +static SENSOR_DEVICE_ATTR(port_36_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 19); +static SENSOR_DEVICE_ATTR(port_37_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 20); +static SENSOR_DEVICE_ATTR(port_38_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 21); +static SENSOR_DEVICE_ATTR(port_39_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 22); +static SENSOR_DEVICE_ATTR(port_40_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 23); +static SENSOR_DEVICE_ATTR(port_41_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 24); +static SENSOR_DEVICE_ATTR(port_42_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 25); +static SENSOR_DEVICE_ATTR(port_43_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 26); +static SENSOR_DEVICE_ATTR(port_44_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 27); +static SENSOR_DEVICE_ATTR(port_45_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 28); +static SENSOR_DEVICE_ATTR(port_46_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 29); +static SENSOR_DEVICE_ATTR(port_47_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 30); +static SENSOR_DEVICE_ATTR(port_48_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 31); + +static struct attribute *swpld2_attributes[] = { + &sensor_dev_attr_scratch.dev_attr.attr, + &sensor_dev_attr_code_ver.dev_attr.attr, + &sensor_dev_attr_board_ver.dev_attr.attr, + &sensor_dev_attr_led_test_amb.dev_attr.attr, + &sensor_dev_attr_led_test_grn.dev_attr.attr, + &sensor_dev_attr_led_test_blink.dev_attr.attr, + &sensor_dev_attr_led_test_src_sel.dev_attr.attr, + &sensor_dev_attr_rst_pld_soft.dev_attr.attr, + + &sensor_dev_attr_port_1_rst.dev_attr.attr, + &sensor_dev_attr_port_2_rst.dev_attr.attr, + &sensor_dev_attr_port_3_rst.dev_attr.attr, + &sensor_dev_attr_port_4_rst.dev_attr.attr, + &sensor_dev_attr_port_5_rst.dev_attr.attr, + &sensor_dev_attr_port_6_rst.dev_attr.attr, + &sensor_dev_attr_port_7_rst.dev_attr.attr, + &sensor_dev_attr_port_8_rst.dev_attr.attr, + &sensor_dev_attr_port_9_rst.dev_attr.attr, + &sensor_dev_attr_port_10_rst.dev_attr.attr, + &sensor_dev_attr_port_11_rst.dev_attr.attr, + &sensor_dev_attr_port_12_rst.dev_attr.attr, + &sensor_dev_attr_port_13_rst.dev_attr.attr, + &sensor_dev_attr_port_14_rst.dev_attr.attr, + &sensor_dev_attr_port_15_rst.dev_attr.attr, + &sensor_dev_attr_port_16_rst.dev_attr.attr, + &sensor_dev_attr_port_33_rst.dev_attr.attr, + &sensor_dev_attr_port_34_rst.dev_attr.attr, + &sensor_dev_attr_port_35_rst.dev_attr.attr, + &sensor_dev_attr_port_36_rst.dev_attr.attr, + &sensor_dev_attr_port_37_rst.dev_attr.attr, + &sensor_dev_attr_port_38_rst.dev_attr.attr, + &sensor_dev_attr_port_39_rst.dev_attr.attr, + &sensor_dev_attr_port_40_rst.dev_attr.attr, + &sensor_dev_attr_port_41_rst.dev_attr.attr, + &sensor_dev_attr_port_42_rst.dev_attr.attr, + &sensor_dev_attr_port_43_rst.dev_attr.attr, + &sensor_dev_attr_port_44_rst.dev_attr.attr, + &sensor_dev_attr_port_45_rst.dev_attr.attr, + &sensor_dev_attr_port_46_rst.dev_attr.attr, + &sensor_dev_attr_port_47_rst.dev_attr.attr, + &sensor_dev_attr_port_48_rst.dev_attr.attr, + + &sensor_dev_attr_port_1_lpmod.dev_attr.attr, + &sensor_dev_attr_port_2_lpmod.dev_attr.attr, + &sensor_dev_attr_port_3_lpmod.dev_attr.attr, + &sensor_dev_attr_port_4_lpmod.dev_attr.attr, + &sensor_dev_attr_port_5_lpmod.dev_attr.attr, + &sensor_dev_attr_port_6_lpmod.dev_attr.attr, + &sensor_dev_attr_port_7_lpmod.dev_attr.attr, + &sensor_dev_attr_port_8_lpmod.dev_attr.attr, + &sensor_dev_attr_port_9_lpmod.dev_attr.attr, + &sensor_dev_attr_port_10_lpmod.dev_attr.attr, + &sensor_dev_attr_port_11_lpmod.dev_attr.attr, + &sensor_dev_attr_port_12_lpmod.dev_attr.attr, + &sensor_dev_attr_port_13_lpmod.dev_attr.attr, + &sensor_dev_attr_port_14_lpmod.dev_attr.attr, + &sensor_dev_attr_port_15_lpmod.dev_attr.attr, + &sensor_dev_attr_port_16_lpmod.dev_attr.attr, + &sensor_dev_attr_port_33_lpmod.dev_attr.attr, + &sensor_dev_attr_port_34_lpmod.dev_attr.attr, + &sensor_dev_attr_port_35_lpmod.dev_attr.attr, + &sensor_dev_attr_port_36_lpmod.dev_attr.attr, + &sensor_dev_attr_port_37_lpmod.dev_attr.attr, + &sensor_dev_attr_port_38_lpmod.dev_attr.attr, + &sensor_dev_attr_port_39_lpmod.dev_attr.attr, + &sensor_dev_attr_port_40_lpmod.dev_attr.attr, + &sensor_dev_attr_port_41_lpmod.dev_attr.attr, + &sensor_dev_attr_port_42_lpmod.dev_attr.attr, + &sensor_dev_attr_port_43_lpmod.dev_attr.attr, + &sensor_dev_attr_port_44_lpmod.dev_attr.attr, + &sensor_dev_attr_port_45_lpmod.dev_attr.attr, + &sensor_dev_attr_port_46_lpmod.dev_attr.attr, + &sensor_dev_attr_port_47_lpmod.dev_attr.attr, + &sensor_dev_attr_port_48_lpmod.dev_attr.attr, + + &sensor_dev_attr_port_1_modsel.dev_attr.attr, + &sensor_dev_attr_port_2_modsel.dev_attr.attr, + &sensor_dev_attr_port_3_modsel.dev_attr.attr, + &sensor_dev_attr_port_4_modsel.dev_attr.attr, + &sensor_dev_attr_port_5_modsel.dev_attr.attr, + &sensor_dev_attr_port_6_modsel.dev_attr.attr, + &sensor_dev_attr_port_7_modsel.dev_attr.attr, + &sensor_dev_attr_port_8_modsel.dev_attr.attr, + &sensor_dev_attr_port_9_modsel.dev_attr.attr, + &sensor_dev_attr_port_10_modsel.dev_attr.attr, + &sensor_dev_attr_port_11_modsel.dev_attr.attr, + &sensor_dev_attr_port_12_modsel.dev_attr.attr, + &sensor_dev_attr_port_13_modsel.dev_attr.attr, + &sensor_dev_attr_port_14_modsel.dev_attr.attr, + &sensor_dev_attr_port_15_modsel.dev_attr.attr, + &sensor_dev_attr_port_16_modsel.dev_attr.attr, + &sensor_dev_attr_port_33_modsel.dev_attr.attr, + &sensor_dev_attr_port_34_modsel.dev_attr.attr, + &sensor_dev_attr_port_35_modsel.dev_attr.attr, + &sensor_dev_attr_port_36_modsel.dev_attr.attr, + &sensor_dev_attr_port_37_modsel.dev_attr.attr, + &sensor_dev_attr_port_38_modsel.dev_attr.attr, + &sensor_dev_attr_port_39_modsel.dev_attr.attr, + &sensor_dev_attr_port_40_modsel.dev_attr.attr, + &sensor_dev_attr_port_41_modsel.dev_attr.attr, + &sensor_dev_attr_port_42_modsel.dev_attr.attr, + &sensor_dev_attr_port_43_modsel.dev_attr.attr, + &sensor_dev_attr_port_44_modsel.dev_attr.attr, + &sensor_dev_attr_port_45_modsel.dev_attr.attr, + &sensor_dev_attr_port_46_modsel.dev_attr.attr, + &sensor_dev_attr_port_47_modsel.dev_attr.attr, + &sensor_dev_attr_port_48_modsel.dev_attr.attr, + + &sensor_dev_attr_port_1_prs.dev_attr.attr, + &sensor_dev_attr_port_2_prs.dev_attr.attr, + &sensor_dev_attr_port_3_prs.dev_attr.attr, + &sensor_dev_attr_port_4_prs.dev_attr.attr, + &sensor_dev_attr_port_5_prs.dev_attr.attr, + &sensor_dev_attr_port_6_prs.dev_attr.attr, + &sensor_dev_attr_port_7_prs.dev_attr.attr, + &sensor_dev_attr_port_8_prs.dev_attr.attr, + &sensor_dev_attr_port_9_prs.dev_attr.attr, + &sensor_dev_attr_port_10_prs.dev_attr.attr, + &sensor_dev_attr_port_11_prs.dev_attr.attr, + &sensor_dev_attr_port_12_prs.dev_attr.attr, + &sensor_dev_attr_port_13_prs.dev_attr.attr, + &sensor_dev_attr_port_14_prs.dev_attr.attr, + &sensor_dev_attr_port_15_prs.dev_attr.attr, + &sensor_dev_attr_port_16_prs.dev_attr.attr, + &sensor_dev_attr_port_33_prs.dev_attr.attr, + &sensor_dev_attr_port_34_prs.dev_attr.attr, + &sensor_dev_attr_port_35_prs.dev_attr.attr, + &sensor_dev_attr_port_36_prs.dev_attr.attr, + &sensor_dev_attr_port_37_prs.dev_attr.attr, + &sensor_dev_attr_port_38_prs.dev_attr.attr, + &sensor_dev_attr_port_39_prs.dev_attr.attr, + &sensor_dev_attr_port_40_prs.dev_attr.attr, + &sensor_dev_attr_port_41_prs.dev_attr.attr, + &sensor_dev_attr_port_42_prs.dev_attr.attr, + &sensor_dev_attr_port_43_prs.dev_attr.attr, + &sensor_dev_attr_port_44_prs.dev_attr.attr, + &sensor_dev_attr_port_45_prs.dev_attr.attr, + &sensor_dev_attr_port_46_prs.dev_attr.attr, + &sensor_dev_attr_port_47_prs.dev_attr.attr, + &sensor_dev_attr_port_48_prs.dev_attr.attr, + + &sensor_dev_attr_modprs_reg1.dev_attr.attr, + &sensor_dev_attr_modprs_reg2.dev_attr.attr, + &sensor_dev_attr_modprs_reg3.dev_attr.attr, + &sensor_dev_attr_modprs_reg4.dev_attr.attr, + + &sensor_dev_attr_port_65_tx_fault.dev_attr.attr, + &sensor_dev_attr_port_65_rx_los.dev_attr.attr, + &sensor_dev_attr_port_65_prs.dev_attr.attr, + &sensor_dev_attr_port_66_tx_fault.dev_attr.attr, + &sensor_dev_attr_port_66_rx_los.dev_attr.attr, + &sensor_dev_attr_port_66_prs.dev_attr.attr, + &sensor_dev_attr_port_65_tx_en.dev_attr.attr, + &sensor_dev_attr_port_65_led.dev_attr.attr, + &sensor_dev_attr_port_66_tx_en.dev_attr.attr, + &sensor_dev_attr_port_66_led.dev_attr.attr, + + &sensor_dev_attr_code_day.dev_attr.attr, + &sensor_dev_attr_code_month.dev_attr.attr, + &sensor_dev_attr_code_year.dev_attr.attr, + + &sensor_dev_attr_port_1_reset.dev_attr.attr, + &sensor_dev_attr_port_2_reset.dev_attr.attr, + &sensor_dev_attr_port_3_reset.dev_attr.attr, + &sensor_dev_attr_port_4_reset.dev_attr.attr, + &sensor_dev_attr_port_5_reset.dev_attr.attr, + &sensor_dev_attr_port_6_reset.dev_attr.attr, + &sensor_dev_attr_port_7_reset.dev_attr.attr, + &sensor_dev_attr_port_8_reset.dev_attr.attr, + &sensor_dev_attr_port_9_reset.dev_attr.attr, + &sensor_dev_attr_port_10_reset.dev_attr.attr, + &sensor_dev_attr_port_11_reset.dev_attr.attr, + &sensor_dev_attr_port_12_reset.dev_attr.attr, + &sensor_dev_attr_port_13_reset.dev_attr.attr, + &sensor_dev_attr_port_14_reset.dev_attr.attr, + &sensor_dev_attr_port_15_reset.dev_attr.attr, + &sensor_dev_attr_port_16_reset.dev_attr.attr, + &sensor_dev_attr_port_33_reset.dev_attr.attr, + &sensor_dev_attr_port_34_reset.dev_attr.attr, + &sensor_dev_attr_port_35_reset.dev_attr.attr, + &sensor_dev_attr_port_36_reset.dev_attr.attr, + &sensor_dev_attr_port_37_reset.dev_attr.attr, + &sensor_dev_attr_port_38_reset.dev_attr.attr, + &sensor_dev_attr_port_39_reset.dev_attr.attr, + &sensor_dev_attr_port_40_reset.dev_attr.attr, + &sensor_dev_attr_port_41_reset.dev_attr.attr, + &sensor_dev_attr_port_42_reset.dev_attr.attr, + &sensor_dev_attr_port_43_reset.dev_attr.attr, + &sensor_dev_attr_port_44_reset.dev_attr.attr, + &sensor_dev_attr_port_45_reset.dev_attr.attr, + &sensor_dev_attr_port_46_reset.dev_attr.attr, + &sensor_dev_attr_port_47_reset.dev_attr.attr, + &sensor_dev_attr_port_48_reset.dev_attr.attr, + + &sensor_dev_attr_port_1_led.dev_attr.attr, + &sensor_dev_attr_port_2_led.dev_attr.attr, + &sensor_dev_attr_port_3_led.dev_attr.attr, + &sensor_dev_attr_port_4_led.dev_attr.attr, + &sensor_dev_attr_port_5_led.dev_attr.attr, + &sensor_dev_attr_port_6_led.dev_attr.attr, + &sensor_dev_attr_port_7_led.dev_attr.attr, + &sensor_dev_attr_port_8_led.dev_attr.attr, + &sensor_dev_attr_port_9_led.dev_attr.attr, + &sensor_dev_attr_port_10_led.dev_attr.attr, + &sensor_dev_attr_port_11_led.dev_attr.attr, + &sensor_dev_attr_port_12_led.dev_attr.attr, + &sensor_dev_attr_port_13_led.dev_attr.attr, + &sensor_dev_attr_port_14_led.dev_attr.attr, + &sensor_dev_attr_port_15_led.dev_attr.attr, + &sensor_dev_attr_port_16_led.dev_attr.attr, + &sensor_dev_attr_port_33_led.dev_attr.attr, + &sensor_dev_attr_port_34_led.dev_attr.attr, + &sensor_dev_attr_port_35_led.dev_attr.attr, + &sensor_dev_attr_port_36_led.dev_attr.attr, + &sensor_dev_attr_port_37_led.dev_attr.attr, + &sensor_dev_attr_port_38_led.dev_attr.attr, + &sensor_dev_attr_port_39_led.dev_attr.attr, + &sensor_dev_attr_port_40_led.dev_attr.attr, + &sensor_dev_attr_port_41_led.dev_attr.attr, + &sensor_dev_attr_port_42_led.dev_attr.attr, + &sensor_dev_attr_port_43_led.dev_attr.attr, + &sensor_dev_attr_port_44_led.dev_attr.attr, + &sensor_dev_attr_port_45_led.dev_attr.attr, + &sensor_dev_attr_port_46_led.dev_attr.attr, + &sensor_dev_attr_port_47_led.dev_attr.attr, + &sensor_dev_attr_port_48_led.dev_attr.attr, + + &sensor_dev_attr_port_1_brknum.dev_attr.attr, + &sensor_dev_attr_port_2_brknum.dev_attr.attr, + &sensor_dev_attr_port_3_brknum.dev_attr.attr, + &sensor_dev_attr_port_4_brknum.dev_attr.attr, + &sensor_dev_attr_port_5_brknum.dev_attr.attr, + &sensor_dev_attr_port_6_brknum.dev_attr.attr, + &sensor_dev_attr_port_7_brknum.dev_attr.attr, + &sensor_dev_attr_port_8_brknum.dev_attr.attr, + &sensor_dev_attr_port_9_brknum.dev_attr.attr, + &sensor_dev_attr_port_10_brknum.dev_attr.attr, + &sensor_dev_attr_port_11_brknum.dev_attr.attr, + &sensor_dev_attr_port_12_brknum.dev_attr.attr, + &sensor_dev_attr_port_13_brknum.dev_attr.attr, + &sensor_dev_attr_port_14_brknum.dev_attr.attr, + &sensor_dev_attr_port_15_brknum.dev_attr.attr, + &sensor_dev_attr_port_16_brknum.dev_attr.attr, + &sensor_dev_attr_port_33_brknum.dev_attr.attr, + &sensor_dev_attr_port_34_brknum.dev_attr.attr, + &sensor_dev_attr_port_35_brknum.dev_attr.attr, + &sensor_dev_attr_port_36_brknum.dev_attr.attr, + &sensor_dev_attr_port_37_brknum.dev_attr.attr, + &sensor_dev_attr_port_38_brknum.dev_attr.attr, + &sensor_dev_attr_port_39_brknum.dev_attr.attr, + &sensor_dev_attr_port_40_brknum.dev_attr.attr, + &sensor_dev_attr_port_41_brknum.dev_attr.attr, + &sensor_dev_attr_port_42_brknum.dev_attr.attr, + &sensor_dev_attr_port_43_brknum.dev_attr.attr, + &sensor_dev_attr_port_44_brknum.dev_attr.attr, + &sensor_dev_attr_port_45_brknum.dev_attr.attr, + &sensor_dev_attr_port_46_brknum.dev_attr.attr, + &sensor_dev_attr_port_47_brknum.dev_attr.attr, + &sensor_dev_attr_port_48_brknum.dev_attr.attr, + + NULL +}; + +static const struct attribute_group swpld2_group = { + .attrs = swpld2_attributes, +}; + +static int swpld2_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct cpld_data *data = NULL; + int i; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia SWPLD2 chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &swpld2_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + dump_reg(data); + dev_info(&client->dev, "[SWPLD2]Reseting PORTs ...\n"); + cpld_i2c_write(data, QSFP_MODSEL_REG0, 0xFF); + cpld_i2c_write(data, QSFP_MODSEL_REG1, 0xFF); + cpld_i2c_write(data, QSFP_MODSEL_REG2, 0xFF); + cpld_i2c_write(data, QSFP_MODSEL_REG3, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG0, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG1, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG2, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG3, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG0, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG1, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG2, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG3, 0xFF); + msleep(500); + cpld_i2c_write(data, QSFP_RST_REG0, 0x0); + cpld_i2c_write(data, QSFP_RST_REG1, 0x0); + cpld_i2c_write(data, QSFP_RST_REG2, 0x0); + cpld_i2c_write(data, QSFP_RST_REG3, 0x0); + dev_info(&client->dev, "[SWPLD2]PORTs reset done.\n"); + cpld_i2c_write(data, SFP_CTRL_REG, 0x0); + dump_reg(data); + for (i=0;i<32;i++) data->reset_list[i] = 0; + + return 0; + +exit: + return status; +} + +static void swpld2_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &swpld2_group); + kfree(data); +} + +static const struct of_device_id swpld2_of_ids[] = { + { + .compatible = "nokia,swpld2", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, swpld2_of_ids); + +static const struct i2c_device_id swpld2_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, swpld2_ids); + +static struct i2c_driver swpld2_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(swpld2_of_ids), + }, + .probe = swpld2_probe, + .remove = swpld2_remove, + .id_table = swpld2_ids, + .address_list = cpld_address_list, +}; + +static int __init swpld2_init(void) +{ + return i2c_add_driver(&swpld2_driver); +} + +static void __exit swpld2_exit(void) +{ + i2c_del_driver(&swpld2_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(swpld2_init); +module_exit(swpld2_exit); + diff --git a/ixr7220h5-64d/modules/swpld3.c b/ixr7220h5-64d/modules/swpld3.c new file mode 100644 index 0000000..69fc7a8 --- /dev/null +++ b/ixr7220h5-64d/modules/swpld3.c @@ -0,0 +1,1564 @@ +// * CPLD driver for Nokia-7220-IXR-H5-64D Router +// * +// * Copyright (C) 2024 Nokia Corporation. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * 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. +// * see + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "swpld3" + +// REGISTERS ADDRESS MAP +#define SCRATCH_REG 0x00 +#define CODE_REV_REG 0x01 +#define BOARD_REV_REG 0x02 +#define BOARD_CFG_REG 0x03 +#define SYS_EEPROM_REG 0x05 +#define BOARD_CTRL_REG 0x07 +#define LED_TEST_REG 0x08 +#define RST_PLD_REG 0x10 +#define INT_CLR_REG 0x20 +#define INT_MSK_REG 0x21 +#define INT_REG 0x22 +#define PLD_INT_REG0 0x23 +#define PLD_INT_REG1 0x24 +#define PLD_INT_REG2 0x25 +#define PLD_INT_REG3 0x26 +#define QSFP_PRS_INT_REG0 0x28 +#define QSFP_PRS_INT_REG1 0x29 +#define QSFP_PRS_INT_REG2 0x2A +#define QSFP_PRS_INT_REG3 0x2B +#define QSFP_INT_EVT_REG0 0x2C +#define QSFP_INT_EVT_REG1 0x2D +#define QSFP_INT_EVT_REG2 0x2E +#define QSFP_INT_EVT_REG3 0x2F +#define QSFP_RST_REG0 0x30 +#define QSFP_RST_REG1 0x31 +#define QSFP_RST_REG2 0x32 +#define QSFP_RST_REG3 0x33 +#define QSFP_LPMODE_REG0 0x34 +#define QSFP_LPMODE_REG1 0x35 +#define QSFP_LPMODE_REG2 0x36 +#define QSFP_LPMODE_REG3 0x37 +#define QSFP_MODSEL_REG0 0x38 +#define QSFP_MODSEL_REG1 0x39 +#define QSFP_MODSEL_REG2 0x3A +#define QSFP_MODSEL_REG3 0x3B +#define QSFP_MODPRS_REG0 0x3C +#define QSFP_MODPRS_REG1 0x3D +#define QSFP_MODPRS_REG2 0x3E +#define QSFP_MODPRS_REG3 0x3F +#define QSFP_INT_STAT_REG0 0x40 +#define QSFP_INT_STAT_REG1 0x41 +#define QSFP_INT_STAT_REG2 0x42 +#define QSFP_INT_STAT_REG3 0x43 +#define PERIF_STAT_REG0 0x50 +#define PERIF_STAT_REG1 0x51 +#define PERIF_STAT_REG2 0x54 +#define PERIF_STAT_REG3 0x55 +#define PWR_STATUS_REG0 0x68 +#define PWR_STATUS_REG1 0x69 +#define QSFP_LED_REG1 0x90 +#define QSFP_BRKNUM_REG1 0xD0 +#define CODE_DAY_REG 0xF0 +#define CODE_MONTH_REG 0xF1 +#define CODE_YEAR_REG 0xF2 +#define TEST_CODE_REV_REG 0xF3 + +// REG BIT FIELD POSITION or MASK +#define BOARD_REV_REG_VER_MSK 0x7 + +#define LED_TEST_REG_AMB 0x0 +#define LED_TEST_REG_GRN 0x1 +#define LED_TEST_REG_BLINK 0x3 +#define LED_TEST_REG_SRC_SEL 0x7 + +#define RST_PLD_REG_SOFT_RST 0x0 + +// common index of each qsfp modules +#define QSFP17_INDEX 0x0 +#define QSFP18_INDEX 0x1 +#define QSFP19_INDEX 0x2 +#define QSFP20_INDEX 0x3 +#define QSFP21_INDEX 0x4 +#define QSFP22_INDEX 0x5 +#define QSFP23_INDEX 0x6 +#define QSFP24_INDEX 0x7 +#define QSFP25_INDEX 0x0 +#define QSFP26_INDEX 0x1 +#define QSFP27_INDEX 0x2 +#define QSFP28_INDEX 0x3 +#define QSFP29_INDEX 0x4 +#define QSFP30_INDEX 0x5 +#define QSFP31_INDEX 0x6 +#define QSFP32_INDEX 0x7 +#define QSFP49_INDEX 0x0 +#define QSFP50_INDEX 0x1 +#define QSFP51_INDEX 0x2 +#define QSFP52_INDEX 0x3 +#define QSFP53_INDEX 0x4 +#define QSFP54_INDEX 0x5 +#define QSFP55_INDEX 0x6 +#define QSFP56_INDEX 0x7 +#define QSFP57_INDEX 0x0 +#define QSFP58_INDEX 0x1 +#define QSFP59_INDEX 0x2 +#define QSFP60_INDEX 0x3 +#define QSFP61_INDEX 0x4 +#define QSFP62_INDEX 0x5 +#define QSFP63_INDEX 0x6 +#define QSFP64_INDEX 0x7 + +static const unsigned short cpld_address_list[] = {0x45, I2C_CLIENT_END}; + +struct cpld_data { + struct i2c_client *client; + struct mutex update_lock; + int reset_list[32]; +}; + +static int cpld_i2c_read(struct cpld_data *data, u8 reg) +{ + int val = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_err(&client->dev, "CPLD READ ERROR: reg(0x%02x) err %d\n", reg, val); + } + mutex_unlock(&data->update_lock); + + return val; +} + +static void cpld_i2c_write(struct cpld_data *data, u8 reg, u8 value) +{ + int res = 0; + struct i2c_client *client = data->client; + + mutex_lock(&data->update_lock); + res = i2c_smbus_write_byte_data(client, reg, value); + if (res < 0) { + dev_err(&client->dev, "CPLD WRITE ERROR: reg(0x%02x) err %d\n", reg, res); + } + mutex_unlock(&data->update_lock); +} + +static void dump_reg(struct cpld_data *data) +{ + struct i2c_client *client = data->client; + u8 val0 = 0; + u8 val1 = 0; + u8 val2 = 0; + u8 val3 = 0; + + + val0 = cpld_i2c_read(data, QSFP_RST_REG0); + val1 = cpld_i2c_read(data, QSFP_RST_REG1); + val2 = cpld_i2c_read(data, QSFP_RST_REG2); + val3 = cpld_i2c_read(data, QSFP_RST_REG3); + dev_info(&client->dev, "[SWPLD3]QSFP_RESET_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, QSFP_LPMODE_REG0); + val1 = cpld_i2c_read(data, QSFP_LPMODE_REG1); + val2 = cpld_i2c_read(data, QSFP_LPMODE_REG2); + val3 = cpld_i2c_read(data, QSFP_LPMODE_REG3); + dev_info(&client->dev, "[SWPLD3]QSFP_LPMODE_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, QSFP_MODSEL_REG0); + val1 = cpld_i2c_read(data, QSFP_MODSEL_REG1); + val2 = cpld_i2c_read(data, QSFP_MODSEL_REG2); + val3 = cpld_i2c_read(data, QSFP_MODSEL_REG3); + dev_info(&client->dev, "[SWPLD3]QSFP_MODSEL_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + + val0 = cpld_i2c_read(data, QSFP_MODPRS_REG0); + val1 = cpld_i2c_read(data, QSFP_MODPRS_REG1); + val2 = cpld_i2c_read(data, QSFP_MODPRS_REG2); + val3 = cpld_i2c_read(data, QSFP_MODPRS_REG3); + dev_info(&client->dev, "[SWPLD3]QSFP_MODPRES_REG: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", val0, val1, val2, val3); + +} + +static ssize_t show_scratch(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, SCRATCH_REG); + + return sprintf(buf, "%02x\n", val); +} + +static ssize_t set_scratch(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + cpld_i2c_write(data, SCRATCH_REG, usr_val); + + return count; +} + +static ssize_t show_code_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_REV_REG); + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_board_ver(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, BOARD_REV_REG) & BOARD_REV_REG_VER_MSK; + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_led_test(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + val = cpld_i2c_read(data, LED_TEST_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_led_test(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, LED_TEST_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, LED_TEST_REG, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_rst(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + val = cpld_i2c_read(data, RST_PLD_REG); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_rst(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, RST_PLD_REG); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, RST_PLD_REG, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG0); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG1); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG2); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG2, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_rst3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_RST_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_rst3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_RST_REG3); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_RST_REG3, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG0); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG1); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG2); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG2, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_lpmode3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_LPMODE_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_lpmode3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_LPMODE_REG3); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_LPMODE_REG3, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel0(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG0); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG0, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel1(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG1); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG1, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel2(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG2); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG2, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_modsel3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODSEL_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t set_qsfp_modsel3(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 1) { + return -EINVAL; + } + + mask = (~(1 << sda->index)) & 0xFF; + reg_val = cpld_i2c_read(data, QSFP_MODSEL_REG3); + reg_val = reg_val & mask; + usr_val = usr_val << sda->index; + cpld_i2c_write(data, QSFP_MODSEL_REG3, (reg_val | usr_val)); + + return count; +} + +static ssize_t show_qsfp_prs0(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG0); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_qsfp_prs1(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG1); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_qsfp_prs2(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG2); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_qsfp_prs3(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + val = cpld_i2c_read(data, QSFP_MODPRS_REG3); + + return sprintf(buf, "%d\n", (val>>sda->index) & 0x1 ? 1:0); +} + +static ssize_t show_modprs_reg(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + + if (sda->index == 1) + val = cpld_i2c_read(data, QSFP_MODPRS_REG0); + if (sda->index == 2) + val = cpld_i2c_read(data, QSFP_MODPRS_REG1); + if (sda->index == 3) + val = cpld_i2c_read(data, QSFP_MODPRS_REG2); + if (sda->index == 4) + val = cpld_i2c_read(data, QSFP_MODPRS_REG3); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t show_code_day(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_DAY_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_code_month(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_MONTH_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_code_year(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + u8 val = 0; + + val = cpld_i2c_read(data, CODE_YEAR_REG); + return sprintf(buf, "%d\n", val); +} + +static ssize_t show_qsfp_reset(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + + return sprintf(buf, "%d\n", data->reset_list[sda->index]); +} + +static ssize_t set_qsfp_reset(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 usr_val = 0; + + int ret = kstrtou8(buf, 10, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFF) { + return -EINVAL; + } + + data->reset_list[sda->index] = usr_val; + return count; +} + +static ssize_t show_qsfp_led(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val1 = 0; + u8 val2 = 0; + + val1 = cpld_i2c_read(data, QSFP_LED_REG1 + sda->index * 2); + val2 = cpld_i2c_read(data, QSFP_LED_REG1 + sda->index * 2 + 1); + + return sprintf(buf, "0x%02x%02x\n", val2, val1); +} + +static ssize_t set_qsfp_led(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u16 usr_val = 0; + u8 val = 0; + + int ret = kstrtou16(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xFFFF) { + return -EINVAL; + } + + val = usr_val & 0xFF; + cpld_i2c_write(data, QSFP_LED_REG1 + sda->index*2, val); + val = (usr_val & 0xFF00) >> 8; + cpld_i2c_write(data, QSFP_LED_REG1 + sda->index*2 + 1, val); + + return count; +} + +static ssize_t show_qsfp_brknum(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 val = 0; + int reg_index; + int bit_index; + + reg_index = QSFP_BRKNUM_REG1 + (int)(sda->index/2); + val = cpld_i2c_read(data, reg_index); + bit_index = sda->index%2 * 4; + + return sprintf(buf, "0x%x\n", val>>bit_index & 0xF); +} + +static ssize_t set_qsfp_brknum(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct sensor_device_attribute *sda = to_sensor_dev_attr(devattr); + u8 reg_val = 0; + u8 usr_val = 0; + u8 mask; + int reg_index; + int bit_index; + + reg_index = QSFP_BRKNUM_REG1 + (int)(sda->index/2); + bit_index = sda->index%2 * 4; + + int ret = kstrtou8(buf, 16, &usr_val); + if (ret != 0) { + return ret; + } + if (usr_val > 0xF) { + return -EINVAL; + } + + mask = (~(7 << bit_index)) & 0xFF; + reg_val = cpld_i2c_read(data, reg_index); + reg_val = reg_val & mask; + usr_val = usr_val << bit_index; + cpld_i2c_write(data, reg_index, (reg_val | usr_val)); + + return count; +} + +// sysfs attributes +static SENSOR_DEVICE_ATTR(scratch, S_IRUGO | S_IWUSR, show_scratch, set_scratch, 0); +static SENSOR_DEVICE_ATTR(code_ver, S_IRUGO, show_code_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(board_ver, S_IRUGO, show_board_ver, NULL, 0); +static SENSOR_DEVICE_ATTR(led_test_amb, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_AMB); +static SENSOR_DEVICE_ATTR(led_test_grn, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_GRN); +static SENSOR_DEVICE_ATTR(led_test_blink, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_BLINK); +static SENSOR_DEVICE_ATTR(led_test_src_sel, S_IRUGO | S_IWUSR, show_led_test, set_led_test, LED_TEST_REG_SRC_SEL); +static SENSOR_DEVICE_ATTR(rst_pld_soft, S_IRUGO | S_IWUSR, show_rst, set_rst, RST_PLD_REG_SOFT_RST); + +static SENSOR_DEVICE_ATTR(port_17_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP17_INDEX); +static SENSOR_DEVICE_ATTR(port_18_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP18_INDEX); +static SENSOR_DEVICE_ATTR(port_19_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP19_INDEX); +static SENSOR_DEVICE_ATTR(port_20_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP20_INDEX); +static SENSOR_DEVICE_ATTR(port_21_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP21_INDEX); +static SENSOR_DEVICE_ATTR(port_22_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP22_INDEX); +static SENSOR_DEVICE_ATTR(port_23_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP23_INDEX); +static SENSOR_DEVICE_ATTR(port_24_rst, S_IRUGO | S_IWUSR, show_qsfp_rst0, set_qsfp_rst0, QSFP24_INDEX); +static SENSOR_DEVICE_ATTR(port_25_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP25_INDEX); +static SENSOR_DEVICE_ATTR(port_26_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP26_INDEX); +static SENSOR_DEVICE_ATTR(port_27_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP27_INDEX); +static SENSOR_DEVICE_ATTR(port_28_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP28_INDEX); +static SENSOR_DEVICE_ATTR(port_29_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP29_INDEX); +static SENSOR_DEVICE_ATTR(port_30_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP30_INDEX); +static SENSOR_DEVICE_ATTR(port_31_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP31_INDEX); +static SENSOR_DEVICE_ATTR(port_32_rst, S_IRUGO | S_IWUSR, show_qsfp_rst1, set_qsfp_rst1, QSFP32_INDEX); +static SENSOR_DEVICE_ATTR(port_49_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP49_INDEX); +static SENSOR_DEVICE_ATTR(port_50_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP50_INDEX); +static SENSOR_DEVICE_ATTR(port_51_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP51_INDEX); +static SENSOR_DEVICE_ATTR(port_52_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP52_INDEX); +static SENSOR_DEVICE_ATTR(port_53_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP53_INDEX); +static SENSOR_DEVICE_ATTR(port_54_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP54_INDEX); +static SENSOR_DEVICE_ATTR(port_55_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP55_INDEX); +static SENSOR_DEVICE_ATTR(port_56_rst, S_IRUGO | S_IWUSR, show_qsfp_rst2, set_qsfp_rst2, QSFP56_INDEX); +static SENSOR_DEVICE_ATTR(port_57_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP57_INDEX); +static SENSOR_DEVICE_ATTR(port_58_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP58_INDEX); +static SENSOR_DEVICE_ATTR(port_59_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP59_INDEX); +static SENSOR_DEVICE_ATTR(port_60_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP60_INDEX); +static SENSOR_DEVICE_ATTR(port_61_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP61_INDEX); +static SENSOR_DEVICE_ATTR(port_62_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP62_INDEX); +static SENSOR_DEVICE_ATTR(port_63_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP63_INDEX); +static SENSOR_DEVICE_ATTR(port_64_rst, S_IRUGO | S_IWUSR, show_qsfp_rst3, set_qsfp_rst3, QSFP64_INDEX); + +static SENSOR_DEVICE_ATTR(port_17_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP17_INDEX); +static SENSOR_DEVICE_ATTR(port_18_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP18_INDEX); +static SENSOR_DEVICE_ATTR(port_19_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP19_INDEX); +static SENSOR_DEVICE_ATTR(port_20_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP20_INDEX); +static SENSOR_DEVICE_ATTR(port_21_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP21_INDEX); +static SENSOR_DEVICE_ATTR(port_22_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP22_INDEX); +static SENSOR_DEVICE_ATTR(port_23_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP23_INDEX); +static SENSOR_DEVICE_ATTR(port_24_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode0, set_qsfp_lpmode0, QSFP24_INDEX); +static SENSOR_DEVICE_ATTR(port_25_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP25_INDEX); +static SENSOR_DEVICE_ATTR(port_26_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP26_INDEX); +static SENSOR_DEVICE_ATTR(port_27_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP27_INDEX); +static SENSOR_DEVICE_ATTR(port_28_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP28_INDEX); +static SENSOR_DEVICE_ATTR(port_29_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP29_INDEX); +static SENSOR_DEVICE_ATTR(port_30_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP30_INDEX); +static SENSOR_DEVICE_ATTR(port_31_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP31_INDEX); +static SENSOR_DEVICE_ATTR(port_32_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode1, set_qsfp_lpmode1, QSFP32_INDEX); +static SENSOR_DEVICE_ATTR(port_49_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP49_INDEX); +static SENSOR_DEVICE_ATTR(port_50_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP50_INDEX); +static SENSOR_DEVICE_ATTR(port_51_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP51_INDEX); +static SENSOR_DEVICE_ATTR(port_52_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP52_INDEX); +static SENSOR_DEVICE_ATTR(port_53_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP53_INDEX); +static SENSOR_DEVICE_ATTR(port_54_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP54_INDEX); +static SENSOR_DEVICE_ATTR(port_55_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP55_INDEX); +static SENSOR_DEVICE_ATTR(port_56_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode2, set_qsfp_lpmode2, QSFP56_INDEX); +static SENSOR_DEVICE_ATTR(port_57_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP57_INDEX); +static SENSOR_DEVICE_ATTR(port_58_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP58_INDEX); +static SENSOR_DEVICE_ATTR(port_59_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP59_INDEX); +static SENSOR_DEVICE_ATTR(port_60_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP60_INDEX); +static SENSOR_DEVICE_ATTR(port_61_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP61_INDEX); +static SENSOR_DEVICE_ATTR(port_62_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP62_INDEX); +static SENSOR_DEVICE_ATTR(port_63_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP63_INDEX); +static SENSOR_DEVICE_ATTR(port_64_lpmod, S_IRUGO | S_IWUSR, show_qsfp_lpmode3, set_qsfp_lpmode3, QSFP64_INDEX); + +static SENSOR_DEVICE_ATTR(port_17_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP17_INDEX); +static SENSOR_DEVICE_ATTR(port_18_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP18_INDEX); +static SENSOR_DEVICE_ATTR(port_19_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP19_INDEX); +static SENSOR_DEVICE_ATTR(port_20_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP20_INDEX); +static SENSOR_DEVICE_ATTR(port_21_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP21_INDEX); +static SENSOR_DEVICE_ATTR(port_22_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP22_INDEX); +static SENSOR_DEVICE_ATTR(port_23_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP23_INDEX); +static SENSOR_DEVICE_ATTR(port_24_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel0, set_qsfp_modsel0, QSFP24_INDEX); +static SENSOR_DEVICE_ATTR(port_25_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP25_INDEX); +static SENSOR_DEVICE_ATTR(port_26_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP26_INDEX); +static SENSOR_DEVICE_ATTR(port_27_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP27_INDEX); +static SENSOR_DEVICE_ATTR(port_28_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP28_INDEX); +static SENSOR_DEVICE_ATTR(port_29_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP29_INDEX); +static SENSOR_DEVICE_ATTR(port_30_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP30_INDEX); +static SENSOR_DEVICE_ATTR(port_31_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP31_INDEX); +static SENSOR_DEVICE_ATTR(port_32_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel1, set_qsfp_modsel1, QSFP32_INDEX); +static SENSOR_DEVICE_ATTR(port_49_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP49_INDEX); +static SENSOR_DEVICE_ATTR(port_50_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP50_INDEX); +static SENSOR_DEVICE_ATTR(port_51_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP51_INDEX); +static SENSOR_DEVICE_ATTR(port_52_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP52_INDEX); +static SENSOR_DEVICE_ATTR(port_53_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP53_INDEX); +static SENSOR_DEVICE_ATTR(port_54_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP54_INDEX); +static SENSOR_DEVICE_ATTR(port_55_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP55_INDEX); +static SENSOR_DEVICE_ATTR(port_56_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel2, set_qsfp_modsel2, QSFP56_INDEX); +static SENSOR_DEVICE_ATTR(port_57_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP57_INDEX); +static SENSOR_DEVICE_ATTR(port_58_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP58_INDEX); +static SENSOR_DEVICE_ATTR(port_59_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP59_INDEX); +static SENSOR_DEVICE_ATTR(port_60_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP60_INDEX); +static SENSOR_DEVICE_ATTR(port_61_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP61_INDEX); +static SENSOR_DEVICE_ATTR(port_62_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP62_INDEX); +static SENSOR_DEVICE_ATTR(port_63_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP63_INDEX); +static SENSOR_DEVICE_ATTR(port_64_modsel, S_IRUGO | S_IWUSR, show_qsfp_modsel3, set_qsfp_modsel3, QSFP64_INDEX); + +static SENSOR_DEVICE_ATTR(port_17_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP17_INDEX); +static SENSOR_DEVICE_ATTR(port_18_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP18_INDEX); +static SENSOR_DEVICE_ATTR(port_19_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP19_INDEX); +static SENSOR_DEVICE_ATTR(port_20_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP20_INDEX); +static SENSOR_DEVICE_ATTR(port_21_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP21_INDEX); +static SENSOR_DEVICE_ATTR(port_22_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP22_INDEX); +static SENSOR_DEVICE_ATTR(port_23_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP23_INDEX); +static SENSOR_DEVICE_ATTR(port_24_prs, S_IRUGO, show_qsfp_prs0, NULL, QSFP24_INDEX); +static SENSOR_DEVICE_ATTR(port_25_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP25_INDEX); +static SENSOR_DEVICE_ATTR(port_26_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP26_INDEX); +static SENSOR_DEVICE_ATTR(port_27_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP27_INDEX); +static SENSOR_DEVICE_ATTR(port_28_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP28_INDEX); +static SENSOR_DEVICE_ATTR(port_29_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP29_INDEX); +static SENSOR_DEVICE_ATTR(port_30_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP30_INDEX); +static SENSOR_DEVICE_ATTR(port_31_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP31_INDEX); +static SENSOR_DEVICE_ATTR(port_32_prs, S_IRUGO, show_qsfp_prs1, NULL, QSFP32_INDEX); +static SENSOR_DEVICE_ATTR(port_49_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP49_INDEX); +static SENSOR_DEVICE_ATTR(port_50_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP50_INDEX); +static SENSOR_DEVICE_ATTR(port_51_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP51_INDEX); +static SENSOR_DEVICE_ATTR(port_52_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP52_INDEX); +static SENSOR_DEVICE_ATTR(port_53_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP53_INDEX); +static SENSOR_DEVICE_ATTR(port_54_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP54_INDEX); +static SENSOR_DEVICE_ATTR(port_55_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP55_INDEX); +static SENSOR_DEVICE_ATTR(port_56_prs, S_IRUGO, show_qsfp_prs2, NULL, QSFP56_INDEX); +static SENSOR_DEVICE_ATTR(port_57_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP57_INDEX); +static SENSOR_DEVICE_ATTR(port_58_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP58_INDEX); +static SENSOR_DEVICE_ATTR(port_59_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP59_INDEX); +static SENSOR_DEVICE_ATTR(port_60_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP60_INDEX); +static SENSOR_DEVICE_ATTR(port_61_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP61_INDEX); +static SENSOR_DEVICE_ATTR(port_62_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP62_INDEX); +static SENSOR_DEVICE_ATTR(port_63_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP63_INDEX); +static SENSOR_DEVICE_ATTR(port_64_prs, S_IRUGO, show_qsfp_prs3, NULL, QSFP64_INDEX); + +static SENSOR_DEVICE_ATTR(modprs_reg1, S_IRUGO, show_modprs_reg, NULL, 1); +static SENSOR_DEVICE_ATTR(modprs_reg2, S_IRUGO, show_modprs_reg, NULL, 2); +static SENSOR_DEVICE_ATTR(modprs_reg3, S_IRUGO, show_modprs_reg, NULL, 3); +static SENSOR_DEVICE_ATTR(modprs_reg4, S_IRUGO, show_modprs_reg, NULL, 4); + +static SENSOR_DEVICE_ATTR(code_day, S_IRUGO, show_code_day, NULL, 0); +static SENSOR_DEVICE_ATTR(code_month, S_IRUGO, show_code_month, NULL, 0); +static SENSOR_DEVICE_ATTR(code_year, S_IRUGO, show_code_year, NULL, 0); + +static SENSOR_DEVICE_ATTR(port_17_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 0); +static SENSOR_DEVICE_ATTR(port_18_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 1); +static SENSOR_DEVICE_ATTR(port_19_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 2); +static SENSOR_DEVICE_ATTR(port_20_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 3); +static SENSOR_DEVICE_ATTR(port_21_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 4); +static SENSOR_DEVICE_ATTR(port_22_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 5); +static SENSOR_DEVICE_ATTR(port_23_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 6); +static SENSOR_DEVICE_ATTR(port_24_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 7); +static SENSOR_DEVICE_ATTR(port_25_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 8); +static SENSOR_DEVICE_ATTR(port_26_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 9); +static SENSOR_DEVICE_ATTR(port_27_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 10); +static SENSOR_DEVICE_ATTR(port_28_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 11); +static SENSOR_DEVICE_ATTR(port_29_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 12); +static SENSOR_DEVICE_ATTR(port_30_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 13); +static SENSOR_DEVICE_ATTR(port_31_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 14); +static SENSOR_DEVICE_ATTR(port_32_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 15); +static SENSOR_DEVICE_ATTR(port_49_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 16); +static SENSOR_DEVICE_ATTR(port_50_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 17); +static SENSOR_DEVICE_ATTR(port_51_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 18); +static SENSOR_DEVICE_ATTR(port_52_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 19); +static SENSOR_DEVICE_ATTR(port_53_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 20); +static SENSOR_DEVICE_ATTR(port_54_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 21); +static SENSOR_DEVICE_ATTR(port_55_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 22); +static SENSOR_DEVICE_ATTR(port_56_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 23); +static SENSOR_DEVICE_ATTR(port_57_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 24); +static SENSOR_DEVICE_ATTR(port_58_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 25); +static SENSOR_DEVICE_ATTR(port_59_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 26); +static SENSOR_DEVICE_ATTR(port_60_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 27); +static SENSOR_DEVICE_ATTR(port_61_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 28); +static SENSOR_DEVICE_ATTR(port_62_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 29); +static SENSOR_DEVICE_ATTR(port_63_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 30); +static SENSOR_DEVICE_ATTR(port_64_reset, S_IRUGO | S_IWUSR, show_qsfp_reset, set_qsfp_reset, 31); + +static SENSOR_DEVICE_ATTR(port_17_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 0); +static SENSOR_DEVICE_ATTR(port_18_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 1); +static SENSOR_DEVICE_ATTR(port_19_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 2); +static SENSOR_DEVICE_ATTR(port_20_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 3); +static SENSOR_DEVICE_ATTR(port_21_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 4); +static SENSOR_DEVICE_ATTR(port_22_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 5); +static SENSOR_DEVICE_ATTR(port_23_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 6); +static SENSOR_DEVICE_ATTR(port_24_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 7); +static SENSOR_DEVICE_ATTR(port_25_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 8); +static SENSOR_DEVICE_ATTR(port_26_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 9); +static SENSOR_DEVICE_ATTR(port_27_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 10); +static SENSOR_DEVICE_ATTR(port_28_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 11); +static SENSOR_DEVICE_ATTR(port_29_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 12); +static SENSOR_DEVICE_ATTR(port_30_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 13); +static SENSOR_DEVICE_ATTR(port_31_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 14); +static SENSOR_DEVICE_ATTR(port_32_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 15); +static SENSOR_DEVICE_ATTR(port_49_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 16); +static SENSOR_DEVICE_ATTR(port_50_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 17); +static SENSOR_DEVICE_ATTR(port_51_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 18); +static SENSOR_DEVICE_ATTR(port_52_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 19); +static SENSOR_DEVICE_ATTR(port_53_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 20); +static SENSOR_DEVICE_ATTR(port_54_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 21); +static SENSOR_DEVICE_ATTR(port_55_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 22); +static SENSOR_DEVICE_ATTR(port_56_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 23); +static SENSOR_DEVICE_ATTR(port_57_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 24); +static SENSOR_DEVICE_ATTR(port_58_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 25); +static SENSOR_DEVICE_ATTR(port_59_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 26); +static SENSOR_DEVICE_ATTR(port_60_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 27); +static SENSOR_DEVICE_ATTR(port_61_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 28); +static SENSOR_DEVICE_ATTR(port_62_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 29); +static SENSOR_DEVICE_ATTR(port_63_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 30); +static SENSOR_DEVICE_ATTR(port_64_led, S_IRUGO | S_IWUSR, show_qsfp_led, set_qsfp_led, 31); + +static SENSOR_DEVICE_ATTR(port_17_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 0); +static SENSOR_DEVICE_ATTR(port_18_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 1); +static SENSOR_DEVICE_ATTR(port_19_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 2); +static SENSOR_DEVICE_ATTR(port_20_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 3); +static SENSOR_DEVICE_ATTR(port_21_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 4); +static SENSOR_DEVICE_ATTR(port_22_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 5); +static SENSOR_DEVICE_ATTR(port_23_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 6); +static SENSOR_DEVICE_ATTR(port_24_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 7); +static SENSOR_DEVICE_ATTR(port_25_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 8); +static SENSOR_DEVICE_ATTR(port_26_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 9); +static SENSOR_DEVICE_ATTR(port_27_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 10); +static SENSOR_DEVICE_ATTR(port_28_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 11); +static SENSOR_DEVICE_ATTR(port_29_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 12); +static SENSOR_DEVICE_ATTR(port_30_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 13); +static SENSOR_DEVICE_ATTR(port_31_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 14); +static SENSOR_DEVICE_ATTR(port_32_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 15); +static SENSOR_DEVICE_ATTR(port_49_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 16); +static SENSOR_DEVICE_ATTR(port_50_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 17); +static SENSOR_DEVICE_ATTR(port_51_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 18); +static SENSOR_DEVICE_ATTR(port_52_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 19); +static SENSOR_DEVICE_ATTR(port_53_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 20); +static SENSOR_DEVICE_ATTR(port_54_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 21); +static SENSOR_DEVICE_ATTR(port_55_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 22); +static SENSOR_DEVICE_ATTR(port_56_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 23); +static SENSOR_DEVICE_ATTR(port_57_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 24); +static SENSOR_DEVICE_ATTR(port_58_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 25); +static SENSOR_DEVICE_ATTR(port_59_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 26); +static SENSOR_DEVICE_ATTR(port_60_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 27); +static SENSOR_DEVICE_ATTR(port_61_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 28); +static SENSOR_DEVICE_ATTR(port_62_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 29); +static SENSOR_DEVICE_ATTR(port_63_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 30); +static SENSOR_DEVICE_ATTR(port_64_brknum, S_IRUGO | S_IWUSR, show_qsfp_brknum, set_qsfp_brknum, 31); + +static struct attribute *swpld3_attributes[] = { + &sensor_dev_attr_scratch.dev_attr.attr, + &sensor_dev_attr_code_ver.dev_attr.attr, + &sensor_dev_attr_board_ver.dev_attr.attr, + &sensor_dev_attr_led_test_amb.dev_attr.attr, + &sensor_dev_attr_led_test_grn.dev_attr.attr, + &sensor_dev_attr_led_test_blink.dev_attr.attr, + &sensor_dev_attr_led_test_src_sel.dev_attr.attr, + &sensor_dev_attr_rst_pld_soft.dev_attr.attr, + + &sensor_dev_attr_port_17_rst.dev_attr.attr, + &sensor_dev_attr_port_18_rst.dev_attr.attr, + &sensor_dev_attr_port_19_rst.dev_attr.attr, + &sensor_dev_attr_port_20_rst.dev_attr.attr, + &sensor_dev_attr_port_21_rst.dev_attr.attr, + &sensor_dev_attr_port_22_rst.dev_attr.attr, + &sensor_dev_attr_port_23_rst.dev_attr.attr, + &sensor_dev_attr_port_24_rst.dev_attr.attr, + &sensor_dev_attr_port_25_rst.dev_attr.attr, + &sensor_dev_attr_port_26_rst.dev_attr.attr, + &sensor_dev_attr_port_27_rst.dev_attr.attr, + &sensor_dev_attr_port_28_rst.dev_attr.attr, + &sensor_dev_attr_port_29_rst.dev_attr.attr, + &sensor_dev_attr_port_30_rst.dev_attr.attr, + &sensor_dev_attr_port_31_rst.dev_attr.attr, + &sensor_dev_attr_port_32_rst.dev_attr.attr, + &sensor_dev_attr_port_49_rst.dev_attr.attr, + &sensor_dev_attr_port_50_rst.dev_attr.attr, + &sensor_dev_attr_port_51_rst.dev_attr.attr, + &sensor_dev_attr_port_52_rst.dev_attr.attr, + &sensor_dev_attr_port_53_rst.dev_attr.attr, + &sensor_dev_attr_port_54_rst.dev_attr.attr, + &sensor_dev_attr_port_55_rst.dev_attr.attr, + &sensor_dev_attr_port_56_rst.dev_attr.attr, + &sensor_dev_attr_port_57_rst.dev_attr.attr, + &sensor_dev_attr_port_58_rst.dev_attr.attr, + &sensor_dev_attr_port_59_rst.dev_attr.attr, + &sensor_dev_attr_port_60_rst.dev_attr.attr, + &sensor_dev_attr_port_61_rst.dev_attr.attr, + &sensor_dev_attr_port_62_rst.dev_attr.attr, + &sensor_dev_attr_port_63_rst.dev_attr.attr, + &sensor_dev_attr_port_64_rst.dev_attr.attr, + + &sensor_dev_attr_port_17_lpmod.dev_attr.attr, + &sensor_dev_attr_port_18_lpmod.dev_attr.attr, + &sensor_dev_attr_port_19_lpmod.dev_attr.attr, + &sensor_dev_attr_port_20_lpmod.dev_attr.attr, + &sensor_dev_attr_port_21_lpmod.dev_attr.attr, + &sensor_dev_attr_port_22_lpmod.dev_attr.attr, + &sensor_dev_attr_port_23_lpmod.dev_attr.attr, + &sensor_dev_attr_port_24_lpmod.dev_attr.attr, + &sensor_dev_attr_port_25_lpmod.dev_attr.attr, + &sensor_dev_attr_port_26_lpmod.dev_attr.attr, + &sensor_dev_attr_port_27_lpmod.dev_attr.attr, + &sensor_dev_attr_port_28_lpmod.dev_attr.attr, + &sensor_dev_attr_port_29_lpmod.dev_attr.attr, + &sensor_dev_attr_port_30_lpmod.dev_attr.attr, + &sensor_dev_attr_port_31_lpmod.dev_attr.attr, + &sensor_dev_attr_port_32_lpmod.dev_attr.attr, + &sensor_dev_attr_port_49_lpmod.dev_attr.attr, + &sensor_dev_attr_port_50_lpmod.dev_attr.attr, + &sensor_dev_attr_port_51_lpmod.dev_attr.attr, + &sensor_dev_attr_port_52_lpmod.dev_attr.attr, + &sensor_dev_attr_port_53_lpmod.dev_attr.attr, + &sensor_dev_attr_port_54_lpmod.dev_attr.attr, + &sensor_dev_attr_port_55_lpmod.dev_attr.attr, + &sensor_dev_attr_port_56_lpmod.dev_attr.attr, + &sensor_dev_attr_port_57_lpmod.dev_attr.attr, + &sensor_dev_attr_port_58_lpmod.dev_attr.attr, + &sensor_dev_attr_port_59_lpmod.dev_attr.attr, + &sensor_dev_attr_port_60_lpmod.dev_attr.attr, + &sensor_dev_attr_port_61_lpmod.dev_attr.attr, + &sensor_dev_attr_port_62_lpmod.dev_attr.attr, + &sensor_dev_attr_port_63_lpmod.dev_attr.attr, + &sensor_dev_attr_port_64_lpmod.dev_attr.attr, + + &sensor_dev_attr_port_17_modsel.dev_attr.attr, + &sensor_dev_attr_port_18_modsel.dev_attr.attr, + &sensor_dev_attr_port_19_modsel.dev_attr.attr, + &sensor_dev_attr_port_20_modsel.dev_attr.attr, + &sensor_dev_attr_port_21_modsel.dev_attr.attr, + &sensor_dev_attr_port_22_modsel.dev_attr.attr, + &sensor_dev_attr_port_23_modsel.dev_attr.attr, + &sensor_dev_attr_port_24_modsel.dev_attr.attr, + &sensor_dev_attr_port_25_modsel.dev_attr.attr, + &sensor_dev_attr_port_26_modsel.dev_attr.attr, + &sensor_dev_attr_port_27_modsel.dev_attr.attr, + &sensor_dev_attr_port_28_modsel.dev_attr.attr, + &sensor_dev_attr_port_29_modsel.dev_attr.attr, + &sensor_dev_attr_port_30_modsel.dev_attr.attr, + &sensor_dev_attr_port_31_modsel.dev_attr.attr, + &sensor_dev_attr_port_32_modsel.dev_attr.attr, + &sensor_dev_attr_port_49_modsel.dev_attr.attr, + &sensor_dev_attr_port_50_modsel.dev_attr.attr, + &sensor_dev_attr_port_51_modsel.dev_attr.attr, + &sensor_dev_attr_port_52_modsel.dev_attr.attr, + &sensor_dev_attr_port_53_modsel.dev_attr.attr, + &sensor_dev_attr_port_54_modsel.dev_attr.attr, + &sensor_dev_attr_port_55_modsel.dev_attr.attr, + &sensor_dev_attr_port_56_modsel.dev_attr.attr, + &sensor_dev_attr_port_57_modsel.dev_attr.attr, + &sensor_dev_attr_port_58_modsel.dev_attr.attr, + &sensor_dev_attr_port_59_modsel.dev_attr.attr, + &sensor_dev_attr_port_60_modsel.dev_attr.attr, + &sensor_dev_attr_port_61_modsel.dev_attr.attr, + &sensor_dev_attr_port_62_modsel.dev_attr.attr, + &sensor_dev_attr_port_63_modsel.dev_attr.attr, + &sensor_dev_attr_port_64_modsel.dev_attr.attr, + + &sensor_dev_attr_port_17_prs.dev_attr.attr, + &sensor_dev_attr_port_18_prs.dev_attr.attr, + &sensor_dev_attr_port_19_prs.dev_attr.attr, + &sensor_dev_attr_port_20_prs.dev_attr.attr, + &sensor_dev_attr_port_21_prs.dev_attr.attr, + &sensor_dev_attr_port_22_prs.dev_attr.attr, + &sensor_dev_attr_port_23_prs.dev_attr.attr, + &sensor_dev_attr_port_24_prs.dev_attr.attr, + &sensor_dev_attr_port_25_prs.dev_attr.attr, + &sensor_dev_attr_port_26_prs.dev_attr.attr, + &sensor_dev_attr_port_27_prs.dev_attr.attr, + &sensor_dev_attr_port_28_prs.dev_attr.attr, + &sensor_dev_attr_port_29_prs.dev_attr.attr, + &sensor_dev_attr_port_30_prs.dev_attr.attr, + &sensor_dev_attr_port_31_prs.dev_attr.attr, + &sensor_dev_attr_port_32_prs.dev_attr.attr, + &sensor_dev_attr_port_49_prs.dev_attr.attr, + &sensor_dev_attr_port_50_prs.dev_attr.attr, + &sensor_dev_attr_port_51_prs.dev_attr.attr, + &sensor_dev_attr_port_52_prs.dev_attr.attr, + &sensor_dev_attr_port_53_prs.dev_attr.attr, + &sensor_dev_attr_port_54_prs.dev_attr.attr, + &sensor_dev_attr_port_55_prs.dev_attr.attr, + &sensor_dev_attr_port_56_prs.dev_attr.attr, + &sensor_dev_attr_port_57_prs.dev_attr.attr, + &sensor_dev_attr_port_58_prs.dev_attr.attr, + &sensor_dev_attr_port_59_prs.dev_attr.attr, + &sensor_dev_attr_port_60_prs.dev_attr.attr, + &sensor_dev_attr_port_61_prs.dev_attr.attr, + &sensor_dev_attr_port_62_prs.dev_attr.attr, + &sensor_dev_attr_port_63_prs.dev_attr.attr, + &sensor_dev_attr_port_64_prs.dev_attr.attr, + + &sensor_dev_attr_modprs_reg1.dev_attr.attr, + &sensor_dev_attr_modprs_reg2.dev_attr.attr, + &sensor_dev_attr_modprs_reg3.dev_attr.attr, + &sensor_dev_attr_modprs_reg4.dev_attr.attr, + + &sensor_dev_attr_code_day.dev_attr.attr, + &sensor_dev_attr_code_month.dev_attr.attr, + &sensor_dev_attr_code_year.dev_attr.attr, + + &sensor_dev_attr_port_17_reset.dev_attr.attr, + &sensor_dev_attr_port_18_reset.dev_attr.attr, + &sensor_dev_attr_port_19_reset.dev_attr.attr, + &sensor_dev_attr_port_20_reset.dev_attr.attr, + &sensor_dev_attr_port_21_reset.dev_attr.attr, + &sensor_dev_attr_port_22_reset.dev_attr.attr, + &sensor_dev_attr_port_23_reset.dev_attr.attr, + &sensor_dev_attr_port_24_reset.dev_attr.attr, + &sensor_dev_attr_port_25_reset.dev_attr.attr, + &sensor_dev_attr_port_26_reset.dev_attr.attr, + &sensor_dev_attr_port_27_reset.dev_attr.attr, + &sensor_dev_attr_port_28_reset.dev_attr.attr, + &sensor_dev_attr_port_29_reset.dev_attr.attr, + &sensor_dev_attr_port_30_reset.dev_attr.attr, + &sensor_dev_attr_port_31_reset.dev_attr.attr, + &sensor_dev_attr_port_32_reset.dev_attr.attr, + &sensor_dev_attr_port_49_reset.dev_attr.attr, + &sensor_dev_attr_port_50_reset.dev_attr.attr, + &sensor_dev_attr_port_51_reset.dev_attr.attr, + &sensor_dev_attr_port_52_reset.dev_attr.attr, + &sensor_dev_attr_port_53_reset.dev_attr.attr, + &sensor_dev_attr_port_54_reset.dev_attr.attr, + &sensor_dev_attr_port_55_reset.dev_attr.attr, + &sensor_dev_attr_port_56_reset.dev_attr.attr, + &sensor_dev_attr_port_57_reset.dev_attr.attr, + &sensor_dev_attr_port_58_reset.dev_attr.attr, + &sensor_dev_attr_port_59_reset.dev_attr.attr, + &sensor_dev_attr_port_60_reset.dev_attr.attr, + &sensor_dev_attr_port_61_reset.dev_attr.attr, + &sensor_dev_attr_port_62_reset.dev_attr.attr, + &sensor_dev_attr_port_63_reset.dev_attr.attr, + &sensor_dev_attr_port_64_reset.dev_attr.attr, + + &sensor_dev_attr_port_17_led.dev_attr.attr, + &sensor_dev_attr_port_18_led.dev_attr.attr, + &sensor_dev_attr_port_19_led.dev_attr.attr, + &sensor_dev_attr_port_20_led.dev_attr.attr, + &sensor_dev_attr_port_21_led.dev_attr.attr, + &sensor_dev_attr_port_22_led.dev_attr.attr, + &sensor_dev_attr_port_23_led.dev_attr.attr, + &sensor_dev_attr_port_24_led.dev_attr.attr, + &sensor_dev_attr_port_25_led.dev_attr.attr, + &sensor_dev_attr_port_26_led.dev_attr.attr, + &sensor_dev_attr_port_27_led.dev_attr.attr, + &sensor_dev_attr_port_28_led.dev_attr.attr, + &sensor_dev_attr_port_29_led.dev_attr.attr, + &sensor_dev_attr_port_30_led.dev_attr.attr, + &sensor_dev_attr_port_31_led.dev_attr.attr, + &sensor_dev_attr_port_32_led.dev_attr.attr, + &sensor_dev_attr_port_49_led.dev_attr.attr, + &sensor_dev_attr_port_50_led.dev_attr.attr, + &sensor_dev_attr_port_51_led.dev_attr.attr, + &sensor_dev_attr_port_52_led.dev_attr.attr, + &sensor_dev_attr_port_53_led.dev_attr.attr, + &sensor_dev_attr_port_54_led.dev_attr.attr, + &sensor_dev_attr_port_55_led.dev_attr.attr, + &sensor_dev_attr_port_56_led.dev_attr.attr, + &sensor_dev_attr_port_57_led.dev_attr.attr, + &sensor_dev_attr_port_58_led.dev_attr.attr, + &sensor_dev_attr_port_59_led.dev_attr.attr, + &sensor_dev_attr_port_60_led.dev_attr.attr, + &sensor_dev_attr_port_61_led.dev_attr.attr, + &sensor_dev_attr_port_62_led.dev_attr.attr, + &sensor_dev_attr_port_63_led.dev_attr.attr, + &sensor_dev_attr_port_64_led.dev_attr.attr, + + &sensor_dev_attr_port_17_brknum.dev_attr.attr, + &sensor_dev_attr_port_18_brknum.dev_attr.attr, + &sensor_dev_attr_port_19_brknum.dev_attr.attr, + &sensor_dev_attr_port_20_brknum.dev_attr.attr, + &sensor_dev_attr_port_21_brknum.dev_attr.attr, + &sensor_dev_attr_port_22_brknum.dev_attr.attr, + &sensor_dev_attr_port_23_brknum.dev_attr.attr, + &sensor_dev_attr_port_24_brknum.dev_attr.attr, + &sensor_dev_attr_port_25_brknum.dev_attr.attr, + &sensor_dev_attr_port_26_brknum.dev_attr.attr, + &sensor_dev_attr_port_27_brknum.dev_attr.attr, + &sensor_dev_attr_port_28_brknum.dev_attr.attr, + &sensor_dev_attr_port_29_brknum.dev_attr.attr, + &sensor_dev_attr_port_30_brknum.dev_attr.attr, + &sensor_dev_attr_port_31_brknum.dev_attr.attr, + &sensor_dev_attr_port_32_brknum.dev_attr.attr, + &sensor_dev_attr_port_49_brknum.dev_attr.attr, + &sensor_dev_attr_port_50_brknum.dev_attr.attr, + &sensor_dev_attr_port_51_brknum.dev_attr.attr, + &sensor_dev_attr_port_52_brknum.dev_attr.attr, + &sensor_dev_attr_port_53_brknum.dev_attr.attr, + &sensor_dev_attr_port_54_brknum.dev_attr.attr, + &sensor_dev_attr_port_55_brknum.dev_attr.attr, + &sensor_dev_attr_port_56_brknum.dev_attr.attr, + &sensor_dev_attr_port_57_brknum.dev_attr.attr, + &sensor_dev_attr_port_58_brknum.dev_attr.attr, + &sensor_dev_attr_port_59_brknum.dev_attr.attr, + &sensor_dev_attr_port_60_brknum.dev_attr.attr, + &sensor_dev_attr_port_61_brknum.dev_attr.attr, + &sensor_dev_attr_port_62_brknum.dev_attr.attr, + &sensor_dev_attr_port_63_brknum.dev_attr.attr, + &sensor_dev_attr_port_64_brknum.dev_attr.attr, + + NULL +}; + +static const struct attribute_group swpld3_group = { + .attrs = swpld3_attributes, +}; + +static int swpld3_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct cpld_data *data = NULL; + int i; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "CPLD PROBE ERROR: i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + dev_info(&client->dev, "Nokia SWPLD3 chip found.\n"); + data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL); + + if (!data) { + dev_err(&client->dev, "CPLD PROBE ERROR: Can't allocate memory\n"); + status = -ENOMEM; + goto exit; + } + + data->client = client; + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + status = sysfs_create_group(&client->dev.kobj, &swpld3_group); + if (status) { + dev_err(&client->dev, "CPLD INIT ERROR: Cannot create sysfs\n"); + goto exit; + } + + dump_reg(data); + dev_info(&client->dev, "[SWPLD3]Reseting PORTs ...\n"); + cpld_i2c_write(data, QSFP_MODSEL_REG0, 0xFF); + cpld_i2c_write(data, QSFP_MODSEL_REG1, 0xFF); + cpld_i2c_write(data, QSFP_MODSEL_REG2, 0xFF); + cpld_i2c_write(data, QSFP_MODSEL_REG3, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG0, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG1, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG2, 0xFF); + cpld_i2c_write(data, QSFP_LPMODE_REG3, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG0, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG1, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG2, 0xFF); + cpld_i2c_write(data, QSFP_RST_REG3, 0xFF); + msleep(500); + cpld_i2c_write(data, QSFP_RST_REG0, 0x0); + cpld_i2c_write(data, QSFP_RST_REG1, 0x0); + cpld_i2c_write(data, QSFP_RST_REG2, 0x0); + cpld_i2c_write(data, QSFP_RST_REG3, 0x0); + dev_info(&client->dev, "[SWPLD3]PORTs reset done.\n"); + dump_reg(data); + for (i=0;i<32;i++) data->reset_list[i] = 0; + + return 0; + +exit: + return status; +} + +static void swpld3_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + sysfs_remove_group(&client->dev.kobj, &swpld3_group); + kfree(data); +} + +static const struct of_device_id swpld3_of_ids[] = { + { + .compatible = "nokia,swpld3", + .data = (void *) 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, swpld3_of_ids); + +static const struct i2c_device_id swpld3_ids[] = { + { DRIVER_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, swpld3_ids); + +static struct i2c_driver swpld3_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(swpld3_of_ids), + }, + .probe = swpld3_probe, + .remove = swpld3_remove, + .id_table = swpld3_ids, + .address_list = cpld_address_list, +}; + +static int __init swpld3_init(void) +{ + return i2c_add_driver(&swpld3_driver); +} + +static void __exit swpld3_exit(void) +{ + i2c_del_driver(&swpld3_driver); +} + +MODULE_AUTHOR("Nokia"); +MODULE_DESCRIPTION("NOKIA CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(swpld3_init); +module_exit(swpld3_exit); + From 39cba28265fa752d7e891a0c96f9628ab3f5a367 Mon Sep 17 00:00:00 2001 From: y7zhou Date: Thu, 12 Dec 2024 09:41:20 -0500 Subject: [PATCH 2/4] [H5-64D]Update init script and sfp, eeprom, fan, psu modules --- ixr7220h5-64d/scripts/h5_64d_platform_init.sh | 154 +++++++--- .../service/h5_64d_platform_init.service | 2 +- ixr7220h5-64d/sonic_platform/chassis.py | 234 ++++++-------- ixr7220h5-64d/sonic_platform/eeprom.py | 66 ++-- ixr7220h5-64d/sonic_platform/fan.py | 288 +++++++----------- ixr7220h5-64d/sonic_platform/fan_drawer.py | 137 +++++++-- ixr7220h5-64d/sonic_platform/psu.py | 271 ++++++---------- ixr7220h5-64d/sonic_platform/sfp.py | 170 +++++------ ixr7220h5-64d/sonic_platform/sfp_event.py | 116 ++++--- ixr7220h5-64d/sonic_platform/sysfs.py | 57 ++++ 10 files changed, 761 insertions(+), 734 deletions(-) create mode 100644 ixr7220h5-64d/sonic_platform/sysfs.py diff --git a/ixr7220h5-64d/scripts/h5_64d_platform_init.sh b/ixr7220h5-64d/scripts/h5_64d_platform_init.sh index 6816339..96ce1e0 100755 --- a/ixr7220h5-64d/scripts/h5_64d_platform_init.sh +++ b/ixr7220h5-64d/scripts/h5_64d_platform_init.sh @@ -5,33 +5,37 @@ # Load required kernel-mode drivers load_kernel_drivers() { echo "Loading Kernel Drivers" - depmod -a - rmmod i2c-i801 - rmmod i2c-ismt - modprobe i2c-ismt - modprobe i2c-i801 - modprobe i2c-dev - modprobe i2c-mux + depmod -a + rmmod amd-xgbe + rmmod igb + rmmod i2c-piix4 + rmmod i2c_designware_platform + modprobe igb + modprobe amd-xgbe + modprobe i2c_designware_platform + modprobe i2c-piix4 modprobe i2c-smbus - rmmod ee1004 - modprobe eeprom + modprobe i2c-dev + modprobe i2c-mux modprobe i2c-mux-gpio modprobe i2c-mux-pca954x modprobe sys_fpga - modprobe emc2305 - modprobe dni_psu - modprobe h5_64d_cpupld - modprobe h5_64d_portpld1 - modprobe h5_64d_portpld2 - modprobe at24 + modprobe cpupld + modprobe swpld2 + modprobe swpld3 + modprobe at24 + modprobe eeprom_tlv + modprobe eeprom_fru modprobe optoe + modprobe dni_psu + modprobe emc2305 } -nokia_7220H5_profile() +h5_64d_profile() { MAC_ADDR=$(sudo decode-syseeprom -m) - sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" /usr/share/sonic/device/x86_64-nokia_ixr7220_h4_32d-r0/Nokia-IXR7220-H4-32D/profile.ini - #echo "Nokia-7220-H4: Updating switch mac address ${MAC_ADDR}" + sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" /usr/share/sonic/device/x86_64-nokia_ixr7220_h5_64d-r0/Nokia-IXR7220-H5-64D/profile.ini + echo "Nokia-7220-H5-64D: Updated switch mac address ${MAC_ADDR}" } file_exists() { @@ -41,33 +45,115 @@ file_exists() { if [ -f $1 ]; then return 1 fi - sleep 1 + sleep 1 done return 0 - } +} - # Install kernel drivers required for i2c bus access +# Install kernel drivers required for i2c bus access load_kernel_drivers -#insmod /lib/modules/6.1.0-11-2-amd64/delta_fpga.ko - #Enumerate I2C Multiplexers -echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-3/new_device -for devnum in {4..11}; do +echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-4/new_device +echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-4/new_device +echo pca9546 0x72 > /sys/bus/i2c/devices/i2c-18/new_device + +#Enumerate CPLDs +echo cpupld 0x40 > /sys/bus/i2c/devices/i2c-4/new_device + +# Enumerate system eeprom +echo 24c02 0x54 > /sys/bus/i2c/devices/i2c-4/new_device + +# Enumerate PSU +echo dni_psu 0x58 > /sys/bus/i2c/devices/i2c-15/new_device +echo dni_psu 0x59 > /sys/bus/i2c/devices/i2c-15/new_device +echo eeprom_fru 0x50 > /sys/bus/i2c/devices/i2c-15/new_device +echo eeprom_fru 0x51 > /sys/bus/i2c/devices/i2c-15/new_device + +# Enumerate Thermal Sensor +echo tmp1075 0x49 > /sys/bus/i2c/devices/i2c-16/new_device +echo tmp1075 0x4a > /sys/bus/i2c/devices/i2c-16/new_device +echo tmp1075 0x4b > /sys/bus/i2c/devices/i2c-16/new_device +echo tmp1075 0x4e > /sys/bus/i2c/devices/i2c-16/new_device +echo tmp1075 0x4f > /sys/bus/i2c/devices/i2c-16/new_device +echo tmp1075 0x4e > /sys/bus/i2c/devices/i2c-17/new_device +echo tmp1075 0x4f > /sys/bus/i2c/devices/i2c-17/new_device +echo tmp1075 0x49 > /sys/bus/i2c/devices/i2c-19/new_device +echo tmp1075 0x48 > /sys/bus/i2c/devices/i2c-20/new_device + +# Enumerate Fan controller +echo emc2305 0x2d > /sys/bus/i2c/devices/i2c-17/new_device +echo emc2305 0x4c > /sys/bus/i2c/devices/i2c-17/new_device + +# Enumerate PCA9555(GPIO Mux) +echo pca9555 0x27 > /sys/bus/i2c/devices/i2c-18/new_device + +#Enumerate CPLDs +echo swpld2 0x41 > /sys/bus/i2c/devices/i2c-21/new_device +echo swpld3 0x45 > /sys/bus/i2c/devices/i2c-21/new_device + +for devnum in {5..13}; do echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-${devnum}/new_device sleep 0.1 done -#Enumerate CPLDs -echo h5_portpld1 0x41 > /sys/bus/i2c/devices/i2c-2/new_device -echo h5_portpld2 0x45 > /sys/bus/i2c/devices/i2c-2/new_device - -#Enumerate QSFPs and SFPs -echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-12/new_device -echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-13/new_device -for qsfpnum in {20..83}; do - echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-${qsfpnum}/new_device +for num in {34..97}; do + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-${num}/new_device sleep 0.1 done +echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-98/new_device +echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-99/new_device + +# Set the PCA9548 mux behavior +echo -2 > /sys/bus/i2c/devices/4-0070/idle_state +echo -2 > /sys/bus/i2c/devices/4-0071/idle_state +echo -2 > /sys/bus/i2c/devices/5-0070/idle_state +echo -2 > /sys/bus/i2c/devices/6-0070/idle_state +echo -2 > /sys/bus/i2c/devices/7-0070/idle_state +echo -2 > /sys/bus/i2c/devices/8-0070/idle_state +echo -2 > /sys/bus/i2c/devices/9-0070/idle_state +echo -2 > /sys/bus/i2c/devices/10-0070/idle_state +echo -2 > /sys/bus/i2c/devices/11-0070/idle_state +echo -2 > /sys/bus/i2c/devices/12-0070/idle_state +echo -2 > /sys/bus/i2c/devices/13-0070/idle_state +echo -2 > /sys/bus/i2c/devices/18-0072/idle_state + +# Enumerate Fans(0-3) eeprom +for chan in {0..3} +do + echo eeprom_tlv 0x50 > /sys/bus/i2c/devices/18-0072/channel-${chan}/new_device +done + +file_exists /sys/bus/i2c/devices/4-0054/eeprom +status=$? +if [ "$status" == "1" ]; then + chmod 644 /sys/bus/i2c/devices/4-0054/eeprom + h5_64d_profile +else + echo "SYSEEPROM file not foud" +fi + +#Enumerate GPIO port +for port in {36..39} +do + echo 99${port} > /sys/class/gpio/export + echo in > /sys/class/gpio/gpio99${port}/direction + sleep 0.1 +done + +check_voltage() { + status=$(cat /sys/kernel/sys_fpga/psu$(($1))_ok) + model=$(cat /sys/bus/i2c/devices/15-005$(($1-1))/part_number) + if [[ ${status[0]} == "0x0" ]] && [[ ${model:0:10} == "3HE20598AA" ]]; then + vol_i=$(cat /sys/bus/i2c/devices/15-005$((7+$1))/psu_v_in) + vol_d=$(echo "$vol_i 1000" | awk '{printf "%0.3f\n", $1/$2}') + if (("$vol_i" < 170000)); then + echo -e "\nERROR: PSU $1 not supplying enough voltage. [$vol_d]v is less than the required 200-220V\n" + fi + fi + return 0 +} +check_voltage 1 +check_voltage 2 exit 0 diff --git a/ixr7220h5-64d/service/h5_64d_platform_init.service b/ixr7220h5-64d/service/h5_64d_platform_init.service index ee280ab..627c5a5 100644 --- a/ixr7220h5-64d/service/h5_64d_platform_init.service +++ b/ixr7220h5-64d/service/h5_64d_platform_init.service @@ -1,7 +1,7 @@ [Unit] Description=Nokia-IXR7220-H5-64D Platform Service After=sysinit.target -Before=pmon.service determine-reboot-cause.service +Before=database.service determine-reboot-cause.service [Service] Type=oneshot diff --git a/ixr7220h5-64d/sonic_platform/chassis.py b/ixr7220h5-64d/sonic_platform/chassis.py index a6bff17..c65aedf 100644 --- a/ixr7220h5-64d/sonic_platform/chassis.py +++ b/ixr7220h5-64d/sonic_platform/chassis.py @@ -1,83 +1,85 @@ -############################################################################# -# -# Module contains an implementation of SONiC Platform Base API and -# provides the platform information -# -############################################################################# +""" + Module contains an implementation of SONiC Platform Base API and + provides the platform information +""" try: import os - import time import sys - import struct - from os import * - from mmap import * from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.sfp import Sfp from sonic_platform.eeprom import Eeprom from sonic_platform.fan import Fan + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file from .fan_drawer import RealDrawer from sonic_platform.psu import Psu from sonic_platform.thermal import Thermal from sonic_platform.component import Component + from sonic_platform.sfp_event import SfpEvent from sonic_py_common import logger - from sonic_py_common.general import getstatusoutput_noshell except ImportError as e: - raise ImportError(str(e) + "- required module not found") + raise ImportError(str(e) + ' - required module not found') from e PORT_START = 1 -QSFP_PORT_NUM = 64 +PORT_NUM = 64 PORT_END = 66 -QSFP_I2C_START = 23 -CPUPLD_DIR = "/sys/bus/i2c/devices/0-0031/" -RESOURCE = "/sys/bus/pci/devices/0000:02:00.0/resource0" -REG_FRONT_SYSLED = 0x0084 +PORT_I2C_START = 34 +CPUPLD_DIR = "/sys/bus/i2c/devices/4-0040/" +FPGA_DIR = "/sys/kernel/sys_fpga/" # Device counts -H5_64D_FAN_DRAWERS = 4 -H5_64D_FANS_PER_DRAWER = 2 -MAX_H5_64D_PSU = 2 -MAX_H5_64D_THERMAL = 10 -MAX_H5_64D_COMPONENT = 4 +FAN_DRAWERS_NUM = 4 +FANS_PER_DRAWER = 2 +PSU_NUM = 2 +THERMAL_NUM = 11 +COMPONENT_NUM = 5 SYSLOG_IDENTIFIER = "chassis" sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) +#sonic_logger.set_min_log_priority_info() class Chassis(ChassisBase): """ - Nokia platform-specific Chassis class + Nokia platform-specific Chassis class customized for the 7220 H5-64D platform. """ def __init__(self): ChassisBase.__init__(self) - self.system_led_supported_color = ['off', 'amber', 'green', 'amber_blink', 'green_blink'] + self.system_led_color = ['off', 'green', 'amber', 'green_blink', + 'amber_blink', 'alter_green_amber', 'off', 'off'] + # Port numbers for SFP List Initialization - self.PORT_START = PORT_START + self.PORT_START = PORT_START self.PORT_END = PORT_END + self._watchdog = None + self.sfp_event = None + self.max_select_event_returned = None - # Verify optoe driver QSFP-DD eeprom devices were enumerated and exist + # Verify optoe driver PORT eeprom devices were enumerated and exist # then create the sfp nodes - eeprom_path = "/sys/bus/i2c/devices/{}-0050/eeprom" - for index in range(PORT_START, PORT_START + QSFP_PORT_NUM): - port_i2c_map = index + QSFP_I2C_START - 1 + eeprom_path = "/sys/bus/i2c/devices/{}-0050/eeprom" + for index in range(PORT_START, PORT_START + PORT_NUM): + if index <= PORT_NUM//2: + port_i2c_map = PORT_I2C_START + 4 * ((index-1) // 2) + ((index-1) % 2) + else: + port_i2c_map = PORT_I2C_START + 4 * (((index-1) - 32) // 2) + 2 + ((index-1) % 2) port_eeprom_path = eeprom_path.format(port_i2c_map) if not os.path.exists(port_eeprom_path): - sonic_logger.log_info("path %s didnt exist" % port_eeprom_path) + sonic_logger.log_info(f"path {port_eeprom_path} didnt exist") sfp_node = Sfp(index, 'QSFPDD', port_eeprom_path, port_i2c_map) self._sfp_list.append(sfp_node) - - port_eeprom_path = "/sys/bus/i2c/devices/14-0050/eeprom" + port_eeprom_path = "/sys/bus/i2c/devices/98-0050/eeprom" if not os.path.exists(port_eeprom_path): - sonic_logger.log_info("path %s didnt exist" % port_eeprom_path) - sfp_node = Sfp(QSFP_PORT_NUM + 1, 'SFP+', port_eeprom_path, 14) + sonic_logger.log_info(f"path {port_eeprom_path} didnt exist") + sfp_node = Sfp(PORT_NUM + 1, 'SFP+', port_eeprom_path, 98) self._sfp_list.append(sfp_node) - port_eeprom_path = "/sys/bus/i2c/devices/15-0050/eeprom" + port_eeprom_path = "/sys/bus/i2c/devices/99-0050/eeprom" if not os.path.exists(port_eeprom_path): - sonic_logger.log_info("path %s didnt exist" % port_eeprom_path) - sfp_node = Sfp(QSFP_PORT_NUM + 1, 'SFP+', port_eeprom_path, 14) + sonic_logger.log_info(f"path {port_eeprom_path} didnt exist") + sfp_node = Sfp(PORT_NUM + 2, 'SFP+', port_eeprom_path, 99) self._sfp_list.append(sfp_node) self.sfp_event_initialized = False @@ -86,12 +88,12 @@ def __init__(self): self._eeprom = Eeprom(False, 0, False, 0) # Construct lists fans, power supplies, thermals & components - for i in range(MAX_H5_64D_THERMAL): + for i in range(THERMAL_NUM): thermal = Thermal(i) self._thermal_list.append(thermal) - drawer_num = H5_64D_FAN_DRAWERS - fan_num_per_drawer = H5_64D_FANS_PER_DRAWER + drawer_num = FAN_DRAWERS_NUM + fan_num_per_drawer = FANS_PER_DRAWER drawer_ctor = RealDrawer for drawer_index in range(drawer_num): drawer = drawer_ctor(drawer_index) @@ -101,71 +103,14 @@ def __init__(self): drawer._fan_list.append(fan) self._fan_list.append(fan) - for i in range(MAX_H5_64D_PSU): + for i in range(PSU_NUM): psu = Psu(i) self._psu_list.append(psu) - for i in range(MAX_H5_64D_COMPONENT): + for i in range(COMPONENT_NUM): component = Component(i) self._component_list.append(component) - - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv - - def _write_sysfs_file(self, sysfs_file, value): - # On successful write, the value read will be written on - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'w') as fd: - rv = fd.write(value) - except Exception as e: - rv = 'ERR' - - # Ensure that the write operation has succeeded - if ((self._read_sysfs_file(sysfs_file)) != value ): - time.sleep(3) - if ((self._read_sysfs_file(sysfs_file)) != value ): - rv = 'ERR' - - return rv - - def pci_set_value(resource, data, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - mm.write(struct.pack('I', data)) - mm.close() - close(fd) - - def pci_get_value(resource, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - read_data_stream = mm.read(4) - reg_val = struct.unpack('I', read_data_stream) - mm.close() - close(fd) - return reg_val - def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index @@ -212,8 +157,7 @@ def get_change_event(self, timeout=0): """ # Initialize SFP event first if not self.sfp_event_initialized: - from sonic_platform.sfp_event import sfp_event - self.sfp_event = sfp_event() + self.sfp_event = SfpEvent() self.sfp_event.initialize() self.MAX_SELECT_EVENT_RETURNED = self.PORT_END self.sfp_event_initialized = True @@ -240,8 +184,12 @@ def get_change_event(self, timeout=0): return True, {'sfp': {}} def get_num_psus(self): - - return MAX_H5_64D_PSU + """ + Retrieves the num of the psus + Returns: + int: The num of the psus + """ + return PSU_NUM def get_name(self): """ @@ -325,10 +273,22 @@ def get_system_eeprom_info(self): return self._eeprom.system_eeprom_info() def get_thermal_manager(self): + """ + Get thermal manager + + Returns: + ThermalManager + """ from .thermal_manager import ThermalManager return ThermalManager - + def initizalize_system_led(self): + """ + Initizalize system led + + Returns: + bool: True if it is successful. + """ return True def get_reboot_cause(self): @@ -341,21 +301,20 @@ def get_reboot_cause(self): is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used to pass a description of the reboot cause. """ + result = read_sysfs_file(CPUPLD_DIR + "reset_cause") - result = self._read_sysfs_file(CPUPLD_DIR + "reset_cause") + if (int(result, 16) & 0x20) >> 5 == 1: + return (self.REBOOT_CAUSE_WATCHDOG, "CPU_WD") if (int(result, 16) & 0x10) >> 4 == 1: - return (self.REBOOT_CAUSE_WATCHDOG, None) + return (self.REBOOT_CAUSE_WATCHDOG, "CPLD_WD") if (int(result, 16) & 0x01) == 1: - return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Power Error") - + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Power Error") + if (int(result, 16) & 0x80) >> 7 == 1: - return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Cold Reset") + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Power Cycle") - if (int(result, 16) & 0x40) >> 6 == 1: - return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Warm Reset") - return (self.REBOOT_CAUSE_NON_HARDWARE, None) def get_watchdog(self): @@ -385,12 +344,12 @@ def get_watchdog(self): def get_position_in_parent(self): """ - Retrieves 1-based relative physical position in parent device. If the agent + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position - for some reason, or if the associated value of entPhysicalContainedIn is '0', + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned Returns: - integer: The 1-based relative physical position in parent device or -1 if + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ return -1 @@ -402,7 +361,7 @@ def is_replaceable(self): bool: True if it is replaceable. """ return False - + def set_status_led(self, color): """ Sets the state of the system LED @@ -414,24 +373,12 @@ def set_status_led(self, color): Returns: bool: True if system LED state is set successfully, False if not """ - if color not in self.system_led_supported_color: - return False - - if (color == 'off'): - value = 0 - elif (color == 'green'): - value = 1 - elif (color == 'amber'): - value = 2 - elif (color == 'green_blink'): - value = 3 - elif (color == 'amber_blink'): - value = 4 - else: + try: + value = self.system_led_color.index(color) + write_sysfs_file(FPGA_DIR + 'led_sys', str(value)) + return True + except ValueError: return False - - self.pci_set_value(RESOURCE, value, REG_FRONT_SYSLED) - return True def get_status_led(self): """ @@ -441,19 +388,8 @@ def get_status_led(self): A string, one of the valid LED color strings which could be vendor specified. """ - - val = self.pci_get_value(RESOURCE, REG_FRONT_SYSLED) - result = val[0] & 0x7 - - if result == 0 or result == 6 or result == 7: - return self.STATUS_LED_COLOR_OFF - elif result == 1: - return self.STATUS_LED_COLOR_GREEN - elif result == 2: - return self.STATUS_LED_COLOR_AMBER - elif result == 3: - return self.STATUS_LED_COLOR_GREEN_BLINK - elif result == 4: - return self.STATUS_LED_COLOR_AMBER_BLINK - else: - return 'N/A' + result = read_sysfs_file(FPGA_DIR + 'led_sys') + val = int(result, 16) & 0x7 + if val < len(self.system_led_color): + return self.system_led_color[val] + return 'N/A' diff --git a/ixr7220h5-64d/sonic_platform/eeprom.py b/ixr7220h5-64d/sonic_platform/eeprom.py index 7f6544a..820e742 100644 --- a/ixr7220h5-64d/sonic_platform/eeprom.py +++ b/ixr7220h5-64d/sonic_platform/eeprom.py @@ -1,20 +1,19 @@ -######################################################################## -# Nokia 7220 IXR H5-64D -# -# Module contains platform specific implementation of SONiC Platform -# Base API and provides the EEPROMs' information. -# -# The different EEPROMs available are as follows: -# - System EEPROM : Contains Serial number, Service tag, Base MA -# address, etc. in ONIE TlvInfo EEPROM format. -######################################################################## +""" + Nokia 7220 IXR H5-64D + Module contains platform specific implementation of SONiC Platform + Base API and provides the EEPROMs' information. + + The different EEPROMs available are as follows: + - System EEPROM : Contains Serial number, Service tag, Base MA + address, etc. in ONIE TlvInfo EEPROM format. +""" try: from sonic_platform_base.sonic_eeprom.eeprom_tlvinfo import TlvInfoDecoder from sonic_py_common import logger except ImportError as e: - raise ImportError(str(e) + "- required module not found") + raise ImportError(str(e) + ' - required module not found') from e sonic_logger = logger.Logger('eeprom') @@ -22,32 +21,29 @@ class Eeprom(TlvInfoDecoder): """Nokia platform-specific EEPROM class""" I2C_DIR = "/sys/bus/i2c/devices/" - I2C_FAN_LIST = ["58", "59", "60", "61", "62", "63"] def __init__(self, is_psu, psu_index, is_fan, drawer_index): self.is_psu_eeprom = is_psu self.is_fan_eeprom = is_fan self.is_sys_eeprom = not (is_psu | is_fan) - + self.service_tag = 'NA' + self.part_number = 'NA' + if self.is_sys_eeprom: self.start_offset = 0 - self.eeprom_path = self.I2C_DIR + "0-0053/eeprom" + self.eeprom_path = self.I2C_DIR + "4-0054/eeprom" # System EEPROM is in ONIE TlvInfo EEPROM format super(Eeprom, self).__init__(self.eeprom_path, self.start_offset, '', True) - self._load_system_eeprom() - - elif self.is_psu_eeprom: - self.part_number = '1' + self.base_mac = '' + self.serial_number = '' + self.part_number = '' self.model_str = '' - self.serial_number = 'NA' - self.serial_number = 'NA' - - elif self.is_fan_eeprom: - self.start_offset = 0 - self.eeprom_path = self.I2C_DIR + "{0}-0050/eeprom".format(self.I2C_FAN_LIST[drawer_index]) - # Fan EEPROM is in ONIE TlvInfo EEPROM format - super(Eeprom, self).__init__(self.eeprom_path, self.start_offset, '', True) - self._load_system_eeprom() + self.service_tag = '' + else: + self.serial_number = 'N/A' + self.part_number = 'N/A' + self.model_str = 'N/A' + self.service_tag = 'N/A' def _load_system_eeprom(self): """ @@ -108,8 +104,7 @@ def _load_system_eeprom(self): self.model_str = self.eeprom_tlv_dict.get( "0x%X" % (self._TLV_CODE_PRODUCT_NAME), 'NA') self.service_tag = self.eeprom_tlv_dict.get( - "0x%X" % (self._TLV_CODE_SERVICE_TAG), 'NA') - + "0x%X" % (self._TLV_CODE_SERVICE_TAG), 'NA') def _get_eeprom_field(self, field_name): """ @@ -129,12 +124,18 @@ def serial_number_str(self): """ Returns the serial number. """ + if not self.serial_number: + self._load_system_eeprom() + return self.serial_number def part_number_str(self): """ Returns the part number. """ + if not self.part_number: + self._load_system_eeprom() + return self.part_number def airflow_fan_type(self): @@ -146,17 +147,22 @@ def airflow_fan_type(self): if self.is_fan_eeprom: return int(self.fan_type.encode('hex'), 16) - # System EEPROM specific methods def base_mac_addr(self): """ Returns the base MAC address found in the system EEPROM. """ + if not self.base_mac: + self._load_system_eeprom() + return self.base_mac def modelstr(self): """ Returns the Model name. """ + if not self.model_str: + self._load_system_eeprom() + return self.model_str def service_tag_str(self): diff --git a/ixr7220h5-64d/sonic_platform/fan.py b/ixr7220h5-64d/sonic_platform/fan.py index 654d2f0..654d24e 100644 --- a/ixr7220h5-64d/sonic_platform/fan.py +++ b/ixr7220h5-64d/sonic_platform/fan.py @@ -1,139 +1,75 @@ -######################################################################## -# Nokia IXR7220 H5-64D -# -# Module contains an implementation of SONiC Platform Base API and -# provides the Fans' information which are available in the platform -# -######################################################################## +""" + Nokia IXR7220 H5-64D + Module contains an implementation of SONiC Platform Base API and + provides the Fans' information which are available in the platform +""" try: import os - import time import glob - import struct - from os import * - from mmap import * from sonic_platform_base.fan_base import FanBase - from sonic_platform.eeprom import Eeprom + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file from sonic_py_common import logger except ImportError as e: raise ImportError(str(e) + "- required module not found") -H5_64D_FANS_PER_DRAWER = 2 - -FAN_PN_F2B = "F2B_FAN" -FAN_PN_B2F = "B2F_FAN" +FANS_PER_DRAWER = 2 +FAN_PN_F2B = "3HE20602AA" +FAN_PN_B2F = "3HE20603AA" MAX_FAN_F_SPEED = 15700 MAX_FAN_R_SPEED = 14600 FAN_TOLERANCE = 50 -WORKING_ixr7220_FAN_SPEED = 1500 - -HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" -I2C_DEV_LIST = [("5-002d", "5-002d"), - ("5-002d", "5-002d"), - ("5-004c", "5-004c"), - ("5-004c", "5-004c")] -FAN_INDEX_IN_DRAWER = [(1, 2), - (3, 4), +WORKING_FAN_SPEED = 1500 + +HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" +I2C_DEV_LIST = [("17-002d", "17-002d"), + ("17-002d", "17-002d"), + ("17-004c", "17-004c"), + ("17-004c", "17-004c")] +FAN_INDEX_IN_DRAWER = [(3, 4), (1, 2), - (3, 4)] -GPIO_DIR = "/sys/class/gpio/gpio{}/" -GPIO_PORT = [10224, 10225, 10226, 10227] -RESOURCE = "/sys/bus/pci/devices/0000:02:00.0/resource0" -REG_FAN_LED = 0x00A0 -INDEX_FAN_LED = [0, 4, 8, 12] - + (3, 4), + (1, 2)] +GPIO_DIR = "/sys/class/gpio/gpio{}/" +GPIO_PORT = [9939, 9938, 9937, 9936] +FPGA_DIR = "/sys/kernel/sys_fpga/" +I2C_BUS = [33, 32, 31, 30] sonic_logger = logger.Logger('fan') - class Fan(FanBase): """Nokia platform-specific Fan class""" - def __init__(self, fan_index, drawer_index, psu_fan=False, dependency=None): + def __init__(self, fan_index, drawer_index, drawer_eeprom=None, psu_fan=False, dependency=None): self.is_psu_fan = psu_fan i2c_dev = I2C_DEV_LIST[drawer_index][fan_index] hwmon_path = glob.glob(HWMON_DIR.format(i2c_dev)) + self.fan_led_color = ['off', 'green','amber', 'green_blink', + 'amber_blink', 'alter_green_amber', 'off', 'off'] + i2c_bus = I2C_BUS[drawer_index] + self.eeprom_dir = f"/sys/bus/i2c/devices/i2c-{i2c_bus}/{i2c_bus}-0050/" + self.new_cmd = f"echo eeprom_tlv 0x50 > /sys/bus/i2c/devices/i2c-{i2c_bus}/new_device" + self.del_cmd = f"echo 0x50 > /sys/bus/i2c/devices/i2c-{i2c_bus}/delete_device" if not self.is_psu_fan: # Fan is 1-based in Nokia platforms - self.index = drawer_index * H5_64D_FANS_PER_DRAWER + fan_index + 1 + self.index = drawer_index * FANS_PER_DRAWER + fan_index + 1 self.fan_drawer = drawer_index fan_index_emc230x = FAN_INDEX_IN_DRAWER[drawer_index][fan_index] - self.set_fan_speed_reg = hwmon_path[0] + "pwm{}".format(fan_index_emc230x) - self.get_fan_speed_reg = hwmon_path[0] + "fan{}_input".format(fan_index_emc230x) + self.set_fan_speed_reg = hwmon_path[0] + f"pwm{fan_index_emc230x}" + self.get_fan_speed_reg = hwmon_path[0] + f"fan{fan_index_emc230x}_input" self.gpio_dir = GPIO_DIR.format(GPIO_PORT[drawer_index]) - - # Fan eeprom - self.eeprom = Eeprom(False, 0, True, drawer_index) if fan_index == 0: - self.max_fan_speed = MAX_FAN_F_SPEED + self.max_fan_speed = MAX_FAN_F_SPEED else: - self.max_fan_speed = MAX_FAN_R_SPEED - + self.max_fan_speed = MAX_FAN_R_SPEED + else: # this is a PSU Fan self.index = fan_index self.dependency = dependency - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv - - def _write_sysfs_file(self, sysfs_file, value): - # On successful write, the value read will be written on - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'w') as fd: - rv = fd.write(value) - except Exception as e: - rv = 'ERR' - - # Ensure that the write operation has succeeded - if (int(self._read_sysfs_file(sysfs_file)) != value ): - time.sleep(3) - if (int(self._read_sysfs_file(sysfs_file)) != value ): - rv = 'ERR' - - return rv - - def pci_set_value(resource, data, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - mm.write(struct.pack('I', data)) - mm.close() - close(fd) - - def pci_get_value(resource, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - read_data_stream = mm.read(4) - reg_val = struct.unpack('I', read_data_stream) - mm.close() - close(fd) - return reg_val - - def get_name(self): """ Retrieves the name of the Fan @@ -142,9 +78,9 @@ def get_name(self): string: The name of the Fan """ if not self.is_psu_fan: - return "Fan{}".format(self.index) + return f"Fan{self.index}" else: - return "PSU{} Fan".format(self.index) + return f"PSU{self.index}_Fan" def get_presence(self): """ @@ -153,11 +89,15 @@ def get_presence(self): Returns: bool: True if Fan is present, False if not """ - result = self._read_sysfs_file(self.gpio_dir + 'value') - if result == '0': + result = read_sysfs_file(self.gpio_dir + 'value') + if result == '0': # present + if not os.path.exists(self.eeprom_dir): + os.system(self.new_cmd) return True - else: - return False + # not present + if os.path.exists(self.eeprom_dir): + os.system(self.del_cmd) + return False def get_model(self): """ @@ -166,7 +106,7 @@ def get_model(self): Returns: string: Model number of Fan. Use part number for this. """ - return self.eeprom.modelstr() + return 'N/A' def get_serial(self): """ @@ -175,7 +115,10 @@ def get_serial(self): Returns: string: Serial number of Fan """ - return self.eeprom.serial_number_str() + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "serial_number") + return result.strip() + return 'N/A' def get_part_number(self): """ @@ -184,7 +127,10 @@ def get_part_number(self): Returns: string: Part number of Fan """ - return self.eeprom.part_number_str() + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "part_number") + return result.strip() + return 'N/A' def get_service_tag(self): """ @@ -193,7 +139,7 @@ def get_service_tag(self): Returns: string: Service Tag of Fan """ - return self.eeprom.service_tag_str() + return 'N/A' def get_status(self): """ @@ -204,9 +150,9 @@ def get_status(self): """ status = False - fan_speed = self._read_sysfs_file(self.get_fan_speed_reg) + fan_speed = read_sysfs_file(self.get_fan_speed_reg) if (fan_speed != 'ERR'): - if (int(fan_speed) > WORKING_ixr7220_FAN_SPEED): + if (int(fan_speed) > WORKING_FAN_SPEED): status = True return status @@ -220,9 +166,9 @@ def get_direction(self): FAN_DIRECTION_EXHAUST depending on fan direction """ part_number = self.get_part_number() - if part_number == FAN_PN_F2B: + if part_number[:10] == FAN_PN_F2B: return self.FAN_DIRECTION_INTAKE - elif part_number == FAN_PN_F2B: + if part_number[:10] == FAN_PN_F2B: return self.FAN_DIRECTION_EXHAUST else: return 'N/A' @@ -252,17 +198,15 @@ def get_speed(self): """ speed = 0 - fan_speed = self._read_sysfs_file(self.get_fan_speed_reg) + fan_speed = read_sysfs_file(self.get_fan_speed_reg) if (fan_speed != 'ERR'): speed_in_rpm = int(fan_speed) else: speed_in_rpm = 0 - speed = 100*speed_in_rpm//self.max_fan_speed - if speed > 100: - speed = 100 + speed = round(100*speed_in_rpm/self.max_fan_speed) - return speed + return min(speed, 100) def get_speed_tolerance(self): """ @@ -272,7 +216,6 @@ def get_speed_tolerance(self): An integer, the percentage of variance from target speed which is considered tolerable """ - return FAN_TOLERANCE def set_speed(self, speed): @@ -287,24 +230,27 @@ def set_speed(self, speed): if self.is_psu_fan: return False - if speed in range(0, 10): - fandutycycle = 0x00 - elif speed in range(10, 21): - fandutycycle = 32 - elif speed in range(21, 31): - fandutycycle = 64 - elif speed in range(31, 46): - fandutycycle = 102 - elif speed in range(46, 61): - fandutycycle = 140 - elif speed in range(61, 81): - fandutycycle = 204 - elif speed in range(81, 101): - fandutycycle = 255 - else: - return False - - rv = self._write_sysfs_file(self.set_fan_speed_reg, str(fandutycycle)) + speed_to_duty = { + range(0, 10): 0x00, + range(10, 20): 40, + range(20, 30): 64, + range(30, 40): 90, + range(40, 54): 115, + range(54, 66): 153, + range(66, 76): 179, + range(76, 86): 204, + range(86, 96): 230, + range(96, 101): 255 + } + + fan_duty_cycle = None + + for speed_range, duty in speed_to_duty.items(): + if speed in speed_range: + fan_duty_cycle = duty + break + + rv = write_sysfs_file(self.set_fan_speed_reg, str(fan_duty_cycle)) if (rv != 'ERR'): return True else: @@ -318,10 +264,7 @@ def set_status_led(self, color): fan module status LED Returns: bool: True if set success, False if fail. - - off , red and green are the only settings 7215 fans """ - return False def get_status_led(self): @@ -331,25 +274,17 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ - if not self.get_presence(): - return self.STATUS_LED_COLOR_OFF - - val = self.pci_get_value(RESOURCE, REG_FAN_LED) - result = val[0] & (0x7<> INDEX_FAN_LED[self.fan_drawer] - - if result == 0 or result == 6 or result == 7: - return self.STATUS_LED_COLOR_OFF - elif result == 1: - return self.STATUS_LED_COLOR_GREEN - elif result == 2: - return self.STATUS_LED_COLOR_AMBER - elif result == 3: - return self.STATUS_LED_COLOR_GREEN_BLINK - elif result == 4: - return self.STATUS_LED_COLOR_AMBER_BLINK - else: + if not self.get_presence(): return 'N/A' + result = read_sysfs_file(FPGA_DIR + f'fan{self.fan_drawer+1}_led') + val = int(result, 16) & 0x7 + + if val < len(self.fan_led_color): + return self.fan_led_color[val] + + return 'N/A' + def get_target_speed(self): """ Retrieves the target (expected) speed of the fan @@ -358,24 +293,21 @@ def get_target_speed(self): An integer, the percentage of full fan speed, in the range 0 (off) to 100 (full speed) """ - speed = 0 - - fan_duty = self._read_sysfs_file(self.set_fan_speed_reg) - if (fan_duty != 'ERR'): + duty_to_speed = { + 0: 0, + 40: 15, + 64: 25, + 90: 35, + 115: 45, + 153: 60, + 179: 70, + 204: 80, + 230: 90, + 255: 100 + } + + fan_duty = read_sysfs_file(self.set_fan_speed_reg) + if fan_duty != 'ERR': dutyspeed = int(fan_duty) - if dutyspeed == 0: - speed = 0 - elif dutyspeed == 32: - speed = 15 - elif dutyspeed == 64: - speed = 25 - elif dutyspeed == 102: - speed = 40 - elif dutyspeed == 140: - speed = 50 - elif dutyspeed == 204: - speed = 70 - elif dutyspeed == 255: - speed = 100 - - return speed + return duty_to_speed.get(dutyspeed, 0) + return 0 diff --git a/ixr7220h5-64d/sonic_platform/fan_drawer.py b/ixr7220h5-64d/sonic_platform/fan_drawer.py index 3683b4a..0bd30e9 100644 --- a/ixr7220h5-64d/sonic_platform/fan_drawer.py +++ b/ixr7220h5-64d/sonic_platform/fan_drawer.py @@ -1,30 +1,68 @@ -############################################################################# -# Nokia -# -# Module contains an implementation of SONiC Platform Base API and -# provides the Fan Drawer status which is available in the platform -# -############################################################################# +""" + Nokia + + Module contains an implementation of SONiC Platform Base API and + provides the Fan Drawer status which is available in the platform +""" try: + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file from sonic_platform_base.fan_drawer_base import FanDrawerBase from sonic_py_common import logger + import os except ImportError as e: - raise ImportError(str(e) + "- required module not found") + raise ImportError(str(e) + ' - required module not found') from e + +FANS_PER_DRAWER = 2 +FAN_PN_F2B = "3HE20602AA" +FAN_PN_B2F = "3HE20603AA" +GPIO_DIR = "/sys/class/gpio/gpio{}/" +GPIO_PORT = [9939, 9938, 9937, 9936] +FPGA_DIR = "/sys/kernel/sys_fpga/" +I2C_BUS = [33, 32, 31, 30] sonic_logger = logger.Logger('fan_drawer') class NokiaFanDrawer(FanDrawerBase): def __init__(self, index): - super(NokiaFanDrawer, self).__init__() + super().__init__() self._index = index + 1 - self._led = None + self.gpio_dir = GPIO_DIR.format(GPIO_PORT[index]) + self.fan_led_color = ['off', 'green','amber', 'green_blink', + 'amber_blink', 'alter_green_amber', 'off', 'off'] + + # Possible fan directions (relative to port-side of device) + self.fan_direction_intake = "intake" + self.fan_direction_exhaust = "exhaust" + i2c_bus = I2C_BUS[index] + self.eeprom_dir = f"/sys/bus/i2c/devices/{i2c_bus}-0050/" + self.new_cmd = f"echo eeprom_tlv 0x50 > /sys/bus/i2c/devices/i2c-{i2c_bus}/new_device" + self.del_cmd = f"echo 0x50 > /sys/bus/i2c/devices/i2c-{i2c_bus}/delete_device" def get_index(self): + """ + Retrieves the index of the Fan Drawer + Returns: + int: the Fan Drawer's index + """ return self._index def get_presence(self): - return self._fan_list[0].get_presence() + """ + Retrieves the presence of the Fan Drawer + Returns: + bool: return True if the Fan Drawer is present + """ + result = read_sysfs_file(self.gpio_dir + 'value') + if result == '0': # present + if not os.path.exists(self.eeprom_dir): + os.system(self.new_cmd) + return True + # not present + if os.path.exists(self.eeprom_dir): + os.system(self.del_cmd) + return False + def get_model(self): """ @@ -32,7 +70,7 @@ def get_model(self): Returns: string: Part number of Fan Drawer """ - return self._fan_list[0].get_model() + return 'N/A' def get_serial(self): """ @@ -40,7 +78,22 @@ def get_serial(self): Returns: string: Serial number of Fan """ - return self._fan_list[0].get_serial() + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "serial_number") + return result.strip() + return 'N/A' + + def get_part_number(self): + """ + Retrieves the part number of the Fan Drawer + + Returns: + string: Part number of Fan + """ + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "part_number") + return result.strip() + return 'N/A' def get_status(self): """ @@ -48,10 +101,27 @@ def get_status(self): Returns: bool: True if Fan is operating properly, False if not """ - return self._fan_list[0].get_status() + good_fan = 0 + for fan in self._fan_list: + if fan.get_status(): + good_fan = good_fan + 1 + + if good_fan == FANS_PER_DRAWER: + return True + return False def get_direction(self): - return 'intake' + """ + Retrieves the direction of the Fan Drawer + Returns: + string: direction string + """ + part_number = self.get_part_number() + if part_number[:10] == FAN_PN_F2B: + return self.fan_direction_intake + if part_number[:10] == FAN_PN_B2F: + return self.fan_direction_exhaust + return 'N/A' def set_status_led(self, color): """ @@ -64,7 +134,17 @@ def set_status_led(self, color): Returns: bool: True if status LED state is set successfully, False if not """ - return self._fan_list[0].set_status_led(color) + if not self.get_presence(): + return False + + try: + value = self.fan_led_color.index(color) + result = write_sysfs_file(FPGA_DIR + f'fan{self._index}_led', str(value)) + if result: + return True + return False + except ValueError: + return False def get_status_led(self): """ @@ -73,7 +153,16 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings """ - return self._fan_list[0].get_status_led() + if not self.get_presence(): + return 'N/A' + + result = read_sysfs_file(FPGA_DIR + f'fan{self._index}_led') + val = int(result, 16) & 0x7 + + if val < len(self.fan_led_color): + return self.fan_led_color[val] + + return 'N/A' def is_replaceable(self): """ @@ -81,7 +170,7 @@ def is_replaceable(self): Returns: bool: True if it is replaceable. """ - return False + return True def get_position_in_parent(self): """ @@ -91,12 +180,16 @@ def get_position_in_parent(self): """ return self._index - -# For Nokia platforms with fan drawer(s) class RealDrawer(NokiaFanDrawer): + """ + For Nokia platforms with fan drawer(s) + """ def __init__(self, index): super(RealDrawer, self).__init__(index) - self._name = 'drawer{}'.format(self._index) + self._name = f'drawer{self._index}' def get_name(self): - return self._name \ No newline at end of file + """ + return module name + """ + return self._name diff --git a/ixr7220h5-64d/sonic_platform/psu.py b/ixr7220h5-64d/sonic_platform/psu.py index 46d3fc7..d1a3a3b 100644 --- a/ixr7220h5-64d/sonic_platform/psu.py +++ b/ixr7220h5-64d/sonic_platform/psu.py @@ -1,36 +1,34 @@ -######################################################################## -# Nokia IXR7220 H5-64D -# -# Module contains an implementation of SONiC Platform Base API and -# provides the PSUs' information which are available in the platform -# -######################################################################## +""" + Nokia IXR7220 H5-64D + + Module contains an implementation of SONiC Platform Base API and + provides the PSUs' information which are available in the platform +""" try: - import os - import time - import struct - from os import * - from mmap import * + from sonic_platform.sysfs import read_sysfs_file from sonic_platform_base.psu_base import PsuBase from sonic_py_common import logger - from sonic_platform.eeprom import Eeprom - from sonic_py_common.general import getstatusoutput_noshell + import os except ImportError as e: - raise ImportError(str(e) + "- required module not found") + raise ImportError(str(e) + ' - required module not found') from e + +PSU_NUM = 2 +PSU_DIR = ["/sys/bus/i2c/devices/15-0058/", + "/sys/bus/i2c/devices/15-0059/"] +PSU_EEPROM_DIR = ["/sys/bus/i2c/devices/15-0050/", + "/sys/bus/i2c/devices/15-0051/"] +EEPROM_I2CBUS = 15 +EEPROM_ADDR = ['0050', '0051'] +FPGA_DIR = "/sys/kernel/sys_fpga/" +MAX_VOLTAGE = 13 +MIN_VOLTAGE = 11 sonic_logger = logger.Logger('psu') -H5_64D_PSU = 2 -PSU_DIR = ["/sys/bus/i2c/devices/2-0058/", - "/sys/bus/i2c/devices/3-0058/"] -RESOURCE = "/sys/bus/pci/devices/0000:02:00.0/resource0" -REG_BRD_CTRL4 = 0x0020 -REG_FRONT_LED = [0x008C, 0x0090] -INDEX_PSU_PRES = [16, 20] -INDEX_PSU_OK = [17, 21] +sonic_logger.set_min_log_priority_error() class Psu(PsuBase): - """Nokia platform-specific PSU class for 7220 H4-32D """ + """Nokia platform-specific PSU class for 7220 H5-64D """ def __init__(self, psu_index): PsuBase.__init__(self) @@ -38,68 +36,14 @@ def __init__(self, psu_index): self.index = psu_index + 1 self._fan_list = [] self.psu_dir = PSU_DIR[psu_index] - - - # PSU eeprom - #self.eeprom = Eeprom(is_psu=True, psu_index=self.index) - self.MAX_VOLTAGE = 14 - self.MIN_VOLTAGE = 10 - - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv - - def _write_sysfs_file(self, sysfs_file, value): - # On successful write, the value read will be written on - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'w') as fd: - rv = fd.write(value) - except Exception as e: - rv = 'ERR' - - # Ensure that the write operation has succeeded - if ((self._read_sysfs_file(sysfs_file)) != value ): - time.sleep(3) - if ((self._read_sysfs_file(sysfs_file)) != value ): - rv = 'ERR' - - return rv - - def pci_set_value(resource, data, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - mm.write(struct.pack('I', data)) - mm.close() - close(fd) - - def pci_get_value(resource, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - read_data_stream = mm.read(4) - reg_val = struct.unpack('I', read_data_stream) - mm.close() - close(fd) - return reg_val + i2c_addr = EEPROM_ADDR[psu_index] + self.eeprom_dir = f"/sys/bus/i2c/devices/i2c-15/15-{i2c_addr}/" + self.new_cmd = f"echo eeprom_fru 0x{i2c_addr} > /sys/bus/i2c/devices/i2c-{EEPROM_I2CBUS}/new_device" + self.del_cmd = f"echo 0x{i2c_addr} > /sys/bus/i2c/devices/i2c-{EEPROM_I2CBUS}/delete_device" + self.prev_presence = '0x1' + self.psu_led_color = ['off', 'green', 'amber', 'green_blink', + 'amber_blink', 'alter_green_amber', 'off', 'by_pin'] + def _get_active_psus(self): """ @@ -108,15 +52,13 @@ def _get_active_psus(self): Returns: Integer: Number of active PSU's - """ + """ active_psus = 0 + for i in range(PSU_NUM): + psu_result = read_sysfs_file(FPGA_DIR + f'psu{i+1}_ok') + if psu_result == "0x0": + active_psus = active_psus + 1 - val = self.pci_get_value(RESOURCE, REG_BRD_CTRL4) - for i in range(H5_64D_PSU): - psu_result = (val[0] & (1<> INDEX_PSU_OK[i] - if psu_result == '0': - active_psus = active_psus + 1 - return active_psus def get_name(self): @@ -126,7 +68,7 @@ def get_name(self): Returns: string: The name of the device """ - return "PSU{}".format(self.index) + return f"PSU{self.index}" def get_presence(self): """ @@ -135,12 +77,14 @@ def get_presence(self): Returns: bool: True if PSU is present, False if not """ - val = self.pci_get_value(RESOURCE, REG_BRD_CTRL4) - result = (val[0] & (1<> INDEX_PSU_PRES[self.index-1] - - if result == '0': + result = read_sysfs_file(FPGA_DIR + f"psu{self.index}_pres") + if result == '0x0': # present + if not os.path.exists(self.eeprom_dir): + os.system(self.new_cmd) return True - + # not present + if os.path.exists(self.eeprom_dir): + os.system(self.del_cmd) return False def get_model(self): @@ -150,12 +94,11 @@ def get_model(self): Returns: string: Part number of PSU """ - if (self.get_presence()): - psu_sysfs_str = self.psu_dir + "psu_mfr_model" - result = self._read_sysfs_file(psu_sysfs_str) - return result - else: - return 'N/A' + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "part_number") + return result.strip() + + return 'N/A' def get_serial(self): """ @@ -164,13 +107,11 @@ def get_serial(self): Returns: string: Serial number of PSU """ - if (self.get_presence()): - psu_sysfs_str = self.psu_dir + "psu_mfr_serial" - result = self._read_sysfs_file(psu_sysfs_str) - return result - else: - return 'N/A' + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "serial_number") + return result.strip() + return 'N/A' def get_revision(self): """ @@ -179,6 +120,9 @@ def get_revision(self): Returns: string: HW revision of PSU """ + if self.get_presence(): + result = read_sysfs_file(self.eeprom_dir + "product_version") + return result.strip() return 'N/A' def get_part_number(self): @@ -188,12 +132,7 @@ def get_part_number(self): Returns: string: Part number of PSU """ - if (self.get_presence()): - psu_sysfs_str = self.psu_dir + "psu_mfr_model" - result = self._read_sysfs_file(psu_sysfs_str) - return result - else: - return 'N/A' + return 'N/A' def get_status(self): """ @@ -202,10 +141,8 @@ def get_status(self): Returns: bool: True if PSU is operating properly, False if not """ - val = self.pci_get_value(RESOURCE, REG_BRD_CTRL4) - result = (val[0] & (1<> INDEX_PSU_OK[self.index-1] - - if result == '0': + result = read_sysfs_file(FPGA_DIR + f"psu{self.index}_ok") + if result == '0x0': return True return False @@ -218,14 +155,20 @@ def get_voltage(self): A float number, the output voltage in volts, e.g. 12.1 """ - if(self.get_status()): - result = self._read_sysfs_file(self.psu_dir+"in2_input") + if self.get_presence(): + result = read_sysfs_file(self.psu_dir + "psu_v_out") psu_voltage = (float(result))/1000 else: - psu_voltage = 0.0 + psu_voltage = 0.0 + + if self.get_status() and self.get_model()[0:8] == "3HE20598": + result = read_sysfs_file(self.psu_dir+"psu_v_in") + voltage_in = (float(result))/1000 + if voltage_in < 170: + sonic_logger.log_error(f"!ERROR!: PSU {self.index} not supplying enough voltage. {voltage_in}v is less than the required 200-220V") return psu_voltage - + def get_current(self): """ Retrieves present electric current supplied by PSU @@ -233,15 +176,14 @@ def get_current(self): Returns: A float number, the electric current in amperes, e.g 15.4 """ - - if(self.get_status()): - result = self._read_sysfs_file(self.psu_dir+"curr2_input") + if self.get_presence(): + result = read_sysfs_file(self.psu_dir + "psu_i_out") psu_current = (float(result))/1000 else: psu_current = 0.0 return psu_current - + def get_power(self): """ Retrieves current energy supplied by PSU @@ -249,12 +191,9 @@ def get_power(self): Returns: A float number, the power in watts, e.g. 302.6 """ - # psu_voltage = self.get_voltage() - # psu_current = self.get_current() - # psu_power = psu_voltage * psu_current - if(self.get_status()): - result = self._read_sysfs_file(self.psu_dir+"power1_input") - psu_power = (float(result))/1000000 + if self.get_presence(): + result = read_sysfs_file(self.psu_dir + "psu_p_in") + psu_power = (float(result))/1000 else: psu_power = 0.0 @@ -276,7 +215,7 @@ def get_voltage_high_threshold(self): A float number, the high threshold output voltage in volts, e.g. 12.1 """ - return self.MAX_VOLTAGE + return MAX_VOLTAGE def get_voltage_low_threshold(self): """ @@ -286,8 +225,8 @@ def get_voltage_low_threshold(self): A float number, the low threshold output voltage in volts, e.g. 12.1 """ - return self.MIN_VOLTAGE - + return MIN_VOLTAGE + def is_replaceable(self): """ Indicate whether this device is replaceable. @@ -303,13 +242,7 @@ def get_powergood_status(self): A boolean, True if PSU has stablized its output voltages and passed all its internal self-tests, False if not. """ - val = self.pci_get_value(RESOURCE, REG_BRD_CTRL4) - result = (val[0] & (1<> INDEX_PSU_OK[self.index-1] - - if result == '0': - return True - - return False + return self.get_status() def get_status_led(self): """ @@ -318,29 +251,13 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ - val = self.pci_get_value(RESOURCE, REG_FRONT_LED[self.index-1]) - result = val[0] & 0x7 - - if result == 0 or result == 6: - return self.STATUS_LED_COLOR_OFF - elif result == 1: - return self.STATUS_LED_COLOR_GREEN - elif result == 2: - return self.STATUS_LED_COLOR_AMBER - elif result == 3: - return self.STATUS_LED_COLOR_GREEN_BLINK - elif result == 4: - return self.STATUS_LED_COLOR_AMBER_BLINK - elif result == 7: - if self.get_presence(): - if self.get_status(): - return self.STATUS_LED_COLOR_GREEN - else: - return self.STATUS_LED_COLOR_AMBER + if self.get_presence(): + if self.get_status(): + return self.STATUS_LED_COLOR_GREEN else: - return self.STATUS_LED_COLOR_OFF + return self.STATUS_LED_COLOR_AMBER else: - return 'N/A' + return 'N/A' def set_status_led(self, color): """ @@ -352,7 +269,6 @@ def set_status_led(self, color): bool: True if status LED state is set successfully, False if not """ - return False def get_status_master_led(self): @@ -362,20 +278,10 @@ def get_status_master_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings. """ - val = self.pci_get_value(RESOURCE, REG_FRONT_LED[self.index-1]) - result = val[0] & 0x7 - - if result == 0 or result == 6: - return self.STATUS_LED_COLOR_OFF - elif result == 1: - return self.STATUS_LED_COLOR_GREEN - elif result == 2: - return self.STATUS_LED_COLOR_AMBER - elif result == 3: - return self.STATUS_LED_COLOR_GREEN_BLINK - elif result == 4: - return self.STATUS_LED_COLOR_AMBER_BLINK - elif result == 7: + result = read_sysfs_file(FPGA_DIR + f'led_psu{self.index}') + val = int(result, 16) & 0x7 + + if val == 7: if self.get_presence(): if self.get_status(): return self.STATUS_LED_COLOR_GREEN @@ -384,7 +290,7 @@ def get_status_master_led(self): else: return self.STATUS_LED_COLOR_OFF else: - return 'N/A' + return self.psu_led_color[val] def set_status_master_led(self, color): """ @@ -394,5 +300,4 @@ def set_status_master_led(self, color): bool: True if status LED state is set successfully, False if not """ - return False diff --git a/ixr7220h5-64d/sonic_platform/sfp.py b/ixr7220h5-64d/sonic_platform/sfp.py index 01de43e..10c7b43 100644 --- a/ixr7220h5-64d/sonic_platform/sfp.py +++ b/ixr7220h5-64d/sonic_platform/sfp.py @@ -1,34 +1,30 @@ -# Name: sfp.py, version: 1.0 -# -# Description: Module contains the definitions of SFP related APIs -# for Nokia IXR 7220 H5-64D platform. -# -# Copyright (c) 2024, Nokia -# All rights reserved. -# +""" + Name: sfp.py, version: 1.0 + + Description: Module contains the definitions of SFP related APIs + for Nokia IXR 7220 H5-64D platform. + + Copyright (c) 2024, Nokia + All rights reserved. +""" try: - import os import time + import sys from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase - from sonic_py_common.logger import Logger - from sonic_py_common import device_info - from sonic_py_common.general import getstatusoutput_noshell - + from sonic_py_common import logger, device_info + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file except ImportError as e: - raise ImportError(str(e) + "- required module not found") - -import subprocess as cmd + raise ImportError(str(e) + ' - required module not found') from e -QSFP_PORT_NUM = 64 -QSFP_IN_SWPLD = 32 +PORT_NUM = 64 -SWPLD2_DIR = "/sys/bus/i2c/devices/9-0034/" -SWPLD3_DIR = "/sys/bus/i2c/devices/9-0035/" +SWPLD2_DIR = "/sys/bus/i2c/devices/21-0041/" +SWPLD3_DIR = "/sys/bus/i2c/devices/21-0045/" -# SFP PORT numbers - -logger = Logger() +SYSLOG_IDENTIFIER = "sfp" +sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) +sonic_logger.set_min_log_priority_info() class Sfp(SfpOptoeBase): """ @@ -37,7 +33,7 @@ class Sfp(SfpOptoeBase): instances = [] port_to_i2c_mapping = 0 - + def __init__(self, index, sfp_type, eeprom_path, port_i2c_map): SfpOptoeBase.__init__(self) @@ -47,58 +43,33 @@ def __init__(self, index, sfp_type, eeprom_path, port_i2c_map): self.eeprom_path = eeprom_path self.port_to_i2c_mapping = port_i2c_map - if index <= QSFP_PORT_NUM: + if index <= PORT_NUM: self.name = sfp_type + '_' + str(index) self.port_name = sfp_type + '_' + str(index-1) else: - self.name = sfp_type + '_' + str(index-QSFP_PORT_NUM) - self.port_name = sfp_type + '_' + str(index-QSFP_PORT_NUM-1) + self.name = sfp_type + '_' + str(index-PORT_NUM) + self.port_name = sfp_type + '_' + str(index-PORT_NUM-1) self.port_to_eeprom_mapping = {} self.port_to_eeprom_mapping[index] = eeprom_path - if self.index <= QSFP_IN_SWPLD: - self.swpld_path = SWPLD2_DIR + if (self.index >= 17 and self.index <= 32) or (self.index >= 49 and self.index <= 64): + self.swpld_path = SWPLD3_DIR else: - self.swpld_path = SWPLD3_DIR - + self.swpld_path = SWPLD2_DIR + self._version_info = device_info.get_sonic_version_info() self.lastPresence = False - logger.log_debug("Sfp __init__ index {} setting name to {} and eeprom_path to {}".format(index, self.name, self.eeprom_path)) + #sonic_logger.log_info(f"Sfp __init__ index {index} setting name to {self.name} " + # "and eeprom_path to {self.eeprom_path}") Sfp.instances.append(self) - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv - - def _write_sysfs_file(self, sysfs_file, value): - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'w') as fd: - rv = fd.write(value) - except Exception as e: - rv = 'ERR' - - return rv - def get_eeprom_path(self): + """ + Retrieves the eeprom path + Returns: + string: eeprom path + """ return self.eeprom_path def get_presence(self): @@ -106,13 +77,9 @@ def get_presence(self): Retrieves the presence Returns: bool: True if is present, False if not - """ - - if self.index <= QSFP_PORT_NUM: - sfpstatus = self._read_sysfs_file(self.swpld_path+"qsfp{}_prs".format(self.index)) - else: - sfpstatus = self._read_sysfs_file(self.swpld_path+"sfp{}_prs".format(self.index - QSFP_PORT_NUM - 1)) - + """ + sfpstatus = read_sysfs_file(self.swpld_path+f"port_{self.index}_prs") + if sfpstatus == '0': return True @@ -176,18 +143,23 @@ def get_reset_status(self): Returns: A Boolean, True if reset enabled, False if disabled """ + if self.index <= PORT_NUM: + result = read_sysfs_file(self.swpld_path+f"port_{self.index}_rst") + if result == '0': + return True + return False return False + def get_status(self): """ Retrieves the operational status of the device """ + status = True reset = self.get_reset_status() - - if reset is True: - status = False - else: - status = True + if self.get_presence(): + if not reset: + status = True return status @@ -197,13 +169,35 @@ def reset(self): Returns: A boolean, True if successful, False if not """ + if not self.get_presence(): + sys.stderr.write(f"Error: Port {self.index} not inserted, could not reset it.\n\n") + return False + sonic_logger.log_info(f"Reseting port #{self.index}.") + result1 = 'ERR' result2 = 'ERR' - if self.index <= QSFP_PORT_NUM: - result1 = self._write_sysfs_file(self.swpld_path+"qsfp{}_rstn".format(self.index), '0') - time.sleep(1) - result2 = self._write_sysfs_file(self.swpld_path+"qsfp{}_rstn".format(self.index), '1') - + t = 0 + + if self.index <= PORT_NUM: + result2 = write_sysfs_file(self.swpld_path+f"port_{self.index}_reset", '1') + result2 = write_sysfs_file(self.swpld_path+f"port_{self.index}_lpmod", '1') + result1 = write_sysfs_file(self.swpld_path+f"port_{self.index}_rst", '1') + time.sleep(0.5) + while t < 10: + if read_sysfs_file(self.swpld_path+f"port_{self.index}_reset") == '2': + result1 = write_sysfs_file(self.swpld_path+f"port_{self.index}_rst", '0') + time.sleep(2) + break + time.sleep(0.5) + if t == 8: + sonic_logger.log_info(f"Reset port #{self.index} timeout, reset failed.") + return False + t = t + 1 + + result2 = write_sysfs_file(self.swpld_path+f"port_{self.index}_reset", '3') + else: + return False + if result1 != 'ERR' and result2 != 'ERR': return True @@ -214,18 +208,18 @@ def set_lpmode(self, lpmode): Sets the lpmode (low power mode) of SFP Args: lpmode: A Boolean, True to enable lpmode, False to disable it - Note : + Note : Returns: A boolean, True if lpmode is set successfully, False if not """ result = 'ERR' - if self.index <= QSFP_PORT_NUM: + if self.index <= PORT_NUM: if lpmode: - result = self._write_sysfs_file(self.swpld_path+"qsfp{}_lpmod".format(self.index), '1') + result = write_sysfs_file(self.swpld_path+f"port_{self.index}_lpmod", '1') else: - result = self._write_sysfs_file(self.swpld_path+"qsfp{}_lpmod".format(self.index), '0') - + result = write_sysfs_file(self.swpld_path+f"port_{self.index}_lpmod", '0') + if result != 'ERR': return True @@ -239,9 +233,9 @@ def get_lpmode(self): """ result = 'ERR' - if self.index <= QSFP_PORT_NUM: - result = self._read_sysfs_file(self.swpld_path+"qsfp{}_lpmod".format(self.index)) - + if self.index <= PORT_NUM: + result = read_sysfs_file(self.swpld_path+f"port_{self.index}_lpmod") + if result == '1': return True diff --git a/ixr7220h5-64d/sonic_platform/sfp_event.py b/ixr7220h5-64d/sonic_platform/sfp_event.py index b1d1f7b..69a5b6f 100644 --- a/ixr7220h5-64d/sonic_platform/sfp_event.py +++ b/ixr7220h5-64d/sonic_platform/sfp_event.py @@ -1,10 +1,13 @@ -''' -listen for the SFP change event and return to chassis. -''' -import os -import time -from sonic_py_common import logger -from sonic_py_common.general import getstatusoutput_noshell +"""" + listen for the SFP change event and return to chassis. +""" + +try: + import time + from sonic_py_common import logger + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e # system level event/error EVENT_ON_ALL_SFP = '-1' @@ -15,67 +18,77 @@ # SFP PORT numbers PORT_START = 1 PORT_END = 66 -QSFP_PORT_NUM = 64 -QSFP_IN_SWPLD = 32 +PORT_NUM = 64 -SWPLD2_DIR = "/sys/bus/i2c/devices/9-0034/" -SWPLD3_DIR = "/sys/bus/i2c/devices/9-0035/" +SWPLD2_DIR = "/sys/bus/i2c/devices/21-0041/" +SWPLD3_DIR = "/sys/bus/i2c/devices/21-0045/" SYSLOG_IDENTIFIER = "sfp_event" sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) +#sonic_logger.set_min_log_priority_info() - -class sfp_event: +class SfpEvent: ''' Listen to plugin/plugout cable events ''' def __init__(self): self.handle = None + self.modprs_list = [] - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv - def initialize(self): - self.modprs_list = [] # Get Transceiver status time.sleep(5) self.modprs_list = self._get_transceiver_status() - sonic_logger.log_info("Initial SFP presence=%s" % str(self.modprs_list)) + #sonic_logger.log_info(f"Initial SFP presence={str(self.modprs_list)}") + if self.modprs_list[PORT_END-2]: + write_sysfs_file(SWPLD2_DIR+"port_65_tx_en", '1') + if self.modprs_list[PORT_END-1]: + write_sysfs_file(SWPLD2_DIR+"port_66_tx_en", '1') def deinitialize(self): if self.handle is None: return def _get_transceiver_status(self): - port_status = [] + reg_value = [] + reg_value.append(read_sysfs_file(SWPLD2_DIR + "modprs_reg1")) + reg_value.append(read_sysfs_file(SWPLD2_DIR + "modprs_reg2")) + reg_value.append(read_sysfs_file(SWPLD3_DIR + "modprs_reg1")) + reg_value.append(read_sysfs_file(SWPLD3_DIR + "modprs_reg2")) + reg_value.append(read_sysfs_file(SWPLD2_DIR + "modprs_reg3")) + reg_value.append(read_sysfs_file(SWPLD2_DIR + "modprs_reg4")) + reg_value.append(read_sysfs_file(SWPLD3_DIR + "modprs_reg3")) + reg_value.append(read_sysfs_file(SWPLD3_DIR + "modprs_reg4")) + for i in range(8): + bin_str = f'{int(reg_value[i], 16):08b}' + bin_str = bin_str[::-1] + bool_list = [not bool(int(bit)) for bit in bin_str] + port_status.extend(bool_list) + for port in range (PORT_START, PORT_START + PORT_END): - if port <= QSFP_IN_SWPLD: - swpld_path = SWPLD2_DIR - else: - swpld_path = SWPLD3_DIR - if port <= QSFP_PORT_NUM: - status = self._read_sysfs_file(swpld_path+"qsfp{}_prs".format(port)) - else: - status = self._read_sysfs_file(swpld_path+"sfp{}_prs".format(port - QSFP_PORT_NUM - 1)) - - if status == '0': - port_status.append(True) + if port <= PORT_NUM: + if port_status[port-1]: + if (port >= 17 and port <= 32) or (port >= 49 and port <= 64): + swpld_path = SWPLD3_DIR + else: + swpld_path = SWPLD2_DIR + + reset_status = read_sysfs_file(swpld_path+f"port_{port}_reset") + if reset_status == '1': + port_status[port-1] = False + write_sysfs_file(swpld_path+f"port_{port}_reset", '2') + elif reset_status == '2': + port_status[port-1] = False + elif reset_status == '3': + port_status[port-1] = True + write_sysfs_file(swpld_path+f"port_{port}_reset", '0') + else: - port_status.append(False) + status = read_sysfs_file(SWPLD2_DIR+f"port_{port}_prs") + if status == '0': + port_status.append(True) + else: + port_status.append(False) return port_status @@ -95,21 +108,26 @@ def check_sfp_status(self, port_change, timeout): return False, {} end_time = start_time + timeout - if (start_time > end_time): + if start_time > end_time: return False, {} # Time wrap or possibly incorrect timeout while (timeout >= 0): # Check for OIR events and return updated port_change port_status = self._get_transceiver_status() - if (port_status != self.modprs_list): + if port_status != self.modprs_list: for i in range(PORT_END): - if (port_status[i] != self.modprs_list[i]): - # sfp_presence is active low + if port_status[i] != self.modprs_list[i]: if port_status[i] == True: port_change[i+1] = '1' else: port_change[i+1] = '0' + if (i == PORT_END -2) or (i == PORT_END -1): + if port_status[i]: + write_sysfs_file(SWPLD2_DIR+f"port_{i+1}_tx_en", '1') + else: + write_sysfs_file(SWPLD2_DIR+f"port_{i+1}_tx_en", '0') + # Update reg value self.modprs_list = port_status return True, port_change diff --git a/ixr7220h5-64d/sonic_platform/sysfs.py b/ixr7220h5-64d/sonic_platform/sysfs.py new file mode 100644 index 0000000..02c37b9 --- /dev/null +++ b/ixr7220h5-64d/sonic_platform/sysfs.py @@ -0,0 +1,57 @@ +""" + Nokia + + Module contains an implementation of SONiC Platform Base API and + provides the PSUs' information which are available in the platform +""" + +try: + import time +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e + +""" +Nokia platform-specific sysfs class +""" + +def read_sysfs_file(sysfs_file): + """ + On successful read, returns the value read from given + reg_name and on failure returns ERR + """ + rv = 'ERR' + + try: + with open(sysfs_file, 'r', encoding='utf-8') as fd: + rv = fd.read() + fd.close() + except FileNotFoundError: + print(f"Error: {sysfs_file} doesn't exist.") + except PermissionError: + print(f"Error: Permission denied when reading file {sysfs_file}.") + except IOError: + print(f"IOError: An error occurred while reading file {sysfs_file}.") + if rv != 'ERR': + rv = rv.rstrip('\r\n') + rv = rv.lstrip(" ") + return rv + +def write_sysfs_file(sysfs_file, value): + """ + On successful write, the value read will be written on + reg_name and on failure returns ERR + """ + rv = 'ERR' + + try: + with open(sysfs_file, 'w', encoding='utf-8') as fd: + rv = fd.write(value) + fd.close() + except FileNotFoundError: + print(f"Error: {sysfs_file} doesn't exist.") + except PermissionError: + print(f"Error: Permission denied when writing file {sysfs_file}.") + except IOError: + print(f"IOError: An error occurred while writing file {sysfs_file}.") + + return rv From 9b2c3a406e161b779f724e2df226d7c1d1f74830 Mon Sep 17 00:00:00 2001 From: y7zhou Date: Thu, 12 Dec 2024 09:44:39 -0500 Subject: [PATCH 3/4] [H5-64D]Add ports_notify and update FW upgrade, thermal info and watcdog modules --- ...sonic-platform-nokia-ixr7220h5-64d.install | 4 +- ...onic-platform-nokia-ixr7220h5-64d.postinst | 3 + ixr7220h5-64d/scripts/pcisysfs.py | 105 ------ ixr7220h5-64d/scripts/ports_notify.py | 121 +++++++ ixr7220h5-64d/service/ports_notify.service | 15 + ixr7220h5-64d/sonic_platform/component.py | 315 +++++++++++------- ixr7220h5-64d/sonic_platform/thermal.py | 121 +++---- ixr7220h5-64d/sonic_platform/watchdog.py | 82 ++--- 8 files changed, 405 insertions(+), 361 deletions(-) delete mode 100755 ixr7220h5-64d/scripts/pcisysfs.py create mode 100644 ixr7220h5-64d/scripts/ports_notify.py create mode 100644 ixr7220h5-64d/service/ports_notify.service diff --git a/debian/sonic-platform-nokia-ixr7220h5-64d.install b/debian/sonic-platform-nokia-ixr7220h5-64d.install index 4473981..2e2e306 100644 --- a/debian/sonic-platform-nokia-ixr7220h5-64d.install +++ b/debian/sonic-platform-nokia-ixr7220h5-64d.install @@ -1,5 +1,5 @@ - ixr7220h5-64d/scripts/h5_64d_platform_init.sh usr/local/bin -ixr7220h5-64d/scripts/pcisysfs.py usr/local/bin +ixr7220h5-64d/scripts/ports_notify.py usr/local/bin ixr7220h5-64d/service/h5_64d_platform_init.service etc/systemd/system +ixr7220h5-64d/service/ports_notify.service etc/systemd/system/ ixr7220h5-64d/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-nokia_ixr7220_h5_64d-r0 diff --git a/debian/sonic-platform-nokia-ixr7220h5-64d.postinst b/debian/sonic-platform-nokia-ixr7220h5-64d.postinst index 0dc4e8d..adf564c 100644 --- a/debian/sonic-platform-nokia-ixr7220h5-64d.postinst +++ b/debian/sonic-platform-nokia-ixr7220h5-64d.postinst @@ -4,5 +4,8 @@ # see: dh_installdeb(1) chmod a+x /usr/local/bin/h5_64d_platform_init.sh +chmod a+x /usr/local/bin/ports_notify.py systemctl enable h5_64d_platform_init.service systemctl start h5_64d_platform_init.service +systemctl enable ports_notify.service +systemctl start --no-block ports_notify.service diff --git a/ixr7220h5-64d/scripts/pcisysfs.py b/ixr7220h5-64d/scripts/pcisysfs.py deleted file mode 100755 index b305f54..0000000 --- a/ixr7220h5-64d/scripts/pcisysfs.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/python3 -# Copyright (c) 2015 Dell Inc. -# -# Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 -# -# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT -# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS -# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. -# -# See the Apache Version 2.0 License for specific language governing -# permissions and limitations under the License. - -import struct -import sys -import getopt -from os import * -from mmap import * - -def usage(): - ''' This is the Usage Method ''' - - print('\t\t pcisysfs.py --get --offset --res ') - print('\t\t pcisysfs.py --set --val --offset --res ') - sys.exit(1) - -def pci_mem_read(mm, offset): - mm.seek(offset) - read_data_stream = mm.read(4) - print("") - reg_val = struct.unpack('I', read_data_stream) - print("reg_val read:%x" % reg_val) - return reg_val - -def pci_mem_write(mm, offset, data): - mm.seek(offset) - print("data to write:%x" % data) - mm.write(struct.pack('I', data)) - -def pci_set_value(resource, val, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - pci_mem_write(mm, offset, val) - mm.close() - close(fd) - -def pci_get_value(resource, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - pci_mem_read(mm, offset) - mm.close() - close(fd) - -def main(argv): - - ''' The main function will read the user input from the - command line argument and process the request ''' - - opts = '' - val = '' - choice = '' - resource = '' - offset = '' - - try: - opts, args = getopt.getopt(argv, "hgsv:", - ["val=", "res=", "offset=", "help", "get", "set"]) - - except getopt.GetoptError: - usage() - - for opt, arg in opts: - - if opt in ('-h', '--help'): - choice = 'help' - - elif opt in ('-g', '--get'): - choice = 'get' - - elif opt in ('-s', '--set'): - choice = 'set' - - elif opt == '--res': - resource = arg - - elif opt == '--val': - val = int(arg, 16) - - elif opt == '--offset': - offset = int(arg, 16) - - if choice == 'set' and val != '' and offset != '' and resource != '': - pci_set_value(resource, val, offset) - - elif choice == 'get' and offset != '' and resource != '': - pci_get_value(resource, offset) - - else: - usage() - -# Calling the main method -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/ixr7220h5-64d/scripts/ports_notify.py b/ixr7220h5-64d/scripts/ports_notify.py new file mode 100644 index 0000000..3f31498 --- /dev/null +++ b/ixr7220h5-64d/scripts/ports_notify.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +""" + port_notify: + notify port status change from Sonic DB +""" + +try: + from swsscommon import swsscommon + from sonic_py_common import daemon_base, logger + from sonic_platform.sysfs import write_sysfs_file +except ImportError as e: + raise ImportError (str(e) + " - required module not found") + +SYSLOG_IDENTIFIER = "ports_notify" + +SELECT_TIMEOUT_MSECS = 1000 + +SWPLD2_DIR = "/sys/bus/i2c/devices/21-0041/" +SWPLD3_DIR = "/sys/bus/i2c/devices/21-0045/" +PORT_NUM = 66 + +# Global logger class instance +sonic_logger = logger.Logger(SYSLOG_IDENTIFIER) + +def wait_for_port_init_done(): + # Connect to APPL_DB and subscribe to PORT table notifications + appl_db = daemon_base.db_connect("APPL_DB") + sel = swsscommon.Select() + sst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME) + sel.addSelectable(sst) + + # Make sure this daemon started after all port configured + while True: + (state, c) = sel.select(1000) + if state == swsscommon.Select.TIMEOUT: + continue + if state != swsscommon.Select.OBJECT: + sonic_logger.log_warning("sel.select() did not return swsscommon.Select.OBJECT") + continue + + (key, op, fvp) = sst.pop() + + # Wait until PortInitDone + if key in ["PortInitDone"]: + break + +def subscribe_port_config_change(): + sel = swsscommon.Select() + config_db = daemon_base.db_connect("CONFIG_DB") + port_tbl = swsscommon.SubscriberStateTable(config_db, swsscommon.CFG_PORT_TABLE_NAME) + port_tbl.filter = ['admin_status'] + sel.addSelectable(port_tbl) + return sel, port_tbl + +def handle_port_config_change(sel, port_config, logger): + """Select PORT table changes, once there is a port configuration add/remove, notify observers + """ + try: + (state, _) = sel.select(SELECT_TIMEOUT_MSECS) + except Exception: + return -1 + + if state == swsscommon.Select.TIMEOUT: + return 0 + if state != swsscommon.Select.OBJECT: + return -2 + + while True: + (port_name, op, fvp) = port_config.pop() + if not port_name: + break + + if fvp is not None: + fvp = dict(fvp) + + if 'admin_status' in fvp: + if 'index' in fvp: + port_index = int(fvp['index']) + if port_index in range(1, 17) or port_index in range(33, 49): + file_name = SWPLD2_DIR + f"port_{port_index}_led" + elif port_index in range(17, 33) or port_index in range(49, 65): + file_name = SWPLD3_DIR + f"port_{port_index}_led" + elif port_index in range(65, PORT_NUM+1): + file_name = SWPLD2_DIR + f"port_{port_index}_led" + else: + logger.log_warning(f"Wrong port index {port_index} for port {port_name}") + continue + else: + logger.log_warning(f"Wrong index from port {port_name}: {fvp}") + continue + + if fvp['admin_status'] == 'up': + if port_index in range(65, PORT_NUM+1): + write_sysfs_file(file_name, '1') + else: + write_sysfs_file(file_name, '0x1') + elif fvp['admin_status'] == 'down': + if port_index in range(65, PORT_NUM+1): + write_sysfs_file(file_name, '0') + else: + write_sysfs_file(file_name, '0x0') + + return 0 + +def main(): + + # Wait for PortInitDone + wait_for_port_init_done() + + sonic_logger.log_info("port init done!") + + sel, port_config = subscribe_port_config_change() + + while True: + status = handle_port_config_change(sel, port_config, sonic_logger) + if status < 0: + return -1 + + +if __name__ == '__main__': + main() diff --git a/ixr7220h5-64d/service/ports_notify.service b/ixr7220h5-64d/service/ports_notify.service new file mode 100644 index 0000000..db83b0e --- /dev/null +++ b/ixr7220h5-64d/service/ports_notify.service @@ -0,0 +1,15 @@ +[Unit] +Description=ports_notify Service +Requires=swss.service database.service +After=swss.service database.service +BindsTo=swss.service database.service + + +[Service] +ExecStart=/usr/local/bin/ports_notify.py +Restart=always +RestartSec=10s +KillSignal=SIGTERM + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/ixr7220h5-64d/sonic_platform/component.py b/ixr7220h5-64d/sonic_platform/component.py index 9741f7c..7e1bd46 100644 --- a/ixr7220h5-64d/sonic_platform/component.py +++ b/ixr7220h5-64d/sonic_platform/component.py @@ -1,56 +1,69 @@ -######################################################################## -# NOKIA IXR7220 H5-64D -# -# Module contains an implementation of SONiC Platform Base API and -# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in -# the platform -# -######################################################################## +""" + NOKIA IXR7220 H5-64D + + Module contains an implementation of SONiC Platform Base API and + provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in + the platform +""" try: - import sys import os - import time import subprocess import ntpath - import struct - from os import * - from mmap import * + import fcntl + import ctypes + import time from sonic_platform_base.component_base import ComponentBase - from sonic_py_common.general import getstatusoutput_noshell, getstatusoutput_noshell_pipe + from sonic_platform.sysfs import read_sysfs_file, write_sysfs_file except ImportError as e: raise ImportError(str(e) + "- required module not found") - -if sys.version_info[0] < 3: - import commands as cmd -else: - import subprocess as cmd - -RESOURCE = "/sys/bus/pci/devices/0000:02:00.0/resource0" -REG_CODE_REV0 = 0x0004 - -CPLD_DIR = ["/sys/bus/i2c/devices/0-0031/", - " ", - "/sys/bus/i2c/devices/9-0034/", - "/sys/bus/i2c/devices/9-0035/"] +GPIO_GET_LINEHANDLE_IOCTL = 0xC16CB403 +GPIOHANDLE_SET_LINE_VALUES_IOCTL = 0xC040B409 +GPIOHANDLE_REQUEST_OUTPUT = 0x02 + +class gpiohandle_request(ctypes.Structure): + _fields_ = [ + ('lineoffsets', ctypes.c_uint32 * 64), + ('flags', ctypes.c_uint32), + ('default_values', ctypes.c_uint8 * 64), + ('consumer_label', ctypes.c_char * 32), + ('lines', ctypes.c_uint32), + ('fd', ctypes.c_int), + ] + +class gpiohandle_data(ctypes.Structure): + _fields_ = [ + ('values', ctypes.c_uint8 * 64), + ] + +COMPONENT_NUM = 5 +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +SYSFS_DIR = [" ", + "/sys/bus/i2c/devices/4-0040/", + "/sys/kernel/sys_fpga/", + "/sys/bus/i2c/devices/21-0041/", + "/sys/bus/i2c/devices/21-0045/"] class Component(ComponentBase): """Nokia platform-specific Component class""" CHASSIS_COMPONENTS = [ + ["BIOS", "Basic Input/Output System"], ["CPUPLD", "Used for managing CPU board "], ["SysFPGA", "Used for managing BCM chip, SFPs, PSUs and LEDs "], - ["PortPLD1", "Used for managing QSFP-DD 1-32 "], - ["PortPLD2", "Used for managing QSFP-DD 33-64, SFP+ "] ] - - CPLD_UPDATE_COMMAND = ['./h5_64d_cpld', ''] + ["SWPLD2", "Used for managing PORT 1-16, 33-48"], + ["SWPLD3", "Used for managing PORT 17-32, 49-64, SFP+"] ] + + CPLD_UPDATE_COMMAND = ['./vme_h5_64d', '', ''] + FPGA_UPDATE_COMMAND = ['./fpga_upg_tool', '-c', '1', '-p', '', ''] + BIOS_UPDATE_COMMAND = ['./afulnx_64', '', '/P', '/B', '/N', '/K', '/X'] def __init__(self, component_index): self.index = component_index self.name = self.CHASSIS_COMPONENTS[self.index][0] self.description = self.CHASSIS_COMPONENTS[self.index][1] - self.cpld_dir = CPLD_DIR[self.index] + self.sysfs_dir = SYSFS_DIR[self.index] def _get_command_result(self, cmdline): try: @@ -63,73 +76,12 @@ def _get_command_result(self, cmdline): result = None return result - - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv - - def _write_sysfs_file(self, sysfs_file, value): - # On successful write, the value read will be written on - # reg_name and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'w') as fd: - rv = fd.write(value) - except Exception as e: - rv = 'ERR' - - # Ensure that the write operation has succeeded - if (int(self._read_sysfs_file(sysfs_file)) != value ): - time.sleep(3) - if (int(self._read_sysfs_file(sysfs_file)) != value ): - rv = 'ERR' - - return rv - - def pci_set_value(resource, data, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - mm.write(struct.pack('I', data)) - mm.close() - close(fd) - - def pci_get_value(resource, offset): - fd = open(resource, O_RDWR) - mm = mmap(fd, 0) - mm.seek(offset) - read_data_stream = mm.read(4) - reg_val = struct.unpack('I', read_data_stream) - mm.close() - close(fd) - return reg_val - - def _get_cpld_version(self, cpld_number): - - if self.index == 1: - val = self.pci_get_value(RESOURCE, REG_CODE_REV0) - code_rev = val[0] & 0xFF - return str(hex(code_rev)) - elif self.index < 3: - return self._read_sysfs_file(self.cpld_dir + "code_ver") + def _get_cpld_version(self): + if self.name == "BIOS": + return read_sysfs_file(BIOS_VERSION_PATH) else: - return 'NA' + return read_sysfs_file(self.sysfs_dir + "code_ver") def get_name(self): """ @@ -204,8 +156,8 @@ def get_firmware_version(self): Returns: A string containing the firmware version of the component - """ - return self._get_cpld_version(self.index) + """ + return self._get_cpld_version() def install_firmware(self, image_path): """ @@ -218,34 +170,128 @@ def install_firmware(self, image_path): A boolean, True if install was successful, False if not """ image_name = ntpath.basename(image_path) - print(" IXR-7220-H5-64D - install cpld {}".format(image_name)) # check whether the image file exists - if not os.path.isfile(image_path): - print("ERROR: the cpld image {} doesn't exist ".format(image_path)) - return False - - # check whether the cpld exe exists - if not os.path.isfile('/tmp/cpldupd_h5_64d'): - print("ERROR: the cpld exe {} doesn't exist ".format('/tmp/cpldupd_h5_64d')) + os.chdir("/tmp") + if not os.path.isfile(image_name): + print(f"ERROR: the image {image_name} doesn't exist in /tmp") return False - self.CPLD_UPDATE_COMMAND[1] = image_name - - success_flag = False - - try: - subprocess.check_call(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) - - success_flag = True - except subprocess.CalledProcessError as e: - print("ERROR: Failed to upgrade CPLD: rc={}".format(e.returncode)) + if self.name == "CPUPLD": + # check whether the cpld upgrade tool exists + if not os.path.isfile('/tmp/vme_h5_64d'): + print("ERROR: the cpld upgrade tool /tmp/vme_h5_64d doesn't exist ") + return False + write_sysfs_file("/sys/class/gpio/export", str(10099)) + write_sysfs_file("/sys/class/gpio/export", str(10076)) + write_sysfs_file("/sys/class/gpio/gpio10099/direction", "out") + write_sysfs_file("/sys/class/gpio/gpio10076/direction", "out") + write_sysfs_file("/sys/class/gpio/gpio10099/value", str(1)) + write_sysfs_file("/sys/class/gpio/gpio10076/value", str(1)) + self.CPLD_UPDATE_COMMAND[1] = 'jtag0' + self.CPLD_UPDATE_COMMAND[2] = image_name + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade CPLD: rc={e.returncode}") + self.gpio_set("/dev/gpiochip0", 105, 1) + self.CPLD_UPDATE_COMMAND[2] = 'h5_64d_cpupld_refresh.vme' + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade CPLD: rc={e.returncode}") + self.gpio_set("/dev/gpiochip0", 105, 0) + write_sysfs_file("/sys/class/gpio/gpio10076/value", str(0)) + write_sysfs_file("/sys/class/gpio/gpio10099/value", str(0)) + write_sysfs_file("/sys/class/gpio/unexport", str(10076)) + write_sysfs_file("/sys/class/gpio/unexport", str(10099)) + print("\nCPUPLD firmware upgraded!\n") + return True + + elif self.name == "SWPLD2": + # check whether the cpld upgrade tool exists + if not os.path.isfile('/tmp/vme_h5_64d'): + print("ERROR: the cpld upgrade tool /tmp/vme_h5_64d doesn't exist ") + return False + write_sysfs_file("/sys/class/gpio/export", str(9953)) + write_sysfs_file("/sys/class/gpio/gpio9953/value", str(1)) + self.CPLD_UPDATE_COMMAND[1] = 'jtag1' + self.CPLD_UPDATE_COMMAND[2] = image_name + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade CPLD: rc={e.returncode}") + self.CPLD_UPDATE_COMMAND[2] = 'h5_64d_swpld2_refresh.vme' + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade CPLD: rc={e.returncode}") + write_sysfs_file("/sys/class/gpio/gpio9953/value", str(0)) + write_sysfs_file("/sys/class/gpio/unexport", str(9953)) + print("\nSWPLD2 firmware upgraded!\n") + return True + + elif self.name == "SWPLD3": + # check whether the cpld upgrade tool exists + if not os.path.isfile('/tmp/vme_h5_64d'): + print("ERROR: the cpld upgrade tool /tmp/vme_h5_64d doesn't exist ") + return False + write_sysfs_file("/sys/class/gpio/export", str(9953)) + write_sysfs_file("/sys/class/gpio/gpio9953/value", str(1)) + self.CPLD_UPDATE_COMMAND[1] = 'jtag1' + self.CPLD_UPDATE_COMMAND[2] = image_name + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade CPLD: rc={e.returncode}") + self.CPLD_UPDATE_COMMAND[2] = 'h5_64d_swpld3_refresh.vme' + try: + subprocess.run(self.CPLD_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade CPLD: rc={e.returncode}") + write_sysfs_file("/sys/class/gpio/gpio9953/value", str(0)) + write_sysfs_file("/sys/class/gpio/unexport", str(9953)) + print("\nSWPLD3 firmware upgraded!\n") + return True + + elif self.name == "SysFPGA": + # check whether the fpga upgrade tool exists + if not os.path.isfile('/tmp/fpga_upg_tool'): + print("ERROR: the fpga upgrade tool /tmp/fpga_upg_tool doesn't exist ") + return False + self.FPGA_UPDATE_COMMAND[4] = '0' + self.FPGA_UPDATE_COMMAND[5] = image_name + try: + subprocess.run(self.FPGA_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade SysFPGA: rc={e.returncode}") + self.FPGA_UPDATE_COMMAND[4] = '1' + self.FPGA_UPDATE_COMMAND[5] = 'h5_64d_sysfpga_g.bit' + try: + subprocess.run(self.FPGA_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade SysFPGA: rc={e.returncode}") + print("\nSysFPGA firmware upgraded!\n") + print("!!!The system will reboot in 10 sec!!!") + time.sleep(10) + write_sysfs_file("/sys/kernel/sys_fpga/sys_pwr", str(1)) + return True + + elif self.name == "BIOS": + # check whether the BIOS upgrade tool exists + if not os.path.isfile('/tmp/afulnx_64'): + print("ERROR: the BIOS upgrade tool /tmp/afulnx_64 doesn't exist ") + return False + self.BIOS_UPDATE_COMMAND[1] = image_name + try: + subprocess.run(self.BIOS_UPDATE_COMMAND, stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print(f"ERROR: Failed to upgrade BIOS: rc={e.returncode}") + print("\nBIOS upgraded!\n") + return True - if success_flag: - print("INFO: Refresh or power cycle is required to finish CPLD installation") + return False - return success_flag - def update_firmware(self, image_path): """ Updates firmware of the component @@ -261,7 +307,7 @@ def update_firmware(self, image_path): RuntimeError: update failed """ return False - + def get_available_firmware_version(self, image_path): """ Retrieves the available firmware version of the component @@ -275,3 +321,28 @@ def get_available_firmware_version(self, image_path): A string containing the available firmware version of the component """ return "N/A" + + def gpio_set(self, gpio_device, line, value): + request = gpiohandle_request() + request.lineoffsets[0] = line + request.flags = GPIOHANDLE_REQUEST_OUTPUT + request.consumer_label = "gpiochip_handler".encode() + request.lines = 1 + try: + chip_fd = os.open(gpio_device, os.O_RDONLY) + except OSError as e: + print(f"ERROR: {e.errno}, Opening GPIO chip: " + e.strerror) + + try: + fcntl.ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, request) + except (OSError, IOError) as e: + print(f"ERROR: {e.errno}, Opening output line handle: " + e.strerror) + os.close(chip_fd) + data = gpiohandle_data() + data.values[0] = value + try: + fcntl.ioctl(request.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data) + except (OSError, IOError) as e: + print(f"ERROR: {e.errno}, Setting line value: " + e.strerror) + os.close(request.fd) + diff --git a/ixr7220h5-64d/sonic_platform/thermal.py b/ixr7220h5-64d/sonic_platform/thermal.py index 7da5239..5b359c5 100644 --- a/ixr7220h5-64d/sonic_platform/thermal.py +++ b/ixr7220h5-64d/sonic_platform/thermal.py @@ -1,48 +1,38 @@ -######################################################################## -# Nokia IXR7220-H5-64D -# -# Module contains an implementation of SONiC Platform Base API and -# provides the Thermals' information which are available in the platform -# -######################################################################## +""" + Nokia IXR7220-H5-64D + Module contains an implementation of SONiC Platform Base API and + provides the Thermals' information which are available in the platform +""" try: - import os import glob from sonic_platform_base.thermal_base import ThermalBase from sonic_py_common import logger - from sonic_py_common import multi_asic - from swsscommon import swsscommon - from swsscommon.swsscommon import SonicV2Connector,ConfigDBConnector + from swsscommon.swsscommon import SonicV2Connector + from sonic_platform.sysfs import read_sysfs_file except ImportError as e: - raise ImportError(str(e) + "- required module not found") + raise ImportError(str(e) + ' - required module not found') from e sonic_logger = logger.Logger('thermal') -H5_64D_THERMAL = 10 +THERMAL_NUM = 11 class Thermal(ThermalBase): """Nokia platform-specific Thermal class""" - HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" - I2C_DEV_LIST = ["6-004f", "6-004b", "6-004a", "6-004e", "6-0049", - "5-0049", "6-0048", "7-004f", "7-004e"] - THERMAL_NAME = ["MB Left", - "MB Front", - "MB Right", - "MB MAC", - "PSU top", - "PSU Bottom", - "CPU Board", - "Fan Left", - "Fan Right", - "ASIC TH5"] + HWMON_DIR = "/sys/bus/i2c/devices/{}/hwmon/hwmon*/" + I2C_DEV_LIST = ["20-0048", "16-004b", "16-0049", "16-004a", "16-004e", + "16-004f", "17-004e", "17-004f", "19-0049"] + THERMAL_NAME = ["CPU Board", "MB Front", "PSU Top", "MB Right", "MB MAC", + "MB Left", "Fan Right", "Fan Left", "PSU Bottom", "ASIC TH5", "CPU"] + THRESHHOLD = [72.0, 60.0, 60.0, 58.0, 82.0, 63.0, 59.0, 60.0, 66.0, 92.0, 95.0] + CRITICAL_THRESHHOLD = [75.0, 63.0, 63.0, 61.0, 85.0, 66.0, 62.0, 63.0, 69.0, 95.0, 100.0] def __init__(self, thermal_index): ThermalBase.__init__(self) - self.index = thermal_index + 1 - if self.index == 6: + self.index = thermal_index + 1 + if self.index == 8 or self.index == 9: self.is_fan_thermal = True else: self.is_fan_thermal = False @@ -50,35 +40,18 @@ def __init__(self, thermal_index): self._minimum = None self._maximum = None self.thermal_high_threshold_file = None - + # sysfs file for crit high threshold value if supported for this sensor self.thermal_high_crit_threshold_file = None - if self.index == H5_64D_THERMAL: # MAC internal sensor - self.thermal_temperature_file = None + if self.index == THERMAL_NUM: # CPU + self.device_path = glob.glob("/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon*/") + self.thermal_temperature_file = self.device_path[0] + "temp1_input" + elif self.index == THERMAL_NUM-1: # MAC internal sensor + self.thermal_temperature_file = None else: - self.device_path = glob.glob(self.HWMON_DIR.format(self.I2C_DEV_LIST[self.index - 1])) - - # sysfs file for current temperature value - self.thermal_temperature_file = self.device_path[0] + "temp1_input" - - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # sysfs_file and on failure returns 'ERR' - rv = 'ERR' - - if (not os.path.isfile(sysfs_file)): - return rv - - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv + self.device_path = glob.glob(self.HWMON_DIR.format(self.I2C_DEV_LIST[self.index - 1])) + self.thermal_temperature_file = self.device_path[0] + "temp1_input" def get_name(self): """ @@ -98,8 +71,7 @@ def get_presence(self): """ if self.dependency: return self.dependency.get_presence() - else: - return True + return True def get_model(self): """ @@ -129,8 +101,7 @@ def get_status(self): """ if self.dependency: return self.dependency.get_status() - else: - return True + return True def get_temperature(self): """ @@ -140,23 +111,24 @@ def get_temperature(self): A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - if self.index == H5_64D_THERMAL: + if self.index == THERMAL_NUM-1: db = SonicV2Connector() db.connect(db.STATE_DB) data_dict = db.get_all(db.STATE_DB, 'ASIC_TEMPERATURE_INFO') thermal_temperature = float(data_dict['maximum_temperature']) else: - thermal_temperature = self._read_sysfs_file(self.thermal_temperature_file) + thermal_temperature = read_sysfs_file(self.thermal_temperature_file) if (thermal_temperature != 'ERR'): thermal_temperature = float(thermal_temperature) / 1000 - if self._minimum is None or self._minimum > thermal_temperature: - self._minimum = thermal_temperature - if self._maximum is None or self._maximum < thermal_temperature: - self._maximum = thermal_temperature else: thermal_temperature = 0 + + if self._minimum is None or self._minimum > thermal_temperature: + self._minimum = thermal_temperature + if self._maximum is None or self._maximum < thermal_temperature: + self._maximum = thermal_temperature - return float("{:.3f}".format(thermal_temperature)) + return float(f"{thermal_temperature:.3f}") def get_high_threshold(self): """ @@ -167,10 +139,7 @@ def get_high_threshold(self): Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - if self.index == H5_64D_THERMAL: - return 100.0 - else: - return 78.0 + return self.THRESHHOLD[self.index - 1] def set_high_threshold(self, temperature): """ @@ -194,11 +163,7 @@ def get_high_critical_threshold(self): A float number, the high critical threshold temperature of thermal in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - - if self.index == H5_64D_THERMAL: - return 103.0 - else: - return 80.0 + return self.CRITICAL_THRESHHOLD[self.index - 1] def set_high_critical_threshold(self): """ @@ -222,7 +187,7 @@ def get_low_threshold(self): up to nearest thousandth of one degree Celsius, e.g. 30.125 """ return 0.0 - + def set_low_threshold(self, temperature): """ Sets the low threshold temperature of thermal @@ -236,12 +201,18 @@ def set_low_threshold(self, temperature): """ # Thermal threshold values are pre-defined based on HW. return False - + def get_minimum_recorded(self): + """ + Retrieves minimum recorded temperature + """ self.get_temperature() return self._minimum def get_maximum_recorded(self): + """ + Retrieves maxmum recorded temperature + """ self.get_temperature() return self._maximum diff --git a/ixr7220h5-64d/sonic_platform/watchdog.py b/ixr7220h5-64d/sonic_platform/watchdog.py index 924adbc..e055819 100644 --- a/ixr7220h5-64d/sonic_platform/watchdog.py +++ b/ixr7220h5-64d/sonic_platform/watchdog.py @@ -1,13 +1,15 @@ """ -Module contains an implementation of SONiC Platform Base API and -provides access to hardware watchdog + Module contains an implementation of SONiC Platform Base API and + provides access to hardware watchdog """ - -import os -import fcntl -import array -import time -from sonic_platform_base.watchdog_base import WatchdogBase +try: + import os + import fcntl + import array + from sonic_platform_base.watchdog_base import WatchdogBase + from sonic_platform.sysfs import read_sysfs_file +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e """ ioctl constants """ IO_WRITE = 0x40000000 @@ -37,50 +39,30 @@ WD_COMMON_ERROR = -1 - class WatchdogImplBase(WatchdogBase): """ Base class that implements common logic for interacting with watchdog using ioctl commands """ - def __init__(self, wd_device_path): """ Open a watchdog handle @param wd_device_path Path to watchdog device """ super(WatchdogImplBase, self).__init__() - + self.watchdog="" self.watchdog_path = wd_device_path self.wd_state_reg = WD_SYSFS_PATH+"state" self.wd_timeout_reg = WD_SYSFS_PATH+"timeout" self.wd_timeleft_reg = WD_SYSFS_PATH+"timeleft" - - self.timeout = self._gettimeout() - - def _read_sysfs_file(self, sysfs_file): - # On successful read, returns the value read from given - # reg_name and on failure returns 'ERR' - rv = 'ERR' - if (not os.path.isfile(sysfs_file)): - return rv - try: - with open(sysfs_file, 'r') as fd: - rv = fd.read() - except Exception as e: - rv = 'ERR' - - rv = rv.rstrip('\r\n') - rv = rv.lstrip(" ") - return rv + self.timeout = self._gettimeout() def _disablewatchdog(self): """ Turn off the watchdog timer """ - req = array.array('h', [WDIOS_DISABLECARD]) fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) @@ -88,7 +70,6 @@ def _enablewatchdog(self): """ Turn on the watchdog timer """ - req = array.array('h', [WDIOS_ENABLECARD]) fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) @@ -96,7 +77,6 @@ def _keepalive(self): """ Keep alive watchdog timer """ - fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) def _settimeout(self, seconds): @@ -105,7 +85,6 @@ def _settimeout(self, seconds): @param seconds - timeout in seconds @return is the actual set timeout """ - req = array.array('I', [seconds]) fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) @@ -116,8 +95,8 @@ def _gettimeout(self): Get watchdog timeout @return watchdog timeout """ - timeout=0 - timeout=self._read_sysfs_file(self.wd_timeout_reg) + timeout = 0 + timeout = read_sysfs_file(self.wd_timeout_reg) return timeout @@ -126,7 +105,6 @@ def _gettimeleft(self): Get time left before watchdog timer expires @return time left in seconds """ - req = array.array('I', [0]) fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) @@ -136,15 +114,10 @@ def arm(self, seconds): """ Arm the hardware watchdog """ - ret = WD_COMMON_ERROR - if seconds < 0: + if (seconds < 0 or seconds > 340 ): return ret - - # Stop the watchdog service to gain access of watchdog file pointer - # if self.is_armed(): - # os.popen("systemctl stop cpu_wdt.service") - # time.sleep(2) + if not self.watchdog: self.watchdog = os.open(self.watchdog_path, os.O_WRONLY) try: @@ -168,17 +141,13 @@ def disarm(self): A boolean, True if watchdog is disarmed successfully, False if not """ - - if self.is_armed(): - #os.popen("systemctl stop cpu_wdt.service") - #time.sleep(2) - if not self.watchdog: - self.watchdog = os.open(self.watchdog_path, os.O_WRONLY) - try: - self._disablewatchdog() - self.timeout = 0 - except IOError: - return False + if not self.watchdog: + self.watchdog = os.open(self.watchdog_path, os.O_WRONLY) + try: + self._disablewatchdog() + self.timeout = 0 + except IOError: + return False return True @@ -188,7 +157,7 @@ def is_armed(self): """ status = False - state = self._read_sysfs_file(self.wd_state_reg) + state = read_sysfs_file(self.wd_state_reg) if (state != 'inactive'): status = True @@ -198,10 +167,9 @@ def get_remaining_time(self): """ Implements get_remaining_time WatchdogBase API """ - timeleft = WD_COMMON_ERROR if self.is_armed(): - timeleft=self._read_sysfs_file(self.wd_timeleft_reg) + timeleft = read_sysfs_file(self.wd_timeleft_reg) return int(timeleft) From cd50907960edd2d24224eddc8a0c361809a1003d Mon Sep 17 00:00:00 2001 From: y7zhou Date: Thu, 12 Dec 2024 09:46:08 -0500 Subject: [PATCH 4/4] [H5-64D]Update thermal algorithm and unit tests --- .../sonic_platform/test/test-chassis.py | 0 .../sonic_platform/test/test-component.py | 0 .../sonic_platform/test/test-eeprom.py | 0 .../sonic_platform/test/test-fan-drawer.py | 29 +++++++++++++ ixr7220h5-64d/sonic_platform/test/test-fan.py | 6 +-- ixr7220h5-64d/sonic_platform/test/test-psu.py | 3 +- ixr7220h5-64d/sonic_platform/test/test-sfp.py | 0 .../sonic_platform/test/test-thermal.py | 0 .../sonic_platform/test/test-watchdog.py | 0 .../sonic_platform/thermal_actions.py | 32 ++++++-------- .../sonic_platform/thermal_conditions.py | 17 +++----- ixr7220h5-64d/sonic_platform/thermal_infos.py | 42 ++++++++----------- .../sonic_platform/thermal_manager.py | 12 +++--- 13 files changed, 76 insertions(+), 65 deletions(-) mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-chassis.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-component.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-eeprom.py create mode 100644 ixr7220h5-64d/sonic_platform/test/test-fan-drawer.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-fan.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-psu.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-sfp.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-thermal.py mode change 100755 => 100644 ixr7220h5-64d/sonic_platform/test/test-watchdog.py diff --git a/ixr7220h5-64d/sonic_platform/test/test-chassis.py b/ixr7220h5-64d/sonic_platform/test/test-chassis.py old mode 100755 new mode 100644 diff --git a/ixr7220h5-64d/sonic_platform/test/test-component.py b/ixr7220h5-64d/sonic_platform/test/test-component.py old mode 100755 new mode 100644 diff --git a/ixr7220h5-64d/sonic_platform/test/test-eeprom.py b/ixr7220h5-64d/sonic_platform/test/test-eeprom.py old mode 100755 new mode 100644 diff --git a/ixr7220h5-64d/sonic_platform/test/test-fan-drawer.py b/ixr7220h5-64d/sonic_platform/test/test-fan-drawer.py new file mode 100644 index 0000000..20860e4 --- /dev/null +++ b/ixr7220h5-64d/sonic_platform/test/test-fan-drawer.py @@ -0,0 +1,29 @@ +#!/usr/bin/python +import unittest +from sonic_platform.chassis import Chassis + +class Test1(unittest.TestCase): + def test_1(self): + print("---------------------------") + print("Chassis Fan Drawer Unit Test") + print("---------------------------") + + chassis = Chassis() + + for fan_drawer in chassis.get_all_fan_drawers(): + if not fan_drawer.get_presence(): + print(" Name: {} not present".format(fan_drawer.get_name())) + else: + print(" Name:", fan_drawer.get_name()) + print(" Presence: {}, Status: {}, LED: {}".format(fan_drawer.get_presence(), + fan_drawer.get_status(), + fan_drawer.get_status_led())) + print(" Serial#: {}".format(fan_drawer.get_serial())) + print(" Part#: {}".format(fan_drawer.get_part_number())) + print(" Direction: {}\n".format(fan_drawer.get_direction())) + print(" Replaceable: {}, Index: {}\n".format(fan_drawer.is_replaceable(), fan_drawer.get_position_in_parent())) + + + +if __name__ == '__main__': + unittest.main() diff --git a/ixr7220h5-64d/sonic_platform/test/test-fan.py b/ixr7220h5-64d/sonic_platform/test/test-fan.py old mode 100755 new mode 100644 index 3fbedf1..a2405d1 --- a/ixr7220h5-64d/sonic_platform/test/test-fan.py +++ b/ixr7220h5-64d/sonic_platform/test/test-fan.py @@ -18,10 +18,8 @@ def main(): print(" Presence: {}, Status: {}, LED: {}".format(fan.get_presence(), fan.get_status(), fan.get_status_led())) - print(" Model: {}, Serial#: {}".format(fan.get_model(), - fan.get_serial())) - print(" Part#: {}, Service Tag: {}".format(fan.get_part_number(), - fan.get_service_tag())) + print(" Serial#: {}".format(fan.get_serial())) + print(" Part#: {}".format(fan.get_part_number())) print(" Direction: {}, Speed: {}%, Target Speed: {}%\n".format(fan.get_direction(), str(fan.get_speed()), str(fan.get_target_speed()))) diff --git a/ixr7220h5-64d/sonic_platform/test/test-psu.py b/ixr7220h5-64d/sonic_platform/test/test-psu.py old mode 100755 new mode 100644 index e3979b8..b345378 --- a/ixr7220h5-64d/sonic_platform/test/test-psu.py +++ b/ixr7220h5-64d/sonic_platform/test/test-psu.py @@ -18,8 +18,9 @@ def main(): print(" Presence: {}, Status: {}, LED: {}".format(psu.get_presence(), psu.get_status(), psu.get_status_led())) - print(" Model: {}, Serial#: {}, Part#: {}".format(psu.get_model(), + print(" Model: {}, Serial#: {}, Revision: {}, Part#: {}".format(psu.get_model(), psu.get_serial(), + psu.get_revision(), psu.get_part_number())) try: current = psu.get_current() diff --git a/ixr7220h5-64d/sonic_platform/test/test-sfp.py b/ixr7220h5-64d/sonic_platform/test/test-sfp.py old mode 100755 new mode 100644 diff --git a/ixr7220h5-64d/sonic_platform/test/test-thermal.py b/ixr7220h5-64d/sonic_platform/test/test-thermal.py old mode 100755 new mode 100644 diff --git a/ixr7220h5-64d/sonic_platform/test/test-watchdog.py b/ixr7220h5-64d/sonic_platform/test/test-watchdog.py old mode 100755 new mode 100644 diff --git a/ixr7220h5-64d/sonic_platform/thermal_actions.py b/ixr7220h5-64d/sonic_platform/thermal_actions.py index d1d15aa..2530681 100644 --- a/ixr7220h5-64d/sonic_platform/thermal_actions.py +++ b/ixr7220h5-64d/sonic_platform/thermal_actions.py @@ -1,11 +1,12 @@ -from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase -from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object - -from sonic_py_common import logger +try: + from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase + from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object + from sonic_py_common import logger +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e sonic_logger = logger.Logger('thermal_actions') - class SetFanSpeedAction(ThermalPolicyActionBase): """ Base thermal action class to set speed for fans @@ -21,10 +22,10 @@ def __init__(self): """ Constructor of SetFanSpeedAction """ - self.default_speed = 40 - self.threshold1_speed=55 - self.threshold2_speed=80 - self.hightemp_speed = 100 + self.default_speed = 45 + self.threshold1_speed=60 + self.threshold2_speed=70 + self.hightemp_speed = 90 self.speed = self.default_speed def load_from_json(self, json_obj): @@ -55,7 +56,6 @@ def set_all_fan_speed(cls, thermal_info_dict, speed): for fan in fan_info_obj.get_presence_fans(): fan.set_speed(int(speed)) - @thermal_json_object('fan.all.set_speed') class SetAllFanSpeedAction(SetFanSpeedAction): """ @@ -69,13 +69,11 @@ def execute(self, thermal_info_dict): """ SetAllFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.speed) - @thermal_json_object('thermal.temp_check_and_set_all_fan_speed') class ThermalRecoverAction(SetFanSpeedAction): """ Action to check thermal sensor temperature change status and set speed for all fans """ - def load_from_json(self, json_obj): """ Construct ThermalRecoverAction via JSON. JSON example: @@ -108,7 +106,7 @@ def load_from_json(self, json_obj): else: raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. format(SetFanSpeedAction.JSON_FIELD_THRESHOLD1_SPEED)) - + if SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED in json_obj: threshold2_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED]) if threshold2_speed < 0 or threshold2_speed > 100: @@ -118,7 +116,7 @@ def load_from_json(self, json_obj): else: raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'. format(SetFanSpeedAction.JSON_FIELD_THRESHOLD2_SPEED)) - + if SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED in json_obj: hightemp_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED]) if hightemp_speed < 0 or hightemp_speed > 100: @@ -143,7 +141,7 @@ def execute(self, thermal_info_dict): thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] if thermal_info_obj.is_set_fan_high_temp_speed(): - ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.hightemp_speed) + ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.hightemp_speed) elif thermal_info_obj.is_set_fan_threshold_two_speed(): ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.threshold2_speed) elif thermal_info_obj.is_set_fan_threshold_one_speed(): @@ -151,7 +149,6 @@ def execute(self, thermal_info_dict): elif thermal_info_obj.is_set_fan_default_speed(): ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.default_speed) - @thermal_json_object('switch.shutdown') class SwitchPolicyAction(ThermalPolicyActionBase): """ @@ -166,9 +163,6 @@ def execute(self, thermal_info_dict): :return: """ sonic_logger.log_warning("Alarm for temperature critical is detected, reboot Device") - # import os - # os.system('reboot') - @thermal_json_object('thermal_control.control') class ControlThermalAlgoAction(ThermalPolicyActionBase): diff --git a/ixr7220h5-64d/sonic_platform/thermal_conditions.py b/ixr7220h5-64d/sonic_platform/thermal_conditions.py index 4923d63..c1bc1dc 100644 --- a/ixr7220h5-64d/sonic_platform/thermal_conditions.py +++ b/ixr7220h5-64d/sonic_platform/thermal_conditions.py @@ -1,6 +1,8 @@ -from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase -from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object - +try: + from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase + from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e class FanCondition(ThermalPolicyConditionBase): def get_fan_info(self, thermal_info_dict): @@ -10,28 +12,24 @@ def get_fan_info(self, thermal_info_dict): else: return None - @thermal_json_object('fan.any.absence') class AnyFanAbsenceCondition(FanCondition): def is_match(self, thermal_info_dict): fan_info_obj = self.get_fan_info(thermal_info_dict) return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False - @thermal_json_object('fan.all.absence') class AllFanAbsenceCondition(FanCondition): def is_match(self, thermal_info_dict): fan_info_obj = self.get_fan_info(thermal_info_dict) return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False - @thermal_json_object('fan.all.presence') class AllFanPresenceCondition(FanCondition): def is_match(self, thermal_info_dict): fan_info_obj = self.get_fan_info(thermal_info_dict) return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False - class ThermalCondition(ThermalPolicyConditionBase): def get_thermal_info(self, thermal_info_dict): from .thermal_infos import ThermalInfo @@ -40,7 +38,6 @@ def get_thermal_info(self, thermal_info_dict): else: return None - @thermal_json_object('thermal.over.high_critical_threshold') class ThermalOverHighCriticalCondition(ThermalCondition): def is_match(self, thermal_info_dict): @@ -50,7 +47,6 @@ def is_match(self, thermal_info_dict): else: return False - class PsuCondition(ThermalPolicyConditionBase): def get_psu_info(self, thermal_info_dict): from .thermal_infos import PsuInfo @@ -59,21 +55,18 @@ def get_psu_info(self, thermal_info_dict): else: return None - @thermal_json_object('psu.any.absence') class AnyPsuAbsenceCondition(PsuCondition): def is_match(self, thermal_info_dict): psu_info_obj = self.get_psu_info(thermal_info_dict) return len(psu_info_obj.get_absence_psus()) > 0 if psu_info_obj else False - @thermal_json_object('psu.all.absence') class AllPsuAbsenceCondition(PsuCondition): def is_match(self, thermal_info_dict): psu_info_obj = self.get_psu_info(thermal_info_dict) return len(psu_info_obj.get_presence_psus()) == 0 if psu_info_obj else False - @thermal_json_object('psu.all.presence') class AllPsuPresenceCondition(PsuCondition): def is_match(self, thermal_info_dict): diff --git a/ixr7220h5-64d/sonic_platform/thermal_infos.py b/ixr7220h5-64d/sonic_platform/thermal_infos.py index 39c70e7..0a46dea 100644 --- a/ixr7220h5-64d/sonic_platform/thermal_infos.py +++ b/ixr7220h5-64d/sonic_platform/thermal_infos.py @@ -1,6 +1,9 @@ -from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase -from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object -from sonic_py_common.logger import Logger +try: + from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase + from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e logger = Logger() @@ -9,7 +12,6 @@ class FanInfo(ThermalPolicyInfoBase): """ Fan information needed by thermal policy """ - # Fan information name INFO_NAME = 'fan_info' @@ -58,13 +60,11 @@ def is_status_changed(self): """ return self._status_changed - @thermal_json_object('thermal_info') class ThermalInfo(ThermalPolicyInfoBase): """ Thermal information needed by thermal policy """ - # Fan information name INFO_NAME = 'thermal_info' @@ -72,14 +72,13 @@ def __init__(self): self._old_threshold_level = -1 self._current_threshold_level = 0 self._num_fan_levels = 3 - self._high_crital_threshold = 80 - self._level_up_threshold = [[47,47,47,47,47,47,73], - [66,66,66,66,66,66,93], - [74,74,74,74,74,74,100]] + self._level_up_threshold = [[63, 51, 39, 48, 72, 40, 48, 46, 39, 81, 87], + [66, 53, 42, 51, 75, 42, 51, 48, 41, 83, 90], + [69, 56, 45, 54, 78, 45, 54, 51, 44, 85, 93]] - self._level_down_threshold = [[42,42,42,42,42,42,68], - [61,61,61,61,61,61,89], - [70,70,70,70,70,70,96]] + self._level_down_threshold = [[60, 48, 35, 44, 69, 36, 45, 43, 35, 79, 85], + [62, 50, 38, 47, 71, 39, 47, 45, 38, 80, 86], + [65, 52, 41, 50, 74, 41, 50, 47, 40, 82, 89]] def collect(self, chassis): """ @@ -98,14 +97,12 @@ def collect(self, chassis): num_of_thermals = chassis.get_num_thermals() for index in range(num_of_thermals): self._temps.insert(index, chassis.get_thermal(index).get_temperature()) - # Find current required threshold level max_level =0 - min_level = [self._num_fan_levels for i in range(num_of_thermals)] + min_level = [self._num_fan_levels for i in range(num_of_thermals)] for index in range(num_of_thermals): for level in range(self._num_fan_levels): - if self._temps[index]>self._level_up_threshold[level][index]: if max_level self._old_threshold_level: max_of_min_level=self._old_threshold_level - + self._current_threshold_level = max(max_of_min_level,max_level) - + #set fan to max speed if one fan is down for fan in chassis.get_all_fans(): if not fan.get_status() : self._current_threshold_level = 3 - - # Decide fan speed based on threshold level + # Decide fan speed based on threshold level if self._current_threshold_level != self._old_threshold_level: if self._current_threshold_level == 0: self._set_fan_default_speed = True @@ -153,7 +149,7 @@ def is_set_fan_threshold_one_speed(self): :return: True if the temperature is warm up and over high threshold else False """ return self._set_fan_threshold_one_speed - + def is_set_fan_threshold_two_speed(self): """ Retrieves if the temperature is warm up and over high threshold @@ -175,7 +171,6 @@ def is_over_high_critical_threshold(self): """ return self._over_high_critical_threshold - @thermal_json_object('psu_info') class PsuInfo(ThermalPolicyInfoBase): """ @@ -228,7 +223,6 @@ def is_status_changed(self): """ return self._status_changed - @thermal_json_object('chassis_info') class ChassisInfo(ThermalPolicyInfoBase): """ diff --git a/ixr7220h5-64d/sonic_platform/thermal_manager.py b/ixr7220h5-64d/sonic_platform/thermal_manager.py index 967cf17..bf41d68 100644 --- a/ixr7220h5-64d/sonic_platform/thermal_manager.py +++ b/ixr7220h5-64d/sonic_platform/thermal_manager.py @@ -1,8 +1,10 @@ -from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase -from .thermal_actions import * -from .thermal_conditions import * -from .thermal_infos import * - +try: + from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase + from .thermal_actions import * + from .thermal_conditions import * + from .thermal_infos import * +except ImportError as e: + raise ImportError(str(e) + ' - required module not found') from e class ThermalManager(ThermalManagerBase): THERMAL_ALGORITHM_CONTROL_PATH = '/var/run/hw-management/config/suspend'