@@ -17,6 +17,7 @@
#include <asm/isc.h>
+#include "chp.h"
#include "ioasm.h"
#include "css.h"
#include "vfio_ccw_private.h"
@@ -88,6 +89,15 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work)
private->state = VFIO_CCW_STATE_IDLE;
}
+static void vfio_ccw_sch_chp_todo(struct work_struct *work)
+{
+ struct vfio_ccw_private *private =
+ container_of(work, struct vfio_ccw_private, chp_work);
+
+ if (private->chp_trigger)
+ eventfd_signal(private->chp_trigger, 1);
+}
+
/*
* Css driver callbacks
*/
@@ -130,6 +140,7 @@ static int vfio_ccw_sch_probe(struct subchannel *sch)
goto out_disable;
INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo);
+ INIT_WORK(&private->chp_work, vfio_ccw_sch_chp_todo);
atomic_set(&private->avail, 1);
private->state = VFIO_CCW_STATE_STANDBY;
@@ -202,6 +213,45 @@ static int vfio_ccw_sch_event(struct subchannel *sch, int process)
return 0;
}
+static int vfio_ccw_sch_chp_event(struct subchannel *sch,
+ struct chp_link *link, int event)
+{
+ struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev);
+ int mask = chp_ssd_get_mask(&sch->ssd_info, link);
+
+ /* move these checks around? */
+ if (!private || !mask)
+ return 0;
+
+ if (cio_update_schib(sch))
+ return -ENODEV;
+
+ switch (event) {
+ case CHP_VARY_OFF:
+ sch->opm &= ~mask;
+ sch->lpm &= ~mask;
+ /* TODO: terminate current I/O on path. */
+ break;
+ case CHP_VARY_ON:
+ sch->opm |= mask;
+ sch->lpm |= mask;
+ break;
+ case CHP_OFFLINE:
+ /* TODO: terminate current I/O on path. */
+ break;
+ case CHP_ONLINE:
+ sch->lpm |= mask & sch->opm;
+ break;
+ default:
+ /* Not possible? */
+ return 0;
+ }
+
+ vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_UPDATE_CHP);
+
+ return 0;
+}
+
static struct css_device_id vfio_ccw_sch_ids[] = {
{ .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, },
{ /* end of list */ },
@@ -219,6 +269,7 @@ static struct css_driver vfio_ccw_sch_driver = {
.remove = vfio_ccw_sch_remove,
.shutdown = vfio_ccw_sch_shutdown,
.sch_event = vfio_ccw_sch_event,
+ .chp_event = vfio_ccw_sch_chp_event,
};
static int __init vfio_ccw_sch_init(void)
@@ -188,6 +188,23 @@ static void fsm_update_subch(struct vfio_ccw_private *private,
sizeof(sch->schib));
}
+static void fsm_update_chp(struct vfio_ccw_private *private,
+ enum vfio_ccw_event event)
+{
+ queue_work(vfio_ccw_work_q, &private->chp_work);
+
+}
+
+static void fsm_update_chp_busy(struct vfio_ccw_private *private,
+ enum vfio_ccw_event event)
+{
+ /*
+ * TODO:
+ * If we are having I/O on the current path, do
+ * extra handling?
+ */
+}
+
/*
* Device statemachine
*/
@@ -197,29 +214,34 @@ fsm_func_t *vfio_ccw_jumptable[NR_VFIO_CCW_STATES][NR_VFIO_CCW_EVENTS] = {
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_disabled_irq,
[VFIO_CCW_EVENT_UPDATE_SUBCH] = fsm_update_subch,
+ [VFIO_CCW_EVENT_UPDATE_CHP] = fsm_nop,
},
[VFIO_CCW_STATE_STANDBY] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_error,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_UPDATE_SUBCH] = fsm_update_subch,
+ [VFIO_CCW_EVENT_UPDATE_CHP] = fsm_update_chp,
},
[VFIO_CCW_STATE_IDLE] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_request,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_UPDATE_SUBCH] = fsm_update_subch,
+ [VFIO_CCW_EVENT_UPDATE_CHP] = fsm_update_chp,
},
[VFIO_CCW_STATE_BOXED] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_UPDATE_SUBCH] = fsm_update_subch,
+ [VFIO_CCW_EVENT_UPDATE_CHP] = fsm_update_chp,
},
[VFIO_CCW_STATE_BUSY] = {
[VFIO_CCW_EVENT_NOT_OPER] = fsm_notoper,
[VFIO_CCW_EVENT_IO_REQ] = fsm_io_busy,
[VFIO_CCW_EVENT_INTERRUPT] = fsm_irq,
[VFIO_CCW_EVENT_UPDATE_SUBCH] = fsm_update_subch,
+ [VFIO_CCW_EVENT_UPDATE_CHP] = fsm_update_chp_busy,
},
};
@@ -35,6 +35,7 @@
* @io_trigger: eventfd ctx for signaling userspace I/O results
* @chp_trigger: eventfd ctx for signaling userspace chp event
* @io_work: work for deferral process of I/O handling
+ * @chp_work: work for deferral process of chp event
*/
struct vfio_ccw_private {
struct subchannel *sch;
@@ -53,6 +54,7 @@ struct vfio_ccw_private {
struct eventfd_ctx *io_trigger;
struct eventfd_ctx *chp_trigger;
struct work_struct io_work;
+ struct work_struct chp_work;
} __aligned(8);
extern int vfio_ccw_mdev_reg(struct subchannel *sch);
@@ -81,6 +83,7 @@ enum vfio_ccw_event {
VFIO_CCW_EVENT_IO_REQ,
VFIO_CCW_EVENT_INTERRUPT,
VFIO_CCW_EVENT_UPDATE_SUBCH,
+ VFIO_CCW_EVENT_UPDATE_CHP,
/* last element! */
NR_VFIO_CCW_EVENTS
};
This adds channel path related event handler for vfio-ccw. This also signals userland when there is a chp event. Signed-off-by: Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> --- drivers/s390/cio/vfio_ccw_drv.c | 51 +++++++++++++++++++++++++++++++++++++ drivers/s390/cio/vfio_ccw_fsm.c | 22 ++++++++++++++++ drivers/s390/cio/vfio_ccw_private.h | 3 +++ 3 files changed, 76 insertions(+)