diff --git a/packages/platforms/accton/x86-64/as5812-54x/modules/builds/x86-64-accton-as5812-54x-cpld.c b/packages/platforms/accton/x86-64/as5812-54x/modules/builds/x86-64-accton-as5812-54x-cpld.c index 16453bf33..d8d7e746b 100644 --- a/packages/platforms/accton/x86-64/as5812-54x/modules/builds/x86-64-accton-as5812-54x-cpld.c +++ b/packages/platforms/accton/x86-64/as5812-54x/modules/builds/x86-64-accton-as5812-54x-cpld.c @@ -38,6 +38,8 @@ #include #include +static const int bit_map[] = {0, 2, 4, 1, 3, 5}; /*for port49~54*/ + #define I2C_RW_RETRY_COUNT 10 #define I2C_RW_RETRY_INTERVAL 60 /* ms */ @@ -104,6 +106,8 @@ MODULE_DEVICE_TABLE(i2c, as5812_54x_cpld_mux_id); #define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index #define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index #define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index enum as5812_54x_cpld1_sysfs_attributes { CPLD_VERSION, @@ -309,6 +313,18 @@ enum as5812_54x_cpld1_sysfs_attributes { TRANSCEIVER_TXFAULT_ATTR_ID(46), TRANSCEIVER_TXFAULT_ATTR_ID(47), TRANSCEIVER_TXFAULT_ATTR_ID(48), + TRANSCEIVER_LPMODE_ATTR_ID(49), + TRANSCEIVER_LPMODE_ATTR_ID(50), + TRANSCEIVER_LPMODE_ATTR_ID(51), + TRANSCEIVER_LPMODE_ATTR_ID(52), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), }; /* sysfs attributes for hwmon @@ -319,7 +335,7 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, +static ssize_t set_control(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t access(struct device *dev, struct device_attribute *da, const char *buf, size_t count); @@ -334,13 +350,19 @@ static int as5812_54x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 #define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr #define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ - static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_TXDISABLE_##index); \ static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) #define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_LPMODE_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_RESET_##index); +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_lpmode_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); @@ -451,6 +473,12 @@ DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(46); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(47); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); static struct attribute *as5812_54x_cpld1_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, &sensor_dev_attr_access.dev_attr.attr, @@ -582,6 +610,12 @@ static struct attribute *as5812_54x_cpld3_attributes[] = { DECLARE_SFP_TRANSCEIVER_ATTR(46), DECLARE_SFP_TRANSCEIVER_ATTR(47), DECLARE_SFP_TRANSCEIVER_ATTR(48), + DECLARE_QSFP_TRANSCEIVER_ATTR(49), + DECLARE_QSFP_TRANSCEIVER_ATTR(50), + DECLARE_QSFP_TRANSCEIVER_ATTR(51), + DECLARE_QSFP_TRANSCEIVER_ATTR(52), + DECLARE_QSFP_TRANSCEIVER_ATTR(53), + DECLARE_QSFP_TRANSCEIVER_ATTR(54), NULL }; @@ -673,56 +707,43 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct i2c_mux_core *muxc = i2c_get_clientdata(client); struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); int status = 0; - u8 reg = 0, mask = 0, revert = 0; + u8 reg = 0, mask = 0, invert = 0; switch (attr->index) { case MODULE_PRESENT_1 ... MODULE_PRESENT_8: reg = 0x6; mask = 0x1 << (attr->index - MODULE_PRESENT_1); + invert = 1; break; case MODULE_PRESENT_9 ... MODULE_PRESENT_16: reg = 0x7; mask = 0x1 << (attr->index - MODULE_PRESENT_9); + invert = 1; break; case MODULE_PRESENT_17 ... MODULE_PRESENT_24: reg = 0x8; mask = 0x1 << (attr->index - MODULE_PRESENT_17); + invert = 1; break; case MODULE_PRESENT_25 ... MODULE_PRESENT_32: reg = 0x6; mask = 0x1 << (attr->index - MODULE_PRESENT_25); + invert = 1; break; case MODULE_PRESENT_33 ... MODULE_PRESENT_40: reg = 0x7; mask = 0x1 << (attr->index - MODULE_PRESENT_33); + invert = 1; break; case MODULE_PRESENT_41 ... MODULE_PRESENT_48: reg = 0x8; mask = 0x1 << (attr->index - MODULE_PRESENT_41); + invert = 1; break; - case MODULE_PRESENT_49: - reg = 0x14; - mask = 0x1; - break; - case MODULE_PRESENT_50: - reg = 0x14; - mask = 0x4; - break; - case MODULE_PRESENT_51: + case MODULE_PRESENT_49 ... MODULE_PRESENT_54: reg = 0x14; - mask = 0x10; - break; - case MODULE_PRESENT_52: - reg = 0x14; - mask = 0x2; - break; - case MODULE_PRESENT_53: - reg = 0x14; - mask = 0x8; - break; - case MODULE_PRESENT_54: - reg = 0x14; - mask = 0x20; + mask = 1 << bit_map[attr->index - MODULE_PRESENT_49]; + invert = 1; break; case MODULE_TXFAULT_1 ... MODULE_TXFAULT_8: reg = 0x9; @@ -796,14 +817,19 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, reg = 0x11; mask = 0x1 << (attr->index - MODULE_RXLOS_41); break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_54: + reg = 0x16; + mask = 1 << bit_map[attr->index - MODULE_LPMODE_49]; + break; + case MODULE_RESET_49 ... MODULE_RESET_54: + reg = 0x15; + mask = 1 << bit_map[attr->index - MODULE_RESET_49]; + invert = 1; + break; default: return 0; } - if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_54) { - revert = 1; - } - mutex_lock(&data->update_lock); status = as5812_54x_cpld_read_internal(client, reg); if (unlikely(status < 0)) { @@ -811,25 +837,25 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, } mutex_unlock(&data->update_lock); - return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + return sprintf(buf, "%d\n", invert ? !(status & mask) : !!(status & mask)); exit: mutex_unlock(&data->update_lock); return status; } -static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, +static ssize_t set_control(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); struct i2c_mux_core *muxc = i2c_get_clientdata(client); struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc); - long disable; + long value; int status; - u8 reg = 0, mask = 0; + u8 reg = 0, mask = 0, invert = 0; - status = kstrtol(buf, 10, &disable); + status = kstrtol(buf, 10, &value); if (status) { return status; } @@ -859,6 +885,15 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, reg = 0xE; mask = 0x1 << (attr->index - MODULE_TXDISABLE_41); break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_54: + reg = 0x16; + mask = 1 << bit_map[attr->index - MODULE_LPMODE_49]; + break; + case MODULE_RESET_49 ... MODULE_RESET_54: + reg = 0x15; + mask = 1 << bit_map[attr->index - MODULE_RESET_49]; + invert = 1; + break; default: return 0; } @@ -870,8 +905,12 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, goto exit; } - /* Update tx_disable status */ - if (disable) { + /* Update tx_disable/lpmode/reset status */ + if (invert) { + value = !value; + } + + if (value) { status |= mask; } else { diff --git a/packages/platforms/accton/x86-64/as5812-54x/onlp/builds/x86_64_accton_as5812_54x/module/src/sfpi.c b/packages/platforms/accton/x86-64/as5812-54x/onlp/builds/x86_64_accton_as5812_54x/module/src/sfpi.c index 0f06f522c..b96291e91 100644 --- a/packages/platforms/accton/x86-64/as5812-54x/onlp/builds/x86_64_accton_as5812_54x/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as5812-54x/onlp/builds/x86_64_accton_as5812_54x/module/src/sfpi.c @@ -29,6 +29,31 @@ #include "x86_64_accton_as5812_54x_int.h" #include "x86_64_accton_as5812_54x_log.h" +#define SFP_PORT_MIN 0 +#define SFP_PORT_MAX 47 +#define QSFP_PORT_MIN 48 +#define QSFP_PORT_MAX 53 +#define MIN_PORT SFP_PORT_MIN +#define MAX_PORT QSFP_PORT_MAX + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < SFP_PORT_MIN || _port > SFP_PORT_MAX) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define CPLD_MUX_BUS_START_INDEX 2 #define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" @@ -36,11 +61,17 @@ #define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/0-00%d/module_rx_los_%d" #define MODULE_TXFAULT_FORMAT "/sys/bus/i2c/devices/0-00%d/module_tx_fault_%d" #define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/0-00%d/module_tx_disable_%d" +#define MODULE_RESET_FORMAT "/sys/bus/i2c/devices/0-00%d/module_reset_%d" +#define MODULE_LPMODE_FORMAT "/sys/bus/i2c/devices/0-00%d/module_lpmode_%d" #define MODULE_PRESENT_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/0-0061/module_present_all" #define MODULE_PRESENT_ALL_ATTR_CPLD3 "/sys/bus/i2c/devices/0-0062/module_present_all" #define MODULE_RXLOS_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/0-0061/module_rx_los_all" #define MODULE_RXLOS_ALL_ATTR_CPLD3 "/sys/bus/i2c/devices/0-0062/module_rx_los_all" +/*QSFP tx_disable*/ +#define PORT_EEPROM_DEVADDR 0x50 +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 + static int front_port_to_driver_port(int port) { int rport = 0; @@ -407,20 +438,68 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; - if (port < 0 || port >= 48) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_PORT(port); int addr = (port < 24) ? 61 : 62; switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + if(present == 1) + { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else { //QSFP + + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value & 0xf; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } + else { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + VALIDATE_QSFP(port); + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: { - if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); + VALIDATE_QSFP(port); + if (onlp_file_write_int(value, MODULE_LPMODE_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } else { @@ -440,11 +519,11 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int tx_disable; - if (port < 0 || port >= 48) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_PORT(port); int addr = (port < 24) ? 61 : 62; @@ -452,6 +531,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { case ONLP_SFP_CONTROL_RX_LOS: { + VALIDATE_SFP(port); if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; @@ -464,6 +544,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_FAULT: { + VALIDATE_SFP(port); if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; @@ -475,9 +556,58 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) } case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + if(present == 1){ + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else { //QSFP + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + + tx_disable = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_disable < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_disable; + rv = ONLP_STATUS_OK; + } + } + } + else { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + VALIDATE_QSFP(port); + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: { - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + VALIDATE_QSFP(port); + if (onlp_file_read_int(value, MODULE_LPMODE_FORMAT, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } else { diff --git a/packages/platforms/accton/x86-64/as5835-54t/onlp/builds/x86_64_accton_as5835_54t/module/src/sfpi.c b/packages/platforms/accton/x86-64/as5835-54t/onlp/builds/x86_64_accton_as5835_54t/module/src/sfpi.c index f8f89f38d..8ac62c6f6 100644 --- a/packages/platforms/accton/x86-64/as5835-54t/onlp/builds/x86_64_accton_as5835_54t/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as5835-54t/onlp/builds/x86_64_accton_as5835_54t/module/src/sfpi.c @@ -228,7 +228,7 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int present = 0; VALIDATE_QSFP(port); @@ -243,12 +243,17 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { /* txdis valid bit(bit0-bit3), xxxx 1111 */ value = value & 0xf; - onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value); - - rv = ONLP_STATUS_OK; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } else { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } break; @@ -289,7 +294,7 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int tx_dis_val = 0; int present = 0; @@ -304,11 +309,18 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) if(present == 1){ /* txdis valid bit(bit0-bit3), xxxx 1111 */ tx_dis_val = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); - *value = tx_dis_val; - - rv = ONLP_STATUS_OK; + + if(tx_dis_val < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis_val; + rv = ONLP_STATUS_OK; + } } else{ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } break; diff --git a/packages/platforms/accton/x86-64/as5835-54x/onlp/builds/x86_64_accton_as5835_54x/module/src/sfpi.c b/packages/platforms/accton/x86-64/as5835-54x/onlp/builds/x86_64_accton_as5835_54x/module/src/sfpi.c index 54e30c5c6..dc012ed7f 100644 --- a/packages/platforms/accton/x86-64/as5835-54x/onlp/builds/x86_64_accton_as5835_54x/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as5835-54x/onlp/builds/x86_64_accton_as5835_54x/module/src/sfpi.c @@ -353,7 +353,7 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int addr = (port < 38) ? 61 : 62; int present = 0; @@ -368,7 +368,7 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) if(present == 1) { if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, 3, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } else { @@ -378,12 +378,17 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) else if(port >= QSFP_PORT_MIN && port <= QSFP_PORT_MAX){ //QSFP /* txdis valid bit(bit0-bit3), xxxx 1111 */ value = value & 0xf; - onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value); - - rv = ONLP_STATUS_OK; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } } else { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } break; @@ -426,7 +431,7 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int addr = (port < 38) ? 61 : 62; int tx_dis_val = 0; int present = 0; @@ -478,12 +483,18 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) else if(port >= QSFP_PORT_MIN && port <= QSFP_PORT_MAX){ //QSFP /* txdis valid bit(bit0-bit3), xxxx 1111 */ tx_dis_val = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); - *value = tx_dis_val; - - rv = ONLP_STATUS_OK; + if(tx_dis_val < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis_val; + rv = ONLP_STATUS_OK; } + } } else { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } break; diff --git a/packages/platforms/accton/x86-64/as7326-56x/modules/builds/src/x86-64-accton-as7326-56x-cpld.c b/packages/platforms/accton/x86-64/as7326-56x/modules/builds/src/x86-64-accton-as7326-56x-cpld.c index d08c5b86c..2bc77fb35 100644 --- a/packages/platforms/accton/x86-64/as7326-56x/modules/builds/src/x86-64-accton-as7326-56x-cpld.c +++ b/packages/platforms/accton/x86-64/as7326-56x/modules/builds/src/x86-64-accton-as7326-56x-cpld.c @@ -290,6 +290,14 @@ enum as7326_56x_cpld_sysfs_attributes { TRANSCEIVER_TXFAULT_ATTR_ID(48), TRANSCEIVER_TXFAULT_ATTR_ID(57), TRANSCEIVER_TXFAULT_ATTR_ID(58), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(55), + TRANSCEIVER_RESET_ATTR_ID(56), }; /* sysfs attributes for hwmon @@ -300,7 +308,7 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, +static ssize_t set_control(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static ssize_t access(struct device *dev, struct device_attribute *da, const char *buf, size_t count); @@ -321,11 +329,11 @@ static int as7326_56x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 #define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr #define DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(index) \ - static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_reset, MODULE_RESET_##index) + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_RESET_##index) #define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##index.dev_attr.attr #define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ - static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_tx_disable, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_TXDISABLE_##index); \ static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) #define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ @@ -450,6 +458,14 @@ DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(48); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(57); DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(58); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(54); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(55); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(56); static struct attribute *as7326_56x_cpu_cpld_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, &sensor_dev_attr_bios_flash_id.dev_attr.attr, @@ -599,6 +615,14 @@ static struct attribute *as7326_56x_cpld1_attributes[] = { DECLARE_SFP_TRANSCEIVER_ATTR(48), DECLARE_SFP_TRANSCEIVER_ATTR(57), DECLARE_SFP_TRANSCEIVER_ATTR(58), + DECLARE_TRANSCEIVER_RESET_ATTR(49), + DECLARE_TRANSCEIVER_RESET_ATTR(50), + DECLARE_TRANSCEIVER_RESET_ATTR(51), + DECLARE_TRANSCEIVER_RESET_ATTR(52), + DECLARE_TRANSCEIVER_RESET_ATTR(53), + DECLARE_TRANSCEIVER_RESET_ATTR(54), + DECLARE_TRANSCEIVER_RESET_ATTR(55), + DECLARE_TRANSCEIVER_RESET_ATTR(56), NULL }; @@ -747,24 +771,28 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); struct as7326_56x_cpld_data *data = i2c_get_clientdata(client); int status = 0; - u8 reg = 0, mask = 0, revert = 0; + u8 reg = 0, mask = 0, invert = 0; switch (attr->index) { case MODULE_PRESENT_1 ... MODULE_PRESENT_30: reg = 0x0f + (attr->index-MODULE_PRESENT_1)/8; mask = 0x1 << ((attr->index - MODULE_PRESENT_1)%8); + invert = 1; break; case MODULE_PRESENT_31 ... MODULE_PRESENT_48: reg = 0x10 + (attr->index-MODULE_PRESENT_31)/8; mask = 0x1 << ((attr->index - MODULE_PRESENT_31)%8); + invert = 1; break; case MODULE_PRESENT_57 ... MODULE_PRESENT_58: reg = 0x12; mask = 0x1 << ((attr->index - MODULE_PRESENT_57)+2); + invert = 1; break; case MODULE_PRESENT_49 ... MODULE_PRESENT_56: /*QSFP*/ reg = 0x13 ; mask = 0x1 << ((attr->index - MODULE_PRESENT_49)%8); + invert = 1; break; case MODULE_TXFAULT_1 ... MODULE_TXFAULT_30: reg = 0x03 + (attr->index - MODULE_TXFAULT_1)/8; @@ -802,14 +830,15 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, reg = 0x19; mask = 0x1 << (( attr->index - MODULE_RXLOS_57)+2); break; + case MODULE_RESET_49 ... MODULE_RESET_56: + reg = 0x4; + mask = 0x1 << (attr->index - MODULE_RESET_49); + invert = 1; + break; default: return 0; } - if (attr->index >= MODULE_PRESENT_1 && attr->index <= MODULE_PRESENT_58) { - revert = 1; - } - mutex_lock(&data->update_lock); status = as7326_56x_cpld_read_internal(client, reg); if (unlikely(status < 0)) { @@ -817,24 +846,24 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, } mutex_unlock(&data->update_lock); - return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + return sprintf(buf, "%d\n", invert ? !(status & mask) : !!(status & mask)); exit: mutex_unlock(&data->update_lock); return status; } -static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, +static ssize_t set_control(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); struct as7326_56x_cpld_data *data = i2c_get_clientdata(client); - long disable; + long value; int status; - u8 reg = 0, mask = 0; + u8 reg = 0, mask = 0, invert = 0; - status = kstrtol(buf, 10, &disable); + status = kstrtol(buf, 10, &value); if (status) { return status; } @@ -852,6 +881,11 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, reg = 0x16; mask = 0x1 << ((attr->index - MODULE_TXDISABLE_57)+2); break; + case MODULE_RESET_49 ... MODULE_RESET_56: + reg = 0x4; + mask = 0x1 << (attr->index - MODULE_RESET_49); + invert = 1; + break; default: return 0; } @@ -863,8 +897,12 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da, goto exit; } - /* Update tx_disable status */ - if (disable) { + /* Update tx_disable/reset status */ + if (invert) { + value = !value; + } + + if (value) { status |= mask; } else { @@ -1071,7 +1109,7 @@ static ssize_t set_reset(struct device *dev, struct device_attribute *da, status = as7326_56x_cpld_write_internal(client, reg, status); if (unlikely(status < 0)) goto exit; - + mutex_unlock(&data->update_lock); break; diff --git a/packages/platforms/accton/x86-64/as7326-56x/onlp/builds/x86_64_accton_as7326_56x/module/src/sfpi.c b/packages/platforms/accton/x86-64/as7326-56x/onlp/builds/x86_64_accton_as7326_56x/module/src/sfpi.c index d9a231ca8..c78cf1498 100644 --- a/packages/platforms/accton/x86-64/as7326-56x/onlp/builds/x86_64_accton_as7326_56x/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as7326-56x/onlp/builds/x86_64_accton_as7326_56x/module/src/sfpi.c @@ -29,6 +29,33 @@ #include "x86_64_accton_as7326_56x_int.h" #include "x86_64_accton_as7326_56x_log.h" +#define SFP_PORT_RANGE1_MIN 0 +#define SFP_PORT_RANGE1_MAX 47 +#define QSFP_PORT_MIN 48 +#define QSFP_PORT_MAX 55 +#define SFP_PORT_RANGE2_MIN 56 +#define SFP_PORT_RANGE2_MAX 57 +#define MIN_PORT SFP_PORT_RANGE1_MIN +#define MAX_PORT SFP_PORT_RANGE2_MAX + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < SFP_PORT_RANGE1_MIN || _port > SFP_PORT_RANGE2_MAX ||(_port >= QSFP_PORT_MIN && _port <= QSFP_PORT_MAX)) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define PORT_BUS_INDEX(port) sfp_map[port] #define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" @@ -37,13 +64,18 @@ #define MODULE_TXFAULT_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_fault_%d" #define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_disable_%d" #define MODULE_PRESENT_ALL_ATTR "/sys/bus/i2c/devices/%d-00%d/module_present_all" +#define MODULE_RESET_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_reset_%d" #define MODULE_RXLOS_ALL_ATTR_CPLD1 "/sys/bus/i2c/devices/18-0060/module_rx_los_all" #define MODULE_RXLOS_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/12-0062/module_rx_los_all" /* QSFP device address of eeprom */ #define PORT_EEPROM_DEVADDR 0x50 -/* QSFP tx disable offset */ + +/* QSFP eeprom offset */ #define QSFP_EEPROM_OFFSET_TXDIS 0x56 +#define QSFP_EEPROM_OFFSET_LPMODE 0x5D +/*QSFP Specific*/ +#define QSFP_LPMODE 0x3 const int sfp_map[] = { 42,41,44,43,47,45,46,50, 48,49,52,51,53,56,55,54, @@ -293,52 +325,100 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int present = 0; - - if (port < 0 || port >= 56) { - return ONLP_STATUS_E_UNSUPPORTED; - } - + int lpmode_value = 0; int addr = (port < 30) ? 62 : 60; int bus = (addr == 62) ? 12 : 18; + VALIDATE_PORT(port); + switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if(port > 47 && port < 56) + present = onlp_sfpi_is_present(port); + /* write qsfp eeprom data of tx disable if qsfp present */ + if(present == 1) { - present = onlp_sfpi_is_present(port); - /* write qsfp eeprom data of tx disable if qsfp present */ - if(present == 1) + if(port >= QSFP_PORT_MIN && port <= QSFP_PORT_MAX) { /* txdis valid bit(bit0-bit3), xxxx 1111 */ - value = value&0xf; - - onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value); - - rv = ONLP_STATUS_OK; - + value = value & 0xf; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } else { - rv = ONLP_STATUS_E_INTERNAL; + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } - } else { - if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + VALIDATE_QSFP(port); + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d):read LP mode value fail\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } else { - rv = ONLP_STATUS_OK; + if(value){ + lpmode_value |= QSFP_LPMODE; + } else{ + lpmode_value &= ~QSFP_LPMODE; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE, lpmode_value) < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d):write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } } - + else + { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } break; } @@ -353,13 +433,12 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int present = 0; int tx_dis = 0; + int lpmode_value = 0; - if (port < 0 || port >= 56) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_PORT(port); int addr = (port < 30) ? 62 : 60; int bus = (addr == 62) ? 12 : 18; @@ -368,9 +447,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { case ONLP_SFP_CONTROL_RX_LOS: { - if (port < 0 || port >= 48) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_SFP(port); if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); @@ -384,9 +461,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_FAULT: { - if (port < 0 || port >= 48) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_SFP(port); if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, bus, addr, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); @@ -401,35 +476,76 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_DISABLE: case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if(port > 47 && port < 56) + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { - present = onlp_sfpi_is_present(port); - /* read qsfp eeprom offset of tx disable if qsfp on the port */ - if(present == 1) + if(port >= QSFP_PORT_MIN && port <= QSFP_PORT_MAX) { tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); - - *value = tx_dis; - - rv = ONLP_STATUS_OK; - + if(tx_dis < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis; + rv = ONLP_STATUS_OK; + } } else { - rv = ONLP_STATUS_E_INTERNAL; + + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } } else { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + case ONLP_SFP_CONTROL_RESET: + { + VALIDATE_QSFP(port); + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0) { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read eeprom fail\r\n", port); rv = ONLP_STATUS_E_INTERNAL; - } + } else { + *value = ((lpmode_value & QSFP_LPMODE) == QSFP_LPMODE); rv = ONLP_STATUS_OK; } } + else + { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } break; } diff --git a/packages/platforms/accton/x86-64/as7712-32x/modules/builds/src/x86-64-accton-as7712-32x-cpld1.c b/packages/platforms/accton/x86-64/as7712-32x/modules/builds/src/x86-64-accton-as7712-32x-cpld1.c index 174f3c8c8..fac3e81af 100644 --- a/packages/platforms/accton/x86-64/as7712-32x/modules/builds/src/x86-64-accton-as7712-32x-cpld1.c +++ b/packages/platforms/accton/x86-64/as7712-32x/modules/builds/src/x86-64-accton-as7712-32x-cpld1.c @@ -47,7 +47,7 @@ struct cpld_client_node { #define MAC_PCIE_RESET_DELAY 200 /* ms */ -static ssize_t show_present(struct device *dev, struct device_attribute *da, +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_present_all(struct device *dev, struct device_attribute *da, char *buf); @@ -59,6 +59,8 @@ static ssize_t get_reset(struct device *dev, struct device_attribute *da, char *buf); static ssize_t set_reset(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); static int as7712_32x_cpld_read_internal(struct i2c_client *client, u8 reg); static int as7712_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); @@ -79,6 +81,7 @@ struct as7712_32x_cpld_data { static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; #define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index enum as7712_32x_cpld_sysfs_attributes { CPLD_VERSION, @@ -118,6 +121,38 @@ enum as7712_32x_cpld_sysfs_attributes { TRANSCEIVER_PRESENT_ATTR_ID(30), TRANSCEIVER_PRESENT_ATTR_ID(31), TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), }; static const struct i2c_device_id as7712_32x_cpld_id[] = { @@ -133,9 +168,14 @@ MODULE_DEVICE_TABLE(i2c, as7712_32x_cpld_id); /* transceiver attributes */ #define DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ - static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_present, NULL, MODULE_PRESENT_##index) + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index) #define DECLARE_TRANSCEIVER_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_RESET_##index); +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); static SENSOR_DEVICE_ATTR(reset_mac, S_IRUGO | S_IWUSR, get_reset, set_reset, RESET_MAC); static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); @@ -173,6 +213,38 @@ DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); static struct attribute *as7712_32x_cpld_attributes[] = { &sensor_dev_attr_version.dev_attr.attr, @@ -212,6 +284,38 @@ static struct attribute *as7712_32x_cpld_attributes[] = { DECLARE_TRANSCEIVER_ATTR(30), DECLARE_TRANSCEIVER_ATTR(31), DECLARE_TRANSCEIVER_ATTR(32), + DECLARE_QSFP_TRANSCEIVER_ATTR(1), + DECLARE_QSFP_TRANSCEIVER_ATTR(2), + DECLARE_QSFP_TRANSCEIVER_ATTR(3), + DECLARE_QSFP_TRANSCEIVER_ATTR(4), + DECLARE_QSFP_TRANSCEIVER_ATTR(5), + DECLARE_QSFP_TRANSCEIVER_ATTR(6), + DECLARE_QSFP_TRANSCEIVER_ATTR(7), + DECLARE_QSFP_TRANSCEIVER_ATTR(8), + DECLARE_QSFP_TRANSCEIVER_ATTR(9), + DECLARE_QSFP_TRANSCEIVER_ATTR(10), + DECLARE_QSFP_TRANSCEIVER_ATTR(11), + DECLARE_QSFP_TRANSCEIVER_ATTR(12), + DECLARE_QSFP_TRANSCEIVER_ATTR(13), + DECLARE_QSFP_TRANSCEIVER_ATTR(14), + DECLARE_QSFP_TRANSCEIVER_ATTR(15), + DECLARE_QSFP_TRANSCEIVER_ATTR(16), + DECLARE_QSFP_TRANSCEIVER_ATTR(17), + DECLARE_QSFP_TRANSCEIVER_ATTR(18), + DECLARE_QSFP_TRANSCEIVER_ATTR(19), + DECLARE_QSFP_TRANSCEIVER_ATTR(20), + DECLARE_QSFP_TRANSCEIVER_ATTR(21), + DECLARE_QSFP_TRANSCEIVER_ATTR(22), + DECLARE_QSFP_TRANSCEIVER_ATTR(23), + DECLARE_QSFP_TRANSCEIVER_ATTR(24), + DECLARE_QSFP_TRANSCEIVER_ATTR(25), + DECLARE_QSFP_TRANSCEIVER_ATTR(26), + DECLARE_QSFP_TRANSCEIVER_ATTR(27), + DECLARE_QSFP_TRANSCEIVER_ATTR(28), + DECLARE_QSFP_TRANSCEIVER_ATTR(29), + DECLARE_QSFP_TRANSCEIVER_ATTR(30), + DECLARE_QSFP_TRANSCEIVER_ATTR(31), + DECLARE_QSFP_TRANSCEIVER_ATTR(32), NULL }; @@ -270,32 +374,56 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, return status; } -static ssize_t show_present(struct device *dev, struct device_attribute *da, +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); struct as7712_32x_cpld_data *data = i2c_get_clientdata(client); int status = 0; - u8 reg = 0, mask = 0; + u8 reg = 0, mask = 0, invert = 0; switch (attr->index) { case MODULE_PRESENT_1 ... MODULE_PRESENT_8: reg = 0x30; mask = 0x1 << (attr->index - MODULE_PRESENT_1); + invert = 1; break; case MODULE_PRESENT_9 ... MODULE_PRESENT_16: reg = 0x31; mask = 0x1 << (attr->index - MODULE_PRESENT_9); + invert = 1; break; case MODULE_PRESENT_17 ... MODULE_PRESENT_24: reg = 0x32; mask = 0x1 << (attr->index - MODULE_PRESENT_17); + invert = 1; break; case MODULE_PRESENT_25 ... MODULE_PRESENT_32: reg = 0x33; mask = 0x1 << (attr->index - MODULE_PRESENT_25); + invert = 1; + break; + case MODULE_RESET_1 ... MODULE_RESET_8: + reg = 0x4; + mask = 0x1 << (attr->index - MODULE_RESET_1); + invert = 1; + break; + case MODULE_RESET_9 ... MODULE_RESET_16: + reg = 0x5; + mask = 0x1 << (attr->index - MODULE_RESET_9); + invert = 1; + break; + case MODULE_RESET_17 ... MODULE_RESET_24: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_RESET_17); + invert = 1; break; + case MODULE_RESET_25 ... MODULE_RESET_32: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_RESET_25); + invert = 1; + break; default: return 0; } @@ -308,7 +436,7 @@ static ssize_t show_present(struct device *dev, struct device_attribute *da, } mutex_unlock(&data->update_lock); - return sprintf(buf, "%d\n", !(status & mask)); + return sprintf(buf, "%d\n", invert ? !(status & mask) : !!(status & mask)); exit: mutex_unlock(&data->update_lock); @@ -383,6 +511,81 @@ static ssize_t get_reset(struct device *dev, struct device_attribute *da, return status; } +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as7712_32x_cpld_data *data = i2c_get_clientdata(client); + long value; + int status; + u8 reg = 0, mask = 0, invert = 0; + + status = kstrtol(buf, 10, &value); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_RESET_1 ... MODULE_RESET_8: + reg = 0x4; + mask = 0x1 << (attr->index - MODULE_RESET_1); + invert = 1; + break; + case MODULE_RESET_9 ... MODULE_RESET_16: + reg = 0x5; + mask = 0x1 << (attr->index - MODULE_RESET_9); + invert = 1; + break; + case MODULE_RESET_17 ... MODULE_RESET_24: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_RESET_17); + invert = 1; + break; + case MODULE_RESET_25 ... MODULE_RESET_32: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_RESET_25); + invert = 1; + break; + + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as7712_32x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update tx_disable/reset status */ + if (invert) { + value = !value; + } + + /* Update tx_disable/reset status */ + if (value) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as7712_32x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + static ssize_t set_reset(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { diff --git a/packages/platforms/accton/x86-64/as7712-32x/onlp/builds/x86_64_accton_as7712_32x/module/src/sfpi.c b/packages/platforms/accton/x86-64/as7712-32x/onlp/builds/x86_64_accton_as7712_32x/module/src/sfpi.c index e98472885..bf8007a28 100644 --- a/packages/platforms/accton/x86-64/as7712-32x/onlp/builds/x86_64_accton_as7712_32x/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as7712-32x/onlp/builds/x86_64_accton_as7712_32x/module/src/sfpi.c @@ -29,6 +29,15 @@ #include #include "platform_lib.h" +#define QSFP_PORT_MIN 0 +#define QSFP_PORT_MAX 31 + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define MUX_START_INDEX 18 #define NUM_OF_SFP_PORT 32 static const int port_bus_index[NUM_OF_SFP_PORT] = { @@ -43,6 +52,17 @@ static const int port_bus_index[NUM_OF_SFP_PORT] = { #define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/4-0060/module_present_%d" #define MODULE_PRESENT_ALL_ATTR "/sys/bus/i2c/devices/4-0060/module_present_all" +#define MODULE_RESET_FORMAT "/sys/bus/i2c/devices/4-0060/module_reset_%d" + +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 + +/* QSFP eeprom offsets*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 +#define QSFP_EEPROM_OFFSET_LPMODE 0x5D + +/*QSFP Specific*/ +#define QSFP_LPMODE 0x3 /************************************************************ * @@ -180,6 +200,171 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) return onlp_i2c_writew(bus, devaddr, addr, value, ONLP_I2C_F_FORCE); } +int +onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) +{ + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int lpmode_value = 0; + + VALIDATE_QSFP(port); + + switch(control) + { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + if(present == 1){ + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value & 0xf; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + + } else { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + present = onlp_sfpi_is_present(port); + if (present == 1) { + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d):read LP mode value fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + if(value){ + lpmode_value |= QSFP_LPMODE; + } else{ + lpmode_value &= ~QSFP_LPMODE; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE, lpmode_value) < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d):write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } + else + { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + break; + } + + return rv; +} + +int +onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) +{ + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int tx_dis = 0; + int lpmode_value = 0; + + VALIDATE_QSFP(port); + + switch(control) + { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + if(present == 1) + { + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_dis < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + + } else { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + present = onlp_sfpi_is_present(port); + if (present == 1) { + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0) { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = ((lpmode_value & QSFP_LPMODE) == QSFP_LPMODE); + rv = ONLP_STATUS_OK; + } + } + else + { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + } + + return rv; +} + int onlp_sfpi_denit(void) { diff --git a/packages/platforms/accton/x86-64/as7816-64x/modules/builds/x86-64-accton-as7816-64x-cpld1.c b/packages/platforms/accton/x86-64/as7816-64x/modules/builds/x86-64-accton-as7816-64x-cpld1.c index f01b5ff4f..3bcb3f12d 100644 --- a/packages/platforms/accton/x86-64/as7816-64x/modules/builds/x86-64-accton-as7816-64x-cpld1.c +++ b/packages/platforms/accton/x86-64/as7816-64x/modules/builds/x86-64-accton-as7816-64x-cpld1.c @@ -45,9 +45,11 @@ struct cpld_client_node { #define I2C_RW_RETRY_COUNT 10 #define I2C_RW_RETRY_INTERVAL 60 /* ms */ -static ssize_t show_psu(struct device *dev, struct device_attribute *da, +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_present(struct device *dev, struct device_attribute *da, +static ssize_t show_psu(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_present_all(struct device *dev, struct device_attribute *da, char *buf); @@ -69,6 +71,7 @@ struct as7816_64x_cpld_data { static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; #define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index #define PSU_PRESENT_ATTR_ID(index) PSU##index##_PRESENT #define PSU_POWERGOOD_ATTR_ID(index) PSU##index##_POWER_GOOD @@ -142,7 +145,70 @@ enum as7816_64x_cpld_sysfs_attributes { TRANSCEIVER_PRESENT_ATTR_ID(62), TRANSCEIVER_PRESENT_ATTR_ID(63), TRANSCEIVER_PRESENT_ATTR_ID(64), - + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_RESET_ATTR_ID(33), + TRANSCEIVER_RESET_ATTR_ID(34), + TRANSCEIVER_RESET_ATTR_ID(35), + TRANSCEIVER_RESET_ATTR_ID(36), + TRANSCEIVER_RESET_ATTR_ID(37), + TRANSCEIVER_RESET_ATTR_ID(38), + TRANSCEIVER_RESET_ATTR_ID(39), + TRANSCEIVER_RESET_ATTR_ID(40), + TRANSCEIVER_RESET_ATTR_ID(41), + TRANSCEIVER_RESET_ATTR_ID(42), + TRANSCEIVER_RESET_ATTR_ID(43), + TRANSCEIVER_RESET_ATTR_ID(44), + TRANSCEIVER_RESET_ATTR_ID(45), + TRANSCEIVER_RESET_ATTR_ID(46), + TRANSCEIVER_RESET_ATTR_ID(47), + TRANSCEIVER_RESET_ATTR_ID(48), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(55), + TRANSCEIVER_RESET_ATTR_ID(56), + TRANSCEIVER_RESET_ATTR_ID(57), + TRANSCEIVER_RESET_ATTR_ID(58), + TRANSCEIVER_RESET_ATTR_ID(59), + TRANSCEIVER_RESET_ATTR_ID(60), + TRANSCEIVER_RESET_ATTR_ID(61), + TRANSCEIVER_RESET_ATTR_ID(62), + TRANSCEIVER_RESET_ATTR_ID(63), + TRANSCEIVER_RESET_ATTR_ID(64), /* psu attributes */ PSU_PRESENT_ATTR_ID(1), PSU_PRESENT_ATTR_ID(2), @@ -155,9 +221,13 @@ enum as7816_64x_cpld_sysfs_attributes { /* transceiver attributes */ #define DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ - static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_present, NULL, MODULE_PRESENT_##index) + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); #define DECLARE_TRANSCEIVER_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr +#define DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_RESET_##index); +#define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##index.dev_attr.attr + /* psu attributes */ #define DECLARE_PSU_SENSOR_DEVICE_ATTR(index) \ static SENSOR_DEVICE_ATTR(psu##index##_present, S_IRUGO, show_psu, NULL, PSU##index##_PRESENT); \ @@ -236,7 +306,70 @@ DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(61); DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(62); DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(63); DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(64); - +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(32); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(33); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(34); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(35); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(36); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(37); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(38); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(39); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(40); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(41); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(42); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(43); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(44); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(45); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(46); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(47); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(48); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(54); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(55); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(56); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(57); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(58); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(59); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(60); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(61); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(62); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(63); +DECLARE_TRANSCEIVER_RESET_SENSOR_DEVICE_ATTR(64); /* psu attributes*/ DECLARE_PSU_SENSOR_DEVICE_ATTR(1); DECLARE_PSU_SENSOR_DEVICE_ATTR(2); @@ -311,7 +444,70 @@ static struct attribute *as7816_64x_cpld_attributes[] = { DECLARE_TRANSCEIVER_ATTR(62), DECLARE_TRANSCEIVER_ATTR(63), DECLARE_TRANSCEIVER_ATTR(64), - + DECLARE_TRANSCEIVER_RESET_ATTR(1), + DECLARE_TRANSCEIVER_RESET_ATTR(2), + DECLARE_TRANSCEIVER_RESET_ATTR(3), + DECLARE_TRANSCEIVER_RESET_ATTR(4), + DECLARE_TRANSCEIVER_RESET_ATTR(5), + DECLARE_TRANSCEIVER_RESET_ATTR(6), + DECLARE_TRANSCEIVER_RESET_ATTR(7), + DECLARE_TRANSCEIVER_RESET_ATTR(8), + DECLARE_TRANSCEIVER_RESET_ATTR(9), + DECLARE_TRANSCEIVER_RESET_ATTR(10), + DECLARE_TRANSCEIVER_RESET_ATTR(11), + DECLARE_TRANSCEIVER_RESET_ATTR(12), + DECLARE_TRANSCEIVER_RESET_ATTR(13), + DECLARE_TRANSCEIVER_RESET_ATTR(14), + DECLARE_TRANSCEIVER_RESET_ATTR(15), + DECLARE_TRANSCEIVER_RESET_ATTR(16), + DECLARE_TRANSCEIVER_RESET_ATTR(17), + DECLARE_TRANSCEIVER_RESET_ATTR(18), + DECLARE_TRANSCEIVER_RESET_ATTR(19), + DECLARE_TRANSCEIVER_RESET_ATTR(20), + DECLARE_TRANSCEIVER_RESET_ATTR(21), + DECLARE_TRANSCEIVER_RESET_ATTR(22), + DECLARE_TRANSCEIVER_RESET_ATTR(23), + DECLARE_TRANSCEIVER_RESET_ATTR(24), + DECLARE_TRANSCEIVER_RESET_ATTR(25), + DECLARE_TRANSCEIVER_RESET_ATTR(26), + DECLARE_TRANSCEIVER_RESET_ATTR(27), + DECLARE_TRANSCEIVER_RESET_ATTR(28), + DECLARE_TRANSCEIVER_RESET_ATTR(29), + DECLARE_TRANSCEIVER_RESET_ATTR(30), + DECLARE_TRANSCEIVER_RESET_ATTR(31), + DECLARE_TRANSCEIVER_RESET_ATTR(32), + DECLARE_TRANSCEIVER_RESET_ATTR(33), + DECLARE_TRANSCEIVER_RESET_ATTR(34), + DECLARE_TRANSCEIVER_RESET_ATTR(35), + DECLARE_TRANSCEIVER_RESET_ATTR(36), + DECLARE_TRANSCEIVER_RESET_ATTR(37), + DECLARE_TRANSCEIVER_RESET_ATTR(38), + DECLARE_TRANSCEIVER_RESET_ATTR(39), + DECLARE_TRANSCEIVER_RESET_ATTR(40), + DECLARE_TRANSCEIVER_RESET_ATTR(41), + DECLARE_TRANSCEIVER_RESET_ATTR(42), + DECLARE_TRANSCEIVER_RESET_ATTR(43), + DECLARE_TRANSCEIVER_RESET_ATTR(44), + DECLARE_TRANSCEIVER_RESET_ATTR(45), + DECLARE_TRANSCEIVER_RESET_ATTR(46), + DECLARE_TRANSCEIVER_RESET_ATTR(47), + DECLARE_TRANSCEIVER_RESET_ATTR(48), + DECLARE_TRANSCEIVER_RESET_ATTR(49), + DECLARE_TRANSCEIVER_RESET_ATTR(50), + DECLARE_TRANSCEIVER_RESET_ATTR(51), + DECLARE_TRANSCEIVER_RESET_ATTR(52), + DECLARE_TRANSCEIVER_RESET_ATTR(53), + DECLARE_TRANSCEIVER_RESET_ATTR(54), + DECLARE_TRANSCEIVER_RESET_ATTR(55), + DECLARE_TRANSCEIVER_RESET_ATTR(56), + DECLARE_TRANSCEIVER_RESET_ATTR(57), + DECLARE_TRANSCEIVER_RESET_ATTR(58), + DECLARE_TRANSCEIVER_RESET_ATTR(59), + DECLARE_TRANSCEIVER_RESET_ATTR(60), + DECLARE_TRANSCEIVER_RESET_ATTR(61), + DECLARE_TRANSCEIVER_RESET_ATTR(62), + DECLARE_TRANSCEIVER_RESET_ATTR(63), + DECLARE_TRANSCEIVER_RESET_ATTR(64), /* psu attributes*/ DECLARE_PSU_ATTR(1), DECLARE_PSU_ATTR(2), @@ -322,6 +518,207 @@ static const struct attribute_group as7816_64x_cpld_group = { .attrs = as7816_64x_cpld_attributes, }; +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as7816_64x_cpld_data *data = i2c_get_clientdata(client); + long value; + int status; + u8 reg = 0, mask = 0, invert = 0; + + status = kstrtol(buf, 10, &value); + + if (status) + return status; + + switch (attr->index) { + case MODULE_RESET_1 ... MODULE_RESET_8: + reg = 0x40; + mask = 0x1 << (attr->index - MODULE_RESET_1); + invert = 1; + break; + case MODULE_RESET_9 ... MODULE_RESET_16: + reg = 0x41; + mask = 0x1 << (attr->index - MODULE_RESET_9); + invert = 1; + break; + case MODULE_RESET_17 ... MODULE_RESET_24: + reg = 0x42; + mask = 0x1 << (attr->index - MODULE_RESET_17); + invert = 1; + break; + case MODULE_RESET_25 ... MODULE_RESET_32: + reg = 0x43; + mask = 0x1 << (attr->index - MODULE_RESET_25); + invert = 1; + break; + case MODULE_RESET_33 ... MODULE_RESET_40: + reg = 0x44; + mask = 0x1 << (attr->index - MODULE_RESET_33); + invert = 1; + break; + case MODULE_RESET_41 ... MODULE_RESET_48: + reg = 0x45; + mask = 0x1 << (attr->index - MODULE_RESET_41); + invert = 1; + break; + case MODULE_RESET_49 ... MODULE_RESET_56: + reg = 0x46; + mask = 0x1 << (attr->index - MODULE_RESET_49); + invert = 1; + break; + case MODULE_RESET_57 ... MODULE_RESET_64: + reg = 0x47; + mask = 0x1 << (attr->index - MODULE_RESET_57); + invert = 1; + break; + + default: + return -EINVAL; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as7816_64x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update reset status */ + if (invert) { + value = !value; + } + + if (value) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as7816_64x_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as7816_64x_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, invert = 0; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_8: + reg = 0x70; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + invert = 1; + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_16: + reg = 0x71; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + invert = 1; + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_24: + reg = 0x72; + mask = 0x1 << (attr->index - MODULE_PRESENT_17); + invert = 1; + break; + case MODULE_PRESENT_25 ... MODULE_PRESENT_32: + reg = 0x73; + mask = 0x1 << (attr->index - MODULE_PRESENT_25); + invert = 1; + break; + case MODULE_PRESENT_33 ... MODULE_PRESENT_40: + reg = 0x74; + mask = 0x1 << (attr->index - MODULE_PRESENT_33); + invert = 1; + break; + case MODULE_PRESENT_41 ... MODULE_PRESENT_48: + reg = 0x75; + mask = 0x1 << (attr->index - MODULE_PRESENT_41); + invert = 1; + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_56: + reg = 0x76; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + invert = 1; + break; + case MODULE_PRESENT_57 ... MODULE_PRESENT_64: + reg = 0x77; + mask = 0x1 << (attr->index - MODULE_PRESENT_57); + invert = 1; + break; + case MODULE_RESET_1 ... MODULE_RESET_8: + reg = 0x40; + mask = 0x1 << (attr->index - MODULE_RESET_1); + invert = 1; + break; + case MODULE_RESET_9 ... MODULE_RESET_16: + reg = 0x41; + mask = 0x1 << (attr->index - MODULE_RESET_9); + invert = 1; + break; + case MODULE_RESET_17 ... MODULE_RESET_24: + reg = 0x42; + mask = 0x1 << (attr->index - MODULE_RESET_17); + invert = 1; + break; + case MODULE_RESET_25 ... MODULE_RESET_32: + reg = 0x43; + mask = 0x1 << (attr->index - MODULE_RESET_25); + invert = 1; + break; + case MODULE_RESET_33 ... MODULE_RESET_40: + reg = 0x44; + mask = 0x1 << (attr->index - MODULE_RESET_33); + invert = 1; + break; + case MODULE_RESET_41 ... MODULE_RESET_48: + reg = 0x45; + mask = 0x1 << (attr->index - MODULE_RESET_41); + invert = 1; + break; + case MODULE_RESET_49 ... MODULE_RESET_56: + reg = 0x46; + mask = 0x1 << (attr->index - MODULE_RESET_49); + invert = 1; + break; + case MODULE_RESET_57 ... MODULE_RESET_64: + reg = 0x47; + mask = 0x1 << (attr->index - MODULE_RESET_57); + invert = 1; + break; + default: + return 0; + } + + mutex_lock(&data->update_lock); + status = as7816_64x_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", invert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + static ssize_t show_psu(struct device *dev, struct device_attribute *da, char *buf) { @@ -391,67 +788,6 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da, return status; } -static ssize_t show_present(struct device *dev, struct device_attribute *da, - char *buf) -{ - struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct i2c_client *client = to_i2c_client(dev); - struct as7816_64x_cpld_data *data = i2c_get_clientdata(client); - int status = 0; - u8 reg = 0, mask = 0; - - switch (attr->index) { - case MODULE_PRESENT_1 ... MODULE_PRESENT_8: - reg = 0x70; - mask = 0x1 << (attr->index - MODULE_PRESENT_1); - break; - case MODULE_PRESENT_9 ... MODULE_PRESENT_16: - reg = 0x71; - mask = 0x1 << (attr->index - MODULE_PRESENT_9); - break; - case MODULE_PRESENT_17 ... MODULE_PRESENT_24: - reg = 0x72; - mask = 0x1 << (attr->index - MODULE_PRESENT_17); - break; - case MODULE_PRESENT_25 ... MODULE_PRESENT_32: - reg = 0x73; - mask = 0x1 << (attr->index - MODULE_PRESENT_25); - break; - case MODULE_PRESENT_33 ... MODULE_PRESENT_40: - reg = 0x74; - mask = 0x1 << (attr->index - MODULE_PRESENT_33); - break; - case MODULE_PRESENT_41 ... MODULE_PRESENT_48: - reg = 0x75; - mask = 0x1 << (attr->index - MODULE_PRESENT_41); - break; - case MODULE_PRESENT_49 ... MODULE_PRESENT_56: - reg = 0x76; - mask = 0x1 << (attr->index - MODULE_PRESENT_49); - break; - case MODULE_PRESENT_57 ... MODULE_PRESENT_64: - reg = 0x77; - mask = 0x1 << (attr->index - MODULE_PRESENT_57); - break; - default: - return 0; - } - - - mutex_lock(&data->update_lock); - status = as7816_64x_cpld_read_internal(client, reg); - if (unlikely(status < 0)) { - goto exit; - } - mutex_unlock(&data->update_lock); - - return sprintf(buf, "%d\n", !(status & mask)); - -exit: - mutex_unlock(&data->update_lock); - return status; -} - static ssize_t show_version(struct device *dev, struct device_attribute *da, char *buf) { diff --git a/packages/platforms/accton/x86-64/as7816-64x/onlp/builds/x86_64_accton_as7816_64x/module/src/sfpi.c b/packages/platforms/accton/x86-64/as7816-64x/onlp/builds/x86_64_accton_as7816_64x/module/src/sfpi.c index e2e724612..0b49cc5ad 100644 --- a/packages/platforms/accton/x86-64/as7816-64x/onlp/builds/x86_64_accton_as7816_64x/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as7816-64x/onlp/builds/x86_64_accton_as7816_64x/module/src/sfpi.c @@ -28,6 +28,14 @@ #include #include "platform_lib.h" +#define QSFP_PORT_MIN 0 +#define QSFP_PORT_MAX 63 +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define NUM_OF_SFP_PORT 64 static const int port_bus_index[NUM_OF_SFP_PORT] = { 37, 38, 39, 40, 42, 41, 44, 43, @@ -45,7 +53,17 @@ static const int port_bus_index[NUM_OF_SFP_PORT] = { #define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/19-0060/module_present_%d" #define MODULE_PRESENT_ALL_ATTR "/sys/bus/i2c/devices/19-0060/module_present_all" +#define MODULE_RESET_FORMAT "/sys/bus/i2c/devices/19-0060/module_reset_%d" + +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 +/*QSFP eeprom offset*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 +#define QSFP_EEPROM_OFFSET_LPMODE 0x5D + +/*QSFP Specific*/ +#define QSFP_LPMODE 0x3 /************************************************************ * * SFPI Entry Points @@ -182,6 +200,177 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) return onlp_i2c_writew(bus, devaddr, addr, value, ONLP_I2C_F_FORCE); } +int +onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) +{ + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int lpmode_value = 0; + + VALIDATE_QSFP(port); //only QSFP + + switch(control) + { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + /* write qsfp eeprom data of tx disable if qsfp present */ + if(present == 1) + { + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value&0xf; + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0){ + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else + { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + present = onlp_sfpi_is_present(port); + if (present == 1) { + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d):read LP mode value fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value){ + lpmode_value |= QSFP_LPMODE; + } else{ + lpmode_value &= ~QSFP_LPMODE; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE, lpmode_value) < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d):write eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } + else + { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + break; + } + + return rv; +} + +int +onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) +{ + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int lpmode_value = 0; + int tx_disable = 0; + VALIDATE_QSFP(port); //only QSFP + + switch(control) + { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) + { + tx_disable = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_disable < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + *value = tx_disable; + rv = ONLP_STATUS_OK; + } + + } + else + { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + case ONLP_SFP_CONTROL_RESET: + { + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + present = onlp_sfpi_is_present(port); + if (present == 1) { + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read eeprom fail\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + *value = ((lpmode_value & QSFP_LPMODE) == QSFP_LPMODE); + rv = ONLP_STATUS_OK; + } + + } + else + { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + + default: + rv = ONLP_STATUS_E_UNSUPPORTED; + } + + return rv; +} + int onlp_sfpi_denit(void) { diff --git a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c index 4dbd2ace8..7bb6232f4 100644 --- a/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as7926-40xfb/onlp/builds/x86_64_accton_as7926_40xfb/module/src/sfpi.c @@ -28,10 +28,33 @@ #include #include "platform_lib.h" -#define EEPROM_I2C_ADDR 0x50 -#define EEPROM_START_OFFSET 0x0 #define NUM_OF_SFP_PORT 55 +#define SFP_PORT_MIN 53 +#define SFP_PORT_MAX 54 +#define QSFP_PORT_MIN 0 +#define QSFP_PORT_MAX 52 +#define MIN_PORT QSFP_PORT_MIN +#define MAX_PORT SFP_PORT_MAX + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < SFP_PORT_MIN || _port > SFP_PORT_MAX) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + static const int port_bus_index[NUM_OF_SFP_PORT] = { 33, 34, 37, 38, 41, 42, 45, 46, 49, 50, 53, 54, 57, 58, 61, 62, 65, 66, 69, 70, @@ -52,6 +75,35 @@ static const int port_bus_index[NUM_OF_SFP_PORT] = { #define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_rx_los_%d" #define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_disable_%d" +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 + +/*QSFP identify offsets*/ +#define QSFP_EEPROM_OFFSET_IDENTIFIER 0x0 + +/* QSFP eeprom offsets*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 +#define QSFP_EEPROM_OFFSET_LPMODE 0x5D + +/* QSFP DD eeprom offsets*/ +#define QSFP_DD_EEPROM_OFFSET_BANK_SELECT 0x7E +#define QSFP_DD_EEPROM_OFFSET_PAGE_SELECT 0x7F +#define QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX 0x82 +#define QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW 0x1A +#define QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1 0x9B + +/*QSFP Specific*/ +#define QSFP_LPMODE 0x3 + +/* QSFP DD Specific*/ +#define QSFP_DD_PAGE_ADMIN_INFO 0x0 +#define QSFP_DD_PAGE_ADVERTISING 0x1 +#define QSFP_DD_PAGE_LANE_CTRL 0x10 +#define QSFP_DD_P01H_TX_DISABLE_SUPPORT 0x2 +#define QSFP_DD_LPMODE 0x10 + +/* OSFP IDENTIFIER Specific*/ +#define QSFP_DD_IDENTIFIER 0x18 /************************************************************ * @@ -202,25 +254,99 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv = ONLP_STATUS_OK; + int rv = ONLP_STATUS_E_INTERNAL; int addr = 62; int bus = 12; + int present = 0; + int lpmode_value = 0; + int identifier = 0; + int eeprom_control; + + VALIDATE_PORT(port); switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if (port >= 53 && port <= 54) { - if (onlp_file_write_int(0, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; + present = onlp_sfpi_is_present(port); + if (present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else{ + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /*QSFP DD*/ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADVERTISING) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + eeprom_control = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1); + if(eeprom_control < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read control from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (eeprom_control & QSFP_DD_P01H_TX_DISABLE_SUPPORT){ + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write bank to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } else { + AIM_LOG_ERROR("Setting tx disable to port(%d) is not supported\r\n", port); + rv = ONLP_STATUS_E_UNSUPPORTED; + } + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + } + } else { /* QSFP 28 or QSFP+ */ + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value&0xf; + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } } else { - rv = ONLP_STATUS_OK; + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } - } - else { - rv = ONLP_STATUS_E_UNSUPPORTED; - } break; } case ONLP_SFP_CONTROL_RESET: @@ -253,6 +379,70 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) break; } + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /*QSFP DD*/ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value) + lpmode_value |= QSFP_DD_LPMODE; + else + lpmode_value &= ~QSFP_DD_LPMODE; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW, lpmode_value) < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } else { /* QSFP 28 or QSFP+*/ + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value){ + lpmode_value |= QSFP_LPMODE; + } else{ + lpmode_value &= ~QSFP_LPMODE; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE, lpmode_value)< 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } + } + else { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } default: rv = ONLP_STATUS_E_UNSUPPORTED; break; @@ -264,21 +454,26 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv = ONLP_STATUS_OK; + int rv = ONLP_STATUS_E_INTERNAL; int addr = 62; int bus = 12; + int present = 0; + int lpmode_value = 0; + int identifier = 0; + int tx_dis = 0; + + VALIDATE_PORT(port); switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { - if (port >= 53 && port <= 54) { - if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; - } + VALIDATE_SFP(port); + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + rv = ONLP_STATUS_OK; } break; @@ -288,15 +483,73 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) rv = ONLP_STATUS_E_UNSUPPORTED; break; case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if (port >= 53 && port <= 54) { - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) {/* QSFP DD */ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write bank to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0 ){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX); + if(tx_dis < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): read TX disable from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + } + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + } + else { /* QSFP 28 or QSFP+ */ + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_dis < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): read TX disable from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + } } } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } @@ -329,7 +582,49 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) } break; } - + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /* QSFP DD */ + /* lpmode valid bit(bit4):Low power requset sw */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): set LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = !!(lpmode_value & QSFP_DD_LPMODE); + rv = ONLP_STATUS_OK; + } + } else { /* QSFP 28 or QSFP+ */ + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): set LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = ((lpmode_value & QSFP_LPMODE) == QSFP_LPMODE); + rv = ONLP_STATUS_OK; + } + } + } + else { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } default: rv = ONLP_STATUS_E_UNSUPPORTED; break; diff --git a/packages/platforms/accton/x86-64/as9716_32d/onlp/builds/x86_64_accton_as9716_32d/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9716_32d/onlp/builds/x86_64_accton_as9716_32d/module/src/sfpi.c index 85a77b4df..a065ab5a1 100755 --- a/packages/platforms/accton/x86-64/as9716_32d/onlp/builds/x86_64_accton_as9716_32d/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as9716_32d/onlp/builds/x86_64_accton_as9716_32d/module/src/sfpi.c @@ -29,6 +29,31 @@ #include "x86_64_accton_as9716_32d_int.h" #include "x86_64_accton_as9716_32d_log.h" +#define SFP_PORT_MIN 32 +#define SFP_PORT_MAX 33 +#define QSFP_PORT_MIN 0 +#define QSFP_PORT_MAX 31 +#define MIN_PORT QSFP_PORT_MIN +#define MAX_PORT SFP_PORT_MAX + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < SFP_PORT_MIN || _port > SFP_PORT_MAX) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" #define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_present_%d" #define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_rx_los_%d" @@ -36,6 +61,36 @@ #define MODULE_TXDISABLE_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_tx_disable_%d" #define MODULE_RESET_FORMAT "/sys/bus/i2c/devices/%d-00%d/module_reset_%d" +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 + +/*QSFP identify offsets*/ +#define QSFP_EEPROM_OFFSET_IDENTIFIER 0x0 + +/* QSFP eeprom offsets*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 +#define QSFP_EEPROM_OFFSET_LPMODE 0x5D + +/* QSFP DD eeprom offsets*/ +#define QSFP_DD_EEPROM_OFFSET_BANK_SELECT 0x7E +#define QSFP_DD_EEPROM_OFFSET_PAGE_SELECT 0x7F +#define QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1 0x9B +#define QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX 0x82 +#define QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW 0x1A + +/*QSFP Specific*/ +#define QSFP_LPMODE 0x3 + +/* QSFP DD Specific*/ +#define QSFP_DD_PAGE_ADMIN_INFO 0x0 +#define QSFP_DD_PAGE_ADVERTISING 0x1 +#define QSFP_DD_PAGE_LANE_CTRL 0x10 +#define QSFP_DD_P01H_TX_DISABLE_SUPPORT 0x2 +#define QSFP_DD_LPMODE 0x10 + +/* OSFP IDENTIFIER Specific*/ +#define QSFP_DD_IDENTIFIER 0x18 + int sfp_map_bus[] ={25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, @@ -88,8 +143,7 @@ onlp_sfpi_is_present(int port) int present; int bus, addr; - if(port <0 || port > 34) - return ONLP_STATUS_E_INTERNAL; + VALIDATE_PORT(port); if(port >=0 && port < 16) { @@ -150,8 +204,8 @@ onlp_sfpi_eeprom_read(int port, uint8_t data[256]) * Return OK if eeprom is read */ int size = 0; - if(port <0 || port > 34) - return ONLP_STATUS_E_INTERNAL; + VALIDATE_PORT(port); + memset(data, 0, 256); if(onlp_file_read(data, 256, &size, PORT_EEPROM_FORMAT, onlp_sfpi_map_bus_index(port)) != ONLP_STATUS_OK) { @@ -227,51 +281,188 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; int addr=0; int bus=0; + int present = 0; + int lpmode_value = 0; + int identifier = 0; + int eeprom_control; + VALIDATE_PORT(port); + + if(port < 16){ + addr=61; + bus=20; + } + else{ + addr=62; + bus=21; + } switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if(port==32 || port==33) { - addr=62; - bus=21; - if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; + present = onlp_sfpi_is_present(port); + if (present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } - else { - rv = ONLP_STATUS_OK; + else { //QSFP + + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /*QSFP DD*/ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADVERTISING) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + eeprom_control = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1); + if(eeprom_control < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read control from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (eeprom_control & QSFP_DD_P01H_TX_DISABLE_SUPPORT){ + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write bank to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } else { + AIM_LOG_ERROR("Setting tx disable to port(%d) is not supported\r\n", port); + rv = ONLP_STATUS_E_UNSUPPORTED; + } + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + } + } else { /* QSFP 28 or QSFP+ */ + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value&0xf; + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } } - } + } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + AIM_LOG_ERROR("Unable to write tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } case ONLP_SFP_CONTROL_RESET: { - if(port >=0 && port<32) { - if(port < 16){ - addr=61; - bus=20; - } - else{ - addr=62; - bus=21; - } - if (onlp_file_write_int(value, MODULE_RESET_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set reset status to port(%d)\r\n", port); + VALIDATE_QSFP(port); + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read identifier from eeprom fail\r\n", + port); rv = ONLP_STATUS_E_INTERNAL; } - else { - rv = ONLP_STATUS_OK; + else if (identifier == QSFP_DD_IDENTIFIER) { /*QSFP DD*/ + + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value) + lpmode_value |= QSFP_DD_LPMODE; + else + lpmode_value &= ~QSFP_DD_LPMODE; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW, lpmode_value) < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + + + } else { /* QSFP 28 or QSFP+*/ + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value){ + lpmode_value |= QSFP_LPMODE; + } else{ + lpmode_value &= ~QSFP_LPMODE; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE, lpmode_value)< 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } @@ -287,63 +478,181 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv; - int addr = 62; - int bus = 21; - + int rv = ONLP_STATUS_E_INTERNAL; + int addr = 0; + int bus = 0; + int present = 0; + int lpmode_value = 0; + int identifier = 0; + int tx_dis = 0; + + VALIDATE_PORT(port); + + if(port < 16){ + addr=61; + bus=20; + } + else{ + addr=62; + bus=21; + } + switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { - if(port==32 || port==33) { - if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; - } - else { - rv = ONLP_STATUS_OK; - } + VALIDATE_SFP(port); + if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + rv = ONLP_STATUS_OK; } break; } case ONLP_SFP_CONTROL_TX_FAULT: { - if(port==32 || port==33) { - if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; + VALIDATE_SFP(port); + if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: + { + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } } else { - rv = ONLP_STATUS_OK; + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) {/* QSFP DD */ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write bank to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0 ){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX); + if(tx_dis < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): read TX disable from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + } + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + } + else { /* QSFP 28 or QSFP+ */ + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_dis < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): read TX disable from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + } } } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } - case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_RESET: { - if(port==32 || port==33) { - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + VALIDATE_QSFP(port); + if (onlp_file_read_int(value, MODULE_RESET_FORMAT, bus, addr, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to get reset status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + break; + } + + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read identifier from eeprom fail\r\n", + port); rv = ONLP_STATUS_E_INTERNAL; } - else { - rv = ONLP_STATUS_OK; + else if (identifier == QSFP_DD_IDENTIFIER) { /* QSFP DD */ + /* lpmode valid bit(bit4):Low power requset sw */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = !!(lpmode_value & QSFP_DD_LPMODE); + rv = ONLP_STATUS_OK; + } + } else { /* QSFP 28 or QSFP+ */ + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = ((lpmode_value & QSFP_LPMODE) == QSFP_LPMODE); + rv = ONLP_STATUS_OK; + } } } else { - rv = ONLP_STATUS_E_UNSUPPORTED; + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } - default: rv = ONLP_STATUS_E_UNSUPPORTED; } diff --git a/packages/platforms/accton/x86-64/as9737-32db/onlp/builds/x86_64_accton_as9737_32db/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9737-32db/onlp/builds/x86_64_accton_as9737_32db/module/src/sfpi.c index 9f38cc975..998f12020 100644 --- a/packages/platforms/accton/x86-64/as9737-32db/onlp/builds/x86_64_accton_as9737_32db/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as9737-32db/onlp/builds/x86_64_accton_as9737_32db/module/src/sfpi.c @@ -29,18 +29,31 @@ #include "x86_64_accton_as9737_32db_int.h" #include "x86_64_accton_as9737_32db_log.h" +#define SFP_PORT_MIN 33 +#define SFP_PORT_MAX 34 +#define QSFP_PORT_MIN 1 +#define QSFP_PORT_MAX 32 +#define MIN_PORT QSFP_PORT_MIN +#define MAX_PORT SFP_PORT_MAX + #define VALIDATE_SFP(_port) \ do { \ - if (_port < 33 || _port > 34) \ + if (_port < SFP_PORT_MIN || _port > SFP_PORT_MAX) \ return ONLP_STATUS_E_UNSUPPORTED; \ } while(0) #define VALIDATE_QSFP(_port) \ do { \ - if (_port < 1 || _port > 32 ) \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ return ONLP_STATUS_E_UNSUPPORTED; \ } while(0) +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define MODULE_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" #define MODULE_PRESENT_CPLD2_FORMAT "/sys/bus/i2c/devices/36-0061/module_present_%d" #define MODULE_PRESENT_CPLD3_FORMAT "/sys/bus/i2c/devices/37-0062/module_present_%d" @@ -61,6 +74,31 @@ static const int port_bus_index[NUM_OF_SFP_PORT] = { #define PORT_BUS_INDEX(port) (port_bus_index[port-1]) +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 + +/*QSFP identify offsets*/ +#define QSFP_EEPROM_OFFSET_IDENTIFIER 0x0 + +/* QSFP eeprom offsets*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 + +/* QSFP DD eeprom offsets*/ +#define QSFP_DD_EEPROM_OFFSET_BANK_SELECT 0x7E +#define QSFP_DD_EEPROM_OFFSET_PAGE_SELECT 0x7F +#define QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1 0x9B +#define QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX 0x82 + +/* QSFP DD Specific*/ +#define QSFP_DD_PAGE_ADMIN_INFO 0x0 +#define QSFP_DD_PAGE_ADVERTISING 0x1 +#define QSFP_DD_PAGE_LANE_CTRL 0x10 +#define QSFP_DD_P01H_TX_DISABLE_SUPPORT 0x2 + +/*QSFP Specific*/ +#define QSFP_DD_IDENTIFIER 0x18 + + /************************************************************ * * SFPI Entry Points @@ -211,15 +249,112 @@ int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { char *path = NULL; + int present = 0; + int identifier = 0; + int eeprom_control; - switch(control) { - case ONLP_SFP_CONTROL_TX_DISABLE: { - VALIDATE_SFP(port); + VALIDATE_PORT(port); - if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, port) - < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", - port); + switch(control) { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, port) + < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + } + else { //QSFP + + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read identifier from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /* QSFP DD */ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADVERTISING) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + + eeprom_control = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1); + if(eeprom_control < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read control from eeprom fail\r\n", port); + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + } + + return ONLP_STATUS_E_INTERNAL; + } + if (eeprom_control & QSFP_DD_P01H_TX_DISABLE_SUPPORT){ + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write bank to eeprom fail\r\n", port); + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + return ONLP_STATUS_E_INTERNAL; + } + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + return ONLP_STATUS_E_INTERNAL; + } + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", port); + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + return ONLP_STATUS_E_INTERNAL; + } + } else { + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + AIM_LOG_ERROR("Setting tx disable to port(%d) is not supported\r\n", port); + return ONLP_STATUS_E_UNSUPPORTED; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + } + else { /* QSFP 28 or QSFP+ */ + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value&0xf; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + + } + } + } + else { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -246,7 +381,7 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) : MODULE_LPMODE_CPLD3_FORMAT; if (onlp_file_write_int(value, path, port) < 0) { - AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", + AIM_LOG_ERROR("Unable to write LP mode to port(%d)\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -254,16 +389,21 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) return ONLP_STATUS_OK; } default: - break; + return ONLP_STATUS_E_UNSUPPORTED; } - return ONLP_STATUS_E_UNSUPPORTED; + return ONLP_STATUS_E_INTERNAL; } int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { char *path = NULL; + int present = 0; + int identifier = 0; + int tx_disable; + + VALIDATE_PORT(port); switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { @@ -291,12 +431,71 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) return ONLP_STATUS_OK; } - case ONLP_SFP_CONTROL_TX_DISABLE: { - VALIDATE_SFP(port); - - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", - port); + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { + + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + } + else { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : read identifier from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /* QSFP DD */ + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write bank to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + + tx_disable = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX); + if(tx_disable < 0){ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", + port); + } + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : read TX disable from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + *value = tx_disable; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + } + else { /* QSFP 28 or QSFP+ */ + tx_disable = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_disable < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : read TX disable from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + *value = tx_disable; + } + } + } + else { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -323,7 +522,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) : MODULE_LPMODE_CPLD3_FORMAT; if (onlp_file_read_int(value, path, port) < 0) { - AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", + AIM_LOG_ERROR("Unable to read LP mode status from port(%d)\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -331,10 +530,10 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) return ONLP_STATUS_OK; } default: - break; + return ONLP_STATUS_E_UNSUPPORTED; } - return ONLP_STATUS_E_UNSUPPORTED; + return ONLP_STATUS_E_INTERNAL; } int diff --git a/packages/platforms/accton/x86-64/as9817-64/src/x86_64_accton_as9817_64/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9817-64/src/x86_64_accton_as9817_64/module/src/sfpi.c index 219021199..c8f0dddbe 100644 --- a/packages/platforms/accton/x86-64/as9817-64/src/x86_64_accton_as9817_64/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as9817-64/src/x86_64_accton_as9817_64/module/src/sfpi.c @@ -29,15 +29,28 @@ #include "x86_64_accton_as9817_64_int.h" #include "x86_64_accton_as9817_64_log.h" +#define SFP_PORT_MIN 65 +#define SFP_PORT_MAX 66 +#define QSFP_PORT_MIN 1 +#define QSFP_PORT_MAX 64 +#define MIN_PORT QSFP_PORT_MIN +#define MAX_PORT SFP_PORT_MAX + #define VALIDATE_SFP(_port) \ do { \ - if (_port < 65 || _port > 66) \ + if (_port < SFP_PORT_MIN || _port > SFP_PORT_MAX) \ return ONLP_STATUS_E_UNSUPPORTED; \ } while(0) #define VALIDATE_QSFP(_port) \ do { \ - if (_port < 1 || _port > 64 ) \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ return ONLP_STATUS_E_UNSUPPORTED; \ } while(0) @@ -60,6 +73,35 @@ static const int port_bus_index[NUM_OF_SFP_PORT] = { #define PORT_BUS_INDEX(port) (port_bus_index[port-1]) +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 + +/*QSFP identify offsets*/ +#define QSFP_EEPROM_OFFSET_IDENTIFIER 0x0 + +/* QSFP eeprom offsets*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 + +/* QSFP DD eeprom offsets*/ +#define QSFP_DD_EEPROM_OFFSET_BANK_SELECT 0x7E +#define QSFP_DD_EEPROM_OFFSET_PAGE_SELECT 0x7F +#define QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX 0x82 +#define QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1 0x9B + +/* QSFP DD Specific*/ +#define QSFP_DD_PAGE_ADMIN_INFO 0x0 +#define QSFP_DD_PAGE_ADVERTISING 0x1 +#define QSFP_DD_PAGE_LANE_CTRL 0x10 +#define QSFP_DD_P01H_TX_DISABLE_SUPPORT 0x2 + + +/* OSFP IDENTIFIER Specific*/ +#define QSFP_28_IDENTIFIER 0x11 +#define QSFP_PLUS_IDENTIFIER 0x0d +#define QSFP_DD_IDENTIFIER 0x18 +#define OSFP_IDENTIFIER 0x19 + + /************************************************************ * * SFPI Entry Points @@ -190,47 +232,158 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - switch(control) { - case ONLP_SFP_CONTROL_TX_DISABLE: { - VALIDATE_SFP(port); + int present = 0; + int identifier = 0; + int eeprom_control; - if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); - return ONLP_STATUS_E_INTERNAL; + VALIDATE_PORT(port); + + switch(control) { + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { + present = onlp_sfpi_is_present(port); + if (present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + } + else { //QSFP + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read identifier from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + else { + switch(identifier) { + case QSFP_DD_IDENTIFIER: //for as9817-64D + case OSFP_IDENTIFIER: { //for as9817-64O + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADVERTISING) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + eeprom_control = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1); + if(eeprom_control < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read control from eeprom fail\r\n", port); + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + } + + return ONLP_STATUS_E_INTERNAL; + } + if (eeprom_control & QSFP_DD_P01H_TX_DISABLE_SUPPORT){ + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write bank to eeprom fail\r\n", port); + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + return ONLP_STATUS_E_INTERNAL; + } + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + return ONLP_STATUS_E_INTERNAL; + } + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", port); + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + return ONLP_STATUS_E_INTERNAL; + } + } else { + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + } + + AIM_LOG_ERROR("Setting tx disable to port(%d) is not supported\r\n", port); + return ONLP_STATUS_E_UNSUPPORTED; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + break; + } + case QSFP_28_IDENTIFIER: //for as9817-64D + case QSFP_PLUS_IDENTIFIER:{ //for as9817-64D + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value&0xf; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + break; + } + default: + return ONLP_STATUS_E_UNSUPPORTED; + + } + } + } + return ONLP_STATUS_OK; + } + else { + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + } + case ONLP_SFP_CONTROL_RESET_STATE: { + VALIDATE_QSFP(port); - return ONLP_STATUS_OK; - } - case ONLP_SFP_CONTROL_RESET_STATE: { - VALIDATE_QSFP(port); + if (onlp_file_write_int(value, MODULE_RESET_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } - if (onlp_file_write_int(value, MODULE_RESET_FORMAT, port) < 0) { - AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); - return ONLP_STATUS_E_INTERNAL; + return ONLP_STATUS_OK; } + case ONLP_SFP_CONTROL_LP_MODE: { + VALIDATE_QSFP(port); - return ONLP_STATUS_OK; - } - case ONLP_SFP_CONTROL_LP_MODE: { - VALIDATE_QSFP(port); + if (onlp_file_write_int(value, MODULE_LPMODE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } - if (onlp_file_write_int(value, MODULE_LPMODE_FORMAT, port) < 0) { - AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); - return ONLP_STATUS_E_INTERNAL; + return ONLP_STATUS_OK; } - - return ONLP_STATUS_OK; - } - default: - break; + default: + return ONLP_STATUS_E_UNSUPPORTED; } - return ONLP_STATUS_E_UNSUPPORTED; + return ONLP_STATUS_E_INTERNAL; } int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { + int present = 0; + int identifier = 0; + int tx_disable; + + VALIDATE_PORT(port); + switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { *value = 0; @@ -255,11 +408,82 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) return ONLP_STATUS_OK; } - case ONLP_SFP_CONTROL_TX_DISABLE: { - VALIDATE_SFP(port); + case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { + + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + return ONLP_STATUS_E_INTERNAL; + } + } + else { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : read identifier from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + else { + switch(identifier) { + case QSFP_DD_IDENTIFIER: //for as9817-64D + case OSFP_IDENTIFIER: { //for as9817-64O + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write bank to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + + tx_disable = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX); + if(tx_disable < 0){ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", + port); + } + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : read TX disable from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + *value = tx_disable; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : write page to eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + break; + } + case QSFP_28_IDENTIFIER: //for as9817-64D + case QSFP_PLUS_IDENTIFIER:{ //for as9817-64D + tx_disable = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_disable < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d) : read TX disable from eeprom fail\r\n", + port); + return ONLP_STATUS_E_INTERNAL; + } + *value = tx_disable; + break; + } + default: + return ONLP_STATUS_E_UNSUPPORTED; + + } + } - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, port) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + } + } + else { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); return ONLP_STATUS_E_INTERNAL; } @@ -279,17 +503,17 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) VALIDATE_QSFP(port); if (onlp_file_read_int(value, MODULE_LPMODE_FORMAT, port) < 0) { - AIM_LOG_ERROR("Unable to read reset status from port(%d)\r\n", port); + AIM_LOG_ERROR("Unable to read LP mode status from port(%d)\r\n", port); return ONLP_STATUS_E_INTERNAL; } return ONLP_STATUS_OK; } default: - break; + return ONLP_STATUS_E_UNSUPPORTED; } - return ONLP_STATUS_E_UNSUPPORTED; + return ONLP_STATUS_E_INTERNAL; } int diff --git a/packages/platforms/accton/x86-64/as9926-24d/onlp/builds/x86_64_accton_as9926_24d/module/src/sfpi.c b/packages/platforms/accton/x86-64/as9926-24d/onlp/builds/x86_64_accton_as9926_24d/module/src/sfpi.c index c5416b901..883157ad8 100644 --- a/packages/platforms/accton/x86-64/as9926-24d/onlp/builds/x86_64_accton_as9926_24d/module/src/sfpi.c +++ b/packages/platforms/accton/x86-64/as9926-24d/onlp/builds/x86_64_accton_as9926_24d/module/src/sfpi.c @@ -29,6 +29,31 @@ #include "x86_64_accton_as9926_24d_int.h" #include "x86_64_accton_as9926_24d_log.h" +#define SFP_PORT_MIN 24 +#define SFP_PORT_MAX 25 +#define QSFP_PORT_MIN 0 +#define QSFP_PORT_MAX 23 +#define MIN_PORT QSFP_PORT_MIN +#define MAX_PORT SFP_PORT_MAX + +#define VALIDATE_SFP(_port) \ + do { \ + if (_port < SFP_PORT_MIN || _port > SFP_PORT_MAX) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_QSFP(_port) \ + do { \ + if (_port < QSFP_PORT_MIN || _port > QSFP_PORT_MAX ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + +#define VALIDATE_PORT(_port) \ + do { \ + if (_port < MIN_PORT || _port > MAX_PORT ) \ + return ONLP_STATUS_E_UNSUPPORTED; \ + } while(0) + #define PORT_BUS_INDEX(port) (port+25) #define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom" @@ -40,6 +65,36 @@ #define MODULE_PRESENT_ALL_ATTR "/sys/bus/i2c/devices/%d-00%d/module_present_all" #define MODULE_RXLOS_ALL_ATTR_CPLD3 "/sys/bus/i2c/devices/21-0062/module_rx_los_all" +/* QSFP device address of eeprom */ +#define PORT_EEPROM_DEVADDR 0x50 + +/*QSFP identify offsets*/ +#define QSFP_EEPROM_OFFSET_IDENTIFIER 0x0 + +/* QSFP eeprom offsets*/ +#define QSFP_EEPROM_OFFSET_TXDIS 0x56 +#define QSFP_EEPROM_OFFSET_LPMODE 0x5D + +/* QSFP DD eeprom offsets*/ +#define QSFP_DD_EEPROM_OFFSET_BANK_SELECT 0x7E +#define QSFP_DD_EEPROM_OFFSET_PAGE_SELECT 0x7F +#define QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1 0x9B +#define QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX 0x82 +#define QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW 0x1A + +/*QSFP Specific*/ +#define QSFP_LPMODE 0x3 + +/* QSFP DD Specific*/ +#define QSFP_DD_PAGE_ADMIN_INFO 0x0 +#define QSFP_DD_PAGE_ADVERTISING 0x1 +#define QSFP_DD_PAGE_LANE_CTRL 0x10 +#define QSFP_DD_P01H_TX_DISABLE_SUPPORT 0x2 +#define QSFP_DD_LPMODE 0x10 + +/* OSFP IDENTIFIER Specific*/ +#define QSFP_DD_IDENTIFIER 0x18 + /************************************************************ * * SFPI Entry Points @@ -264,36 +319,111 @@ onlp_sfpi_dev_writew(int port, uint8_t devaddr, uint8_t addr, uint16_t value) int onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int lpmode_value = 0; + int identifier = 0; + int eeprom_control; + + VALIDATE_PORT(port); switch(control) { case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if (port < 24 || port >= 26) { - return ONLP_STATUS_E_UNSUPPORTED; - } - - if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, 21, 62, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; + present = onlp_sfpi_is_present(port); + if (present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { //SFP + + if (onlp_file_write_int(value, MODULE_TXDISABLE_FORMAT, 21, 62, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else { //QSFP + + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /*QSFP DD*/ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADVERTISING) <0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + eeprom_control = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P01H_OFFSET_CONTROL_1); + if(eeprom_control < 0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): read control from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (eeprom_control & QSFP_DD_P01H_TX_DISABLE_SUPPORT){ + if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write bank to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX, value) < 0) { + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } else { + AIM_LOG_ERROR("Setting tx disable to port(%d) is not supported\r\n", port); + rv = ONLP_STATUS_E_UNSUPPORTED; + } + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) <0){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + } + } else { /* QSFP 28 or QSFP+ */ + /* txdis valid bit(bit0-bit3), xxxx 1111 */ + value = value&0xf; + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS, value) < 0 ){ + AIM_LOG_ERROR("Unable to write tx_disable status to port(%d): write TX disable to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + } } else { - rv = ONLP_STATUS_OK; + AIM_LOG_ERROR("Unable to write tx_disabled status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } case ONLP_SFP_CONTROL_RESET: { - if (port < 0 || port >= 24) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_QSFP(port); int addr = (port < 16) ? 61 : 62; int bus = (port < 16) ? 20 : 21; if (onlp_file_write_int(value, MODULE_RESET_FORMAT, bus, addr, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to set reset status to port(%d)\r\n", port); + AIM_LOG_ERROR("Unable to write reset status to port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; } else { @@ -303,6 +433,75 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) break; } + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /*QSFP DD*/ + + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value) + lpmode_value |= QSFP_DD_LPMODE; + else + lpmode_value &= ~QSFP_DD_LPMODE; + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW, lpmode_value) < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + + + } else { /* QSFP 28 or QSFP+*/ + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + if(value){ + lpmode_value |= QSFP_LPMODE; + } else{ + lpmode_value &= ~QSFP_LPMODE; + } + + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE, lpmode_value)< 0){ + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): write LP mode value to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + + } + } + else { + AIM_LOG_ERROR("Unable to write LP mode status to port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + default: rv = ONLP_STATUS_E_UNSUPPORTED; break; @@ -314,16 +513,19 @@ onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value) int onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) { - int rv; + int rv = ONLP_STATUS_E_INTERNAL; + int present = 0; + int lpmode_value = 0; + int identifier = 0; + int tx_dis = 0; - if (port < 24 || port >= 26) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_PORT(port); switch(control) { case ONLP_SFP_CONTROL_RX_LOS: { + VALIDATE_SFP(port); if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, 21, 62, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read rx_loss status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; @@ -336,6 +538,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) case ONLP_SFP_CONTROL_TX_FAULT: { + VALIDATE_SFP(port); if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, 21, 62, (port+1)) < 0) { AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port); rv = ONLP_STATUS_E_INTERNAL; @@ -347,22 +550,80 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) } case ONLP_SFP_CONTROL_TX_DISABLE: + case ONLP_SFP_CONTROL_TX_DISABLE_CHANNEL: { - if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, 21, 62, (port+1)) < 0) { - AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); - rv = ONLP_STATUS_E_INTERNAL; + present = onlp_sfpi_is_present(port); + /* read qsfp eeprom offset of tx disable if qsfp on the port */ + if(present == 1) { + if (port >= SFP_PORT_MIN && port <= SFP_PORT_MAX) { + if (onlp_file_read_int(value, MODULE_TXDISABLE_FORMAT, 21, 62, (port+1)) < 0) { + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + rv = ONLP_STATUS_OK; + } + } + else { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) {/* QSFP DD */ + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_BANK_SELECT, 0) < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write bank to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_LANE_CTRL) < 0 ){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_P10H_OFFSET_OUTPUT_DISABLE_TX); + if(tx_dis < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): read TX disable from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else{ + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + } + if(onlp_sfpi_dev_writeb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_PAGE_SELECT, QSFP_DD_PAGE_ADMIN_INFO) < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): write page to eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + } + else { /* QSFP 28 or QSFP+ */ + tx_dis = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_TXDIS); + if(tx_dis < 0){ + AIM_LOG_ERROR("Unable to read tx_disable status from port(%d): read TX disable from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = tx_dis; + rv = ONLP_STATUS_OK; + } + } + } } else { - rv = ONLP_STATUS_OK; + AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; } break; } case ONLP_SFP_CONTROL_RESET: { - if (port < 0 || port >= 24) { - return ONLP_STATUS_E_UNSUPPORTED; - } + VALIDATE_QSFP(port); int addr = (port < 16) ? 61 : 62; int bus = (port < 16) ? 20 : 21; @@ -378,6 +639,50 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value) break; } + case ONLP_SFP_CONTROL_LP_MODE: + { + VALIDATE_QSFP(port); + present = onlp_sfpi_is_present(port); + if (present == 1) { + identifier = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_IDENTIFIER); + if(identifier < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read identifier from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else if (identifier == QSFP_DD_IDENTIFIER) { /* QSFP DD */ + /* lpmode valid bit(bit4):Low power requset sw */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_DD_EEPROM_OFFSET_LOWPWR_REQUEST_SW); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = !!(lpmode_value & QSFP_DD_LPMODE); + rv = ONLP_STATUS_OK; + } + } else { /* QSFP 28 or QSFP+ */ + /* lpmode valid bit(bit0):set LP/txdis mode bit(bit1):set low/high power mode */ + lpmode_value = onlp_sfpi_dev_readb(port, PORT_EEPROM_DEVADDR, QSFP_EEPROM_OFFSET_LPMODE); + if(lpmode_value < 0){ + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): read LP mode value from eeprom fail\r\n", + port); + rv = ONLP_STATUS_E_INTERNAL; + } + else { + *value = ((lpmode_value & QSFP_LPMODE) == QSFP_LPMODE); + rv = ONLP_STATUS_OK; + } + } + } + else { + AIM_LOG_ERROR("Unable to read LP mode status from port(%d): module is not present\r\n", port); + rv = ONLP_STATUS_E_INTERNAL; + } + break; + } + default: rv = ONLP_STATUS_E_UNSUPPORTED; }