diff options
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/airq.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 69 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.c | 5 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 3 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 8 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 17 | ||||
-rw-r--r-- | drivers/s390/cio/idset.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 21 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_debug.c | 79 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_debug.h | 6 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 132 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_setup.c | 48 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_thinint.c | 62 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_drv.c | 5 |
14 files changed, 185 insertions, 280 deletions
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 427b2e24a8ce..cb466ed7eb5e 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -105,16 +105,12 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy) return IRQ_HANDLED; } -static struct irqaction airq_interrupt = { - .name = "AIO", - .handler = do_airq_interrupt, -}; - void __init init_airq_interrupts(void) { irq_set_chip_and_handler(THIN_INTERRUPT, &dummy_irq_chip, handle_percpu_irq); - setup_irq(THIN_INTERRUPT, &airq_interrupt); + if (request_irq(THIN_INTERRUPT, do_airq_interrupt, 0, "AIO", NULL)) + panic("Failed to register AIO interrupt\n"); } static inline unsigned long iv_size(unsigned long bits) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index b42a93736668..483a9ecfcbb1 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -485,79 +485,10 @@ static void ccwgroup_shutdown(struct device *dev) gdrv->shutdown(gdev); } -static int ccwgroup_pm_prepare(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - /* Fail while device is being set online/offline. */ - if (atomic_read(&gdev->onoff)) - return -EAGAIN; - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->prepare ? gdrv->prepare(gdev) : 0; -} - -static void ccwgroup_pm_complete(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return; - - if (gdrv->complete) - gdrv->complete(gdev); -} - -static int ccwgroup_pm_freeze(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->freeze ? gdrv->freeze(gdev) : 0; -} - -static int ccwgroup_pm_thaw(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->thaw ? gdrv->thaw(gdev) : 0; -} - -static int ccwgroup_pm_restore(struct device *dev) -{ - struct ccwgroup_device *gdev = to_ccwgroupdev(dev); - struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); - - if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) - return 0; - - return gdrv->restore ? gdrv->restore(gdev) : 0; -} - -static const struct dev_pm_ops ccwgroup_pm_ops = { - .prepare = ccwgroup_pm_prepare, - .complete = ccwgroup_pm_complete, - .freeze = ccwgroup_pm_freeze, - .thaw = ccwgroup_pm_thaw, - .restore = ccwgroup_pm_restore, -}; - static struct bus_type ccwgroup_bus_type = { .name = "ccwgroup", .remove = ccwgroup_remove, .shutdown = ccwgroup_shutdown, - .pm = &ccwgroup_pm_ops, }; bool dev_is_ccwgroup(struct device *dev) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 6392a1b95b02..1ca73c2e5a8f 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -180,11 +180,12 @@ EXPORT_SYMBOL_GPL(chsc_ssqd); * @scssc: request and response block for SADC * @summary_indicator_addr: summary indicator address * @subchannel_indicator_addr: subchannel indicator address + * @isc: Interruption Subclass for this subchannel * * Returns 0 on success. */ int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, - u64 summary_indicator_addr, u64 subchannel_indicator_addr) + u64 summary_indicator_addr, u64 subchannel_indicator_addr, u8 isc) { memset(scssc, 0, sizeof(*scssc)); scssc->request.length = 0x0fe0; @@ -196,7 +197,7 @@ int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, scssc->ks = PAGE_DEFAULT_KEY >> 4; scssc->kc = PAGE_DEFAULT_KEY >> 4; - scssc->isc = QDIO_AIRQ_ISC; + scssc->isc = isc; scssc->schid = schid; /* enable the time delay disablement facility */ diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index e57d68e325a3..34de6d77442c 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -163,7 +163,8 @@ void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd); int chsc_sadc(struct subchannel_id schid, struct chsc_scssc_area *scssc, - u64 summary_indicator_addr, u64 subchannel_indicator_addr); + u64 summary_indicator_addr, u64 subchannel_indicator_addr, + u8 isc); int chsc_sgib(u32 origin); int chsc_error_from_response(int response); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 18f5458f90e8..6d716db2a46a 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -563,16 +563,12 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) return IRQ_HANDLED; } -static struct irqaction io_interrupt = { - .name = "I/O", - .handler = do_cio_interrupt, -}; - void __init init_cio_interrupts(void) { irq_set_chip_and_handler(IO_INTERRUPT, &dummy_irq_chip, handle_percpu_irq); - setup_irq(IO_INTERRUPT, &io_interrupt); + if (request_irq(IO_INTERRUPT, do_cio_interrupt, 0, "I/O", NULL)) + panic("Failed to register I/O interrupt\n"); } #ifdef CONFIG_CCW_CONSOLE diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 0c6245fc7706..b29fe8d50baf 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -849,8 +849,10 @@ static void io_subchannel_register(struct ccw_device *cdev) * Now we know this subchannel will stay, we can throw * our delayed uevent. */ - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + if (dev_get_uevent_suppress(&sch->dev)) { + dev_set_uevent_suppress(&sch->dev, 0); + kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + } /* make it known to the system */ ret = ccw_device_add(cdev); if (ret) { @@ -1058,8 +1060,11 @@ static int io_subchannel_probe(struct subchannel *sch) * Throw the delayed uevent for the subchannel, register * the ccw_device and exit. */ - dev_set_uevent_suppress(&sch->dev, 0); - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + if (dev_get_uevent_suppress(&sch->dev)) { + /* should always be the case for the console */ + dev_set_uevent_suppress(&sch->dev, 0); + kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + } cdev = sch_get_cdev(sch); rc = ccw_device_add(cdev); if (rc) { @@ -1262,7 +1267,7 @@ static int recovery_check(struct device *dev, void *data) sch = to_subchannel(cdev->dev.parent); if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm) break; - /* fall through */ + fallthrough; case DEV_STATE_DISCONNECTED: CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", cdev->private->dev_id.ssid, @@ -2091,7 +2096,7 @@ static void ccw_device_todo(struct work_struct *work) case CDEV_TODO_UNREG_EVAL: if (!sch_is_pseudo_sch(sch)) css_schedule_eval(sch->schid); - /* fall-through */ + fallthrough; case CDEV_TODO_UNREG: if (sch_is_pseudo_sch(sch)) ccw_device_unregister(cdev); diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c index 835de44dbbcc..77d0ea7b381b 100644 --- a/drivers/s390/cio/idset.c +++ b/drivers/s390/cio/idset.c @@ -13,7 +13,7 @@ struct idset { int num_ssid; int num_id; - unsigned long bitmap[0]; + unsigned long bitmap[]; }; static inline unsigned long bitmap_size(int num_ssid, int num_id) diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index ff74eb5fce50..b8453b594679 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -177,8 +177,8 @@ struct qdio_queue_perf_stat { unsigned int nr_sbal_total; }; -enum qdio_queue_irq_states { - QDIO_QUEUE_IRQS_DISABLED, +enum qdio_irq_poll_states { + QDIO_IRQ_DISABLED, }; struct qdio_input_q { @@ -188,10 +188,6 @@ struct qdio_input_q { int ack_count; /* last time of noticing incoming data */ u64 timestamp; - /* upper-layer polling flag */ - unsigned long queue_irq_state; - /* callback to start upper-layer polling */ - void (*queue_start_poll) (struct ccw_device *, int, unsigned long); }; struct qdio_output_q { @@ -254,7 +250,6 @@ struct qdio_q { /* upper-layer program handler */ qdio_handler_t (*handler); - struct dentry *debugfs_q; struct qdio_irq *irq_ptr; struct sl *sl; /* @@ -270,7 +265,6 @@ struct qdio_irq { struct ccw_device *cdev; struct list_head entry; /* list of thinint devices */ struct dentry *debugfs_dev; - struct dentry *debugfs_perf; unsigned long int_parm; struct subchannel_id schid; @@ -299,6 +293,9 @@ struct qdio_irq { struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ]; struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; + void (*irq_poll)(struct ccw_device *cdev, unsigned long data); + unsigned long poll_state; + debug_info_t *debug_area; struct mutex setup_mutex; struct qdio_dev_perf_stat perf_stat; @@ -377,7 +374,6 @@ int tiqdio_allocate_memory(void); void tiqdio_free_memory(void); int tiqdio_register_thinints(void); void tiqdio_unregister_thinints(void); -void clear_nonshared_ind(struct qdio_irq *); int test_nonshared_ind(struct qdio_irq *); /* prototypes for setup */ @@ -392,12 +388,9 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, struct subchannel_id *schid, struct qdio_ssqd_desc *data); -int qdio_setup_irq(struct qdio_initialize *init_data); -void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, - struct ccw_device *cdev); +int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data); +void qdio_print_subchannel_info(struct qdio_irq *irq_ptr); void qdio_release_memory(struct qdio_irq *irq_ptr); -int qdio_setup_create_sysfs(struct ccw_device *cdev); -void qdio_setup_destroy_sysfs(struct ccw_device *cdev); int qdio_setup_init(void); void qdio_setup_exit(void); int qdio_enable_async_operation(struct qdio_output_q *q); diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 9c0370b27426..286b044fb027 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -58,30 +58,16 @@ static void qdio_clear_dbf_list(void) mutex_unlock(&qdio_dbf_list_mutex); } -int qdio_allocate_dbf(struct qdio_initialize *init_data, - struct qdio_irq *irq_ptr) +int qdio_allocate_dbf(struct qdio_irq *irq_ptr) { char text[QDIO_DBF_NAME_LEN]; struct qdio_dbf_entry *new_entry; - DBF_EVENT("qfmt:%1d", init_data->q_format); - DBF_HEX(init_data->adapter_name, 8); - DBF_EVENT("qpff%4x", init_data->qib_param_field_format); - DBF_HEX(&init_data->qib_param_field, sizeof(void *)); - DBF_HEX(&init_data->input_slib_elements, sizeof(void *)); - DBF_HEX(&init_data->output_slib_elements, sizeof(void *)); - DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs, - init_data->no_output_qs); - DBF_HEX(&init_data->input_handler, sizeof(void *)); - DBF_HEX(&init_data->output_handler, sizeof(void *)); - DBF_HEX(&init_data->int_parm, sizeof(long)); - DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); - DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); /* allocate trace view for the interface */ snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s", - dev_name(&init_data->cdev->dev)); + dev_name(&irq_ptr->cdev->dev)); irq_ptr->debug_area = qdio_get_dbf_entry(text); if (irq_ptr->debug_area) DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused"); @@ -128,8 +114,8 @@ static int qstat_show(struct seq_file *m, void *v) q->u.in.ack_start, q->u.in.ack_count); seq_printf(m, "DSCI: %x IRQs disabled: %u\n", *(u8 *)q->irq_ptr->dsci, - test_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)); + test_bit(QDIO_IRQ_DISABLED, + &q->irq_ptr->poll_state)); } seq_printf(m, "SBAL states:\n"); seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); @@ -190,6 +176,23 @@ static int qstat_show(struct seq_file *m, void *v) DEFINE_SHOW_ATTRIBUTE(qstat); +static int ssqd_show(struct seq_file *m, void *v) +{ + struct ccw_device *cdev = m->private; + struct qdio_ssqd_desc ssqd; + int rc; + + rc = qdio_get_ssqd_desc(cdev, &ssqd); + if (rc) + return rc; + + seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd), + false); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(ssqd); + static char *qperf_names[] = { "Assumed adapter interrupts", "QDIO interrupts", @@ -284,53 +287,37 @@ static const struct file_operations debugfs_perf_fops = { .release = single_release, }; -static void setup_debugfs_entry(struct qdio_q *q) +static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q) { char name[QDIO_DEBUGFS_NAME_LEN]; snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", q->is_input_q ? "input" : "output", q->nr); - q->debugfs_q = debugfs_create_file(name, 0444, - q->irq_ptr->debugfs_dev, q, &qstat_fops); - if (IS_ERR(q->debugfs_q)) - q->debugfs_q = NULL; + debugfs_create_file(name, 0444, parent, q, &qstat_fops); } -void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) +void qdio_setup_debug_entries(struct qdio_irq *irq_ptr) { struct qdio_q *q; int i; - irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), + irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev), debugfs_root); - if (IS_ERR(irq_ptr->debugfs_dev)) - irq_ptr->debugfs_dev = NULL; - - irq_ptr->debugfs_perf = debugfs_create_file("statistics", - S_IFREG | S_IRUGO | S_IWUSR, - irq_ptr->debugfs_dev, irq_ptr, - &debugfs_perf_fops); - if (IS_ERR(irq_ptr->debugfs_perf)) - irq_ptr->debugfs_perf = NULL; + debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, + irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops); + debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev, + &ssqd_fops); for_each_input_queue(irq_ptr, q, i) - setup_debugfs_entry(q); + setup_debugfs_entry(irq_ptr->debugfs_dev, q); for_each_output_queue(irq_ptr, q, i) - setup_debugfs_entry(q); + setup_debugfs_entry(irq_ptr->debugfs_dev, q); } void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr) { - struct qdio_q *q; - int i; - - for_each_input_queue(irq_ptr, q, i) - debugfs_remove(q->debugfs_q); - for_each_output_queue(irq_ptr, q, i) - debugfs_remove(q->debugfs_q); - debugfs_remove(irq_ptr->debugfs_perf); - debugfs_remove(irq_ptr->debugfs_dev); + debugfs_remove_recursive(irq_ptr->debugfs_dev); } int __init qdio_debug_init(void) @@ -352,7 +339,7 @@ int __init qdio_debug_init(void) void qdio_debug_exit(void) { qdio_clear_dbf_list(); - debugfs_remove(debugfs_root); + debugfs_remove_recursive(debugfs_root); debug_unregister(qdio_dbf_setup); debug_unregister(qdio_dbf_error); } diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index f85f5fa7cefc..0dfba085f360 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -64,10 +64,8 @@ static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr, debug_event(dev->debug_area, level, addr, len); } -int qdio_allocate_dbf(struct qdio_initialize *init_data, - struct qdio_irq *irq_ptr); -void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, - struct ccw_device *cdev); +int qdio_allocate_dbf(struct qdio_irq *irq_ptr); +void qdio_setup_debug_entries(struct qdio_irq *irq_ptr); void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr); int qdio_debug_init(void); void qdio_debug_exit(void); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3475317c42e5..bcc3ab14e72d 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -950,19 +950,14 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) if (unlikely(irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; - for_each_input_queue(irq_ptr, q, i) { - if (q->u.in.queue_start_poll) { - /* skip if polling is enabled or already in work */ - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) { - QDIO_PERF_STAT_INC(irq_ptr, int_discarded); - continue; - } - q->u.in.queue_start_poll(q->irq_ptr->cdev, q->nr, - q->irq_ptr->int_parm); - } else { + if (irq_ptr->irq_poll) { + if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) + irq_ptr->irq_poll(irq_ptr->cdev, irq_ptr->int_parm); + else + QDIO_PERF_STAT_INC(irq_ptr, int_discarded); + } else { + for_each_input_queue(irq_ptr, q, i) tasklet_schedule(&q->tasklet); - } } if (!pci_out_supported(irq_ptr) || !irq_ptr->scan_threshold) @@ -1105,9 +1100,8 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev, } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); -static void qdio_shutdown_queues(struct ccw_device *cdev) +static void qdio_shutdown_queues(struct qdio_irq *irq_ptr) { - struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct qdio_q *q; int i; @@ -1155,7 +1149,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how) qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); tiqdio_remove_device(irq_ptr); - qdio_shutdown_queues(cdev); + qdio_shutdown_queues(irq_ptr); qdio_shutdown_debug_entries(irq_ptr); /* cleanup subchannel */ @@ -1226,26 +1220,21 @@ EXPORT_SYMBOL_GPL(qdio_free); /** * qdio_allocate - allocate qdio queues and associated data - * @init_data: initialization data + * @cdev: associated ccw device + * @no_input_qs: allocate this number of Input Queues + * @no_output_qs: allocate this number of Output Queues */ -int qdio_allocate(struct qdio_initialize *init_data) +int qdio_allocate(struct ccw_device *cdev, unsigned int no_input_qs, + unsigned int no_output_qs) { struct subchannel_id schid; struct qdio_irq *irq_ptr; - ccw_device_get_schid(init_data->cdev, &schid); + ccw_device_get_schid(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)) - return -EINVAL; - - if ((init_data->no_input_qs > QDIO_MAX_QUEUES_PER_IRQ) || - (init_data->no_output_qs > QDIO_MAX_QUEUES_PER_IRQ)) - return -EINVAL; - - if ((!init_data->input_sbal_addr_array) || - (!init_data->output_sbal_addr_array)) + if (no_input_qs > QDIO_MAX_QUEUES_PER_IRQ || + no_output_qs > QDIO_MAX_QUEUES_PER_IRQ) return -EINVAL; /* irq_ptr must be in GFP_DMA since it contains ccw1.cda */ @@ -1253,10 +1242,14 @@ int qdio_allocate(struct qdio_initialize *init_data) if (!irq_ptr) goto out_err; + irq_ptr->cdev = cdev; mutex_init(&irq_ptr->setup_mutex); - if (qdio_allocate_dbf(init_data, irq_ptr)) + if (qdio_allocate_dbf(irq_ptr)) goto out_rel; + DBF_DEV_EVENT(DBF_ERR, irq_ptr, "alloc niq:%1u noq:%1u", no_input_qs, + no_output_qs); + /* * Allocate a page for the chsc calls in qdio_establish. * Must be pre-allocated since a zfcp recovery will call @@ -1272,12 +1265,11 @@ int qdio_allocate(struct qdio_initialize *init_data) if (!irq_ptr->qdr) goto out_rel; - if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs, - init_data->no_output_qs)) + if (qdio_allocate_qs(irq_ptr, no_input_qs, no_output_qs)) goto out_rel; INIT_LIST_HEAD(&irq_ptr->entry); - init_data->cdev->private->qdio_data = irq_ptr; + cdev->private->qdio_data = irq_ptr; qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); return 0; out_rel: @@ -1309,26 +1301,54 @@ static void qdio_detect_hsicq(struct qdio_irq *irq_ptr) DBF_EVENT("use_cq:%d", use_cq); } +static void qdio_trace_init_data(struct qdio_irq *irq, + struct qdio_initialize *data) +{ + DBF_DEV_EVENT(DBF_ERR, irq, "qfmt:%1u", data->q_format); + DBF_DEV_HEX(irq, data->adapter_name, 8, DBF_ERR); + DBF_DEV_EVENT(DBF_ERR, irq, "qpff%4x", data->qib_param_field_format); + DBF_DEV_HEX(irq, &data->qib_param_field, sizeof(void *), DBF_ERR); + DBF_DEV_HEX(irq, &data->input_slib_elements, sizeof(void *), DBF_ERR); + DBF_DEV_HEX(irq, &data->output_slib_elements, sizeof(void *), DBF_ERR); + DBF_DEV_EVENT(DBF_ERR, irq, "niq:%1u noq:%1u", data->no_input_qs, + data->no_output_qs); + DBF_DEV_HEX(irq, &data->input_handler, sizeof(void *), DBF_ERR); + DBF_DEV_HEX(irq, &data->output_handler, sizeof(void *), DBF_ERR); + DBF_DEV_HEX(irq, &data->int_parm, sizeof(long), DBF_ERR); + DBF_DEV_HEX(irq, &data->input_sbal_addr_array, sizeof(void *), DBF_ERR); + DBF_DEV_HEX(irq, &data->output_sbal_addr_array, sizeof(void *), + DBF_ERR); +} + /** * qdio_establish - establish queues on a qdio subchannel + * @cdev: associated ccw device * @init_data: initialization data */ -int qdio_establish(struct qdio_initialize *init_data) +int qdio_establish(struct ccw_device *cdev, + struct qdio_initialize *init_data) { - struct ccw_device *cdev = init_data->cdev; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; - struct qdio_irq *irq_ptr; int rc; 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 ((init_data->no_input_qs && !init_data->input_handler) || + (init_data->no_output_qs && !init_data->output_handler)) + return -EINVAL; + + if (!init_data->input_sbal_addr_array || + !init_data->output_sbal_addr_array) + return -EINVAL; + mutex_lock(&irq_ptr->setup_mutex); - qdio_setup_irq(init_data); + qdio_trace_init_data(irq_ptr, init_data); + qdio_setup_irq(irq_ptr, init_data); rc = qdio_establish_thinint(irq_ptr); if (rc) { @@ -1374,8 +1394,8 @@ int qdio_establish(struct qdio_initialize *init_data) qdio_init_buf_states(irq_ptr); mutex_unlock(&irq_ptr->setup_mutex); - qdio_print_subchannel_info(irq_ptr, cdev); - qdio_setup_debug_entries(irq_ptr, cdev); + qdio_print_subchannel_info(irq_ptr); + qdio_setup_debug_entries(irq_ptr); return 0; } EXPORT_SYMBOL_GPL(qdio_establish); @@ -1386,14 +1406,13 @@ EXPORT_SYMBOL_GPL(qdio_establish); */ int qdio_activate(struct ccw_device *cdev) { + struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; - struct qdio_irq *irq_ptr; int rc; ccw_device_get_schid(cdev, &schid); DBF_EVENT("qactivate:%4x", schid.sch_no); - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; @@ -1610,24 +1629,24 @@ EXPORT_SYMBOL_GPL(do_QDIO); /** * qdio_start_irq - process input buffers * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number * * Return codes * 0 - success * 1 - irqs not started since new data is available */ -int qdio_start_irq(struct ccw_device *cdev, int nr) +int qdio_start_irq(struct ccw_device *cdev) { struct qdio_q *q; struct qdio_irq *irq_ptr = cdev->private->qdio_data; + unsigned int i; if (!irq_ptr) return -ENODEV; - q = irq_ptr->input_qs[nr]; - clear_nonshared_ind(irq_ptr); - qdio_stop_polling(q); - clear_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state); + for_each_input_queue(irq_ptr, q, i) + qdio_stop_polling(q); + + clear_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state); /* * We need to check again to not lose initiative after @@ -1635,13 +1654,16 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) */ if (test_nonshared_ind(irq_ptr)) goto rescan; - if (!qdio_inbound_q_done(q, q->first_to_check)) - goto rescan; + + for_each_input_queue(irq_ptr, q, i) { + if (!qdio_inbound_q_done(q, q->first_to_check)) + goto rescan; + } + return 0; rescan: - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) + if (test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) return 0; else return 1; @@ -1729,23 +1751,19 @@ EXPORT_SYMBOL(qdio_get_next_buffers); /** * qdio_stop_irq - disable interrupt processing for the device * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number * * Return codes * 0 - interrupts were already disabled * 1 - interrupts successfully disabled */ -int qdio_stop_irq(struct ccw_device *cdev, int nr) +int qdio_stop_irq(struct ccw_device *cdev) { - struct qdio_q *q; struct qdio_irq *irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; - q = irq_ptr->input_qs[nr]; - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) + if (test_and_set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state)) return 0; else return 1; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index e115623b86b2..3083edd61f0c 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -213,8 +213,6 @@ static void setup_queues(struct qdio_irq *irq_ptr, struct qdio_initialize *qdio_init) { struct qdio_q *q; - struct qdio_buffer **input_sbal_array = qdio_init->input_sbal_addr_array; - struct qdio_buffer **output_sbal_array = qdio_init->output_sbal_addr_array; struct qdio_outbuf_state *output_sbal_state_array = qdio_init->output_sbal_state_array; int i; @@ -224,11 +222,9 @@ static void setup_queues(struct qdio_irq *irq_ptr, setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); q->is_input_q = 1; - q->u.in.queue_start_poll = qdio_init->queue_start_poll_array ? - qdio_init->queue_start_poll_array[i] : NULL; - setup_storage_lists(q, irq_ptr, input_sbal_array, i); - input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; + setup_storage_lists(q, irq_ptr, + qdio_init->input_sbal_addr_array[i], i); if (is_thinint_irq(irq_ptr)) { tasklet_init(&q->tasklet, tiqdio_inbound_processing, @@ -247,8 +243,8 @@ static void setup_queues(struct qdio_irq *irq_ptr, output_sbal_state_array += QDIO_MAX_BUFFERS_PER_Q; q->is_input_q = 0; - setup_storage_lists(q, irq_ptr, output_sbal_array, i); - output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; + setup_storage_lists(q, irq_ptr, + qdio_init->output_sbal_addr_array[i], i); tasklet_init(&q->tasklet, qdio_outbound_processing, (unsigned long) q); @@ -451,10 +447,10 @@ static void setup_qib(struct qdio_irq *irq_ptr, memcpy(irq_ptr->qib.ebcnam, init_data->adapter_name, 8); } -int qdio_setup_irq(struct qdio_initialize *init_data) +int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) { + struct ccw_device *cdev = irq_ptr->cdev; struct ciw *ciw; - struct qdio_irq *irq_ptr = init_data->cdev->private->qdio_data; memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); @@ -462,8 +458,9 @@ int qdio_setup_irq(struct qdio_initialize *init_data) memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc)); memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); - irq_ptr->debugfs_dev = irq_ptr->debugfs_perf = NULL; - irq_ptr->sch_token = irq_ptr->state = irq_ptr->perf_stat_enabled = 0; + irq_ptr->debugfs_dev = NULL; + irq_ptr->sch_token = irq_ptr->perf_stat_enabled = 0; + irq_ptr->state = QDIO_IRQ_STATE_INACTIVE; /* wipes qib.ac, required by ar7063 */ memset(irq_ptr->qdr, 0, sizeof(struct qdr)); @@ -471,11 +468,17 @@ int qdio_setup_irq(struct qdio_initialize *init_data) irq_ptr->int_parm = init_data->int_parm; irq_ptr->nr_input_qs = init_data->no_input_qs; irq_ptr->nr_output_qs = init_data->no_output_qs; - irq_ptr->cdev = init_data->cdev; irq_ptr->scan_threshold = init_data->scan_threshold; - ccw_device_get_schid(irq_ptr->cdev, &irq_ptr->schid); + ccw_device_get_schid(cdev, &irq_ptr->schid); setup_queues(irq_ptr, init_data); + if (init_data->irq_poll) { + irq_ptr->irq_poll = init_data->irq_poll; + set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state); + } else { + irq_ptr->irq_poll = NULL; + } + setup_qib(irq_ptr, init_data); qdio_setup_thinint(irq_ptr); set_impl_params(irq_ptr, init_data->qib_param_field_format, @@ -489,14 +492,14 @@ int qdio_setup_irq(struct qdio_initialize *init_data) /* qdr, qib, sls, slsbs, slibs, sbales are filled now */ /* get qdio commands */ - ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); + ciw = ccw_device_get_ciw(cdev, CIW_TYPE_EQUEUE); if (!ciw) { DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); return -EINVAL; } irq_ptr->equeue = *ciw; - ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); + ciw = ccw_device_get_ciw(cdev, CIW_TYPE_AQUEUE); if (!ciw) { DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); return -EINVAL; @@ -504,21 +507,20 @@ int qdio_setup_irq(struct qdio_initialize *init_data) irq_ptr->aqueue = *ciw; /* set new interrupt handler */ - spin_lock_irq(get_ccwdev_lock(irq_ptr->cdev)); - irq_ptr->orig_handler = init_data->cdev->handler; - init_data->cdev->handler = qdio_int_handler; - spin_unlock_irq(get_ccwdev_lock(irq_ptr->cdev)); + spin_lock_irq(get_ccwdev_lock(cdev)); + irq_ptr->orig_handler = cdev->handler; + cdev->handler = qdio_int_handler; + spin_unlock_irq(get_ccwdev_lock(cdev)); return 0; } -void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, - struct ccw_device *cdev) +void qdio_print_subchannel_info(struct qdio_irq *irq_ptr) { char s[80]; snprintf(s, 80, "qdio: %s %s on SC %x using " "AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s\n", - dev_name(&cdev->dev), + dev_name(&irq_ptr->cdev->dev), (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), irq_ptr->schid.sch_no, diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 7c4e4ec08a12..ae50373617cd 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -82,36 +82,16 @@ void tiqdio_remove_device(struct qdio_irq *irq_ptr) INIT_LIST_HEAD(&irq_ptr->entry); } -static inline int has_multiple_inq_on_dsci(struct qdio_irq *irq_ptr) -{ - return irq_ptr->nr_input_qs > 1; -} - static inline int references_shared_dsci(struct qdio_irq *irq_ptr) { return irq_ptr->dsci == &q_indicators[TIQDIO_SHARED_IND].ind; } -static inline int shared_ind(struct qdio_irq *irq_ptr) -{ - return references_shared_dsci(irq_ptr) || - has_multiple_inq_on_dsci(irq_ptr); -} - -void clear_nonshared_ind(struct qdio_irq *irq_ptr) -{ - if (!is_thinint_irq(irq_ptr)) - return; - if (shared_ind(irq_ptr)) - return; - xchg(irq_ptr->dsci, 0); -} - int test_nonshared_ind(struct qdio_irq *irq_ptr) { if (!is_thinint_irq(irq_ptr)) return 0; - if (shared_ind(irq_ptr)) + if (references_shared_dsci(irq_ptr)) return 0; if (*irq_ptr->dsci) return 1; @@ -131,32 +111,24 @@ static inline void tiqdio_call_inq_handlers(struct qdio_irq *irq) struct qdio_q *q; int i; - if (!references_shared_dsci(irq) && - has_multiple_inq_on_dsci(irq)) + if (!references_shared_dsci(irq)) xchg(irq->dsci, 0); + if (irq->irq_poll) { + if (!test_and_set_bit(QDIO_IRQ_DISABLED, &irq->poll_state)) + irq->irq_poll(irq->cdev, irq->int_parm); + else + QDIO_PERF_STAT_INC(irq, int_discarded); + + return; + } + for_each_input_queue(irq, q, i) { - if (q->u.in.queue_start_poll) { - /* skip if polling is enabled or already in work */ - if (test_and_set_bit(QDIO_QUEUE_IRQS_DISABLED, - &q->u.in.queue_irq_state)) { - QDIO_PERF_STAT_INC(irq, int_discarded); - continue; - } - - /* avoid dsci clear here, done after processing */ - q->u.in.queue_start_poll(irq->cdev, q->nr, - irq->int_parm); - } else { - if (!shared_ind(irq)) - xchg(irq->dsci, 0); - - /* - * Call inbound processing but not directly - * since that could starve other thinint queues. - */ - tasklet_schedule(&q->tasklet); - } + /* + * Call inbound processing but not directly + * since that could starve other thinint queues. + */ + tasklet_schedule(&q->tasklet); } } @@ -211,7 +183,7 @@ static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) } rc = chsc_sadc(irq_ptr->schid, scssc, summary_indicator_addr, - subchannel_indicator_addr); + subchannel_indicator_addr, tiqdio_airq.isc); if (rc) { DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, scssc->response.code); diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index e401a3d0aa57..339a6bc0339b 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -167,6 +167,11 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) if (ret) goto out_disable; + if (dev_get_uevent_suppress(&sch->dev)) { + dev_set_uevent_suppress(&sch->dev, 0); + kobject_uevent(&sch->dev.kobj, KOBJ_ADD); + } + VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n", sch->schid.cssid, sch->schid.ssid, sch->schid.sch_no); |