Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef0f6226 authored by Vadim Pasternak's avatar Vadim Pasternak Committed by Darren Hart (VMware)
Browse files

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: default avatarVadim Pasternak <vadimp@mellanox.com>
[dvhart: Rewrite commit message more concisely]
[dvhart: Add build dependencies]
Signed-off-by: default avatarDarren Hart (VMware) <dvhart@infradead.org>
parent f709e1bf
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -96,6 +96,8 @@ struct mlxreg_hotplug_priv_data {
static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
					struct mlxreg_core_data *data)
{
	struct mlxreg_core_hotplug_platform_data *pdata;

	/*
	 * Return if adapter number is negative. It could be in case hotplug
	 * 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)
		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) {
		dev_err(priv->dev, "Failed to get adapter for bus %d\n",
			data->hpdev.nr);
			data->hpdev.nr + pdata->shift_nr);
		return -EFAULT;
	}

@@ -114,8 +118,8 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
					    data->hpdev.brdinfo);
	if (!data->hpdev.client) {
		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->addr);
			data->hpdev.brdinfo->type, data->hpdev.nr +
			pdata->shift_nr, data->hpdev.brdinfo->addr);

		i2c_put_adapter(data->hpdev.adapter);
		data->hpdev.adapter = NULL;
+1 −0
Original line number Diff line number Diff line
@@ -1175,6 +1175,7 @@ config INTEL_TELEMETRY

config MLX_PLATFORM
	tristate "Mellanox Technologies platform support"
	depends on I2C && REGMAP
	---help---
	  This option enables system support for the Mellanox Technologies
	  platform. The Mellanox systems provide data center networking
+51 −2
Original line number Diff line number Diff line
@@ -85,6 +85,12 @@
#define MLXPLAT_CPLD_FAN_MASK		GENMASK(3, 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 */
#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);

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)
{
	struct mlxplat_priv *priv;
	int i, err;
	int i, nr, err;

	if (!dmi_check_system(mlxplat_dmi_table))
		return -ENODEV;
@@ -866,7 +910,12 @@ static int __init mlxplat_init(void)
	}
	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);
	if (IS_ERR(priv->pdev_i2c)) {
		err = PTR_ERR(priv->pdev_i2c);
+2 −0
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ struct mlxreg_core_platform_data {
 * @cell_low: location of low aggregation interrupt register;
 * @mask_low: low aggregation interrupt common mask;
 * @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_item *items;
@@ -141,6 +142,7 @@ struct mlxreg_core_hotplug_platform_data {
	u32 cell_low;
	u32 mask_low;
	int deferred_nr;
	int shift_nr;
};

#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */