Revert "[as6812-32x] Add support for OOM"

This commit is contained in:
Jeffrey Townsend
2018-04-11 14:06:55 -07:00
committed by GitHub
parent 3e3681a01e
commit 53002164da
7 changed files with 1771 additions and 545 deletions

View File

@@ -33,28 +33,44 @@
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/dmi.h>
#include <linux/version.h>
#include <linux/stat.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
static struct dmi_system_id as6812_dmi_table[] = {
{
.ident = "Accton AS6812",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Accton"),
DMI_MATCH(DMI_PRODUCT_NAME, "AS6812"),
},
},
{
.ident = "Accton AS6812",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Accton"),
DMI_MATCH(DMI_PRODUCT_NAME, "AS6812"),
},
},
};
int platform_accton_as6812_32x(void)
{
return dmi_check_system(as6812_dmi_table);
}
EXPORT_SYMBOL(platform_accton_as6812_32x);
#define NUM_OF_CPLD1_CHANS 0x0
#define NUM_OF_CPLD2_CHANS 0x10
#define NUM_OF_CPLD3_CHANS 0x10
#define CPLD_CHANNEL_SELECT_REG 0x2
#define CPLD_DESELECT_CHANNEL 0xFF
#define ACCTON_I2C_CPLD_MUX_MAX_NCHANS NUM_OF_CPLD3_CHANS
#define NUM_OF_ALL_CPLD_CHANS (NUM_OF_CPLD2_CHANS + NUM_OF_CPLD3_CHANS)
#define ACCTON_I2C_CPLD_MUX_MAX_NCHANS NUM_OF_CPLD3_CHANS
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
static struct mutex list_lock;
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
struct i2c_client *client;
struct list_head list;
};
enum cpld_mux_type {
@@ -63,13 +79,10 @@ enum cpld_mux_type {
as6812_32x_cpld1
};
struct as6812_32x_cpld_data {
enum cpld_mux_type type;
struct i2c_adapter *virt_adaps[ACCTON_I2C_CPLD_MUX_MAX_NCHANS];
u8 last_chan; /* last register value */
struct device *hwmon_dev;
struct mutex update_lock;
struct accton_i2c_cpld_mux {
enum cpld_mux_type type;
struct i2c_adapter *virt_adaps[ACCTON_I2C_CPLD_MUX_MAX_NCHANS];
u8 last_chan; /* last register value */
};
struct chip_desc {
@@ -93,289 +106,18 @@ static const struct chip_desc chips[] = {
}
};
static const struct i2c_device_id as6812_32x_cpld_mux_id[] = {
static const struct i2c_device_id accton_i2c_cpld_mux_id[] = {
{ "as6812_32x_cpld1", as6812_32x_cpld1 },
{ "as6812_32x_cpld2", as6812_32x_cpld2 },
{ "as6812_32x_cpld3", as6812_32x_cpld3 },
{ }
};
MODULE_DEVICE_TABLE(i2c, as6812_32x_cpld_mux_id);
#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index
#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index
#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index
#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index
enum as6812_32x_cpld_sysfs_attributes {
CPLD_VERSION,
ACCESS,
MODULE_PRESENT_ALL,
MODULE_RXLOS_ALL,
/* transceiver attributes */
TRANSCEIVER_PRESENT_ATTR_ID(1),
TRANSCEIVER_PRESENT_ATTR_ID(2),
TRANSCEIVER_PRESENT_ATTR_ID(3),
TRANSCEIVER_PRESENT_ATTR_ID(4),
TRANSCEIVER_PRESENT_ATTR_ID(5),
TRANSCEIVER_PRESENT_ATTR_ID(6),
TRANSCEIVER_PRESENT_ATTR_ID(7),
TRANSCEIVER_PRESENT_ATTR_ID(8),
TRANSCEIVER_PRESENT_ATTR_ID(9),
TRANSCEIVER_PRESENT_ATTR_ID(10),
TRANSCEIVER_PRESENT_ATTR_ID(11),
TRANSCEIVER_PRESENT_ATTR_ID(12),
TRANSCEIVER_PRESENT_ATTR_ID(13),
TRANSCEIVER_PRESENT_ATTR_ID(14),
TRANSCEIVER_PRESENT_ATTR_ID(15),
TRANSCEIVER_PRESENT_ATTR_ID(16),
TRANSCEIVER_PRESENT_ATTR_ID(17),
TRANSCEIVER_PRESENT_ATTR_ID(18),
TRANSCEIVER_PRESENT_ATTR_ID(19),
TRANSCEIVER_PRESENT_ATTR_ID(20),
TRANSCEIVER_PRESENT_ATTR_ID(21),
TRANSCEIVER_PRESENT_ATTR_ID(22),
TRANSCEIVER_PRESENT_ATTR_ID(23),
TRANSCEIVER_PRESENT_ATTR_ID(24),
TRANSCEIVER_PRESENT_ATTR_ID(25),
TRANSCEIVER_PRESENT_ATTR_ID(26),
TRANSCEIVER_PRESENT_ATTR_ID(27),
TRANSCEIVER_PRESENT_ATTR_ID(28),
TRANSCEIVER_PRESENT_ATTR_ID(29),
TRANSCEIVER_PRESENT_ATTR_ID(30),
TRANSCEIVER_PRESENT_ATTR_ID(31),
TRANSCEIVER_PRESENT_ATTR_ID(32),
};
/* sysfs attributes for hwmon
*/
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t show_version(struct device *dev, struct device_attribute *da,
char *buf);
static int as6812_32x_cpld_read_internal(struct i2c_client *client, u8 reg);
static int as6812_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
/* transceiver attributes */
#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index)
#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr
static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION);
static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS);
/* transceiver attributes */
static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(7);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(8);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(9);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(10);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(11);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(12);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(13);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(14);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(15);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(16);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(17);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(18);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(19);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(20);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(21);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(22);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(23);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(24);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(25);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(26);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(27);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(28);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(29);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(30);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(31);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(32);
static struct attribute *as6812_32x_cpld1_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
NULL
};
static const struct attribute_group as6812_32x_cpld1_group = {
.attrs = as6812_32x_cpld1_attributes,
};
static struct attribute *as6812_32x_cpld2_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
/* transceiver attributes */
&sensor_dev_attr_module_present_all.dev_attr.attr,
DECLARE_TRANSCEIVER_PRESENT_ATTR(1),
DECLARE_TRANSCEIVER_PRESENT_ATTR(2),
DECLARE_TRANSCEIVER_PRESENT_ATTR(3),
DECLARE_TRANSCEIVER_PRESENT_ATTR(4),
DECLARE_TRANSCEIVER_PRESENT_ATTR(5),
DECLARE_TRANSCEIVER_PRESENT_ATTR(6),
DECLARE_TRANSCEIVER_PRESENT_ATTR(7),
DECLARE_TRANSCEIVER_PRESENT_ATTR(8),
DECLARE_TRANSCEIVER_PRESENT_ATTR(9),
DECLARE_TRANSCEIVER_PRESENT_ATTR(10),
DECLARE_TRANSCEIVER_PRESENT_ATTR(11),
DECLARE_TRANSCEIVER_PRESENT_ATTR(12),
DECLARE_TRANSCEIVER_PRESENT_ATTR(13),
DECLARE_TRANSCEIVER_PRESENT_ATTR(14),
DECLARE_TRANSCEIVER_PRESENT_ATTR(15),
DECLARE_TRANSCEIVER_PRESENT_ATTR(16),
NULL
};
static const struct attribute_group as6812_32x_cpld2_group = {
.attrs = as6812_32x_cpld2_attributes,
};
static struct attribute *as6812_32x_cpld3_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
/* transceiver attributes */
&sensor_dev_attr_module_present_all.dev_attr.attr,
DECLARE_TRANSCEIVER_PRESENT_ATTR(17),
DECLARE_TRANSCEIVER_PRESENT_ATTR(18),
DECLARE_TRANSCEIVER_PRESENT_ATTR(19),
DECLARE_TRANSCEIVER_PRESENT_ATTR(20),
DECLARE_TRANSCEIVER_PRESENT_ATTR(21),
DECLARE_TRANSCEIVER_PRESENT_ATTR(22),
DECLARE_TRANSCEIVER_PRESENT_ATTR(23),
DECLARE_TRANSCEIVER_PRESENT_ATTR(24),
DECLARE_TRANSCEIVER_PRESENT_ATTR(25),
DECLARE_TRANSCEIVER_PRESENT_ATTR(26),
DECLARE_TRANSCEIVER_PRESENT_ATTR(27),
DECLARE_TRANSCEIVER_PRESENT_ATTR(28),
DECLARE_TRANSCEIVER_PRESENT_ATTR(29),
DECLARE_TRANSCEIVER_PRESENT_ATTR(30),
DECLARE_TRANSCEIVER_PRESENT_ATTR(31),
DECLARE_TRANSCEIVER_PRESENT_ATTR(32),
NULL
};
static const struct attribute_group as6812_32x_cpld3_group = {
.attrs = as6812_32x_cpld3_attributes,
};
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf)
{
int i, status;
u8 values[2] = {0};
u8 regs[] = {0xA, 0xB};
struct i2c_client *client = to_i2c_client(dev);
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
for (i = 0; i < ARRAY_SIZE(regs); i++) {
status = as6812_32x_cpld_read_internal(client, regs[i]);
if (status < 0) {
goto exit;
}
values[i] = ~(u8)status;
}
mutex_unlock(&data->update_lock);
/* Return values 1 -> 32 in order */
return sprintf(buf, "%.2x %.2x\n", values[0], values[1]);
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 as6812_32x_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 = 0xA;
mask = 0x1 << (attr->index - MODULE_PRESENT_1);
break;
case MODULE_PRESENT_9 ... MODULE_PRESENT_16:
reg = 0xB;
mask = 0x1 << (attr->index - MODULE_PRESENT_9);
break;
case MODULE_PRESENT_17 ... MODULE_PRESENT_24:
reg = 0xA;
mask = 0x1 << (attr->index - MODULE_PRESENT_17);
break;
case MODULE_PRESENT_25 ... MODULE_PRESENT_32:
reg = 0xB;
mask = 0x1 << (attr->index - MODULE_PRESENT_25);
break;
default:
return 0;
}
mutex_lock(&data->update_lock);
status = as6812_32x_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", !(status & mask));
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
int status;
u32 addr, val;
struct i2c_client *client = to_i2c_client(dev);
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
return -EINVAL;
}
if (addr > 0xFF || val > 0xFF) {
return -EINVAL;
}
mutex_lock(&data->update_lock);
status = as6812_32x_cpld_write_internal(client, addr, val);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
MODULE_DEVICE_TABLE(i2c, accton_i2c_cpld_mux_id);
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
for this as they will try to lock adapter a second time */
static int as6812_32x_cpld_mux_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val)
static int accton_i2c_cpld_mux_reg_write(struct i2c_adapter *adap,
struct i2c_client *client, u8 val)
{
unsigned long orig_jiffies;
unsigned short flags;
@@ -392,8 +134,8 @@ static int as6812_32x_cpld_mux_reg_write(struct i2c_adapter *adap,
orig_jiffies = jiffies;
for (res = 0, try = 0; try <= adap->retries; try++) {
res = adap->algo->smbus_xfer(adap, client->addr, flags,
I2C_SMBUS_WRITE, CPLD_CHANNEL_SELECT_REG,
I2C_SMBUS_BYTE_DATA, &data);
I2C_SMBUS_WRITE, 0x2,
I2C_SMBUS_BYTE_DATA, &data);
if (res != -EAGAIN)
break;
if (time_after(jiffies,
@@ -405,35 +147,35 @@ static int as6812_32x_cpld_mux_reg_write(struct i2c_adapter *adap,
return res;
}
static int as6812_32x_cpld_mux_select_chan(struct i2c_adapter *adap,
void *client, u32 chan)
static int accton_i2c_cpld_mux_select_chan(struct i2c_adapter *adap,
void *client, u32 chan)
{
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
struct accton_i2c_cpld_mux *data = i2c_get_clientdata(client);
u8 regval;
int ret = 0;
regval = chan;
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
ret = as6812_32x_cpld_mux_reg_write(adap, client, regval);
ret = accton_i2c_cpld_mux_reg_write(adap, client, regval);
data->last_chan = regval;
}
return ret;
}
static int as6812_32x_cpld_mux_deselect_mux(struct i2c_adapter *adap,
static int accton_i2c_cpld_mux_deselect_mux(struct i2c_adapter *adap,
void *client, u32 chan)
{
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
struct accton_i2c_cpld_mux *data = i2c_get_clientdata(client);
/* Deselect active channel */
data->last_chan = chips[data->type].deselectChan;
return as6812_32x_cpld_mux_reg_write(adap, client, data->last_chan);
return accton_i2c_cpld_mux_reg_write(adap, client, data->last_chan);
}
static void as6812_32x_cpld_add_client(struct i2c_client *client)
static void accton_i2c_cpld_add_client(struct i2c_client *client)
{
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
@@ -449,7 +191,7 @@ static void as6812_32x_cpld_add_client(struct i2c_client *client)
mutex_unlock(&list_lock);
}
static void as6812_32x_cpld_remove_client(struct i2c_client *client)
static void accton_i2c_cpld_remove_client(struct i2c_client *client)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
@@ -475,250 +217,177 @@ static void as6812_32x_cpld_remove_client(struct i2c_client *client)
mutex_unlock(&list_lock);
}
static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t show_cpld_version(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
val = i2c_smbus_read_byte_data(client, 0x1);
u8 reg = 0x1;
struct i2c_client *client;
int len;
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
}
return sprintf(buf, "%d", val);
client = to_i2c_client(dev);
len = sprintf(buf, "%d", i2c_smbus_read_byte_data(client, reg));
return len;
}
static struct device_attribute ver = __ATTR(version, 0600, show_cpld_version, NULL);
/*
* I2C init/probing/exit functions
*/
static int as6812_32x_cpld_mux_probe(struct i2c_client *client,
static int accton_i2c_cpld_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
int chan=0;
struct as6812_32x_cpld_data *data;
struct accton_i2c_cpld_mux *data;
int ret = -ENODEV;
const struct attribute_group *group = NULL;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
goto exit;
goto err;
data = kzalloc(sizeof(struct as6812_32x_cpld_data), GFP_KERNEL);
data = kzalloc(sizeof(struct accton_i2c_cpld_mux), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto exit;
goto err;
}
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->type = id->driver_data;
if (data->type == as6812_32x_cpld2 || data->type == as6812_32x_cpld3) {
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
if (data->type == as6812_32x_cpld2 || data->type == as6812_32x_cpld3) {
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
/* Now create an adapter for each channel */
for (chan = 0; chan < chips[data->type].nchans; chan++) {
data->virt_adaps[chan] = i2c_add_mux_adapter(adap, &client->dev, client, 0, chan, 0,
as6812_32x_cpld_mux_select_chan,
as6812_32x_cpld_mux_deselect_mux);
/* Now create an adapter for each channel */
for (chan = 0; chan < chips[data->type].nchans; chan++) {
data->virt_adaps[chan] = i2c_add_mux_adapter(adap, &client->dev, client, 0, chan,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
I2C_CLASS_HWMON | I2C_CLASS_SPD,
#endif
accton_i2c_cpld_mux_select_chan,
accton_i2c_cpld_mux_deselect_mux);
if (data->virt_adaps[chan] == NULL) {
ret = -ENODEV;
dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
goto exit_mux_register;
}
}
if (data->virt_adaps[chan] == NULL) {
ret = -ENODEV;
dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
goto virt_reg_failed;
}
}
dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
chan, client->name);
}
dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
chan, client->name);
}
/* Register sysfs hooks */
switch (data->type) {
case as6812_32x_cpld1:
group = &as6812_32x_cpld1_group;
break;
case as6812_32x_cpld2:
group = &as6812_32x_cpld2_group;
break;
case as6812_32x_cpld3:
group = &as6812_32x_cpld3_group;
break;
default:
break;
}
accton_i2c_cpld_add_client(client);
if (group) {
ret = sysfs_create_group(&client->dev.kobj, group);
if (ret) {
goto exit_mux_register;
}
}
ret = sysfs_create_file(&client->dev.kobj, &ver.attr);
if (ret)
goto virt_reg_failed;
as6812_32x_cpld_add_client(client);
return 0;
return 0;
exit_mux_register:
virt_reg_failed:
for (chan--; chan >= 0; chan--) {
i2c_del_mux_adapter(data->virt_adaps[chan]);
}
kfree(data);
exit:
}
kfree(data);
err:
return ret;
}
static int as6812_32x_cpld_mux_remove(struct i2c_client *client)
{
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
const struct chip_desc *chip = &chips[data->type];
int chan;
const struct attribute_group *group = NULL;
as6812_32x_cpld_remove_client(client);
/* Remove sysfs hooks */
switch (data->type) {
case as6812_32x_cpld1:
group = &as6812_32x_cpld1_group;
break;
case as6812_32x_cpld2:
group = &as6812_32x_cpld2_group;
break;
case as6812_32x_cpld3:
group = &as6812_32x_cpld3_group;
break;
default:
break;
}
if (group) {
sysfs_remove_group(&client->dev.kobj, group);
}
for (chan = 0; chan < chip->nchans; ++chan) {
if (data->virt_adaps[chan]) {
i2c_del_mux_adapter(data->virt_adaps[chan]);
data->virt_adaps[chan] = NULL;
}
}
kfree(data);
return 0;
}
static int as6812_32x_cpld_read_internal(struct i2c_client *client, u8 reg)
static int accton_i2c_cpld_mux_remove(struct i2c_client *client)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
struct accton_i2c_cpld_mux *data = i2c_get_clientdata(client);
const struct chip_desc *chip = &chips[data->type];
int chan;
while (retry) {
status = i2c_smbus_read_byte_data(client, reg);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
sysfs_remove_file(&client->dev.kobj, &ver.attr);
for (chan = 0; chan < chip->nchans; ++chan) {
if (data->virt_adaps[chan]) {
i2c_del_mux_adapter(data->virt_adaps[chan]);
data->virt_adaps[chan] = NULL;
}
break;
}
return status;
kfree(data);
accton_i2c_cpld_remove_client(client);
return 0;
}
static int as6812_32x_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value)
int as6812_32x_i2c_cpld_read(unsigned short cpld_addr, u8 reg)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_write_byte_data(client, reg, value);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
int as6812_32x_cpld_read(unsigned short cpld_addr, u8 reg)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as6812_32x_cpld_read_internal(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as6812_32x_cpld_read);
int as6812_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as6812_32x_cpld_write_internal(cpld_node->client, reg, value);
break;
}
}
if (cpld_node->client->addr == cpld_addr) {
ret = i2c_smbus_read_byte_data(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
return ret;
}
EXPORT_SYMBOL(as6812_32x_cpld_write);
EXPORT_SYMBOL(as6812_32x_i2c_cpld_read);
static struct i2c_driver as6812_32x_cpld_mux_driver = {
int as6812_32x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as6812_32x_i2c_cpld_write);
static struct i2c_driver accton_i2c_cpld_mux_driver = {
.driver = {
.name = "as6812_32x_cpld",
.owner = THIS_MODULE,
},
.probe = as6812_32x_cpld_mux_probe,
.remove = as6812_32x_cpld_mux_remove,
.id_table = as6812_32x_cpld_mux_id,
.probe = accton_i2c_cpld_mux_probe,
.remove = accton_i2c_cpld_mux_remove,
.id_table = accton_i2c_cpld_mux_id,
};
static int __init as6812_32x_cpld_mux_init(void)
static int __init accton_i2c_cpld_mux_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&as6812_32x_cpld_mux_driver);
mutex_init(&list_lock);
return i2c_add_driver(&accton_i2c_cpld_mux_driver);
}
static void __exit as6812_32x_cpld_mux_exit(void)
static void __exit accton_i2c_cpld_mux_exit(void)
{
i2c_del_driver(&as6812_32x_cpld_mux_driver);
i2c_del_driver(&accton_i2c_cpld_mux_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("Accton I2C CPLD mux driver");
MODULE_LICENSE("GPL");
module_init(as6812_32x_cpld_mux_init);
module_exit(as6812_32x_cpld_mux_exit);
module_init(accton_i2c_cpld_mux_init);
module_exit(accton_i2c_cpld_mux_exit);

View File

@@ -137,8 +137,8 @@ static ssize_t fan_set_duty_cycle(struct device *dev,
static ssize_t fan_show_value(struct device *dev,
struct device_attribute *da, char *buf);
extern int as6812_32x_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as6812_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern int as6812_32x_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as6812_32x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
/*******************/
@@ -257,12 +257,12 @@ static const struct attribute_group accton_as6812_32x_fan_group = {
static int accton_as6812_32x_fan_read_value(u8 reg)
{
return as6812_32x_cpld_read(0x60, reg);
return as6812_32x_i2c_cpld_read(0x60, reg);
}
static int accton_as6812_32x_fan_write_value(u8 reg, u8 value)
{
return as6812_32x_cpld_write(0x60, reg, value);
return as6812_32x_i2c_cpld_write(0x60, reg, value);
}
static void accton_as6812_32x_fan_update_device(struct device *dev)
@@ -385,6 +385,11 @@ static struct platform_driver accton_as6812_32x_fan_driver = {
static int __init accton_as6812_32x_fan_init(void)
{
int ret;
extern int platform_accton_as6812_32x(void);
if(!platform_accton_as6812_32x()) {
return -ENODEV;
}
ret = platform_driver_register(&accton_as6812_32x_fan_driver);
if (ret < 0) {

View File

@@ -29,8 +29,8 @@
#include <linux/leds.h>
#include <linux/slab.h>
extern int as6812_32x_cpld_read (unsigned short cpld_addr, u8 reg);
extern int as6812_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern int as6812_32x_i2c_cpld_read (unsigned short cpld_addr, u8 reg);
extern int as6812_32x_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern void led_classdev_unregister(struct led_classdev *led_cdev);
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
@@ -239,12 +239,12 @@ static u8 led_light_mode_to_reg_val(enum led_type type,
static int accton_as6812_32x_led_read_value(u8 reg)
{
return as6812_32x_cpld_read(0x60, reg);
return as6812_32x_i2c_cpld_read(0x60, reg);
}
static int accton_as6812_32x_led_write_value(u8 reg, u8 value)
{
return as6812_32x_cpld_write(0x60, reg, value);
return as6812_32x_i2c_cpld_write(0x60, reg, value);
}
static void accton_as6812_32x_led_update(void)
@@ -571,6 +571,11 @@ static int __init accton_as6812_32x_led_init(void)
{
int ret;
extern int platform_accton_as6812_32x(void);
if(!platform_accton_as6812_32x()) {
return -ENODEV;
}
ret = platform_driver_register(&accton_as6812_32x_led_driver);
if (ret < 0) {
goto exit;

View File

@@ -44,7 +44,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, char
static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t show_serial_number(struct device *dev, struct device_attribute *da,char *buf);
static int as6812_32x_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int as6812_32x_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as6812_32x_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
static int as6812_32x_psu_model_name_get(struct device *dev, int get_serial);
/* Addresses scanned
@@ -415,7 +415,7 @@ static struct as6812_32x_psu_data *as6812_32x_psu_update_device(struct device *d
data->valid = 0;
/* Read psu status */
status = as6812_32x_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET);
status = as6812_32x_i2c_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET);
if (status < 0) {
dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status);
@@ -435,9 +435,19 @@ exit:
return data;
}
module_i2c_driver(as6812_32x_psu_driver);
static int __init as6812_32x_psu_init(void)
{
return i2c_add_driver(&as6812_32x_psu_driver);
}
static void __exit as6812_32x_psu_exit(void)
{
i2c_del_driver(&as6812_32x_psu_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("as6812_32x_psu driver");
MODULE_LICENSE("GPL");
module_init(as6812_32x_psu_init);
module_exit(as6812_32x_psu_exit);

View File

@@ -24,17 +24,35 @@
*
***********************************************************/
#include <onlp/platformi/sfpi.h>
#include <onlplib/i2c.h>
#include <fcntl.h> /* For O_RDWR && open */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "platform_lib.h"
#include <onlplib/file.h>
#include "x86_64_accton_as6812_32x_int.h"
#include "x86_64_accton_as6812_32x_log.h"
#define PORT_BUS_INDEX(port) (port+2)
#define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom"
#define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/0-00%d/module_present_%d"
#define MODULE_PRESENT_ALL_ATTR_CPLD2 "/sys/bus/i2c/devices/0-0062/module_present_all"
#define MODULE_PRESENT_ALL_ATTR_CPLD3 "/sys/bus/i2c/devices/0-0064/module_present_all"
#define MAX_SFP_PATH 64
static char sfp_node_path[MAX_SFP_PATH] = {0};
#define FRONT_PORT_TO_CPLD_MUX_INDEX(port) (port+2)
static int
as6812_32x_sfp_node_read_int(char *node_path, int *value, int data_len)
{
return onlp_file_read_int(value, node_path);
}
static char*
as6812_32x_sfp_get_port_path(int port, char *node_name)
{
sprintf(sfp_node_path, "/sys/bus/i2c/devices/%d-0050/%s",
FRONT_PORT_TO_CPLD_MUX_INDEX(port),
node_name);
return sfp_node_path;
}
/************************************************************
*
@@ -73,13 +91,12 @@ onlp_sfpi_is_present(int port)
* Return < 0 if error.
*/
int present;
int addr = (port < 16) ? 62 : 64;
if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, addr, (port+1)) < 0) {
char* path = as6812_32x_sfp_get_port_path(port, "sfp_is_present");
if (as6812_32x_sfp_node_read_int(path, &present, 1) != 0) {
AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port);
return ONLP_STATUS_E_INTERNAL;
}
return present;
}
@@ -87,34 +104,27 @@ int
onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst)
{
uint32_t bytes[4];
uint32_t *ptr = bytes;
char* path;
FILE* fp;
/* Read present status of port 0~31 */
int addr;
path = as6812_32x_sfp_get_port_path(0, "sfp_is_present_all");
fp = fopen(path, "r");
for (addr = 62; addr <= 64; addr+=2) {
if (addr == 62) {
fp = fopen(MODULE_PRESENT_ALL_ATTR_CPLD2, "r");
}
else {
fp = fopen(MODULE_PRESENT_ALL_ATTR_CPLD3, "r");
}
if(fp == NULL) {
AIM_LOG_ERROR("Unable to open the module_present_all device file of CPLD(0x%d)", addr);
return ONLP_STATUS_E_INTERNAL;
}
int count = fscanf(fp, "%x %x", ptr+0, ptr+1);
fclose(fp);
if(count != 2) {
/* Likely a CPLD read timeout. */
AIM_LOG_ERROR("Unable to read all fields from the module_present_all device file of CPLD(0x%d)", addr);
return ONLP_STATUS_E_INTERNAL;
}
ptr += count;
if(fp == NULL) {
AIM_LOG_ERROR("Unable to open the sfp_is_present_all device file.");
return ONLP_STATUS_E_INTERNAL;
}
int count = fscanf(fp, "%x %x %x %x",
bytes+0,
bytes+1,
bytes+2,
bytes+3
);
fclose(fp);
if(count != AIM_ARRAYSIZE(bytes)) {
/* Likely a CPLD read timeout. */
AIM_LOG_ERROR("Unable to read all fields from the sfp_is_present_all device file.");
return ONLP_STATUS_E_INTERNAL;
}
/* Convert to 64 bit integer in port order */
@@ -143,25 +153,21 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst)
int
onlp_sfpi_eeprom_read(int port, uint8_t data[256])
{
char* path = as6812_32x_sfp_get_port_path(port, "sfp_eeprom");
/*
* Read the SFP eeprom into data[]
*
* Return MISSING if SFP is missing.
* Return OK if eeprom is read
*/
int size = 0;
memset(data, 0, 256);
if(onlp_file_read(data, 256, &size, PORT_EEPROM_FORMAT, PORT_BUS_INDEX(port)) != ONLP_STATUS_OK) {
if (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) {
AIM_LOG_ERROR("Unable to read eeprom from port(%d)\r\n", port);
return ONLP_STATUS_E_INTERNAL;
}
if (size != 256) {
AIM_LOG_ERROR("Unable to read eeprom from port(%d), size is different!\r\n", port);
return ONLP_STATUS_E_INTERNAL;
}
return ONLP_STATUS_OK;
}
@@ -170,4 +176,3 @@ onlp_sfpi_denit(void)
{
return ONLP_STATUS_OK;
}

View File

@@ -8,10 +8,9 @@ class OnlPlatform_x86_64_accton_as6812_32x_r0(OnlPlatformAccton,
SYS_OBJECT_ID=".6812.32"
def baseconfig(self):
self.insmod('optoe')
self.insmod('cpr_4011_4mxx')
self.insmod("ym2651y")
for m in [ 'cpld', 'fan', 'psu', 'leds' ]:
for m in [ 'cpld', 'fan', 'psu', 'leds', 'sfp' ]:
self.insmod("x86-64-accton-as6812-32x-%s.ko" % m)
########### initialize I2C bus 0 ###########
@@ -26,8 +25,9 @@ class OnlPlatform_x86_64_accton_as6812_32x_r0(OnlPlatformAccton,
# initialize QSFP port 1~32
for port in range(1, 33):
self.new_i2c_device('optoe1', 0x50, port+1)
subprocess.call('echo port%d > /sys/bus/i2c/devices/%d-0050/port_name' % (port, port+1), shell=True)
self.new_i2c_device('as6812_32x_port%d' % port,
0x50,
port+1)
########### initialize I2C bus 1 ###########
self.new_i2c_devices(