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) { |