diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-28 12:02:24 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-28 12:02:24 -0500 |
| commit | e770d73ceb93c235525cb9bbbf1374c9b61a0895 (patch) | |
| tree | ac72b64d1978fece984c8b5a27442acbef7f172c /drivers/tty | |
| parent | be86497152220677e3e5cb326519e19d727f8674 (diff) | |
| parent | 07be0382097027cde68d9268cc628741069b5762 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 patches from Martin Schwidefsky:
"A new binary interface to be able to query and modify the LPAR
scheduler weight and cap settings. Some improvements for the hvc
terminal over iucv and a couple of bux fixes"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/hypfs: add interface for diagnose 0x304
s390: wire up sys_sched_setattr/sys_sched_getattr
s390/uapi: fix struct statfs64 definition
s390/uaccess: remove dead extern declarations, make functions static
s390/uaccess: test if current->mm is set before walking page tables
s390/zfcpdump: make zfcpdump depend on 64BIT
s390/32bit: fix cmpxchg64
s390/xpram: don't modify module parameters
s390/zcrypt: remove zcrypt kmsg documentation again
s390/hvc_iucv: Automatically assign free HVC terminal devices
s390/hvc_iucv: Display connection details through device attributes
s390/hvc_iucv: fix sparse warning
s390/vmur: Link parent CCW device during UR device creation
Diffstat (limited to 'drivers/tty')
| -rw-r--r-- | drivers/tty/hvc/hvc_iucv.c | 103 |
1 files changed, 95 insertions, 8 deletions
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index db19a38c8c69..ea74460f3638 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c | |||
| @@ -77,6 +77,7 @@ struct hvc_iucv_private { | |||
| 77 | struct list_head tty_outqueue; /* outgoing IUCV messages */ | 77 | struct list_head tty_outqueue; /* outgoing IUCV messages */ |
| 78 | struct list_head tty_inqueue; /* incoming IUCV messages */ | 78 | struct list_head tty_inqueue; /* incoming IUCV messages */ |
| 79 | struct device *dev; /* device structure */ | 79 | struct device *dev; /* device structure */ |
| 80 | u8 info_path[16]; /* IUCV path info (dev attr) */ | ||
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| 82 | struct iucv_tty_buffer { | 83 | struct iucv_tty_buffer { |
| @@ -126,7 +127,7 @@ static struct iucv_handler hvc_iucv_handler = { | |||
| 126 | * This function returns the struct hvc_iucv_private instance that corresponds | 127 | * This function returns the struct hvc_iucv_private instance that corresponds |
| 127 | * to the HVC virtual terminal number specified as parameter @num. | 128 | * to the HVC virtual terminal number specified as parameter @num. |
| 128 | */ | 129 | */ |
| 129 | struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) | 130 | static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) |
| 130 | { | 131 | { |
| 131 | if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) | 132 | if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) |
| 132 | return NULL; | 133 | return NULL; |
| @@ -772,18 +773,37 @@ static int hvc_iucv_filter_connreq(u8 ipvmid[8]) | |||
| 772 | static int hvc_iucv_path_pending(struct iucv_path *path, | 773 | static int hvc_iucv_path_pending(struct iucv_path *path, |
| 773 | u8 ipvmid[8], u8 ipuser[16]) | 774 | u8 ipvmid[8], u8 ipuser[16]) |
| 774 | { | 775 | { |
| 775 | struct hvc_iucv_private *priv; | 776 | struct hvc_iucv_private *priv, *tmp; |
| 777 | u8 wildcard[9] = "lnxhvc "; | ||
| 778 | int i, rc, find_unused; | ||
| 776 | u8 nuser_data[16]; | 779 | u8 nuser_data[16]; |
| 777 | u8 vm_user_id[9]; | 780 | u8 vm_user_id[9]; |
| 778 | int i, rc; | ||
| 779 | 781 | ||
| 782 | ASCEBC(wildcard, sizeof(wildcard)); | ||
| 783 | find_unused = !memcmp(wildcard, ipuser, 8); | ||
| 784 | |||
| 785 | /* First, check if the pending path request is managed by this | ||
| 786 | * IUCV handler: | ||
| 787 | * - find a disconnected device if ipuser contains the wildcard | ||
| 788 | * - find the device that matches the terminal ID in ipuser | ||
| 789 | */ | ||
| 780 | priv = NULL; | 790 | priv = NULL; |
| 781 | for (i = 0; i < hvc_iucv_devices; i++) | 791 | for (i = 0; i < hvc_iucv_devices; i++) { |
| 782 | if (hvc_iucv_table[i] && | 792 | tmp = hvc_iucv_table[i]; |
| 783 | (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { | 793 | if (!tmp) |
| 784 | priv = hvc_iucv_table[i]; | 794 | continue; |
| 795 | |||
| 796 | if (find_unused) { | ||
| 797 | spin_lock(&tmp->lock); | ||
| 798 | if (tmp->iucv_state == IUCV_DISCONN) | ||
| 799 | priv = tmp; | ||
| 800 | spin_unlock(&tmp->lock); | ||
| 801 | |||
| 802 | } else if (!memcmp(tmp->srv_name, ipuser, 8)) | ||
| 803 | priv = tmp; | ||
| 804 | if (priv) | ||
| 785 | break; | 805 | break; |
| 786 | } | 806 | } |
| 787 | if (!priv) | 807 | if (!priv) |
| 788 | return -ENODEV; | 808 | return -ENODEV; |
| 789 | 809 | ||
| @@ -826,6 +846,10 @@ static int hvc_iucv_path_pending(struct iucv_path *path, | |||
| 826 | priv->path = path; | 846 | priv->path = path; |
| 827 | priv->iucv_state = IUCV_CONNECTED; | 847 | priv->iucv_state = IUCV_CONNECTED; |
| 828 | 848 | ||
| 849 | /* store path information */ | ||
| 850 | memcpy(priv->info_path, ipvmid, 8); | ||
| 851 | memcpy(priv->info_path + 8, ipuser + 8, 8); | ||
| 852 | |||
| 829 | /* flush buffered output data... */ | 853 | /* flush buffered output data... */ |
| 830 | schedule_delayed_work(&priv->sndbuf_work, 5); | 854 | schedule_delayed_work(&priv->sndbuf_work, 5); |
| 831 | 855 | ||
| @@ -960,6 +984,49 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev) | |||
| 960 | return 0; | 984 | return 0; |
| 961 | } | 985 | } |
| 962 | 986 | ||
| 987 | static ssize_t hvc_iucv_dev_termid_show(struct device *dev, | ||
| 988 | struct device_attribute *attr, | ||
| 989 | char *buf) | ||
| 990 | { | ||
| 991 | struct hvc_iucv_private *priv = dev_get_drvdata(dev); | ||
| 992 | size_t len; | ||
| 993 | |||
| 994 | len = sizeof(priv->srv_name); | ||
| 995 | memcpy(buf, priv->srv_name, len); | ||
| 996 | EBCASC(buf, len); | ||
| 997 | buf[len++] = '\n'; | ||
| 998 | return len; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | static ssize_t hvc_iucv_dev_state_show(struct device *dev, | ||
| 1002 | struct device_attribute *attr, | ||
| 1003 | char *buf) | ||
| 1004 | { | ||
| 1005 | struct hvc_iucv_private *priv = dev_get_drvdata(dev); | ||
| 1006 | return sprintf(buf, "%u:%u\n", priv->iucv_state, priv->tty_state); | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static ssize_t hvc_iucv_dev_peer_show(struct device *dev, | ||
| 1010 | struct device_attribute *attr, | ||
| 1011 | char *buf) | ||
| 1012 | { | ||
| 1013 | struct hvc_iucv_private *priv = dev_get_drvdata(dev); | ||
| 1014 | char vmid[9], ipuser[9]; | ||
| 1015 | |||
| 1016 | memset(vmid, 0, sizeof(vmid)); | ||
| 1017 | memset(ipuser, 0, sizeof(ipuser)); | ||
| 1018 | |||
| 1019 | spin_lock_bh(&priv->lock); | ||
| 1020 | if (priv->iucv_state == IUCV_CONNECTED) { | ||
| 1021 | memcpy(vmid, priv->info_path, 8); | ||
| 1022 | memcpy(ipuser, priv->info_path + 8, 8); | ||
| 1023 | } | ||
| 1024 | spin_unlock_bh(&priv->lock); | ||
| 1025 | EBCASC(ipuser, 8); | ||
| 1026 | |||
| 1027 | return sprintf(buf, "%s:%s\n", vmid, ipuser); | ||
| 1028 | } | ||
| 1029 | |||
| 963 | 1030 | ||
| 964 | /* HVC operations */ | 1031 | /* HVC operations */ |
| 965 | static const struct hv_ops hvc_iucv_ops = { | 1032 | static const struct hv_ops hvc_iucv_ops = { |
| @@ -985,6 +1052,25 @@ static struct device_driver hvc_iucv_driver = { | |||
| 985 | .pm = &hvc_iucv_pm_ops, | 1052 | .pm = &hvc_iucv_pm_ops, |
| 986 | }; | 1053 | }; |
| 987 | 1054 | ||
| 1055 | /* IUCV HVC device attributes */ | ||
| 1056 | static DEVICE_ATTR(termid, 0640, hvc_iucv_dev_termid_show, NULL); | ||
| 1057 | static DEVICE_ATTR(state, 0640, hvc_iucv_dev_state_show, NULL); | ||
| 1058 | static DEVICE_ATTR(peer, 0640, hvc_iucv_dev_peer_show, NULL); | ||
| 1059 | static struct attribute *hvc_iucv_dev_attrs[] = { | ||
| 1060 | &dev_attr_termid.attr, | ||
| 1061 | &dev_attr_state.attr, | ||
| 1062 | &dev_attr_peer.attr, | ||
| 1063 | NULL, | ||
| 1064 | }; | ||
| 1065 | static struct attribute_group hvc_iucv_dev_attr_group = { | ||
| 1066 | .attrs = hvc_iucv_dev_attrs, | ||
| 1067 | }; | ||
| 1068 | static const struct attribute_group *hvc_iucv_dev_attr_groups[] = { | ||
| 1069 | &hvc_iucv_dev_attr_group, | ||
| 1070 | NULL, | ||
| 1071 | }; | ||
| 1072 | |||
| 1073 | |||
| 988 | /** | 1074 | /** |
| 989 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance | 1075 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance |
| 990 | * @id: hvc_iucv_table index | 1076 | * @id: hvc_iucv_table index |
| @@ -1046,6 +1132,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) | |||
| 1046 | priv->dev->bus = &iucv_bus; | 1132 | priv->dev->bus = &iucv_bus; |
| 1047 | priv->dev->parent = iucv_root; | 1133 | priv->dev->parent = iucv_root; |
| 1048 | priv->dev->driver = &hvc_iucv_driver; | 1134 | priv->dev->driver = &hvc_iucv_driver; |
| 1135 | priv->dev->groups = hvc_iucv_dev_attr_groups; | ||
| 1049 | priv->dev->release = (void (*)(struct device *)) kfree; | 1136 | priv->dev->release = (void (*)(struct device *)) kfree; |
| 1050 | rc = device_register(priv->dev); | 1137 | rc = device_register(priv->dev); |
| 1051 | if (rc) { | 1138 | if (rc) { |
