From f00081a6e0b7af5a0b85db3121afe3cc6a62f9e7 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 11 Dec 2022 11:08:07 +0200 Subject: [PATCH backport 5.10 072/150] platform: mellanox: Split logic in init and exit flow Split logic in mlxplat_init()/mlxplat_exit() routines. Separate initialization of I2C infrastructure and others platform drivers. Motivation is to provide synchronization between I2C bus and mux drivers and other drivers using this infrastructure. I2C main bus and MUX busses are implemented in FPGA logic. On some new systems the numbers allocated for these busses could be variable depending on order of initialization of I2C native busses. Since bus numbers are passed to some other platform drivers during initialization flow, it is necessary to synchronize completion of I2C infrastructure drivers and activation of rest of drivers. Thus initialization flow will be performed in synchronized order. Signed-off-by: Vadim Pasternak --- drivers/platform/x86/mlx-platform.c | 313 ++++++++++++++++++---------- 1 file changed, 204 insertions(+), 109 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 199f22d72..05a630135 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -321,6 +321,9 @@ /* Default value for PWM control register for rack switch system */ #define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4 +#define MLXPLAT_I2C_MAIN_BUS_NOTIFIED 0x01 +#define MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED 0x02 + /* mlxplat_priv - platform private data * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices @@ -332,6 +335,7 @@ * @regmap: device register map * @hotplug_resources: system hotplug resources * @hotplug_resources_size: size of system hotplug resources + * @hi2c_main_init_status: init status of I2C main bus */ struct mlxplat_priv { struct platform_device *pdev_i2c; @@ -344,9 +348,11 @@ struct mlxplat_priv { void *regmap; struct resource *hotplug_resources; unsigned int hotplug_resources_size; + u8 i2c_main_init_status; }; static struct platform_device *mlxplat_dev; +static int mlxplat_i2c_main_complition_notify(void *handle, int id); /* Regions for LPC I2C controller and LPC base register space */ static const struct resource mlxplat_lpc_resources[] = { @@ -381,6 +387,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, + .completion_notify = mlxplat_i2c_main_complition_notify, }; /* Platform default channels */ @@ -6413,68 +6420,9 @@ static void mlxplat_post_exit(void) mlxplat_lpc_cpld_device_exit(); } -static int __init mlxplat_init(void) +static int mlxplat_post_init(struct mlxplat_priv *priv) { - unsigned int hotplug_resources_size; - struct resource *hotplug_resources; - struct mlxplat_priv *priv; - int i, j, nr, err; - - if (!dmi_check_system(mlxplat_dmi_table)) - return -ENODEV; - - err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); - if (err) - return err; - - priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), - GFP_KERNEL); - if (!priv) { - err = -ENOMEM; - goto fail_alloc; - } - platform_set_drvdata(mlxplat_dev, priv); - - priv->hotplug_resources = hotplug_resources; - priv->hotplug_resources_size = hotplug_resources_size; - - if (!mlxplat_regmap_config) - mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; - - priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, - &mlxplat_mlxcpld_regmap_ctx, - mlxplat_regmap_config); - if (IS_ERR(priv->regmap)) { - err = PTR_ERR(priv->regmap); - goto fail_alloc; - } - - err = mlxplat_mlxcpld_verify_bus_topology(&nr); - if (nr < 0) - goto fail_alloc; - - nr = (nr == mlxplat_max_adap_num) ? -1 : nr; - if (mlxplat_i2c) - mlxplat_i2c->regmap = priv->regmap; - priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", - nr, priv->hotplug_resources, - priv->hotplug_resources_size, - mlxplat_i2c, sizeof(*mlxplat_i2c)); - if (IS_ERR(priv->pdev_i2c)) { - err = PTR_ERR(priv->pdev_i2c); - goto fail_alloc; - } - - for (i = 0; i < mlxplat_mux_num; i++) { - priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, - "i2c-mux-reg", i, NULL, 0, - &mlxplat_mux_data[i], - sizeof(mlxplat_mux_data[i])); - if (IS_ERR(priv->pdev_mux[i])) { - err = PTR_ERR(priv->pdev_mux[i]); - goto fail_platform_mux_register; - } - } + int i = 0, err; /* Add hotplug driver */ if (mlxplat_hotplug) { @@ -6487,19 +6435,10 @@ static int __init mlxplat_init(void) mlxplat_hotplug, sizeof(*mlxplat_hotplug)); if (IS_ERR(priv->pdev_hotplug)) { err = PTR_ERR(priv->pdev_hotplug); - goto fail_platform_mux_register; + goto fail_platform_hotplug_register; } } - /* Set default registers. */ - for (j = 0; j < mlxplat_regmap_config->num_reg_defaults; j++) { - err = regmap_write(priv->regmap, - mlxplat_regmap_config->reg_defaults[j].reg, - mlxplat_regmap_config->reg_defaults[j].def); - if (err) - goto fail_platform_mux_register; - } - /* Add LED driver. */ if (mlxplat_led) { mlxplat_led->regmap = priv->regmap; @@ -6509,7 +6448,7 @@ static int __init mlxplat_init(void) sizeof(*mlxplat_led)); if (IS_ERR(priv->pdev_led)) { err = PTR_ERR(priv->pdev_led); - goto fail_platform_hotplug_register; + goto fail_platform_leds_register; } } @@ -6523,7 +6462,7 @@ static int __init mlxplat_init(void) sizeof(*mlxplat_regs_io)); if (IS_ERR(priv->pdev_io_regs)) { err = PTR_ERR(priv->pdev_io_regs); - goto fail_platform_led_register; + goto fail_platform_io_register; } } @@ -6536,7 +6475,7 @@ static int __init mlxplat_init(void) sizeof(*mlxplat_fan)); if (IS_ERR(priv->pdev_fan)) { err = PTR_ERR(priv->pdev_fan); - goto fail_platform_io_regs_register; + goto fail_platform_fan_register; } } @@ -6547,59 +6486,42 @@ static int __init mlxplat_init(void) err = mlxplat_mlxcpld_check_wd_capability(priv->regmap); if (err) goto fail_platform_wd_register; - for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { - if (mlxplat_wd_data[j]) { - mlxplat_wd_data[j]->regmap = priv->regmap; - priv->pdev_wd[j] = - platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", j, - NULL, 0, mlxplat_wd_data[j], - sizeof(*mlxplat_wd_data[j])); - if (IS_ERR(priv->pdev_wd[j])) { - err = PTR_ERR(priv->pdev_wd[j]); + for (i = 0; i < MLXPLAT_CPLD_WD_MAX_DEVS; i++) { + if (mlxplat_wd_data[i]) { + mlxplat_wd_data[i]->regmap = priv->regmap; + priv->pdev_wd[i] = + platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", i, + NULL, 0, mlxplat_wd_data[i], + sizeof(*mlxplat_wd_data[i])); + if (IS_ERR(priv->pdev_wd[i])) { + err = PTR_ERR(priv->pdev_wd[i]); goto fail_platform_wd_register; } } } - /* Sync registers with hardware. */ - regcache_mark_dirty(priv->regmap); - err = regcache_sync(priv->regmap); - if (err) - goto fail_platform_wd_register; - return 0; fail_platform_wd_register: - while (--j >= 0) - platform_device_unregister(priv->pdev_wd[j]); - if (mlxplat_fan) - platform_device_unregister(priv->pdev_fan); -fail_platform_io_regs_register: + while (--i >= 0) + platform_device_unregister(priv->pdev_wd[i]); +fail_platform_fan_register: if (mlxplat_regs_io) platform_device_unregister(priv->pdev_io_regs); -fail_platform_led_register: +fail_platform_io_register: if (mlxplat_led) platform_device_unregister(priv->pdev_led); -fail_platform_hotplug_register: +fail_platform_leds_register: if (mlxplat_hotplug) platform_device_unregister(priv->pdev_hotplug); -fail_platform_mux_register: - while (--i >= 0) - platform_device_unregister(priv->pdev_mux[i]); - platform_device_unregister(priv->pdev_i2c); -fail_alloc: - +fail_platform_hotplug_register: return err; } -module_init(mlxplat_init); -static void __exit mlxplat_exit(void) +static void mlxplat_pre_exit(struct mlxplat_priv *priv) { - struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; - if (pm_power_off) - pm_power_off = NULL; for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) platform_device_unregister(priv->pdev_wd[i]); if (priv->pdev_fan) @@ -6610,13 +6532,186 @@ static void __exit mlxplat_exit(void) platform_device_unregister(priv->pdev_led); if (priv->pdev_hotplug) platform_device_unregister(priv->pdev_hotplug); +} + +static int +mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, + struct i2c_adapter *adapters[]) +{ + struct mlxplat_priv *priv = handle; + + return mlxplat_post_init(priv); +} - for (i = mlxplat_mux_num - 1; i >= 0 ; i--) +static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) +{ + int i, err; + + if (!priv->pdev_i2c) { + priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_NOTIFIED; + return 0; + } + + priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED; + for (i = 0; i < mlxplat_mux_num; i++) { + priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, + "i2c-mux-reg", i, NULL, 0, + &mlxplat_mux_data[i], + sizeof(mlxplat_mux_data[i])); + if (IS_ERR(priv->pdev_mux[i])) { + err = PTR_ERR(priv->pdev_mux[i]); + goto fail_platform_mux_register; + } + } + + return mlxplat_i2c_mux_complition_notify(priv, NULL, NULL); + +fail_platform_mux_register: + while (--i >= 0) platform_device_unregister(priv->pdev_mux[i]); + return err; +} + +static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv) +{ + int i; + + for (i = mlxplat_mux_num - 1; i >= 0 ; i--) { + if (priv->pdev_mux[i]) + platform_device_unregister(priv->pdev_mux[i]); + } - platform_device_unregister(priv->pdev_i2c); mlxplat_post_exit(); } + +static int mlxplat_i2c_main_complition_notify(void *handle, int id) +{ + struct mlxplat_priv *priv = handle; + + return mlxplat_i2c_mux_topolgy_init(priv); +} + +static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) +{ + int nr, err; + + if (!mlxplat_i2c) + return 0; + + err = mlxplat_mlxcpld_verify_bus_topology(&nr); + if (nr < 0) + goto fail_mlxplat_mlxcpld_verify_bus_topology; + + nr = (nr == mlxplat_max_adap_num) ? -1 : nr; + mlxplat_i2c->regmap = priv->regmap; + mlxplat_i2c->handle = priv; + + priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", + nr, priv->hotplug_resources, + priv->hotplug_resources_size, + mlxplat_i2c, sizeof(*mlxplat_i2c)); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); + goto fail_platform_i2c_register; + } + + if (priv->i2c_main_init_status == MLXPLAT_I2C_MAIN_BUS_NOTIFIED) { + err = mlxplat_i2c_mux_topolgy_init(priv); + if (err) + goto fail_mlxplat_i2c_mux_topolgy_init; + } + + return 0; + +fail_mlxplat_i2c_mux_topolgy_init: +fail_platform_i2c_register: +fail_mlxplat_mlxcpld_verify_bus_topology: + return err; +} + +static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv) +{ + mlxplat_i2c_mux_topolgy_exit(priv); + if (priv->pdev_i2c) + platform_device_unregister(priv->pdev_i2c); +} + +static int __init mlxplat_init(void) +{ + unsigned int hotplug_resources_size; + struct resource *hotplug_resources; + struct mlxplat_priv *priv; + int i, err; + + if (!dmi_check_system(mlxplat_dmi_table)) + return -ENODEV; + + err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); + if (err) + return err; + + priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), + GFP_KERNEL); + if (!priv) { + err = -ENOMEM; + goto fail_alloc; + } + platform_set_drvdata(mlxplat_dev, priv); + priv->hotplug_resources = hotplug_resources; + priv->hotplug_resources_size = hotplug_resources_size; + + if (!mlxplat_regmap_config) + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; + + priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL, + &mlxplat_mlxcpld_regmap_ctx, + mlxplat_regmap_config); + if (IS_ERR(priv->regmap)) { + err = PTR_ERR(priv->regmap); + goto fail_alloc; + } + + /* Set default registers. */ + for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) { + err = regmap_write(priv->regmap, + mlxplat_regmap_config->reg_defaults[i].reg, + mlxplat_regmap_config->reg_defaults[i].def); + if (err) + goto fail_regmap_write; + } + + err = mlxplat_i2c_main_init(priv); + if (err) + goto fail_mlxplat_i2c_main_init; + + /* Sync registers with hardware. */ + regcache_mark_dirty(priv->regmap); + err = regcache_sync(priv->regmap); + if (err) + goto fail_regcache_sync; + + return 0; + +fail_regcache_sync: + mlxplat_pre_exit(priv); +fail_mlxplat_i2c_main_init: +fail_regmap_write: +fail_alloc: + mlxplat_post_exit(); + + return err; +} +module_init(mlxplat_init); + +static void __exit mlxplat_exit(void) +{ + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + + if (pm_power_off) + pm_power_off = NULL; + mlxplat_pre_exit(priv); + mlxplat_i2c_main_exit(priv); +} module_exit(mlxplat_exit); MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); -- 2.20.1