The only generic interface to execute asynchronously in the BH context is tasklet; however, it's marked deprecated and has some design flaws. To replace tasklets, BH workqueue support was recently added. A BH workqueue behaves similarly to regular workqueues except that the queued work items are executed in the BH context. This patch converts drivers/infiniband/* from tasklet to BH workqueue. Based on the work done by Tejun Heo <tj@xxxxxxxxxx> Branch: https://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git for-6.10 Note: Not tested. Please test/review. Signed-off-by: Allen Pais <allen.lkml@xxxxxxxxx> --- drivers/s390/block/dasd.c | 42 ++++++++++++------------ drivers/s390/block/dasd_int.h | 10 +++--- drivers/s390/char/con3270.c | 27 ++++++++-------- drivers/s390/crypto/ap_bus.c | 24 +++++++------- drivers/s390/crypto/ap_bus.h | 2 +- drivers/s390/crypto/zcrypt_msgtype50.c | 2 +- drivers/s390/crypto/zcrypt_msgtype6.c | 4 +-- drivers/s390/net/ctcm_fsms.c | 4 +-- drivers/s390/net/ctcm_main.c | 15 ++++----- drivers/s390/net/ctcm_main.h | 5 +-- drivers/s390/net/ctcm_mpc.c | 12 +++---- drivers/s390/net/ctcm_mpc.h | 7 ++-- drivers/s390/net/lcs.c | 26 +++++++-------- drivers/s390/net/lcs.h | 2 +- drivers/s390/net/qeth_core_main.c | 2 +- drivers/s390/scsi/zfcp_qdio.c | 45 +++++++++++++------------- drivers/s390/scsi/zfcp_qdio.h | 9 +++--- 17 files changed, 117 insertions(+), 121 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 0a97cfedd706..c6f9910f0a98 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -54,8 +54,8 @@ MODULE_LICENSE("GPL"); * SECTION: prototypes for static functions of dasd.c */ static int dasd_flush_block_queue(struct dasd_block *); -static void dasd_device_tasklet(unsigned long); -static void dasd_block_tasklet(unsigned long); +static void dasd_device_work(struct work_struct *); +static void dasd_block_work(struct work_struct *); static void do_kick_device(struct work_struct *); static void do_reload_device(struct work_struct *); static void do_requeue_requests(struct work_struct *); @@ -114,9 +114,8 @@ struct dasd_device *dasd_alloc_device(void) dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE); dasd_init_chunklist(&device->ese_chunks, device->ese_mem, PAGE_SIZE * 2); spin_lock_init(&device->mem_lock); - atomic_set(&device->tasklet_scheduled, 0); - tasklet_init(&device->tasklet, dasd_device_tasklet, - (unsigned long) device); + atomic_set(&device->work_scheduled, 0); + INIT_WORK(&device->bh, dasd_device_work); INIT_LIST_HEAD(&device->ccw_queue); timer_setup(&device->timer, dasd_device_timeout, 0); INIT_WORK(&device->kick_work, do_kick_device); @@ -154,9 +153,8 @@ struct dasd_block *dasd_alloc_block(void) /* open_count = 0 means device online but not in use */ atomic_set(&block->open_count, -1); - atomic_set(&block->tasklet_scheduled, 0); - tasklet_init(&block->tasklet, dasd_block_tasklet, - (unsigned long) block); + atomic_set(&block->work_scheduled, 0); + INIT_WORK(&block->bh, dasd_block_work); INIT_LIST_HEAD(&block->ccw_queue); spin_lock_init(&block->queue_lock); INIT_LIST_HEAD(&block->format_list); @@ -2148,12 +2146,12 @@ EXPORT_SYMBOL_GPL(dasd_flush_device_queue); /* * Acquire the device lock and process queues for the device. */ -static void dasd_device_tasklet(unsigned long data) +static void dasd_device_work(struct work_struct *t) { - struct dasd_device *device = (struct dasd_device *) data; + struct dasd_device *device = from_work(device, t, bh); struct list_head final_queue; - atomic_set (&device->tasklet_scheduled, 0); + atomic_set (&device->work_scheduled, 0); INIT_LIST_HEAD(&final_queue); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Check expire time of first request on the ccw queue. */ @@ -2174,15 +2172,15 @@ static void dasd_device_tasklet(unsigned long data) } /* - * Schedules a call to dasd_tasklet over the device tasklet. + * Schedules a call to dasd_work over the device wq. */ void dasd_schedule_device_bh(struct dasd_device *device) { /* Protect against rescheduling. */ - if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0) + if (atomic_cmpxchg (&device->work_scheduled, 0, 1) != 0) return; dasd_get_device(device); - tasklet_hi_schedule(&device->tasklet); + queue_work(system_bh_highpri_wq, &device->bh); } EXPORT_SYMBOL(dasd_schedule_device_bh); @@ -2595,7 +2593,7 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) else rc = -EIO; - /* kick tasklets */ + /* kick works */ dasd_schedule_device_bh(device); if (device->block) dasd_schedule_block_bh(device->block); @@ -2891,15 +2889,15 @@ static void __dasd_block_start_head(struct dasd_block *block) * block layer request queue, creates ccw requests, enqueues them on * a dasd_device and processes ccw requests that have been returned. */ -static void dasd_block_tasklet(unsigned long data) +static void dasd_block_work(struct work_struct *t) { - struct dasd_block *block = (struct dasd_block *) data; + struct dasd_block *block = from_work(block, t, bh); struct list_head final_queue; struct list_head *l, *n; struct dasd_ccw_req *cqr; struct dasd_queue *dq; - atomic_set(&block->tasklet_scheduled, 0); + atomic_set(&block->work_scheduled, 0); INIT_LIST_HEAD(&final_queue); spin_lock_irq(&block->queue_lock); /* Finish off requests on ccw queue */ @@ -2970,7 +2968,7 @@ static int _dasd_requests_to_flushqueue(struct dasd_block *block, if (rc < 0) break; /* Rechain request (including erp chain) so it won't be - * touched by the dasd_block_tasklet anymore. + * touched by the dasd_block_work anymore. * Replace the callback so we notice when the request * is returned from the dasd_device layer. */ @@ -3025,16 +3023,16 @@ static int dasd_flush_block_queue(struct dasd_block *block) } /* - * Schedules a call to dasd_tasklet over the device tasklet. + * Schedules a call to dasd_work over the device wq. */ void dasd_schedule_block_bh(struct dasd_block *block) { /* Protect against rescheduling. */ - if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0) + if (atomic_cmpxchg(&block->work_scheduled, 0, 1) != 0) return; /* life cycle of block is bound to it's base device */ dasd_get_device(block->base); - tasklet_hi_schedule(&block->tasklet); + queue_work(system_bh_highpri_wq, &block->bh); } EXPORT_SYMBOL(dasd_schedule_block_bh); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index e5f40536b425..abe4d43f474e 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -28,7 +28,7 @@ * known -> basic: request irq line for the device. * basic -> ready: do the initial analysis, e.g. format detection, * do block device setup and detect partitions. - * ready -> online: schedule the device tasklet. + * ready -> online: schedule the device work. * Things to do for shutdown state transitions: * online -> ready: just set the new device state. * ready -> basic: flush requests from the block device layer, clear @@ -579,8 +579,8 @@ struct dasd_device { struct list_head erp_chunks; struct list_head ese_chunks; - atomic_t tasklet_scheduled; - struct tasklet_struct tasklet; + atomic_t work_scheduled; + struct work_struct bh; struct work_struct kick_work; struct work_struct reload_device; struct work_struct kick_validate; @@ -630,8 +630,8 @@ struct dasd_block { struct list_head ccw_queue; spinlock_t queue_lock; - atomic_t tasklet_scheduled; - struct tasklet_struct tasklet; + atomic_t work_scheduled; + struct work_struct bh; struct timer_list timer; struct dentry *debugfs_dentry; diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 251d2a1c3eef..993275e9b2f4 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -28,6 +28,7 @@ #include <asm/ebcdic.h> #include <asm/cpcmd.h> #include <linux/uaccess.h> +#include <linux/workqueue.h> #include "raw3270.h" #include "keyboard.h" @@ -107,8 +108,8 @@ struct tty3270 { struct raw3270_request *readpartreq; unsigned char inattr; /* Visible/invisible input. */ int throttle, attn; /* tty throttle/unthrottle. */ - struct tasklet_struct readlet; /* Tasklet to issue read request. */ - struct tasklet_struct hanglet; /* Tasklet to hang up the tty. */ + struct work_struct read_work; /* Work to issue read request. */ + struct work_struct hang_work; /* Work to hang up the tty. */ struct kbd_data *kbd; /* key_maps stuff. */ /* Escape sequence parsing. */ @@ -667,9 +668,9 @@ static void tty3270_scroll_backward(struct kbd_data *kbd) /* * Pass input line to tty. */ -static void tty3270_read_tasklet(unsigned long data) +static void tty3270_read_work(struct work_struct *T) { - struct raw3270_request *rrq = (struct raw3270_request *)data; + struct raw3270_request *rrq = from_work(rrq, t, read_work); static char kreset_data = TW_KR; struct tty3270 *tp = container_of(rrq->view, struct tty3270, view); char *input; @@ -734,8 +735,8 @@ static void tty3270_read_callback(struct raw3270_request *rq, void *data) struct tty3270 *tp = container_of(rq->view, struct tty3270, view); raw3270_get_view(rq->view); - /* Schedule tasklet to pass input to tty. */ - tasklet_schedule(&tp->readlet); + /* Schedule work to pass input to tty. */ + queue_work(system_bh_wq, &tp->read_work); } /* @@ -768,9 +769,9 @@ static void tty3270_issue_read(struct tty3270 *tp, int lock) /* * Hang up the tty */ -static void tty3270_hangup_tasklet(unsigned long data) +static void tty3270_hangup_work(struct work_struct *t) { - struct tty3270 *tp = (struct tty3270 *)data; + struct tty3270 *tp = from_work(tp, t, hang_work); tty_port_tty_hangup(&tp->port, true); raw3270_put_view(&tp->view); @@ -797,7 +798,7 @@ static void tty3270_deactivate(struct raw3270_view *view) static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) { - /* Handle ATTN. Schedule tasklet to read aid. */ + /* Handle ATTN. Schedule work to read aid. */ if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { if (!tp->throttle) tty3270_issue_read(tp, 0); @@ -809,7 +810,7 @@ static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct i if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { rq->rc = -EIO; raw3270_get_view(&tp->view); - tasklet_schedule(&tp->hanglet); + queue_work(system_bh_wq, &tp->hang_work); } else { /* Normal end. Copy residual count. */ rq->rescnt = irb->scsw.cmd.count; @@ -850,10 +851,8 @@ static struct tty3270 *tty3270_alloc_view(void) tty_port_init(&tp->port); timer_setup(&tp->timer, tty3270_update, 0); - tasklet_init(&tp->readlet, tty3270_read_tasklet, - (unsigned long)tp->read); - tasklet_init(&tp->hanglet, tty3270_hangup_tasklet, - (unsigned long)tp); + INIT_WORK(&tp->read_work, tty3270_read_work); + INIT_WORK(&tp->hang_work, tty3270_hangup_work); return tp; out_readpartreq: diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index cce0bafd4c92..5136ecd965ae 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -111,10 +111,10 @@ static void ap_scan_bus_wq_callback(struct work_struct *); static DECLARE_WORK(ap_scan_bus_work, ap_scan_bus_wq_callback); /* - * Tasklet & timer for AP request polling and interrupts + * Work & timer for AP request polling and interrupts */ -static void ap_tasklet_fn(unsigned long); -static DECLARE_TASKLET_OLD(ap_tasklet, ap_tasklet_fn); +static void ap_work_fn(struct work_struct *); +static DECLARE_WORK(ap_work, ap_work_fn); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread; static DEFINE_MUTEX(ap_poll_thread_mutex); @@ -450,16 +450,16 @@ void ap_request_timeout(struct timer_list *t) * ap_poll_timeout(): AP receive polling for finished AP requests. * @unused: Unused pointer. * - * Schedules the AP tasklet using a high resolution timer. + * Schedules the AP work using a high resolution timer. */ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) { - tasklet_schedule(&ap_tasklet); + queue_work(system_bh_wq, &ap_work); return HRTIMER_NORESTART; } /** - * ap_interrupt_handler() - Schedule ap_tasklet on interrupt + * ap_interrupt_handler() - Schedule ap_work on interrupt * @airq: pointer to adapter interrupt descriptor * @tpi_info: ignored */ @@ -467,23 +467,23 @@ static void ap_interrupt_handler(struct airq_struct *airq, struct tpi_info *tpi_info) { inc_irq_stat(IRQIO_APB); - tasklet_schedule(&ap_tasklet); + queue_work(system_bh_wq, &ap_work); } /** - * ap_tasklet_fn(): Tasklet to poll all AP devices. - * @dummy: Unused variable + * ap_work_fn(): Work to poll all AP devices. + * @t: pointer to work_struct * * Poll all AP devices on the bus. */ -static void ap_tasklet_fn(unsigned long dummy) +static void ap_work_fn(struct work_struct *t) { int bkt; struct ap_queue *aq; enum ap_sm_wait wait = AP_SM_WAIT_NONE; /* Reset the indicator if interrupts are used. Thus new interrupts can - * be received. Doing it in the beginning of the tasklet is therefore + * be received. Doing it in the beginning of the work is therefore * important that no requests on any AP get lost. */ if (ap_irq_flag) @@ -546,7 +546,7 @@ static int ap_poll_thread(void *data) try_to_freeze(); continue; } - ap_tasklet_fn(0); + queue_work(system_bh_wq, &ap_work); } return 0; diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 59c7ed49aa02..7daea5c536c9 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -223,7 +223,7 @@ struct ap_message { u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ int rc; /* Return code for this message */ void *private; /* ap driver private pointer. */ - /* receive is called from tasklet context */ + /* receive is called from work context */ void (*receive)(struct ap_queue *, struct ap_message *, struct ap_message *); }; diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 3b39cb8f926d..c7bf389f2938 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -403,7 +403,7 @@ static int convert_response(struct zcrypt_queue *zq, /* * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". - * It is called from tasklet context. + * It is called from work context. * @aq: pointer to the AP device * @msg: pointer to the AP message * @reply: pointer to the AP reply message diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 215f257d2360..b62e2c9cee58 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -847,7 +847,7 @@ static int convert_response_rng(struct zcrypt_queue *zq, /* * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". - * It is called from tasklet context. + * It is called from work context. * @aq: pointer to the AP queue * @msg: pointer to the AP message * @reply: pointer to the AP reply message @@ -913,7 +913,7 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, /* * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". - * It is called from tasklet context. + * It is called from work context. * @aq: pointer to the AP queue * @msg: pointer to the AP message * @reply: pointer to the AP reply message diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index 9678c6a2cda7..3b02a41c4386 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -1420,12 +1420,12 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg) case MPCG_STATE_READY: skb_put_data(new_skb, skb->data, block_len); skb_queue_tail(&ch->io_queue, new_skb); - tasklet_schedule(&ch->ch_tasklet); + queue_work(system_bh_wq, &ch->ch_work); break; default: skb_put_data(new_skb, skb->data, len); skb_queue_tail(&ch->io_queue, new_skb); - tasklet_hi_schedule(&ch->ch_tasklet); + queue_work(system_bh_highpri_wq, &ch->ch_work); break; } } diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 878fe3ce53ad..c504db179982 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -223,8 +223,8 @@ static void channel_remove(struct channel *ch) dev_kfree_skb_any(ch->trans_skb); } if (IS_MPC(ch)) { - tasklet_kill(&ch->ch_tasklet); - tasklet_kill(&ch->ch_disc_tasklet); + cancel_work_sync(&ch->ch_work); + cancel_work_sync(&ch->ch_disc_work); kfree(ch->discontact_th); } kfree(ch->ccw); @@ -1027,7 +1027,7 @@ static void ctcm_free_netdevice(struct net_device *dev) kfree_fsm(grp->fsm); dev_kfree_skb(grp->xid_skb); dev_kfree_skb(grp->rcvd_xid_skb); - tasklet_kill(&grp->mpc_tasklet2); + cancel_work_sync(&grp->mpc_work2); kfree(grp); priv->mpcg = NULL; } @@ -1118,8 +1118,7 @@ static struct net_device *ctcm_init_netdevice(struct ctcm_priv *priv) free_netdev(dev); return NULL; } - tasklet_init(&grp->mpc_tasklet2, - mpc_group_ready, (unsigned long)dev); + INIT_WORK(&grp->mpc_work2, mpc_group_ready); dev->mtu = MPC_BUFSIZE_DEFAULT - TH_HEADER_LENGTH - PDU_HEADER_LENGTH; @@ -1319,10 +1318,8 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type, goto nomem_return; ch->discontact_th->th_blk_flag = TH_DISCONTACT; - tasklet_init(&ch->ch_disc_tasklet, - mpc_action_send_discontact, (unsigned long)ch); - - tasklet_init(&ch->ch_tasklet, ctcmpc_bh, (unsigned long)ch); + INIT_WORK(&ch->ch_disc_work, mpc_action_send_discontact); + INIT_WORK(&ch->ch_work, ctcmpc_bh); ch->max_bufsize = (MPC_BUFSIZE_DEFAULT - 35); ccw_num = 17; } else diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index 25164e8bf13d..1143c037a7f7 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -13,6 +13,7 @@ #include <linux/skbuff.h> #include <linux/netdevice.h> +#include <linux/workqueue.h> #include "fsm.h" #include "ctcm_dbug.h" @@ -154,7 +155,7 @@ struct channel { int max_bufsize; struct sk_buff *trans_skb; /* transmit/receive buffer */ struct sk_buff_head io_queue; /* universal I/O queue */ - struct tasklet_struct ch_tasklet; /* MPC ONLY */ + struct work_struct ch_work; /* MPC ONLY */ /* * TX queue for collecting skb's during busy. */ @@ -188,7 +189,7 @@ struct channel { fsm_timer sweep_timer; struct sk_buff_head sweep_queue; struct th_header *discontact_th; - struct tasklet_struct ch_disc_tasklet; + struct work_struct ch_disc_work; /* MPC ONLY section end */ int retry; /* retry counter for misc. operations */ diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index 9e580ef69bda..0b7ed15ce29d 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -588,7 +588,7 @@ void ctc_mpc_flow_control(int port_num, int flowc) fsm_newstate(grp->fsm, MPCG_STATE_READY); /* ensure any data that has accumulated */ /* on the io_queue will now be sen t */ - tasklet_schedule(&rch->ch_tasklet); + queue_work(system_bh_wq, &rch->ch_work); } /* possible race condition */ if (mpcg_state == MPCG_STATE_READY) { @@ -847,7 +847,7 @@ static void mpc_action_go_ready(fsm_instance *fsm, int event, void *arg) grp->out_of_sequence = 0; grp->estconn_called = 0; - tasklet_hi_schedule(&grp->mpc_tasklet2); + queue_work(system_bh_highpri_wq, &grp->mpc_work2); return; } @@ -1213,16 +1213,16 @@ static void ctcmpc_unpack_skb(struct channel *ch, struct sk_buff *pskb) } /* - * tasklet helper for mpc's skb unpacking. + * work helper for mpc's skb unpacking. * * ch The channel to work on. * Allow flow control back pressure to occur here. * Throttling back channel can result in excessive * channel inactivity and system deact of channel */ -void ctcmpc_bh(unsigned long thischan) +void ctcmpc_bh(struct work_struct *t) { - struct channel *ch = (struct channel *)thischan; + struct channel *ch = from_work(ch, t, ch_work); struct sk_buff *skb; struct net_device *dev = ch->netdev; struct ctcm_priv *priv = dev->ml_priv; @@ -1380,7 +1380,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg) case MPCG_STATE_FLOWC: case MPCG_STATE_READY: default: - tasklet_hi_schedule(&wch->ch_disc_tasklet); + queue_work(system_bh_wq, &wch->ch_disc_work); } grp->xid2_tgnum = 0; diff --git a/drivers/s390/net/ctcm_mpc.h b/drivers/s390/net/ctcm_mpc.h index da41b26f76d1..735bea5d565a 100644 --- a/drivers/s390/net/ctcm_mpc.h +++ b/drivers/s390/net/ctcm_mpc.h @@ -13,6 +13,7 @@ #include <linux/interrupt.h> #include <linux/skbuff.h> +#include <linux/workqueue.h> #include "fsm.h" /* @@ -156,8 +157,8 @@ struct mpcg_info { }; struct mpc_group { - struct tasklet_struct mpc_tasklet; - struct tasklet_struct mpc_tasklet2; + struct work_struct mpc_work; + struct work_struct mpc_work2; int changed_side; int saved_state; int channels_terminating; @@ -233,6 +234,6 @@ void mpc_group_ready(unsigned long adev); void mpc_channel_action(struct channel *ch, int direction, int action); void mpc_action_send_discontact(unsigned long thischan); void mpc_action_discontact(fsm_instance *fi, int event, void *arg); -void ctcmpc_bh(unsigned long thischan); +void ctcmpc_bh(struct work_struct *t); #endif /* --- This is the END my friend --- */ diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 25d4e6376591..751b7b212c91 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -49,7 +49,7 @@ static struct device *lcs_root_dev; /* * Some prototypes. */ -static void lcs_tasklet(unsigned long); +static void lcs_work(struct work_struct *); static void lcs_start_kernel_thread(struct work_struct *); static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); #ifdef CONFIG_IP_MULTICAST @@ -140,8 +140,8 @@ static void lcs_cleanup_channel(struct lcs_channel *channel) { LCS_DBF_TEXT(3, setup, "cleanch"); - /* Kill write channel tasklets. */ - tasklet_kill(&channel->irq_tasklet); + /* Kill write channel works. */ + cancel_work_sync(&channel->irq_work); /* Free channel buffers. */ lcs_free_channel(channel); } @@ -244,9 +244,8 @@ lcs_setup_read(struct lcs_card *card) LCS_DBF_TEXT(3, setup, "initread"); lcs_setup_read_ccws(card); - /* Initialize read channel tasklet. */ - card->read.irq_tasklet.data = (unsigned long) &card->read; - card->read.irq_tasklet.func = lcs_tasklet; + /* Initialize read channel work. */ + INIT_WORK(card->read.irq_work, lcs_work); /* Initialize waitqueue. */ init_waitqueue_head(&card->read.wait_q); } @@ -290,9 +289,8 @@ lcs_setup_write(struct lcs_card *card) LCS_DBF_TEXT(3, setup, "initwrit"); lcs_setup_write_ccws(card); - /* Initialize write channel tasklet. */ - card->write.irq_tasklet.data = (unsigned long) &card->write; - card->write.irq_tasklet.func = lcs_tasklet; + /* Initialize write channel work. */ + INIT_WORK(card->write.irq_work, lcs_work); /* Initialize waitqueue. */ init_waitqueue_head(&card->write.wait_q); } @@ -1429,22 +1427,22 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) channel->state = LCS_CH_STATE_CLEARED; - /* Do the rest in the tasklet. */ - tasklet_schedule(&channel->irq_tasklet); + /* Do the rest in the work. */ + queue_work(system_bh_wq, &channel->irq_work); } /* - * Tasklet for IRQ handler + * Work for IRQ handler */ static void -lcs_tasklet(unsigned long data) +lcs_work(struct work_struct *t) { unsigned long flags; struct lcs_channel *channel; struct lcs_buffer *iob; int buf_idx; - channel = (struct lcs_channel *) data; + channel = from_work(channel, t, irq_work); LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev)); /* Check for processed buffers. */ diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index a2699b70b050..66bc02e1d7e5 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -290,7 +290,7 @@ struct lcs_channel { struct ccw_device *ccwdev; struct ccw1 ccws[LCS_NUM_BUFFS + 1]; wait_queue_head_t wait_q; - struct tasklet_struct irq_tasklet; + struct work_struct irq_work; struct lcs_buffer iob[LCS_NUM_BUFFS]; int io_idx; int buf_idx; diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index a0cce6872075..10ea95abc753 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2911,7 +2911,7 @@ static int qeth_init_input_buffer(struct qeth_card *card, } /* - * since the buffer is accessed only from the input_tasklet + * since the buffer is accessed only from the input_work * there shouldn't be a need to synchronize; also, since we use * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run out off * buffers diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 8cbc5e1711af..407590697c66 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -13,6 +13,7 @@ #include <linux/lockdep.h> #include <linux/slab.h> #include <linux/module.h> +#include <linux/workqueue.h> #include "zfcp_ext.h" #include "zfcp_qdio.h" @@ -72,9 +73,9 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err); } -static void zfcp_qdio_request_tasklet(struct tasklet_struct *tasklet) +static void zfcp_qdio_request_work(struct work_struct *work) { - struct zfcp_qdio *qdio = from_tasklet(qdio, tasklet, request_tasklet); + struct zfcp_qdio *qdio = from_work(qdio, work, request_work); struct ccw_device *cdev = qdio->adapter->ccw_device; unsigned int start, error; int completed; @@ -104,7 +105,7 @@ static void zfcp_qdio_request_timer(struct timer_list *timer) { struct zfcp_qdio *qdio = from_timer(qdio, timer, request_timer); - tasklet_schedule(&qdio->request_tasklet); + queue_work(system_bh_wq, &qdio->request_work); } static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, @@ -158,15 +159,15 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2"); } -static void zfcp_qdio_irq_tasklet(struct tasklet_struct *tasklet) +static void zfcp_qdio_irq_work(struct work_struct *work) { - struct zfcp_qdio *qdio = from_tasklet(qdio, tasklet, irq_tasklet); + struct zfcp_qdio *qdio = from_work(qdio, work, irq_work); struct ccw_device *cdev = qdio->adapter->ccw_device; unsigned int start, error; int completed; if (atomic_read(&qdio->req_q_free) < QDIO_MAX_BUFFERS_PER_Q) - tasklet_schedule(&qdio->request_tasklet); + queue_work(system_bh_wq, &qdio->request_work); /* Check the Response Queue: */ completed = qdio_inspect_input_queue(cdev, 0, &start, &error); @@ -178,14 +179,14 @@ static void zfcp_qdio_irq_tasklet(struct tasklet_struct *tasklet) if (qdio_start_irq(cdev)) /* More work pending: */ - tasklet_schedule(&qdio->irq_tasklet); + queue_work(system_bh_wq, &qdio->irq_work); } static void zfcp_qdio_poll(struct ccw_device *cdev, unsigned long data) { struct zfcp_qdio *qdio = (struct zfcp_qdio *) data; - tasklet_schedule(&qdio->irq_tasklet); + queue_work(system_bh_wq, &qdio->irq_work); } static struct qdio_buffer_element * @@ -315,7 +316,7 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) /* * This should actually be a spin_lock_bh(stat_lock), to protect against - * Request Queue completion processing in tasklet context. + * Request Queue completion processing in work context. * But we can't do so (and are safe), as we always get called with IRQs * disabled by spin_lock_irq[save](req_q_lock). */ @@ -339,7 +340,7 @@ int zfcp_qdio_send(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) } if (atomic_read(&qdio->req_q_free) <= 2 * ZFCP_QDIO_MAX_SBALS_PER_REQ) - tasklet_schedule(&qdio->request_tasklet); + queue_work(system_bh_wq, &qdio->request_work); else timer_reduce(&qdio->request_timer, jiffies + msecs_to_jiffies(ZFCP_QDIO_REQUEST_SCAN_MSECS)); @@ -406,8 +407,8 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) wake_up(&qdio->req_q_wq); - tasklet_disable(&qdio->irq_tasklet); - tasklet_disable(&qdio->request_tasklet); + disable_work_sync(&qdio->irq_work); + disable_work_sync(&qdio->request_work); del_timer_sync(&qdio->request_timer); qdio_stop_irq(adapter->ccw_device); qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR); @@ -511,11 +512,11 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) atomic_or(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); /* Enable processing for Request Queue completions: */ - tasklet_enable(&qdio->request_tasklet); + enable_and_queue_work(system_bh_wq, &qdio->request_work); /* Enable processing for QDIO interrupts: */ - tasklet_enable(&qdio->irq_tasklet); + enable_and_queue_work(system_bh_wq, &qdio->irq_work); /* This results in a qdio_start_irq(): */ - tasklet_schedule(&qdio->irq_tasklet); + queue_work(system_bh_wq, &qdio->irq_work); zfcp_qdio_shost_update(adapter, qdio); @@ -534,8 +535,8 @@ void zfcp_qdio_destroy(struct zfcp_qdio *qdio) if (!qdio) return; - tasklet_kill(&qdio->irq_tasklet); - tasklet_kill(&qdio->request_tasklet); + cancel_work_sync(&qdio->irq_work); + cancel_work_sync(&qdio->request_work); if (qdio->adapter->ccw_device) qdio_free(qdio->adapter->ccw_device); @@ -563,10 +564,10 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) spin_lock_init(&qdio->req_q_lock); spin_lock_init(&qdio->stat_lock); timer_setup(&qdio->request_timer, zfcp_qdio_request_timer, 0); - tasklet_setup(&qdio->irq_tasklet, zfcp_qdio_irq_tasklet); - tasklet_setup(&qdio->request_tasklet, zfcp_qdio_request_tasklet); - tasklet_disable(&qdio->irq_tasklet); - tasklet_disable(&qdio->request_tasklet); + INIT_WORK(&qdio->irq_work, zfcp_qdio_irq_work); + INIT_WORK(&qdio->request_work, zfcp_qdio_request_work); + disable_work_sync(&qdio->irq_work); + disable_work_sync(&qdio->request_work); adapter->qdio = qdio; return 0; @@ -580,7 +581,7 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) * wrapper function sets a flag to ensure hardware logging is only * triggered once before going through qdio shutdown. * - * The triggers are always run from qdio tasklet context, so no + * The triggers are always run from qdio work context, so no * additional synchronization is necessary. */ void zfcp_qdio_siosl(struct zfcp_adapter *adapter) diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 8f7d2ae94441..ce92d2378b98 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h @@ -11,6 +11,7 @@ #define ZFCP_QDIO_H #include <linux/interrupt.h> +#include <linux/workqueue.h> #include <asm/qdio.h> #define ZFCP_QDIO_SBALE_LEN PAGE_SIZE @@ -30,8 +31,8 @@ * @req_q_util: used for accounting * @req_q_full: queue full incidents * @req_q_wq: used to wait for SBAL availability - * @irq_tasklet: used for QDIO interrupt processing - * @request_tasklet: used for Request Queue completion processing + * @irq_work: used for QDIO interrupt processing + * @request_work: used for Request Queue completion processing * @request_timer: used to trigger the Request Queue completion processing * @adapter: adapter used in conjunction with this qdio structure * @max_sbale_per_sbal: qdio limit per sbal @@ -48,8 +49,8 @@ struct zfcp_qdio { u64 req_q_util; atomic_t req_q_full; wait_queue_head_t req_q_wq; - struct tasklet_struct irq_tasklet; - struct tasklet_struct request_tasklet; + struct work_struct irq_work; + struct work_struct request_work; struct timer_list request_timer; struct zfcp_adapter *adapter; u16 max_sbale_per_sbal; -- 2.17.1