diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-13 11:47:01 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-13 11:47:01 -0800 |
commit | d60a540ac5f2fbab3e6fe592717b445bd7343a91 (patch) | |
tree | cdfe23e7c2cb753aba10e5edc7c38972eac25ed0 /drivers/s390 | |
parent | 2101dd64b304b034862f5ca40877c41b7ccb9c5e (diff) | |
parent | 364a5607d6988b05b54cc0138cf8229203b9a33e (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Heiko Carstens:
"Since Martin is on vacation you get the s390 pull request for the
v4.15 merge window this time from me.
Besides a lot of cleanups and bug fixes these are the most important
changes:
- a new regset for runtime instrumentation registers
- hardware accelerated AES-GCM support for the aes_s390 module
- support for the new CEX6S crypto cards
- support for FORTIFY_SOURCE
- addition of missing z13 and new z14 instructions to the in-kernel
disassembler
- generate opcode tables for the in-kernel disassembler out of a
simple text file instead of having to manually maintain those
tables
- fast memset16, memset32 and memset64 implementations
- removal of named saved segment support
- hardware counter support for z14
- queued spinlocks and queued rwlocks implementations for s390
- use the stack_depth tracking feature for s390 BPF JIT
- a new s390_sthyi system call which emulates the sthyi (store
hypervisor information) instruction
- removal of the old KVM virtio transport
- an s390 specific CPU alternatives implementation which is used in
the new spinlock code"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (88 commits)
MAINTAINERS: add virtio-ccw.h to virtio/s390 section
s390/noexec: execute kexec datamover without DAT
s390: fix transactional execution control register handling
s390/bpf: take advantage of stack_depth tracking
s390: simplify transactional execution elf hwcap handling
s390/zcrypt: Rework struct ap_qact_ap_info.
s390/virtio: remove unused header file kvm_virtio.h
s390: avoid undefined behaviour
s390/disassembler: generate opcode tables from text file
s390/disassembler: remove insn_to_mnemonic()
s390/dasd: avoid calling do_gettimeofday()
s390: vfio-ccw: Do not attempt to free no-op, test and tic cda.
s390: remove named saved segment support
s390/archrandom: Reconsider s390 arch random implementation
s390/pci: do not require AIS facility
s390/qdio: sanitize put_indicator
s390/qdio: use atomic_cmpxchg
s390/nmi: avoid using long-displacement facility
s390: pass endianness info to sparse
s390/decompressor: remove informational messages
...
Diffstat (limited to 'drivers/s390')
32 files changed, 327 insertions, 828 deletions
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 4630782b5456..a7917d473774 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -296,7 +296,7 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, { struct dasd_ccw_req *temp_cqr; int data_size; - struct timeval tv; + struct timespec64 ts; struct dasd_eer_header header; unsigned long flags; struct eerbuffer *eerb; @@ -310,9 +310,9 @@ static void dasd_eer_write_standard_trigger(struct dasd_device *device, header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ header.trigger = trigger; - do_gettimeofday(&tv); - header.tv_sec = tv.tv_sec; - header.tv_usec = tv.tv_usec; + ktime_get_real_ts64(&ts); + header.tv_sec = ts.tv_sec; + header.tv_usec = ts.tv_nsec / NSEC_PER_USEC; strncpy(header.busid, dev_name(&device->cdev->dev), DASD_EER_BUSID_SIZE); @@ -340,7 +340,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device, { int data_size; int snss_rc; - struct timeval tv; + struct timespec64 ts; struct dasd_eer_header header; unsigned long flags; struct eerbuffer *eerb; @@ -353,9 +353,9 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device, header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ header.trigger = DASD_EER_STATECHANGE; - do_gettimeofday(&tv); - header.tv_sec = tv.tv_sec; - header.tv_usec = tv.tv_usec; + ktime_get_real_ts64(&ts); + header.tv_sec = ts.tv_sec; + header.tv_usec = ts.tv_nsec / NSEC_PER_USEC; strncpy(header.busid, dev_name(&device->cdev->dev), DASD_EER_BUSID_SIZE); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index e94080a5196f..b095a23bcc0c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -96,14 +96,6 @@ do { \ d_data); \ } while(0) -#define DBF_DEV_EXC(d_level, d_device, d_str, d_data...) \ -do { \ - debug_sprintf_exception(d_device->debug_area, \ - d_level, \ - d_str "\n", \ - d_data); \ -} while(0) - #define DBF_EVENT(d_level, d_str, d_data...)\ do { \ debug_sprintf_event(dasd_debug_area, \ @@ -122,14 +114,6 @@ do { \ __dev_id.ssid, __dev_id.devno, d_data); \ } while (0) -#define DBF_EXC(d_level, d_str, d_data...)\ -do { \ - debug_sprintf_exception(dasd_debug_area, \ - d_level,\ - d_str "\n", \ - d_data); \ -} while(0) - /* limit size for an errorstring */ #define ERRORLENGTH 30 diff --git a/drivers/s390/block/scm_blk.h b/drivers/s390/block/scm_blk.h index aa42c3a2c90a..a05a4297cfae 100644 --- a/drivers/s390/block/scm_blk.h +++ b/drivers/s390/block/scm_blk.h @@ -56,13 +56,7 @@ extern debug_info_t *scm_debug; static inline void SCM_LOG_HEX(int level, void *data, int length) { - if (!debug_level_enabled(scm_debug, level)) - return; - while (length > 0) { - debug_event(scm_debug, level, data, length); - length -= scm_debug->buf_size; - data += scm_debug->buf_size; - } + debug_event(scm_debug, level, data, length); } static inline void SCM_LOG_STATE(int level, struct scm_device *scmdev) diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index d247f238faf8..7027e61a6931 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -211,11 +211,8 @@ sclp_console_write(struct console *console, const char *message, /* Setup timer to output current console buffer after 1/10 second */ if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 && !timer_pending(&sclp_con_timer)) { - init_timer(&sclp_con_timer); - sclp_con_timer.function = sclp_console_timeout; - sclp_con_timer.data = 0UL; - sclp_con_timer.expires = jiffies + HZ/10; - add_timer(&sclp_con_timer); + setup_timer(&sclp_con_timer, sclp_console_timeout, 0UL); + mod_timer(&sclp_con_timer, jiffies + HZ / 10); } out: spin_unlock_irqrestore(&sclp_con_lock, flags); diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 875628dab419..1cceefdc03e0 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -218,11 +218,8 @@ static int sclp_tty_write_string(const unsigned char *str, int count, int may_fa /* Setup timer to output current console buffer after 1/10 second */ if (sclp_ttybuf && sclp_chars_in_buffer(sclp_ttybuf) && !timer_pending(&sclp_tty_timer)) { - init_timer(&sclp_tty_timer); - sclp_tty_timer.function = sclp_tty_timeout; - sclp_tty_timer.data = 0UL; - sclp_tty_timer.expires = jiffies + HZ/10; - add_timer(&sclp_tty_timer); + setup_timer(&sclp_tty_timer, sclp_tty_timeout, 0UL); + mod_timer(&sclp_tty_timer, jiffies + HZ / 10); } spin_unlock_irqrestore(&sclp_tty_lock, flags); out: diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c index 91c3c642c76e..e7d23048d3f0 100644 --- a/drivers/s390/char/tape_class.c +++ b/drivers/s390/char/tape_class.c @@ -68,9 +68,8 @@ struct tape_class_device *register_tape_dev( tcd->char_device->owner = fops->owner; tcd->char_device->ops = fops; - tcd->char_device->dev = dev; - rc = cdev_add(tcd->char_device, tcd->char_device->dev, 1); + rc = cdev_add(tcd->char_device, dev, 1); if (rc) goto fail_with_cdev; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index b19020b9efff..62559dc0169f 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -812,8 +812,7 @@ static int vmlogrdr_register_cdev(dev_t dev) } vmlogrdr_cdev->owner = THIS_MODULE; vmlogrdr_cdev->ops = &vmlogrdr_fops; - vmlogrdr_cdev->dev = dev; - rc = cdev_add(vmlogrdr_cdev, vmlogrdr_cdev->dev, MAXMINOR); + rc = cdev_add(vmlogrdr_cdev, dev, MAXMINOR); if (!rc) return 0; diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 04aceb694d51..fa90ef05afc0 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -110,7 +110,7 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev) mutex_init(&urd->io_mutex); init_waitqueue_head(&urd->wait); spin_lock_init(&urd->open_lock); - atomic_set(&urd->ref_count, 1); + refcount_set(&urd->ref_count, 1); urd->cdev = cdev; get_device(&cdev->dev); return urd; @@ -126,7 +126,7 @@ static void urdev_free(struct urdev *urd) static void urdev_get(struct urdev *urd) { - atomic_inc(&urd->ref_count); + refcount_inc(&urd->ref_count); } static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev) @@ -159,7 +159,7 @@ static struct urdev *urdev_get_from_devno(u16 devno) static void urdev_put(struct urdev *urd) { - if (atomic_dec_and_test(&urd->ref_count)) + if (refcount_dec_and_test(&urd->ref_count)) urdev_free(urd); } @@ -892,10 +892,9 @@ static int ur_set_online(struct ccw_device *cdev) } urd->char_device->ops = &ur_fops; - urd->char_device->dev = MKDEV(major, minor); urd->char_device->owner = ur_fops.owner; - rc = cdev_add(urd->char_device, urd->char_device->dev, 1); + rc = cdev_add(urd->char_device, MKDEV(major, minor), 1); if (rc) goto fail_free_cdev; if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) { @@ -946,7 +945,7 @@ static int ur_set_offline_force(struct ccw_device *cdev, int force) rc = -EBUSY; goto fail_urdev_put; } - if (!force && (atomic_read(&urd->ref_count) > 2)) { + if (!force && (refcount_read(&urd->ref_count) > 2)) { /* There is still a user of urd (e.g. ur_open) */ TRACE("ur_set_offline: BUSY\n"); rc = -EBUSY; diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h index 67164ba22f11..608b0719ce17 100644 --- a/drivers/s390/char/vmur.h +++ b/drivers/s390/char/vmur.h @@ -12,6 +12,8 @@ #ifndef _VMUR_H_ #define _VMUR_H_ +#include <linux/refcount.h> + #define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */ #define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */ /* @@ -70,7 +72,7 @@ struct urdev { size_t reclen; /* Record length for *write* CCWs */ int class; /* VM device class */ int io_request_rc; /* return code from I/O request */ - atomic_t ref_count; /* reference counter */ + refcount_t ref_count; /* reference counter */ wait_queue_head_t wait; /* wait queue to serialize open */ int open_flag; /* "urdev is open" flag */ spinlock_t open_lock; /* serialize critical sections */ diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 34b9ad6b3143..e2f7b6e93efd 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -373,6 +373,12 @@ int ccwgroup_create_dev(struct device *parent, struct ccwgroup_driver *gdrv, rc = -EINVAL; goto error; } + /* Check if the devices are bound to the required ccw driver. */ + if (gdev->count && gdrv && gdrv->ccw_driver && + gdev->cdev[0]->drv != gdrv->ccw_driver) { + rc = -EINVAL; + goto error; + } dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); gdev->dev.groups = ccwgroup_attr_groups; diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 735052ecd3e5..8e7e19b9e92c 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -43,11 +43,7 @@ static DEFINE_MUTEX(on_close_mutex); static void CHSC_LOG_HEX(int level, void *data, int length) { - while (length > 0) { - debug_event(chsc_debug_log_id, level, data, length); - length -= chsc_debug_log_id->buf_size; - data += chsc_debug_log_id->buf_size; - } + debug_event(chsc_debug_log_id, level, data, length); } MODULE_AUTHOR("IBM Corporation"); diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h index fa817efcec8f..7bdbe73707c2 100644 --- a/drivers/s390/cio/cio_debug.h +++ b/drivers/s390/cio/cio_debug.h @@ -23,13 +23,7 @@ extern debug_info_t *cio_debug_crw_id; static inline void CIO_HEX_EVENT(int level, void *data, int length) { - if (unlikely(!cio_debug_trace_id)) - return; - while (length > 0) { - debug_event(cio_debug_trace_id, level, data, length); - length -= cio_debug_trace_id->buf_size; - data += cio_debug_trace_id->buf_size; - } + debug_event(cio_debug_trace_id, level, data, length); } #endif diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 220491d27ef4..7d59230e88bb 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -58,8 +58,9 @@ /* indices for READCMB */ enum cmb_index { + avg_utilization = -1, /* basic and exended format: */ - cmb_ssch_rsch_count, + cmb_ssch_rsch_count = 0, cmb_sample_count, cmb_device_connect_time, cmb_function_pending_time, @@ -215,71 +216,52 @@ struct set_schib_struct { unsigned long address; wait_queue_head_t wait; int ret; - struct kref kref; }; -static void cmf_set_schib_release(struct kref *kref) -{ - struct set_schib_struct *set_data; - - set_data = container_of(kref, struct set_schib_struct, kref); - kfree(set_data); -} - #define CMF_PENDING 1 +#define SET_SCHIB_TIMEOUT (10 * HZ) static int set_schib_wait(struct ccw_device *cdev, u32 mme, - int mbfc, unsigned long address) + int mbfc, unsigned long address) { - struct set_schib_struct *set_data; - int ret; + struct set_schib_struct set_data; + int ret = -ENODEV; spin_lock_irq(cdev->ccwlock); - if (!cdev->private->cmb) { - ret = -ENODEV; + if (!cdev->private->cmb) goto out; - } - set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC); - if (!set_data) { - ret = -ENOMEM; - goto out; - } - init_waitqueue_head(&set_data->wait); - kref_init(&set_data->kref); - set_data->mme = mme; - set_data->mbfc = mbfc; - set_data->address = address; ret = set_schib(cdev, mme, mbfc, address); if (ret != -EBUSY) - goto out_put; + goto out; - if (cdev->private->state != DEV_STATE_ONLINE) { - /* if the device is not online, don't even try again */ - ret = -EBUSY; - goto out_put; - } + /* if the device is not online, don't even try again */ + if (cdev->private->state != DEV_STATE_ONLINE) + goto out; - cdev->private->state = DEV_STATE_CMFCHANGE; - set_data->ret = CMF_PENDING; - cdev->private->cmb_wait = set_data; + init_waitqueue_head(&set_data.wait); + set_data.mme = mme; + set_data.mbfc = mbfc; + set_data.address = address; + set_data.ret = CMF_PENDING; + cdev->private->state = DEV_STATE_CMFCHANGE; + cdev->private->cmb_wait = &set_data; spin_unlock_irq(cdev->ccwlock); - if (wait_event_interruptible(set_data->wait, - set_data->ret != CMF_PENDING)) { - spin_lock_irq(cdev->ccwlock); - if (set_data->ret == CMF_PENDING) { - set_data->ret = -ERESTARTSYS; + + ret = wait_event_interruptible_timeout(set_data.wait, + set_data.ret != CMF_PENDING, + SET_SCHIB_TIMEOUT); + spin_lock_irq(cdev->ccwlock); + if (ret <= 0) { + if (set_data.ret == CMF_PENDING) { + set_data.ret = (ret == 0) ? -ETIME : ret; if (cdev->private->state == DEV_STATE_CMFCHANGE) cdev->private->state = DEV_STATE_ONLINE; } - spin_unlock_irq(cdev->ccwlock); } - spin_lock_irq(cdev->ccwlock); cdev->private->cmb_wait = NULL; - ret = set_data->ret; -out_put: - kref_put(&set_data->kref, cmf_set_schib_release); + ret = set_data.ret; out: spin_unlock_irq(cdev->ccwlock); return ret; @@ -287,28 +269,21 @@ out: void retry_set_schib(struct ccw_device *cdev) { - struct set_schib_struct *set_data; + struct set_schib_struct *set_data = cdev->private->cmb_wait; - set_data = cdev->private->cmb_wait; - if (!set_data) { - WARN_ON(1); + if (!set_data) return; - } - kref_get(&set_data->kref); + set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc, set_data->address); wake_up(&set_data->wait); - kref_put(&set_data->kref, cmf_set_schib_release); } static int cmf_copy_block(struct ccw_device *cdev) { - struct subchannel *sch; - void *reference_buf; - void *hw_block; + struct subchannel *sch = to_subchannel(cdev->dev.parent); struct cmb_data *cmb_data; - - sch = to_subchannel(cdev->dev.parent); + void *hw_block; if (cio_update_schib(sch)) return -ENODEV; @@ -323,102 +298,65 @@ static int cmf_copy_block(struct ccw_device *cdev) } cmb_data = cdev->private->cmb; hw_block = cmb_data->hw_block; - if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size)) - /* No need to copy. */ - return 0; - reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC); - if (!reference_buf) - return -ENOMEM; - /* Ensure consistency of block copied from hardware. */ - do { - memcpy(cmb_data->last_block, hw_block, cmb_data->size); - memcpy(reference_buf, hw_block, cmb_data->size); - } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size)); + memcpy(cmb_data->last_block, hw_block, cmb_data->size); cmb_data->last_update = get_tod_clock(); - kfree(reference_buf); return 0; } struct copy_block_struct { wait_queue_head_t wait; int ret; - struct kref kref; }; -static void cmf_copy_block_release(struct kref *kref) -{ - struct copy_block_struct *copy_block; - - copy_block = container_of(kref, struct copy_block_struct, kref); - kfree(copy_block); -} - static int cmf_cmb_copy_wait(struct ccw_device *cdev) { - struct copy_block_struct *copy_block; - int ret; - unsigned long flags; + struct copy_block_struct copy_block; + int ret = -ENODEV; - spin_lock_irqsave(cdev->ccwlock, flags); - if (!cdev->private->cmb) { - ret = -ENODEV; - goto out; - } - copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC); - if (!copy_block) { - ret = -ENOMEM; + spin_lock_irq(cdev->ccwlock); + if (!cdev->private->cmb) goto out; - } - init_waitqueue_head(©_block->wait); - kref_init(©_block->kref); ret = cmf_copy_block(cdev); if (ret != -EBUSY) - goto out_put; + goto out; - if (cdev->private->state != DEV_STATE_ONLINE) { - ret = -EBUSY; - goto out_put; - } + if (cdev->private->state != DEV_STATE_ONLINE) + goto out; + + init_waitqueue_head(©_block.wait); + copy_block.ret = CMF_PENDING; cdev->private->state = DEV_STATE_CMFUPDATE; - copy_block->ret = CMF_PENDING; - cdev->private->cmb_wait = copy_block; + cdev->private->cmb_wait = ©_block; + spin_unlock_irq(cdev->ccwlock); - spin_unlock_irqrestore(cdev->ccwlock, flags); - if (wait_event_interruptible(copy_block->wait, - copy_block->ret != CMF_PENDING)) { - spin_lock_irqsave(cdev->ccwlock, flags); - if (copy_block->ret == CMF_PENDING) { - copy_block->ret = -ERESTARTSYS; + ret = wait_event_interruptible(copy_block.wait, + copy_block.ret != CMF_PENDING); + spin_lock_irq(cdev->ccwlock); + if (ret) { + if (copy_block.ret == CMF_PENDING) { + copy_block.ret = -ERESTARTSYS; if (cdev->private->state == DEV_STATE_CMFUPDATE) cdev->private->state = DEV_STATE_ONLINE; } - spin_unlock_irqrestore(cdev->ccwlock, flags); } - spin_lock_irqsave(cdev->ccwlock, flags); cdev->private->cmb_wait = NULL; - ret = copy_block->ret; -out_put: - kref_put(©_block->kref, cmf_copy_block_release); + ret = copy_block.ret; out: - spin_unlock_irqrestore(cdev->ccwlock, flags); + spin_unlock_irq(cdev->ccwlock); return ret; } void cmf_retry_copy_block(struct ccw_device *cdev) { - struct copy_block_struct *copy_block; + struct copy_block_struct *copy_block = cdev->private->cmb_wait; - copy_block = cdev->private->cmb_wait; - if (!copy_block) { - WARN_ON(1); + if (!copy_block) return; - } - kref_get(©_block->kref); + copy_block->ret = cmf_copy_block(cdev); wake_up(©_block->wait); - kref_put(©_block->kref, cmf_copy_block_release); } static void cmf_generic_reset(struct ccw_device *cdev) @@ -650,25 +588,44 @@ static int set_cmb(struct ccw_device *cdev, u32 mme) return set_schib_wait(cdev, mme, 0, offset); } +/* calculate utilization in 0.1 percent units */ +static u64 __cmb_utilization(u64 device_connect_time, u64 function_pending_time, + u64 device_disconnect_time, u64 start_time) +{ + u64 utilization, elapsed_time; + + utilization = time_to_nsec(device_connect_time + + function_pending_time + + device_disconnect_time); + + elapsed_time = get_tod_clock() - start_time; + elapsed_time = tod_to_ns(elapsed_time); + elapsed_time /= 1000; + + return elapsed_time ? (utilization / elapsed_time) : 0; +} + static u64 read_cmb(struct ccw_device *cdev, int index) { + struct cmb_data *cmb_data; + unsigned long flags; struct cmb *cmb; + u64 ret = 0; u32 val; - int ret; - unsigned long flags; - - ret = cmf_cmb_copy_wait(cdev); - if (ret < 0) - return 0; spin_lock_irqsave(cdev->ccwlock, flags); - if (!cdev->private->cmb) { - ret = 0; + cmb_data = cdev->private->cmb; + if (!cmb_data) goto out; - } - cmb = ((struct cmb_data *)cdev->private->cmb)->last_block; + cmb = cmb_data->hw_block; switch (index) { + case avg_utilization: + ret = __cmb_utilization(cmb->device_connect_time, + cmb->function_pending_time, + cmb->device_disconnect_time, + cdev->private->cmb_start_time); + goto out; case cmb_ssch_rsch_count: ret = cmb->ssch_rsch_count; goto out; @@ -691,7 +648,6 @@ static u64 read_cmb(struct ccw_device *cdev, int index) val = cmb->device_active_only_time; break; default: - ret = 0; goto out; } ret = time_to_avg_nsec(val, cmb->sample_count); @@ -729,8 +685,7 @@ static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data) /* we only know values before device_busy_time */ data->size = offsetof(struct cmbdata, device_busy_time); - /* convert to nanoseconds */ - data->elapsed_time = (time * 1000) >> 12; + data->elapsed_time = tod_to_ns(time); /* copy data to new structure */ data->ssch_rsch_count = cmb->ssch_rsch_count; @@ -904,28 +859,27 @@ static int set_cmbe(struct ccw_device *cdev, u32 mme) return set_schib_wait(cdev, mme, 1, mba); } - static u64 read_cmbe(struct ccw_device *cdev, int index) { - struct cmbe *cmb; struct cmb_data *cmb_data; - u32 val; - int ret; unsigned long flags; - - ret = cmf_cmb_copy_wait(cdev); - if (ret < 0) - return 0; + struct cmbe *cmb; + u64 ret = 0; + u32 val; spin_lock_irqsave(cdev->ccwlock, flags); cmb_data = cdev->private->cmb; - if (!cmb_data) { - ret = 0; + if (!cmb_data) goto out; - } - cmb = cmb_data->last_block; + cmb = cmb_data->hw_block; switch (index) { + case avg_utilization: + ret = __cmb_utilization(cmb->device_connect_time, + cmb->function_pending_time, + cmb->device_disconnect_time, + cdev->private->cmb_start_time); + goto out; case cmb_ssch_rsch_count: ret = cmb->ssch_rsch_count; goto out; @@ -954,7 +908,6 @@ static u64 read_cmbe(struct ccw_device *cdev, int index) val = cmb->initial_command_response_time; break; default: - ret = 0; goto out; } ret = time_to_avg_nsec(val, cmb->sample_count); @@ -991,8 +944,7 @@ static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data) /* we only know values before device_busy_time */ data->size = offsetof(struct cmbdata, device_busy_time); - /* conver to nanoseconds */ - data->elapsed_time = (time * 1000) >> 12; + data->elapsed_time = tod_to_ns(time); cmb = cmb_data->last_block; /* copy data to new structure */ @@ -1045,19 +997,15 @@ static ssize_t cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct ccw_device *cdev; - long interval; + struct ccw_device *cdev = to_ccwdev(dev); unsigned long count; - struct cmb_data *cmb_data; + long interval; - cdev = to_ccwdev(dev); count = cmf_read(cdev, cmb_sample_count); spin_lock_irq(cdev->ccwlock); - cmb_data = cdev->private->cmb; if (count) { - interval = cmb_data->last_update - - cdev->private->cmb_start_time; - interval = (interval * 1000) >> 12; + interval = get_tod_clock() - cdev->private->cmb_start_time; + interval = tod_to_ns(interval); interval /= count; } else interval = -1; @@ -1069,27 +1017,9 @@ static ssize_t cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf) { - struct cmbdata data; - u64 utilization; - unsigned long t, u; - int ret; - - ret = cmf_readall(to_ccwdev(dev), &data); - if (ret == -EAGAIN || ret == -ENODEV) - /* No data (yet/currently) available to use for calculation. */ - return sprintf(buf, "n/a\n"); - else if (ret) - return ret; - - utilization = data.device_connect_time + - data.function_pending_time + - data.device_disconnect_time; - - /* calculate value in 0.1 percent units */ - t = data.elapsed_time / 1000; - u = utilization / t; + unsigned long u = cmf_read(to_ccwdev(dev), avg_utilization); - return sprintf(buf, "%02ld.%01ld%%\n", u/ 10, u - (u/ 10) * 10); + return sprintf(buf, "%02lu.%01lu%%\n", u / 10, u % 10); } #define cmf_attr(name) \ diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index 0f11f3bcac82..d14795f7110b 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -43,13 +43,7 @@ static debug_info_t *eadm_debug; static void EADM_LOG_HEX(int level, void *data, int length) { - if (!debug_level_enabled(eadm_debug, level)) - return; - while (length > 0) { - debug_event(eadm_debug, level, data, length); - length -= eadm_debug->buf_size; - data += eadm_debug->buf_size; - } + debug_event(eadm_debug, level, data, length); } static void orb_init(union orb *orb) diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index e06496ab0036..f85f5fa7cefc 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -34,11 +34,7 @@ extern debug_info_t *qdio_dbf_error; static inline void DBF_HEX(void *addr, int len) { - while (len > 0) { - debug_event(qdio_dbf_setup, DBF_ERR, addr, len); - len -= qdio_dbf_setup->buf_size; - addr += qdio_dbf_setup->buf_size; - } + debug_event(qdio_dbf_setup, DBF_ERR, addr, len); } #define DBF_ERROR(text...) \ @@ -50,11 +46,7 @@ static inline void DBF_HEX(void *addr, int len) static inline void DBF_ERROR_HEX(void *addr, int len) { - while (len > 0) { - debug_event(qdio_dbf_error, DBF_ERR, addr, len); - len -= qdio_dbf_error->buf_size; - addr += qdio_dbf_error->buf_size; - } + debug_event(qdio_dbf_error, DBF_ERR, addr, len); } #define DBF_DEV_EVENT(level, device, text...) \ @@ -69,11 +61,7 @@ static inline void DBF_ERROR_HEX(void *addr, int len) static inline void DBF_DEV_HEX(struct qdio_irq *dev, void *addr, int len, int level) { - while (len > 0) { - debug_event(dev->debug_area, level, addr, len); - len -= dev->debug_area->buf_size; - addr += dev->debug_area->buf_size; - } + debug_event(dev->debug_area, level, addr, len); } int qdio_allocate_dbf(struct qdio_initialize *init_data, diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index a739bdf9630e..0787b587e4b8 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -57,10 +57,8 @@ static u32 *get_indicator(void) int i; for (i = 0; i < TIQDIO_NR_NONSHARED_IND; i++) - if (!atomic_read(&q_indicators[i].count)) { - atomic_set(&q_indicators[i].count, 1); + if (!atomic_cmpxchg(&q_indicators[i].count, 0, 1)) return &q_indicators[i].ind; - } /* use the shared indicator */ atomic_inc(&q_indicators[TIQDIO_SHARED_IND].count); @@ -69,13 +67,11 @@ static u32 *get_indicator(void) static void put_indicator(u32 *addr) { - int i; + struct indicator_t *ind = container_of(addr, struct indicator_t, ind); if (!addr) return; - i = ((unsigned long)addr - (unsigned long)q_indicators) / - sizeof(struct indicator_t); - atomic_dec(&q_indicators[i].count); + atomic_dec(&ind->count); } void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index f20b4d66c75f..d9a2fffd034b 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -106,7 +106,10 @@ static int pfn_array_alloc_pin(struct pfn_array *pa, struct device *mdev, { int ret = 0; - if (!len || pa->pa_nr) + if (!len) + return 0; + + if (pa->pa_nr) return -EINVAL; pa->pa_iova = iova; @@ -330,6 +333,8 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx) { struct ccw1 *ccw = chain->ch_ccw + idx; + if (ccw_is_test(ccw) || ccw_is_noop(ccw) || ccw_is_tic(ccw)) + return; if (!ccw->count) return; @@ -502,6 +507,16 @@ static int ccwchain_fetch_direct(struct ccwchain *chain, ccw = chain->ch_ccw + idx; + if (!ccw->count) { + /* + * We just want the translation result of any direct ccw + * to be an IDA ccw, so let's add the IDA flag for it. + * Although the flag will be ignored by firmware. + */ + ccw->flags |= CCW_FLAG_IDA; + return 0; + } + /* * Pin data page(s) in memory. * The number of pages actually is the count of the idaws which will be @@ -542,6 +557,9 @@ static int ccwchain_fetch_idal(struct ccwchain *chain, ccw = chain->ch_ccw + idx; + if (!ccw->count) + return 0; + /* Calculate size of idaws. */ ret = copy_from_iova(cp->mdev, &idaw_iova, ccw->cda, sizeof(idaw_iova)); if (ret) @@ -570,10 +588,6 @@ static int ccwchain_fetch_idal(struct ccwchain *chain, for (i = 0; i < idaw_nr; i++) { idaw_iova = *(idaws + i); - if (IS_ERR_VALUE(idaw_iova)) { - ret = -EFAULT; - goto out_free_idaws; - } ret = pfn_array_alloc_pin(pat->pat_pa + i, cp->mdev, idaw_iova, 1); diff --git a/drivers/s390/crypto/ap_asm.h b/drivers/s390/crypto/ap_asm.h index 6c0474c834d4..16b59ce5e01d 100644 --- a/drivers/s390/crypto/ap_asm.h +++ b/drivers/s390/crypto/ap_asm.h @@ -117,6 +117,49 @@ static inline int ap_qci(void *config) return reg1; } +/* + * union ap_qact_ap_info - used together with the + * ap_aqic() function to provide a convenient way + * to handle the ap info needed by the qact function. + */ +union ap_qact_ap_info { + unsigned long val; + struct { + unsigned int : 3; + unsigned int mode : 3; + unsigned int : 26; + unsigned int cat : 8; + unsigned int : 8; + unsigned char ver[2]; + }; +}; + +/** + * ap_qact(): Query AP combatibility type. + * @qid: The AP queue number + * @apinfo: On input the info about the AP queue. On output the + * alternate AP queue info provided by the qact function + * in GR2 is stored in. + * + * Returns AP queue status. Check response_code field for failures. + */ +static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, + union ap_qact_ap_info *apinfo) +{ + register unsigned long reg0 asm ("0") = qid | (5UL << 24) + | ((ifbit & 0x01) << 22); + register unsigned long reg1_in asm ("1") = apinfo->val; + register struct ap_queue_status reg1_out asm ("1"); + register unsigned long reg2 asm ("2") = 0; + + asm volatile( + ".long 0xb2af0000" /* PQAP(QACT) */ + : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) + : : "cc"); + apinfo->val = reg2; + return reg1_out; +} + /** * ap_nqap(): Send message to adjunct processor queue. * @qid: The AP queue number diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5f0be2040272..8b5658b0bec3 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -176,6 +176,18 @@ static int ap_apft_available(void) return test_facility(15); } +/* + * ap_qact_available(): Test if the PQAP(QACT) subfunction is available. + * + * Returns 1 if the QACT subfunction is available. + */ +static inline int ap_qact_available(void) +{ + if (ap_configuration) + return ap_configuration->qact; + return 0; +} + /** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number @@ -988,6 +1000,47 @@ static int ap_select_domain(void) } /* + * This function checks the type and returns either 0 for not + * supported or the highest compatible type value (which may + * include the input type value). + */ +static int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) +{ + int comp_type = 0; + + /* < CEX2A is not supported */ + if (rawtype < AP_DEVICE_TYPE_CEX2A) + return 0; + /* up to CEX6 known and fully supported */ + if (rawtype <= AP_DEVICE_TYPE_CEX6) + return rawtype; + /* + * unknown new type > CEX6, check for compatibility + * to the highest known and supported type which is + * currently CEX6 with the help of the QACT function. + */ + if (ap_qact_available()) { + struct ap_queue_status status; + union ap_qact_ap_info apinfo = {0}; + + apinfo.mode = (func >> 26) & 0x07; + apinfo.cat = AP_DEVICE_TYPE_CEX6; + status = ap_qact(qid, 0, &apinfo); + if (status.response_code == AP_RESPONSE_NORMAL + && apinfo.cat >= AP_DEVICE_TYPE_CEX2A + && apinfo.cat <= AP_DEVICE_TYPE_CEX6) + comp_type = apinfo.cat; + } + if (!comp_type) + AP_DBF(DBF_WARN, "queue=%02x.%04x unable to map type %d\n", + AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype); + else if (comp_type != rawtype) + AP_DBF(DBF_INFO, "queue=%02x.%04x map type %d to %d\n", + AP_QID_CARD(qid), AP_QID_QUEUE(qid), rawtype, comp_type); + return comp_type; +} + +/* * helper function to be used with bus_find_dev * matches for the card device with the given id */ @@ -1014,8 +1067,8 @@ static void ap_scan_bus(struct work_struct *unused) struct ap_card *ac; struct device *dev; ap_qid_t qid; - int depth = 0, type = 0; - unsigned int functions = 0; + int comp_type, depth = 0, type = 0; + unsigned int func = 0; int rc, id, dom, borked, domains, defdomdevs = 0; AP_DBF(DBF_DEBUG, "ap_scan_bus running\n"); @@ -1066,12 +1119,12 @@ static void ap_scan_bus(struct work_struct *unused) } continue; } - rc = ap_query_queue(qid, &depth, &type, &functions); + rc = ap_query_queue(qid, &depth, &type, &func); if (dev) { spin_lock_bh(&aq->lock); if (rc == -ENODEV || /* adapter reconfiguration */ - (ac && ac->functions != functions)) + (ac && ac->functions != func)) aq->state = AP_STATE_BORKED; borked = aq->state == AP_STATE_BORKED; spin_unlock_bh(&aq->lock); @@ -1087,11 +1140,14 @@ static void ap_scan_bus(struct work_struct *unused) } if (rc) continue; - /* new queue device needed */ + /* a new queue device is needed, check out comp type */ + comp_type = ap_get_compatible_type(qid, type, func); + if (!comp_type) + continue; + /* maybe a card device needs to be created first */ if (!ac) { - /* but first create the card device */ - ac = ap_card_create(id, depth, - type, functions); + ac = ap_card_create(id, depth, type, + comp_type, func); if (!ac) continue; ac->ap_dev.device.bus = &ap_bus_type; @@ -1109,7 +1165,7 @@ static void ap_scan_bus(struct work_struct *unused) get_device(&ac->ap_dev.device); } /* now create the new queue device */ - aq = ap_queue_create(qid, type); + aq = ap_queue_create(qid, comp_type); if (!aq) continue; aq->card = ac; diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 754cf2223cfb..3a0e19d87e7c 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -250,8 +250,8 @@ void ap_queue_remove(struct ap_queue *aq); void ap_queue_suspend(struct ap_device *ap_dev); void ap_queue_resume(struct ap_device *ap_dev); -struct ap_card *ap_card_create(int id, int queue_depth, int device_type, - unsigned int device_functions); +struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type, + int comp_device_type, unsigned int functions); int ap_module_init(void); void ap_module_exit(void); diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 8a31c9e95430..97a8cf578116 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -171,22 +171,20 @@ static void ap_card_device_release(struct device *dev) kfree(ac); } -struct ap_card *ap_card_create(int id, int queue_depth, int device_type, - unsigned int functions) +struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, + int comp_type, unsigned int functions) { struct ap_card *ac; ac = kzalloc(sizeof(*ac), GFP_KERNEL); if (!ac) return NULL; + INIT_LIST_HEAD(&ac->list); INIT_LIST_HEAD(&ac->queues); ac->ap_dev.device.release = ap_card_device_release; ac->ap_dev.device.type = &ap_card_type; - ac->ap_dev.device_type = device_type; - /* CEX6 toleration: map to CEX5 */ - if (device_type == AP_DEVICE_TYPE_CEX6) - ac->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; - ac->raw_hwtype = device_type; + ac->ap_dev.device_type = comp_type; + ac->raw_hwtype = raw_type; ac->queue_depth = queue_depth; ac->functions = functions; ac->id = id; diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 6c8bd8ad6185..a550d40921e7 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -627,13 +627,11 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) aq->ap_dev.device.release = ap_queue_device_release; aq->ap_dev.device.type = &ap_queue_type; aq->ap_dev.device_type = device_type; - /* CEX6 toleration: map to CEX5 */ - if (device_type == AP_DEVICE_TYPE_CEX6) - aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; aq->qid = qid; aq->state = AP_STATE_RESET_START; aq->interrupt = AP_INTR_DISABLED; spin_lock_init(&aq->lock); + INIT_LIST_HEAD(&aq->list); INIT_LIST_HEAD(&aq->pendingq); INIT_LIST_HEAD(&aq->requestq); setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq); diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index f61fa47135a6..8dda5bb34a2f 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -125,10 +125,9 @@ static int alloc_and_prep_cprbmem(size_t paramblen, * allocate consecutive memory for request CPRB, request param * block, reply CPRB and reply param block */ - cprbmem = kmalloc(2 * cprbplusparamblen, GFP_KERNEL); + cprbmem = kzalloc(2 * cprbplusparamblen, GFP_KERNEL); if (!cprbmem) return -ENOMEM; - memset(cprbmem, 0, 2 * cprbplusparamblen); preqcblk = (struct CPRBX *) cprbmem; prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen); diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 6c94efd23eac..73541a798db7 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -76,6 +76,7 @@ struct ica_z90_status { #define ZCRYPT_CEX3A 8 #define ZCRYPT_CEX4 10 #define ZCRYPT_CEX5 11 +#define ZCRYPT_CEX6 12 /** * Large random numbers are pulled in 4096 byte chunks from the crypto cards diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 4e91163d70a6..e2eebc775a37 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -45,6 +45,8 @@ static struct ap_device_id zcrypt_cex4_card_ids[] = { .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, { .dev_type = AP_DEVICE_TYPE_CEX5, .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX6, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, { /* end of list */ }, }; @@ -55,6 +57,8 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = { .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, { .dev_type = AP_DEVICE_TYPE_CEX5, .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX6, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, { /* end of list */ }, }; @@ -72,17 +76,25 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY */ static const int CEX4A_SPEED_IDX[] = { - 5, 6, 59, 20, 115, 581, 0, 0}; + 14, 19, 249, 42, 228, 1458, 0, 0}; static const int CEX5A_SPEED_IDX[] = { - 3, 3, 6, 8, 32, 218, 0, 0}; + 8, 9, 20, 18, 66, 458, 0, 0}; + static const int CEX6A_SPEED_IDX[] = { + 6, 9, 20, 17, 65, 438, 0, 0}; + static const int CEX4C_SPEED_IDX[] = { - 24, 25, 82, 41, 138, 1111, 79, 8}; + 59, 69, 308, 83, 278, 2204, 209, 40}; static const int CEX5C_SPEED_IDX[] = { - 10, 14, 23, 17, 45, 242, 63, 4}; + 24, 31, 50, 37, 90, 479, 27, 10}; + static const int CEX6C_SPEED_IDX[] = { + 16, 20, 32, 27, 77, 455, 23, 9}; + static const int CEX4P_SPEED_IDX[] = { - 142, 198, 1852, 203, 331, 1563, 0, 8}; + 224, 313, 3560, 359, 605, 2827, 0, 50}; static const int CEX5P_SPEED_IDX[] = { - 49, 67, 131, 52, 85, 287, 0, 4}; + 63, 84, 156, 83, 142, 533, 0, 10}; + static const int CEX6P_SPEED_IDX[] = { + 55, 70, 121, 73, 129, 522, 0, 9}; struct ap_card *ac = to_ap_card(&ap_dev->device); struct zcrypt_card *zc; @@ -99,11 +111,16 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->user_space_type = ZCRYPT_CEX4; memcpy(zc->speed_rating, CEX4A_SPEED_IDX, sizeof(CEX4A_SPEED_IDX)); - } else { + } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) { zc->type_string = "CEX5A"; zc->user_space_type = ZCRYPT_CEX5; memcpy(zc->speed_rating, CEX5A_SPEED_IDX, sizeof(CEX5A_SPEED_IDX)); + } else { + zc->type_string = "CEX6A"; + zc->user_space_type = ZCRYPT_CEX6; + memcpy(zc->speed_rating, CEX6A_SPEED_IDX, + sizeof(CEX6A_SPEED_IDX)); } zc->min_mod_size = CEX4A_MIN_MOD_SIZE; if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && @@ -125,7 +142,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->user_space_type = ZCRYPT_CEX3C; memcpy(zc->speed_rating, CEX4C_SPEED_IDX, sizeof(CEX4C_SPEED_IDX)); - } else { + } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) { zc->type_string = "CEX5C"; /* wrong user space type, must be CEX5 * just keep it for cca compatibility @@ -133,6 +150,14 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->user_space_type = ZCRYPT_CEX3C; memcpy(zc->speed_rating, CEX5C_SPEED_IDX, sizeof(CEX5C_SPEED_IDX)); + } else { + zc->type_string = "CEX6C"; + /* wrong user space type, must be CEX6 + * just keep it for cca compatibility + */ + zc->user_space_type = ZCRYPT_CEX3C; + memcpy(zc->speed_rating, CEX6C_SPEED_IDX, + sizeof(CEX6C_SPEED_IDX)); } zc->min_mod_size = CEX4C_MIN_MOD_SIZE; zc->max_mod_size = CEX4C_MAX_MOD_SIZE; @@ -143,11 +168,16 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) zc->user_space_type = ZCRYPT_CEX4; memcpy(zc->speed_rating, CEX4P_SPEED_IDX, sizeof(CEX4P_SPEED_IDX)); - } else { + } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) { zc->type_string = "CEX5P"; zc->user_space_type = ZCRYPT_CEX5; memcpy(zc->speed_rating, CEX5P_SPEED_IDX, sizeof(CEX5P_SPEED_IDX)); + } else { + zc->type_string = "CEX6P"; + zc->user_space_type = ZCRYPT_CEX6; + memcpy(zc->speed_rating, CEX6P_SPEED_IDX, + sizeof(CEX6P_SPEED_IDX)); } zc->min_mod_size = CEX4C_MIN_MOD_SIZE; zc->max_mod_size = CEX4C_MAX_MOD_SIZE; diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 6dd5d7c58dd0..db5bde47dfb0 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -240,8 +240,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, mod = meb2->modulus + sizeof(meb2->modulus) - mod_len; exp = meb2->exponent + sizeof(meb2->exponent) - mod_len; inp = meb2->message + sizeof(meb2->message) - mod_len; - } else { - /* mod_len > 256 = 4096 bit RSA Key */ + } else if (mod_len <= 512) { struct type50_meb3_msg *meb3 = ap_msg->message; memset(meb3, 0, sizeof(*meb3)); ap_msg->length = sizeof(*meb3); @@ -251,7 +250,8 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, mod = meb3->modulus + sizeof(meb3->modulus) - mod_len; exp = meb3->exponent + sizeof(meb3->exponent) - mod_len; inp = meb3->message + sizeof(meb3->message) - mod_len; - } + } else + return -EINVAL; if (copy_from_user(mod, mex->n_modulus, mod_len) || copy_from_user(exp, mex->b_key, mod_len) || diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index afd20cee7ea0..785620d30504 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -474,7 +474,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; *dom = (unsigned short *)&msg->cprbx.domain; - if (memcmp(function_code, "US", 2) == 0) + if (memcmp(function_code, "US", 2) == 0 + || memcmp(function_code, "AU", 2) == 0) ap_msg->special = 1; else ap_msg->special = 0; diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 26363e0816fe..be9f17218531 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1761,6 +1761,7 @@ static struct ccwgroup_driver ctcm_group_driver = { .owner = THIS_MODULE, .name = CTC_DRIVER_NAME, }, + .ccw_driver = &ctcm_ccw_driver, .setup = ctcm_probe_device, .remove = ctcm_remove_device, .set_online = ctcm_new_device, diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index d01b5c2a7760..0bf7b7356f10 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -2396,6 +2396,7 @@ static struct ccwgroup_driver lcs_group_driver = { .owner = THIS_MODULE, .name = "lcs", }, + .ccw_driver = &lcs_ccw_driver, .setup = lcs_probe_device, .remove = lcs_remove_device, .set_online = lcs_new_device, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index bae7440abc01..61cf3e9c0acb 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -5875,6 +5875,7 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { .owner = THIS_MODULE, .name = "qeth", }, + .ccw_driver = &qeth_ccw_driver, .setup = qeth_core_probe_device, .remove = qeth_core_remove_device, .set_online = qeth_core_set_online, diff --git a/drivers/s390/virtio/Makefile b/drivers/s390/virtio/Makefile index df40692a9011..f68af1f317f1 100644 --- a/drivers/s390/virtio/Makefile +++ b/drivers/s390/virtio/Makefile @@ -6,8 +6,4 @@ # it under the terms of the GNU General Public License (version 2 only) # as published by the Free Software Foundation. -s390-virtio-objs := virtio_ccw.o -ifdef CONFIG_S390_GUEST_OLD_TRANSPORT -s390-virtio-objs += kvm_virtio.o -endif -obj-$(CONFIG_S390_GUEST) += $(s390-virtio-objs) +obj-$(CONFIG_S390_GUEST) += virtio_ccw.o diff --git a/drivers/s390/virtio/kvm_virtio.c b/drivers/s390/virtio/kvm_virtio.c deleted file mode 100644 index a99d09a11f05..000000000000 --- a/drivers/s390/virtio/kvm_virtio.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * virtio for kvm on s390 - * - * Copyright IBM Corp. 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (version 2 only) - * as published by the Free Software Foundation. - * - * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> - */ - -#include <linux/kernel_stat.h> -#include <linux/init.h> -#include <linux/bootmem.h> -#include <linux/err.h> -#include <linux/virtio.h> -#include <linux/virtio_config.h> -#include <linux/slab.h> -#include <linux/virtio_console.h> -#include <linux/interrupt.h> -#include <linux/virtio_ring.h> -#include <linux/export.h> -#include <linux/pfn.h> -#include <asm/io.h> -#include <asm/kvm_para.h> -#include <asm/kvm_virtio.h> -#include <asm/sclp.h> -#include <asm/setup.h> -#include <asm/irq.h> - -#define VIRTIO_SUBCODE_64 0x0D00 - -/* - * The pointer to our (page) of device descriptions. - */ -static void *kvm_devices; -static struct work_struct hotplug_work; - -struct kvm_device { - struct virtio_device vdev; - struct kvm_device_desc *desc; -}; - -#define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev) - -/* - * memory layout: - * - kvm_device_descriptor - * struct kvm_device_desc - * - configuration - * struct kvm_vqconfig - * - feature bits - * - config space - */ -static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc) -{ - return (struct kvm_vqconfig *)(desc + 1); -} - -static u8 *kvm_vq_features(const struct kvm_device_desc *desc) -{ - return (u8 *)(kvm_vq_config(desc) + desc->num_vq); -} - -static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc) -{ - return kvm_vq_features(desc) + desc->feature_len * 2; -} - -/* - * The total size of the config page used by this device (incl. desc) - */ -static unsigned desc_size(const struct kvm_device_desc *desc) -{ - return sizeof(*desc) - + desc->num_vq * sizeof(struct kvm_vqconfig) - + desc->feature_len * 2 - + desc->config_len; -} - -/* This gets the device's feature bits. */ -static u64 kvm_get_features(struct virtio_device *vdev) -{ - unsigned int i; - u32 features = 0; - struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; - u8 *in_features = kvm_vq_features(desc); - - for (i = 0; i < min(desc->feature_len * 8, 32); i++) - if (in_features[i / 8] & (1 << (i % 8))) - features |= (1 << i); - return features; -} - -static int kvm_finalize_features(struct virtio_device *vdev) -{ - unsigned int i, bits; - struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; - /* Second half of bitmap is features we accept. */ - u8 *out_features = kvm_vq_features(desc) + desc->feature_len; - - /* Give virtio_ring a chance to accept features. */ - vring_transport_features(vdev); - - /* Make sure we don't have any features > 32 bits! */ - BUG_ON((u32)vdev->features != vdev->features); - - memset(out_features, 0, desc->feature_len); - bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8; - for (i = 0; i < bits; i++) { - if (__virtio_test_bit(vdev, i)) - out_features[i / 8] |= (1 << (i % 8)); - } - - return 0; -} - -/* - * Reading and writing elements in config space - */ -static void kvm_get(struct virtio_device *vdev, unsigned int offset, - void *buf, unsigned len) -{ - struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; - - BUG_ON(offset + len > desc->config_len); - memcpy(buf, kvm_vq_configspace(desc) + offset, len); -} - -static void kvm_set(struct virtio_device *vdev, unsigned int offset, - const void *buf, unsigned len) -{ - struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; - - BUG_ON(offset + len > desc->config_len); - memcpy(kvm_vq_configspace(desc) + offset, buf, len); -} - -/* - * The operations to get and set the status word just access - * the status field of the device descriptor. set_status will also - * make a hypercall to the host, to tell about status changes - */ -static u8 kvm_get_status(struct virtio_device *vdev) -{ - return to_kvmdev(vdev)->desc->status; -} - -static void kvm_set_status(struct virtio_device *vdev, u8 status) -{ - BUG_ON(!status); - to_kvmdev(vdev)->desc->status = status; - kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS, - (unsigned long) to_kvmdev(vdev)->desc); -} - -/* - * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the - * descriptor address. The Host will zero the status and all the - * features. - */ -static void kvm_reset(struct virtio_device *vdev) -{ - kvm_hypercall1(KVM_S390_VIRTIO_RESET, - (unsigned long) to_kvmdev(vdev)->desc); -} - -/* - * When the virtio_ring code wants to notify the Host, it calls us here and we - * make a hypercall. We hand the address of the virtqueue so the Host - * knows which virtqueue we're talking about. - */ -static bool kvm_notify(struct virtqueue *vq) -{ - long rc; - struct kvm_vqconfig *config = vq->priv; - - rc = kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address); - if (rc < 0) - return false; - return true; -} - -/* - * This routine finds the first virtqueue described in the configuration of - * this device and sets it up. - */ -static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, - unsigned index, - void (*callback)(struct virtqueue *vq), - const char *name, bool ctx) -{ - struct kvm_device *kdev = to_kvmdev(vdev); - struct kvm_vqconfig *config; - struct virtqueue *vq; - int err; - - if (index >= kdev->desc->num_vq) - return ERR_PTR(-ENOENT); - - if (!name) - return NULL; - - config = kvm_vq_config(kdev->desc)+index; - - err = vmem_add_mapping(config->address, - vring_size(config->num, - KVM_S390_VIRTIO_RING_ALIGN)); - if (err) - goto out; - - vq = vring_new_virtqueue(index, config->num, KVM_S390_VIRTIO_RING_ALIGN, - vdev, true, ctx, (void *) config->address, - kvm_notify, callback, name); - if (!vq) { - err = -ENOMEM; - goto unmap; - } - - /* - * register a callback token - * The host will sent this via the external interrupt parameter - */ - config->token = (u64) vq; - - vq->priv = config; - return vq; -unmap: - vmem_remove_mapping(config->address, - vring_size(config->num, - KVM_S390_VIRTIO_RING_ALIGN)); -out: - return ERR_PTR(err); -} - -static void kvm_del_vq(struct virtqueue *vq) -{ - struct kvm_vqconfig *config = vq->priv; - - vring_del_virtqueue(vq); - vmem_remove_mapping(config->address, - vring_size(config->num, - KVM_S390_VIRTIO_RING_ALIGN)); -} - -static void kvm_del_vqs(struct virtio_device *vdev) -{ - struct virtqueue *vq, *n; - - list_for_each_entry_safe(vq, n, &vdev->vqs, list) - kvm_del_vq(vq); -} - -static int kvm_find_vqs(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[], - const bool *ctx, - struct irq_affinity *desc) -{ - struct kvm_device *kdev = to_kvmdev(vdev); - int i; - - /* We must have this many virtqueues. */ - if (nvqs > kdev->desc->num_vq) - return -ENOENT; - - for (i = 0; i < nvqs; ++i) { - vqs[i] = kvm_find_vq(vdev, i, callbacks[i], names[i], - ctx ? ctx[i] : false); - if (IS_ERR(vqs[i])) - goto error; - } - return 0; - -error: - kvm_del_vqs(vdev); - return PTR_ERR(vqs[i]); -} - -static const char *kvm_bus_name(struct virtio_device *vdev) -{ - return ""; -} - -/* - * The config ops structure as defined by virtio config - */ -static const struct virtio_config_ops kvm_vq_configspace_ops = { - .get_features = kvm_get_features, - .finalize_features = kvm_finalize_features, - .get = kvm_get, - .set = kvm_set, - .get_status = kvm_get_status, - .set_status = kvm_set_status, - .reset = kvm_reset, - .find_vqs = kvm_find_vqs, - .del_vqs = kvm_del_vqs, - .bus_name = kvm_bus_name, -}; - -/* - * The root device for the kvm virtio devices. - * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2. - */ -static struct device *kvm_root; - -/* - * adds a new device and register it with virtio - * appropriate drivers are loaded by the device model - */ -static void add_kvm_device(struct kvm_device_desc *d, unsigned int offset) -{ - struct kvm_device *kdev; - - kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); - if (!kdev) { - printk(KERN_EMERG "Cannot allocate kvm dev %u type %u\n", - offset, d->type); - return; - } - - kdev->vdev.dev.parent = kvm_root; - kdev->vdev.id.device = d->type; - kdev->vdev.config = &kvm_vq_configspace_ops; - kdev->desc = d; - - if (register_virtio_device(&kdev->vdev) != 0) { - printk(KERN_ERR "Failed to register kvm device %u type %u\n", - offset, d->type); - kfree(kdev); - } -} - -/* - * scan_devices() simply iterates through the device page. - * The type 0 is reserved to mean "end of devices". - */ -static void scan_devices(void) -{ - unsigned int i; - struct kvm_device_desc *d; - - for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { - d = kvm_devices + i; - - if (d->type == 0) - break; - - add_kvm_device(d, i); - } -} - -/* - * match for a kvm device with a specific desc pointer - */ -static int match_desc(struct device *dev, void *data) -{ - struct virtio_device *vdev = dev_to_virtio(dev); - struct kvm_device *kdev = to_kvmdev(vdev); - - return kdev->desc == data; -} - -/* - * hotplug_device tries to find changes in the device page. - */ -static void hotplug_devices(struct work_struct *dummy) -{ - unsigned int i; - struct kvm_device_desc *d; - struct device *dev; - - for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { - d = kvm_devices + i; - - /* end of list */ - if (d->type == 0) - break; - - /* device already exists */ - dev = device_find_child(kvm_root, d, match_desc); - if (dev) { - /* XXX check for hotplug remove */ - put_device(dev); - continue; - } - - /* new device */ - printk(KERN_INFO "Adding new virtio device %p\n", d); - add_kvm_device(d, i); - } -} - -/* - * we emulate the request_irq behaviour on top of s390 extints - */ -static void kvm_extint_handler(struct ext_code ext_code, - unsigned int param32, unsigned long param64) -{ - struct virtqueue *vq; - u32 param; - - if ((ext_code.subcode & 0xff00) != VIRTIO_SUBCODE_64) - return; - inc_irq_stat(IRQEXT_VRT); - - /* The LSB might be overloaded, we have to mask it */ - vq = (struct virtqueue *)(param64 & ~1UL); - - /* We use ext_params to decide what this interrupt means */ - param = param32 & VIRTIO_PARAM_MASK; - - switch (param) { - case VIRTIO_PARAM_CONFIG_CHANGED: - virtio_config_changed(vq->vdev); - break; - case VIRTIO_PARAM_DEV_ADD: - schedule_work(&hotplug_work); - break; - case VIRTIO_PARAM_VRING_INTERRUPT: - default: - vring_interrupt(0, vq); - break; - } -} - -/* - * For s390-virtio, we expect a page above main storage containing - * the virtio configuration. Try to actually load from this area - * in order to figure out if the host provides this page. - */ -static int __init test_devices_support(unsigned long addr) -{ - int ret = -EIO; - - asm volatile( - "0: lura 0,%1\n" - "1: xgr %0,%0\n" - "2:\n" - EX_TABLE(0b,2b) - EX_TABLE(1b,2b) - : "+d" (ret) - : "a" (addr) - : "0", "cc"); - return ret; -} -/* - * Init function for virtio - * devices are in a single page above top of "normal" + standby mem - */ -static int __init kvm_devices_init(void) -{ - int rc; - unsigned long total_memory_size = sclp.rzm * sclp.rnmax; - - if (!MACHINE_IS_KVM) - return -ENODEV; - - if (test_devices_support(total_memory_size) < 0) - return -ENODEV; - - pr_warn("The s390-virtio transport is deprecated. Please switch to a modern host providing virtio-ccw.\n"); - - rc = vmem_add_mapping(total_memory_size, PAGE_SIZE); - if (rc) - return rc; - - kvm_devices = (void *) total_memory_size; - - kvm_root = root_device_register("kvm_s390"); - if (IS_ERR(kvm_root)) { - rc = PTR_ERR(kvm_root); - printk(KERN_ERR "Could not register kvm_s390 root device"); - vmem_remove_mapping(total_memory_size, PAGE_SIZE); - return rc; - } - - INIT_WORK(&hotplug_work, hotplug_devices); - - irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL); - register_external_irq(EXT_IRQ_CP_SERVICE, kvm_extint_handler); - - scan_devices(); - return 0; -} - -/* code for early console output with virtio_console */ -static int early_put_chars(u32 vtermno, const char *buf, int count) -{ - char scratch[17]; - unsigned int len = count; - - if (len > sizeof(scratch) - 1) - len = sizeof(scratch) - 1; - scratch[len] = '\0'; - memcpy(scratch, buf, len); - kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch)); - return len; -} - -static int __init s390_virtio_console_init(void) -{ - if (sclp.has_vt220 || sclp.has_linemode) - return -ENODEV; - return virtio_cons_early_init(early_put_chars); -} -console_initcall(s390_virtio_console_init); - - -/* - * We do this after core stuff, but before the drivers. - */ -postcore_initcall(kvm_devices_init); |