Skip to content
Permalink
Browse files
TMP: platform/mellanox
Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
  • Loading branch information
vadimp-nvidia authored and Jiri Pirko committed Jun 17, 2021
1 parent 651ac4a commit 998a3bef90771cf08f5ee530ac739dcf3f3a8a05
Show file tree
Hide file tree
Showing 4 changed files with 461 additions and 62 deletions.
@@ -115,7 +115,7 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
*/
if (data->hpdev.nr < 0)
return 0;

dev_info(priv->dev, "label %s action %d kind %d\n", data->label, data->hpdev.action, kind);
pdata = dev_get_platdata(&priv->pdev->dev);
switch (data->hpdev.action) {
case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
@@ -150,6 +150,8 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data)
mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data,
pdata->regmap);
/* Pass parent hotplug device handle to underlying device. */
data->notifier = data->hpdev.notifier;
data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev,
brdinfo->type,
data->hpdev.nr,
@@ -163,8 +165,8 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
break;
}

if (data->hpdev.user_handler)
return data->hpdev.user_handler(data->hpdev.handle, kind, 1);
if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1);

return 0;
}
@@ -176,6 +178,9 @@ mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
{
/* Notify user by sending hwmon uevent. */
mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
dev_info(priv->dev, "label %s action %d kind %d client %p\n", data->label, data->hpdev.action, kind, data->hpdev.client);
if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0);

switch (data->hpdev.action) {
case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
@@ -196,9 +201,6 @@ mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
default:
break;
}

if (data->hpdev.user_handler)
data->hpdev.user_handler(data->hpdev.handle, kind, 0);
}

static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
@@ -27,11 +27,7 @@
#define MLXREG_LC_REG_FPGA1_MVER_OFFSET 0x25df
#define MLXREG_LC_REG_MAX_POWER_OFFSET 0x25f1
#define MLXREG_LC_REG_CONFIG_OFFSET 0x25fb
#define MLXREG_LC_REG_MAX 0x2600

#define MLXREG_LC_SYNCED BIT(0)
#define MLXREG_LC_READY BIT(1)
#define MLXREG_LC_ENABLE (MLXREG_LC_SYNCED | MLXREG_LC_READY)
#define MLXREG_LC_REG_MAX 0x3fff

/**
* enum mlxreg_lc_type - line cards types
@@ -42,6 +38,21 @@ enum mlxreg_lc_type {
MLXREG_LC_SN4800_C16 = 0x0000,
};

/**
* enum mlxreg_lc_state - line cards state
*
* @MLXREG_LC_INITIALIZED: line card is initialized;
* @MLXREG_LC_POWERD: line card is powered;
* @MLXREG_LC_SYNCED: line card is syncronized between hardware and firmware;
*/
enum mlxreg_lc_state {
MLXREG_LC_INITIALIZED = BIT(0),
MLXREG_LC_POWERED = BIT(1),
MLXREG_LC_SYNCED = BIT(2),
};

#define MLXREG_LC_CONFIGURED (MLXREG_LC_INITIALIZED | MLXREG_LC_POWERED | MLXREG_LC_SYNCED)

/* mlxreg_lc - device private data
* @dev: platform device;
* @lock: line card lock;
@@ -76,7 +87,7 @@ struct mlxreg_lc {
int aux_devs_num;
struct mlxreg_hotplug_device *main_devs;
int main_devs_num;
u8 state;
enum mlxreg_lc_state state;
};

static bool mlxreg_lc_writeable_reg(struct device *dev, unsigned int reg)
@@ -411,7 +422,7 @@ mlxreg_lc_create_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotpl
struct mlxreg_hotplug_device *dev = devs;
int i;

/* Create static I2C device feeding by auxiliary power. */
/* Create static I2C device feeding by auxiliary or main power. */
for (i = 0; i < size; i++, dev++) {
dev->client = i2c_new_client_device(dev->adapter, dev->brdinfo);
if (IS_ERR(dev->client)) {
@@ -430,7 +441,6 @@ mlxreg_lc_create_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotpl
dev = devs + i;
i2c_unregister_device(dev->client);
dev->client = NULL;
dev->adapter = NULL;
}
return IS_ERR(dev->client);
}
@@ -442,12 +452,11 @@ mlxreg_lc_destroy_static_devices(struct mlxreg_lc *mlxreg_lc, struct mlxreg_hotp
struct mlxreg_hotplug_device *dev = devs;
int i;

/* Destroy static I2C device feeding by auxiliary power. */
/* Destroy static I2C device feeding by auxiliary or main power. */
for (i = 0; i < size; i++, dev++) {
if (dev->client) {
i2c_unregister_device(dev->client);
dev->client = NULL;
dev->adapter = NULL;
}
}
}
@@ -457,16 +466,23 @@ static int mlxreg_lc_power_on_off(struct mlxreg_lc *mlxreg_lc, u8 action)
u32 regval;
int err;

mutex_lock(&mlxreg_lc->lock);

err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, &regval);
if (err)
return err;
goto regmap_read_fail;

if (action)
regval |= BIT(mlxreg_lc->data->slot);
regval |= BIT(mlxreg_lc->data->slot - 1);
else
regval &= ~BIT(mlxreg_lc->data->slot);
regval &= ~BIT(mlxreg_lc->data->slot - 1);

err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval);

return regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_pwr, regval);
mutex_unlock(&mlxreg_lc->lock);

regmap_read_fail:
return err;
}

static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action)
@@ -489,9 +505,9 @@ static int mlxreg_lc_enable_disable(struct mlxreg_lc *mlxreg_lc, bool action)
goto regmap_read_fail;

if (action)
regval |= BIT(mlxreg_lc->data->slot);
regval |= BIT(mlxreg_lc->data->slot - 1);
else
regval &= ~BIT(mlxreg_lc->data->slot);
regval &= ~BIT(mlxreg_lc->data->slot - 1);

err = regmap_write(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_ena, regval);

@@ -527,43 +543,82 @@ mlxreg_lc_sn4800_c16_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap,
return 0;
}

static void
mlxreg_lc_state_update(struct mlxreg_lc *mlxreg_lc, enum mlxreg_lc_state state, u8 action)
{
mutex_lock(&mlxreg_lc->lock);

if (action)
mlxreg_lc->state |= state;
else
mlxreg_lc->state &= ~state;

mutex_unlock(&mlxreg_lc->lock);
}

/*
* Callback is to be called from mlxreg-hotplug driver to notify about line card about received
* event.
*/
static int mlxreg_lc_event_handler(void *handle, enum mlxreg_hotplug_kind kind, u8 action)
{
struct mlxreg_lc *mlxreg_lc = handle;
int err;
int err = 0;

dev_info(mlxreg_lc->dev, "linecard#%d state %d event kind %d action %d\n",
mlxreg_lc->data->slot, mlxreg_lc->state, kind, action);

if (!(mlxreg_lc->state & MLXREG_LC_INITIALIZED))
return 0;

switch (kind) {
case MLXREG_HOTPLUG_LC_VERIFIED:
err = mlxreg_lc_power_on_off(mlxreg_lc, action);
case MLXREG_HOTPLUG_LC_SYNCED:
/*
* Synchronization event - hardware and firmware are synchronized. Power on/off
* line card - to allow/disallow main power source.
*/
mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, action);
/* Power line card if it is not powered yet. */
if (!(mlxreg_lc->state & MLXREG_LC_POWERED) && action) {
err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
if (err)
return err;
}
/* In case line card is configured - enable it. */
if (mlxreg_lc->state & MLXREG_LC_CONFIGURED && action)
err = mlxreg_lc_enable_disable(mlxreg_lc, 1);
break;
case MLXREG_HOTPLUG_LC_POWERED:
if (action)
err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->aux_devs,
/* Power event - attach or de-attach line card device feeding by the main power. */
if (action) {
/* Do not create devices, if line card is already powered. */
if (mlxreg_lc->state & MLXREG_LC_POWERED) {
/* In case line card is configured - enable it. */
if (mlxreg_lc->state & MLXREG_LC_CONFIGURED)
err = mlxreg_lc_enable_disable(mlxreg_lc, 1);
return err;
}
err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
mlxreg_lc->main_devs_num);
else
mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs,
if (err)
return err;
} else {
mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
mlxreg_lc->main_devs_num);
break;
case MLXREG_HOTPLUG_LC_SYNCED:
if (action)
mlxreg_lc->state |= MLXREG_LC_SYNCED;
else
mlxreg_lc->state &= ~MLXREG_LC_SYNCED;
err = mlxreg_lc_enable_disable(mlxreg_lc, mlxreg_lc->state == MLXREG_LC_ENABLE);
}
mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, action);
break;
case MLXREG_HOTPLUG_LC_READY:
if (action)
mlxreg_lc->state |= MLXREG_LC_READY;
else
mlxreg_lc->state &= ~MLXREG_LC_READY;
err = mlxreg_lc_enable_disable(mlxreg_lc, mlxreg_lc->state == MLXREG_LC_ENABLE);
/*
* Ready event – enable line card by releasing it from reset or disable it by put
* to reset state.
*/
err = mlxreg_lc_enable_disable(mlxreg_lc, !!action);
break;
case MLXREG_HOTPLUG_LC_THERMAL:
err = mlxreg_lc_power_on_off(mlxreg_lc, !action);
/* Thermal shutdown event – power off line card. */
if (action)
err = mlxreg_lc_power_on_off(mlxreg_lc, 0);
break;
default:
break;
@@ -593,6 +648,8 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,

err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->aux_devs,
mlxreg_lc->aux_devs_num);
if (err)
return err;

/* Update I2C devices feeding by main power. */
main_dev = mlxreg_lc->main_devs;
@@ -601,17 +658,47 @@ static int mlxreg_lc_completion_notify(void *handle, struct i2c_adapter *parent,
main_dev->nr = adapters[main_dev->nr]->nr;
}

/* Verify if line card is powered. */
err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_prsnt, &regval);
if (err)
goto mlxreg_lc_completion_notify_fail;
goto mlxreg_lc_regmap_read_power_fail;

if (regval & mlxreg_lc->data->mask)
if (regval & mlxreg_lc->data->mask) {
err = mlxreg_lc_create_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
mlxreg_lc->main_devs_num);
if (err)
goto mlxreg_lc_create_static_devices_failed;

mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_POWERED, 1);
}

/* Verify if line card is synchronized. */
err = regmap_read(mlxreg_lc->par_regmap, mlxreg_lc->data->reg_sync, &regval);
if (err)
goto mlxreg_lc_regmap_read_sync_fail;

/* Power on line card if necessary. */
if (regval & mlxreg_lc->data->mask && mlxreg_lc->state & MLXREG_LC_SYNCED) {
err = mlxreg_lc_power_on_off(mlxreg_lc, 1);
if (err)
goto mlxreg_lc_regmap_power_on_off_fail;

mlxreg_lc->state |= MLXREG_LC_SYNCED;
mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_SYNCED, 1);
}

mlxreg_lc_state_update(mlxreg_lc, MLXREG_LC_INITIALIZED, 1);

return 0;

mlxreg_lc_completion_notify_fail:
mlxreg_lc_regmap_power_on_off_fail:
mlxreg_lc_regmap_read_sync_fail:
if (mlxreg_lc->state & MLXREG_LC_POWERED)
mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs,
mlxreg_lc->main_devs_num);
mlxreg_lc_create_static_devices_failed:
mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->aux_devs, mlxreg_lc->aux_devs_num);
mlxreg_lc_regmap_read_power_fail:
return err;
}

@@ -716,8 +803,11 @@ static int mlxreg_lc_probe(struct platform_device *pdev)
return -ENOMEM;

mutex_init(&mlxreg_lc->lock);
data->hpdev.user_handler = mlxreg_lc_event_handler;
data->hpdev.handle = mlxreg_lc;
/* Set event notification callback. */
if (data->notifier) {
data->notifier->user_handler = mlxreg_lc_event_handler;
data->notifier->handle = mlxreg_lc;
}
data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
if (!data->hpdev.adapter) {
dev_err(&pdev->dev, "Failed to get adapter for bus %d\n",
@@ -761,6 +851,7 @@ static int mlxreg_lc_probe(struct platform_device *pdev)
par_pdata = data->hpdev.brdinfo->platform_data;
mlxreg_lc->par_regmap = par_pdata->regmap;
mlxreg_lc->data = data;
mlxreg_lc->dev = &pdev->dev;
platform_set_drvdata(pdev, mlxreg_lc);

/* Configure line card. */

0 comments on commit 998a3be

Please sign in to comment.