platform/x86: mlx-platform: Add physical bus number auto detection

mlx-platform does not provide a bus number to i2c-mlxcpld, assuming it
is always one. On some x86 systems, other i2c drivers may probe before
i2c-mlxcpld, causing bus one to be busy.

Make mlx-platform determine which adapter number is free prior to
activating i2c-mlxpld, adjusting the mux base numbers accordingly.
Update the mlxreg-hotplug pdata similarly.

This adds an explicit mlx-platform build dependency on I2C, update the
Kconfig accordingly. Add the missing REGMAP dependency while we're at
it.

Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
[dvhart: Rewrite commit message more concisely]
[dvhart: Add build dependencies]
Signed-off-by: Darren Hart (VMware) <dvhart@infradead.org>
This commit is contained in:
Vadim Pasternak 2018-02-13 22:09:36 +00:00 committed by Darren Hart (VMware)
parent f709e1bfb0
commit ef0f62264b
4 changed files with 62 additions and 6 deletions

View File

@ -96,6 +96,8 @@ struct mlxreg_hotplug_priv_data {
static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
struct mlxreg_core_data *data) struct mlxreg_core_data *data)
{ {
struct mlxreg_core_hotplug_platform_data *pdata;
/* /*
* Return if adapter number is negative. It could be in case hotplug * Return if adapter number is negative. It could be in case hotplug
* event is not associated with hotplug device. * event is not associated with hotplug device.
@ -103,10 +105,12 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
if (data->hpdev.nr < 0) if (data->hpdev.nr < 0)
return 0; return 0;
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); pdata = dev_get_platdata(&priv->pdev->dev);
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
pdata->shift_nr);
if (!data->hpdev.adapter) { if (!data->hpdev.adapter) {
dev_err(priv->dev, "Failed to get adapter for bus %d\n", dev_err(priv->dev, "Failed to get adapter for bus %d\n",
data->hpdev.nr); data->hpdev.nr + pdata->shift_nr);
return -EFAULT; return -EFAULT;
} }
@ -114,8 +118,8 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
data->hpdev.brdinfo); data->hpdev.brdinfo);
if (!data->hpdev.client) { if (!data->hpdev.client) {
dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->type, data->hpdev.nr +
data->hpdev.brdinfo->addr); pdata->shift_nr, data->hpdev.brdinfo->addr);
i2c_put_adapter(data->hpdev.adapter); i2c_put_adapter(data->hpdev.adapter);
data->hpdev.adapter = NULL; data->hpdev.adapter = NULL;

View File

@ -1175,6 +1175,7 @@ config INTEL_TELEMETRY
config MLX_PLATFORM config MLX_PLATFORM
tristate "Mellanox Technologies platform support" tristate "Mellanox Technologies platform support"
depends on I2C && REGMAP
---help--- ---help---
This option enables system support for the Mellanox Technologies This option enables system support for the Mellanox Technologies
platform. The Mellanox systems provide data center networking platform. The Mellanox systems provide data center networking

View File

@ -85,6 +85,12 @@
#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0)
#define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0)
/* Default I2C parent bus number */
#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
/* Maximum number of possible physical buses equipped on system */
#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
/* Number of channels in group */ /* Number of channels in group */
#define MLXPLAT_CPLD_GRP_CHNL_NUM 8 #define MLXPLAT_CPLD_GRP_CHNL_NUM 8
@ -843,10 +849,48 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
{
struct i2c_adapter *search_adap;
int shift, i;
/* Scan adapters from expected id to verify it is free. */
*nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
search_adap = i2c_get_adapter(i);
if (search_adap) {
i2c_put_adapter(search_adap);
continue;
}
/* Return if expected parent adapter is free. */
if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
return 0;
break;
}
/* Return with error if free id for adapter is not found. */
if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
return -ENODEV;
/* Shift adapter ids, since expected parent adapter is not free. */
*nr = i;
for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
shift = *nr - mlxplat_mux_data[i].parent;
mlxplat_mux_data[i].parent = *nr;
mlxplat_mux_data[i].base_nr += shift;
if (shift > 0)
mlxplat_hotplug->shift_nr = shift;
}
return 0;
}
static int __init mlxplat_init(void) static int __init mlxplat_init(void)
{ {
struct mlxplat_priv *priv; struct mlxplat_priv *priv;
int i, err; int i, nr, err;
if (!dmi_check_system(mlxplat_dmi_table)) if (!dmi_check_system(mlxplat_dmi_table))
return -ENODEV; return -ENODEV;
@ -866,7 +910,12 @@ static int __init mlxplat_init(void)
} }
platform_set_drvdata(mlxplat_dev, priv); platform_set_drvdata(mlxplat_dev, priv);
priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, err = mlxplat_mlxcpld_verify_bus_topology(&nr);
if (nr < 0)
goto fail_alloc;
nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
NULL, 0); NULL, 0);
if (IS_ERR(priv->pdev_i2c)) { if (IS_ERR(priv->pdev_i2c)) {
err = PTR_ERR(priv->pdev_i2c); err = PTR_ERR(priv->pdev_i2c);

View File

@ -130,6 +130,7 @@ struct mlxreg_core_platform_data {
* @cell_low: location of low aggregation interrupt register; * @cell_low: location of low aggregation interrupt register;
* @mask_low: low aggregation interrupt common mask; * @mask_low: low aggregation interrupt common mask;
* @deferred_nr: I2C adapter number must be exist prior probing execution; * @deferred_nr: I2C adapter number must be exist prior probing execution;
* @shift_nr: I2C adapter numbers must be incremented by this value;
*/ */
struct mlxreg_core_hotplug_platform_data { struct mlxreg_core_hotplug_platform_data {
struct mlxreg_core_item *items; struct mlxreg_core_item *items;
@ -141,6 +142,7 @@ struct mlxreg_core_hotplug_platform_data {
u32 cell_low; u32 cell_low;
u32 mask_low; u32 mask_low;
int deferred_nr; int deferred_nr;
int shift_nr;
}; };
#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */