From d0b2f91bede3bd5e3d24dd6803e56eee959c1797 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 20 Oct 2016 00:10:27 -0300 Subject: Linux-libre 4.8.2-gnu --- drivers/s390/cio/chp.c | 82 ++++++++++++++++------------ drivers/s390/cio/chp.h | 2 +- drivers/s390/cio/chsc.c | 25 +++++---- drivers/s390/cio/chsc.h | 5 +- drivers/s390/cio/chsc_sch.c | 2 +- drivers/s390/cio/cmf.c | 15 +++--- drivers/s390/cio/device.c | 2 - drivers/s390/cio/device_ops.c | 22 ++++---- drivers/s390/cio/device_status.c | 7 +-- drivers/s390/cio/idset.h | 2 +- drivers/s390/cio/io_sch.h | 1 - drivers/s390/cio/ioasm.c | 91 +++++++++++++++++++++++++++---- drivers/s390/cio/qdio_main.c | 113 ++++++++++++++++++++------------------- 13 files changed, 231 insertions(+), 138 deletions(-) (limited to 'drivers/s390/cio') diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index 50597f952..46be25c74 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c @@ -37,8 +37,7 @@ enum cfg_task_t { /* Map for pending configure tasks. */ static enum cfg_task_t chp_cfg_task[__MAX_CSSID + 1][__MAX_CHPID + 1]; -static DEFINE_MUTEX(cfg_lock); -static int cfg_busy; +static DEFINE_SPINLOCK(cfg_lock); /* Map for channel-path status. */ static struct sclp_chp_info chp_info; @@ -47,8 +46,6 @@ static DEFINE_MUTEX(info_lock); /* Time after which channel-path status may be outdated. */ static unsigned long chp_info_expires; -/* Workqueue to perform pending configure tasks. */ -static struct workqueue_struct *chp_wq; static struct work_struct cfg_work; /* Wait queue for configure completion events. */ @@ -428,11 +425,14 @@ int chp_update_desc(struct channel_path *chp) if (rc) return rc; - rc = chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); - if (rc) - return rc; + /* + * Fetching the following data is optional. Not all machines or + * hypervisors implement the required chsc commands. + */ + chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); + chsc_get_channel_measurement_chars(chp); - return chsc_get_channel_measurement_chars(chp); + return 0; } /** @@ -665,6 +665,20 @@ static void cfg_set_task(struct chp_id chpid, enum cfg_task_t cfg) chp_cfg_task[chpid.cssid][chpid.id] = cfg; } +/* Fetch the first configure task. Set chpid accordingly. */ +static enum cfg_task_t chp_cfg_fetch_task(struct chp_id *chpid) +{ + enum cfg_task_t t = cfg_none; + + chp_id_for_each(chpid) { + t = cfg_get_task(*chpid); + if (t != cfg_none) + break; + } + + return t; +} + /* Perform one configure/deconfigure request. Reschedule work function until * last request. */ static void cfg_func(struct work_struct *work) @@ -673,16 +687,9 @@ static void cfg_func(struct work_struct *work) enum cfg_task_t t; int rc; - mutex_lock(&cfg_lock); - t = cfg_none; - chp_id_for_each(&chpid) { - t = cfg_get_task(chpid); - if (t != cfg_none) { - cfg_set_task(chpid, cfg_none); - break; - } - } - mutex_unlock(&cfg_lock); + spin_lock(&cfg_lock); + t = chp_cfg_fetch_task(&chpid); + spin_unlock(&cfg_lock); switch (t) { case cfg_configure: @@ -708,13 +715,14 @@ static void cfg_func(struct work_struct *work) case cfg_none: /* Get updated information after last change. */ info_update(); - mutex_lock(&cfg_lock); - cfg_busy = 0; - mutex_unlock(&cfg_lock); wake_up_interruptible(&cfg_wait_queue); return; } - queue_work(chp_wq, &cfg_work); + spin_lock(&cfg_lock); + if (t == cfg_get_task(chpid)) + cfg_set_task(chpid, cfg_none); + spin_unlock(&cfg_lock); + schedule_work(&cfg_work); } /** @@ -728,11 +736,10 @@ void chp_cfg_schedule(struct chp_id chpid, int configure) { CIO_MSG_EVENT(2, "chp_cfg_sched%x.%02x=%d\n", chpid.cssid, chpid.id, configure); - mutex_lock(&cfg_lock); + spin_lock(&cfg_lock); cfg_set_task(chpid, configure ? cfg_configure : cfg_deconfigure); - cfg_busy = 1; - mutex_unlock(&cfg_lock); - queue_work(chp_wq, &cfg_work); + spin_unlock(&cfg_lock); + schedule_work(&cfg_work); } /** @@ -745,15 +752,27 @@ void chp_cfg_schedule(struct chp_id chpid, int configure) void chp_cfg_cancel_deconfigure(struct chp_id chpid) { CIO_MSG_EVENT(2, "chp_cfg_cancel:%x.%02x\n", chpid.cssid, chpid.id); - mutex_lock(&cfg_lock); + spin_lock(&cfg_lock); if (cfg_get_task(chpid) == cfg_deconfigure) cfg_set_task(chpid, cfg_none); - mutex_unlock(&cfg_lock); + spin_unlock(&cfg_lock); +} + +static bool cfg_idle(void) +{ + struct chp_id chpid; + enum cfg_task_t t; + + spin_lock(&cfg_lock); + t = chp_cfg_fetch_task(&chpid); + spin_unlock(&cfg_lock); + + return t == cfg_none; } static int cfg_wait_idle(void) { - if (wait_event_interruptible(cfg_wait_queue, !cfg_busy)) + if (wait_event_interruptible(cfg_wait_queue, cfg_idle())) return -ERESTARTSYS; return 0; } @@ -766,11 +785,6 @@ static int __init chp_init(void) ret = crw_register_handler(CRW_RSC_CPATH, chp_process_crw); if (ret) return ret; - chp_wq = create_singlethread_workqueue("cio_chp"); - if (!chp_wq) { - crw_unregister_handler(CRW_RSC_CPATH); - return -ENOMEM; - } INIT_WORK(&cfg_work, cfg_func); init_waitqueue_head(&cfg_wait_queue); if (info_update()) diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index af0232290..bb5a68226 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h @@ -4,7 +4,7 @@ */ #ifndef S390_CHP_H -#define S390_CHP_H S390_CHP_H +#define S390_CHP_H #include #include diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index c424c0c73..940e725bd 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -907,7 +907,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, struct chsc_scpd *scpd_area; int ccode, ret; - if ((rfmt == 1) && !css_general_characteristics.fcs) + if ((rfmt == 1 || rfmt == 0) && c == 1 && + !css_general_characteristics.fcs) return -EINVAL; if ((rfmt == 2) && !css_general_characteristics.cib) return -EINVAL; @@ -939,7 +940,6 @@ EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); int chsc_determine_base_channel_path_desc(struct chp_id chpid, struct channel_path_desc *desc) { - struct chsc_response_struct *chsc_resp; struct chsc_scpd *scpd_area; unsigned long flags; int ret; @@ -949,8 +949,8 @@ int chsc_determine_base_channel_path_desc(struct chp_id chpid, ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area); if (ret) goto out; - chsc_resp = (void *)&scpd_area->response; - memcpy(desc, &chsc_resp->data, sizeof(*desc)); + + memcpy(desc, scpd_area->data, sizeof(*desc)); out: spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; @@ -959,18 +959,17 @@ out: int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, struct channel_path_desc_fmt1 *desc) { - struct chsc_response_struct *chsc_resp; struct chsc_scpd *scpd_area; unsigned long flags; int ret; spin_lock_irqsave(&chsc_page_lock, flags); scpd_area = chsc_page; - ret = chsc_determine_channel_path_desc(chpid, 0, 0, 1, 0, scpd_area); + ret = chsc_determine_channel_path_desc(chpid, 0, 1, 1, 0, scpd_area); if (ret) goto out; - chsc_resp = (void *)&scpd_area->response; - memcpy(desc, &chsc_resp->data, sizeof(*desc)); + + memcpy(desc, scpd_area->data, sizeof(*desc)); out: spin_unlock_irqrestore(&chsc_page_lock, flags); return ret; @@ -1020,7 +1019,7 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) chp->cmg = -1; if (!css_chsc_characteristics.scmc || !css_chsc_characteristics.secm) - return 0; + return -EINVAL; spin_lock_irq(&chsc_page_lock); memset(chsc_page, 0, PAGE_SIZE); @@ -1176,7 +1175,7 @@ exit: EXPORT_SYMBOL_GPL(css_general_characteristics); EXPORT_SYMBOL_GPL(css_chsc_characteristics); -int chsc_sstpc(void *page, unsigned int op, u16 ctrl) +int chsc_sstpc(void *page, unsigned int op, u16 ctrl, u64 *clock_delta) { struct { struct chsc_header request; @@ -1186,7 +1185,9 @@ int chsc_sstpc(void *page, unsigned int op, u16 ctrl) unsigned int ctrl : 16; unsigned int rsvd2[5]; struct chsc_header response; - unsigned int rsvd3[7]; + unsigned int rsvd3[3]; + u64 clock_delta; + unsigned int rsvd4[2]; } __attribute__ ((packed)) *rr; int rc; @@ -1200,6 +1201,8 @@ int chsc_sstpc(void *page, unsigned int op, u16 ctrl) if (rc) return -EIO; rc = (rr->response.code == 0x0001) ? 0 : -EIO; + if (clock_delta) + *clock_delta = rr->clock_delta; return rc; } diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 0de134c3a..67c87b6e6 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -112,8 +112,9 @@ struct chsc_scpd { u32 last_chpid:8; u32 zeroes1; struct chsc_header response; - u8 data[PAGE_SIZE - 20]; -} __attribute__ ((packed)); + u32:32; + u8 data[0]; +} __packed; struct chsc_sda_area { struct chsc_header request; diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index b6f12c2bb..735052ecd 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -552,7 +552,7 @@ static int chsc_ioctl_info_cu(void __user *user_cd) goto out_free; } scucd_area->request.length = 0x0010; - scucd_area->request.code = 0x0028; + scucd_area->request.code = 0x0026; scucd_area->m = cd->m; scucd_area->fmt1 = cd->fmt; scucd_area->cssid = cd->cssid; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 2a34eb5f6..268aa23af 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -164,6 +164,9 @@ static inline u64 time_to_avg_nsec(u32 value, u32 count) return ret; } +#define CMF_OFF 0 +#define CMF_ON 2 + /* * Activate or deactivate the channel monitor. When area is NULL, * the monitor is deactivated. The channel monitor needs to @@ -176,7 +179,7 @@ static inline void cmf_activate(void *area, unsigned int onoff) register long __gpr1 asm("1"); __gpr2 = area; - __gpr1 = onoff ? 2 : 0; + __gpr1 = onoff; /* activate channel measurement */ asm("schm" : : "d" (__gpr2), "d" (__gpr1) ); } @@ -587,7 +590,7 @@ static int alloc_cmb(struct ccw_device *cdev) /* everything ok */ memset(mem, 0, size); cmb_area.mem = mem; - cmf_activate(cmb_area.mem, 1); + cmf_activate(cmb_area.mem, CMF_ON); } } @@ -621,7 +624,7 @@ static void free_cmb(struct ccw_device *cdev) if (list_empty(&cmb_area.list)) { ssize_t size; size = sizeof(struct cmb) * cmb_area.num_channels; - cmf_activate(NULL, 0); + cmf_activate(NULL, CMF_OFF); free_pages((unsigned long)cmb_area.mem, get_order(size)); cmb_area.mem = NULL; } @@ -841,7 +844,7 @@ static int alloc_cmbe(struct ccw_device *cdev) /* activate global measurement if this is the first channel */ if (list_empty(&cmb_area.list)) - cmf_activate(NULL, 1); + cmf_activate(NULL, CMF_ON); list_add_tail(&cdev->private->cmb_list, &cmb_area.list); spin_unlock_irq(cdev->ccwlock); @@ -878,7 +881,7 @@ static void free_cmbe(struct ccw_device *cdev) /* deactivate global measurement if this is the last channel */ list_del_init(&cdev->private->cmb_list); if (list_empty(&cmb_area.list)) - cmf_activate(NULL, 0); + cmf_activate(NULL, CMF_OFF); spin_unlock_irq(cdev->ccwlock); spin_unlock(&cmb_area.lock); } @@ -1332,7 +1335,7 @@ void cmf_reactivate(void) { spin_lock(&cmb_area.lock); if (!list_empty(&cmb_area.list)) - cmf_activate(cmb_area.mem, 1); + cmf_activate(cmb_area.mem, CMF_ON); spin_unlock(&cmb_area.lock); } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7ada078ff..6a58bc8f4 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -762,7 +762,6 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, priv->state = DEV_STATE_NOT_OPER; priv->dev_id.devno = sch->schib.pmcw.dev; priv->dev_id.ssid = sch->schid.ssid; - priv->schid = sch->schid; INIT_WORK(&priv->todo_work, ccw_device_todo); INIT_LIST_HEAD(&priv->cmb_list); @@ -1000,7 +999,6 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, put_device(&old_sch->dev); /* Initialize new subchannel. */ spin_lock_irq(sch->lock); - cdev->private->schid = sch->schid; cdev->ccwlock = sch->lock; if (!sch_is_pseudo_sch(sch)) sch_set_cdev(sch, cdev); diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index a69f702a2..877d9f601 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -97,7 +97,7 @@ void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags) } /** - * ccw_device_is_pathgroup - determine if paths to this device are grouped + * ccw_device_is_pathgroup() - determine if paths to this device are grouped * @cdev: ccw device * * Return non-zero if there is a path group, zero otherwise. @@ -109,7 +109,7 @@ int ccw_device_is_pathgroup(struct ccw_device *cdev) EXPORT_SYMBOL(ccw_device_is_pathgroup); /** - * ccw_device_is_multipath - determine if device is operating in multipath mode + * ccw_device_is_multipath() - determine if device is operating in multipath mode * @cdev: ccw device * * Return non-zero if device is operating in multipath mode, zero otherwise. @@ -457,7 +457,7 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev) } /** - * chp_get_chp_desc - return newly allocated channel-path descriptor + * ccw_device_get_chp_desc() - return newly allocated channel-path descriptor * @cdev: device to obtain the descriptor for * @chp_idx: index of the channel path * @@ -477,7 +477,7 @@ struct channel_path_desc *ccw_device_get_chp_desc(struct ccw_device *cdev, } /** - * ccw_device_get_id - obtain a ccw device id + * ccw_device_get_id() - obtain a ccw device id * @cdev: device to obtain the id for * @dev_id: where to fill in the values */ @@ -488,7 +488,7 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) EXPORT_SYMBOL(ccw_device_get_id); /** - * ccw_device_tm_start_key - perform start function + * ccw_device_tm_start_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -533,7 +533,7 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start_key); /** - * ccw_device_tm_start_timeout_key - perform start function + * ccw_device_tm_start_timeout_key() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -559,7 +559,7 @@ int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); /** - * ccw_device_tm_start - perform start function + * ccw_device_tm_start() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -577,7 +577,7 @@ int ccw_device_tm_start(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start); /** - * ccw_device_tm_start_timeout - perform start function + * ccw_device_tm_start_timeout() - perform start function * @cdev: ccw device on which to perform the start function * @tcw: transport-command word to be started * @intparm: user defined parameter to be passed to the interrupt handler @@ -596,7 +596,7 @@ int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw, EXPORT_SYMBOL(ccw_device_tm_start_timeout); /** - * ccw_device_get_mdc - accumulate max data count + * ccw_device_get_mdc() - accumulate max data count * @cdev: ccw device for which the max data count is accumulated * @mask: mask of paths to use * @@ -642,7 +642,7 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask) EXPORT_SYMBOL(ccw_device_get_mdc); /** - * ccw_device_tm_intrg - perform interrogate function + * ccw_device_tm_intrg() - perform interrogate function * @cdev: ccw device on which to perform the interrogate function * * Perform an interrogate function on the given ccw device. Return zero on @@ -664,7 +664,7 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) EXPORT_SYMBOL(ccw_device_tm_intrg); /** - * ccw_device_get_schid - obtain a subchannel id + * ccw_device_get_schid() - obtain a subchannel id * @cdev: device to obtain the id for * @schid: where to fill in the values */ diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 15b56a15d..9bc351237 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -26,6 +26,7 @@ static void ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) { + struct subchannel *sch = to_subchannel(cdev->dev.parent); char dbf_text[15]; if (!scsw_is_valid_cstat(&irb->scsw) || @@ -36,10 +37,10 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) "received" " ... device %04x on subchannel 0.%x.%04x, dev_stat " ": %02X sch_stat : %02X\n", - cdev->private->dev_id.devno, cdev->private->schid.ssid, - cdev->private->schid.sch_no, + cdev->private->dev_id.devno, sch->schid.ssid, + sch->schid.sch_no, scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw)); - sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); + sprintf(dbf_text, "chk%x", sch->schid.sch_no); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, irb, sizeof(struct irb)); } diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h index 22b581046..89a787790 100644 --- a/drivers/s390/cio/idset.h +++ b/drivers/s390/cio/idset.h @@ -4,7 +4,7 @@ */ #ifndef S390_IDSET_H -#define S390_IDSET_H S390_IDSET_H +#define S390_IDSET_H #include diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 8975060af..220f49145 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -120,7 +120,6 @@ struct ccw_device_private { int state; /* device state */ atomic_t onoff; struct ccw_dev_id dev_id; /* device id */ - struct subchannel_id schid; /* subchannel number */ struct ccw_request req; /* internal I/O request */ int iretry; u8 pgid_valid_mask; /* mask of valid PGIDs */ diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c index 989848186..8225da619 100644 --- a/drivers/s390/cio/ioasm.c +++ b/drivers/s390/cio/ioasm.c @@ -12,7 +12,7 @@ #include "orb.h" #include "cio.h" -int stsch(struct subchannel_id schid, struct schib *addr) +static inline int __stsch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; @@ -26,13 +26,21 @@ int stsch(struct subchannel_id schid, struct schib *addr) : "+d" (ccode), "=m" (*addr) : "d" (reg1), "a" (addr) : "cc"); + return ccode; +} + +int stsch(struct subchannel_id schid, struct schib *addr) +{ + int ccode; + + ccode = __stsch(schid, addr); trace_s390_cio_stsch(schid, addr, ccode); return ccode; } EXPORT_SYMBOL(stsch); -int msch(struct subchannel_id schid, struct schib *addr) +static inline int __msch(struct subchannel_id schid, struct schib *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode = -EIO; @@ -46,12 +54,20 @@ int msch(struct subchannel_id schid, struct schib *addr) : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + return ccode; +} + +int msch(struct subchannel_id schid, struct schib *addr) +{ + int ccode; + + ccode = __msch(schid, addr); trace_s390_cio_msch(schid, addr, ccode); return ccode; } -int tsch(struct subchannel_id schid, struct irb *addr) +static inline int __tsch(struct subchannel_id schid, struct irb *addr) { register struct subchannel_id reg1 asm ("1") = schid; int ccode; @@ -63,12 +79,20 @@ int tsch(struct subchannel_id schid, struct irb *addr) : "=d" (ccode), "=m" (*addr) : "d" (reg1), "a" (addr) : "cc"); + return ccode; +} + +int tsch(struct subchannel_id schid, struct irb *addr) +{ + int ccode; + + ccode = __tsch(schid, addr); trace_s390_cio_tsch(schid, addr, ccode); return ccode; } -int ssch(struct subchannel_id schid, union orb *addr) +static inline int __ssch(struct subchannel_id schid, union orb *addr) { register struct subchannel_id reg1 asm("1") = schid; int ccode = -EIO; @@ -82,13 +106,21 @@ int ssch(struct subchannel_id schid, union orb *addr) : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc", "memory"); + return ccode; +} + +int ssch(struct subchannel_id schid, union orb *addr) +{ + int ccode; + + ccode = __ssch(schid, addr); trace_s390_cio_ssch(schid, addr, ccode); return ccode; } EXPORT_SYMBOL(ssch); -int csch(struct subchannel_id schid) +static inline int __csch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -100,6 +132,14 @@ int csch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int csch(struct subchannel_id schid) +{ + int ccode; + + ccode = __csch(schid); trace_s390_cio_csch(schid, ccode); return ccode; @@ -140,7 +180,7 @@ int chsc(void *chsc_area) } EXPORT_SYMBOL(chsc); -int rchp(struct chp_id chpid) +static inline int __rchp(struct chp_id chpid) { register struct chp_id reg1 asm ("1") = chpid; int ccode; @@ -151,12 +191,20 @@ int rchp(struct chp_id chpid) " ipm %0\n" " srl %0,28" : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int rchp(struct chp_id chpid) +{ + int ccode; + + ccode = __rchp(chpid); trace_s390_cio_rchp(chpid, ccode); return ccode; } -int rsch(struct subchannel_id schid) +static inline int __rsch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -168,12 +216,21 @@ int rsch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc", "memory"); + + return ccode; +} + +int rsch(struct subchannel_id schid) +{ + int ccode; + + ccode = __rsch(schid); trace_s390_cio_rsch(schid, ccode); return ccode; } -int hsch(struct subchannel_id schid) +static inline int __hsch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -185,12 +242,20 @@ int hsch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int hsch(struct subchannel_id schid) +{ + int ccode; + + ccode = __hsch(schid); trace_s390_cio_hsch(schid, ccode); return ccode; } -int xsch(struct subchannel_id schid) +static inline int __xsch(struct subchannel_id schid) { register struct subchannel_id reg1 asm("1") = schid; int ccode; @@ -202,6 +267,14 @@ int xsch(struct subchannel_id schid) : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +int xsch(struct subchannel_id schid) +{ + int ccode; + + ccode = __xsch(schid); trace_s390_cio_xsch(schid, ccode); return ccode; diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 4bb5262f7..71bf9bded 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -686,6 +686,15 @@ static void qdio_kick_handler(struct qdio_q *q) q->qdio_error = 0; } +static inline int qdio_tasklet_schedule(struct qdio_q *q) +{ + if (likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) { + tasklet_schedule(&q->tasklet); + return 0; + } + return -EPERM; +} + static void __qdio_inbound_processing(struct qdio_q *q) { qperf_inc(q, tasklet_inbound); @@ -698,10 +707,8 @@ static void __qdio_inbound_processing(struct qdio_q *q) if (!qdio_inbound_q_done(q)) { /* means poll time is not yet over */ qperf_inc(q, tasklet_inbound_resched); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { - tasklet_schedule(&q->tasklet); + if (!qdio_tasklet_schedule(q)) return; - } } qdio_stop_polling(q); @@ -711,8 +718,7 @@ static void __qdio_inbound_processing(struct qdio_q *q) */ if (!qdio_inbound_q_done(q)) { qperf_inc(q, tasklet_inbound_resched2); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) - tasklet_schedule(&q->tasklet); + qdio_tasklet_schedule(q); } } @@ -869,16 +875,15 @@ static void __qdio_outbound_processing(struct qdio_q *q) * is noticed and outbound_handler is called after some time. */ if (qdio_outbound_q_done(q)) - del_timer(&q->u.out.timer); + del_timer_sync(&q->u.out.timer); else - if (!timer_pending(&q->u.out.timer)) + if (!timer_pending(&q->u.out.timer) && + likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) mod_timer(&q->u.out.timer, jiffies + 10 * HZ); return; sched: - if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) - return; - tasklet_schedule(&q->tasklet); + qdio_tasklet_schedule(q); } /* outbound tasklet */ @@ -892,9 +897,7 @@ void qdio_outbound_timer(unsigned long data) { struct qdio_q *q = (struct qdio_q *)data; - if (unlikely(q->irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) - return; - tasklet_schedule(&q->tasklet); + qdio_tasklet_schedule(q); } static inline void qdio_check_outbound_after_thinint(struct qdio_q *q) @@ -907,7 +910,7 @@ static inline void qdio_check_outbound_after_thinint(struct qdio_q *q) for_each_output_queue(q->irq_ptr, out, i) if (!qdio_outbound_q_done(out)) - tasklet_schedule(&out->tasklet); + qdio_tasklet_schedule(out); } static void __tiqdio_inbound_processing(struct qdio_q *q) @@ -929,10 +932,8 @@ static void __tiqdio_inbound_processing(struct qdio_q *q) if (!qdio_inbound_q_done(q)) { qperf_inc(q, tasklet_inbound_resched); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { - tasklet_schedule(&q->tasklet); + if (!qdio_tasklet_schedule(q)) return; - } } qdio_stop_polling(q); @@ -942,8 +943,7 @@ static void __tiqdio_inbound_processing(struct qdio_q *q) */ if (!qdio_inbound_q_done(q)) { qperf_inc(q, tasklet_inbound_resched2); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) - tasklet_schedule(&q->tasklet); + qdio_tasklet_schedule(q); } } @@ -977,7 +977,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) int i; struct qdio_q *q; - if (unlikely(irq_ptr->state == QDIO_IRQ_STATE_STOPPED)) + if (unlikely(irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; for_each_input_queue(irq_ptr, q, i) { @@ -1003,7 +1003,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) continue; if (need_siga_sync(q) && need_siga_sync_out_after_pci(q)) qdio_siga_sync_q(q); - tasklet_schedule(&q->tasklet); + qdio_tasklet_schedule(q); } } @@ -1066,10 +1066,12 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; + struct subchannel_id schid; int cstat, dstat; if (!intparm || !irq_ptr) { - DBF_ERROR("qint:%4x", cdev->private->schid.sch_no); + ccw_device_get_schid(cdev, &schid); + DBF_ERROR("qint:%4x", schid.sch_no); return; } @@ -1122,12 +1124,14 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, int qdio_get_ssqd_desc(struct ccw_device *cdev, struct qdio_ssqd_desc *data) { + struct subchannel_id schid; if (!cdev || !cdev->private) return -EINVAL; - DBF_EVENT("get ssqd:%4x", cdev->private->schid.sch_no); - return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); + ccw_device_get_schid(cdev, &schid); + DBF_EVENT("get ssqd:%4x", schid.sch_no); + return qdio_setup_get_ssqd(NULL, &schid, data); } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); @@ -1141,7 +1145,7 @@ static void qdio_shutdown_queues(struct ccw_device *cdev) tasklet_kill(&q->tasklet); for_each_output_queue(irq_ptr, q, i) { - del_timer(&q->u.out.timer); + del_timer_sync(&q->u.out.timer); tasklet_kill(&q->tasklet); } } @@ -1154,14 +1158,15 @@ static void qdio_shutdown_queues(struct ccw_device *cdev) int qdio_shutdown(struct ccw_device *cdev, int how) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; + struct subchannel_id schid; int rc; - unsigned long flags; if (!irq_ptr) return -ENODEV; WARN_ON_ONCE(irqs_disabled()); - DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); + ccw_device_get_schid(cdev, &schid); + DBF_EVENT("qshutdown:%4x", schid.sch_no); mutex_lock(&irq_ptr->setup_mutex); /* @@ -1184,7 +1189,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how) qdio_shutdown_debug_entries(irq_ptr); /* cleanup subchannel */ - spin_lock_irqsave(get_ccwdev_lock(cdev), flags); + spin_lock_irq(get_ccwdev_lock(cdev)); if (how & QDIO_FLAG_CLEANUP_USING_CLEAR) rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP); @@ -1198,12 +1203,12 @@ int qdio_shutdown(struct ccw_device *cdev, int how) } qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); - spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); + spin_unlock_irq(get_ccwdev_lock(cdev)); wait_event_interruptible_timeout(cdev->private->wait_q, irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || irq_ptr->state == QDIO_IRQ_STATE_ERR, 10 * HZ); - spin_lock_irqsave(get_ccwdev_lock(cdev), flags); + spin_lock_irq(get_ccwdev_lock(cdev)); no_cleanup: qdio_shutdown_thinint(irq_ptr); @@ -1211,7 +1216,7 @@ no_cleanup: /* restore interrupt handler */ if ((void *)cdev->handler == (void *)qdio_int_handler) cdev->handler = irq_ptr->orig_handler; - spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); + spin_unlock_irq(get_ccwdev_lock(cdev)); qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); mutex_unlock(&irq_ptr->setup_mutex); @@ -1228,11 +1233,13 @@ EXPORT_SYMBOL_GPL(qdio_shutdown); int qdio_free(struct ccw_device *cdev) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; + struct subchannel_id schid; if (!irq_ptr) return -ENODEV; - DBF_EVENT("qfree:%4x", cdev->private->schid.sch_no); + ccw_device_get_schid(cdev, &schid); + DBF_EVENT("qfree:%4x", schid.sch_no); DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf abandoned"); mutex_lock(&irq_ptr->setup_mutex); @@ -1251,9 +1258,11 @@ EXPORT_SYMBOL_GPL(qdio_free); */ int qdio_allocate(struct qdio_initialize *init_data) { + struct subchannel_id schid; struct qdio_irq *irq_ptr; - DBF_EVENT("qallocate:%4x", init_data->cdev->private->schid.sch_no); + ccw_device_get_schid(init_data->cdev, &schid); + DBF_EVENT("qallocate:%4x", schid.sch_no); if ((init_data->no_input_qs && !init_data->input_handler) || (init_data->no_output_qs && !init_data->output_handler)) @@ -1331,20 +1340,18 @@ static void qdio_detect_hsicq(struct qdio_irq *irq_ptr) */ int qdio_establish(struct qdio_initialize *init_data) { - struct qdio_irq *irq_ptr; struct ccw_device *cdev = init_data->cdev; - unsigned long saveflags; + struct subchannel_id schid; + struct qdio_irq *irq_ptr; int rc; - DBF_EVENT("qestablish:%4x", cdev->private->schid.sch_no); + ccw_device_get_schid(cdev, &schid); + DBF_EVENT("qestablish:%4x", schid.sch_no); irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; - if (cdev->private->state != DEV_STATE_ONLINE) - return -EINVAL; - mutex_lock(&irq_ptr->setup_mutex); qdio_setup_irq(init_data); @@ -1361,17 +1368,14 @@ int qdio_establish(struct qdio_initialize *init_data) irq_ptr->ccw.count = irq_ptr->equeue.count; irq_ptr->ccw.cda = (u32)((addr_t)irq_ptr->qdr); - spin_lock_irqsave(get_ccwdev_lock(cdev), saveflags); + spin_lock_irq(get_ccwdev_lock(cdev)); ccw_device_set_options_mask(cdev, 0); rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0); + spin_unlock_irq(get_ccwdev_lock(cdev)); if (rc) { DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no); DBF_ERROR("rc:%4x", rc); - } - spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); - - if (rc) { mutex_unlock(&irq_ptr->setup_mutex); qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); return rc; @@ -1407,19 +1411,17 @@ EXPORT_SYMBOL_GPL(qdio_establish); */ int qdio_activate(struct ccw_device *cdev) { + struct subchannel_id schid; struct qdio_irq *irq_ptr; int rc; - unsigned long saveflags; - DBF_EVENT("qactivate:%4x", cdev->private->schid.sch_no); + ccw_device_get_schid(cdev, &schid); + DBF_EVENT("qactivate:%4x", schid.sch_no); irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; - if (cdev->private->state != DEV_STATE_ONLINE) - return -EINVAL; - mutex_lock(&irq_ptr->setup_mutex); if (irq_ptr->state == QDIO_IRQ_STATE_INACTIVE) { rc = -EBUSY; @@ -1431,19 +1433,17 @@ int qdio_activate(struct ccw_device *cdev) irq_ptr->ccw.count = irq_ptr->aqueue.count; irq_ptr->ccw.cda = 0; - spin_lock_irqsave(get_ccwdev_lock(cdev), saveflags); + spin_lock_irq(get_ccwdev_lock(cdev)); ccw_device_set_options(cdev, CCWDEV_REPORT_ALL); rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ACTIVATE, 0, DOIO_DENY_PREFETCH); + spin_unlock_irq(get_ccwdev_lock(cdev)); if (rc) { DBF_ERROR("%4x act IO ERR", irq_ptr->schid.sch_no); DBF_ERROR("rc:%4x", rc); - } - spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); - - if (rc) goto out; + } if (is_thinint_irq(irq_ptr)) tiqdio_add_input_queues(irq_ptr); @@ -1585,10 +1585,11 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, /* in case of SIGA errors we must process the error immediately */ if (used >= q->u.out.scan_threshold || rc) - tasklet_schedule(&q->tasklet); + qdio_tasklet_schedule(q); else /* free the SBALs in case of no further traffic */ - if (!timer_pending(&q->u.out.timer)) + if (!timer_pending(&q->u.out.timer) && + likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) mod_timer(&q->u.out.timer, jiffies + HZ); return rc; } -- cgit v1.2.3-54-g00ecf