Skip to content

Commit 2af7a83

Browse files
efarmancohuck
authored andcommitted
vfio-ccw: Serialize FSM IDLE state with I/O completion
Today, the stacked call to vfio_ccw_sch_io_todo() does three things: 1) Update a solicited IRB with CP information, and release the CP if the interrupt was the end of a START operation. 2) Copy the IRB data into the io_region, under the protection of the io_mutex 3) Reset the vfio-ccw FSM state to IDLE to acknowledge that vfio-ccw can accept more work. The trouble is that step 3 is (A) invoked for both solicited and unsolicited interrupts, and (B) sitting after the mutex for step 2. This second piece becomes a problem if it processes an interrupt for a CLEAR SUBCHANNEL while another thread initiates a START, thus allowing the CP and FSM states to get out of sync. That is: CPU 1 CPU 2 fsm_do_clear() fsm_irq() fsm_io_request() vfio_ccw_sch_io_todo() fsm_io_helper() Since the FSM state and CP should be kept in sync, let's make a note when the CP is released, and rely on that as an indication that the FSM should also be reset at the end of this routine and open up the device for more work. Signed-off-by: Eric Farman <[email protected]> Acked-by: Matthew Rosato <[email protected]> Reviewed-by: Cornelia Huck <[email protected]> Message-Id: <[email protected]> Signed-off-by: Cornelia Huck <[email protected]>
1 parent 6c02ac4 commit 2af7a83

File tree

1 file changed

+10
-2
lines changed

1 file changed

+10
-2
lines changed

drivers/s390/cio/vfio_ccw_drv.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
8686
struct vfio_ccw_private *private;
8787
struct irb *irb;
8888
bool is_final;
89+
bool cp_is_finished = false;
8990

9091
private = container_of(work, struct vfio_ccw_private, io_work);
9192
irb = &private->irb;
@@ -94,14 +95,21 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
9495
(SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT));
9596
if (scsw_is_solicited(&irb->scsw)) {
9697
cp_update_scsw(&private->cp, &irb->scsw);
97-
if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING)
98+
if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) {
9899
cp_free(&private->cp);
100+
cp_is_finished = true;
101+
}
99102
}
100103
mutex_lock(&private->io_mutex);
101104
memcpy(private->io_region->irb_area, irb, sizeof(*irb));
102105
mutex_unlock(&private->io_mutex);
103106

104-
if (private->mdev && is_final)
107+
/*
108+
* Reset to IDLE only if processing of a channel program
109+
* has finished. Do not overwrite a possible processing
110+
* state if the final interrupt was for HSCH or CSCH.
111+
*/
112+
if (private->mdev && cp_is_finished)
105113
private->state = VFIO_CCW_STATE_IDLE;
106114

107115
if (private->io_trigger)

0 commit comments

Comments
 (0)