diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd.c | 20 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 10 | ||||
-rw-r--r-- | drivers/s390/char/con3215.c | 22 | ||||
-rw-r--r-- | drivers/s390/char/con3270.c | 13 | ||||
-rw-r--r-- | drivers/s390/char/monreader.c | 6 | ||||
-rw-r--r-- | drivers/s390/char/raw3270.c | 36 | ||||
-rw-r--r-- | drivers/s390/char/sclp_con.c | 7 | ||||
-rw-r--r-- | drivers/s390/char/sclp_vt220.c | 18 | ||||
-rw-r--r-- | drivers/s390/char/tape_core.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/vmlogrdr.c | 4 | ||||
-rw-r--r-- | drivers/s390/char/vmur.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 11 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_debug.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 144 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 114 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 85 | ||||
-rw-r--r-- | drivers/s390/net/netiucv.c | 4 |
17 files changed, 229 insertions, 272 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index e5b84db0aa03..749836668655 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -470,7 +470,7 @@ static int dasd_decrease_state(struct dasd_device *device) */ static void dasd_change_state(struct dasd_device *device) { - int rc; + int rc; if (device->state == device->target) /* Already where we want to go today... */ @@ -479,8 +479,10 @@ static void dasd_change_state(struct dasd_device *device) rc = dasd_increase_state(device); else rc = dasd_decrease_state(device); - if (rc && rc != -EAGAIN) - device->target = device->state; + if (rc == -EAGAIN) + return; + if (rc) + device->target = device->state; if (device->state == device->target) { wake_up(&dasd_init_waitq); @@ -2503,15 +2505,25 @@ int dasd_generic_restore_device(struct ccw_device *cdev) if (IS_ERR(device)) return PTR_ERR(device); + /* allow new IO again */ + device->stopped &= ~DASD_STOPPED_PM; + device->stopped &= ~DASD_UNRESUMED_PM; + dasd_schedule_device_bh(device); if (device->block) dasd_schedule_block_bh(device->block); if (device->discipline->restore) rc = device->discipline->restore(device); + if (rc) + /* + * if the resume failed for the DASD we put it in + * an UNRESUMED stop state + */ + device->stopped |= DASD_UNRESUMED_PM; dasd_put_device(device); - return rc; + return 0; } EXPORT_SYMBOL_GPL(dasd_generic_restore_device); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 1c28ec3e4ccb..f8b1f04f26b8 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3243,9 +3243,6 @@ int dasd_eckd_restore_device(struct dasd_device *device) int is_known, rc; struct dasd_uid temp_uid; - /* allow new IO again */ - device->stopped &= ~DASD_STOPPED_PM; - private = (struct dasd_eckd_private *) device->private; /* Read Configuration Data */ @@ -3295,12 +3292,7 @@ int dasd_eckd_restore_device(struct dasd_device *device) return 0; out_err: - /* - * if the resume failed for the DASD we put it in - * an UNRESUMED stop state - */ - device->stopped |= DASD_UNRESUMED_PM; - return 0; + return -1; } static struct ccw_driver dasd_eckd_driver = { diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 04dc734805c6..21639d6c996f 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -20,10 +20,7 @@ #include <linux/interrupt.h> #include <linux/err.h> #include <linux/reboot.h> - #include <linux/slab.h> -#include <linux/bootmem.h> - #include <asm/ccwdev.h> #include <asm/cio.h> #include <asm/io.h> @@ -735,7 +732,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev) unsigned long flags; /* Empty the output buffer, then prevent new I/O. */ - raw = cdev->dev.driver_data; + raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); raw->flags |= RAW3215_FROZEN; @@ -749,7 +746,7 @@ static int raw3215_pm_start(struct ccw_device *cdev) unsigned long flags; /* Allow I/O again and flush output buffer. */ - raw = cdev->dev.driver_data; + raw = dev_get_drvdata(&cdev->dev); spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); raw->flags &= ~RAW3215_FROZEN; raw->flags |= RAW3215_FLUSHING; @@ -883,7 +880,7 @@ static int __init con3215_init(void) raw3215_freelist = NULL; spin_lock_init(&raw3215_freelist_lock); for (i = 0; i < NR_3215_REQ; i++) { - req = (struct raw3215_req *) alloc_bootmem_low(sizeof(struct raw3215_req)); + req = kzalloc(sizeof(struct raw3215_req), GFP_KERNEL | GFP_DMA); req->next = raw3215_freelist; raw3215_freelist = req; } @@ -893,10 +890,9 @@ static int __init con3215_init(void) return -ENODEV; raw3215[0] = raw = (struct raw3215_info *) - alloc_bootmem_low(sizeof(struct raw3215_info)); - memset(raw, 0, sizeof(struct raw3215_info)); - raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); - raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); + kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA); + raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); + raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA); raw->cdev = cdev; dev_set_drvdata(&cdev->dev, raw); cdev->handler = raw3215_irq; @@ -906,9 +902,9 @@ static int __init con3215_init(void) /* Request the console irq */ if (raw3215_startup(raw) != 0) { - free_bootmem((unsigned long) raw->inbuf, RAW3215_INBUF_SIZE); - free_bootmem((unsigned long) raw->buffer, RAW3215_BUFFER_SIZE); - free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); + kfree(raw->inbuf); + kfree(raw->buffer); + kfree(raw); raw3215[0] = NULL; return -ENODEV; } diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 44d02e371c04..bb838bdf829d 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -7,7 +7,6 @@ * Copyright IBM Corp. 2003, 2009 */ -#include <linux/bootmem.h> #include <linux/console.h> #include <linux/init.h> #include <linux/interrupt.h> @@ -600,16 +599,14 @@ con3270_init(void) if (IS_ERR(rp)) return PTR_ERR(rp); - condev = (struct con3270 *) alloc_bootmem_low(sizeof(struct con3270)); - memset(condev, 0, sizeof(struct con3270)); + condev = kzalloc(sizeof(struct con3270), GFP_KERNEL | GFP_DMA); condev->view.dev = rp; - condev->read = raw3270_request_alloc_bootmem(0); + condev->read = raw3270_request_alloc(0); condev->read->callback = con3270_read_callback; condev->read->callback_data = condev; - condev->write = - raw3270_request_alloc_bootmem(CON3270_OUTPUT_BUFFER_SIZE); - condev->kreset = raw3270_request_alloc_bootmem(1); + condev->write = raw3270_request_alloc(CON3270_OUTPUT_BUFFER_SIZE); + condev->kreset = raw3270_request_alloc(1); INIT_LIST_HEAD(&condev->lines); INIT_LIST_HEAD(&condev->update); @@ -623,7 +620,7 @@ con3270_init(void) INIT_LIST_HEAD(&condev->freemem); for (i = 0; i < CON3270_STRING_PAGES; i++) { - cbuf = (void *) alloc_bootmem_low_pages(PAGE_SIZE); + cbuf = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); add_string_memory(&condev->freemem, cbuf, PAGE_SIZE); } condev->cline = alloc_string(&condev->freemem, condev->view.cols); diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 75a8831eebbc..7892550d7932 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -320,7 +320,7 @@ static int mon_open(struct inode *inode, struct file *filp) goto out_path; } filp->private_data = monpriv; - monreader_device->driver_data = monpriv; + dev_set_drvdata(&monreader_device, monpriv); unlock_kernel(); return nonseekable_open(inode, filp); @@ -463,7 +463,7 @@ static struct miscdevice mon_dev = { *****************************************************************************/ static int monreader_freeze(struct device *dev) { - struct mon_private *monpriv = dev->driver_data; + struct mon_private *monpriv = dev_get_drvdata(&dev); int rc; if (!monpriv) @@ -487,7 +487,7 @@ static int monreader_freeze(struct device *dev) static int monreader_thaw(struct device *dev) { - struct mon_private *monpriv = dev->driver_data; + struct mon_private *monpriv = dev_get_drvdata(dev); int rc; if (!monpriv) diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index acab7b2dfe8a..d6a022f55e92 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -7,7 +7,6 @@ * Copyright IBM Corp. 2003, 2009 */ -#include <linux/bootmem.h> #include <linux/module.h> #include <linux/err.h> #include <linux/init.h> @@ -143,33 +142,6 @@ raw3270_request_alloc(size_t size) return rq; } -#ifdef CONFIG_TN3270_CONSOLE -/* - * Allocate a new 3270 ccw request from bootmem. Only works very - * early in the boot process. Only con3270.c should be using this. - */ -struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size) -{ - struct raw3270_request *rq; - - rq = alloc_bootmem_low(sizeof(struct raw3270)); - - /* alloc output buffer. */ - if (size > 0) - rq->buffer = alloc_bootmem_low(size); - rq->size = size; - INIT_LIST_HEAD(&rq->list); - - /* - * Setup ccw. - */ - rq->ccw.cda = __pa(rq->buffer); - rq->ccw.flags = CCW_FLAG_SLI; - - return rq; -} -#endif - /* * Free 3270 ccw request */ @@ -846,8 +818,8 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev) char *ascebc; int rc; - rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270)); - ascebc = (char *) alloc_bootmem(256); + rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA); + ascebc = kzalloc(256, GFP_KERNEL); rc = raw3270_setup_device(cdev, rp, ascebc); if (rc) return ERR_PTR(rc); @@ -1350,7 +1322,7 @@ static int raw3270_pm_stop(struct ccw_device *cdev) struct raw3270_view *view; unsigned long flags; - rp = cdev->dev.driver_data; + rp = dev_get_drvdata(&cdev->dev); if (!rp) return 0; spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); @@ -1376,7 +1348,7 @@ static int raw3270_pm_start(struct ccw_device *cdev) struct raw3270 *rp; unsigned long flags; - rp = cdev->dev.driver_data; + rp = dev_get_drvdata(&cdev->dev); if (!rp) return 0; spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 336811a77672..ad698d30cb3b 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/timer.h> #include <linux/jiffies.h> -#include <linux/bootmem.h> #include <linux/termios.h> #include <linux/err.h> #include <linux/reboot.h> @@ -110,7 +109,7 @@ static void sclp_console_sync_queue(void) spin_lock_irqsave(&sclp_con_lock, flags); if (timer_pending(&sclp_con_timer)) - del_timer_sync(&sclp_con_timer); + del_timer(&sclp_con_timer); while (sclp_con_queue_running) { spin_unlock_irqrestore(&sclp_con_lock, flags); sclp_sync_wait(); @@ -298,8 +297,8 @@ sclp_console_init(void) /* Allocate pages for output buffering */ INIT_LIST_HEAD(&sclp_con_pages); for (i = 0; i < MAX_CONSOLE_PAGES; i++) { - page = alloc_bootmem_low_pages(PAGE_SIZE); - list_add_tail((struct list_head *) page, &sclp_con_pages); + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + list_add_tail(page, &sclp_con_pages); } INIT_LIST_HEAD(&sclp_con_outqueue); spin_lock_init(&sclp_con_lock); diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 5518e24946aa..178724f2a4c3 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -20,7 +20,6 @@ #include <linux/major.h> #include <linux/console.h> #include <linux/kdev_t.h> -#include <linux/bootmem.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/reboot.h> @@ -601,10 +600,7 @@ static void __init __sclp_vt220_free_pages(void) list_for_each_safe(page, p, &sclp_vt220_empty) { list_del(page); - if (slab_is_available()) - free_page((unsigned long) page); - else - free_bootmem((unsigned long) page, PAGE_SIZE); + free_page((unsigned long) page); } } @@ -640,16 +636,12 @@ static int __init __sclp_vt220_init(int num_pages) sclp_vt220_flush_later = 0; /* Allocate pages for output buffering */ + rc = -ENOMEM; for (i = 0; i < num_pages; i++) { - if (slab_is_available()) - page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - else - page = alloc_bootmem_low_pages(PAGE_SIZE); - if (!page) { - rc = -ENOMEM; + page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!page) goto out; - } - list_add_tail((struct list_head *) page, &sclp_vt220_empty); + list_add_tail(page, &sclp_vt220_empty); } rc = sclp_register(&sclp_vt220_register); out: diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 595aa04cfd01..1d420d947596 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -396,7 +396,7 @@ int tape_generic_pm_suspend(struct ccw_device *cdev) { struct tape_device *device; - device = cdev->dev.driver_data; + device = dev_get_drvdata(&cdev->dev); if (!device) { return -ENODEV; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 411cfa3c7719..c20a4fe6da51 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -663,7 +663,7 @@ static struct attribute *vmlogrdr_attrs[] = { static int vmlogrdr_pm_prepare(struct device *dev) { int rc; - struct vmlogrdr_priv_t *priv = dev->driver_data; + struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev); rc = 0; if (priv) { @@ -753,7 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) dev->bus = &iucv_bus; dev->parent = iucv_root; dev->driver = &vmlogrdr_driver; - dev->driver_data = priv; + dev_set_drvdata(dev, priv); /* * The release function could be called after the * module has been unloaded. It's _only_ task is to diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 7d9e67cb6471..31b902e94f7b 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -170,7 +170,7 @@ static void urdev_put(struct urdev *urd) */ static int ur_pm_suspend(struct ccw_device *cdev) { - struct urdev *urd = cdev->dev.driver_data; + struct urdev *urd = dev_get_drvdata(&cdev->dev); TRACE("ur_pm_suspend: cdev=%p\n", cdev); if (urd->open_flag) { diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 13bcb8114388..b1241f8fae88 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -351,15 +351,6 @@ static inline unsigned long long get_usecs(void) ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK) /* prototypes for thin interrupt */ -void qdio_sync_after_thinint(struct qdio_q *q); -int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state, - int auto_ack); -void qdio_check_outbound_after_thinint(struct qdio_q *q); -int qdio_inbound_q_moved(struct qdio_q *q); -void qdio_kick_handler(struct qdio_q *q); -void qdio_stop_polling(struct qdio_q *q); -int qdio_siga_sync_q(struct qdio_q *q); - void qdio_setup_thinint(struct qdio_irq *irq_ptr); int qdio_establish_thinint(struct qdio_irq *irq_ptr); void qdio_shutdown_thinint(struct qdio_irq *irq_ptr); @@ -392,4 +383,6 @@ void qdio_setup_destroy_sysfs(struct ccw_device *cdev); int qdio_setup_init(void); void qdio_setup_exit(void); +int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, + unsigned char *state); #endif /* _CIO_QDIO_H */ diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index e3434b34f86c..b8626d4df116 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -70,9 +70,8 @@ static int qstat_show(struct seq_file *m, void *v) seq_printf(m, "slsb buffer states:\n"); seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); - qdio_siga_sync_q(q); for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { - get_buf_state(q, i, &state, 0); + debug_get_buf_state(q, i, &state); switch (state) { case SLSB_P_INPUT_NOT_INIT: case SLSB_P_OUTPUT_NOT_INIT: diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index d79cf5bf0e62..0038750ad945 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -231,8 +231,8 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, return i; } -inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, - unsigned char *state, int auto_ack) +static inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, + unsigned char *state, int auto_ack) { return get_buf_states(q, bufnr, state, 1, auto_ack); } @@ -276,7 +276,7 @@ void qdio_init_buf_states(struct qdio_irq *irq_ptr) QDIO_MAX_BUFFERS_PER_Q); } -static int qdio_siga_sync(struct qdio_q *q, unsigned int output, +static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, unsigned int input) { int cc; @@ -293,7 +293,7 @@ static int qdio_siga_sync(struct qdio_q *q, unsigned int output, return cc; } -inline int qdio_siga_sync_q(struct qdio_q *q) +static inline int qdio_siga_sync_q(struct qdio_q *q) { if (q->is_input_q) return qdio_siga_sync(q, 0, q->mask); @@ -358,8 +358,7 @@ static inline int qdio_siga_input(struct qdio_q *q) return cc; } -/* called from thinint inbound handler */ -void qdio_sync_after_thinint(struct qdio_q *q) +static inline void qdio_sync_after_thinint(struct qdio_q *q) { if (pci_out_supported(q)) { if (need_siga_sync_thinint(q)) @@ -370,7 +369,14 @@ void qdio_sync_after_thinint(struct qdio_q *q) qdio_siga_sync_q(q); } -inline void qdio_stop_polling(struct qdio_q *q) +int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, + unsigned char *state) +{ + qdio_siga_sync_q(q); + return get_buf_states(q, bufnr, state, 1, 0); +} + +static inline void qdio_stop_polling(struct qdio_q *q) { if (!q->u.in.polling) return; @@ -449,13 +455,6 @@ static inline void inbound_primed(struct qdio_q *q, int count) count--; if (!count) return; - - /* - * Need to change all PRIMED buffers to NOT_INIT, otherwise - * we're loosing initiative in the thinint code. - */ - set_buf_states(q, q->first_to_check, SLSB_P_INPUT_NOT_INIT, - count); } static int get_inbound_buffer_frontier(struct qdio_q *q) @@ -470,19 +469,13 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); stop = add_buf(q->first_to_check, count); - /* - * No siga sync here, as a PCI or we after a thin interrupt - * will sync the queues. - */ - - /* need to set count to 1 for non-qebsm */ - if (!is_qebsm(q)) - count = 1; - -check_next: if (q->first_to_check == stop) goto out; + /* + * No siga sync here, as a PCI or we after a thin interrupt + * already sync'ed the queues. + */ count = get_buf_states(q, q->first_to_check, &state, count, 1); if (!count) goto out; @@ -490,14 +483,9 @@ check_next: switch (state) { case SLSB_P_INPUT_PRIMED: inbound_primed(q, count); - /* - * No siga-sync needed for non-qebsm here, as the inbound queue - * will be synced on the next siga-r, resp. - * tiqdio_is_inbound_q_done will do the siga-sync. - */ q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); - goto check_next; + break; case SLSB_P_INPUT_ERROR: announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ @@ -516,7 +504,7 @@ out: return q->first_to_check; } -int qdio_inbound_q_moved(struct qdio_q *q) +static int qdio_inbound_q_moved(struct qdio_q *q) { int bufnr; @@ -524,35 +512,32 @@ int qdio_inbound_q_moved(struct qdio_q *q) if ((bufnr != q->last_move) || q->qdio_error) { q->last_move = bufnr; - if (!need_siga_sync(q) && !pci_out_supported(q)) + if (!is_thinint_irq(q->irq_ptr) && !MACHINE_IS_VM) q->u.in.timestamp = get_usecs(); - - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in moved"); return 1; } else return 0; } -static int qdio_inbound_q_done(struct qdio_q *q) +static inline int qdio_inbound_q_done(struct qdio_q *q) { unsigned char state = 0; if (!atomic_read(&q->nr_buf_used)) return 1; - /* - * We need that one for synchronization with the adapter, as it - * does a kind of PCI avoidance. - */ qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state, 0); + if (state == SLSB_P_INPUT_PRIMED) - /* we got something to do */ + /* more work coming */ return 0; - /* on VM, we don't poll, so the q is always done here */ - if (need_siga_sync(q) || pci_out_supported(q)) + if (is_thinint_irq(q->irq_ptr)) + return 1; + + /* don't poll under z/VM */ + if (MACHINE_IS_VM) return 1; /* @@ -563,14 +548,11 @@ static int qdio_inbound_q_done(struct qdio_q *q) DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", q->first_to_check); return 1; - } else { - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in notd:%3d", - q->first_to_check); + } else return 0; - } } -void qdio_kick_handler(struct qdio_q *q) +static void qdio_kick_handler(struct qdio_q *q) { int start = q->first_to_kick; int end = q->first_to_check; @@ -619,7 +601,6 @@ again: goto again; } -/* inbound tasklet */ void qdio_inbound_processing(unsigned long data) { struct qdio_q *q = (struct qdio_q *)data; @@ -642,11 +623,6 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); stop = add_buf(q->first_to_check, count); - /* need to set count to 1 for non-qebsm */ - if (!is_qebsm(q)) - count = 1; - -check_next: if (q->first_to_check == stop) return q->first_to_check; @@ -661,13 +637,7 @@ check_next: atomic_sub(count, &q->nr_buf_used); q->first_to_check = add_buf(q->first_to_check, count); - /* - * We fetch all buffer states at once. get_buf_states may - * return count < stop. For QEBSM we do not loop. - */ - if (is_qebsm(q)) - break; - goto check_next; + break; case SLSB_P_OUTPUT_ERROR: announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ @@ -797,8 +767,7 @@ void qdio_outbound_timer(unsigned long data) tasklet_schedule(&q->tasklet); } -/* called from thinint inbound tasklet */ -void qdio_check_outbound_after_thinint(struct qdio_q *q) +static inline void qdio_check_outbound_after_thinint(struct qdio_q *q) { struct qdio_q *out; int i; @@ -811,6 +780,46 @@ void qdio_check_outbound_after_thinint(struct qdio_q *q) tasklet_schedule(&out->tasklet); } +static void __tiqdio_inbound_processing(struct qdio_q *q) +{ + qdio_perf_stat_inc(&perf_stats.thinint_inbound); + qdio_sync_after_thinint(q); + + /* + * The interrupt could be caused by a PCI request. Check the + * PCI capable outbound queues. + */ + qdio_check_outbound_after_thinint(q); + + if (!qdio_inbound_q_moved(q)) + return; + + qdio_kick_handler(q); + + if (!qdio_inbound_q_done(q)) { + qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); + } + + qdio_stop_polling(q); + /* + * We need to check again to not lose initiative after + * resetting the ACK state. + */ + if (!qdio_inbound_q_done(q)) { + qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); + if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) + tasklet_schedule(&q->tasklet); + } +} + +void tiqdio_inbound_processing(unsigned long data) +{ + struct qdio_q *q = (struct qdio_q *)data; + __tiqdio_inbound_processing(q); +} + static inline void qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) { @@ -1488,18 +1497,13 @@ out: * @count: how many buffers to process */ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, - int q_nr, int bufnr, int count) + int q_nr, unsigned int bufnr, unsigned int count) { struct qdio_irq *irq_ptr; - if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || - (count > QDIO_MAX_BUFFERS_PER_Q) || - (q_nr >= QDIO_MAX_QUEUES_PER_IRQ)) + if (bufnr >= QDIO_MAX_BUFFERS_PER_Q || count > QDIO_MAX_BUFFERS_PER_Q) return -EINVAL; - if (!count) - return 0; - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index c655d011a78d..981a77ea7ee2 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -43,9 +43,6 @@ struct indicator_t { }; static struct indicator_t *q_indicators; -static void tiqdio_tasklet_fn(unsigned long data); -static DECLARE_TASKLET(tiqdio_tasklet, tiqdio_tasklet_fn, 0); - static int css_qdio_omit_svs; static inline unsigned long do_clear_global_summary(void) @@ -103,11 +100,6 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) xchg(irq_ptr->dsci, 1); } -/* - * we cannot stop the tiqdio tasklet here since it is for all - * thinint qdio devices and it must run as long as there is a - * thinint device left - */ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) { struct qdio_q *q; @@ -126,79 +118,39 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) } } -static inline int tiqdio_inbound_q_done(struct qdio_q *q) -{ - unsigned char state = 0; - - if (!atomic_read(&q->nr_buf_used)) - return 1; - - qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state, 0); - - if (state == SLSB_P_INPUT_PRIMED) - /* more work coming */ - return 0; - return 1; -} - static inline int shared_ind(struct qdio_irq *irq_ptr) { return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; } -static void __tiqdio_inbound_processing(struct qdio_q *q) +/** + * tiqdio_thinint_handler - thin interrupt handler for qdio + * @ind: pointer to adapter local summary indicator + * @drv_data: NULL + */ +static void tiqdio_thinint_handler(void *ind, void *drv_data) { - qdio_perf_stat_inc(&perf_stats.thinint_inbound); - qdio_sync_after_thinint(q); + struct qdio_q *q; + + qdio_perf_stat_inc(&perf_stats.thin_int); /* - * Maybe we have work on our outbound queues... at least - * we have to check the PCI capable queues. + * SVS only when needed: issue SVS to benefit from iqdio interrupt + * avoidance (SVS clears adapter interrupt suppression overwrite) */ - qdio_check_outbound_after_thinint(q); - - if (!qdio_inbound_q_moved(q)) - return; - - qdio_kick_handler(q); - - if (!tiqdio_inbound_q_done(q)) { - qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) - tasklet_schedule(&q->tasklet); - } + if (!css_qdio_omit_svs) + do_clear_global_summary(); - qdio_stop_polling(q); /* - * We need to check again to not lose initiative after - * resetting the ACK state. + * reset local summary indicator (tiqdio_alsi) to stop adapter + * interrupts for now */ - if (!tiqdio_inbound_q_done(q)) { - qdio_perf_stat_inc(&perf_stats.thinint_inbound_loop2); - if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) - tasklet_schedule(&q->tasklet); - } -} - -void tiqdio_inbound_processing(unsigned long data) -{ - struct qdio_q *q = (struct qdio_q *)data; - - __tiqdio_inbound_processing(q); -} - -/* check for work on all inbound thinint queues */ -static void tiqdio_tasklet_fn(unsigned long data) -{ - struct qdio_q *q; - - qdio_perf_stat_inc(&perf_stats.tasklet_thinint); -again: + xchg((u8 *)ind, 0); /* protect tiq_list entries, only changed in activate or shutdown */ rcu_read_lock(); + /* check for work on all inbound thinint queues */ list_for_each_entry_rcu(q, &tiq_list, entry) /* only process queues from changed sets */ if (*q->irq_ptr->dsci) { @@ -226,37 +178,6 @@ again: if (*tiqdio_alsi) xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); } - - /* check for more work */ - if (*tiqdio_alsi) { - xchg(tiqdio_alsi, 0); - qdio_perf_stat_inc(&perf_stats.tasklet_thinint_loop); - goto again; - } -} - -/** - * tiqdio_thinint_handler - thin interrupt handler for qdio - * @ind: pointer to adapter local summary indicator - * @drv_data: NULL - */ -static void tiqdio_thinint_handler(void *ind, void *drv_data) -{ - qdio_perf_stat_inc(&perf_stats.thin_int); - - /* - * SVS only when needed: issue SVS to benefit from iqdio interrupt - * avoidance (SVS clears adapter interrupt suppression overwrite) - */ - if (!css_qdio_omit_svs) - do_clear_global_summary(); - - /* - * reset local summary indicator (tiqdio_alsi) to stop adapter - * interrupts for now, the tasklet will clean all dsci's - */ - xchg((u8 *)ind, 0); - tasklet_hi_schedule(&tiqdio_tasklet); } static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) @@ -376,5 +297,4 @@ void __exit tiqdio_unregister_thinints(void) s390_unregister_adapter_interrupt(tiqdio_alsi, QDIO_AIRQ_ISC); isc_unregister(QDIO_AIRQ_ISC); } - tasklet_kill(&tiqdio_tasklet); } diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 9c148406b980..727a809636d8 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -54,6 +54,12 @@ static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); static inline void ap_schedule_poll_timer(void); +static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags); +static int ap_device_remove(struct device *dev); +static int ap_device_probe(struct device *dev); +static void ap_interrupt_handler(void *unused1, void *unused2); +static void ap_reset(struct ap_device *ap_dev); +static void ap_config_timeout(unsigned long ptr); /* * Module description. @@ -101,6 +107,10 @@ static struct hrtimer ap_poll_timer; * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ static unsigned long long poll_timeout = 250000; +/* Suspend flag */ +static int ap_suspend_flag; +static struct bus_type ap_bus_type; + /** * ap_using_interrupts() - Returns non-zero if interrupt support is * available. @@ -617,10 +627,79 @@ static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) return retval; } +static int ap_bus_suspend(struct device *dev, pm_message_t state) +{ + struct ap_device *ap_dev = to_ap_dev(dev); + unsigned long flags; + + if (!ap_suspend_flag) { + ap_suspend_flag = 1; + + /* Disable scanning for devices, thus we do not want to scan + * for them after removing. + */ + del_timer_sync(&ap_config_timer); + if (ap_work_queue != NULL) { + destroy_workqueue(ap_work_queue); + ap_work_queue = NULL; + } + tasklet_disable(&ap_tasklet); + } + /* Poll on the device until all requests are finished. */ + do { + flags = 0; + __ap_poll_device(ap_dev, &flags); + } while ((flags & 1) || (flags & 2)); + + ap_device_remove(dev); + return 0; +} + +static int ap_bus_resume(struct device *dev) +{ + int rc = 0; + struct ap_device *ap_dev = to_ap_dev(dev); + + if (ap_suspend_flag) { + ap_suspend_flag = 0; + if (!ap_interrupts_available()) + ap_interrupt_indicator = NULL; + ap_device_probe(dev); + ap_reset(ap_dev); + setup_timer(&ap_dev->timeout, ap_request_timeout, + (unsigned long) ap_dev); + ap_scan_bus(NULL); + init_timer(&ap_config_timer); + ap_config_timer.function = ap_config_timeout; + ap_config_timer.data = 0; + ap_config_timer.expires = jiffies + ap_config_time * HZ; + add_timer(&ap_config_timer); + ap_work_queue = create_singlethread_workqueue("kapwork"); + if (!ap_work_queue) + return -ENOMEM; + tasklet_enable(&ap_tasklet); + if (!ap_using_interrupts()) + ap_schedule_poll_timer(); + else + tasklet_schedule(&ap_tasklet); + if (ap_thread_flag) + rc = ap_poll_thread_start(); + } else { + ap_device_probe(dev); + ap_reset(ap_dev); + setup_timer(&ap_dev->timeout, ap_request_timeout, + (unsigned long) ap_dev); + } + + return rc; +} + static struct bus_type ap_bus_type = { .name = "ap", .match = &ap_bus_match, .uevent = &ap_uevent, + .suspend = ap_bus_suspend, + .resume = ap_bus_resume }; static int ap_device_probe(struct device *dev) @@ -1066,7 +1145,7 @@ ap_config_timeout(unsigned long ptr) */ static inline void ap_schedule_poll_timer(void) { - if (ap_using_interrupts()) + if (ap_using_interrupts() || ap_suspend_flag) return; if (hrtimer_is_queued(&ap_poll_timer)) return; @@ -1384,6 +1463,8 @@ static int ap_poll_thread(void *data) set_user_nice(current, 19); while (1) { + if (ap_suspend_flag) + return 0; if (need_resched()) { schedule(); continue; @@ -1414,7 +1495,7 @@ static int ap_poll_thread_start(void) { int rc; - if (ap_using_interrupts()) + if (ap_using_interrupts() || ap_suspend_flag) return 0; mutex_lock(&ap_poll_thread_mutex); if (!ap_poll_kthread) { diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 52574ce797b2..8c36eafcfbfe 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1307,7 +1307,7 @@ static void netiucv_pm_complete(struct device *dev) */ static int netiucv_pm_freeze(struct device *dev) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); struct net_device *ndev = NULL; int rc = 0; @@ -1331,7 +1331,7 @@ out: */ static int netiucv_pm_restore_thaw(struct device *dev) { - struct netiucv_priv *priv = dev->driver_data; + struct netiucv_priv *priv = dev_get_drvdata(dev); struct net_device *ndev = NULL; int rc = 0; |