mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 01:41:39 +00:00
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:
parent
f709e1bfb0
commit
ef0f62264b
4 changed files with 62 additions and 6 deletions
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue