|
@@ -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);
|