/* * Helpers
*/ int vfio_ccw_sch_quiesce(struct subchannel *sch)
{ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev); struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev);
DECLARE_COMPLETION_ONSTACK(completion); int iretry, ret = 0;
/* * Probably an impossible situation, after being called through * FSM callbacks. But in the event it did, register a warning * and return as if things were fine.
*/ if (WARN_ON(!private)) return 0;
iretry = 255; do {
ret = cio_cancel_halt_clear(sch, &iretry);
if (ret == -EIO) {
pr_err("vfio_ccw: could not quiesce subchannel 0.%x.%04x!\n",
sch->schid.ssid, sch->schid.sch_no); break;
}
/* * Flush all I/O and wait for * cancel/halt/clear completion.
*/
private->completion = &completion;
spin_unlock_irq(&sch->lock);
if (ret == -EBUSY)
wait_for_completion_timeout(&completion, 3*HZ);
private->completion = NULL;
flush_workqueue(vfio_ccw_work_q);
spin_lock_irq(&sch->lock);
ret = cio_disable_subchannel(sch);
} while (ret == -EBUSY);
/* * Reset to IDLE only if processing of a channel program * has finished. Do not overwrite a possible processing * state if the interrupt was unsolicited, or if the final * interrupt was for HSCH or CSCH.
*/ if (cp_is_finished)
private->state = VFIO_CCW_STATE_IDLE;
if (private->io_trigger)
eventfd_signal(private->io_trigger);
}
/* * The subchannel should still be disabled at this point, * so an interrupt would be quite surprising. As with an * interrupt while the FSM is closed, let's attempt to * disable the subchannel again.
*/ if (!private) {
VFIO_CCW_MSG_EVENT(2, "sch %x.%x.%04x: unexpected interrupt\n",
sch->schid.cssid, sch->schid.ssid,
sch->schid.sch_no);
/** * vfio_ccw_sch_event - process subchannel event * @sch: subchannel * @process: non-zero if function is called in process context * * An unspecified event occurred for this subchannel. Adjust data according * to the current operational state of the subchannel. Return zero when the * event has been handled sufficiently or -EAGAIN when this function should * be called again in process context.
*/ staticint vfio_ccw_sch_event(struct subchannel *sch, int process)
{ struct vfio_ccw_parent *parent = dev_get_drvdata(&sch->dev); struct vfio_ccw_private *private = dev_get_drvdata(&parent->dev); unsignedlong flags; int rc = -EAGAIN;
spin_lock_irqsave(&sch->lock, flags); if (!device_is_registered(&sch->dev)) goto out_unlock;
if (work_pending(&sch->todo_work)) goto out_unlock;
rc = 0;
if (cio_update_schib(sch)) { if (private)
vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_NOT_OPER);
}
/* * If unable to allocate a CRW, just drop the event and * carry on. The guest will either see a later one or * learn when it issues its own store subchannel.
*/
crw = kzalloc(sizeof(*crw), GFP_ATOMIC); if (!crw) return;
/* * Build the CRW based on the inputs given to us.
*/
crw->crw.rsc = rsc;
crw->crw.erc = erc;
crw->crw.rsid = rsid;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.