From 0a2c7a5fcc10c9f65c9fb1fe1968e13b07a325ea Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Thu, 4 May 2017 17:40:50 +0800 Subject: [PATCH 1/5] [as7712-32x] Upgrade sfp driver to make sfp_eeprom writable --- .../builds/x86-64-accton-as7712-32x-sfp.c | 1358 ++++++++++++++--- 1 file changed, 1117 insertions(+), 241 deletions(-) diff --git a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/modules/builds/x86-64-accton-as7712-32x-sfp.c b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/modules/builds/x86-64-accton-as7712-32x-sfp.c index 5953ae6d..202d85a0 100644 --- a/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/modules/builds/x86-64-accton-as7712-32x-sfp.c +++ b/packages/platforms/accton/x86-64/x86-64-accton-as7712-32x/modules/builds/x86-64-accton-as7712-32x-sfp.c @@ -1,8 +1,7 @@ /* - * An hwmon driver for accton as7712_32x sfp + * SFP driver for accton as7712 sfp * - * Copyright (C) 2014 Accton Technology Corporation. - * Brandon Chuang + * Copyright (C) Brandon Chuang * * Based on ad7414.c * Copyright 2006 Stefan Roese , DENX Software Engineering @@ -31,326 +30,1203 @@ #include #include #include +#include -#define BIT_INDEX(i) (1UL << (i)) +#define DRIVER_NAME "as7712_32x_sfp" /* Platform dependent */ +#define DEBUG_MODE 0 -/* Addresses scanned - */ -static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; +#if (DEBUG_MODE == 1) + #define DEBUG_PRINT(fmt, args...) \ + printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) +#endif -/* Each client has this additional data - */ -struct as7712_32x_sfp_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - int port; /* Front port index */ - char eeprom[256]; /* eeprom data */ - u32 is_present; /* present status */ -}; +#define NUM_OF_SFP_PORT 32 +#define EEPROM_NAME "sfp_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ +#define BIT_INDEX(i) (1ULL << (i)) +#define USE_I2C_BLOCK_READ 1 /* Platform dependent */ +#define I2C_RW_RETRY_COUNT 3 +#define I2C_RW_RETRY_INTERVAL 100 /* ms */ + +#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) +#define SFP_EEPROM_A2_I2C_ADDR (0xA2 >> 1) + +#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 +#define SFF8024_DEVICE_ID_SFP 0x3 +#define SFF8024_DEVICE_ID_QSFP 0xC +#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD +#define SFF8024_DEVICE_ID_QSFP28 0x11 + +#define SFF8472_DIAG_MON_TYPE_ADDR 92 +#define SFF8472_DIAG_MON_TYPE_DDM_MASK 0x40 +#define SFF8472_10G_ETH_COMPLIANCE_ADDR 0x3 +#define SFF8472_10G_BASE_MASK 0xF0 + +#define SFF8436_RX_LOS_ADDR 3 +#define SFF8436_TX_FAULT_ADDR 4 +#define SFF8436_TX_DISABLE_ADDR 86 -static struct as7712_32x_sfp_data *as7712_32x_sfp_update_device(struct device *dev); static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); -static ssize_t show_present(struct device *dev, struct device_attribute *da,char *buf); -static ssize_t show_eeprom(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_port_type(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count); +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);; +static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); +static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg); extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); -enum as7712_32x_sfp_sysfs_attributes { - SFP_PORT_NUMBER, - SFP_IS_PRESENT, - SFP_IS_PRESENT_ALL, - SFP_EEPROM +enum sfp_sysfs_attributes { + PRESENT, + PRESENT_ALL, + PORT_NUMBER, + PORT_TYPE, + DDM_IMPLEMENTED, + TX_FAULT, + TX_FAULT1, + TX_FAULT2, + TX_FAULT3, + TX_FAULT4, + TX_DISABLE, + TX_DISABLE1, + TX_DISABLE2, + TX_DISABLE3, + TX_DISABLE4, + RX_LOS, + RX_LOS1, + RX_LOS2, + RX_LOS3, + RX_LOS4, + RX_LOS_ALL }; -/* sysfs attributes for hwmon - */ -static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, SFP_PORT_NUMBER); -static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, SFP_IS_PRESENT); -static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, SFP_IS_PRESENT_ALL); -static SENSOR_DEVICE_ATTR(sfp_eeprom, S_IRUGO, show_eeprom, NULL, SFP_EEPROM); +/* SFP/QSFP common attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); +static SENSOR_DEVICE_ATTR(sfp_port_type, S_IRUGO, show_port_type, NULL, PORT_TYPE); +static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); +static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); +static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS); +static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, sfp_show_tx_rx_status, sfp_set_tx_disable, TX_DISABLE); +static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, sfp_show_tx_rx_status, NULL, TX_FAULT); -static struct attribute *as7712_32x_sfp_attributes[] = { +/* QSFP attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); +static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); +static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); +static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); +static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); +static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); +static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); +static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); +static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); +static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); +static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); +static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); +static struct attribute *qsfp_attributes[] = { &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_port_type.dev_attr.attr, &sensor_dev_attr_sfp_is_present.dev_attr.attr, &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, - &sensor_dev_attr_sfp_eeprom.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, NULL }; +/* SFP msa attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_ddm_implemented, S_IRUGO, sfp_show_ddm_implemented, NULL, DDM_IMPLEMENTED); +static SENSOR_DEVICE_ATTR(sfp_rx_los_all, S_IRUGO, sfp_show_tx_rx_status, NULL, RX_LOS_ALL); +static struct attribute *sfp_msa_attributes[] = { + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_port_type.dev_attr.attr, + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_ddm_implemented.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los_all.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + NULL +}; + +/* SFP ddm attributes for sysfs */ +static struct attribute *sfp_ddm_attributes[] = { + NULL +}; + +/* Platform dependent +++ */ +#define CPLD_PORT_TO_FRONT_PORT(port) (port+1) + +enum port_numbers { +as7712_32x_sfp1, as7712_32x_sfp2, as7712_32x_sfp3, as7712_32x_sfp4, as7712_32x_sfp5, as7712_32x_sfp6, as7712_32x_sfp7, as7712_32x_sfp8, +as7712_32x_sfp9, as7712_32x_sfp10, as7712_32x_sfp11, as7712_32x_sfp12, as7712_32x_sfp13, as7712_32x_sfp14, as7712_32x_sfp15, as7712_32x_sfp16, +as7712_32x_sfp17, as7712_32x_sfp18, as7712_32x_sfp19, as7712_32x_sfp20, as7712_32x_sfp21, as7712_32x_sfp22, as7712_32x_sfp23, as7712_32x_sfp24, +as7712_32x_sfp25, as7712_32x_sfp26, as7712_32x_sfp27, as7712_32x_sfp28, as7712_32x_sfp29, as7712_32x_sfp30, as7712_32x_sfp31, as7712_32x_sfp32 +}; + +#define I2C_DEV_ID(x) { #x, x} + +static const struct i2c_device_id sfp_device_id[] = { +I2C_DEV_ID(as7712_32x_sfp1), +I2C_DEV_ID(as7712_32x_sfp2), +I2C_DEV_ID(as7712_32x_sfp3), +I2C_DEV_ID(as7712_32x_sfp4), +I2C_DEV_ID(as7712_32x_sfp5), +I2C_DEV_ID(as7712_32x_sfp6), +I2C_DEV_ID(as7712_32x_sfp7), +I2C_DEV_ID(as7712_32x_sfp8), +I2C_DEV_ID(as7712_32x_sfp9), +I2C_DEV_ID(as7712_32x_sfp10), +I2C_DEV_ID(as7712_32x_sfp11), +I2C_DEV_ID(as7712_32x_sfp12), +I2C_DEV_ID(as7712_32x_sfp13), +I2C_DEV_ID(as7712_32x_sfp14), +I2C_DEV_ID(as7712_32x_sfp15), +I2C_DEV_ID(as7712_32x_sfp16), +I2C_DEV_ID(as7712_32x_sfp17), +I2C_DEV_ID(as7712_32x_sfp18), +I2C_DEV_ID(as7712_32x_sfp19), +I2C_DEV_ID(as7712_32x_sfp20), +I2C_DEV_ID(as7712_32x_sfp21), +I2C_DEV_ID(as7712_32x_sfp22), +I2C_DEV_ID(as7712_32x_sfp23), +I2C_DEV_ID(as7712_32x_sfp24), +I2C_DEV_ID(as7712_32x_sfp25), +I2C_DEV_ID(as7712_32x_sfp26), +I2C_DEV_ID(as7712_32x_sfp27), +I2C_DEV_ID(as7712_32x_sfp28), +I2C_DEV_ID(as7712_32x_sfp29), +I2C_DEV_ID(as7712_32x_sfp30), +I2C_DEV_ID(as7712_32x_sfp31), +I2C_DEV_ID(as7712_32x_sfp32), +{ /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, sfp_device_id); +/* Platform dependent --- */ + +/* + * list of valid port types + * note OOM_PORT_TYPE_NOT_PRESENT to indicate no + * module is present in this port + */ +typedef enum oom_driver_port_type_e { + OOM_DRIVER_PORT_TYPE_INVALID, + OOM_DRIVER_PORT_TYPE_NOT_PRESENT, + OOM_DRIVER_PORT_TYPE_SFP, + OOM_DRIVER_PORT_TYPE_SFP_PLUS, + OOM_DRIVER_PORT_TYPE_QSFP, + OOM_DRIVER_PORT_TYPE_QSFP_PLUS, + OOM_DRIVER_PORT_TYPE_QSFP28 +} oom_driver_port_type_t; + +enum driver_type_e { + DRIVER_TYPE_SFP_MSA, + DRIVER_TYPE_SFP_DDM, + DRIVER_TYPE_QSFP +}; + +/* Each client has this additional data + */ +struct eeprom_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + struct bin_attribute bin; /* eeprom data */ +}; + +struct sfp_msa_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u64 status[6]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss + 3 => device id + 4 => 10G Ethernet Compliance Codes + to distinguish SFP or SFP+ + 5 => DIAGNOSTIC MONITORING TYPE */ + struct eeprom_data eeprom; +}; + +struct sfp_ddm_data { + struct eeprom_data eeprom; +}; + +struct qsfp_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 status[3]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss */ + + u8 device_id; + struct eeprom_data eeprom; +}; + +struct sfp_port_data { + struct mutex update_lock; + enum driver_type_e driver_type; + int port; /* CPLD port index */ + oom_driver_port_type_t port_type; + u64 present; /* present status, bit0:port0, bit1:port1 and so on */ + + struct sfp_msa_data *msa; + struct sfp_ddm_data *ddm; + struct qsfp_data *qsfp; + + struct i2c_client *client; +}; + static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf) { struct i2c_client *client = to_i2c_client(dev); - struct as7712_32x_sfp_data *data = i2c_get_clientdata(client); - - return sprintf(buf, "%d\n", data->port+1); + struct sfp_port_data *data = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); } -/* Error-check the CPLD read results. */ -#define VALIDATED_READ(_buf, _rv, _read_expr, _invert) \ -do { \ - _rv = (_read_expr); \ - if(_rv < 0) { \ - return sprintf(_buf, "READ ERROR\n"); \ - } \ - if(_invert) { \ - _rv = ~_rv; \ - } \ - _rv &= 0xFF; \ -} while(0) +/* Platform dependent +++ */ +static struct sfp_port_data *sfp_update_present(struct i2c_client *client) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + int i = 0; + int status = -1; + u8 regs[] = {0x30, 0x31, 0x32, 0x33}; + DEBUG_PRINT("Starting sfp present status update"); + mutex_lock(&data->update_lock); + + /* Read present status of port 1~32 */ + data->present = 0; + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + status = accton_i2c_cpld_read(0x60, regs[i]); + + if (status < 0) { + DEBUG_PRINT("cpld(0x60) reg(0x%x) err %d", regs[i], status); + goto exit; + } + + DEBUG_PRINT("Present status = 0x%lx", data->present); + data->present |= (u64)status << (i*8); + } + + DEBUG_PRINT("Present status = 0x%lx", data->present); +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static struct sfp_port_data *sfp_update_tx_rx_status(struct device *dev) +{ + return NULL; +} + +/* Platform dependent --- */ + +static ssize_t sfp_set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + if (data->driver_type == DRIVER_TYPE_QSFP) { + return qsfp_set_tx_disable(dev, da, buf, count); + } + + return 0; +} + +static int sfp_is_port_present(struct i2c_client *client, int port) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + data = sfp_update_present(client); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + return (data->present & BIT_INDEX(data->port)) ? 0 : 1; /* Platform dependent */ +} + +/* Platform dependent +++ */ static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); - if(attr->index == SFP_IS_PRESENT_ALL) { - int values[4]; - /* - * Report the SFP_PRESENCE status for all ports. - */ - - /* SFP_PRESENT Ports 1-8 */ - VALIDATED_READ(buf, values[0], accton_i2c_cpld_read(0x60, 0x30), 1); - /* SFP_PRESENT Ports 9-16 */ - VALIDATED_READ(buf, values[1], accton_i2c_cpld_read(0x60, 0x31), 1); - /* SFP_PRESENT Ports 17-24 */ - VALIDATED_READ(buf, values[2], accton_i2c_cpld_read(0x60, 0x32), 1); - /* SFP_PRESENT Ports 25-32 */ - VALIDATED_READ(buf, values[3], accton_i2c_cpld_read(0x60, 0x33), 1); - - /* Return values 1 -> 32 in order */ - return sprintf(buf, "%.2x %.2x %.2x %.2x\n", - values[0], values[1], values[2], values[3]); - } - else { /* SFP_IS_PRESENT */ - struct as7712_32x_sfp_data *data = as7712_32x_sfp_update_device(dev); - - if (!data->valid) { - return -EIO; + if (PRESENT_ALL == attr->index) { + int i; + u8 values[4] = {0}; + struct sfp_port_data *data = sfp_update_present(client); + + if (IS_ERR(data)) { + return PTR_ERR(data); } - - return sprintf(buf, "%d\n", data->is_present); + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = ~(u8)(data->present >> (i * 8)); + } + + /* Return values 1 -> 32 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], + values[3]); + } + else { + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + /* PRESENT */ + return sprintf(buf, "%d\n", present); } } +/* Platform dependent --- */ -static ssize_t show_eeprom(struct device *dev, struct device_attribute *da, - char *buf) +static struct sfp_port_data *sfp_update_port_type(struct device *dev) { - struct as7712_32x_sfp_data *data = as7712_32x_sfp_update_device(dev); - - if (!data->valid) { - return 0; - } - - if (!data->is_present) { - return 0; - } - - memcpy(buf, data->eeprom, sizeof(data->eeprom)); - - return sizeof(data->eeprom); -} - -static const struct attribute_group as7712_32x_sfp_group = { - .attrs = as7712_32x_sfp_attributes, -}; - -static int as7712_32x_sfp_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) -{ - struct as7712_32x_sfp_data *data; + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + u8 buf = 0; int status; - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + mutex_lock(&data->update_lock); + + switch (data->driver_type) { + case DRIVER_TYPE_SFP_MSA: + { + status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + if (buf != SFF8024_DEVICE_ID_SFP) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + status = sfp_eeprom_read(client, SFF8472_10G_ETH_COMPLIANCE_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + DEBUG_PRINT("sfp port type (0x3) data = (0x%x)", buf); + data->port_type = buf & SFF8472_10G_BASE_MASK ? OOM_DRIVER_PORT_TYPE_SFP_PLUS : OOM_DRIVER_PORT_TYPE_SFP; + break; + } + case DRIVER_TYPE_QSFP: + { + status = sfp_eeprom_read(client, SFF8024_PHYSICAL_DEVICE_ID_ADDR, &buf, sizeof(buf)); + if (unlikely(status < 0)) { + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + DEBUG_PRINT("qsfp port type (0x0) buf = (0x%x)", buf); + switch (buf) { + case SFF8024_DEVICE_ID_QSFP: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP; + break; + case SFF8024_DEVICE_ID_QSFP_PLUS: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; + break; + case SFF8024_DEVICE_ID_QSFP28: + data->port_type = OOM_DRIVER_PORT_TYPE_QSFP_PLUS; + break; + default: + data->port_type = OOM_DRIVER_PORT_TYPE_INVALID; + break; + } + + break; + } + default: + break; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static ssize_t show_port_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + if (!present) { + return sprintf(buf, "%d\n", OOM_DRIVER_PORT_TYPE_NOT_PRESENT); + } + + sfp_update_port_type(dev); + return sprintf(buf, "%d\n", data->port_type); +} + +static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int i, status = -1; + u8 buf = 0; + u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; + + if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { + return data; + } + + DEBUG_PRINT("Starting sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->qsfp->valid = 0; + memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); + + /* Notify device to update tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + goto exit; + } + } + msleep(200); + + /* Read actual tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + goto exit; + } + + DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); + data->qsfp->status[i] = (buf & 0xF); + } + + data->qsfp->valid = 1; + data->qsfp->last_updated = jiffies; + +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + int present; + u8 val = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENXIO; + } + + data = qsfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + switch (attr->index) { + case TX_FAULT: + val = !!(data->qsfp->status[2] & 0xF); + break; + case TX_FAULT1: + case TX_FAULT2: + case TX_FAULT3: + case TX_FAULT4: + val = !!(data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)); + break; + case TX_DISABLE: + val = data->qsfp->status[1] & 0xF; + break; + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + val = !!(data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)); + break; + case RX_LOS: + val = !!(data->qsfp->status[0] & 0xF); + break; + case RX_LOS1: + case RX_LOS2: + case RX_LOS3: + case RX_LOS4: + val = !!(data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)); + break; + default: + break; + } + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long disable; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (!status) { + /* port is not present */ + return -ENXIO; + } + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + data = qsfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + mutex_lock(&data->update_lock); + + if (attr->index == TX_DISABLE) { + if (disable) { + data->qsfp->status[1] |= 0xF; + } + else { + data->qsfp->status[1] &= ~0xF; + } + } + else {/* TX_DISABLE1 ~ TX_DISABLE4*/ + if (disable) { + data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); + } + else { + data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); + } + } + + DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); + status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); + if (unlikely(status < 0)) { + count = status; + } + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t sfp_show_ddm_implemented(struct device *dev, struct device_attribute *da, + char *buf) +{ + int status; + char ddm; + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (status == 0) { + /* port is not present */ + return -ENODEV; + } + + status = sfp_eeprom_read(client, SFF8472_DIAG_MON_TYPE_ADDR, &ddm, sizeof(ddm)); + if (unlikely(status < 0)) { + return status; + } + + return sprintf(buf, "%d\n", !!(ddm & SFF8472_DIAG_MON_TYPE_DDM_MASK)); +} + +/* Platform dependent +++ */ +static ssize_t sfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + u8 val = 0, index = 0; + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + if (data->driver_type == DRIVER_TYPE_QSFP) { + return qsfp_show_tx_rx_status(dev, da, buf); + } + + data = sfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + if(attr->index == RX_LOS_ALL) { + int i = 0; + u8 values[6] = {0}; + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = (u8)(data->msa->status[2] >> (i * 8)); + } + + /** Return values 1 -> 48 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], + values[3], values[4], values[5]); + } + + switch (attr->index) { + case TX_FAULT: + index = 0; + break; + case TX_DISABLE: + index = 1; + break; + case RX_LOS: + index = 2; + break; + default: + return 0; + } + + val = !!(data->msa->status[index] & BIT_INDEX(data->port)); + return sprintf(buf, "%d\n", val); +} +/* Platform dependent --- */ +static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, command, *data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return 1; +#endif + + +} + +static ssize_t sfp_port_write(struct sfp_port_data *data, + const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_write(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; +} + + +static ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + return sfp_port_write(data, buf, off, count); +} + +static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + + //result = data_len; + +abort: + return status; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + status = 1; + +abort: + return status; +#endif +} + +static ssize_t sfp_port_read(struct sfp_port_data *data, + char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + DEBUG_PRINT("Count = 0, return"); + return count; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_read(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; + +} + +static ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + + return sfp_port_read(data, buf, off, count); +} + +static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = sfp_bin_read; + eeprom->write = sfp_bin_write; + eeprom->size = EEPROM_SIZE; + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + +static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + +static const struct attribute_group sfp_msa_group = { + .attrs = sfp_msa_attributes, +}; + +static int sfp_i2c_check_functionality(struct i2c_client *client) +{ +#if USE_I2C_BLOCK_READ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); +#else + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); +#endif +} + +static int sfp_msa_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct sfp_msa_data **data) +{ + int status; + struct sfp_msa_data *msa; + + if (!sfp_i2c_check_functionality(client)) { status = -EIO; goto exit; } - data = kzalloc(sizeof(struct as7712_32x_sfp_data), GFP_KERNEL); - if (!data) { + msa = kzalloc(sizeof(struct sfp_msa_data), GFP_KERNEL); + if (!msa) { status = -ENOMEM; goto exit; } - mutex_init(&data->update_lock); - data->port = dev_id->driver_data; - i2c_set_clientdata(client, data); - - dev_info(&client->dev, "chip found\n"); - /* Register sysfs hooks */ - status = sysfs_create_group(&client->dev.kobj, &as7712_32x_sfp_group); + status = sysfs_create_group(&client->dev.kobj, &sfp_msa_group); if (status) { goto exit_free; } - data->hwmon_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &msa->eeprom.bin); + if (status) { goto exit_remove; } - dev_info(&client->dev, "%s: sfp '%s'\n", - dev_name(data->hwmon_dev), client->name); + *data = msa; + dev_info(&client->dev, "sfp msa '%s'\n", client->name); return 0; exit_remove: - sysfs_remove_group(&client->dev.kobj, &as7712_32x_sfp_group); + sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); exit_free: - kfree(data); + kfree(msa); exit: return status; } -static int as7712_32x_sfp_remove(struct i2c_client *client) -{ - struct as7712_32x_sfp_data *data = i2c_get_clientdata(client); +static const struct attribute_group sfp_ddm_group = { + .attrs = sfp_ddm_attributes, +}; - hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &as7712_32x_sfp_group); +static int sfp_ddm_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct sfp_ddm_data **data) +{ + int status; + struct sfp_ddm_data *ddm; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + ddm = kzalloc(sizeof(struct sfp_ddm_data), GFP_KERNEL); + if (!ddm) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &sfp_ddm_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &ddm->eeprom.bin); + if (status) { + goto exit_remove; + } + + *data = ddm; + dev_info(&client->dev, "sfp ddm '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); +exit_free: + kfree(ddm); +exit: + + return status; +} + +static const struct attribute_group qsfp_group = { + .attrs = qsfp_attributes, +}; + +static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct qsfp_data **data) +{ + int status; + struct qsfp_data *qsfp; + + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } + + qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); + if (!qsfp) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &qsfp_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); + if (status) { + goto exit_remove; + } + + *data = qsfp; + dev_info(&client->dev, "qsfp '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &qsfp_group); +exit_free: + kfree(qsfp); +exit: + + return status; +} + +/* Platform dependent +++ */ +static int sfp_device_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct sfp_port_data *data = NULL; + + data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->port = dev_id->driver_data; + data->client = client; + + if (client->addr != SFP_EEPROM_A0_I2C_ADDR) { + return -ENODEV; + } + + data->driver_type = DRIVER_TYPE_QSFP; + return qsfp_probe(client, dev_id, &data->qsfp); +} +/* Platform dependent --- */ + +static int sfp_msa_remove(struct i2c_client *client, struct sfp_msa_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &sfp_msa_group); kfree(data); + return 0; +} + +static int sfp_ddm_remove(struct i2c_client *client, struct sfp_ddm_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &sfp_ddm_group); + kfree(data); + return 0; +} + +static int qfp_remove(struct i2c_client *client, struct qsfp_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &qsfp_group); + kfree(data); + return 0; +} + +static int sfp_device_remove(struct i2c_client *client) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + switch (data->driver_type) { + case DRIVER_TYPE_SFP_MSA: + return sfp_msa_remove(client, data->msa); + case DRIVER_TYPE_SFP_DDM: + return sfp_ddm_remove(client, data->ddm); + case DRIVER_TYPE_QSFP: + return qfp_remove(client, data->qsfp); + } return 0; } -enum port_numbers { -as7712_32x_sfp1, as7712_32x_sfp2, as7712_32x_sfp3, as7712_32x_sfp4, -as7712_32x_sfp5, as7712_32x_sfp6, as7712_32x_sfp7, as7712_32x_sfp8, -as7712_32x_sfp9, as7712_32x_sfp10,as7712_32x_sfp11,as7712_32x_sfp12, -as7712_32x_sfp13,as7712_32x_sfp14,as7712_32x_sfp15,as7712_32x_sfp16, -as7712_32x_sfp17,as7712_32x_sfp18,as7712_32x_sfp19,as7712_32x_sfp20, -as7712_32x_sfp21,as7712_32x_sfp22,as7712_32x_sfp23,as7712_32x_sfp24, -as7712_32x_sfp25,as7712_32x_sfp26,as7712_32x_sfp27,as7712_32x_sfp28, -as7712_32x_sfp29,as7712_32x_sfp30,as7712_32x_sfp31,as7712_32x_sfp32 -}; +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; -static const struct i2c_device_id as7712_32x_sfp_id[] = { -{ "as7712_32x_sfp1", as7712_32x_sfp1 }, { "as7712_32x_sfp2", as7712_32x_sfp2 }, -{ "as7712_32x_sfp3", as7712_32x_sfp3 }, { "as7712_32x_sfp4", as7712_32x_sfp4 }, -{ "as7712_32x_sfp5", as7712_32x_sfp5 }, { "as7712_32x_sfp6", as7712_32x_sfp6 }, -{ "as7712_32x_sfp7", as7712_32x_sfp7 }, { "as7712_32x_sfp8", as7712_32x_sfp8 }, -{ "as7712_32x_sfp9", as7712_32x_sfp9 }, { "as7712_32x_sfp10", as7712_32x_sfp10 }, -{ "as7712_32x_sfp11", as7712_32x_sfp11 }, { "as7712_32x_sfp12", as7712_32x_sfp12 }, -{ "as7712_32x_sfp13", as7712_32x_sfp13 }, { "as7712_32x_sfp14", as7712_32x_sfp14 }, -{ "as7712_32x_sfp15", as7712_32x_sfp15 }, { "as7712_32x_sfp16", as7712_32x_sfp16 }, -{ "as7712_32x_sfp17", as7712_32x_sfp17 }, { "as7712_32x_sfp18", as7712_32x_sfp18 }, -{ "as7712_32x_sfp19", as7712_32x_sfp19 }, { "as7712_32x_sfp20", as7712_32x_sfp20 }, -{ "as7712_32x_sfp21", as7712_32x_sfp21 }, { "as7712_32x_sfp22", as7712_32x_sfp22 }, -{ "as7712_32x_sfp23", as7712_32x_sfp23 }, { "as7712_32x_sfp24", as7712_32x_sfp24 }, -{ "as7712_32x_sfp25", as7712_32x_sfp25 }, { "as7712_32x_sfp26", as7712_32x_sfp26 }, -{ "as7712_32x_sfp27", as7712_32x_sfp27 }, { "as7712_32x_sfp28", as7712_32x_sfp28 }, -{ "as7712_32x_sfp29", as7712_32x_sfp29 }, { "as7712_32x_sfp30", as7712_32x_sfp30 }, -{ "as7712_32x_sfp31", as7712_32x_sfp31 }, { "as7712_32x_sfp32", as7712_32x_sfp32 }, -{} -}; -MODULE_DEVICE_TABLE(i2c, as7712_32x_sfp_id); - -static struct i2c_driver as7712_32x_sfp_driver = { - .class = I2C_CLASS_HWMON, +static struct i2c_driver sfp_driver = { .driver = { - .name = "as7712_32x_sfp", + .name = DRIVER_NAME, }, - .probe = as7712_32x_sfp_probe, - .remove = as7712_32x_sfp_remove, - .id_table = as7712_32x_sfp_id, + .probe = sfp_device_probe, + .remove = sfp_device_remove, + .id_table = sfp_device_id, .address_list = normal_i2c, }; -static int as7712_32x_sfp_read_block(struct i2c_client *client, u8 command, u8 *data, - int data_len) +static int __init sfp_init(void) { - int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); - - if (unlikely(result < 0)) - goto abort; - if (unlikely(result != data_len)) { - result = -EIO; - goto abort; - } - - result = 0; - -abort: - return result; + return i2c_add_driver(&sfp_driver); } -static struct as7712_32x_sfp_data *as7712_32x_sfp_update_device(struct device *dev) +static void __exit sfp_exit(void) { - struct i2c_client *client = to_i2c_client(dev); - struct as7712_32x_sfp_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int status = -1; - int i = 0; - u8 cpld_reg = 0x30 + (data->port/8); - - data->valid = 0; - - /* Read present status of the specified port number */ - data->is_present = 0; - status = accton_i2c_cpld_read(0x60, cpld_reg); - - if (status < 0) { - dev_dbg(&client->dev, "cpld(0x60) reg(0x%x) err %d\n", cpld_reg, status); - goto exit; - } - - data->is_present = (status & (1 << (data->port % 8))) ? 0 : 1; - - /* Read eeprom data based on port number */ - memset(data->eeprom, 0, sizeof(data->eeprom)); - - /* Check if the port is present */ - if (data->is_present) { - /* read eeprom */ - for (i = 0; i < sizeof(data->eeprom)/I2C_SMBUS_BLOCK_MAX; i++) { - status = as7712_32x_sfp_read_block(client, i*I2C_SMBUS_BLOCK_MAX, - data->eeprom+(i*I2C_SMBUS_BLOCK_MAX), - I2C_SMBUS_BLOCK_MAX); - if (status < 0) { - dev_dbg(&client->dev, "unable to read eeprom from port(%d)\n", data->port); - goto exit; - } - } - } - - data->last_updated = jiffies; - data->valid = 1; - } - -exit: - mutex_unlock(&data->update_lock); - - return data; -} - -static int __init as7712_32x_sfp_init(void) -{ - extern int platform_accton_as7712_32x(void); - if (!platform_accton_as7712_32x()) { - return -ENODEV; - } - - return i2c_add_driver(&as7712_32x_sfp_driver); -} - -static void __exit as7712_32x_sfp_exit(void) -{ - i2c_del_driver(&as7712_32x_sfp_driver); + i2c_del_driver(&sfp_driver); } MODULE_AUTHOR("Brandon Chuang "); MODULE_DESCRIPTION("accton as7712_32x_sfp driver"); MODULE_LICENSE("GPL"); -module_init(as7712_32x_sfp_init); -module_exit(as7712_32x_sfp_exit); +module_init(sfp_init); +module_exit(sfp_exit); + From c29c3bf03eb853b823ccb354af4ace19b59f06a6 Mon Sep 17 00:00:00 2001 From: hans Date: Mon, 15 May 2017 13:48:06 +0800 Subject: [PATCH 2/5] 1. remove the unnecessary file tmp421.c Signed-off-by: hans --- .../modules/builds/tmp421.c | 309 ------------------ 1 file changed, 309 deletions(-) delete mode 100644 packages/platforms/delta/x86-64/x86-64-delta-agc7648a/modules/builds/tmp421.c diff --git a/packages/platforms/delta/x86-64/x86-64-delta-agc7648a/modules/builds/tmp421.c b/packages/platforms/delta/x86-64/x86-64-delta-agc7648a/modules/builds/tmp421.c deleted file mode 100644 index 7bab7a9b..00000000 --- a/packages/platforms/delta/x86-64/x86-64-delta-agc7648a/modules/builds/tmp421.c +++ /dev/null @@ -1,309 +0,0 @@ -/* tmp421.c - * - * Copyright (C) 2009 Andre Prendel - * Preliminary support by: - * Melvin Rook, Raymond Ng - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* - * Driver for the Texas Instruments TMP421 SMBus temperature sensor IC. - * Supported models: TMP421, TMP422, TMP423 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Addresses to scan */ -static const unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f, - I2C_CLIENT_END }; - -enum chips { tmp421, tmp422, tmp423 }; - -/* The TMP421 registers */ -#define TMP421_CONFIG_REG_1 0x09 -#define TMP421_CONVERSION_RATE_REG 0x0B -#define TMP421_MANUFACTURER_ID_REG 0xFE -#define TMP421_DEVICE_ID_REG 0xFF - -static const u8 TMP421_TEMP_MSB[4] = { 0x00, 0x01, 0x02, 0x03 }; -static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 }; - -/* Flags */ -#define TMP421_CONFIG_SHUTDOWN 0x40 -#define TMP421_CONFIG_RANGE 0x04 - -/* Manufacturer / Device ID's */ -#define TMP421_MANUFACTURER_ID 0x55 -#define TMP421_DEVICE_ID 0x21 -#define TMP422_DEVICE_ID 0x22 -#define TMP423_DEVICE_ID 0x23 - -static const struct i2c_device_id tmp421_id[] = { - { "tmp421", 2 }, - { "tmp422", 3 }, - { "tmp423", 4 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tmp421_id); - -struct tmp421_data { - struct i2c_client *client; - struct mutex update_lock; - char valid; - unsigned long last_updated; - int channels; - u8 config; - s16 temp[4]; -}; - -static int temp_from_s16(s16 reg) -{ - /* Mask out status bits */ - int temp = reg & ~0xf; - - return (temp * 1000 + 128) / 256; -} - -static int temp_from_u16(u16 reg) -{ - /* Mask out status bits */ - int temp = reg & ~0xf; - - /* Add offset for extended temperature range. */ - temp -= 64 * 256; - - return (temp * 1000 + 128) / 256; -} - -static struct tmp421_data *tmp421_update_device(struct device *dev) -{ - struct tmp421_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - int i; - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { - data->config = i2c_smbus_read_byte_data(client, - TMP421_CONFIG_REG_1); - - for (i = 0; i < data->channels; i++) { - data->temp[i] = i2c_smbus_read_byte_data(client, - TMP421_TEMP_MSB[i]) << 8; - data->temp[i] |= i2c_smbus_read_byte_data(client, - TMP421_TEMP_LSB[i]); - } - data->last_updated = jiffies; - data->valid = 1; - } - - mutex_unlock(&data->update_lock); - - return data; -} - -static ssize_t show_temp_value(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - int index = to_sensor_dev_attr(devattr)->index; - struct tmp421_data *data = tmp421_update_device(dev); - int temp; - - mutex_lock(&data->update_lock); - if (data->config & TMP421_CONFIG_RANGE) - temp = temp_from_u16(data->temp[index]); - else - temp = temp_from_s16(data->temp[index]); - mutex_unlock(&data->update_lock); - - return sprintf(buf, "%d\n", temp); -} - -static ssize_t show_fault(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - int index = to_sensor_dev_attr(devattr)->index; - struct tmp421_data *data = tmp421_update_device(dev); - - /* - * The OPEN bit signals a fault. This is bit 0 of the temperature - * register (low byte). - */ - if (data->temp[index] & 0x01) - return sprintf(buf, "1\n"); - else - return sprintf(buf, "0\n"); -} - -static umode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a, - int n) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct tmp421_data *data = dev_get_drvdata(dev); - struct device_attribute *devattr; - unsigned int index; - - devattr = container_of(a, struct device_attribute, attr); - index = to_sensor_dev_attr(devattr)->index; - - if (index < data->channels) - return a->mode; - - return 0; -} - -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0); -static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1); -static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1); -static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2); -static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2); -static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_value, NULL, 3); -static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3); - -static struct attribute *tmp421_attr[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp2_fault.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, - &sensor_dev_attr_temp3_fault.dev_attr.attr, - &sensor_dev_attr_temp4_input.dev_attr.attr, - &sensor_dev_attr_temp4_fault.dev_attr.attr, - NULL -}; - -static const struct attribute_group tmp421_group = { - .attrs = tmp421_attr, - .is_visible = tmp421_is_visible, -}; - -static const struct attribute_group *tmp421_groups[] = { - &tmp421_group, - NULL -}; - -static int tmp421_init_client(struct i2c_client *client) -{ - int config, config_orig; - - /* Set the conversion rate to 2 Hz */ - i2c_smbus_write_byte_data(client, TMP421_CONVERSION_RATE_REG, 0x05); - - /* Start conversions (disable shutdown if necessary) */ - config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1); - if (config < 0) { - dev_err(&client->dev, - "Could not read configuration register (%d)\n", config); - return config; - } - - config_orig = config; - config &= ~TMP421_CONFIG_SHUTDOWN; - - if (config != config_orig) { - dev_info(&client->dev, "Enable monitoring chip\n"); - i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_1, config); - } - - return 0; -} - -static int tmp421_detect(struct i2c_client *client, - struct i2c_board_info *info) -{ - enum chips kind; - struct i2c_adapter *adapter = client->adapter; - const char *names[] = { "TMP421", "TMP422", "TMP423" }; - u8 reg; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - reg = i2c_smbus_read_byte_data(client, TMP421_MANUFACTURER_ID_REG); - if (reg != TMP421_MANUFACTURER_ID) - return -ENODEV; - - reg = i2c_smbus_read_byte_data(client, TMP421_DEVICE_ID_REG); - switch (reg) { - case TMP421_DEVICE_ID: - kind = tmp421; - break; - case TMP422_DEVICE_ID: - kind = tmp422; - break; - case TMP423_DEVICE_ID: - kind = tmp423; - break; - default: - return -ENODEV; - } - - strlcpy(info->type, tmp421_id[kind].name, I2C_NAME_SIZE); - dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n", - names[kind], client->addr); - - return 0; -} - -static int tmp421_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct device *hwmon_dev; - struct tmp421_data *data; - int err; - - data = devm_kzalloc(dev, sizeof(struct tmp421_data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - mutex_init(&data->update_lock); - data->channels = id->driver_data; - data->client = client; - - err = tmp421_init_client(client); - if (err) - return err; - - hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, - data, tmp421_groups); - return PTR_ERR_OR_ZERO(hwmon_dev); -} - -static struct i2c_driver tmp421_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "tmp421", - }, - .probe = tmp421_probe, - .id_table = tmp421_id, - .detect = tmp421_detect, - .address_list = normal_i2c, -}; - -module_i2c_driver(tmp421_driver); - -MODULE_AUTHOR("Andre Prendel "); -MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor driver"); -MODULE_LICENSE("GPL"); From 79a9f9b459e991cd0d42a27dc0cdfdf48a2862de Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Mon, 15 May 2017 14:31:24 -0700 Subject: [PATCH 3/5] Add post-install update hook. TODO: parameterize --- tools/autobuild/install.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/autobuild/install.sh b/tools/autobuild/install.sh index 9f904a76..d86ecd1c 100755 --- a/tools/autobuild/install.sh +++ b/tools/autobuild/install.sh @@ -91,3 +91,4 @@ _rsync() { sshpass -p $REMOTE_PASS ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l $REMOTE_USER $REMOTE_SERVER mkdir -p $REMOTE_DIR _rsync $ONL/RELEASE $REMOTE_SERVER:$REMOTE_DIR _rsync $ONL/REPO $REMOTE_SERVER:$REMOTE_DIR +sshpass -p $REMOTE_PASS ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -l $REMOTE_USER $REMOTE_SERVER "$REMOTE_BASE_DIR/.tools/update-latest.py" --dir "$REMOTE_BASE_DIR/$BUILD_BRANCH" || true From f4c9125c2ee1177df33c75b2adeddb913a0c17cf Mon Sep 17 00:00:00 2001 From: Jonathan Tsai Date: Wed, 17 May 2017 10:34:34 +0800 Subject: [PATCH 4/5] Quanta IX1 ONLP Update: 1. [IX1] Fix unexpected module present issue: Set P3V3_ZQSFP_EN as high directly --- .../src/x86_64_quanta_ix1_rangeley/module/src/sfpi.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ix1-rangeley/onlp/builds/src/x86_64_quanta_ix1_rangeley/module/src/sfpi.c b/packages/platforms/quanta/x86-64/x86-64-quanta-ix1-rangeley/onlp/builds/src/x86_64_quanta_ix1_rangeley/module/src/sfpi.c index 6c618b61..ffcfde0b 100755 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ix1-rangeley/onlp/builds/src/x86_64_quanta_ix1_rangeley/module/src/sfpi.c +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ix1-rangeley/onlp/builds/src/x86_64_quanta_ix1_rangeley/module/src/sfpi.c @@ -83,15 +83,11 @@ static sfpmap_t sfpmap__[] = int onlp_sfpi_init(void) { - int value = -1, ret; + int ret; - onlp_gpio_export(QUANTA_IX1_ZQSFP_EN_GPIO_P3V3_PW_EN, ONLP_GPIO_DIRECTION_IN); - ret = onlp_gpio_get(QUANTA_IX1_ZQSFP_EN_GPIO_P3V3_PW_EN, &value); - if(ret == ONLP_STATUS_OK && value != 1) { - onlp_gpio_export(QUANTA_IX1_ZQSFP_EN_GPIO_P3V3_PW_EN, ONLP_GPIO_DIRECTION_OUT); - ret = onlp_gpio_set(QUANTA_IX1_ZQSFP_EN_GPIO_P3V3_PW_EN, 1); - sleep(1); - } + onlp_gpio_export(QUANTA_IX1_ZQSFP_EN_GPIO_P3V3_PW_EN, ONLP_GPIO_DIRECTION_OUT); + ret = onlp_gpio_set(QUANTA_IX1_ZQSFP_EN_GPIO_P3V3_PW_EN, 1); + sleep(1); return ret; } From fbc38a58b5bbb4677e0ffc3d5c7c6d907543cb2d Mon Sep 17 00:00:00 2001 From: Jeffrey Townsend Date: Tue, 23 May 2017 08:12:43 -0700 Subject: [PATCH 5/5] Change extract message from warn to info. --- tools/onlpm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/onlpm.py b/tools/onlpm.py index 72d11653..074dd930 100755 --- a/tools/onlpm.py +++ b/tools/onlpm.py @@ -756,7 +756,7 @@ class OnlPackageRepo(object): logger.debug("Existing extract for %s matches the package file." % pkg) else: # Existing extract must be removed. - logger.warn("Existing extract for %s does not match." % pkg) + logger.info("Existing extract for %s does not match." % pkg) force=True else: # Status unknown. Really shouldn't happen.