diff options
author | Vadim Pasternak <vadimp@nvidia.com> | 2023-02-08 08:33:24 +0200 |
---|---|---|
committer | Hans de Goede <hdegoede@redhat.com> | 2023-02-13 12:07:49 +0100 |
commit | 158cd83207768abdba86e408fed3169bb3ad3e9f (patch) | |
tree | 289b4e9bf03748806fdd8505f86bf4d25ff9d367 | |
parent | 0170f616f496fcaf25dde0fea042880d4af3089a (diff) |
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 <vadimp@nvidia.com>
Reviewed-by: Michael Shych <michaelsh@nvidia.com>
Link: https://lore.kernel.org/r/20230208063331.15560-8-vadimp@nvidia.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r-- | drivers/platform/x86/mlx-platform.c | 313 |
1 files changed, 204 insertions, 109 deletions
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 2d33d1e5d427..bd94d82ecce5 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -319,6 +319,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 @@ -330,6 +333,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; @@ -342,9 +346,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[] = { @@ -379,6 +385,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 */ @@ -6050,68 +6057,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) { @@ -6124,19 +6072,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; @@ -6146,7 +6085,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; } } @@ -6160,7 +6099,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; } } @@ -6173,7 +6112,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; } } @@ -6181,59 +6120,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) @@ -6244,13 +6166,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)"); |