diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-12 20:04:08 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-12-12 20:04:08 +0100 |
commit | 47477c84b8914525b427bccbdcded0cf0086f2a1 (patch) | |
tree | 6d23dc9da24d9464612aabe593473509c414833e /drivers/s390 | |
parent | Merge tag 'm68k-for-v6.2-tag1' of git://git.kernel.org/pub/scm/linux/kernel/g... (diff) | |
parent | s390/nmi: get rid of private slab cache (diff) | |
download | linux-47477c84b8914525b427bccbdcded0cf0086f2a1.tar.xz linux-47477c84b8914525b427bccbdcded0cf0086f2a1.zip |
Merge tag 's390-6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Alexander Gordeev:
- Factor out handle_write() function and simplify 3215 console write
operation
- When 3170 terminal emulator is connected to the 3215 console driver
the boot time could be very long due to limited buffer space or
missing operator input. Add con3215_drop command line parameter and
con3215_drop sysfs attribute file to instruct the kernel drop console
data when such conditions are met
- Fix white space errors in 3215 console driver
- Move enum paiext_mode definition to a header file and rename it to
paievt_mode to indicate this is now used for several events. Rename
PAI_MODE_COUNTER to PAI_MODE_COUNTING to make consistent with
PAI_MODE_SAMPLING
- Simplify the logic of PMU pai_crypto mapped buffer reference counter
and make it consistent with PMU pai_ext
- Rename PMU pai_crypto mapped buffer structure member users to
active_events to make it consistent with PMU pai_ext
- Enable HUGETLB_PAGE_OPTIMIZE_VMEMMAP configuration option. This
results in saving of 12K per 1M hugetlb page (~1.2%) and 32764K per
2G hugetlb page (~1.6%)
- Use generic serial.h, bugs.h, shmparam.h and vga.h header files and
scrap s390-specific versions
- The generic percpu setup code does not expect the s390-like
implementation and emits a warning. To get rid of that warning and
provide sane CPU-to-node and CPU-to-CPU distance mappings implementat
a minimal version of setup_per_cpu_areas()
- Use kstrtobool() instead of strtobool() for re-IPL sysfs device
attributes
- Avoid unnecessary lookup of a pointer to MSI descriptor when setting
IRQ affinity for a PCI device
- Get rid of "an incompatible function type cast" warning by changing
debug_sprintf_format_fn() function prototype so it matches the
debug_format_proc_t function type
- Remove unused info_blk_hdr__pcpus() and get_page_state() functions
- Get rid of clang "unused unused insn cache ops function" warning by
moving s390_insn definition to a private header
- Get rid of clang "unused function" warning by making function
raw3270_state_final() only available if CONFIG_TN3270_CONSOLE is
enabled
- Use kstrobool() to parse sclp_con_drop parameter to make it identical
to the con3215_drop parameter and allow passing values like "yes" and
"true"
- Use sysfs_emit() for all SCLP sysfs show functions, which is the
current standard way to generate output strings
- Make SCLP con_drop sysfs attribute also writable and allow to change
its value during runtime. This makes SCLP console drop handling
consistent with the 3215 device driver
- Virtual and physical addresses are indentical on s390. However, there
is still a confusion when pointers are directly casted to physical
addresses or vice versa. Use correct address converters
virt_to_phys() and phys_to_virt() for s390 channel IO drivers
- Support for power managemant has been removed from s390 since quite
some time. Remove unused power managemant code from the appldata
device driver
- Allow memory tools like KASAN see memory accesses from the checksum
code. Switch to GENERIC_CSUM if KASAN is enabled, just like x86 does
- Add support of ECKD DASDs disks so it could be used as boot and dump
devices
- Follow checkpatch recommendations and use octal values instead of
S_IRUGO and S_IWUSR for dump device attributes in sysfs
- Changes to vx-insn.h do not cause a recompile of C files that use
asm(".include \"asm/vx-insn.h\"\n") magic to access vector
instruction macros from inline assemblies. Add wrapper include header
file to avoid this problem
- Use vector instruction macros instead of byte patterns to increase
register validation routine readability
- The current machine check register validation handling does not take
into account various scenarios and might lead to killing a wrong user
process or potentially ignore corrupted FPU registers. Simplify logic
of the machine check handler and stop the whole machine if the
previous context was kerenel mode. If the previous context was user
mode, kill the current task
- Introduce sclp_emergency_printk() function which can be used to emit
a message in emergency cases. It is supposed to be used in cases
where regular console device drivers may not work anymore, e.g.
unrecoverable machine checks
Keep the early Service-Call Control Block so it can also be used
after initdata has been freed to allow sclp_emergency_printk()
implementation
- In case a system will be stopped because of an unrecoverable machine
check error print the machine check interruption code to give a hint
of what went wrong
- Move storage error checking from the assembly entry code to C in
order to simplify machine check handling. Enter the handler with DAT
turned on, which simplifies the entry code even more
- The machine check extended save areas are allocated using a private
"nmi_save_areas" slab cache which guarantees a required power-of-two
alignment. Get rid of that cache in favour of kmalloc()
* tag 's390-6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (38 commits)
s390/nmi: get rid of private slab cache
s390/nmi: move storage error checking back to C, enter with DAT on
s390/nmi: print machine check interruption code before stopping system
s390/sclp: introduce sclp_emergency_printk()
s390/sclp: keep sclp_early_sccb
s390/nmi: rework register validation handling
s390/nmi: use vector instruction macros instead of byte patterns
s390/vx: add vx-insn.h wrapper include file
s390/ipl: use octal values instead of S_* macros
s390/ipl: add eckd dump support
s390/ipl: add eckd support
vfio/ccw: identify CCW data addresses as physical
vfio/ccw: sort out physical vs virtual pointers usage
s390/checksum: support GENERIC_CSUM, enable it for KASAN
s390/appldata: remove power management callbacks
s390/cio: sort out physical vs virtual pointers usage
s390/sclp: allow to change sclp_console_drop during runtime
s390/sclp: convert to use sysfs_emit()
s390/sclp: use kstrobool() to parse sclp_con_drop parameter
s390/3270: make raw3270_state_final() depend on CONFIG_TN3270_CONSOLE
...
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/char/con3215.c | 275 | ||||
-rw-r--r-- | drivers/s390/char/raw3270.c | 12 | ||||
-rw-r--r-- | drivers/s390/char/sclp.c | 25 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_early.c | 4 | ||||
-rw-r--r-- | drivers/s390/char/sclp_early_core.c | 26 | ||||
-rw-r--r-- | drivers/s390/char/zcore.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/chsc_sch.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/cio.c | 14 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 11 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/eadm_sch.c | 9 | ||||
-rw-r--r-- | drivers/s390/cio/fcx.c | 23 | ||||
-rw-r--r-- | drivers/s390/cio/itcw.c | 3 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_cp.c | 4 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_fsm.c | 2 |
19 files changed, 277 insertions, 160 deletions
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 4ae07c7e2175..72ba83c1bc79 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -102,6 +102,7 @@ static struct raw3215_req *raw3215_freelist; static DEFINE_SPINLOCK(raw3215_freelist_lock); static struct tty_driver *tty3215_driver; +static bool con3215_drop = true; /* * Get a request structure from the free list @@ -159,7 +160,7 @@ static void raw3215_mk_read_req(struct raw3215_info *raw) ccw->cmd_code = 0x0A; /* read inquiry */ ccw->flags = 0x20; /* ignore incorrect length */ ccw->count = 160; - ccw->cda = (__u32) __pa(raw->inbuf); + ccw->cda = (__u32)__pa(raw->inbuf); } /* @@ -218,8 +219,7 @@ static void raw3215_mk_write_req(struct raw3215_info *raw) ccw[-1].flags |= 0x40; /* use command chaining */ ccw->cmd_code = 0x01; /* write, auto carrier return */ ccw->flags = 0x20; /* ignore incorrect length ind. */ - ccw->cda = - (__u32) __pa(raw->buffer + ix); + ccw->cda = (__u32)__pa(raw->buffer + ix); count = len; if (ix + count > RAW3215_BUFFER_SIZE) count = RAW3215_BUFFER_SIZE - ix; @@ -447,13 +447,45 @@ put_tty: } /* + * Need to drop data to avoid blocking. Drop as much data as possible. + * This is unqueued part in the buffer and the queued part in the request. + * Also adjust the head position to append new data and set count + * accordingly. + * + * Return number of bytes available in buffer. + */ +static unsigned int raw3215_drop(struct raw3215_info *raw) +{ + struct raw3215_req *req; + + req = raw->queued_write; + if (req) { + /* Drop queued data and delete request */ + raw->written -= req->len; + raw3215_free_req(req); + raw->queued_write = NULL; + } + raw->head = (raw->head - raw->count + raw->written) & + (RAW3215_BUFFER_SIZE - 1); + raw->count = raw->written; + + return RAW3215_BUFFER_SIZE - raw->count; +} + +/* * Wait until length bytes are available int the output buffer. + * If drop mode is active and wait condition holds true, start dropping + * data. * Has to be called with the s390irq lock held. Can be called * disabled. */ -static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) +static unsigned int raw3215_make_room(struct raw3215_info *raw, + unsigned int length, bool drop) { while (RAW3215_BUFFER_SIZE - raw->count < length) { + if (drop) + return raw3215_drop(raw); + /* there might be a request pending */ raw->flags |= RAW3215_FLUSHING; raw3215_mk_write_req(raw); @@ -470,75 +502,89 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) udelay(100); spin_lock(get_ccwdev_lock(raw->cdev)); } + return length; } +#define RAW3215_COUNT 1 +#define RAW3215_STORE 2 + /* - * String write routine for 3215 devices + * Add text to console buffer. Find tabs in input and calculate size + * including tab replacement. + * This function operates in 2 different modes, depending on parameter + * opmode: + * RAW3215_COUNT: Get the size needed for the input string with + * proper tab replacement calculation. + * Return value is the number of bytes required to store the + * input. However no data is actually stored. + * The parameter todrop is not used. + * RAW3215_STORE: Add data to the console buffer. The parameter todrop is + * valid and contains the number of bytes to be dropped from head of + * string without blocking. + * Return value is the number of bytes copied. */ -static void raw3215_write(struct raw3215_info *raw, const char *str, - unsigned int length) +static unsigned int raw3215_addtext(const char *str, unsigned int length, + struct raw3215_info *raw, int opmode, + unsigned int todrop) { - unsigned long flags; - int c, count; + unsigned int c, ch, i, blanks, expanded_size = 0; + unsigned int column = raw->line_pos; - while (length > 0) { - spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); - count = (length > RAW3215_BUFFER_SIZE) ? - RAW3215_BUFFER_SIZE : length; - length -= count; - - raw3215_make_room(raw, count); - - /* copy string to output buffer and convert it to EBCDIC */ - while (1) { - c = min_t(int, count, - min(RAW3215_BUFFER_SIZE - raw->count, - RAW3215_BUFFER_SIZE - raw->head)); - if (c <= 0) - break; - memcpy(raw->buffer + raw->head, str, c); - ASCEBC(raw->buffer + raw->head, c); - raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); - raw->count += c; - raw->line_pos += c; - str += c; - count -= c; + if (opmode == RAW3215_COUNT) + todrop = 0; + + for (c = 0; c < length; ++c) { + blanks = 1; + ch = str[c]; + + switch (ch) { + case '\n': + expanded_size++; + column = 0; + break; + case '\t': + blanks = TAB_STOP_SIZE - (column % TAB_STOP_SIZE); + column += blanks; + expanded_size += blanks; + ch = ' '; + break; + default: + expanded_size++; + column++; + break; } - if (!(raw->flags & RAW3215_WORKING)) { - raw3215_mk_write_req(raw); - /* start or queue request */ - raw3215_try_io(raw); + + if (opmode == RAW3215_COUNT) + continue; + if (todrop && expanded_size < todrop) /* Drop head data */ + continue; + for (i = 0; i < blanks; i++) { + raw->buffer[raw->head] = (char)_ascebc[(int)ch]; + raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); + raw->count++; } - spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + raw->line_pos = column; } + return expanded_size - todrop; } /* - * Put character routine for 3215 devices + * String write routine for 3215 devices */ -static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) +static void raw3215_write(struct raw3215_info *raw, const char *str, + unsigned int length) { + unsigned int count, avail; unsigned long flags; - unsigned int length, i; spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); - if (ch == '\t') { - length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); - raw->line_pos += length; - ch = ' '; - } else if (ch == '\n') { - length = 1; - raw->line_pos = 0; - } else { - length = 1; - raw->line_pos++; - } - raw3215_make_room(raw, length); - for (i = 0; i < length; i++) { - raw->buffer[raw->head] = (char) _ascebc[(int) ch]; - raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); - raw->count++; + count = raw3215_addtext(str, length, raw, RAW3215_COUNT, 0); + + avail = raw3215_make_room(raw, count, con3215_drop); + if (avail) { + raw3215_addtext(str, length, raw, RAW3215_STORE, + count - avail); } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); @@ -549,6 +595,14 @@ static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) } /* + * Put character routine for 3215 devices + */ +static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) +{ + raw3215_write(raw, &ch, 1); +} + +/* * Flush routine, it simply sets the flush flag and tries to start * pending IO. */ @@ -642,7 +696,7 @@ static void raw3215_free_info(struct raw3215_info *raw) kfree(raw); } -static int raw3215_probe (struct ccw_device *cdev) +static int raw3215_probe(struct ccw_device *cdev) { struct raw3215_info *raw; int line; @@ -675,7 +729,7 @@ static int raw3215_probe (struct ccw_device *cdev) return 0; } -static void raw3215_remove (struct ccw_device *cdev) +static void raw3215_remove(struct ccw_device *cdev) { struct raw3215_info *raw; unsigned int line; @@ -694,7 +748,7 @@ static void raw3215_remove (struct ccw_device *cdev) } } -static int raw3215_set_online (struct ccw_device *cdev) +static int raw3215_set_online(struct ccw_device *cdev) { struct raw3215_info *raw; @@ -705,7 +759,7 @@ static int raw3215_set_online (struct ccw_device *cdev) return raw3215_startup(raw); } -static int raw3215_set_offline (struct ccw_device *cdev) +static int raw3215_set_offline(struct ccw_device *cdev) { struct raw3215_info *raw; @@ -723,9 +777,43 @@ static struct ccw_device_id raw3215_id[] = { { /* end of list */ }, }; +static ssize_t con_drop_store(struct device_driver *dev, const char *buf, size_t count) +{ + bool drop; + int rc; + + rc = kstrtobool(buf, &drop); + if (!rc) + con3215_drop = drop; + return rc ?: count; +} + +static ssize_t con_drop_show(struct device_driver *dev, char *buf) +{ + return sysfs_emit(buf, "%d\n", con3215_drop ? 1 : 0); +} + +static DRIVER_ATTR_RW(con_drop); + +static struct attribute *con3215_drv_attrs[] = { + &driver_attr_con_drop.attr, + NULL, +}; + +static struct attribute_group con3215_drv_attr_group = { + .attrs = con3215_drv_attrs, + NULL, +}; + +static const struct attribute_group *con3215_drv_attr_groups[] = { + &con3215_drv_attr_group, + NULL, +}; + static struct ccw_driver raw3215_ccw_driver = { .driver = { .name = "3215", + .groups = con3215_drv_attr_groups, .owner = THIS_MODULE, }, .ids = raw3215_id, @@ -736,34 +824,27 @@ static struct ccw_driver raw3215_ccw_driver = { .int_class = IRQIO_C15, }; -#ifdef CONFIG_TN3215_CONSOLE -/* - * Write a string to the 3215 console - */ -static void con3215_write(struct console *co, const char *str, - unsigned int count) +static void handle_write(struct raw3215_info *raw, const char *str, int count) { - struct raw3215_info *raw; int i; - if (count <= 0) - return; - raw = raw3215[0]; /* console 3215 is the first one */ while (count > 0) { - for (i = 0; i < count; i++) - if (str[i] == '\t' || str[i] == '\n') - break; + i = min_t(int, count, RAW3215_BUFFER_SIZE - 1); raw3215_write(raw, str, i); count -= i; str += i; - if (count > 0) { - raw3215_putchar(raw, *str); - count--; - str++; - } } } +#ifdef CONFIG_TN3215_CONSOLE +/* + * Write a string to the 3215 console + */ +static void con3215_write(struct console *co, const char *str, unsigned int count) +{ + handle_write(raw3215[0], str, count); +} + static struct tty_driver *con3215_device(struct console *c, int *index) { *index = c->index; @@ -787,7 +868,7 @@ static int con3215_notify(struct notifier_block *self, raw = raw3215[0]; /* console 3215 is the first one */ if (!spin_trylock_irqsave(get_ccwdev_lock(raw->cdev), flags)) return NOTIFY_DONE; - raw3215_make_room(raw, RAW3215_BUFFER_SIZE); + raw3215_make_room(raw, RAW3215_BUFFER_SIZE, false); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); return NOTIFY_DONE; @@ -940,27 +1021,11 @@ static unsigned int tty3215_write_room(struct tty_struct *tty) /* * String write routine for 3215 ttys */ -static int tty3215_write(struct tty_struct * tty, +static int tty3215_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct raw3215_info *raw = tty->driver_data; - int i, written; - - written = count; - while (count > 0) { - for (i = 0; i < count; i++) - if (buf[i] == '\t' || buf[i] == '\n') - break; - raw3215_write(raw, buf, i); - count -= i; - buf += i; - if (count > 0) { - raw3215_putchar(raw, *buf); - count--; - buf++; - } - } - return written; + handle_write(tty->driver_data, buf, count); + return count; } /* @@ -1000,7 +1065,7 @@ static void tty3215_flush_buffer(struct tty_struct *tty) /* * Disable reading from a 3215 tty */ -static void tty3215_throttle(struct tty_struct * tty) +static void tty3215_throttle(struct tty_struct *tty) { struct raw3215_info *raw = tty->driver_data; @@ -1010,7 +1075,7 @@ static void tty3215_throttle(struct tty_struct * tty) /* * Enable reading from a 3215 tty */ -static void tty3215_unthrottle(struct tty_struct * tty) +static void tty3215_unthrottle(struct tty_struct *tty) { struct raw3215_info *raw = tty->driver_data; unsigned long flags; @@ -1065,6 +1130,18 @@ static const struct tty_operations tty3215_ops = { .start = tty3215_start, }; +static int __init con3215_setup_drop(char *str) +{ + bool drop; + int rc; + + rc = kstrtobool(str, &drop); + if (!rc) + con3215_drop = drop; + return rc; +} +early_param("con3215_drop", con3215_setup_drop); + /* * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 4e2b3a1a3b2e..fb3f62ac8be4 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -111,12 +111,6 @@ static inline int raw3270_state_ready(struct raw3270 *rp) return rp->state == RAW3270_STATE_READY; } -static inline int raw3270_state_final(struct raw3270 *rp) -{ - return rp->state == RAW3270_STATE_INIT || - rp->state == RAW3270_STATE_READY; -} - void raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr) { @@ -749,6 +743,12 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) /* Tentative definition - see below for actual definition. */ static struct ccw_driver raw3270_ccw_driver; +static inline int raw3270_state_final(struct raw3270 *rp) +{ + return rp->state == RAW3270_STATE_INIT || + rp->state == RAW3270_STATE_READY; +} + /* * Setup 3270 device configured as console. */ diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index ae1d6ee382a5..8f74db689a0c 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -69,7 +69,7 @@ static struct init_sccb *sclp_init_sccb; /* Number of console pages to allocate, used by sclp_con.c and sclp_vt220.c */ int sclp_console_pages = SCLP_CONSOLE_PAGES; /* Flag to indicate if buffer pages are dropped on buffer full condition */ -int sclp_console_drop = 1; +bool sclp_console_drop = true; /* Number of times the console dropped buffer pages */ unsigned long sclp_console_full; @@ -195,12 +195,7 @@ __setup("sclp_con_pages=", sclp_setup_console_pages); static int __init sclp_setup_console_drop(char *str) { - int drop, rc; - - rc = kstrtoint(str, 0, &drop); - if (!rc) - sclp_console_drop = drop; - return 1; + return kstrtobool(str, &sclp_console_drop) == 0; } __setup("sclp_con_drop=", sclp_setup_console_drop); @@ -1205,21 +1200,29 @@ static struct notifier_block sclp_reboot_notifier = { static ssize_t con_pages_show(struct device_driver *dev, char *buf) { - return sprintf(buf, "%i\n", sclp_console_pages); + return sysfs_emit(buf, "%i\n", sclp_console_pages); } static DRIVER_ATTR_RO(con_pages); +static ssize_t con_drop_store(struct device_driver *dev, const char *buf, size_t count) +{ + int rc; + + rc = kstrtobool(buf, &sclp_console_drop); + return rc ?: count; +} + static ssize_t con_drop_show(struct device_driver *dev, char *buf) { - return sprintf(buf, "%i\n", sclp_console_drop); + return sysfs_emit(buf, "%i\n", sclp_console_drop); } -static DRIVER_ATTR_RO(con_drop); +static DRIVER_ATTR_RW(con_drop); static ssize_t con_full_show(struct device_driver *dev, char *buf) { - return sprintf(buf, "%lu\n", sclp_console_full); + return sysfs_emit(buf, "%lu\n", sclp_console_full); } static DRIVER_ATTR_RO(con_full); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 86dd2cde0f78..909ba7f08688 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -307,7 +307,7 @@ enum { extern int sclp_init_state; extern int sclp_console_pages; -extern int sclp_console_drop; +extern bool sclp_console_drop; extern unsigned long sclp_console_full; extern bool sclp_mask_compat_mode; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index d15b0d541de3..c1c70a161c0e 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -57,8 +57,10 @@ static void __init sclp_early_facilities_detect(void) sclp.has_diag318 = !!(sccb->byte_134 & 0x80); sclp.has_iplcc = !!(sccb->byte_134 & 0x02); } - if (sccb->cpuoff > 137) + if (sccb->cpuoff > 137) { sclp.has_sipl = !!(sccb->cbl & 0x4000); + sclp.has_sipl_eckd = !!(sccb->cbl & 0x2000); + } sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; sclp.rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; sclp.rzm <<= 20; diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 676634de65a8..ac1d00980fa6 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -17,7 +17,7 @@ static struct read_info_sccb __bootdata(sclp_info_sccb); static int __bootdata(sclp_info_sccb_valid); -char *__bootdata(sclp_early_sccb); +char *__bootdata_preserved(sclp_early_sccb); int sclp_init_state = sclp_init_state_uninitialized; /* * Used to keep track of the size of the event masks. Qemu until version 2.11 @@ -241,6 +241,30 @@ void sclp_early_printk(const char *str) } /* + * Use sclp_emergency_printk() to print a string when the system is in a + * state where regular console drivers cannot be assumed to work anymore. + * + * Callers must make sure that no concurrent SCLP requests are outstanding + * and all other CPUs are stopped, or at least disabled for external + * interrupts. + */ +void sclp_emergency_printk(const char *str) +{ + int have_linemode, have_vt220; + unsigned int len; + + len = strlen(str); + /* + * Don't care about return values; if requests fail, just ignore and + * continue to have a rather high chance that anything is printed. + */ + sclp_early_setup(0, &have_linemode, &have_vt220); + sclp_early_print_lm(str, len); + sclp_early_print_vt220(str, len); + sclp_early_setup(1, &have_linemode, &have_vt220); +} + +/* * We can't pass sclp_info_sccb to sclp_early_cmd() here directly, * because it might not fulfil the requiremets for a SCLP communication buffer: * - lie below 2G in memory diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 6165e6aae762..b30670ca6e5d 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -282,6 +282,10 @@ static int __init zcore_init(void) TRACE("type: nvme\n"); TRACE("fid: %x\n", ipl_info.data.nvme.fid); TRACE("nsid: %x\n", ipl_info.data.nvme.nsid); + } else if (ipl_info.type == IPL_TYPE_ECKD_DUMP) { + TRACE("type: eckd\n"); + TRACE("devno: %x\n", ipl_info.data.eckd.dev_id.devno); + TRACE("ssid: %x\n", ipl_info.data.eckd.dev_id.ssid); } rc = sclp_sdias_init(); diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 962dfa25a310..180ab899289c 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/compat.h> #include <linux/device.h> +#include <linux/io.h> #include <linux/module.h> #include <linux/uaccess.h> #include <linux/miscdevice.h> @@ -85,7 +86,7 @@ static int chsc_subchannel_probe(struct subchannel *sch) if (!private) return -ENOMEM; dev_set_drvdata(&sch->dev, private); - ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); + ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); if (ret) { CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n", sch->schid.ssid, sch->schid.sch_no, ret); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 923f5ca4f5e6..6127add746d1 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -134,7 +134,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ memset(orb, 0, sizeof(union orb)); /* sch is always under 2G. */ - orb->cmd.intparm = (u32)(addr_t)sch; + orb->cmd.intparm = (u32)virt_to_phys(sch); orb->cmd.fmt = 1; orb->cmd.pfch = priv->options.prefetch == 0; @@ -148,7 +148,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ orb->cmd.i2k = 0; orb->cmd.key = key >> 4; /* issue "Start Subchannel" */ - orb->cmd.cpa = (__u32) __pa(cpa); + orb->cmd.cpa = (u32)virt_to_phys(cpa); ccode = ssch(sch->schid, orb); /* process condition code */ @@ -539,13 +539,13 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy) tpi_info = &get_irq_regs()->tpi_info; trace_s390_cio_interrupt(tpi_info); irb = this_cpu_ptr(&cio_irb); - sch = (struct subchannel *)(unsigned long) tpi_info->intparm; - if (!sch) { + if (!tpi_info->intparm) { /* Clear pending interrupt condition. */ inc_irq_stat(IRQIO_CIO); tsch(tpi_info->schid, irb); return IRQ_HANDLED; } + sch = phys_to_virt(tpi_info->intparm); spin_lock(sch->lock); /* Store interrupt response block to lowcore. */ if (tsch(tpi_info->schid, irb) == 0) { @@ -666,7 +666,7 @@ struct subchannel *cio_probe_console(void) lockdep_set_class(sch->lock, &console_sch_key); isc_register(CONSOLE_ISC); sch->config.isc = CONSOLE_ISC; - sch->config.intparm = (u32)(addr_t)sch; + sch->config.intparm = (u32)virt_to_phys(sch); ret = cio_commit_config(sch); if (ret) { isc_unregister(CONSOLE_ISC); @@ -713,11 +713,11 @@ int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key) union orb *orb = &to_io_private(sch)->orb; memset(orb, 0, sizeof(union orb)); - orb->tm.intparm = (u32) (addr_t) sch; + orb->tm.intparm = (u32)virt_to_phys(sch); orb->tm.key = key >> 4; orb->tm.b = 1; orb->tm.lpm = lpm ? lpm : sch->lpm; - orb->tm.tcw = (u32) (addr_t) tcw; + orb->tm.tcw = (u32)virt_to_phys(tcw); cc = ssch(sch->schid, orb); switch (cc) { case 0: diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 3b1cd0c96a74..9e0cf44ff9d4 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -936,7 +936,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev, if (old_enabled) { /* Try to reenable the old subchannel. */ spin_lock_irq(old_sch->lock); - cio_enable_subchannel(old_sch, (u32)(addr_t)old_sch); + cio_enable_subchannel(old_sch, (u32)virt_to_phys(old_sch)); spin_unlock_irq(old_sch->lock); } /* Release child reference for new parent. */ diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 6d63b968309a..2b2058427a2b 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/jiffies.h> #include <linux/string.h> @@ -63,7 +64,7 @@ static void ccw_timeout_log(struct ccw_device *cdev) printk(KERN_WARNING "cio: orb indicates transport mode\n"); printk(KERN_WARNING "cio: last tcw:\n"); print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - (void *)(addr_t)orb->tm.tcw, + phys_to_virt(orb->tm.tcw), sizeof(struct tcw), 0); } else { printk(KERN_WARNING "cio: orb indicates command mode\n"); @@ -77,7 +78,7 @@ static void ccw_timeout_log(struct ccw_device *cdev) printk(KERN_WARNING "cio: last channel program:\n"); print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - (void *)(addr_t)orb->cmd.cpa, + phys_to_virt(orb->cmd.cpa), sizeof(struct ccw1), 0); } printk(KERN_WARNING "cio: ccw device state: %d\n", @@ -397,7 +398,7 @@ void ccw_device_recognition(struct ccw_device *cdev) */ cdev->private->flags.recog_done = 0; cdev->private->state = DEV_STATE_SENSE_ID; - if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) { + if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch))) { ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER); return; } @@ -548,7 +549,7 @@ ccw_device_online(struct ccw_device *cdev) (cdev->private->state != DEV_STATE_BOXED)) return -EINVAL; sch = to_subchannel(cdev->dev.parent); - ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); + ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); if (ret != 0) { /* Couldn't enable the subchannel for i/o. Sick device. */ if (ret == -ENODEV) @@ -691,7 +692,7 @@ static void ccw_device_boxed_verify(struct ccw_device *cdev, struct subchannel *sch = to_subchannel(cdev->dev.parent); if (cdev->online) { - if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) + if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch))) ccw_device_done(cdev, DEV_STATE_NOT_OPER); else ccw_device_online_verify(cdev, dev_event); @@ -922,7 +923,7 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); - if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0) + if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)) != 0) /* Couldn't enable the subchannel for i/o. Sick device. */ return; cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID; diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 7835a87a60b5..ce99ee2457e6 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -210,7 +210,7 @@ void ccw_device_sense_id_start(struct ccw_device *cdev) snsid_init(cdev); /* Channel program setup. */ cp->cmd_code = CCW_CMD_SENSE_ID; - cp->cda = (u32) (addr_t) &cdev->private->dma_area->senseid; + cp->cda = (u32)virt_to_phys(&cdev->private->dma_area->senseid); cp->count = sizeof(struct senseid); cp->flags = CCW_FLAG_SLI; /* Request setup. */ diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 767a85635a0f..3862961697eb 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/slab.h> +#include <linux/io.h> #include <asm/ccwdev.h> #include <asm/cio.h> @@ -140,7 +141,7 @@ static void spid_build_cp(struct ccw_device *cdev, u8 fn) pgid->inf.fc = fn; cp->cmd_code = CCW_CMD_SET_PGID; - cp->cda = (u32) (addr_t) pgid; + cp->cda = (u32)virt_to_phys(pgid); cp->count = sizeof(*pgid); cp->flags = CCW_FLAG_SLI; req->cp = cp; @@ -441,7 +442,7 @@ static void snid_build_cp(struct ccw_device *cdev) /* Channel program setup. */ cp->cmd_code = CCW_CMD_SENSE_PGID; - cp->cda = (u32) (addr_t) &cdev->private->dma_area->pgid[i]; + cp->cda = (u32)virt_to_phys(&cdev->private->dma_area->pgid[i]); cp->count = sizeof(struct pgid); cp->flags = CCW_FLAG_SLI; req->cp = cp; @@ -631,11 +632,11 @@ static void stlck_build_cp(struct ccw_device *cdev, void *buf1, void *buf2) struct ccw1 *cp = cdev->private->dma_area->iccws; cp[0].cmd_code = CCW_CMD_STLCK; - cp[0].cda = (u32) (addr_t) buf1; + cp[0].cda = (u32)virt_to_phys(buf1); cp[0].count = 32; cp[0].flags = CCW_FLAG_CC; cp[1].cmd_code = CCW_CMD_RELEASE; - cp[1].cda = (u32) (addr_t) buf2; + cp[1].cda = (u32)virt_to_phys(buf2); cp[1].count = 32; cp[1].flags = 0; req->cp = cp; @@ -698,7 +699,7 @@ int ccw_device_stlck(struct ccw_device *cdev) init_completion(&data.done); data.rc = -EIO; spin_lock_irq(sch->lock); - rc = cio_enable_subchannel(sch, (u32) (addr_t) sch); + rc = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); if (rc) goto out_unlock; /* Perform operation. */ diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 0bd8f2642732..6c2e35065fec 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/io.h> #include <asm/ccwdev.h> #include <asm/cio.h> @@ -331,7 +332,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) */ sense_ccw = &to_io_private(sch)->dma_area->sense_ccw; sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE; - sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw); + sense_ccw->cda = virt_to_phys(cdev->private->dma_area->irb.ecw); sense_ccw->count = SENSE_MAX_COUNT; sense_ccw->flags = CCW_FLAG_SLI; diff --git a/drivers/s390/cio/eadm_sch.c b/drivers/s390/cio/eadm_sch.c index ab6a7495180a..826364d2facd 100644 --- a/drivers/s390/cio/eadm_sch.c +++ b/drivers/s390/cio/eadm_sch.c @@ -15,6 +15,7 @@ #include <linux/timer.h> #include <linux/slab.h> #include <linux/list.h> +#include <linux/io.h> #include <asm/css_chars.h> #include <asm/debug.h> @@ -62,8 +63,8 @@ static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob) int cc; orb_init(orb); - orb->eadm.aob = (u32)__pa(aob); - orb->eadm.intparm = (u32)(addr_t)sch; + orb->eadm.aob = (u32)virt_to_phys(aob); + orb->eadm.intparm = (u32)virt_to_phys(sch); orb->eadm.key = PAGE_DEFAULT_KEY >> 4; EADM_LOG(6, "start"); @@ -146,7 +147,7 @@ static void eadm_subchannel_irq(struct subchannel *sch) css_sched_sch_todo(sch, SCH_TODO_EVAL); return; } - scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error); + scm_irq_handler(phys_to_virt(scsw->aob), error); private->state = EADM_IDLE; if (private->completion) @@ -225,7 +226,7 @@ static int eadm_subchannel_probe(struct subchannel *sch) private->state = EADM_IDLE; private->sch = sch; sch->isc = EADM_SCH_ISC; - ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); + ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch)); if (ret) { set_eadm_private(sch, NULL); spin_unlock_irq(sch->lock); diff --git a/drivers/s390/cio/fcx.c b/drivers/s390/cio/fcx.c index 99c900cc3e5b..84f24a2f46e4 100644 --- a/drivers/s390/cio/fcx.c +++ b/drivers/s390/cio/fcx.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h> +#include <linux/io.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/module.h> @@ -24,7 +25,7 @@ */ struct tcw *tcw_get_intrg(struct tcw *tcw) { - return (struct tcw *) ((addr_t) tcw->intrg); + return phys_to_virt(tcw->intrg); } EXPORT_SYMBOL(tcw_get_intrg); @@ -39,9 +40,9 @@ EXPORT_SYMBOL(tcw_get_intrg); void *tcw_get_data(struct tcw *tcw) { if (tcw->r) - return (void *) ((addr_t) tcw->input); + return phys_to_virt(tcw->input); if (tcw->w) - return (void *) ((addr_t) tcw->output); + return phys_to_virt(tcw->output); return NULL; } EXPORT_SYMBOL(tcw_get_data); @@ -54,7 +55,7 @@ EXPORT_SYMBOL(tcw_get_data); */ struct tccb *tcw_get_tccb(struct tcw *tcw) { - return (struct tccb *) ((addr_t) tcw->tccb); + return phys_to_virt(tcw->tccb); } EXPORT_SYMBOL(tcw_get_tccb); @@ -66,7 +67,7 @@ EXPORT_SYMBOL(tcw_get_tccb); */ struct tsb *tcw_get_tsb(struct tcw *tcw) { - return (struct tsb *) ((addr_t) tcw->tsb); + return phys_to_virt(tcw->tsb); } EXPORT_SYMBOL(tcw_get_tsb); @@ -189,7 +190,7 @@ EXPORT_SYMBOL(tcw_finalize); */ void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw) { - tcw->intrg = (u32) ((addr_t) intrg_tcw); + tcw->intrg = (u32)virt_to_phys(intrg_tcw); } EXPORT_SYMBOL(tcw_set_intrg); @@ -207,11 +208,11 @@ EXPORT_SYMBOL(tcw_set_intrg); void tcw_set_data(struct tcw *tcw, void *data, int use_tidal) { if (tcw->r) { - tcw->input = (u64) ((addr_t) data); + tcw->input = virt_to_phys(data); if (use_tidal) tcw->flags |= TCW_FLAGS_INPUT_TIDA; } else if (tcw->w) { - tcw->output = (u64) ((addr_t) data); + tcw->output = virt_to_phys(data); if (use_tidal) tcw->flags |= TCW_FLAGS_OUTPUT_TIDA; } @@ -227,7 +228,7 @@ EXPORT_SYMBOL(tcw_set_data); */ void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb) { - tcw->tccb = (u64) ((addr_t) tccb); + tcw->tccb = virt_to_phys(tccb); } EXPORT_SYMBOL(tcw_set_tccb); @@ -240,7 +241,7 @@ EXPORT_SYMBOL(tcw_set_tccb); */ void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb) { - tcw->tsb = (u64) ((addr_t) tsb); + tcw->tsb = virt_to_phys(tsb); } EXPORT_SYMBOL(tcw_set_tsb); @@ -345,7 +346,7 @@ struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags, memset(tidaw, 0, sizeof(struct tidaw)); tidaw->flags = flags; tidaw->count = count; - tidaw->addr = (u64) ((addr_t) addr); + tidaw->addr = virt_to_phys(addr); return tidaw; } EXPORT_SYMBOL(tcw_add_tidaw); diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c index 19e46363348c..dbd3099c520e 100644 --- a/drivers/s390/cio/itcw.c +++ b/drivers/s390/cio/itcw.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/string.h> +#include <linux/io.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/module.h> @@ -187,7 +188,7 @@ struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, /* Check for 2G limit. */ start = (addr_t) buffer; end = start + size; - if (end > (1 << 31)) + if ((virt_to_phys(buffer) + size) > (1 << 31)) return ERR_PTR(-EINVAL); memset(buffer, 0, size); /* ITCW. */ diff --git a/drivers/s390/cio/vfio_ccw_cp.c b/drivers/s390/cio/vfio_ccw_cp.c index 7b02e97f4b29..c0a09fa8991a 100644 --- a/drivers/s390/cio/vfio_ccw_cp.c +++ b/drivers/s390/cio/vfio_ccw_cp.c @@ -394,7 +394,7 @@ static void ccwchain_cda_free(struct ccwchain *chain, int idx) if (ccw_is_tic(ccw)) return; - kfree((void *)(u64)ccw->cda); + kfree(phys_to_virt(ccw->cda)); } /** @@ -845,7 +845,7 @@ union orb *cp_get_orb(struct channel_program *cp, u32 intparm, u8 lpm) chain = list_first_entry(&cp->ccwchain_list, struct ccwchain, next); cpa = chain->ch_ccw; - orb->cmd.cpa = (__u32) __pa(cpa); + orb->cmd.cpa = (__u32)virt_to_phys(cpa); return orb; } diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index a59c758869f8..0a5e8b4a6743 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -29,7 +29,7 @@ static int fsm_io_helper(struct vfio_ccw_private *private) spin_lock_irqsave(sch->lock, flags); - orb = cp_get_orb(&private->cp, (u32)(addr_t)sch, sch->lpm); + orb = cp_get_orb(&private->cp, (u32)virt_to_phys(sch), sch->lpm); if (!orb) { ret = -EIO; goto out; |