diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/mellanox/mlxreg-hotplug.c | 48 |
1 files changed, 31 insertions, 17 deletions
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index b56953ae1ab8..922913b8870f 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -55,6 +55,7 @@ #define MLXREG_HOTPLUG_RST_CNTR 3 #define MLXREG_HOTPLUG_ATTRS_MAX 24 +#define MLXREG_HOTPLUG_NOT_ASSERT 3 /** * struct mlxreg_hotplug_priv_data - platform private data: @@ -74,6 +75,7 @@ * @mask: top aggregation interrupt common mask; * @aggr_cache: last value of aggregation register status; * @after_probe: flag indication probing completion; + * @not_asserted: number of entries in workqueue with no signal assertion; */ struct mlxreg_hotplug_priv_data { int irq; @@ -93,6 +95,7 @@ struct mlxreg_hotplug_priv_data { u32 mask; u32 aggr_cache; bool after_probe; + u8 not_asserted; }; static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, @@ -410,6 +413,18 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) aggr_asserted = priv->aggr_cache ^ regval; priv->aggr_cache = regval; + /* + * Handler is invoked, but no assertion is detected at top aggregation + * status level. Set aggr_asserted to mask value to allow handler extra + * run over all relevant signals to recover any missed signal. + */ + if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { + priv->not_asserted = 0; + aggr_asserted = pdata->mask; + } + if (!aggr_asserted) + goto unmask_event; + /* Handle topology and health configuration changes. */ for (i = 0; i < pdata->counter; i++, item++) { if (aggr_asserted & item->aggr_mask) { @@ -420,27 +435,26 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work) } } - if (aggr_asserted) { - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); - /* - * It is possible, that some signals have been inserted, while - * interrupt has been masked by mlxreg_hotplug_work_handler. - * In this case such signals will be missed. In order to handle - * these signals delayed work is canceled and work task - * re-scheduled for immediate execution. It allows to handle - * missed signals, if any. In other case work handler just - * validates that no new signals have been received during - * masking. - */ - cancel_delayed_work(&priv->dwork_irq); - schedule_delayed_work(&priv->dwork_irq, 0); + /* + * It is possible, that some signals have been inserted, while + * interrupt has been masked by mlxreg_hotplug_work_handler. In this + * case such signals will be missed. In order to handle these signals + * delayed work is canceled and work task re-scheduled for immediate + * execution. It allows to handle missed signals, if any. In other case + * work handler just validates that no new signals have been received + * during masking. + */ + cancel_delayed_work(&priv->dwork_irq); + schedule_delayed_work(&priv->dwork_irq, 0); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->lock, flags); - return; - } + return; +unmask_event: + priv->not_asserted++; /* Unmask aggregation event (no need acknowledge). */ ret = regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); |