diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/airq.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 60 | ||||
-rw-r--r-- | drivers/s390/cio/chp.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 13 | ||||
-rw-r--r-- | drivers/s390/cio/cmf.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/ioasm.c | 143 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 25 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 62 | ||||
-rw-r--r-- | drivers/s390/cio/trace.h | 6 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_cp.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_drv.c | 12 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_fsm.c | 1 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_ops.c | 2 |
15 files changed, 169 insertions, 181 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index cb466ed7eb5e..e56535c99888 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -93,7 +93,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy) struct hlist_head *head; set_cpu_flag(CIF_NOHZ_DELAY); - tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; + tpi_info = &get_irq_regs()->tpi_info; trace_s390_cio_adapter_int(tpi_info); head = &airq_lists[tpi_info->isc]; rcu_read_lock(); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 444385da5792..9748165e08e9 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -45,27 +45,6 @@ static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) } } -/* - * Remove references from ccw devices to ccw group device and from - * ccw group device to ccw devices. - */ -static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev) -{ - struct ccw_device *cdev; - int i; - - for (i = 0; i < gdev->count; i++) { - cdev = gdev->cdev[i]; - if (!cdev) - continue; - spin_lock_irq(cdev->ccwlock); - dev_set_drvdata(&cdev->dev, NULL); - spin_unlock_irq(cdev->ccwlock); - gdev->cdev[i] = NULL; - put_device(&cdev->dev); - } -} - /** * ccwgroup_set_online() - enable a ccwgroup device * @gdev: target ccwgroup device @@ -175,7 +154,6 @@ static void ccwgroup_ungroup(struct ccwgroup_device *gdev) if (device_is_registered(&gdev->dev)) { __ccwgroup_remove_symlinks(gdev); device_unregister(&gdev->dev); - __ccwgroup_remove_cdev_refs(gdev); } mutex_unlock(&gdev->reg_mutex); } @@ -228,7 +206,23 @@ static void ccwgroup_ungroup_workfn(struct work_struct *work) static void ccwgroup_release(struct device *dev) { - kfree(to_ccwgroupdev(dev)); + struct ccwgroup_device *gdev = to_ccwgroupdev(dev); + unsigned int i; + + for (i = 0; i < gdev->count; i++) { + struct ccw_device *cdev = gdev->cdev[i]; + unsigned long flags; + + if (cdev) { + spin_lock_irqsave(cdev->ccwlock, flags); + if (dev_get_drvdata(&cdev->dev) == gdev) + dev_set_drvdata(&cdev->dev, NULL); + spin_unlock_irqrestore(cdev->ccwlock, flags); + put_device(&cdev->dev); + } + } + + kfree(gdev); } static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) @@ -396,15 +390,6 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, mutex_unlock(&gdev->reg_mutex); return 0; error: - for (i = 0; i < num_devices; i++) - if (gdev->cdev[i]) { - spin_lock_irq(gdev->cdev[i]->ccwlock); - if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) - dev_set_drvdata(&gdev->cdev[i]->dev, NULL); - spin_unlock_irq(gdev->cdev[i]->ccwlock); - put_device(&gdev->cdev[i]->dev); - gdev->cdev[i] = NULL; - } mutex_unlock(&gdev->reg_mutex); put_device(&gdev->dev); return rc; @@ -416,7 +401,7 @@ static int ccwgroup_notifier(struct notifier_block *nb, unsigned long action, { struct ccwgroup_device *gdev = to_ccwgroupdev(data); - if (action == BUS_NOTIFY_UNBIND_DRIVER) { + if (action == BUS_NOTIFY_UNBOUND_DRIVER) { get_device(&gdev->dev); schedule_work(&gdev->ungroup_work); } @@ -514,15 +499,6 @@ EXPORT_SYMBOL(ccwgroup_driver_register); */ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) { - struct device *dev; - - /* We don't want ccwgroup devices to live longer than their driver. */ - while ((dev = driver_find_next_device(&cdriver->driver, NULL))) { - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - - ccwgroup_ungroup(gdev); - put_device(dev); - } driver_unregister(&cdriver->driver); } EXPORT_SYMBOL(ccwgroup_driver_unregister); diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index e42113825415..1097e76982a5 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -255,6 +255,9 @@ static ssize_t chp_status_write(struct device *dev, if (!num_args) return count; + /* Wait until previous actions have settled. */ + css_wait_for_slow_path(); + if (!strncasecmp(cmd, "on", 2) || !strcmp(cmd, "1")) { mutex_lock(&cp->lock); error = s390_vary_chpid(cp->chpid, 1); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index c22d9ee27ba1..297fb399363c 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -801,8 +801,6 @@ int chsc_chp_vary(struct chp_id chpid, int on) { struct channel_path *chp = chpid_to_chp(chpid); - /* Wait until previous actions have settled. */ - css_wait_for_slow_path(); /* * Redo PathVerification on the devices the chpid connects to */ diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 6d716db2a46a..923f5ca4f5e6 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -536,7 +536,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) struct irb *irb; set_cpu_flag(CIF_NOHZ_DELAY); - tpi_info = (struct tpi_info *) &get_irq_regs()->int_code; + tpi_info = &get_irq_regs()->tpi_info; trace_s390_cio_interrupt(tpi_info); irb = this_cpu_ptr(&cio_irb); sch = (struct subchannel *)(unsigned long) tpi_info->intparm; diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index dcdaba689b20..1cb9daf9c645 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -9,6 +9,7 @@ #include <asm/cio.h> #include <asm/fcx.h> #include <asm/schid.h> +#include <asm/tpi.h> #include "chsc.h" /* @@ -46,18 +47,6 @@ struct pmcw { /* ... in an operand exception. */ } __attribute__ ((packed)); -/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */ -struct tpi_info { - struct subchannel_id schid; - u32 intparm; - u32 adapter_IO:1; - u32 directed_irq:1; - u32 isc:3; - u32 :27; - u32 type:3; - u32 :12; -} __packed __aligned(4); - /* Target SCHIB configuration. */ struct schib_config { u64 mba; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index b7b590646d58..5584aa46c94e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -163,13 +163,14 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) */ static inline void cmf_activate(void *area, unsigned int onoff) { - register void * __gpr2 asm("2"); - register long __gpr1 asm("1"); - - __gpr2 = area; - __gpr1 = onoff; /* activate channel measurement */ - asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); + asm volatile( + " lgr 1,%[r1]\n" + " lgr 2,%[mbo]\n" + " schm\n" + : + : [r1] "d" ((unsigned long)onoff), [mbo] "d" (area) + : "1", "2"); } static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c index 4c5244d6052b..180913007824 100644 --- a/drivers/s390/cio/ioasm.c +++ b/drivers/s390/cio/ioasm.c @@ -16,18 +16,19 @@ static inline int __stsch(struct subchannel_id schid, struct schib *addr) { - register struct subchannel_id reg1 asm ("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode = -EIO; asm volatile( - " stsch 0(%3)\n" - "0: ipm %0\n" - " srl %0,28\n" + " lgr 1,%[r1]\n" + " stsch %[addr]\n" + "0: ipm %[cc]\n" + " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : "+d" (ccode), "=m" (*addr) - : "d" (reg1), "a" (addr) - : "cc"); + : [cc] "+&d" (ccode), [addr] "=Q" (*addr) + : [r1] "d" (r1) + : "cc", "1"); return ccode; } @@ -44,18 +45,19 @@ EXPORT_SYMBOL(stsch); static inline int __msch(struct subchannel_id schid, struct schib *addr) { - register struct subchannel_id reg1 asm ("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode = -EIO; asm volatile( - " msch 0(%2)\n" - "0: ipm %0\n" - " srl %0,28\n" + " lgr 1,%[r1]\n" + " msch %[addr]\n" + "0: ipm %[cc]\n" + " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : "+d" (ccode) - : "d" (reg1), "a" (addr), "m" (*addr) - : "cc"); + : [cc] "+&d" (ccode) + : [r1] "d" (r1), [addr] "Q" (*addr) + : "cc", "1"); return ccode; } @@ -71,16 +73,17 @@ int msch(struct subchannel_id schid, struct schib *addr) static inline int __tsch(struct subchannel_id schid, struct irb *addr) { - register struct subchannel_id reg1 asm ("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( - " tsch 0(%3)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode), "=m" (*addr) - : "d" (reg1), "a" (addr) - : "cc"); + " lgr 1,%[r1]\n" + " tsch %[addr]\n" + " ipm %[cc]\n" + " srl %[cc],28" + : [cc] "=&d" (ccode), [addr] "=Q" (*addr) + : [r1] "d" (r1) + : "cc", "1"); return ccode; } @@ -96,18 +99,19 @@ int tsch(struct subchannel_id schid, struct irb *addr) static inline int __ssch(struct subchannel_id schid, union orb *addr) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode = -EIO; asm volatile( - " ssch 0(%2)\n" - "0: ipm %0\n" - " srl %0,28\n" + " lgr 1,%[r1]\n" + " ssch %[addr]\n" + "0: ipm %[cc]\n" + " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : "+d" (ccode) - : "d" (reg1), "a" (addr), "m" (*addr) - : "cc", "memory"); + : [cc] "+&d" (ccode) + : [r1] "d" (r1), [addr] "Q" (*addr) + : "cc", "memory", "1"); return ccode; } @@ -124,16 +128,17 @@ EXPORT_SYMBOL(ssch); static inline int __csch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " csch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc"); + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (ccode) + : [r1] "d" (r1) + : "cc", "1"); return ccode; } @@ -153,11 +158,11 @@ int tpi(struct tpi_info *addr) int ccode; asm volatile( - " tpi 0(%2)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode), "=m" (*addr) - : "a" (addr) + " tpi %[addr]\n" + " ipm %[cc]\n" + " srl %[cc],28" + : [cc] "=&d" (ccode), [addr] "=Q" (*addr) + : : "cc"); trace_s390_cio_tpi(addr, ccode); @@ -170,13 +175,13 @@ int chsc(void *chsc_area) int cc = -EIO; asm volatile( - " .insn rre,0xb25f0000,%2,0\n" - "0: ipm %0\n" - " srl %0,28\n" + " .insn rre,0xb25f0000,%[chsc_area],0\n" + "0: ipm %[cc]\n" + " srl %[cc],28\n" "1:\n" EX_TABLE(0b, 1b) - : "+d" (cc), "=m" (*(addr_type *) chsc_area) - : "d" (chsc_area), "m" (*(addr_type *) chsc_area) + : [cc] "+&d" (cc), "+m" (*(addr_type *)chsc_area) + : [chsc_area] "d" (chsc_area) : "cc"); trace_s390_cio_chsc(chsc_area, cc); @@ -186,17 +191,17 @@ EXPORT_SYMBOL(chsc); static inline int __rsch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " rsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc", "memory"); - + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (ccode) + : [r1] "d" (r1) + : "cc", "memory", "1"); return ccode; } @@ -212,16 +217,17 @@ int rsch(struct subchannel_id schid) static inline int __hsch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " hsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc"); + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (ccode) + : [r1] "d" (r1) + : "cc", "1"); return ccode; } @@ -238,16 +244,17 @@ EXPORT_SYMBOL(hsch); static inline int __xsch(struct subchannel_id schid) { - register struct subchannel_id reg1 asm("1") = schid; + unsigned long r1 = *(unsigned int *)&schid; int ccode; asm volatile( + " lgr 1,%[r1]\n" " xsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) - : "d" (reg1) - : "cc"); + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (ccode) + : [r1] "d" (r1) + : "cc", "1"); return ccode; } @@ -266,11 +273,11 @@ static inline int __stcrw(struct crw *crw) int ccode; asm volatile( - " stcrw 0(%2)\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "=m" (*crw) - : "a" (crw) + " stcrw %[crw]\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (ccode), [crw] "=Q" (*crw) + : : "cc"); return ccode; } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 0e0044d70844..f69ffbb8edc9 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -88,15 +88,15 @@ enum qdio_irq_states { static inline int do_sqbs(u64 token, unsigned char state, int queue, int *start, int *count) { - register unsigned long _ccq asm ("0") = *count; - register unsigned long _token asm ("1") = token; unsigned long _queuestart = ((unsigned long)queue << 32) | *start; + unsigned long _ccq = *count; asm volatile( - " .insn rsy,0xeb000000008A,%1,0,0(%2)" - : "+d" (_ccq), "+d" (_queuestart) - : "d" ((unsigned long)state), "d" (_token) - : "memory", "cc"); + " lgr 1,%[token]\n" + " .insn rsy,0xeb000000008a,%[qs],%[ccq],0(%[state])" + : [ccq] "+&d" (_ccq), [qs] "+&d" (_queuestart) + : [state] "d" ((unsigned long)state), [token] "d" (token) + : "memory", "cc", "1"); *count = _ccq & 0xff; *start = _queuestart & 0xff; @@ -106,16 +106,17 @@ static inline int do_sqbs(u64 token, unsigned char state, int queue, static inline int do_eqbs(u64 token, unsigned char *state, int queue, int *start, int *count, int ack) { - register unsigned long _ccq asm ("0") = *count; - register unsigned long _token asm ("1") = token; unsigned long _queuestart = ((unsigned long)queue << 32) | *start; unsigned long _state = (unsigned long)ack << 63; + unsigned long _ccq = *count; asm volatile( - " .insn rrf,0xB99c0000,%1,%2,0,0" - : "+d" (_ccq), "+d" (_queuestart), "+d" (_state) - : "d" (_token) - : "memory", "cc"); + " lgr 1,%[token]\n" + " .insn rrf,0xb99c0000,%[qs],%[state],%[ccq],0" + : [ccq] "+&d" (_ccq), [qs] "+&d" (_queuestart), + [state] "+&d" (_state) + : [token] "d" (token) + : "memory", "cc", "1"); *count = _ccq & 0xff; *start = _queuestart & 0xff; *state = _state & 0xff; diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 307ce7ff5ca4..3052fab00597 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -31,38 +31,41 @@ MODULE_DESCRIPTION("QDIO base support"); MODULE_LICENSE("GPL"); static inline int do_siga_sync(unsigned long schid, - unsigned int out_mask, unsigned int in_mask, + unsigned long out_mask, unsigned long in_mask, unsigned int fc) { - register unsigned long __fc asm ("0") = fc; - register unsigned long __schid asm ("1") = schid; - register unsigned long out asm ("2") = out_mask; - register unsigned long in asm ("3") = in_mask; int cc; asm volatile( + " lgr 0,%[fc]\n" + " lgr 1,%[schid]\n" + " lgr 2,%[out]\n" + " lgr 3,%[in]\n" " siga 0\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) - : "d" (__fc), "d" (__schid), "d" (out), "d" (in) : "cc"); + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc) + : [fc] "d" (fc), [schid] "d" (schid), + [out] "d" (out_mask), [in] "d" (in_mask) + : "cc", "0", "1", "2", "3"); return cc; } -static inline int do_siga_input(unsigned long schid, unsigned int mask, - unsigned int fc) +static inline int do_siga_input(unsigned long schid, unsigned long mask, + unsigned long fc) { - register unsigned long __fc asm ("0") = fc; - register unsigned long __schid asm ("1") = schid; - register unsigned long __mask asm ("2") = mask; int cc; asm volatile( + " lgr 0,%[fc]\n" + " lgr 1,%[schid]\n" + " lgr 2,%[mask]\n" " siga 0\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc) - : "d" (__fc), "d" (__schid), "d" (__mask) : "cc"); + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc) + : [fc] "d" (fc), [schid] "d" (schid), [mask] "d" (mask) + : "cc", "0", "1", "2"); return cc; } @@ -78,23 +81,24 @@ static inline int do_siga_input(unsigned long schid, unsigned int mask, * Note: For IQDC unicast queues only the highest priority queue is processed. */ static inline int do_siga_output(unsigned long schid, unsigned long mask, - unsigned int *bb, unsigned int fc, + unsigned int *bb, unsigned long fc, unsigned long aob) { - register unsigned long __fc asm("0") = fc; - register unsigned long __schid asm("1") = schid; - register unsigned long __mask asm("2") = mask; - register unsigned long __aob asm("3") = aob; int cc; asm volatile( + " lgr 0,%[fc]\n" + " lgr 1,%[schid]\n" + " lgr 2,%[mask]\n" + " lgr 3,%[aob]\n" " siga 0\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (cc), "+d" (__fc), "+d" (__aob) - : "d" (__schid), "d" (__mask) - : "cc"); - *bb = __fc >> 31; + " lgr %[fc],0\n" + " ipm %[cc]\n" + " srl %[cc],28\n" + : [cc] "=&d" (cc), [fc] "+&d" (fc) + : [schid] "d" (schid), [mask] "d" (mask), [aob] "d" (aob) + : "cc", "0", "1", "2", "3"); + *bb = fc >> 31; return cc; } diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h index 4803139bce14..86993de25345 100644 --- a/drivers/s390/cio/trace.h +++ b/drivers/s390/cio/trace.h @@ -168,10 +168,8 @@ TRACE_EVENT(s390_cio_tpi, memset(&__entry->tpi_info, 0, sizeof(struct tpi_info)); else if (addr) __entry->tpi_info = *addr; - else { - memcpy(&__entry->tpi_info, &S390_lowcore.subchannel_id, - sizeof(struct tpi_info)); - } + else + __entry->tpi_info = S390_lowcore.tpi_info; __entry->cssid = __entry->tpi_info.schid.cssid; __entry->ssid = __entry->tpi_info.schid.ssid; __entry->schno = __entry->tpi_info.schid.sch_no; diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index b9febc581b1f..8d1b2771c1aa 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -638,6 +638,10 @@ int cp_init(struct channel_program *cp, struct device *mdev, union orb *orb) static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 1); int ret; + /* this is an error in the caller */ + if (cp->initialized) + return -EBUSY; + /* * We only support prefetching the channel program. We assume all channel * programs executed by supported guests likewise support prefetching. diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 8c625b530035..9b61e9b131ad 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -86,6 +86,7 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) struct vfio_ccw_private *private; struct irb *irb; bool is_final; + bool cp_is_finished = false; private = container_of(work, struct vfio_ccw_private, io_work); irb = &private->irb; @@ -94,14 +95,21 @@ static void vfio_ccw_sch_io_todo(struct work_struct *work) (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)); if (scsw_is_solicited(&irb->scsw)) { cp_update_scsw(&private->cp, &irb->scsw); - if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) + if (is_final && private->state == VFIO_CCW_STATE_CP_PENDING) { cp_free(&private->cp); + cp_is_finished = true; + } } mutex_lock(&private->io_mutex); memcpy(private->io_region->irb_area, irb, sizeof(*irb)); mutex_unlock(&private->io_mutex); - if (private->mdev && is_final) + /* + * Reset to IDLE only if processing of a channel program + * has finished. Do not overwrite a possible processing + * state if the final interrupt was for HSCH or CSCH. + */ + if (private->mdev && cp_is_finished) private->state = VFIO_CCW_STATE_IDLE; if (private->io_trigger) diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index 23e61aa638e4..e435a9cd92da 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -318,6 +318,7 @@ static void fsm_io_request(struct vfio_ccw_private *private, } err_out: + private->state = VFIO_CCW_STATE_IDLE; trace_vfio_ccw_fsm_io_request(scsw->cmd.fctl, schid, io_region->ret_code, errstr); } diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index 491a64c61fff..c57d2a7f0919 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c @@ -279,8 +279,6 @@ static ssize_t vfio_ccw_mdev_write_io_region(struct vfio_ccw_private *private, } vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_IO_REQ); - if (region->ret_code != 0) - private->state = VFIO_CCW_STATE_IDLE; ret = (region->ret_code != 0) ? region->ret_code : count; out_unlock: |