diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-09 12:04:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-09 12:04:10 -0400 |
commit | becdce1c66b21ce1c0452e16127182ef692f47ba (patch) | |
tree | a37f26fbbc43fad56b12881f6d57dc4a0fdb8d98 /drivers | |
parent | f8cf2f16a7c95acce497bfafa90e7c6d8397d653 (diff) | |
parent | 92fa7a13c845c91f6a8177250474bbcab7fcf45e (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
- Improvements for the spectre defense:
* The spectre related code is consolidated to a single file
nospec-branch.c
* Automatic enable/disable for the spectre v2 defenses (expoline vs.
nobp)
* Syslog messages for specve v2 are added
* Enable CONFIG_GENERIC_CPU_VULNERABILITIES and define the attribute
functions for spectre v1 and v2
- Add helper macros for assembler alternatives and use them to shorten
the code in entry.S.
- Add support for persistent configuration data via the SCLP Store Data
interface. The H/W interface requires a page table that uses 4K pages
only, the code to setup such an address space is added as well.
- Enable virtio GPU emulation in QEMU. To do this the depends
statements for a few common Kconfig options are modified.
- Add support for format-3 channel path descriptors and add a binary
sysfs interface to export the associated utility strings.
- Add a sysfs attribute to control the IFCC handling in case of
constant channel errors.
- The vfio-ccw changes from Cornelia.
- Bug fixes and cleanups.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (40 commits)
s390/kvm: improve stack frame constants in entry.S
s390/lpp: use assembler alternatives for the LPP instruction
s390/entry.S: use assembler alternatives
s390: add assembler macros for CPU alternatives
s390: add sysfs attributes for spectre
s390: report spectre mitigation via syslog
s390: add automatic detection of the spectre defense
s390: move nobp parameter functions to nospec-branch.c
s390/cio: add util_string sysfs attribute
s390/chsc: query utility strings via fmt3 channel path descriptor
s390/cio: rename struct channel_path_desc
s390/cio: fix unbind of io_subchannel_driver
s390/qdio: split up CCQ handling for EQBS / SQBS
s390/qdio: don't retry EQBS after CCQ 96
s390/qdio: restrict buffer merging to eligible devices
s390/qdio: don't merge ERROR output buffers
s390/qdio: simplify math in get_*_buffer_frontier()
s390/decompressor: trim uncompressed image head during the build
s390/crypto: Fix kernel crash on aes_s390 module remove.
s390/defkeymap: fix global init to zero
...
Diffstat (limited to 'drivers')
26 files changed, 981 insertions, 239 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index b5692a284bd8..04143c08bd6e 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -3918,8 +3918,13 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device) | |||
3918 | cqr = refers; | 3918 | cqr = refers; |
3919 | } | 3919 | } |
3920 | 3920 | ||
3921 | if (cqr->block) | 3921 | /* |
3922 | list_del_init(&cqr->blocklist); | 3922 | * _dasd_requeue_request already checked for a valid |
3923 | * blockdevice, no need to check again | ||
3924 | * all erp requests (cqr->refers) have a cqr->block | ||
3925 | * pointer copy from the original cqr | ||
3926 | */ | ||
3927 | list_del_init(&cqr->blocklist); | ||
3923 | cqr->block->base->discipline->free_cp( | 3928 | cqr->block->base->discipline->free_cp( |
3924 | cqr, (struct request *) cqr->callback_data); | 3929 | cqr, (struct request *) cqr->callback_data); |
3925 | } | 3930 | } |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index ee14d8e45c97..ee73b0607e47 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
@@ -2214,15 +2214,28 @@ static void dasd_3990_erp_disable_path(struct dasd_device *device, __u8 lpum) | |||
2214 | { | 2214 | { |
2215 | int pos = pathmask_to_pos(lpum); | 2215 | int pos = pathmask_to_pos(lpum); |
2216 | 2216 | ||
2217 | if (!(device->features & DASD_FEATURE_PATH_AUTODISABLE)) { | ||
2218 | dev_err(&device->cdev->dev, | ||
2219 | "Path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n", | ||
2220 | device->path[pos].cssid, device->path[pos].chpid, lpum); | ||
2221 | goto out; | ||
2222 | } | ||
2223 | |||
2217 | /* no remaining path, cannot disable */ | 2224 | /* no remaining path, cannot disable */ |
2218 | if (!(dasd_path_get_opm(device) & ~lpum)) | 2225 | if (!(dasd_path_get_opm(device) & ~lpum)) { |
2219 | return; | 2226 | dev_err(&device->cdev->dev, |
2227 | "Last path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n", | ||
2228 | device->path[pos].cssid, device->path[pos].chpid, lpum); | ||
2229 | goto out; | ||
2230 | } | ||
2220 | 2231 | ||
2221 | dev_err(&device->cdev->dev, | 2232 | dev_err(&device->cdev->dev, |
2222 | "Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n", | 2233 | "Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n", |
2223 | device->path[pos].cssid, device->path[pos].chpid, lpum); | 2234 | device->path[pos].cssid, device->path[pos].chpid, lpum); |
2224 | dasd_path_remove_opm(device, lpum); | 2235 | dasd_path_remove_opm(device, lpum); |
2225 | dasd_path_add_ifccpm(device, lpum); | 2236 | dasd_path_add_ifccpm(device, lpum); |
2237 | |||
2238 | out: | ||
2226 | device->path[pos].errorclk = 0; | 2239 | device->path[pos].errorclk = 0; |
2227 | atomic_set(&device->path[pos].error_count, 0); | 2240 | atomic_set(&device->path[pos].error_count, 0); |
2228 | } | 2241 | } |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index e7cd28ff1984..b9ebb565ee2c 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -1550,9 +1550,49 @@ dasd_path_threshold_store(struct device *dev, struct device_attribute *attr, | |||
1550 | dasd_put_device(device); | 1550 | dasd_put_device(device); |
1551 | return count; | 1551 | return count; |
1552 | } | 1552 | } |
1553 | |||
1554 | static DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show, | 1553 | static DEVICE_ATTR(path_threshold, 0644, dasd_path_threshold_show, |
1555 | dasd_path_threshold_store); | 1554 | dasd_path_threshold_store); |
1555 | |||
1556 | /* | ||
1557 | * configure if path is disabled after IFCC/CCC error threshold is | ||
1558 | * exceeded | ||
1559 | */ | ||
1560 | static ssize_t | ||
1561 | dasd_path_autodisable_show(struct device *dev, | ||
1562 | struct device_attribute *attr, char *buf) | ||
1563 | { | ||
1564 | struct dasd_devmap *devmap; | ||
1565 | int flag; | ||
1566 | |||
1567 | devmap = dasd_find_busid(dev_name(dev)); | ||
1568 | if (!IS_ERR(devmap)) | ||
1569 | flag = (devmap->features & DASD_FEATURE_PATH_AUTODISABLE) != 0; | ||
1570 | else | ||
1571 | flag = (DASD_FEATURE_DEFAULT & | ||
1572 | DASD_FEATURE_PATH_AUTODISABLE) != 0; | ||
1573 | return snprintf(buf, PAGE_SIZE, flag ? "1\n" : "0\n"); | ||
1574 | } | ||
1575 | |||
1576 | static ssize_t | ||
1577 | dasd_path_autodisable_store(struct device *dev, | ||
1578 | struct device_attribute *attr, | ||
1579 | const char *buf, size_t count) | ||
1580 | { | ||
1581 | unsigned int val; | ||
1582 | int rc; | ||
1583 | |||
1584 | if (kstrtouint(buf, 0, &val) || val > 1) | ||
1585 | return -EINVAL; | ||
1586 | |||
1587 | rc = dasd_set_feature(to_ccwdev(dev), | ||
1588 | DASD_FEATURE_PATH_AUTODISABLE, val); | ||
1589 | |||
1590 | return rc ? : count; | ||
1591 | } | ||
1592 | |||
1593 | static DEVICE_ATTR(path_autodisable, 0644, | ||
1594 | dasd_path_autodisable_show, | ||
1595 | dasd_path_autodisable_store); | ||
1556 | /* | 1596 | /* |
1557 | * interval for IFCC/CCC checks | 1597 | * interval for IFCC/CCC checks |
1558 | * meaning time with no IFCC/CCC error before the error counter | 1598 | * meaning time with no IFCC/CCC error before the error counter |
@@ -1623,6 +1663,7 @@ static struct attribute * dasd_attrs[] = { | |||
1623 | &dev_attr_host_access_count.attr, | 1663 | &dev_attr_host_access_count.attr, |
1624 | &dev_attr_path_masks.attr, | 1664 | &dev_attr_path_masks.attr, |
1625 | &dev_attr_path_threshold.attr, | 1665 | &dev_attr_path_threshold.attr, |
1666 | &dev_attr_path_autodisable.attr, | ||
1626 | &dev_attr_path_interval.attr, | 1667 | &dev_attr_path_interval.attr, |
1627 | &dev_attr_path_reset.attr, | 1668 | &dev_attr_path_reset.attr, |
1628 | &dev_attr_hpf.attr, | 1669 | &dev_attr_hpf.attr, |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 29397a9dba68..be208e7adcb4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -214,24 +214,25 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head) | |||
214 | geo->head |= head; | 214 | geo->head |= head; |
215 | } | 215 | } |
216 | 216 | ||
217 | static int check_XRC(struct ccw1 *ccw, struct DE_eckd_data *data, | 217 | static int set_timestamp(struct ccw1 *ccw, struct DE_eckd_data *data, |
218 | struct dasd_device *device) | 218 | struct dasd_device *device) |
219 | { | 219 | { |
220 | struct dasd_eckd_private *private = device->private; | 220 | struct dasd_eckd_private *private = device->private; |
221 | int rc; | 221 | int rc; |
222 | 222 | ||
223 | if (!private->rdc_data.facilities.XRC_supported) | 223 | rc = get_phys_clock(&data->ep_sys_time); |
224 | /* | ||
225 | * Ignore return code if XRC is not supported or | ||
226 | * sync clock is switched off | ||
227 | */ | ||
228 | if ((rc && !private->rdc_data.facilities.XRC_supported) || | ||
229 | rc == -EOPNOTSUPP || rc == -EACCES) | ||
224 | return 0; | 230 | return 0; |
225 | 231 | ||
226 | /* switch on System Time Stamp - needed for XRC Support */ | 232 | /* switch on System Time Stamp - needed for XRC Support */ |
227 | data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ | 233 | data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ |
228 | data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ | 234 | data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ |
229 | 235 | ||
230 | rc = get_phys_clock(&data->ep_sys_time); | ||
231 | /* Ignore return code if sync clock is switched off. */ | ||
232 | if (rc == -EOPNOTSUPP || rc == -EACCES) | ||
233 | rc = 0; | ||
234 | |||
235 | if (ccw) { | 236 | if (ccw) { |
236 | ccw->count = sizeof(struct DE_eckd_data); | 237 | ccw->count = sizeof(struct DE_eckd_data); |
237 | ccw->flags |= CCW_FLAG_SLI; | 238 | ccw->flags |= CCW_FLAG_SLI; |
@@ -286,12 +287,12 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, | |||
286 | case DASD_ECKD_CCW_WRITE_KD_MT: | 287 | case DASD_ECKD_CCW_WRITE_KD_MT: |
287 | data->mask.perm = 0x02; | 288 | data->mask.perm = 0x02; |
288 | data->attributes.operation = private->attrib.operation; | 289 | data->attributes.operation = private->attrib.operation; |
289 | rc = check_XRC(ccw, data, device); | 290 | rc = set_timestamp(ccw, data, device); |
290 | break; | 291 | break; |
291 | case DASD_ECKD_CCW_WRITE_CKD: | 292 | case DASD_ECKD_CCW_WRITE_CKD: |
292 | case DASD_ECKD_CCW_WRITE_CKD_MT: | 293 | case DASD_ECKD_CCW_WRITE_CKD_MT: |
293 | data->attributes.operation = DASD_BYPASS_CACHE; | 294 | data->attributes.operation = DASD_BYPASS_CACHE; |
294 | rc = check_XRC(ccw, data, device); | 295 | rc = set_timestamp(ccw, data, device); |
295 | break; | 296 | break; |
296 | case DASD_ECKD_CCW_ERASE: | 297 | case DASD_ECKD_CCW_ERASE: |
297 | case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: | 298 | case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: |
@@ -299,7 +300,7 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, | |||
299 | data->mask.perm = 0x3; | 300 | data->mask.perm = 0x3; |
300 | data->mask.auth = 0x1; | 301 | data->mask.auth = 0x1; |
301 | data->attributes.operation = DASD_BYPASS_CACHE; | 302 | data->attributes.operation = DASD_BYPASS_CACHE; |
302 | rc = check_XRC(ccw, data, device); | 303 | rc = set_timestamp(ccw, data, device); |
303 | break; | 304 | break; |
304 | case DASD_ECKD_CCW_WRITE_FULL_TRACK: | 305 | case DASD_ECKD_CCW_WRITE_FULL_TRACK: |
305 | data->mask.perm = 0x03; | 306 | data->mask.perm = 0x03; |
@@ -310,7 +311,7 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, | |||
310 | data->mask.perm = 0x02; | 311 | data->mask.perm = 0x02; |
311 | data->attributes.operation = private->attrib.operation; | 312 | data->attributes.operation = private->attrib.operation; |
312 | data->blk_size = blksize; | 313 | data->blk_size = blksize; |
313 | rc = check_XRC(ccw, data, device); | 314 | rc = set_timestamp(ccw, data, device); |
314 | break; | 315 | break; |
315 | default: | 316 | default: |
316 | dev_err(&device->cdev->dev, | 317 | dev_err(&device->cdev->dev, |
@@ -993,7 +994,7 @@ static int dasd_eckd_read_conf(struct dasd_device *device) | |||
993 | struct dasd_eckd_private *private, path_private; | 994 | struct dasd_eckd_private *private, path_private; |
994 | struct dasd_uid *uid; | 995 | struct dasd_uid *uid; |
995 | char print_path_uid[60], print_device_uid[60]; | 996 | char print_path_uid[60], print_device_uid[60]; |
996 | struct channel_path_desc *chp_desc; | 997 | struct channel_path_desc_fmt0 *chp_desc; |
997 | struct subchannel_id sch_id; | 998 | struct subchannel_id sch_id; |
998 | 999 | ||
999 | private = device->private; | 1000 | private = device->private; |
@@ -3440,7 +3441,7 @@ static int prepare_itcw(struct itcw *itcw, | |||
3440 | dedata->mask.perm = 0x02; | 3441 | dedata->mask.perm = 0x02; |
3441 | dedata->attributes.operation = basepriv->attrib.operation; | 3442 | dedata->attributes.operation = basepriv->attrib.operation; |
3442 | dedata->blk_size = blksize; | 3443 | dedata->blk_size = blksize; |
3443 | rc = check_XRC(NULL, dedata, basedev); | 3444 | rc = set_timestamp(NULL, dedata, basedev); |
3444 | dedata->ga_extended |= 0x42; | 3445 | dedata->ga_extended |= 0x42; |
3445 | lredata->operation.orientation = 0x0; | 3446 | lredata->operation.orientation = 0x0; |
3446 | lredata->operation.operation = 0x3F; | 3447 | lredata->operation.operation = 0x3F; |
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index a2b33a22c82a..d049e2d74484 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile | |||
@@ -23,7 +23,7 @@ CFLAGS_REMOVE_sclp_early_core.o += $(CC_FLAGS_EXPOLINE) | |||
23 | 23 | ||
24 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ | 24 | obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ |
25 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ | 25 | sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o sclp_ctl.o \ |
26 | sclp_early.o sclp_early_core.o | 26 | sclp_early.o sclp_early_core.o sclp_sd.o |
27 | 27 | ||
28 | obj-$(CONFIG_TN3270) += raw3270.o | 28 | obj-$(CONFIG_TN3270) += raw3270.o |
29 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o | 29 | obj-$(CONFIG_TN3270_CONSOLE) += con3270.o |
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c index 98a5c459a1bf..60845d467a1b 100644 --- a/drivers/s390/char/defkeymap.c +++ b/drivers/s390/char/defkeymap.c | |||
@@ -9,7 +9,9 @@ | |||
9 | #include <linux/kbd_kern.h> | 9 | #include <linux/kbd_kern.h> |
10 | #include <linux/kbd_diacr.h> | 10 | #include <linux/kbd_diacr.h> |
11 | 11 | ||
12 | u_short plain_map[NR_KEYS] = { | 12 | #include "keyboard.h" |
13 | |||
14 | u_short ebc_plain_map[NR_KEYS] = { | ||
13 | 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, | 15 | 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, |
14 | 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, | 16 | 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, |
15 | 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, | 17 | 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, |
@@ -85,12 +87,12 @@ static u_short shift_ctrl_map[NR_KEYS] = { | |||
85 | 0xf20a, 0xf108, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, | 87 | 0xf20a, 0xf108, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, |
86 | }; | 88 | }; |
87 | 89 | ||
88 | ushort *key_maps[MAX_NR_KEYMAPS] = { | 90 | ushort *ebc_key_maps[MAX_NR_KEYMAPS] = { |
89 | plain_map, shift_map, NULL, NULL, | 91 | ebc_plain_map, shift_map, NULL, NULL, |
90 | ctrl_map, shift_ctrl_map, NULL, | 92 | ctrl_map, shift_ctrl_map, NULL, |
91 | }; | 93 | }; |
92 | 94 | ||
93 | unsigned int keymap_count = 4; | 95 | unsigned int ebc_keymap_count = 4; |
94 | 96 | ||
95 | 97 | ||
96 | /* | 98 | /* |
@@ -99,7 +101,7 @@ unsigned int keymap_count = 4; | |||
99 | * the default and allocate dynamically in chunks of 512 bytes. | 101 | * the default and allocate dynamically in chunks of 512 bytes. |
100 | */ | 102 | */ |
101 | 103 | ||
102 | char func_buf[] = { | 104 | char ebc_func_buf[] = { |
103 | '\033', '[', '[', 'A', 0, | 105 | '\033', '[', '[', 'A', 0, |
104 | '\033', '[', '[', 'B', 0, | 106 | '\033', '[', '[', 'B', 0, |
105 | '\033', '[', '[', 'C', 0, | 107 | '\033', '[', '[', 'C', 0, |
@@ -123,37 +125,37 @@ char func_buf[] = { | |||
123 | }; | 125 | }; |
124 | 126 | ||
125 | 127 | ||
126 | char *funcbufptr = func_buf; | 128 | char *ebc_funcbufptr = ebc_func_buf; |
127 | int funcbufsize = sizeof(func_buf); | 129 | int ebc_funcbufsize = sizeof(ebc_func_buf); |
128 | int funcbufleft = 0; /* space left */ | 130 | int ebc_funcbufleft; /* space left */ |
129 | 131 | ||
130 | char *func_table[MAX_NR_FUNC] = { | 132 | char *ebc_func_table[MAX_NR_FUNC] = { |
131 | func_buf + 0, | 133 | ebc_func_buf + 0, |
132 | func_buf + 5, | 134 | ebc_func_buf + 5, |
133 | func_buf + 10, | 135 | ebc_func_buf + 10, |
134 | func_buf + 15, | 136 | ebc_func_buf + 15, |
135 | func_buf + 20, | 137 | ebc_func_buf + 20, |
136 | func_buf + 25, | 138 | ebc_func_buf + 25, |
137 | func_buf + 31, | 139 | ebc_func_buf + 31, |
138 | func_buf + 37, | 140 | ebc_func_buf + 37, |
139 | func_buf + 43, | 141 | ebc_func_buf + 43, |
140 | func_buf + 49, | 142 | ebc_func_buf + 49, |
141 | func_buf + 55, | 143 | ebc_func_buf + 55, |
142 | func_buf + 61, | 144 | ebc_func_buf + 61, |
143 | func_buf + 67, | 145 | ebc_func_buf + 67, |
144 | func_buf + 73, | 146 | ebc_func_buf + 73, |
145 | func_buf + 79, | 147 | ebc_func_buf + 79, |
146 | func_buf + 85, | 148 | ebc_func_buf + 85, |
147 | func_buf + 91, | 149 | ebc_func_buf + 91, |
148 | func_buf + 97, | 150 | ebc_func_buf + 97, |
149 | func_buf + 103, | 151 | ebc_func_buf + 103, |
150 | func_buf + 109, | 152 | ebc_func_buf + 109, |
151 | NULL, | 153 | NULL, |
152 | }; | 154 | }; |
153 | 155 | ||
154 | struct kbdiacruc accent_table[MAX_DIACR] = { | 156 | struct kbdiacruc ebc_accent_table[MAX_DIACR] = { |
155 | {'^', 'c', 0003}, {'^', 'd', 0004}, | 157 | {'^', 'c', 0003}, {'^', 'd', 0004}, |
156 | {'^', 'z', 0032}, {'^', 0012, 0000}, | 158 | {'^', 'z', 0032}, {'^', 0012, 0000}, |
157 | }; | 159 | }; |
158 | 160 | ||
159 | unsigned int accent_table_size = 4; | 161 | unsigned int ebc_accent_table_size = 4; |
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 5b505fdaedec..db1fbf9b00b5 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c | |||
@@ -54,24 +54,24 @@ kbd_alloc(void) { | |||
54 | kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); | 54 | kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); |
55 | if (!kbd) | 55 | if (!kbd) |
56 | goto out; | 56 | goto out; |
57 | kbd->key_maps = kzalloc(sizeof(key_maps), GFP_KERNEL); | 57 | kbd->key_maps = kzalloc(sizeof(ebc_key_maps), GFP_KERNEL); |
58 | if (!kbd->key_maps) | 58 | if (!kbd->key_maps) |
59 | goto out_kbd; | 59 | goto out_kbd; |
60 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { | 60 | for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) { |
61 | if (key_maps[i]) { | 61 | if (ebc_key_maps[i]) { |
62 | kbd->key_maps[i] = kmemdup(key_maps[i], | 62 | kbd->key_maps[i] = kmemdup(ebc_key_maps[i], |
63 | sizeof(u_short) * NR_KEYS, | 63 | sizeof(u_short) * NR_KEYS, |
64 | GFP_KERNEL); | 64 | GFP_KERNEL); |
65 | if (!kbd->key_maps[i]) | 65 | if (!kbd->key_maps[i]) |
66 | goto out_maps; | 66 | goto out_maps; |
67 | } | 67 | } |
68 | } | 68 | } |
69 | kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); | 69 | kbd->func_table = kzalloc(sizeof(ebc_func_table), GFP_KERNEL); |
70 | if (!kbd->func_table) | 70 | if (!kbd->func_table) |
71 | goto out_maps; | 71 | goto out_maps; |
72 | for (i = 0; i < ARRAY_SIZE(func_table); i++) { | 72 | for (i = 0; i < ARRAY_SIZE(ebc_func_table); i++) { |
73 | if (func_table[i]) { | 73 | if (ebc_func_table[i]) { |
74 | kbd->func_table[i] = kstrdup(func_table[i], | 74 | kbd->func_table[i] = kstrdup(ebc_func_table[i], |
75 | GFP_KERNEL); | 75 | GFP_KERNEL); |
76 | if (!kbd->func_table[i]) | 76 | if (!kbd->func_table[i]) |
77 | goto out_func; | 77 | goto out_func; |
@@ -81,22 +81,22 @@ kbd_alloc(void) { | |||
81 | kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); | 81 | kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); |
82 | if (!kbd->fn_handler) | 82 | if (!kbd->fn_handler) |
83 | goto out_func; | 83 | goto out_func; |
84 | kbd->accent_table = kmemdup(accent_table, | 84 | kbd->accent_table = kmemdup(ebc_accent_table, |
85 | sizeof(struct kbdiacruc) * MAX_DIACR, | 85 | sizeof(struct kbdiacruc) * MAX_DIACR, |
86 | GFP_KERNEL); | 86 | GFP_KERNEL); |
87 | if (!kbd->accent_table) | 87 | if (!kbd->accent_table) |
88 | goto out_fn_handler; | 88 | goto out_fn_handler; |
89 | kbd->accent_table_size = accent_table_size; | 89 | kbd->accent_table_size = ebc_accent_table_size; |
90 | return kbd; | 90 | return kbd; |
91 | 91 | ||
92 | out_fn_handler: | 92 | out_fn_handler: |
93 | kfree(kbd->fn_handler); | 93 | kfree(kbd->fn_handler); |
94 | out_func: | 94 | out_func: |
95 | for (i = 0; i < ARRAY_SIZE(func_table); i++) | 95 | for (i = 0; i < ARRAY_SIZE(ebc_func_table); i++) |
96 | kfree(kbd->func_table[i]); | 96 | kfree(kbd->func_table[i]); |
97 | kfree(kbd->func_table); | 97 | kfree(kbd->func_table); |
98 | out_maps: | 98 | out_maps: |
99 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) | 99 | for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) |
100 | kfree(kbd->key_maps[i]); | 100 | kfree(kbd->key_maps[i]); |
101 | kfree(kbd->key_maps); | 101 | kfree(kbd->key_maps); |
102 | out_kbd: | 102 | out_kbd: |
@@ -112,10 +112,10 @@ kbd_free(struct kbd_data *kbd) | |||
112 | 112 | ||
113 | kfree(kbd->accent_table); | 113 | kfree(kbd->accent_table); |
114 | kfree(kbd->fn_handler); | 114 | kfree(kbd->fn_handler); |
115 | for (i = 0; i < ARRAY_SIZE(func_table); i++) | 115 | for (i = 0; i < ARRAY_SIZE(ebc_func_table); i++) |
116 | kfree(kbd->func_table[i]); | 116 | kfree(kbd->func_table[i]); |
117 | kfree(kbd->func_table); | 117 | kfree(kbd->func_table); |
118 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) | 118 | for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) |
119 | kfree(kbd->key_maps[i]); | 119 | kfree(kbd->key_maps[i]); |
120 | kfree(kbd->key_maps); | 120 | kfree(kbd->key_maps); |
121 | kfree(kbd); | 121 | kfree(kbd); |
@@ -131,7 +131,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) | |||
131 | int i, j, k; | 131 | int i, j, k; |
132 | 132 | ||
133 | memset(ascebc, 0x40, 256); | 133 | memset(ascebc, 0x40, 256); |
134 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { | 134 | for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) { |
135 | keymap = kbd->key_maps[i]; | 135 | keymap = kbd->key_maps[i]; |
136 | if (!keymap) | 136 | if (!keymap) |
137 | continue; | 137 | continue; |
@@ -158,7 +158,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) | |||
158 | int i, j, k; | 158 | int i, j, k; |
159 | 159 | ||
160 | memset(ebcasc, ' ', 256); | 160 | memset(ebcasc, ' ', 256); |
161 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { | 161 | for (i = 0; i < ARRAY_SIZE(ebc_key_maps); i++) { |
162 | keymap = kbd->key_maps[i]; | 162 | keymap = kbd->key_maps[i]; |
163 | if (!keymap) | 163 | if (!keymap) |
164 | continue; | 164 | continue; |
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h index a074d9711628..c467589c7f45 100644 --- a/drivers/s390/char/keyboard.h +++ b/drivers/s390/char/keyboard.h | |||
@@ -14,6 +14,17 @@ | |||
14 | 14 | ||
15 | struct kbd_data; | 15 | struct kbd_data; |
16 | 16 | ||
17 | extern int ebc_funcbufsize, ebc_funcbufleft; | ||
18 | extern char *ebc_func_table[MAX_NR_FUNC]; | ||
19 | extern char ebc_func_buf[]; | ||
20 | extern char *ebc_funcbufptr; | ||
21 | extern unsigned int ebc_keymap_count; | ||
22 | |||
23 | extern struct kbdiacruc ebc_accent_table[]; | ||
24 | extern unsigned int ebc_accent_table_size; | ||
25 | extern unsigned short *ebc_key_maps[MAX_NR_KEYMAPS]; | ||
26 | extern unsigned short ebc_plain_map[NR_KEYS]; | ||
27 | |||
17 | typedef void (fn_handler_fn)(struct kbd_data *); | 28 | typedef void (fn_handler_fn)(struct kbd_data *); |
18 | 29 | ||
19 | /* | 30 | /* |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index e4e2df7a478e..e9aa71cdfc44 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -417,7 +417,7 @@ sclp_dispatch_evbufs(struct sccb_header *sccb) | |||
417 | reg = NULL; | 417 | reg = NULL; |
418 | list_for_each(l, &sclp_reg_list) { | 418 | list_for_each(l, &sclp_reg_list) { |
419 | reg = list_entry(l, struct sclp_register, list); | 419 | reg = list_entry(l, struct sclp_register, list); |
420 | if (reg->receive_mask & (1 << (32 - evbuf->type))) | 420 | if (reg->receive_mask & SCLP_EVTYP_MASK(evbuf->type)) |
421 | break; | 421 | break; |
422 | else | 422 | else |
423 | reg = NULL; | 423 | reg = NULL; |
@@ -618,9 +618,12 @@ struct sclp_statechangebuf { | |||
618 | u16 _zeros : 12; | 618 | u16 _zeros : 12; |
619 | u16 mask_length; | 619 | u16 mask_length; |
620 | u64 sclp_active_facility_mask; | 620 | u64 sclp_active_facility_mask; |
621 | sccb_mask_t sclp_receive_mask; | 621 | u8 masks[2 * 1021 + 4]; /* variable length */ |
622 | sccb_mask_t sclp_send_mask; | 622 | /* |
623 | u32 read_data_function_mask; | 623 | * u8 sclp_receive_mask[mask_length]; |
624 | * u8 sclp_send_mask[mask_length]; | ||
625 | * u32 read_data_function_mask; | ||
626 | */ | ||
624 | } __attribute__((packed)); | 627 | } __attribute__((packed)); |
625 | 628 | ||
626 | 629 | ||
@@ -631,14 +634,14 @@ sclp_state_change_cb(struct evbuf_header *evbuf) | |||
631 | unsigned long flags; | 634 | unsigned long flags; |
632 | struct sclp_statechangebuf *scbuf; | 635 | struct sclp_statechangebuf *scbuf; |
633 | 636 | ||
637 | BUILD_BUG_ON(sizeof(struct sclp_statechangebuf) > PAGE_SIZE); | ||
638 | |||
634 | scbuf = (struct sclp_statechangebuf *) evbuf; | 639 | scbuf = (struct sclp_statechangebuf *) evbuf; |
635 | if (scbuf->mask_length != sizeof(sccb_mask_t)) | ||
636 | return; | ||
637 | spin_lock_irqsave(&sclp_lock, flags); | 640 | spin_lock_irqsave(&sclp_lock, flags); |
638 | if (scbuf->validity_sclp_receive_mask) | 641 | if (scbuf->validity_sclp_receive_mask) |
639 | sclp_receive_mask = scbuf->sclp_receive_mask; | 642 | sclp_receive_mask = sccb_get_recv_mask(scbuf); |
640 | if (scbuf->validity_sclp_send_mask) | 643 | if (scbuf->validity_sclp_send_mask) |
641 | sclp_send_mask = scbuf->sclp_send_mask; | 644 | sclp_send_mask = sccb_get_send_mask(scbuf); |
642 | spin_unlock_irqrestore(&sclp_lock, flags); | 645 | spin_unlock_irqrestore(&sclp_lock, flags); |
643 | if (scbuf->validity_sclp_active_facility_mask) | 646 | if (scbuf->validity_sclp_active_facility_mask) |
644 | sclp.facilities = scbuf->sclp_active_facility_mask; | 647 | sclp.facilities = scbuf->sclp_active_facility_mask; |
@@ -748,7 +751,7 @@ EXPORT_SYMBOL(sclp_remove_processed); | |||
748 | 751 | ||
749 | /* Prepare init mask request. Called while sclp_lock is locked. */ | 752 | /* Prepare init mask request. Called while sclp_lock is locked. */ |
750 | static inline void | 753 | static inline void |
751 | __sclp_make_init_req(u32 receive_mask, u32 send_mask) | 754 | __sclp_make_init_req(sccb_mask_t receive_mask, sccb_mask_t send_mask) |
752 | { | 755 | { |
753 | struct init_sccb *sccb; | 756 | struct init_sccb *sccb; |
754 | 757 | ||
@@ -761,12 +764,15 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask) | |||
761 | sclp_init_req.callback = NULL; | 764 | sclp_init_req.callback = NULL; |
762 | sclp_init_req.callback_data = NULL; | 765 | sclp_init_req.callback_data = NULL; |
763 | sclp_init_req.sccb = sccb; | 766 | sclp_init_req.sccb = sccb; |
764 | sccb->header.length = sizeof(struct init_sccb); | 767 | sccb->header.length = sizeof(*sccb); |
765 | sccb->mask_length = sizeof(sccb_mask_t); | 768 | if (sclp_mask_compat_mode) |
766 | sccb->receive_mask = receive_mask; | 769 | sccb->mask_length = SCLP_MASK_SIZE_COMPAT; |
767 | sccb->send_mask = send_mask; | 770 | else |
768 | sccb->sclp_receive_mask = 0; | 771 | sccb->mask_length = sizeof(sccb_mask_t); |
769 | sccb->sclp_send_mask = 0; | 772 | sccb_set_recv_mask(sccb, receive_mask); |
773 | sccb_set_send_mask(sccb, send_mask); | ||
774 | sccb_set_sclp_recv_mask(sccb, 0); | ||
775 | sccb_set_sclp_send_mask(sccb, 0); | ||
770 | } | 776 | } |
771 | 777 | ||
772 | /* Start init mask request. If calculate is non-zero, calculate the mask as | 778 | /* Start init mask request. If calculate is non-zero, calculate the mask as |
@@ -822,8 +828,8 @@ sclp_init_mask(int calculate) | |||
822 | sccb->header.response_code == 0x20) { | 828 | sccb->header.response_code == 0x20) { |
823 | /* Successful request */ | 829 | /* Successful request */ |
824 | if (calculate) { | 830 | if (calculate) { |
825 | sclp_receive_mask = sccb->sclp_receive_mask; | 831 | sclp_receive_mask = sccb_get_sclp_recv_mask(sccb); |
826 | sclp_send_mask = sccb->sclp_send_mask; | 832 | sclp_send_mask = sccb_get_sclp_send_mask(sccb); |
827 | } else { | 833 | } else { |
828 | sclp_receive_mask = 0; | 834 | sclp_receive_mask = 0; |
829 | sclp_send_mask = 0; | 835 | sclp_send_mask = 0; |
@@ -974,12 +980,18 @@ sclp_check_interface(void) | |||
974 | irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL); | 980 | irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL); |
975 | spin_lock_irqsave(&sclp_lock, flags); | 981 | spin_lock_irqsave(&sclp_lock, flags); |
976 | del_timer(&sclp_request_timer); | 982 | del_timer(&sclp_request_timer); |
977 | if (sclp_init_req.status == SCLP_REQ_DONE && | 983 | rc = -EBUSY; |
978 | sccb->header.response_code == 0x20) { | 984 | if (sclp_init_req.status == SCLP_REQ_DONE) { |
979 | rc = 0; | 985 | if (sccb->header.response_code == 0x20) { |
980 | break; | 986 | rc = 0; |
981 | } else | 987 | break; |
982 | rc = -EBUSY; | 988 | } else if (sccb->header.response_code == 0x74f0) { |
989 | if (!sclp_mask_compat_mode) { | ||
990 | sclp_mask_compat_mode = true; | ||
991 | retry = 0; | ||
992 | } | ||
993 | } | ||
994 | } | ||
983 | } | 995 | } |
984 | unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); | 996 | unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); |
985 | spin_unlock_irqrestore(&sclp_lock, flags); | 997 | spin_unlock_irqrestore(&sclp_lock, flags); |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index f41f6e2ca063..1fe4918088e7 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -18,7 +18,7 @@ | |||
18 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) | 18 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) |
19 | #define SCLP_CONSOLE_PAGES 6 | 19 | #define SCLP_CONSOLE_PAGES 6 |
20 | 20 | ||
21 | #define SCLP_EVTYP_MASK(T) (1U << (32 - (T))) | 21 | #define SCLP_EVTYP_MASK(T) (1UL << (sizeof(sccb_mask_t) * BITS_PER_BYTE - (T))) |
22 | 22 | ||
23 | #define EVTYP_OPCMD 0x01 | 23 | #define EVTYP_OPCMD 0x01 |
24 | #define EVTYP_MSG 0x02 | 24 | #define EVTYP_MSG 0x02 |
@@ -28,6 +28,7 @@ | |||
28 | #define EVTYP_PMSGCMD 0x09 | 28 | #define EVTYP_PMSGCMD 0x09 |
29 | #define EVTYP_ASYNC 0x0A | 29 | #define EVTYP_ASYNC 0x0A |
30 | #define EVTYP_CTLPROGIDENT 0x0B | 30 | #define EVTYP_CTLPROGIDENT 0x0B |
31 | #define EVTYP_STORE_DATA 0x0C | ||
31 | #define EVTYP_ERRNOTIFY 0x18 | 32 | #define EVTYP_ERRNOTIFY 0x18 |
32 | #define EVTYP_VT220MSG 0x1A | 33 | #define EVTYP_VT220MSG 0x1A |
33 | #define EVTYP_SDIAS 0x1C | 34 | #define EVTYP_SDIAS 0x1C |
@@ -42,6 +43,7 @@ | |||
42 | #define EVTYP_PMSGCMD_MASK SCLP_EVTYP_MASK(EVTYP_PMSGCMD) | 43 | #define EVTYP_PMSGCMD_MASK SCLP_EVTYP_MASK(EVTYP_PMSGCMD) |
43 | #define EVTYP_ASYNC_MASK SCLP_EVTYP_MASK(EVTYP_ASYNC) | 44 | #define EVTYP_ASYNC_MASK SCLP_EVTYP_MASK(EVTYP_ASYNC) |
44 | #define EVTYP_CTLPROGIDENT_MASK SCLP_EVTYP_MASK(EVTYP_CTLPROGIDENT) | 45 | #define EVTYP_CTLPROGIDENT_MASK SCLP_EVTYP_MASK(EVTYP_CTLPROGIDENT) |
46 | #define EVTYP_STORE_DATA_MASK SCLP_EVTYP_MASK(EVTYP_STORE_DATA) | ||
45 | #define EVTYP_ERRNOTIFY_MASK SCLP_EVTYP_MASK(EVTYP_ERRNOTIFY) | 47 | #define EVTYP_ERRNOTIFY_MASK SCLP_EVTYP_MASK(EVTYP_ERRNOTIFY) |
46 | #define EVTYP_VT220MSG_MASK SCLP_EVTYP_MASK(EVTYP_VT220MSG) | 48 | #define EVTYP_VT220MSG_MASK SCLP_EVTYP_MASK(EVTYP_VT220MSG) |
47 | #define EVTYP_SDIAS_MASK SCLP_EVTYP_MASK(EVTYP_SDIAS) | 49 | #define EVTYP_SDIAS_MASK SCLP_EVTYP_MASK(EVTYP_SDIAS) |
@@ -85,7 +87,7 @@ enum sclp_pm_event { | |||
85 | #define SCLP_PANIC_PRIO 1 | 87 | #define SCLP_PANIC_PRIO 1 |
86 | #define SCLP_PANIC_PRIO_CLIENT 0 | 88 | #define SCLP_PANIC_PRIO_CLIENT 0 |
87 | 89 | ||
88 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ | 90 | typedef u64 sccb_mask_t; |
89 | 91 | ||
90 | struct sccb_header { | 92 | struct sccb_header { |
91 | u16 length; | 93 | u16 length; |
@@ -98,12 +100,53 @@ struct init_sccb { | |||
98 | struct sccb_header header; | 100 | struct sccb_header header; |
99 | u16 _reserved; | 101 | u16 _reserved; |
100 | u16 mask_length; | 102 | u16 mask_length; |
101 | sccb_mask_t receive_mask; | 103 | u8 masks[4 * 1021]; /* variable length */ |
102 | sccb_mask_t send_mask; | 104 | /* |
103 | sccb_mask_t sclp_receive_mask; | 105 | * u8 receive_mask[mask_length]; |
104 | sccb_mask_t sclp_send_mask; | 106 | * u8 send_mask[mask_length]; |
107 | * u8 sclp_receive_mask[mask_length]; | ||
108 | * u8 sclp_send_mask[mask_length]; | ||
109 | */ | ||
105 | } __attribute__((packed)); | 110 | } __attribute__((packed)); |
106 | 111 | ||
112 | #define SCLP_MASK_SIZE_COMPAT 4 | ||
113 | |||
114 | static inline sccb_mask_t sccb_get_mask(u8 *masks, size_t len, int i) | ||
115 | { | ||
116 | sccb_mask_t res = 0; | ||
117 | |||
118 | memcpy(&res, masks + i * len, min(sizeof(res), len)); | ||
119 | return res; | ||
120 | } | ||
121 | |||
122 | static inline void sccb_set_mask(u8 *masks, size_t len, int i, sccb_mask_t val) | ||
123 | { | ||
124 | memset(masks + i * len, 0, len); | ||
125 | memcpy(masks + i * len, &val, min(sizeof(val), len)); | ||
126 | } | ||
127 | |||
128 | #define sccb_get_generic_mask(sccb, i) \ | ||
129 | ({ \ | ||
130 | __typeof__(sccb) __sccb = sccb; \ | ||
131 | \ | ||
132 | sccb_get_mask(__sccb->masks, __sccb->mask_length, i); \ | ||
133 | }) | ||
134 | #define sccb_get_recv_mask(sccb) sccb_get_generic_mask(sccb, 0) | ||
135 | #define sccb_get_send_mask(sccb) sccb_get_generic_mask(sccb, 1) | ||
136 | #define sccb_get_sclp_recv_mask(sccb) sccb_get_generic_mask(sccb, 2) | ||
137 | #define sccb_get_sclp_send_mask(sccb) sccb_get_generic_mask(sccb, 3) | ||
138 | |||
139 | #define sccb_set_generic_mask(sccb, i, val) \ | ||
140 | ({ \ | ||
141 | __typeof__(sccb) __sccb = sccb; \ | ||
142 | \ | ||
143 | sccb_set_mask(__sccb->masks, __sccb->mask_length, i, val); \ | ||
144 | }) | ||
145 | #define sccb_set_recv_mask(sccb, val) sccb_set_generic_mask(sccb, 0, val) | ||
146 | #define sccb_set_send_mask(sccb, val) sccb_set_generic_mask(sccb, 1, val) | ||
147 | #define sccb_set_sclp_recv_mask(sccb, val) sccb_set_generic_mask(sccb, 2, val) | ||
148 | #define sccb_set_sclp_send_mask(sccb, val) sccb_set_generic_mask(sccb, 3, val) | ||
149 | |||
107 | struct read_cpu_info_sccb { | 150 | struct read_cpu_info_sccb { |
108 | struct sccb_header header; | 151 | struct sccb_header header; |
109 | u16 nr_configured; | 152 | u16 nr_configured; |
@@ -221,15 +264,17 @@ extern int sclp_init_state; | |||
221 | extern int sclp_console_pages; | 264 | extern int sclp_console_pages; |
222 | extern int sclp_console_drop; | 265 | extern int sclp_console_drop; |
223 | extern unsigned long sclp_console_full; | 266 | extern unsigned long sclp_console_full; |
267 | extern bool sclp_mask_compat_mode; | ||
224 | 268 | ||
225 | extern char sclp_early_sccb[PAGE_SIZE]; | 269 | extern char sclp_early_sccb[PAGE_SIZE]; |
226 | 270 | ||
227 | void sclp_early_wait_irq(void); | 271 | void sclp_early_wait_irq(void); |
228 | int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb); | 272 | int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb); |
229 | unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb); | 273 | unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb); |
274 | unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb); | ||
230 | int sclp_early_set_event_mask(struct init_sccb *sccb, | 275 | int sclp_early_set_event_mask(struct init_sccb *sccb, |
231 | unsigned long receive_mask, | 276 | sccb_mask_t receive_mask, |
232 | unsigned long send_mask); | 277 | sccb_mask_t send_mask); |
233 | 278 | ||
234 | /* useful inlines */ | 279 | /* useful inlines */ |
235 | 280 | ||
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 6b1891539c84..9a74abb9224d 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c | |||
@@ -249,7 +249,7 @@ static void __init sclp_early_console_detect(struct init_sccb *sccb) | |||
249 | if (sccb->header.response_code != 0x20) | 249 | if (sccb->header.response_code != 0x20) |
250 | return; | 250 | return; |
251 | 251 | ||
252 | if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) | 252 | if (sclp_early_con_check_vt220(sccb)) |
253 | sclp.has_vt220 = 1; | 253 | sclp.has_vt220 = 1; |
254 | 254 | ||
255 | if (sclp_early_con_check_linemode(sccb)) | 255 | if (sclp_early_con_check_linemode(sccb)) |
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 17b0c67f3e8d..5f8d9ea69ebd 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c | |||
@@ -14,6 +14,11 @@ | |||
14 | 14 | ||
15 | char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); | 15 | char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); |
16 | int sclp_init_state __section(.data) = sclp_init_state_uninitialized; | 16 | int sclp_init_state __section(.data) = sclp_init_state_uninitialized; |
17 | /* | ||
18 | * Used to keep track of the size of the event masks. Qemu until version 2.11 | ||
19 | * only supports 4 and needs a workaround. | ||
20 | */ | ||
21 | bool sclp_mask_compat_mode; | ||
17 | 22 | ||
18 | void sclp_early_wait_irq(void) | 23 | void sclp_early_wait_irq(void) |
19 | { | 24 | { |
@@ -142,16 +147,24 @@ static void sclp_early_print_vt220(const char *str, unsigned int len) | |||
142 | } | 147 | } |
143 | 148 | ||
144 | int sclp_early_set_event_mask(struct init_sccb *sccb, | 149 | int sclp_early_set_event_mask(struct init_sccb *sccb, |
145 | unsigned long receive_mask, | 150 | sccb_mask_t receive_mask, |
146 | unsigned long send_mask) | 151 | sccb_mask_t send_mask) |
147 | { | 152 | { |
153 | retry: | ||
148 | memset(sccb, 0, sizeof(*sccb)); | 154 | memset(sccb, 0, sizeof(*sccb)); |
149 | sccb->header.length = sizeof(*sccb); | 155 | sccb->header.length = sizeof(*sccb); |
150 | sccb->mask_length = sizeof(sccb_mask_t); | 156 | if (sclp_mask_compat_mode) |
151 | sccb->receive_mask = receive_mask; | 157 | sccb->mask_length = SCLP_MASK_SIZE_COMPAT; |
152 | sccb->send_mask = send_mask; | 158 | else |
159 | sccb->mask_length = sizeof(sccb_mask_t); | ||
160 | sccb_set_recv_mask(sccb, receive_mask); | ||
161 | sccb_set_send_mask(sccb, send_mask); | ||
153 | if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) | 162 | if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) |
154 | return -EIO; | 163 | return -EIO; |
164 | if ((sccb->header.response_code == 0x74f0) && !sclp_mask_compat_mode) { | ||
165 | sclp_mask_compat_mode = true; | ||
166 | goto retry; | ||
167 | } | ||
155 | if (sccb->header.response_code != 0x20) | 168 | if (sccb->header.response_code != 0x20) |
156 | return -EIO; | 169 | return -EIO; |
157 | return 0; | 170 | return 0; |
@@ -159,19 +172,28 @@ int sclp_early_set_event_mask(struct init_sccb *sccb, | |||
159 | 172 | ||
160 | unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) | 173 | unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) |
161 | { | 174 | { |
162 | if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK)) | 175 | if (!(sccb_get_sclp_send_mask(sccb) & EVTYP_OPCMD_MASK)) |
163 | return 0; | 176 | return 0; |
164 | if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) | 177 | if (!(sccb_get_sclp_recv_mask(sccb) & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) |
165 | return 0; | 178 | return 0; |
166 | return 1; | 179 | return 1; |
167 | } | 180 | } |
168 | 181 | ||
182 | unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb) | ||
183 | { | ||
184 | if (sccb_get_sclp_send_mask(sccb) & EVTYP_VT220MSG_MASK) | ||
185 | return 1; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
169 | static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) | 189 | static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) |
170 | { | 190 | { |
171 | unsigned long receive_mask, send_mask; | 191 | unsigned long receive_mask, send_mask; |
172 | struct init_sccb *sccb; | 192 | struct init_sccb *sccb; |
173 | int rc; | 193 | int rc; |
174 | 194 | ||
195 | BUILD_BUG_ON(sizeof(struct init_sccb) > PAGE_SIZE); | ||
196 | |||
175 | *have_linemode = *have_vt220 = 0; | 197 | *have_linemode = *have_vt220 = 0; |
176 | sccb = (struct init_sccb *) &sclp_early_sccb; | 198 | sccb = (struct init_sccb *) &sclp_early_sccb; |
177 | receive_mask = disable ? 0 : EVTYP_OPCMD_MASK; | 199 | receive_mask = disable ? 0 : EVTYP_OPCMD_MASK; |
@@ -180,7 +202,7 @@ static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) | |||
180 | if (rc) | 202 | if (rc) |
181 | return rc; | 203 | return rc; |
182 | *have_linemode = sclp_early_con_check_linemode(sccb); | 204 | *have_linemode = sclp_early_con_check_linemode(sccb); |
183 | *have_vt220 = sccb->send_mask & EVTYP_VT220MSG_MASK; | 205 | *have_vt220 = !!(sccb_get_send_mask(sccb) & EVTYP_VT220MSG_MASK); |
184 | return rc; | 206 | return rc; |
185 | } | 207 | } |
186 | 208 | ||
diff --git a/drivers/s390/char/sclp_sd.c b/drivers/s390/char/sclp_sd.c new file mode 100644 index 000000000000..99f41db5123b --- /dev/null +++ b/drivers/s390/char/sclp_sd.c | |||
@@ -0,0 +1,569 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * SCLP Store Data support and sysfs interface | ||
4 | * | ||
5 | * Copyright IBM Corp. 2017 | ||
6 | */ | ||
7 | |||
8 | #define KMSG_COMPONENT "sclp_sd" | ||
9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
10 | |||
11 | #include <linux/completion.h> | ||
12 | #include <linux/kobject.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/printk.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/vmalloc.h> | ||
17 | #include <linux/async.h> | ||
18 | #include <linux/export.h> | ||
19 | #include <linux/mutex.h> | ||
20 | |||
21 | #include <asm/pgalloc.h> | ||
22 | |||
23 | #include "sclp.h" | ||
24 | |||
25 | #define SD_EQ_STORE_DATA 0 | ||
26 | #define SD_EQ_HALT 1 | ||
27 | #define SD_EQ_SIZE 2 | ||
28 | |||
29 | #define SD_DI_CONFIG 3 | ||
30 | |||
31 | struct sclp_sd_evbuf { | ||
32 | struct evbuf_header hdr; | ||
33 | u8 eq; | ||
34 | u8 di; | ||
35 | u8 rflags; | ||
36 | u64 :56; | ||
37 | u32 id; | ||
38 | u16 :16; | ||
39 | u8 fmt; | ||
40 | u8 status; | ||
41 | u64 sat; | ||
42 | u64 sa; | ||
43 | u32 esize; | ||
44 | u32 dsize; | ||
45 | } __packed; | ||
46 | |||
47 | struct sclp_sd_sccb { | ||
48 | struct sccb_header hdr; | ||
49 | struct sclp_sd_evbuf evbuf; | ||
50 | } __packed __aligned(PAGE_SIZE); | ||
51 | |||
52 | /** | ||
53 | * struct sclp_sd_data - Result of a Store Data request | ||
54 | * @esize_bytes: Resulting esize in bytes | ||
55 | * @dsize_bytes: Resulting dsize in bytes | ||
56 | * @data: Pointer to data - must be released using vfree() | ||
57 | */ | ||
58 | struct sclp_sd_data { | ||
59 | size_t esize_bytes; | ||
60 | size_t dsize_bytes; | ||
61 | void *data; | ||
62 | }; | ||
63 | |||
64 | /** | ||
65 | * struct sclp_sd_listener - Listener for asynchronous Store Data response | ||
66 | * @list: For enqueueing this struct | ||
67 | * @id: Event ID of response to listen for | ||
68 | * @completion: Can be used to wait for response | ||
69 | * @evbuf: Contains the resulting Store Data response after completion | ||
70 | */ | ||
71 | struct sclp_sd_listener { | ||
72 | struct list_head list; | ||
73 | u32 id; | ||
74 | struct completion completion; | ||
75 | struct sclp_sd_evbuf evbuf; | ||
76 | }; | ||
77 | |||
78 | /** | ||
79 | * struct sclp_sd_file - Sysfs representation of a Store Data entity | ||
80 | * @kobj: Kobject | ||
81 | * @data_attr: Attribute for accessing data contents | ||
82 | * @data_mutex: Mutex to serialize access and updates to @data | ||
83 | * @data: Data associated with this entity | ||
84 | * @di: DI value associated with this entity | ||
85 | */ | ||
86 | struct sclp_sd_file { | ||
87 | struct kobject kobj; | ||
88 | struct bin_attribute data_attr; | ||
89 | struct mutex data_mutex; | ||
90 | struct sclp_sd_data data; | ||
91 | u8 di; | ||
92 | }; | ||
93 | #define to_sd_file(x) container_of(x, struct sclp_sd_file, kobj) | ||
94 | |||
95 | static struct kset *sclp_sd_kset; | ||
96 | static struct sclp_sd_file *config_file; | ||
97 | |||
98 | static LIST_HEAD(sclp_sd_queue); | ||
99 | static DEFINE_SPINLOCK(sclp_sd_queue_lock); | ||
100 | |||
101 | /** | ||
102 | * sclp_sd_listener_add() - Add listener for Store Data responses | ||
103 | * @listener: Listener to add | ||
104 | */ | ||
105 | static void sclp_sd_listener_add(struct sclp_sd_listener *listener) | ||
106 | { | ||
107 | spin_lock_irq(&sclp_sd_queue_lock); | ||
108 | list_add_tail(&listener->list, &sclp_sd_queue); | ||
109 | spin_unlock_irq(&sclp_sd_queue_lock); | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * sclp_sd_listener_remove() - Remove listener for Store Data responses | ||
114 | * @listener: Listener to remove | ||
115 | */ | ||
116 | static void sclp_sd_listener_remove(struct sclp_sd_listener *listener) | ||
117 | { | ||
118 | spin_lock_irq(&sclp_sd_queue_lock); | ||
119 | list_del(&listener->list); | ||
120 | spin_unlock_irq(&sclp_sd_queue_lock); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * sclp_sd_listener_init() - Initialize a Store Data response listener | ||
125 | * @id: Event ID to listen for | ||
126 | * | ||
127 | * Initialize a listener for asynchronous Store Data responses. This listener | ||
128 | * can afterwards be used to wait for a specific response and to retrieve | ||
129 | * the associated response data. | ||
130 | */ | ||
131 | static void sclp_sd_listener_init(struct sclp_sd_listener *listener, u32 id) | ||
132 | { | ||
133 | memset(listener, 0, sizeof(*listener)); | ||
134 | listener->id = id; | ||
135 | init_completion(&listener->completion); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * sclp_sd_receiver() - Receiver for Store Data events | ||
140 | * @evbuf_hdr: Header of received events | ||
141 | * | ||
142 | * Process Store Data events and complete listeners with matching event IDs. | ||
143 | */ | ||
144 | static void sclp_sd_receiver(struct evbuf_header *evbuf_hdr) | ||
145 | { | ||
146 | struct sclp_sd_evbuf *evbuf = (struct sclp_sd_evbuf *) evbuf_hdr; | ||
147 | struct sclp_sd_listener *listener; | ||
148 | int found = 0; | ||
149 | |||
150 | pr_debug("received event (id=0x%08x)\n", evbuf->id); | ||
151 | spin_lock(&sclp_sd_queue_lock); | ||
152 | list_for_each_entry(listener, &sclp_sd_queue, list) { | ||
153 | if (listener->id != evbuf->id) | ||
154 | continue; | ||
155 | |||
156 | listener->evbuf = *evbuf; | ||
157 | complete(&listener->completion); | ||
158 | found = 1; | ||
159 | break; | ||
160 | } | ||
161 | spin_unlock(&sclp_sd_queue_lock); | ||
162 | |||
163 | if (!found) | ||
164 | pr_debug("unsolicited event (id=0x%08x)\n", evbuf->id); | ||
165 | } | ||
166 | |||
167 | static struct sclp_register sclp_sd_register = { | ||
168 | .send_mask = EVTYP_STORE_DATA_MASK, | ||
169 | .receive_mask = EVTYP_STORE_DATA_MASK, | ||
170 | .receiver_fn = sclp_sd_receiver, | ||
171 | }; | ||
172 | |||
173 | /** | ||
174 | * sclp_sd_sync() - Perform Store Data request synchronously | ||
175 | * @page: Address of work page - must be below 2GB | ||
176 | * @eq: Input EQ value | ||
177 | * @di: Input DI value | ||
178 | * @sat: Input SAT value | ||
179 | * @sa: Input SA value used to specify the address of the target buffer | ||
180 | * @dsize_ptr: Optional pointer to input and output DSIZE value | ||
181 | * @esize_ptr: Optional pointer to output ESIZE value | ||
182 | * | ||
183 | * Perform Store Data request with specified parameters and wait for completion. | ||
184 | * | ||
185 | * Return %0 on success and store resulting DSIZE and ESIZE values in | ||
186 | * @dsize_ptr and @esize_ptr (if provided). Return non-zero on error. | ||
187 | */ | ||
188 | static int sclp_sd_sync(unsigned long page, u8 eq, u8 di, u64 sat, u64 sa, | ||
189 | u32 *dsize_ptr, u32 *esize_ptr) | ||
190 | { | ||
191 | struct sclp_sd_sccb *sccb = (void *) page; | ||
192 | struct sclp_sd_listener listener; | ||
193 | struct sclp_sd_evbuf *evbuf; | ||
194 | int rc; | ||
195 | |||
196 | sclp_sd_listener_init(&listener, (u32) (addr_t) sccb); | ||
197 | sclp_sd_listener_add(&listener); | ||
198 | |||
199 | /* Prepare SCCB */ | ||
200 | memset(sccb, 0, PAGE_SIZE); | ||
201 | sccb->hdr.length = sizeof(sccb->hdr) + sizeof(sccb->evbuf); | ||
202 | evbuf = &sccb->evbuf; | ||
203 | evbuf->hdr.length = sizeof(*evbuf); | ||
204 | evbuf->hdr.type = EVTYP_STORE_DATA; | ||
205 | evbuf->eq = eq; | ||
206 | evbuf->di = di; | ||
207 | evbuf->id = listener.id; | ||
208 | evbuf->fmt = 1; | ||
209 | evbuf->sat = sat; | ||
210 | evbuf->sa = sa; | ||
211 | if (dsize_ptr) | ||
212 | evbuf->dsize = *dsize_ptr; | ||
213 | |||
214 | /* Perform command */ | ||
215 | pr_debug("request (eq=%d, di=%d, id=0x%08x)\n", eq, di, listener.id); | ||
216 | rc = sclp_sync_request(SCLP_CMDW_WRITE_EVENT_DATA, sccb); | ||
217 | pr_debug("request done (rc=%d)\n", rc); | ||
218 | if (rc) | ||
219 | goto out; | ||
220 | |||
221 | /* Evaluate response */ | ||
222 | if (sccb->hdr.response_code == 0x73f0) { | ||
223 | pr_debug("event not supported\n"); | ||
224 | rc = -EIO; | ||
225 | goto out_remove; | ||
226 | } | ||
227 | if (sccb->hdr.response_code != 0x0020 || !(evbuf->hdr.flags & 0x80)) { | ||
228 | rc = -EIO; | ||
229 | goto out; | ||
230 | } | ||
231 | if (!(evbuf->rflags & 0x80)) { | ||
232 | rc = wait_for_completion_interruptible(&listener.completion); | ||
233 | if (rc) | ||
234 | goto out; | ||
235 | evbuf = &listener.evbuf; | ||
236 | } | ||
237 | switch (evbuf->status) { | ||
238 | case 0: | ||
239 | if (dsize_ptr) | ||
240 | *dsize_ptr = evbuf->dsize; | ||
241 | if (esize_ptr) | ||
242 | *esize_ptr = evbuf->esize; | ||
243 | pr_debug("success (dsize=%u, esize=%u)\n", evbuf->dsize, | ||
244 | evbuf->esize); | ||
245 | break; | ||
246 | case 3: | ||
247 | rc = -ENOENT; | ||
248 | break; | ||
249 | default: | ||
250 | rc = -EIO; | ||
251 | break; | ||
252 | |||
253 | } | ||
254 | |||
255 | out: | ||
256 | if (rc && rc != -ENOENT) { | ||
257 | /* Provide some information about what went wrong */ | ||
258 | pr_warn("Store Data request failed (eq=%d, di=%d, " | ||
259 | "response=0x%04x, flags=0x%02x, status=%d, rc=%d)\n", | ||
260 | eq, di, sccb->hdr.response_code, evbuf->hdr.flags, | ||
261 | evbuf->status, rc); | ||
262 | } | ||
263 | |||
264 | out_remove: | ||
265 | sclp_sd_listener_remove(&listener); | ||
266 | |||
267 | return rc; | ||
268 | } | ||
269 | |||
270 | /** | ||
271 | * sclp_sd_store_data() - Obtain data for specified Store Data entity | ||
272 | * @result: Resulting data | ||
273 | * @di: DI value associated with this entity | ||
274 | * | ||
275 | * Perform a series of Store Data requests to obtain the size and contents of | ||
276 | * the specified Store Data entity. | ||
277 | * | ||
278 | * Return: | ||
279 | * %0: Success - result is stored in @result. @result->data must be | ||
280 | * released using vfree() after use. | ||
281 | * %-ENOENT: No data available for this entity | ||
282 | * %<0: Other error | ||
283 | */ | ||
284 | static int sclp_sd_store_data(struct sclp_sd_data *result, u8 di) | ||
285 | { | ||
286 | u32 dsize = 0, esize = 0; | ||
287 | unsigned long page, asce = 0; | ||
288 | void *data = NULL; | ||
289 | int rc; | ||
290 | |||
291 | page = __get_free_page(GFP_KERNEL | GFP_DMA); | ||
292 | if (!page) | ||
293 | return -ENOMEM; | ||
294 | |||
295 | /* Get size */ | ||
296 | rc = sclp_sd_sync(page, SD_EQ_SIZE, di, 0, 0, &dsize, &esize); | ||
297 | if (rc) | ||
298 | goto out; | ||
299 | if (dsize == 0) | ||
300 | goto out_result; | ||
301 | |||
302 | /* Allocate memory */ | ||
303 | data = vzalloc((size_t) dsize * PAGE_SIZE); | ||
304 | if (!data) { | ||
305 | rc = -ENOMEM; | ||
306 | goto out; | ||
307 | } | ||
308 | |||
309 | /* Get translation table for buffer */ | ||
310 | asce = base_asce_alloc((unsigned long) data, dsize); | ||
311 | if (!asce) { | ||
312 | vfree(data); | ||
313 | rc = -ENOMEM; | ||
314 | goto out; | ||
315 | } | ||
316 | |||
317 | /* Get data */ | ||
318 | rc = sclp_sd_sync(page, SD_EQ_STORE_DATA, di, asce, (u64) data, &dsize, | ||
319 | &esize); | ||
320 | if (rc) { | ||
321 | /* Cancel running request if interrupted */ | ||
322 | if (rc == -ERESTARTSYS) | ||
323 | sclp_sd_sync(page, SD_EQ_HALT, di, 0, 0, NULL, NULL); | ||
324 | vfree(data); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | out_result: | ||
329 | result->esize_bytes = (size_t) esize * PAGE_SIZE; | ||
330 | result->dsize_bytes = (size_t) dsize * PAGE_SIZE; | ||
331 | result->data = data; | ||
332 | |||
333 | out: | ||
334 | base_asce_free(asce); | ||
335 | free_page(page); | ||
336 | |||
337 | return rc; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * sclp_sd_data_reset() - Reset Store Data result buffer | ||
342 | * @data: Data buffer to reset | ||
343 | * | ||
344 | * Reset @data to initial state and release associated memory. | ||
345 | */ | ||
346 | static void sclp_sd_data_reset(struct sclp_sd_data *data) | ||
347 | { | ||
348 | vfree(data->data); | ||
349 | data->data = NULL; | ||
350 | data->dsize_bytes = 0; | ||
351 | data->esize_bytes = 0; | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * sclp_sd_file_release() - Release function for sclp_sd_file object | ||
356 | * @kobj: Kobject embedded in sclp_sd_file object | ||
357 | */ | ||
358 | static void sclp_sd_file_release(struct kobject *kobj) | ||
359 | { | ||
360 | struct sclp_sd_file *sd_file = to_sd_file(kobj); | ||
361 | |||
362 | sclp_sd_data_reset(&sd_file->data); | ||
363 | kfree(sd_file); | ||
364 | } | ||
365 | |||
366 | /** | ||
367 | * sclp_sd_file_update() - Update contents of sclp_sd_file object | ||
368 | * @sd_file: Object to update | ||
369 | * | ||
370 | * Obtain the current version of data associated with the Store Data entity | ||
371 | * @sd_file. | ||
372 | * | ||
373 | * On success, return %0 and generate a KOBJ_CHANGE event to indicate that the | ||
374 | * data may have changed. Return non-zero otherwise. | ||
375 | */ | ||
376 | static int sclp_sd_file_update(struct sclp_sd_file *sd_file) | ||
377 | { | ||
378 | const char *name = kobject_name(&sd_file->kobj); | ||
379 | struct sclp_sd_data data; | ||
380 | int rc; | ||
381 | |||
382 | rc = sclp_sd_store_data(&data, sd_file->di); | ||
383 | if (rc) { | ||
384 | if (rc == -ENOENT) { | ||
385 | pr_info("No data is available for the %s data entity\n", | ||
386 | name); | ||
387 | } | ||
388 | return rc; | ||
389 | } | ||
390 | |||
391 | mutex_lock(&sd_file->data_mutex); | ||
392 | sclp_sd_data_reset(&sd_file->data); | ||
393 | sd_file->data = data; | ||
394 | mutex_unlock(&sd_file->data_mutex); | ||
395 | |||
396 | pr_info("A %zu-byte %s data entity was retrieved\n", data.dsize_bytes, | ||
397 | name); | ||
398 | kobject_uevent(&sd_file->kobj, KOBJ_CHANGE); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | /** | ||
404 | * sclp_sd_file_update_async() - Wrapper for asynchronous update call | ||
405 | * @data: Object to update | ||
406 | */ | ||
407 | static void sclp_sd_file_update_async(void *data, async_cookie_t cookie) | ||
408 | { | ||
409 | struct sclp_sd_file *sd_file = data; | ||
410 | |||
411 | sclp_sd_file_update(sd_file); | ||
412 | } | ||
413 | |||
414 | /** | ||
415 | * reload_store() - Store function for "reload" sysfs attribute | ||
416 | * @kobj: Kobject of sclp_sd_file object | ||
417 | * | ||
418 | * Initiate a reload of the data associated with an sclp_sd_file object. | ||
419 | */ | ||
420 | static ssize_t reload_store(struct kobject *kobj, struct kobj_attribute *attr, | ||
421 | const char *buf, size_t count) | ||
422 | { | ||
423 | struct sclp_sd_file *sd_file = to_sd_file(kobj); | ||
424 | |||
425 | sclp_sd_file_update(sd_file); | ||
426 | |||
427 | return count; | ||
428 | } | ||
429 | |||
430 | static struct kobj_attribute reload_attr = __ATTR_WO(reload); | ||
431 | |||
432 | static struct attribute *sclp_sd_file_default_attrs[] = { | ||
433 | &reload_attr.attr, | ||
434 | NULL, | ||
435 | }; | ||
436 | |||
437 | static struct kobj_type sclp_sd_file_ktype = { | ||
438 | .sysfs_ops = &kobj_sysfs_ops, | ||
439 | .release = sclp_sd_file_release, | ||
440 | .default_attrs = sclp_sd_file_default_attrs, | ||
441 | }; | ||
442 | |||
443 | /** | ||
444 | * data_read() - Read function for "read" sysfs attribute | ||
445 | * @kobj: Kobject of sclp_sd_file object | ||
446 | * @buffer: Target buffer | ||
447 | * @off: Requested file offset | ||
448 | * @size: Requested number of bytes | ||
449 | * | ||
450 | * Store the requested portion of the Store Data entity contents into the | ||
451 | * specified buffer. Return the number of bytes stored on success, or %0 | ||
452 | * on EOF. | ||
453 | */ | ||
454 | static ssize_t data_read(struct file *file, struct kobject *kobj, | ||
455 | struct bin_attribute *attr, char *buffer, | ||
456 | loff_t off, size_t size) | ||
457 | { | ||
458 | struct sclp_sd_file *sd_file = to_sd_file(kobj); | ||
459 | size_t data_size; | ||
460 | char *data; | ||
461 | |||
462 | mutex_lock(&sd_file->data_mutex); | ||
463 | |||
464 | data = sd_file->data.data; | ||
465 | data_size = sd_file->data.dsize_bytes; | ||
466 | if (!data || off >= data_size) { | ||
467 | size = 0; | ||
468 | } else { | ||
469 | if (off + size > data_size) | ||
470 | size = data_size - off; | ||
471 | memcpy(buffer, data + off, size); | ||
472 | } | ||
473 | |||
474 | mutex_unlock(&sd_file->data_mutex); | ||
475 | |||
476 | return size; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * sclp_sd_file_create() - Add a sysfs file representing a Store Data entity | ||
481 | * @name: Name of file | ||
482 | * @di: DI value associated with this entity | ||
483 | * | ||
484 | * Create a sysfs directory with the given @name located under | ||
485 | * | ||
486 | * /sys/firmware/sclp_sd/ | ||
487 | * | ||
488 | * The files in this directory can be used to access the contents of the Store | ||
489 | * Data entity associated with @DI. | ||
490 | * | ||
491 | * Return pointer to resulting sclp_sd_file object on success, %NULL otherwise. | ||
492 | * The object must be freed by calling kobject_put() on the embedded kobject | ||
493 | * pointer after use. | ||
494 | */ | ||
495 | static __init struct sclp_sd_file *sclp_sd_file_create(const char *name, u8 di) | ||
496 | { | ||
497 | struct sclp_sd_file *sd_file; | ||
498 | int rc; | ||
499 | |||
500 | sd_file = kzalloc(sizeof(*sd_file), GFP_KERNEL); | ||
501 | if (!sd_file) | ||
502 | return NULL; | ||
503 | sd_file->di = di; | ||
504 | mutex_init(&sd_file->data_mutex); | ||
505 | |||
506 | /* Create kobject located under /sys/firmware/sclp_sd/ */ | ||
507 | sd_file->kobj.kset = sclp_sd_kset; | ||
508 | rc = kobject_init_and_add(&sd_file->kobj, &sclp_sd_file_ktype, NULL, | ||
509 | "%s", name); | ||
510 | if (rc) { | ||
511 | kobject_put(&sd_file->kobj); | ||
512 | return NULL; | ||
513 | } | ||
514 | |||
515 | sysfs_bin_attr_init(&sd_file->data_attr); | ||
516 | sd_file->data_attr.attr.name = "data"; | ||
517 | sd_file->data_attr.attr.mode = 0444; | ||
518 | sd_file->data_attr.read = data_read; | ||
519 | |||
520 | rc = sysfs_create_bin_file(&sd_file->kobj, &sd_file->data_attr); | ||
521 | if (rc) { | ||
522 | kobject_put(&sd_file->kobj); | ||
523 | return NULL; | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * For completeness only - users interested in entity data should listen | ||
528 | * for KOBJ_CHANGE instead. | ||
529 | */ | ||
530 | kobject_uevent(&sd_file->kobj, KOBJ_ADD); | ||
531 | |||
532 | /* Don't let a slow Store Data request delay further initialization */ | ||
533 | async_schedule(sclp_sd_file_update_async, sd_file); | ||
534 | |||
535 | return sd_file; | ||
536 | } | ||
537 | |||
538 | /** | ||
539 | * sclp_sd_init() - Initialize sclp_sd support and register sysfs files | ||
540 | */ | ||
541 | static __init int sclp_sd_init(void) | ||
542 | { | ||
543 | int rc; | ||
544 | |||
545 | rc = sclp_register(&sclp_sd_register); | ||
546 | if (rc) | ||
547 | return rc; | ||
548 | |||
549 | /* Create kset named "sclp_sd" located under /sys/firmware/ */ | ||
550 | rc = -ENOMEM; | ||
551 | sclp_sd_kset = kset_create_and_add("sclp_sd", NULL, firmware_kobj); | ||
552 | if (!sclp_sd_kset) | ||
553 | goto err_kset; | ||
554 | |||
555 | rc = -EINVAL; | ||
556 | config_file = sclp_sd_file_create("config", SD_DI_CONFIG); | ||
557 | if (!config_file) | ||
558 | goto err_config; | ||
559 | |||
560 | return 0; | ||
561 | |||
562 | err_config: | ||
563 | kset_unregister(sclp_sd_kset); | ||
564 | err_kset: | ||
565 | sclp_unregister(&sclp_sd_register); | ||
566 | |||
567 | return rc; | ||
568 | } | ||
569 | device_initcall(sclp_sd_init); | ||
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 9f7b87d6d434..5aff8b684eb2 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
@@ -502,7 +502,10 @@ sclp_tty_init(void) | |||
502 | int i; | 502 | int i; |
503 | int rc; | 503 | int rc; |
504 | 504 | ||
505 | if (!CONSOLE_IS_SCLP) | 505 | /* z/VM multiplexes the line mode output on the 32xx screen */ |
506 | if (MACHINE_IS_VM && !CONSOLE_IS_SCLP) | ||
507 | return 0; | ||
508 | if (!sclp.has_linemode) | ||
506 | return 0; | 509 | return 0; |
507 | driver = alloc_tty_driver(1); | 510 | driver = alloc_tty_driver(1); |
508 | if (!driver) | 511 | if (!driver) |
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c index f95b452b8bbc..afbdee74147d 100644 --- a/drivers/s390/cio/chp.c +++ b/drivers/s390/cio/chp.c | |||
@@ -384,6 +384,28 @@ static ssize_t chp_chid_external_show(struct device *dev, | |||
384 | } | 384 | } |
385 | static DEVICE_ATTR(chid_external, 0444, chp_chid_external_show, NULL); | 385 | static DEVICE_ATTR(chid_external, 0444, chp_chid_external_show, NULL); |
386 | 386 | ||
387 | static ssize_t util_string_read(struct file *filp, struct kobject *kobj, | ||
388 | struct bin_attribute *attr, char *buf, | ||
389 | loff_t off, size_t count) | ||
390 | { | ||
391 | struct channel_path *chp = to_channelpath(kobj_to_dev(kobj)); | ||
392 | ssize_t rc; | ||
393 | |||
394 | mutex_lock(&chp->lock); | ||
395 | rc = memory_read_from_buffer(buf, count, &off, chp->desc_fmt3.util_str, | ||
396 | sizeof(chp->desc_fmt3.util_str)); | ||
397 | mutex_unlock(&chp->lock); | ||
398 | |||
399 | return rc; | ||
400 | } | ||
401 | static BIN_ATTR_RO(util_string, | ||
402 | sizeof(((struct channel_path_desc_fmt3 *)0)->util_str)); | ||
403 | |||
404 | static struct bin_attribute *chp_bin_attrs[] = { | ||
405 | &bin_attr_util_string, | ||
406 | NULL, | ||
407 | }; | ||
408 | |||
387 | static struct attribute *chp_attrs[] = { | 409 | static struct attribute *chp_attrs[] = { |
388 | &dev_attr_status.attr, | 410 | &dev_attr_status.attr, |
389 | &dev_attr_configure.attr, | 411 | &dev_attr_configure.attr, |
@@ -396,6 +418,7 @@ static struct attribute *chp_attrs[] = { | |||
396 | }; | 418 | }; |
397 | static struct attribute_group chp_attr_group = { | 419 | static struct attribute_group chp_attr_group = { |
398 | .attrs = chp_attrs, | 420 | .attrs = chp_attrs, |
421 | .bin_attrs = chp_bin_attrs, | ||
399 | }; | 422 | }; |
400 | static const struct attribute_group *chp_attr_groups[] = { | 423 | static const struct attribute_group *chp_attr_groups[] = { |
401 | &chp_attr_group, | 424 | &chp_attr_group, |
@@ -422,7 +445,7 @@ int chp_update_desc(struct channel_path *chp) | |||
422 | { | 445 | { |
423 | int rc; | 446 | int rc; |
424 | 447 | ||
425 | rc = chsc_determine_base_channel_path_desc(chp->chpid, &chp->desc); | 448 | rc = chsc_determine_fmt0_channel_path_desc(chp->chpid, &chp->desc); |
426 | if (rc) | 449 | if (rc) |
427 | return rc; | 450 | return rc; |
428 | 451 | ||
@@ -431,6 +454,7 @@ int chp_update_desc(struct channel_path *chp) | |||
431 | * hypervisors implement the required chsc commands. | 454 | * hypervisors implement the required chsc commands. |
432 | */ | 455 | */ |
433 | chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); | 456 | chsc_determine_fmt1_channel_path_desc(chp->chpid, &chp->desc_fmt1); |
457 | chsc_determine_fmt3_channel_path_desc(chp->chpid, &chp->desc_fmt3); | ||
434 | chsc_get_channel_measurement_chars(chp); | 458 | chsc_get_channel_measurement_chars(chp); |
435 | 459 | ||
436 | return 0; | 460 | return 0; |
@@ -506,20 +530,20 @@ out: | |||
506 | * On success return a newly allocated copy of the channel-path description | 530 | * On success return a newly allocated copy of the channel-path description |
507 | * data associated with the given channel-path ID. Return %NULL on error. | 531 | * data associated with the given channel-path ID. Return %NULL on error. |
508 | */ | 532 | */ |
509 | struct channel_path_desc *chp_get_chp_desc(struct chp_id chpid) | 533 | struct channel_path_desc_fmt0 *chp_get_chp_desc(struct chp_id chpid) |
510 | { | 534 | { |
511 | struct channel_path *chp; | 535 | struct channel_path *chp; |
512 | struct channel_path_desc *desc; | 536 | struct channel_path_desc_fmt0 *desc; |
513 | 537 | ||
514 | chp = chpid_to_chp(chpid); | 538 | chp = chpid_to_chp(chpid); |
515 | if (!chp) | 539 | if (!chp) |
516 | return NULL; | 540 | return NULL; |
517 | desc = kmalloc(sizeof(struct channel_path_desc), GFP_KERNEL); | 541 | desc = kmalloc(sizeof(*desc), GFP_KERNEL); |
518 | if (!desc) | 542 | if (!desc) |
519 | return NULL; | 543 | return NULL; |
520 | 544 | ||
521 | mutex_lock(&chp->lock); | 545 | mutex_lock(&chp->lock); |
522 | memcpy(desc, &chp->desc, sizeof(struct channel_path_desc)); | 546 | memcpy(desc, &chp->desc, sizeof(*desc)); |
523 | mutex_unlock(&chp->lock); | 547 | mutex_unlock(&chp->lock); |
524 | return desc; | 548 | return desc; |
525 | } | 549 | } |
diff --git a/drivers/s390/cio/chp.h b/drivers/s390/cio/chp.h index 7e80323cd261..20259f3fbf45 100644 --- a/drivers/s390/cio/chp.h +++ b/drivers/s390/cio/chp.h | |||
@@ -44,8 +44,9 @@ struct channel_path { | |||
44 | struct chp_id chpid; | 44 | struct chp_id chpid; |
45 | struct mutex lock; /* Serialize access to below members. */ | 45 | struct mutex lock; /* Serialize access to below members. */ |
46 | int state; | 46 | int state; |
47 | struct channel_path_desc desc; | 47 | struct channel_path_desc_fmt0 desc; |
48 | struct channel_path_desc_fmt1 desc_fmt1; | 48 | struct channel_path_desc_fmt1 desc_fmt1; |
49 | struct channel_path_desc_fmt3 desc_fmt3; | ||
49 | /* Channel-measurement related stuff: */ | 50 | /* Channel-measurement related stuff: */ |
50 | int cmg; | 51 | int cmg; |
51 | int shared; | 52 | int shared; |
@@ -61,7 +62,7 @@ static inline struct channel_path *chpid_to_chp(struct chp_id chpid) | |||
61 | int chp_get_status(struct chp_id chpid); | 62 | int chp_get_status(struct chp_id chpid); |
62 | u8 chp_get_sch_opm(struct subchannel *sch); | 63 | u8 chp_get_sch_opm(struct subchannel *sch); |
63 | int chp_is_registered(struct chp_id chpid); | 64 | int chp_is_registered(struct chp_id chpid); |
64 | struct channel_path_desc *chp_get_chp_desc(struct chp_id chpid); | 65 | struct channel_path_desc_fmt0 *chp_get_chp_desc(struct chp_id chpid); |
65 | void chp_remove_cmg_attr(struct channel_path *chp); | 66 | void chp_remove_cmg_attr(struct channel_path *chp); |
66 | int chp_add_cmg_attr(struct channel_path *chp); | 67 | int chp_add_cmg_attr(struct channel_path *chp); |
67 | int chp_update_desc(struct channel_path *chp); | 68 | int chp_update_desc(struct channel_path *chp); |
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index c08fc5a8df0c..6652a49a49b1 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -915,6 +915,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, | |||
915 | return -EINVAL; | 915 | return -EINVAL; |
916 | if ((rfmt == 2) && !css_general_characteristics.cib) | 916 | if ((rfmt == 2) && !css_general_characteristics.cib) |
917 | return -EINVAL; | 917 | return -EINVAL; |
918 | if ((rfmt == 3) && !css_general_characteristics.util_str) | ||
919 | return -EINVAL; | ||
918 | 920 | ||
919 | memset(page, 0, PAGE_SIZE); | 921 | memset(page, 0, PAGE_SIZE); |
920 | scpd_area = page; | 922 | scpd_area = page; |
@@ -940,43 +942,30 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, | |||
940 | } | 942 | } |
941 | EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); | 943 | EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); |
942 | 944 | ||
943 | int chsc_determine_base_channel_path_desc(struct chp_id chpid, | 945 | #define chsc_det_chp_desc(FMT, c) \ |
944 | struct channel_path_desc *desc) | 946 | int chsc_determine_fmt##FMT##_channel_path_desc( \ |
945 | { | 947 | struct chp_id chpid, struct channel_path_desc_fmt##FMT *desc) \ |
946 | struct chsc_scpd *scpd_area; | 948 | { \ |
947 | unsigned long flags; | 949 | struct chsc_scpd *scpd_area; \ |
948 | int ret; | 950 | unsigned long flags; \ |
949 | 951 | int ret; \ | |
950 | spin_lock_irqsave(&chsc_page_lock, flags); | 952 | \ |
951 | scpd_area = chsc_page; | 953 | spin_lock_irqsave(&chsc_page_lock, flags); \ |
952 | ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, scpd_area); | 954 | scpd_area = chsc_page; \ |
953 | if (ret) | 955 | ret = chsc_determine_channel_path_desc(chpid, 0, FMT, c, 0, \ |
954 | goto out; | 956 | scpd_area); \ |
955 | 957 | if (ret) \ | |
956 | memcpy(desc, scpd_area->data, sizeof(*desc)); | 958 | goto out; \ |
957 | out: | 959 | \ |
958 | spin_unlock_irqrestore(&chsc_page_lock, flags); | 960 | memcpy(desc, scpd_area->data, sizeof(*desc)); \ |
959 | return ret; | 961 | out: \ |
962 | spin_unlock_irqrestore(&chsc_page_lock, flags); \ | ||
963 | return ret; \ | ||
960 | } | 964 | } |
961 | 965 | ||
962 | int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, | 966 | chsc_det_chp_desc(0, 0) |
963 | struct channel_path_desc_fmt1 *desc) | 967 | chsc_det_chp_desc(1, 1) |
964 | { | 968 | chsc_det_chp_desc(3, 0) |
965 | struct chsc_scpd *scpd_area; | ||
966 | unsigned long flags; | ||
967 | int ret; | ||
968 | |||
969 | spin_lock_irqsave(&chsc_page_lock, flags); | ||
970 | scpd_area = chsc_page; | ||
971 | ret = chsc_determine_channel_path_desc(chpid, 0, 1, 1, 0, scpd_area); | ||
972 | if (ret) | ||
973 | goto out; | ||
974 | |||
975 | memcpy(desc, scpd_area->data, sizeof(*desc)); | ||
976 | out: | ||
977 | spin_unlock_irqrestore(&chsc_page_lock, flags); | ||
978 | return ret; | ||
979 | } | ||
980 | 969 | ||
981 | static void | 970 | static void |
982 | chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, | 971 | chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index dda5953534b7..5c9f0dd33f4e 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -40,6 +40,11 @@ struct channel_path_desc_fmt1 { | |||
40 | u32 zeros[2]; | 40 | u32 zeros[2]; |
41 | } __attribute__ ((packed)); | 41 | } __attribute__ ((packed)); |
42 | 42 | ||
43 | struct channel_path_desc_fmt3 { | ||
44 | struct channel_path_desc_fmt1 fmt1_desc; | ||
45 | u8 util_str[64]; | ||
46 | }; | ||
47 | |||
43 | struct channel_path; | 48 | struct channel_path; |
44 | 49 | ||
45 | struct css_chsc_char { | 50 | struct css_chsc_char { |
@@ -147,10 +152,12 @@ int __chsc_do_secm(struct channel_subsystem *css, int enable); | |||
147 | int chsc_chp_vary(struct chp_id chpid, int on); | 152 | int chsc_chp_vary(struct chp_id chpid, int on); |
148 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, | 153 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, |
149 | int c, int m, void *page); | 154 | int c, int m, void *page); |
150 | int chsc_determine_base_channel_path_desc(struct chp_id chpid, | 155 | int chsc_determine_fmt0_channel_path_desc(struct chp_id chpid, |
151 | struct channel_path_desc *desc); | 156 | struct channel_path_desc_fmt0 *desc); |
152 | int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, | 157 | int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, |
153 | struct channel_path_desc_fmt1 *desc); | 158 | struct channel_path_desc_fmt1 *desc); |
159 | int chsc_determine_fmt3_channel_path_desc(struct chp_id chpid, | ||
160 | struct channel_path_desc_fmt3 *desc); | ||
154 | void chsc_chp_online(struct chp_id chpid); | 161 | void chsc_chp_online(struct chp_id chpid); |
155 | void chsc_chp_offline(struct chp_id chpid); | 162 | void chsc_chp_offline(struct chp_id chpid); |
156 | int chsc_get_channel_measurement_chars(struct channel_path *chp); | 163 | int chsc_get_channel_measurement_chars(struct channel_path *chp); |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index f50ea035aa9b..1540229a37bb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -1073,8 +1073,7 @@ out_schedule: | |||
1073 | return 0; | 1073 | return 0; |
1074 | } | 1074 | } |
1075 | 1075 | ||
1076 | static int | 1076 | static int io_subchannel_remove(struct subchannel *sch) |
1077 | io_subchannel_remove (struct subchannel *sch) | ||
1078 | { | 1077 | { |
1079 | struct io_subchannel_private *io_priv = to_io_private(sch); | 1078 | struct io_subchannel_private *io_priv = to_io_private(sch); |
1080 | struct ccw_device *cdev; | 1079 | struct ccw_device *cdev; |
@@ -1082,14 +1081,12 @@ io_subchannel_remove (struct subchannel *sch) | |||
1082 | cdev = sch_get_cdev(sch); | 1081 | cdev = sch_get_cdev(sch); |
1083 | if (!cdev) | 1082 | if (!cdev) |
1084 | goto out_free; | 1083 | goto out_free; |
1085 | io_subchannel_quiesce(sch); | 1084 | |
1086 | /* Set ccw device to not operational and drop reference. */ | 1085 | ccw_device_unregister(cdev); |
1087 | spin_lock_irq(cdev->ccwlock); | 1086 | spin_lock_irq(sch->lock); |
1088 | sch_set_cdev(sch, NULL); | 1087 | sch_set_cdev(sch, NULL); |
1089 | set_io_private(sch, NULL); | 1088 | set_io_private(sch, NULL); |
1090 | cdev->private->state = DEV_STATE_NOT_OPER; | 1089 | spin_unlock_irq(sch->lock); |
1091 | spin_unlock_irq(cdev->ccwlock); | ||
1092 | ccw_device_unregister(cdev); | ||
1093 | out_free: | 1090 | out_free: |
1094 | kfree(io_priv); | 1091 | kfree(io_priv); |
1095 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); | 1092 | sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); |
@@ -1721,6 +1718,7 @@ static int ccw_device_remove(struct device *dev) | |||
1721 | { | 1718 | { |
1722 | struct ccw_device *cdev = to_ccwdev(dev); | 1719 | struct ccw_device *cdev = to_ccwdev(dev); |
1723 | struct ccw_driver *cdrv = cdev->drv; | 1720 | struct ccw_driver *cdrv = cdev->drv; |
1721 | struct subchannel *sch; | ||
1724 | int ret; | 1722 | int ret; |
1725 | 1723 | ||
1726 | if (cdrv->remove) | 1724 | if (cdrv->remove) |
@@ -1746,7 +1744,9 @@ static int ccw_device_remove(struct device *dev) | |||
1746 | ccw_device_set_timeout(cdev, 0); | 1744 | ccw_device_set_timeout(cdev, 0); |
1747 | cdev->drv = NULL; | 1745 | cdev->drv = NULL; |
1748 | cdev->private->int_class = IRQIO_CIO; | 1746 | cdev->private->int_class = IRQIO_CIO; |
1747 | sch = to_subchannel(cdev->dev.parent); | ||
1749 | spin_unlock_irq(cdev->ccwlock); | 1748 | spin_unlock_irq(cdev->ccwlock); |
1749 | io_subchannel_quiesce(sch); | ||
1750 | __disable_cmf(cdev); | 1750 | __disable_cmf(cdev); |
1751 | 1751 | ||
1752 | return 0; | 1752 | return 0; |
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 75ce12a24dc2..aecfebb74157 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c | |||
@@ -460,8 +460,8 @@ __u8 ccw_device_get_path_mask(struct ccw_device *cdev) | |||
460 | * On success return a newly allocated copy of the channel-path description | 460 | * On success return a newly allocated copy of the channel-path description |
461 | * data associated with the given channel path. Return %NULL on error. | 461 | * data associated with the given channel path. Return %NULL on error. |
462 | */ | 462 | */ |
463 | struct channel_path_desc *ccw_device_get_chp_desc(struct ccw_device *cdev, | 463 | struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *cdev, |
464 | int chp_idx) | 464 | int chp_idx) |
465 | { | 465 | { |
466 | struct subchannel *sch; | 466 | struct subchannel *sch; |
467 | struct chp_id chpid; | 467 | struct chp_id chpid; |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index d5b02de02a3a..a337281337a7 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
@@ -98,22 +98,6 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, | |||
98 | return cc; | 98 | return cc; |
99 | } | 99 | } |
100 | 100 | ||
101 | static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) | ||
102 | { | ||
103 | /* all done or next buffer state different */ | ||
104 | if (ccq == 0 || ccq == 32) | ||
105 | return 0; | ||
106 | /* no buffer processed */ | ||
107 | if (ccq == 97) | ||
108 | return 1; | ||
109 | /* not all buffers processed */ | ||
110 | if (ccq == 96) | ||
111 | return 2; | ||
112 | /* notify devices immediately */ | ||
113 | DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); | ||
114 | return -EIO; | ||
115 | } | ||
116 | |||
117 | /** | 101 | /** |
118 | * qdio_do_eqbs - extract buffer states for QEBSM | 102 | * qdio_do_eqbs - extract buffer states for QEBSM |
119 | * @q: queue to manipulate | 103 | * @q: queue to manipulate |
@@ -128,7 +112,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) | |||
128 | static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, | 112 | static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, |
129 | int start, int count, int auto_ack) | 113 | int start, int count, int auto_ack) |
130 | { | 114 | { |
131 | int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0; | 115 | int tmp_count = count, tmp_start = start, nr = q->nr; |
132 | unsigned int ccq = 0; | 116 | unsigned int ccq = 0; |
133 | 117 | ||
134 | qperf_inc(q, eqbs); | 118 | qperf_inc(q, eqbs); |
@@ -138,34 +122,30 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, | |||
138 | again: | 122 | again: |
139 | ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, | 123 | ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, |
140 | auto_ack); | 124 | auto_ack); |
141 | rc = qdio_check_ccq(q, ccq); | ||
142 | if (!rc) | ||
143 | return count - tmp_count; | ||
144 | 125 | ||
145 | if (rc == 1) { | 126 | switch (ccq) { |
146 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); | 127 | case 0: |
147 | goto again; | 128 | case 32: |
148 | } | 129 | /* all done, or next buffer state different */ |
149 | 130 | return count - tmp_count; | |
150 | if (rc == 2) { | 131 | case 96: |
132 | /* not all buffers processed */ | ||
151 | qperf_inc(q, eqbs_partial); | 133 | qperf_inc(q, eqbs_partial); |
152 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x", | 134 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x", |
153 | tmp_count); | 135 | tmp_count); |
154 | /* | 136 | return count - tmp_count; |
155 | * Retry once, if that fails bail out and process the | 137 | case 97: |
156 | * extracted buffers before trying again. | 138 | /* no buffer processed */ |
157 | */ | 139 | DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); |
158 | if (!retried++) | 140 | goto again; |
159 | goto again; | 141 | default: |
160 | else | 142 | DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); |
161 | return count - tmp_count; | 143 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); |
144 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | ||
145 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE, q->nr, | ||
146 | q->first_to_kick, count, q->irq_ptr->int_parm); | ||
147 | return 0; | ||
162 | } | 148 | } |
163 | |||
164 | DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); | ||
165 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | ||
166 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_GET_BUF_STATE, | ||
167 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); | ||
168 | return 0; | ||
169 | } | 149 | } |
170 | 150 | ||
171 | /** | 151 | /** |
@@ -185,7 +165,6 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, | |||
185 | unsigned int ccq = 0; | 165 | unsigned int ccq = 0; |
186 | int tmp_count = count, tmp_start = start; | 166 | int tmp_count = count, tmp_start = start; |
187 | int nr = q->nr; | 167 | int nr = q->nr; |
188 | int rc; | ||
189 | 168 | ||
190 | if (!count) | 169 | if (!count) |
191 | return 0; | 170 | return 0; |
@@ -195,26 +174,32 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, | |||
195 | nr += q->irq_ptr->nr_input_qs; | 174 | nr += q->irq_ptr->nr_input_qs; |
196 | again: | 175 | again: |
197 | ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); | 176 | ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); |
198 | rc = qdio_check_ccq(q, ccq); | 177 | |
199 | if (!rc) { | 178 | switch (ccq) { |
179 | case 0: | ||
180 | case 32: | ||
181 | /* all done, or active buffer adapter-owned */ | ||
200 | WARN_ON_ONCE(tmp_count); | 182 | WARN_ON_ONCE(tmp_count); |
201 | return count - tmp_count; | 183 | return count - tmp_count; |
202 | } | 184 | case 96: |
203 | 185 | /* not all buffers processed */ | |
204 | if (rc == 1 || rc == 2) { | ||
205 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); | 186 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); |
206 | qperf_inc(q, sqbs_partial); | 187 | qperf_inc(q, sqbs_partial); |
207 | goto again; | 188 | goto again; |
189 | default: | ||
190 | DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); | ||
191 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); | ||
192 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | ||
193 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE, q->nr, | ||
194 | q->first_to_kick, count, q->irq_ptr->int_parm); | ||
195 | return 0; | ||
208 | } | 196 | } |
209 | |||
210 | DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); | ||
211 | DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); | ||
212 | q->handler(q->irq_ptr->cdev, QDIO_ERROR_SET_BUF_STATE, | ||
213 | q->nr, q->first_to_kick, count, q->irq_ptr->int_parm); | ||
214 | return 0; | ||
215 | } | 197 | } |
216 | 198 | ||
217 | /* returns number of examined buffers and their common state in *state */ | 199 | /* |
200 | * Returns number of examined buffers and their common state in *state. | ||
201 | * Requested number of buffers-to-examine must be > 0. | ||
202 | */ | ||
218 | static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, | 203 | static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, |
219 | unsigned char *state, unsigned int count, | 204 | unsigned char *state, unsigned int count, |
220 | int auto_ack, int merge_pending) | 205 | int auto_ack, int merge_pending) |
@@ -225,17 +210,23 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, | |||
225 | if (is_qebsm(q)) | 210 | if (is_qebsm(q)) |
226 | return qdio_do_eqbs(q, state, bufnr, count, auto_ack); | 211 | return qdio_do_eqbs(q, state, bufnr, count, auto_ack); |
227 | 212 | ||
228 | for (i = 0; i < count; i++) { | 213 | /* get initial state: */ |
229 | if (!__state) { | 214 | __state = q->slsb.val[bufnr]; |
230 | __state = q->slsb.val[bufnr]; | 215 | if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) |
231 | if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) | 216 | __state = SLSB_P_OUTPUT_EMPTY; |
232 | __state = SLSB_P_OUTPUT_EMPTY; | 217 | |
233 | } else if (merge_pending) { | 218 | for (i = 1; i < count; i++) { |
234 | if ((q->slsb.val[bufnr] & __state) != __state) | ||
235 | break; | ||
236 | } else if (q->slsb.val[bufnr] != __state) | ||
237 | break; | ||
238 | bufnr = next_buf(bufnr); | 219 | bufnr = next_buf(bufnr); |
220 | |||
221 | /* merge PENDING into EMPTY: */ | ||
222 | if (merge_pending && | ||
223 | q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING && | ||
224 | __state == SLSB_P_OUTPUT_EMPTY) | ||
225 | continue; | ||
226 | |||
227 | /* stop if next state differs from initial state: */ | ||
228 | if (q->slsb.val[bufnr] != __state) | ||
229 | break; | ||
239 | } | 230 | } |
240 | *state = __state; | 231 | *state = __state; |
241 | return i; | 232 | return i; |
@@ -502,8 +493,8 @@ static inline void inbound_primed(struct qdio_q *q, int count) | |||
502 | 493 | ||
503 | static int get_inbound_buffer_frontier(struct qdio_q *q) | 494 | static int get_inbound_buffer_frontier(struct qdio_q *q) |
504 | { | 495 | { |
505 | int count, stop; | ||
506 | unsigned char state = 0; | 496 | unsigned char state = 0; |
497 | int count; | ||
507 | 498 | ||
508 | q->timestamp = get_tod_clock_fast(); | 499 | q->timestamp = get_tod_clock_fast(); |
509 | 500 | ||
@@ -512,9 +503,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) | |||
512 | * would return 0. | 503 | * would return 0. |
513 | */ | 504 | */ |
514 | count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); | 505 | count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); |
515 | stop = add_buf(q->first_to_check, count); | 506 | if (!count) |
516 | |||
517 | if (q->first_to_check == stop) | ||
518 | goto out; | 507 | goto out; |
519 | 508 | ||
520 | /* | 509 | /* |
@@ -734,8 +723,8 @@ void qdio_inbound_processing(unsigned long data) | |||
734 | 723 | ||
735 | static int get_outbound_buffer_frontier(struct qdio_q *q) | 724 | static int get_outbound_buffer_frontier(struct qdio_q *q) |
736 | { | 725 | { |
737 | int count, stop; | ||
738 | unsigned char state = 0; | 726 | unsigned char state = 0; |
727 | int count; | ||
739 | 728 | ||
740 | q->timestamp = get_tod_clock_fast(); | 729 | q->timestamp = get_tod_clock_fast(); |
741 | 730 | ||
@@ -751,11 +740,11 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) | |||
751 | * would return 0. | 740 | * would return 0. |
752 | */ | 741 | */ |
753 | count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); | 742 | count = min(atomic_read(&q->nr_buf_used), QDIO_MAX_BUFFERS_MASK); |
754 | stop = add_buf(q->first_to_check, count); | 743 | if (!count) |
755 | if (q->first_to_check == stop) | ||
756 | goto out; | 744 | goto out; |
757 | 745 | ||
758 | count = get_buf_states(q, q->first_to_check, &state, count, 0, 1); | 746 | count = get_buf_states(q, q->first_to_check, &state, count, 0, |
747 | q->u.out.use_cq); | ||
759 | if (!count) | 748 | if (!count) |
760 | goto out; | 749 | goto out; |
761 | 750 | ||
diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index c30420c517b1..ff6963ad6e39 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c | |||
@@ -124,6 +124,11 @@ static void fsm_io_request(struct vfio_ccw_private *private, | |||
124 | if (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) { | 124 | if (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) { |
125 | orb = (union orb *)io_region->orb_area; | 125 | orb = (union orb *)io_region->orb_area; |
126 | 126 | ||
127 | /* Don't try to build a cp if transport mode is specified. */ | ||
128 | if (orb->tm.b) { | ||
129 | io_region->ret_code = -EOPNOTSUPP; | ||
130 | goto err_out; | ||
131 | } | ||
127 | io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev), | 132 | io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev), |
128 | orb); | 133 | orb); |
129 | if (io_region->ret_code) | 134 | if (io_region->ret_code) |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 19203340f879..04fefa5bb08d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -1369,7 +1369,7 @@ static void qeth_set_multiple_write_queues(struct qeth_card *card) | |||
1369 | static void qeth_update_from_chp_desc(struct qeth_card *card) | 1369 | static void qeth_update_from_chp_desc(struct qeth_card *card) |
1370 | { | 1370 | { |
1371 | struct ccw_device *ccwdev; | 1371 | struct ccw_device *ccwdev; |
1372 | struct channel_path_desc *chp_dsc; | 1372 | struct channel_path_desc_fmt0 *chp_dsc; |
1373 | 1373 | ||
1374 | QETH_DBF_TEXT(SETUP, 2, "chp_desc"); | 1374 | QETH_DBF_TEXT(SETUP, 2, "chp_desc"); |
1375 | 1375 | ||
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index e5041c605fd0..0840d27381ea 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig | |||
@@ -11,7 +11,7 @@ if TTY | |||
11 | 11 | ||
12 | config VT | 12 | config VT |
13 | bool "Virtual terminal" if EXPERT | 13 | bool "Virtual terminal" if EXPERT |
14 | depends on !S390 && !UML | 14 | depends on !UML |
15 | select INPUT | 15 | select INPUT |
16 | default y | 16 | default y |
17 | ---help--- | 17 | ---help--- |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3c20af999893..4f950c686055 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -3,7 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | menu "Graphics support" | 5 | menu "Graphics support" |
6 | depends on HAS_IOMEM | 6 | |
7 | if HAS_IOMEM | ||
7 | 8 | ||
8 | config HAVE_FB_ATMEL | 9 | config HAVE_FB_ATMEL |
9 | bool | 10 | bool |
@@ -36,6 +37,8 @@ config VIDEOMODE_HELPERS | |||
36 | config HDMI | 37 | config HDMI |
37 | bool | 38 | bool |
38 | 39 | ||
40 | endif # HAS_IOMEM | ||
41 | |||
39 | if VT | 42 | if VT |
40 | source "drivers/video/console/Kconfig" | 43 | source "drivers/video/console/Kconfig" |
41 | endif | 44 | endif |
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 198574b7dbef..4110ba7d7ca9 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig | |||
@@ -8,7 +8,7 @@ config VGA_CONSOLE | |||
8 | bool "VGA text console" if EXPERT || !X86 | 8 | bool "VGA text console" if EXPERT || !X86 |
9 | depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \ | 9 | depends on !4xx && !PPC_8xx && !SPARC && !M68K && !PARISC && !SUPERH && \ |
10 | (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ | 10 | (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ |
11 | !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 | 11 | !ARM64 && !ARC && !MICROBLAZE && !OPENRISC && !NDS32 && !S390 |
12 | default y | 12 | default y |
13 | help | 13 | help |
14 | Saying Y here will allow you to use Linux in text mode through a | 14 | Saying Y here will allow you to use Linux in text mode through a |
@@ -84,7 +84,7 @@ config MDA_CONSOLE | |||
84 | 84 | ||
85 | config SGI_NEWPORT_CONSOLE | 85 | config SGI_NEWPORT_CONSOLE |
86 | tristate "SGI Newport Console support" | 86 | tristate "SGI Newport Console support" |
87 | depends on SGI_IP22 | 87 | depends on SGI_IP22 && HAS_IOMEM |
88 | select FONT_SUPPORT | 88 | select FONT_SUPPORT |
89 | help | 89 | help |
90 | Say Y here if you want the console on the Newport aka XL graphics | 90 | Say Y here if you want the console on the Newport aka XL graphics |
@@ -152,7 +152,7 @@ config FRAMEBUFFER_CONSOLE_ROTATION | |||
152 | 152 | ||
153 | config STI_CONSOLE | 153 | config STI_CONSOLE |
154 | bool "STI text console" | 154 | bool "STI text console" |
155 | depends on PARISC | 155 | depends on PARISC && HAS_IOMEM |
156 | select FONT_SUPPORT | 156 | select FONT_SUPPORT |
157 | default y | 157 | default y |
158 | help | 158 | help |