platform/x86: mlx-platform: Add physical bus number auto detection
authorVadim Pasternak <vadimp@mellanox.com>
Tue, 13 Feb 2018 22:09:36 +0000 (22:09 +0000)
committerDarren Hart (VMware) <dvhart@infradead.org>
Fri, 23 Mar 2018 23:14:29 +0000 (16:14 -0700)
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>
drivers/platform/mellanox/mlxreg-hotplug.c
drivers/platform/x86/Kconfig
drivers/platform/x86/mlx-platform.c
include/linux/platform_data/mlxreg.h

index c1e1c4f254ce28cdc9127d9820cd5597b00f78eb..ea9e7f4479cad668dc261ee4386dee272f729888 100644 (file)
@@ -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;
index 1868aab0282a59b683ddc6ddaa55643d7b38b8a7..b528e44ad8ae9eb7c00fc8cde2591d68401724f8 100644 (file)
@@ -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
index 67f3c6d3698873e39267133602f31a4943b4f9b9..7a0bd24c1ae2dcd5304150d52a54d124192e753a 100644 (file)
 #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);
index 262910967476a30a382b2f25967e7f2e58bbb69f..2744cff1b297e198041e6982700d2dc9fb9d8c58 100644 (file)
@@ -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 */