/* Consume invalid HPTEs */
while ((index < htabslots)
&& !HPTE_VALID(HPTE(spapr->htab, index))) {
- index++;
CLEAN_HPTE(HPTE(spapr->htab, index));
+ index++;
}
/* Consume valid HPTEs */
chunkstart = index;
while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
&& HPTE_VALID(HPTE(spapr->htab, index))) {
- index++;
CLEAN_HPTE(HPTE(spapr->htab, index));
+ index++;
}
if (index > chunkstart) {
if (!drc->dev) {
return RTAS_OUT_NO_SUCH_INDICATOR;
}
+ if (drc->awaiting_release && drc->awaiting_allocation) {
+ /* kernel is acknowledging a previous hotplug event
+ * while we are already removing it.
+ * it's safe to ignore awaiting_allocation here since we know the
+ * situation is predicated on the guest either already having done
+ * so (boot-time hotplug), or never being able to acquire in the
+ * first place (hotplug followed by immediate unplug).
+ */
+ drc->awaiting_allocation_skippable = true;
+ return RTAS_OUT_NO_SUCH_INDICATOR;
+ }
}
if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
}
if (drc->awaiting_allocation) {
- drc->awaiting_release = true;
- trace_spapr_drc_awaiting_allocation(get_index(drc));
- return;
+ if (!drc->awaiting_allocation_skippable) {
+ drc->awaiting_release = true;
+ trace_spapr_drc_awaiting_allocation(get_index(drc));
+ return;
+ }
}
drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
}
drc->awaiting_release = false;
+ drc->awaiting_allocation_skippable = false;
g_free(drc->fdt);
drc->fdt = NULL;
drc->fdt_start_offset = 0;