2018-01-23 18:39:14

by Vadim Pasternak

[permalink] [raw]
Subject: [patch v10 1/6] platform/mellanox: mlxreg-hotplug: Remove unused wait.h include

The driver does not make use of anything defined in wait.h.

Signed-off-by: Vadim Pasternak <[email protected]>
Acked-by: Andy Shevchenko <[email protected]>
---
v9->v10:
Fixes provideded by Darren:
- make separate patch for cleaning unused includes;
- do not remove spinlock.h from includes and make;
---
drivers/platform/mellanox/mlxreg-hotplug.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index 2866c76..c015fe9 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -42,7 +42,6 @@
#include <linux/platform_data/mlxreg.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <linux/wait.h>
#include <linux/workqueue.h>

/* Offset of event and mask registers from status register */
--
2.1.4



2018-01-23 18:39:15

by Vadim Pasternak

[permalink] [raw]
Subject: [patch v10 2/6] platform/mellanox: Group create/destroy with attribute functions

Move the mlxreg_hotplug_device_create and _destroy functions up with the
related attribute functions. No functional changes.

Signed-off-by: Vadim Pasternak <[email protected]>
Acked-by: Andy Shevchenko <[email protected]>
v9->v10:
Fixes provideded by Darren:
- make separate patch for relocating create/destroy;
---
drivers/platform/mellanox/mlxreg-hotplug.c | 70 +++++++++++++++---------------
1 file changed, 35 insertions(+), 35 deletions(-)

diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index c015fe9..1a04cb2 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -98,6 +98,41 @@ struct mlxreg_hotplug_priv_data {
u8 fan_cache;
};

+static int mlxreg_hotplug_device_create(struct device *dev,
+ struct mlxreg_hotplug_device *item)
+{
+ item->adapter = i2c_get_adapter(item->bus);
+ if (!item->adapter) {
+ dev_err(dev, "Failed to get adapter for bus %d\n",
+ item->bus);
+ return -EFAULT;
+ }
+
+ item->client = i2c_new_device(item->adapter, &item->brdinfo);
+ if (!item->client) {
+ dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
+ item->brdinfo.type, item->bus, item->brdinfo.addr);
+ i2c_put_adapter(item->adapter);
+ item->adapter = NULL;
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item)
+{
+ if (item->client) {
+ i2c_unregister_device(item->client);
+ item->client = NULL;
+ }
+
+ if (item->adapter) {
+ i2c_put_adapter(item->adapter);
+ item->adapter = NULL;
+ }
+}
+
static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -183,41 +218,6 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
return 0;
}

-static int mlxreg_hotplug_device_create(struct device *dev,
- struct mlxreg_hotplug_device *item)
-{
- item->adapter = i2c_get_adapter(item->bus);
- if (!item->adapter) {
- dev_err(dev, "Failed to get adapter for bus %d\n",
- item->bus);
- return -EFAULT;
- }
-
- item->client = i2c_new_device(item->adapter, &item->brdinfo);
- if (!item->client) {
- dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
- item->brdinfo.type, item->bus, item->brdinfo.addr);
- i2c_put_adapter(item->adapter);
- item->adapter = NULL;
- return -EFAULT;
- }
-
- return 0;
-}
-
-static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item)
-{
- if (item->client) {
- i2c_unregister_device(item->client);
- item->client = NULL;
- }
-
- if (item->adapter) {
- i2c_put_adapter(item->adapter);
- item->adapter = NULL;
- }
-}
-
static inline void
mlxreg_hotplug_work_helper(struct device *dev,
struct mlxreg_hotplug_device *item, u8 is_inverse,
--
2.1.4


2018-01-23 18:39:27

by Vadim Pasternak

[permalink] [raw]
Subject: [patch v10 3/6] platform/mellanox: Rename i2c bus to nr

Use Linux convention of nr instead of bus for i2c adapter number.

Signed-off-by: Vadim Pasternak <[email protected]>
Acked-by: Andy Shevchenko <[email protected]>
---
v9->v10:
Fixes provideded by Darren:
- refactore commit into smaller functional changes;
---
drivers/platform/mellanox/mlxreg-hotplug.c | 6 +++---
drivers/platform/x86/mlx-platform.c | 16 ++++++++--------
include/linux/platform_data/mlxreg.h | 4 ++--
3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index 1a04cb2..5f0b4ff 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -101,17 +101,17 @@ struct mlxreg_hotplug_priv_data {
static int mlxreg_hotplug_device_create(struct device *dev,
struct mlxreg_hotplug_device *item)
{
- item->adapter = i2c_get_adapter(item->bus);
+ item->adapter = i2c_get_adapter(item->nr);
if (!item->adapter) {
dev_err(dev, "Failed to get adapter for bus %d\n",
- item->bus);
+ item->nr);
return -EFAULT;
}

item->client = i2c_new_device(item->adapter, &item->brdinfo);
if (!item->client) {
dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
- item->brdinfo.type, item->bus, item->brdinfo.addr);
+ item->brdinfo.type, item->nr, item->brdinfo.addr);
i2c_put_adapter(item->adapter);
item->adapter = NULL;
return -EFAULT;
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 0fbec1f..5601714 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -141,41 +141,41 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = {
{
.brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
- .bus = 10,
+ .nr = 10,
},
{
.brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
- .bus = 10,
+ .nr = 10,
},
};

static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = {
{
.brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
- .bus = 10,
+ .nr = 10,
},
{
.brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
- .bus = 10,
+ .nr = 10,
},
};

static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = {
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 11,
+ .nr = 11,
},
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 12,
+ .nr = 12,
},
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 13,
+ .nr = 13,
},
{
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .bus = 14,
+ .nr = 14,
},
};

diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
index 8dcbb8e..ffbcb78 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -39,7 +39,7 @@
* @adapter: I2C device adapter;
* @client: I2C device client;
* @brdinfo: device board information;
- * @bus: I2C bus, where device is attached;
+ * @nr: I2C device adapter number, to which device is to be attached;
*
* Structure represents I2C hotplug device static data (board topology) and
* dynamic data (related kernel objects handles).
@@ -48,7 +48,7 @@ struct mlxreg_hotplug_device {
struct i2c_adapter *adapter;
struct i2c_client *client;
struct i2c_board_info brdinfo;
- u16 bus;
+ int nr;
};

/**
--
2.1.4


2018-01-23 18:40:03

by Vadim Pasternak

[permalink] [raw]
Subject: [patch v10 6/6] platform/mellanox: mlxreg-hotplug: Enable building for ARM

Add ARM in addition to X86 as supported architectures in the Mellanox
Hotplug Platform driver Kconfig entry.

Signed-off-by: Vadim Pasternak <[email protected]>
---
v10->v9
v9->v8
Comments pointed out by Darren:
- Leave in this patch only the code related to ARM architecture.
Move other code to a separate patch, since it is not related to
subject.
---
drivers/platform/mellanox/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
index 0fb25687..591bccd 100644
--- a/drivers/platform/mellanox/Kconfig
+++ b/drivers/platform/mellanox/Kconfig
@@ -5,7 +5,7 @@

menuconfig MELLANOX_PLATFORM
bool "Platform support for Mellanox hardware"
- depends on X86 || COMPILE_TEST
+ depends on X86 || ARM || COMPILE_TEST
---help---
Say Y here to get to see options for platform support for
Mellanox systems. This option alone does not add any kernel code.
--
2.1.4


2018-01-23 18:40:18

by Vadim Pasternak

[permalink] [raw]
Subject: [patch v10 5/6] platform/mellanox: mlxreg-hotplug: Add check for negative adapter number value

Verify before creation of hotplug device if the associated adapter number
is negative. It could be in case hotplug event is not associated with
hotplug device.

Signed-off-by: Vadim Pasternak <[email protected]>
---
v10->v9:
Fixes added by Vadim:
- add this patch to the series;
---
drivers/platform/mellanox/mlxreg-hotplug.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index f841379..b0d7587 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -96,6 +96,14 @@ struct mlxreg_hotplug_priv_data {
static int mlxreg_hotplug_device_create(struct device *dev,
struct mlxreg_core_data *data)
{
+ /*
+ * Return if adapter number is negative. Return if adapter number is
+ * negative. It could be in case hotplug event is not associated with
+ * hotplug device.
+ */
+ if (data->hpdev.nr < 0)
+ return 0;
+
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
if (!data->hpdev.adapter) {
dev_err(dev, "Failed to get adapter for bus %d\n",
--
2.1.4


2018-01-23 18:40:39

by Vadim Pasternak

[permalink] [raw]
Subject: [patch v10 4/6] platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface

Restructure mlxreg header for unification of hotplug item definitions.

Unify hotplug items to allow any kind of item (power controller, fan
eeprom, psu eeprom, asic health) in common way.

Use a hardware independent regmap interface, enabling the support of
hotplug events over programmable devices attached to different bus
types, such as I2C, LPC, or SPI. Add a device node to the
mlxreg_core_data structure.

Signed-off-by: Vadim Pasternak <[email protected]>
Acked-by: Andy Shevchenko <[email protected]>
---
v10->v9:
Fixes provided by Vadim:
- add missed description of pdev_hotplug for struct mlxplat_priv;
- remove struct mlxplat_mlxcpld_regmap_context, which contains only
the field with base address. Instead obtain locally defined base
address by devm_ioport_map in mlxplat_init and pass it to
devm_regmap_init;
- modify mlxplat_mlxcpld_reg_read/write to use directly pointer to
context;
v8->v9:
Fixes provideded by Vadim:
- Simplify exit path in mlxreg-hotplug
- Cleanup local variable declarations
driver. Separate inline initial assignments when it cleans up the
declaration block.
v7->v8
v6->v7
Fixes added by Vadim:
- Remove include <linux/io.h> in mlxreg-hotplug.c in this patch.
v5->v6:
Fixes added by Vadim:
- rename mlxreg_core_led_platform_data to common name
mlxreg_core_platform_data;
- add cell_low and mask_low fields to
mlxreg_core_hotplug_platform_data for low aggregation interrupt
registers and check for these fields in mlxreg_hotplug_set_irq and
mlxreg_hotplug_unset_irq;
v4->v5:
Comments pointed out by Andy:
- use suffix OFFSET instead of ADDR for aggregation registers;
- return back MACROS;
- rearrange mlxreg_hotplug_attr_init routine;
---
drivers/platform/mellanox/Kconfig | 1 +
drivers/platform/mellanox/mlxreg-hotplug.c | 615 +++++++++++++++++------------
drivers/platform/x86/mlx-platform.c | 222 ++++++++---
include/linux/platform_data/mlxreg.h | 126 ++++--
4 files changed, 626 insertions(+), 338 deletions(-)

diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
index d735292..0fb25687 100644
--- a/drivers/platform/mellanox/Kconfig
+++ b/drivers/platform/mellanox/Kconfig
@@ -16,6 +16,7 @@ if MELLANOX_PLATFORM

config MLXREG_HOTPLUG
tristate "Mellanox platform hotplug driver support"
+ depends on REGMAP
depends on HWMON
depends on I2C
---help---
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index 5f0b4ff..f841379 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -37,99 +37,96 @@
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
-#include <linux/io.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/platform_data/mlxreg.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+#include <linux/regmap.h>
#include <linux/workqueue.h>

-/* Offset of event and mask registers from status register */
+/* Offset of event and mask registers from status register. */
#define MLXREG_HOTPLUG_EVENT_OFF 1
-#define MLXREG_HOTPLUG_MASK_OFF 2
-#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
+#define MLXREG_HOTPLUG_MASK_OFF 2
+#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1

-#define MLXREG_HOTPLUG_ATTRS_NUM 8
+/* ASIC health parameters. */
+#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
+#define MLXREG_HOTPLUG_RST_CNTR 3

-/**
- * enum mlxreg_hotplug_attr_type - sysfs attributes for hotplug events:
- * @MLXREG_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute;
- * @MLXREG_HOTPLUG_ATTR_TYPE_PWR: power cable attribute;
- * @MLXREG_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute;
- */
-enum mlxreg_hotplug_attr_type {
- MLXREG_HOTPLUG_ATTR_TYPE_PSU,
- MLXREG_HOTPLUG_ATTR_TYPE_PWR,
- MLXREG_HOTPLUG_ATTR_TYPE_FAN,
-};
+#define MLXREG_HOTPLUG_ATTRS_MAX 24

/**
* struct mlxreg_hotplug_priv_data - platform private data:
- * @irq: platform interrupt number;
+ * @irq: platform device interrupt number;
* @pdev: platform device;
* @plat: platform data;
+ * @dwork: delayed work template;
+ * @lock: spin lock;
* @hwmon: hwmon device;
* @mlxreg_hotplug_attr: sysfs attributes array;
* @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
* @group: sysfs attribute group;
* @groups: list of sysfs attribute group for hwmon registration;
- * @dwork: delayed work template;
- * @lock: spin lock;
+ * @cell: location of top aggregation interrupt register;
+ * @mask: top aggregation interrupt common mask;
* @aggr_cache: last value of aggregation register status;
- * @psu_cache: last value of PSU register status;
- * @pwr_cache: last value of power register status;
- * @fan_cache: last value of FAN register status;
*/
struct mlxreg_hotplug_priv_data {
int irq;
+ struct device *dev;
struct platform_device *pdev;
struct mlxreg_hotplug_platform_data *plat;
+ struct regmap *regmap;
+ struct delayed_work dwork_irq;
+ struct delayed_work dwork;
+ spinlock_t lock; /* sync with interrupt */
struct device *hwmon;
- struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_NUM + 1];
+ struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
struct sensor_device_attribute_2
- mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_NUM];
+ mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
struct attribute_group group;
const struct attribute_group *groups[2];
- struct delayed_work dwork;
- spinlock_t lock;
- u8 aggr_cache;
- u8 psu_cache;
- u8 pwr_cache;
- u8 fan_cache;
+ u32 cell;
+ u32 mask;
+ u32 aggr_cache;
+ bool after_probe;
};

static int mlxreg_hotplug_device_create(struct device *dev,
- struct mlxreg_hotplug_device *item)
+ struct mlxreg_core_data *data)
{
- item->adapter = i2c_get_adapter(item->nr);
- if (!item->adapter) {
+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
+ if (!data->hpdev.adapter) {
dev_err(dev, "Failed to get adapter for bus %d\n",
- item->nr);
+ data->hpdev.nr);
return -EFAULT;
}

- item->client = i2c_new_device(item->adapter, &item->brdinfo);
- if (!item->client) {
+ data->hpdev.client = i2c_new_device(data->hpdev.adapter,
+ data->hpdev.brdinfo);
+ if (!data->hpdev.client) {
dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
- item->brdinfo.type, item->nr, item->brdinfo.addr);
- i2c_put_adapter(item->adapter);
- item->adapter = NULL;
+ data->hpdev.brdinfo->type, data->hpdev.nr,
+ data->hpdev.brdinfo->addr);
+ i2c_put_adapter(data->hpdev.adapter);
+ data->hpdev.adapter = NULL;
return -EFAULT;
}

return 0;
}

-static void mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_device *item)
+static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
{
- if (item->client) {
- i2c_unregister_device(item->client);
- item->client = NULL;
+ if (data->hpdev.client) {
+ i2c_unregister_device(data->hpdev.client);
+ data->hpdev.client = NULL;
}

- if (item->adapter) {
- i2c_put_adapter(item->adapter);
- item->adapter = NULL;
+ if (data->hpdev.adapter) {
+ i2c_put_adapter(data->hpdev.adapter);
+ data->hpdev.adapter = NULL;
}
}

@@ -137,41 +134,76 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev);
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
+ struct mlxreg_core_hotplug_platform_data *pdata;
int index = to_sensor_dev_attr_2(attr)->index;
int nr = to_sensor_dev_attr_2(attr)->nr;
- u8 reg_val = 0;
-
- switch (nr) {
- case MLXREG_HOTPLUG_ATTR_TYPE_PSU:
- /* Bit = 0 : PSU is present. */
- reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index));
- break;
-
- case MLXREG_HOTPLUG_ATTR_TYPE_PWR:
- /* Bit = 1 : power cable is attached. */
- reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index %
- priv->plat->pwr_count));
- break;
-
- case MLXREG_HOTPLUG_ATTR_TYPE_FAN:
- /* Bit = 0 : FAN is present. */
- reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index %
- priv->plat->fan_count));
- break;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ u32 regval;
+ int ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items + nr;
+ data = item->data + index;
+
+ ret = regmap_read(priv->regmap, data->reg, &regval);
+ if (ret)
+ return ret;
+
+ if (item->health) {
+ regval &= data->mask;
+ } else {
+ /* Bit = 0 : functional if item->inversed is true. */
+ if (item->inversed)
+ regval = !(regval & data->mask);
+ else
+ regval = !!(regval & data->mask);
}

- return sprintf(buf, "%u\n", reg_val);
+ return sprintf(buf, "%u\n", regval);
}

#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
+
static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
{
- int num_attrs = priv->plat->psu_count + priv->plat->pwr_count +
- priv->plat->fan_count;
- int i;
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ int num_attrs = 0, id = 0, i, j;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ /* Go over all kinds of items - psu, pwr, fan. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ num_attrs += item->count;
+ data = item->data;
+ /* Go over all units within the item. */
+ for (j = 0; j < item->count; j++, data++, id++) {
+ PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
+ PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
+ GFP_KERNEL,
+ data->label);
+
+ if (!PRIV_ATTR(id)->name) {
+ dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
+ id);
+ return -ENOMEM;
+ }
+
+ PRIV_DEV_ATTR(id).dev_attr.attr.name =
+ PRIV_ATTR(id)->name;
+ PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
+ PRIV_DEV_ATTR(id).dev_attr.show =
+ mlxreg_hotplug_attr_show;
+ PRIV_DEV_ATTR(id).nr = i;
+ PRIV_DEV_ATTR(id).index = j;
+ sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
+ }
+ }

priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
sizeof(struct attribute *),
@@ -179,38 +211,6 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
if (!priv->group.attrs)
return -ENOMEM;

- for (i = 0; i < num_attrs; i++) {
- PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr;
-
- if (i < priv->plat->psu_count) {
- PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
- GFP_KERNEL, "psu%u", i + 1);
- PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PSU;
- } else if (i < priv->plat->psu_count + priv->plat->pwr_count) {
- PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
- GFP_KERNEL, "pwr%u", i %
- priv->plat->pwr_count + 1);
- PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_PWR;
- } else {
- PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
- GFP_KERNEL, "fan%u", i %
- priv->plat->fan_count + 1);
- PRIV_DEV_ATTR(i).nr = MLXREG_HOTPLUG_ATTR_TYPE_FAN;
- }
-
- if (!PRIV_ATTR(i)->name) {
- dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
- i + 1);
- return -ENOMEM;
- }
-
- PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name;
- PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO;
- PRIV_DEV_ATTR(i).dev_attr.show = mlxreg_hotplug_attr_show;
- PRIV_DEV_ATTR(i).index = i;
- sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr);
- }
-
priv->group.attrs = priv->mlxreg_hotplug_attr;
priv->groups[0] = &priv->group;
priv->groups[1] = NULL;
@@ -218,20 +218,13 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
return 0;
}

-static inline void
-mlxreg_hotplug_work_helper(struct device *dev,
- struct mlxreg_hotplug_device *item, u8 is_inverse,
- u16 offset, u8 mask, u8 *cache)
+static void
+mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
+ struct mlxreg_core_item *item)
{
- u8 val, asserted;
- int bit;
-
- /* Mask event. */
- outb(0, offset + MLXREG_HOTPLUG_MASK_OFF);
- /* Read status. */
- val = inb(offset) & mask;
- asserted = *cache ^ val;
- *cache = val;
+ struct mlxreg_core_data *data;
+ u32 asserted, regval, bit;
+ int ret;

/*
* Validate if item related to received signal type is valid.
@@ -241,86 +234,177 @@ mlxreg_hotplug_work_helper(struct device *dev,
* signals from other devices if any.
*/
if (unlikely(!item)) {
- dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n",
- offset, mask);
+ dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
+ item->reg, item->mask);
+
return;
}

+ /* Mask event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
+ 0);
+ if (ret)
+ goto out;
+
+ /* Read status. */
+ ret = regmap_read(priv->regmap, item->reg, &regval);
+ if (ret)
+ goto out;
+
+ /* Set asserted bits and save last status. */
+ regval &= item->mask;
+ asserted = item->cache ^ regval;
+ item->cache = regval;
+
for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
- if (val & BIT(bit)) {
- if (is_inverse)
- mlxreg_hotplug_device_destroy(item + bit);
+ data = item->data + bit;
+ if (regval & BIT(bit)) {
+ if (item->inversed)
+ mlxreg_hotplug_device_destroy(data);
else
- mlxreg_hotplug_device_create(dev, item + bit);
+ mlxreg_hotplug_device_create(priv->dev, data);
} else {
- if (is_inverse)
- mlxreg_hotplug_device_create(dev, item + bit);
+ if (item->inversed)
+ mlxreg_hotplug_device_create(priv->dev, data);
else
- mlxreg_hotplug_device_destroy(item + bit);
+ mlxreg_hotplug_device_destroy(data);
}
}

/* Acknowledge event. */
- outb(0, offset + MLXREG_HOTPLUG_EVENT_OFF);
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
+ 0);
+ if (ret)
+ goto out;
+
/* Unmask event. */
- outb(mask, offset + MLXREG_HOTPLUG_MASK_OFF);
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
+ item->mask);
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+static void
+mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
+ struct mlxreg_core_item *item)
+{
+ struct mlxreg_core_data *data = item->data;
+ u32 regval;
+ int i, ret;
+
+ for (i = 0; i < item->count; i++, data++) {
+ /* Mask event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_MASK_OFF, 0);
+ if (ret)
+ goto out;
+
+ /* Read status. */
+ ret = regmap_read(priv->regmap, data->reg, &regval);
+ if (ret)
+ goto out;
+
+ regval &= data->mask;
+ item->cache = regval;
+ if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
+ if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
+ !priv->after_probe) {
+ mlxreg_hotplug_device_create(priv->dev, data);
+ data->attached = true;
+ }
+ } else {
+ if (data->attached) {
+ mlxreg_hotplug_device_destroy(data);
+ data->attached = false;
+ data->health_cntr = 0;
+ }
+ }
+
+ /* Acknowledge event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+ if (ret)
+ goto out;
+
+ /* Unmask event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_MASK_OFF, data->mask);
+ if (ret)
+ goto out;
+ }
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
}

/*
- * mlxreg_hotplug_work_handler - performs traversing of CPLD interrupt
+ * mlxreg_hotplug_work_handler - performs traversing of device interrupt
* registers according to the below hierarchy schema:
*
- * Aggregation registers (status/mask)
- * PSU registers: *---*
- * *-----------------* | |
- * |status/event/mask|----->| * |
- * *-----------------* | |
- * Power registers: | |
- * *-----------------* | |
- * |status/event/mask|----->| * |---> CPU
- * *-----------------* | |
- * FAN registers:
- * *-----------------* | |
- * |status/event/mask|----->| * |
- * *-----------------* | |
- * *---*
+ * Aggregation registers (status/mask)
+ * PSU registers: *---*
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * Power registers: | |
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * FAN registers: | |--> CPU
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * ASIC registers: | |
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * *---*
+ *
* In case some system changed are detected: FAN in/out, PSU in/out, power
- * cable attached/detached, relevant device is created or destroyed.
+ * cable attached/detached, ASIC health good/bad, relevant device is created
+ * or destroyed.
*/
static void mlxreg_hotplug_work_handler(struct work_struct *work)
{
- struct mlxreg_hotplug_priv_data *priv = container_of(work,
- struct mlxreg_hotplug_priv_data, dwork.work);
- u8 val, aggr_asserted;
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_hotplug_priv_data *priv;
+ struct mlxreg_core_item *item;
+ u32 regval, aggr_asserted;
unsigned long flags;
+ int i, ret;
+
+ priv = container_of(work, struct mlxreg_hotplug_priv_data,
+ dwork_irq.work);
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;

/* Mask aggregation event. */
- outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF);
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
+ if (ret < 0)
+ goto out;
+
/* Read aggregation status. */
- val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask;
- aggr_asserted = priv->aggr_cache ^ val;
- priv->aggr_cache = val;
-
- /* Handle PSU configuration changes. */
- if (aggr_asserted & priv->plat->top_aggr_psu_mask)
- mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu,
- 1, priv->plat->psu_reg_offset,
- priv->plat->psu_mask,
- &priv->psu_cache);
-
- /* Handle power cable configuration changes. */
- if (aggr_asserted & priv->plat->top_aggr_pwr_mask)
- mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr,
- 0, priv->plat->pwr_reg_offset,
- priv->plat->pwr_mask,
- &priv->pwr_cache);
-
- /* Handle FAN configuration changes. */
- if (aggr_asserted & priv->plat->top_aggr_fan_mask)
- mlxreg_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan,
- 1, priv->plat->fan_reg_offset,
- priv->plat->fan_mask,
- &priv->fan_cache);
+ ret = regmap_read(priv->regmap, pdata->cell, &regval);
+ if (ret)
+ goto out;
+
+ regval &= pdata->mask;
+ aggr_asserted = priv->aggr_cache ^ regval;
+ priv->aggr_cache = regval;
+
+ /* Handle topology and health configuration changes. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ if (aggr_asserted & item->aggr_mask) {
+ if (item->health)
+ mlxreg_hotplug_health_work_helper(priv, item);
+ else
+ mlxreg_hotplug_work_helper(priv, item);
+ }
+ }

if (aggr_asserted) {
spin_lock_irqsave(&priv->lock, flags);
@@ -335,8 +419,8 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
* validates that no new signals have been received during
* masking.
*/
- cancel_delayed_work(&priv->dwork);
- schedule_delayed_work(&priv->dwork, 0);
+ cancel_delayed_work(&priv->dwork_irq);
+ schedule_delayed_work(&priv->dwork_irq, 0);

spin_unlock_irqrestore(&priv->lock, flags);

@@ -344,92 +428,119 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
}

/* Unmask aggregation event (no need acknowledge). */
- outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
- MLXREG_HOTPLUG_AGGR_MASK_OFF);
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
+
+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
}

-static void mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
+static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
{
- /* Clear psu presense event. */
- outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
- /* Set psu initial status as mask and unmask psu event. */
- priv->psu_cache = priv->plat->psu_mask;
- outb(priv->plat->psu_mask, priv->plat->psu_reg_offset +
- MLXREG_HOTPLUG_MASK_OFF);
-
- /* Clear power cable event. */
- outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
- /* Keep power initial status as zero and unmask power event. */
- outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset +
- MLXREG_HOTPLUG_MASK_OFF);
-
- /* Clear fan presense event. */
- outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
- /* Set fan initial status as mask and unmask fan event. */
- priv->fan_cache = priv->plat->fan_mask;
- outb(priv->plat->fan_mask, priv->plat->fan_reg_offset +
- MLXREG_HOTPLUG_MASK_OFF);
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ int i, ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ for (i = 0; i < pdata->counter; i++, item++) {
+ /* Clear group presense event. */
+ ret = regmap_write(priv->regmap, item->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+ if (ret)
+ goto out;
+
+ /* Set group initial status as mask and unmask group event. */
+ if (item->inversed) {
+ item->cache = item->mask;
+ ret = regmap_write(priv->regmap, item->reg +
+ MLXREG_HOTPLUG_MASK_OFF,
+ item->mask);
+ if (ret)
+ goto out;
+ }
+ }

/* Keep aggregation initial status as zero and unmask events. */
- outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
- MLXREG_HOTPLUG_AGGR_MASK_OFF);
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
+ if (ret)
+ goto out;
+
+ /* Keep low aggregation initial status as zero and unmask events. */
+ if (pdata->cell_low) {
+ ret = regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF,
+ pdata->mask_low);
+ if (ret)
+ goto out;
+ }

/* Invoke work handler for initializing hot plug devices setting. */
- mlxreg_hotplug_work_handler(&priv->dwork.work);
+ mlxreg_hotplug_work_handler(&priv->dwork_irq.work);

+ out:
+ if (ret)
+ dev_err(priv->dev, "Failed to set interrupts.\n");
enable_irq(priv->irq);
+ return ret;
}

static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
{
- int i;
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ int count, i, j;

+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
disable_irq(priv->irq);
- cancel_delayed_work_sync(&priv->dwork);
-
- /* Mask aggregation event. */
- outb(0, priv->plat->top_aggr_offset + MLXREG_HOTPLUG_AGGR_MASK_OFF);
-
- /* Mask psu presense event. */
- outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_MASK_OFF);
- /* Clear psu presense event. */
- outb(0, priv->plat->psu_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
-
- /* Mask power cable event. */
- outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_MASK_OFF);
- /* Clear power cable event. */
- outb(0, priv->plat->pwr_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
-
- /* Mask fan presense event. */
- outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_MASK_OFF);
- /* Clear fan presense event. */
- outb(0, priv->plat->fan_reg_offset + MLXREG_HOTPLUG_EVENT_OFF);
-
- /* Remove all the attached devices. */
- for (i = 0; i < priv->plat->psu_count; i++)
- mlxreg_hotplug_device_destroy(priv->plat->psu + i);
+ cancel_delayed_work_sync(&priv->dwork_irq);

- for (i = 0; i < priv->plat->pwr_count; i++)
- mlxreg_hotplug_device_destroy(priv->plat->pwr + i);
+ /* Mask low aggregation event, if defined. */
+ if (pdata->cell_low)
+ regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);

- for (i = 0; i < priv->plat->fan_count; i++)
- mlxreg_hotplug_device_destroy(priv->plat->fan + i);
+ /* Mask aggregation event. */
+ regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
+ 0);
+
+ /* Clear topology configurations. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ data = item->data;
+ /* Mask group presense event. */
+ regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
+ 0);
+ /* Clear group presense event. */
+ regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+
+ /* Remove all the attached devices in group. */
+ count = item->count;
+ for (j = 0; j < count; j++, data++)
+ mlxreg_hotplug_device_destroy(data);
+ }
}

static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
{
- struct mlxreg_hotplug_priv_data *priv =
- (struct mlxreg_hotplug_priv_data *)dev;
+ struct mlxreg_hotplug_priv_data *priv;
+
+ priv = (struct mlxreg_hotplug_priv_data *)dev;

/* Schedule work task for immediate execution.*/
- schedule_delayed_work(&priv->dwork, 0);
+ schedule_delayed_work(&priv->dwork_irq, 0);

return IRQ_HANDLED;
}

static int mlxreg_hotplug_probe(struct platform_device *pdev)
{
- struct mlxreg_hotplug_platform_data *pdata;
+ struct mlxreg_core_hotplug_platform_data *pdata;
struct mlxreg_hotplug_priv_data *priv;
int err;

@@ -443,31 +554,42 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;

- priv->pdev = pdev;
- priv->plat = pdata;
-
- priv->irq = platform_get_irq(pdev, 0);
- if (priv->irq < 0) {
- dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
- priv->irq);
- return priv->irq;
+ if (pdata->irq) {
+ priv->irq = pdata->irq;
+ } else {
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
+ priv->irq);
+ return priv->irq;
+ }
}

+ priv->regmap = pdata->regmap;
+ priv->dev = pdev->dev.parent;
+ priv->pdev = pdev;
+
err = devm_request_irq(&pdev->dev, priv->irq,
- mlxreg_hotplug_irq_handler, 0, pdev->name,
- priv);
+ mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
+ | IRQF_SHARED, "mlxreg-hotplug", priv);
if (err) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
return err;
}
- disable_irq(priv->irq);

- INIT_DELAYED_WORK(&priv->dwork, mlxreg_hotplug_work_handler);
+ disable_irq(priv->irq);
spin_lock_init(&priv->lock);
+ INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
+ /* Perform initial interrupts setup. */
+ mlxreg_hotplug_set_irq(priv);
+
+ priv->after_probe = true;
+ dev_set_drvdata(&pdev->dev, priv);

err = mlxreg_hotplug_attr_init(priv);
if (err) {
- dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err);
+ dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
+ err);
return err;
}

@@ -479,17 +601,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
return PTR_ERR(priv->hwmon);
}

- platform_set_drvdata(pdev, priv);
-
- /* Perform initial interrupts setup. */
- mlxreg_hotplug_set_irq(priv);
-
return 0;
}

static int mlxreg_hotplug_remove(struct platform_device *pdev)
{
- struct mlxreg_hotplug_priv_data *priv = platform_get_drvdata(pdev);
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);

/* Clean interrupts setup. */
mlxreg_hotplug_unset_irq(priv);
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 5601714..81a7306 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -35,20 +35,22 @@
#include <linux/dmi.h>
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_data/i2c-mux-reg.h>
#include <linux/platform_data/mlxreg.h>
+#include <linux/regmap.h>

#define MLX_PLAT_DEVICE_NAME "mlxplat"

/* LPC bus IO offsets */
#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
-#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a
-#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558
-#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564
-#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588
+#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
+#define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
+#define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
+#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -81,6 +83,7 @@
/* mlxplat_priv - platform private data
* @pdev_i2c - i2c controller platform device
* @pdev_mux - array of mux platform devices
+ * @pdev_hotplug - hotplug platform devices
*/
struct mlxplat_priv {
struct platform_device *pdev_i2c;
@@ -138,78 +141,184 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
};

/* Platform hotplug devices */
-static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = {
+static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
{
- .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) },
- .nr = 10,
+ I2C_BOARD_INFO("24c02", 0x51),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) },
- .nr = 10,
+ I2C_BOARD_INFO("24c02", 0x50),
},
};

-static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = {
+static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
{
- .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) },
- .nr = 10,
+ I2C_BOARD_INFO("dps460", 0x59),
},
{
- .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) },
- .nr = 10,
+ I2C_BOARD_INFO("dps460", 0x58),
},
};

-static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = {
+static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .nr = 11,
+ I2C_BOARD_INFO("24c32", 0x50),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .nr = 12,
+ I2C_BOARD_INFO("24c32", 0x50),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .nr = 13,
+ I2C_BOARD_INFO("24c32", 0x50),
},
{
- .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) },
- .nr = 14,
+ I2C_BOARD_INFO("24c32", 0x50),
},
};

/* Platform hotplug default data */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
+ {
+ .label = "psu1",
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
+ .hpdev.nr = 10,
+ },
+ {
+ .label = "psu2",
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
+ .hpdev.nr = 10,
+ },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
+ {
+ .label = "pwr1",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
+ .hpdev.nr = 10,
+ },
+ {
+ .label = "pwr2",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
+ .hpdev.nr = 10,
+ },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
+ {
+ .label = "fan1",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
+ .hpdev.nr = 11,
+ },
+ {
+ .label = "fan2",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
+ .hpdev.nr = 12,
+ },
+ {
+ .label = "fan3",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(2),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
+ .hpdev.nr = 13,
+ },
+ {
+ .label = "fan4",
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = BIT(3),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
+ .hpdev.nr = 14,
+ },
+};
+
+static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
+ {
+ .data = mlxplat_mlxcpld_default_psu_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = MLXPLAT_CPLD_PSU_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_pwr_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+ .inversed = 0,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_fan_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = MLXPLAT_CPLD_FAN_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
+ .inversed = 1,
+ .health = false,
+ },
+};
+
static
-struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_default_data = {
- .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
- .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
- .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
- .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR,
- .psu_mask = MLXPLAT_CPLD_PSU_MASK,
- .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
- .psu = mlxplat_mlxcpld_psu,
- .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
- .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
- .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
- .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
- .pwr = mlxplat_mlxcpld_pwr,
- .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
- .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
- .fan_mask = MLXPLAT_CPLD_FAN_MASK,
- .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
- .fan = mlxplat_mlxcpld_fan,
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
+ .items = mlxplat_mlxcpld_default_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
};

/* Platform hotplug MSN21xx system family data */
+static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
+ {
+ .data = mlxplat_mlxcpld_default_pwr_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+ .inversed = 0,
+ .health = false,
+ },
+};
+
static
-struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
- .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR,
- .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
- .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX,
- .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
- .pwr_mask = MLXPLAT_CPLD_PWR_MASK,
- .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
+ .items = mlxplat_mlxcpld_msn21xx_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
+};
+
+static int
+mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ *val = ioread8(context + reg);
+ return 0;
+}
+
+static int
+mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ iowrite8(val, context + reg);
+ return 0;
+}
+
+static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 255,
+ .reg_read = mlxplat_mlxcpld_reg_read,
+ .reg_write = mlxplat_mlxcpld_reg_write,
};

static struct resource mlxplat_mlxcpld_resources[] = {
@@ -217,7 +326,7 @@ static struct resource mlxplat_mlxcpld_resources[] = {
};

static struct platform_device *mlxplat_dev;
-static struct mlxreg_hotplug_platform_data *mlxplat_hotplug;
+static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;

static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{
@@ -289,6 +398,7 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
static int __init mlxplat_init(void)
{
struct mlxplat_priv *priv;
+ void __iomem *base;
int i, err;

if (!dmi_check_system(mlxplat_dmi_table))
@@ -328,6 +438,20 @@ static int __init mlxplat_init(void)
}
}

+ base = devm_ioport_map(&mlxplat_dev->dev,
+ mlxplat_lpc_resources[1].start, 1);
+ if (IS_ERR(base)) {
+ err = PTR_ERR(base);
+ goto fail_platform_mux_register;
+ }
+
+ mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
+ base, &mlxplat_mlxcpld_regmap_config);
+ if (IS_ERR(mlxplat_hotplug->regmap)) {
+ err = PTR_ERR(mlxplat_hotplug->regmap);
+ goto fail_platform_mux_register;
+ }
+
priv->pdev_hotplug = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxreg-hotplug",
PLATFORM_DEVID_NONE,
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
index ffbcb78..dda0d2e 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -34,8 +34,11 @@
#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
#define __LINUX_PLATFORM_DATA_MLXREG_H

+#define MLXREG_CORE_LABEL_MAX_SIZE 32
+
/**
* struct mlxreg_hotplug_device - I2C device data:
+ *
* @adapter: I2C device adapter;
* @client: I2C device client;
* @brdinfo: device board information;
@@ -47,52 +50,95 @@
struct mlxreg_hotplug_device {
struct i2c_adapter *adapter;
struct i2c_client *client;
- struct i2c_board_info brdinfo;
+ struct i2c_board_info *brdinfo;
int nr;
};

/**
- * struct mlxreg_hotplug_platform_data - device platform data:
- * @top_aggr_offset: offset of top aggregation interrupt register;
- * @top_aggr_mask: top aggregation interrupt common mask;
- * @top_aggr_psu_mask: top aggregation interrupt PSU mask;
- * @psu_reg_offset: offset of PSU interrupt register;
- * @psu_mask: PSU interrupt mask;
- * @psu_count: number of equipped replaceable PSUs;
- * @psu: pointer to PSU devices data array;
- * @top_aggr_pwr_mask: top aggregation interrupt power mask;
- * @pwr_reg_offset: offset of power interrupt register
- * @pwr_mask: power interrupt mask;
- * @pwr_count: number of power sources;
- * @pwr: pointer to power devices data array;
- * @top_aggr_fan_mask: top aggregation interrupt FAN mask;
- * @fan_reg_offset: offset of FAN interrupt register;
- * @fan_mask: FAN interrupt mask;
- * @fan_count: number of equipped replaceable FANs;
- * @fan: pointer to FAN devices data array;
+ * struct mlxreg_core_data - attributes control data:
+ *
+ * @label: attribute label;
+ * @label: attribute register offset;
+ * @reg: attribute register;
+ * @mask: attribute access mask;
+ * @mode: access mode;
+ * @bit: attribute effective bit;
+ * @np - pointer to node platform associated with attribute;
+ * @hpdev - hotplug device data;
+ * @health_cntr: dynamic device health indication counter;
+ * @attached: true if device has been attached after good health indication;
+ */
+struct mlxreg_core_data {
+ char label[MLXREG_CORE_LABEL_MAX_SIZE];
+ u32 reg;
+ u32 mask;
+ u32 bit;
+ umode_t mode;
+ struct device_node *np;
+ struct mlxreg_hotplug_device hpdev;
+ u8 health_cntr;
+ bool attached;
+};
+
+/**
+ * struct mlxreg_core_item - same type components controlled by the driver:
+ *
+ * @data: component data;
+ * @aggr_mask: group aggregation mask;
+ * @reg: group interrupt status register;
+ * @mask: group interrupt mask;
+ * @cache: last status value for elements fro the same group;
+ * @count: number of available elements in the group;
+ * @ind: element's index inside the group;
+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
+ * @health: true if device has health indication, false in other case;
+ */
+struct mlxreg_core_item {
+ struct mlxreg_core_data *data;
+ u32 aggr_mask;
+ u32 reg;
+ u32 mask;
+ u32 cache;
+ u8 count;
+ u8 ind;
+ u8 inversed;
+ u8 health;
+};
+
+/**
+ * struct mlxreg_core_platform_data - platform data:
+ *
+ * @led_data: led private data;
+ * @regmap: register map of parent device;
+ * @counter: number of instances;
+ */
+struct mlxreg_core_platform_data {
+ struct mlxreg_core_data *data;
+ void *regmap;
+ int counter;
+};
+
+/**
+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data:
*
- * Structure represents board platform data, related to system hotplug events,
- * like FAN, PSU, power cable insertion and removing. This data provides the
- * number of hot-pluggable devices and hardware description for event handling.
+ * @items: same type components with the hotplug capability;
+ * @irq: platform interrupt number;
+ * @regmap: register map of parent device;
+ * @counter: number of the components with the hotplug capability;
+ * @cell: location of top aggregation interrupt register;
+ * @mask: top aggregation interrupt common mask;
+ * @cell_low: location of low aggregation interrupt register;
+ * @mask_low: low aggregation interrupt common mask;
*/
-struct mlxreg_hotplug_platform_data {
- u16 top_aggr_offset;
- u8 top_aggr_mask;
- u8 top_aggr_psu_mask;
- u16 psu_reg_offset;
- u8 psu_mask;
- u8 psu_count;
- struct mlxreg_hotplug_device *psu;
- u8 top_aggr_pwr_mask;
- u16 pwr_reg_offset;
- u8 pwr_mask;
- u8 pwr_count;
- struct mlxreg_hotplug_device *pwr;
- u8 top_aggr_fan_mask;
- u16 fan_reg_offset;
- u8 fan_mask;
- u8 fan_count;
- struct mlxreg_hotplug_device *fan;
+struct mlxreg_core_hotplug_platform_data {
+ struct mlxreg_core_item *items;
+ int irq;
+ void *regmap;
+ int counter;
+ u32 cell;
+ u32 mask;
+ u32 cell_low;
+ u32 mask_low;
};

#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
--
2.1.4


2018-01-23 22:59:29

by Darren Hart

[permalink] [raw]
Subject: Re: [patch v10 4/6] platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface

On Tue, Jan 23, 2018 at 08:34:23PM +0000, Vadim Pasternak wrote:
> Restructure mlxreg header for unification of hotplug item definitions.
>
> Unify hotplug items to allow any kind of item (power controller, fan
> eeprom, psu eeprom, asic health) in common way.
>
> Use a hardware independent regmap interface, enabling the support of
> hotplug events over programmable devices attached to different bus
> types, such as I2C, LPC, or SPI. Add a device node to the
> mlxreg_core_data structure.
>
> Signed-off-by: Vadim Pasternak <[email protected]>
> Acked-by: Andy Shevchenko <[email protected]>
> ---
> v10->v9:
> Fixes provided by Vadim:
> - add missed description of pdev_hotplug for struct mlxplat_priv;

I didn't see this in the diff from my version to this one.

> - remove struct mlxplat_mlxcpld_regmap_context, which contains only
> the field with base address. Instead obtain locally defined base
> address by devm_ioport_map in mlxplat_init and pass it to
> devm_regmap_init;
> - modify mlxplat_mlxcpld_reg_read/write to use directly pointer to
> context;

Also adds incorrect conversion of tabs to spaces in at least 3 locations ...

I had also corrected various typos and the copyright statement, as well as
reworked the commit messages. So at this point, I'd rather see these as changes
on top of what I have cleaned up.

Please compare what you have here with:
https://github.com/dvhart/linux-pdx86/tree/review-dvhart-mellanox-v10

And send me any changes strictly on top of that.

Are you anticipating any additional changes beyond those in this version?

--
Darren Hart
VMware Open Source Technology Center

2018-01-24 17:06:10

by Vadim Pasternak

[permalink] [raw]
Subject: RE: [patch v10 4/6] platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface



> -----Original Message-----
> From: Darren Hart [mailto:[email protected]]
> Sent: Wednesday, January 24, 2018 12:58 AM
> To: Vadim Pasternak <[email protected]>
> Cc: [email protected]; [email protected]; linux-
> [email protected]; [email protected]; [email protected]
> Subject: Re: [patch v10 4/6] platform/mellanox: mlxreg-hotplug: Modify to use a
> regmap interface
>
> On Tue, Jan 23, 2018 at 08:34:23PM +0000, Vadim Pasternak wrote:
> > Restructure mlxreg header for unification of hotplug item definitions.
> >
> > Unify hotplug items to allow any kind of item (power controller, fan
> > eeprom, psu eeprom, asic health) in common way.
> >
> > Use a hardware independent regmap interface, enabling the support of
> > hotplug events over programmable devices attached to different bus
> > types, such as I2C, LPC, or SPI. Add a device node to the
> > mlxreg_core_data structure.
> >
> > Signed-off-by: Vadim Pasternak <[email protected]>
> > Acked-by: Andy Shevchenko <[email protected]>
> > ---
> > v10->v9:
> > Fixes provided by Vadim:
> > - add missed description of pdev_hotplug for struct mlxplat_priv;
>
> I didn't see this in the diff from my version to this one.
>
> > - remove struct mlxplat_mlxcpld_regmap_context, which contains only
> > the field with base address. Instead obtain locally defined base
> > address by devm_ioport_map in mlxplat_init and pass it to
> > devm_regmap_init;
> > - modify mlxplat_mlxcpld_reg_read/write to use directly pointer to
> > context;
>
> Also adds incorrect conversion of tabs to spaces in at least 3 locations ...
>
> I had also corrected various typos and the copyright statement, as well as
> reworked the commit messages. So at this point, I'd rather see these as changes
> on top of what I have cleaned up.
>
> Please compare what you have here with:
> https://github.com/dvhart/linux-pdx86/tree/review-dvhart-mellanox-v10
>
> And send me any changes strictly on top of that.

Hi Darren,

I'll send you four patches on top review-dvhart-mellanox-v10.
There are
- Patch to simplify IO access to regmap context.
- Register map configuration extension with IO access verification
callbacks.
- Adding check for negative adapter number value in hotplug;
- Adding validation of return code of mlxreg_hotplug_device_create.
This is instead of what have been removed in "FIXME:"

But there were two Kbuild issues with these two patches:
[4/9] FIXME platform/mellanox: Remove redundant dev_err messages on device_create
[6/8] platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface

This is because of incorrect order of patches: FIXME platform/mellanox
uses filed nr which replaces field
bus in Rename-i2c-bus-to-nr.
0003-FIXME-platform-mellanox-Remove-redundant-dev_err-mes.patch
0004-platform-mellanox-Group-create-destroy-with-attribut.patch
0005-platform-mellanox-Rename-i2c-bus-to-nr.patch

So, I'll resend the above three patches marked v11 "re-ordered".
If it's not good I'll redo it according to your input.

>
> Are you anticipating any additional changes beyond those in this version?
>

Additionally, after we are done with this series, I'd like to add:
- several new systems to mlx-platform;
- new module to mellanox folder with sysfs access to some special registers,
like resets and reset causes registers (mlxreg-io);
- make configuration and activation of mlxreg-io in mlx-patfrom;

And later, after I am done with upstream work with leds-mlxreg driver, I'd
like to add configuration and activation of this driver in mlx-patform as well.

Thanks,
Vadim.

> --
> Darren Hart
> VMware Open Source Technology Center