Commit 47477c84 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 49d07f01 bb3860cc
......@@ -703,6 +703,17 @@
condev= [HW,S390] console device
conmode=
con3215_drop= [S390] 3215 console drop mode.
Format: y|n|Y|N|1|0
When set to true, drop data on the 3215 console when
the console buffer is full. In this case the
operator using a 3270 terminal emulator (for example
x3270) does not have to enter the clear key for the
console output to advance and the kernel to continue.
This leads to a much faster boot time when a 3270
terminal emulator is active. If no 3270 terminal
emulator is used, this parameter has no effect.
console= [KNL] Output console device and options.
tty<n> Use the virtual console device <n>.
......
......@@ -26,6 +26,10 @@ config GENERIC_BUG
config GENERIC_BUG_RELATIVE_POINTERS
def_bool y
config GENERIC_CSUM
bool
default y if KASAN
config GENERIC_LOCKBREAK
def_bool y if PREEMPTION
......@@ -122,6 +126,7 @@ config S390
select ARCH_WANTS_NO_INSTR
select ARCH_WANT_DEFAULT_BPF_JIT
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
select BUILDTIME_TABLE_SORT
select CLONE_BACKWARDS2
select DMA_OPS if PCI
......@@ -197,6 +202,7 @@ config S390
select HAVE_RSEQ
select HAVE_SAMPLE_FTRACE_DIRECT
select HAVE_SAMPLE_FTRACE_DIRECT_MULTI
select HAVE_SETUP_PER_CPU_AREA
select HAVE_SOFTIRQ_ON_OWN_STACK
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_VIRT_CPU_ACCOUNTING
......@@ -208,6 +214,7 @@ config S390
select MMU_GATHER_MERGE_VMAS
select MODULES_USE_ELF_RELA
select NEED_DMA_MAP_STATE if PCI
select NEED_PER_CPU_EMBED_FIRST_CHUNK
select NEED_SG_DMA_LENGTH if PCI
select OLD_SIGACTION
select OLD_SIGSUSPEND3
......
......@@ -26,8 +26,6 @@
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/workqueue.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>
#include <asm/appldata.h>
#include <asm/vtimer.h>
#include <linux/uaccess.h>
......@@ -44,8 +42,6 @@
#define TOD_MICRO 0x01000 /* nr. of TOD clock units
for 1 microsecond */
static struct platform_device *appldata_pdev;
/*
* /proc entries (sysctl)
*/
......@@ -88,7 +84,6 @@ static struct vtimer_list appldata_timer;
static DEFINE_SPINLOCK(appldata_timer_lock);
static int appldata_interval = APPLDATA_CPU_INTERVAL;
static int appldata_timer_active;
static int appldata_timer_suspended = 0;
/*
* Work queue
......@@ -412,88 +407,6 @@ void appldata_unregister_ops(struct appldata_ops *ops)
/********************** module-ops management <END> **************************/
/**************************** suspend / resume *******************************/
static int appldata_freeze(struct device *dev)
{
struct appldata_ops *ops;
int rc;
struct list_head *lh;
spin_lock(&appldata_timer_lock);
if (appldata_timer_active) {
__appldata_vtimer_setup(APPLDATA_DEL_TIMER);
appldata_timer_suspended = 1;
}
spin_unlock(&appldata_timer_lock);
mutex_lock(&appldata_ops_mutex);
list_for_each(lh, &appldata_ops_list) {
ops = list_entry(lh, struct appldata_ops, list);
if (ops->active == 1) {
rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
(unsigned long) ops->data, ops->size,
ops->mod_lvl);
if (rc != 0)
pr_err("Stopping the data collection for %s "
"failed with rc=%d\n", ops->name, rc);
}
}
mutex_unlock(&appldata_ops_mutex);
return 0;
}
static int appldata_restore(struct device *dev)
{
struct appldata_ops *ops;
int rc;
struct list_head *lh;
spin_lock(&appldata_timer_lock);
if (appldata_timer_suspended) {
__appldata_vtimer_setup(APPLDATA_ADD_TIMER);
appldata_timer_suspended = 0;
}
spin_unlock(&appldata_timer_lock);
mutex_lock(&appldata_ops_mutex);
list_for_each(lh, &appldata_ops_list) {
ops = list_entry(lh, struct appldata_ops, list);
if (ops->active == 1) {
ops->callback(ops->data); // init record
rc = appldata_diag(ops->record_nr,
APPLDATA_START_INTERVAL_REC,
(unsigned long) ops->data, ops->size,
ops->mod_lvl);
if (rc != 0) {
pr_err("Starting the data collection for %s "
"failed with rc=%d\n", ops->name, rc);
}
}
}
mutex_unlock(&appldata_ops_mutex);
return 0;
}
static int appldata_thaw(struct device *dev)
{
return appldata_restore(dev);
}
static const struct dev_pm_ops appldata_pm_ops = {
.freeze = appldata_freeze,
.thaw = appldata_thaw,
.restore = appldata_restore,
};
static struct platform_driver appldata_pdrv = {
.driver = {
.name = "appldata",
.pm = &appldata_pm_ops,
},
};
/************************* suspend / resume <END> ****************************/
/******************************* init / exit *********************************/
/*
......@@ -503,36 +416,14 @@ static struct platform_driver appldata_pdrv = {
*/
static int __init appldata_init(void)
{
int rc;
init_virt_timer(&appldata_timer);
appldata_timer.function = appldata_timer_function;
appldata_timer.data = (unsigned long) &appldata_work;
rc = platform_driver_register(&appldata_pdrv);
if (rc)
return rc;
appldata_pdev = platform_device_register_simple("appldata", -1, NULL,
0);
if (IS_ERR(appldata_pdev)) {
rc = PTR_ERR(appldata_pdev);
goto out_driver;
}
appldata_wq = alloc_ordered_workqueue("appldata", 0);
if (!appldata_wq) {
rc = -ENOMEM;
goto out_device;
}
if (!appldata_wq)
return -ENOMEM;
appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
return 0;
out_device:
platform_device_unregister(appldata_pdev);
out_driver:
platform_driver_unregister(&appldata_pdrv);
return rc;
}
__initcall(appldata_init);
......
......@@ -77,6 +77,9 @@ bool is_ipl_block_dump(void)
if (ipl_block.pb0_hdr.pbt == IPL_PBT_NVME &&
ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
return true;
if (ipl_block.pb0_hdr.pbt == IPL_PBT_ECKD &&
ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
return true;
return false;
}
......@@ -108,6 +111,11 @@ static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
scp_data_len = ipb->nvme.scp_data_len;
scp_data = ipb->nvme.scp_data;
break;
case IPL_PBT_ECKD:
scp_data_len = ipb->eckd.scp_data_len;
scp_data = ipb->eckd.scp_data;
break;
default:
goto out;
}
......@@ -153,6 +161,7 @@ static void append_ipl_block_parm(void)
break;
case IPL_PBT_FCP:
case IPL_PBT_NVME:
case IPL_PBT_ECKD:
rc = ipl_block_get_ascii_scpdata(
parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
break;
......
......@@ -68,14 +68,6 @@ static inline __u8 info_blk_hdr__flags(enum diag204_format type, void *hdr)
return ((struct diag204_x_info_blk_hdr *)hdr)->flags;
}
static inline __u16 info_blk_hdr__pcpus(enum diag204_format type, void *hdr)
{
if (type == DIAG204_INFO_SIMPLE)
return ((struct diag204_info_blk_hdr *)hdr)->phys_cpus;
else /* DIAG204_INFO_EXT */
return ((struct diag204_x_info_blk_hdr *)hdr)->phys_cpus;
}
/* Partition header */
static inline int part_hdr__size(enum diag204_format type)
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
* Copyright IBM Corp. 1999
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
*
* Derived from "include/asm-i386/bugs.h"
* Copyright (C) 1994 Linus Torvalds
*/
/*
* This is included by init/main.c to check for architecture-dependent bugs.
*
* Needs:
* void check_bugs(void);
*/
static inline void check_bugs(void)
{
/* s390 has no bugs ... */
}
......@@ -12,6 +12,12 @@
#ifndef _S390_CHECKSUM_H
#define _S390_CHECKSUM_H
#ifdef CONFIG_GENERIC_CSUM
#include <asm-generic/checksum.h>
#else /* CONFIG_GENERIC_CSUM */
#include <linux/uaccess.h>
#include <linux/in6.h>
......@@ -129,4 +135,5 @@ static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
return csum_fold((__force __wsum)(sum >> 32));
}
#endif /* CONFIG_GENERIC_CSUM */
#endif /* _S390_CHECKSUM_H */
......@@ -22,6 +22,7 @@ struct ipl_parameter_block {
struct ipl_pb0_common common;
struct ipl_pb0_fcp fcp;
struct ipl_pb0_ccw ccw;
struct ipl_pb0_eckd eckd;
struct ipl_pb0_nvme nvme;
char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
};
......@@ -41,6 +42,10 @@ struct ipl_parameter_block {
sizeof(struct ipl_pb0_ccw))
#define IPL_BP0_CCW_LEN (sizeof(struct ipl_pb0_ccw))
#define IPL_BP_ECKD_LEN (sizeof(struct ipl_pl_hdr) + \
sizeof(struct ipl_pb0_eckd))
#define IPL_BP0_ECKD_LEN (sizeof(struct ipl_pb0_eckd))
#define IPL_MAX_SUPPORTED_VERSION (0)
#define IPL_RB_CERT_UNKNOWN ((unsigned short)-1)
......@@ -68,6 +73,8 @@ enum ipl_type {
IPL_TYPE_NSS = 16,
IPL_TYPE_NVME = 32,
IPL_TYPE_NVME_DUMP = 64,
IPL_TYPE_ECKD = 128,
IPL_TYPE_ECKD_DUMP = 256,
};
struct ipl_info
......@@ -77,6 +84,9 @@ struct ipl_info
struct {
struct ccw_dev_id dev_id;
} ccw;
struct {
struct ccw_dev_id dev_id;
} eckd;
struct {
struct ccw_dev_id dev_id;
u64 wwpn;
......@@ -99,6 +109,7 @@ extern void set_os_info_reipl_block(void);
static inline bool is_ipl_type_dump(void)
{
return (ipl_info.type == IPL_TYPE_FCP_DUMP) ||
(ipl_info.type == IPL_TYPE_ECKD_DUMP) ||
(ipl_info.type == IPL_TYPE_NVME_DUMP);
}
......
......@@ -75,4 +75,10 @@ static __always_inline void pai_kernel_exit(struct pt_regs *regs)
WRITE_ONCE(S390_lowcore.ccd, S390_lowcore.ccd & ~PAI_CRYPTO_KERNEL_OFFSET);
}
enum paievt_mode {
PAI_MODE_NONE,
PAI_MODE_SAMPLING,
PAI_MODE_COUNTING,
};
#endif
......@@ -87,6 +87,7 @@ struct sclp_info {
unsigned char has_gisaf : 1;
unsigned char has_diag318 : 1;
unsigned char has_sipl : 1;
unsigned char has_sipl_eckd : 1;
unsigned char has_dirq : 1;
unsigned char has_iplcc : 1;
unsigned char has_zpci_lsi : 1;
......@@ -131,6 +132,7 @@ void sclp_early_get_ipl_info(struct sclp_ipl_info *info);
void sclp_early_detect(void);
void sclp_early_printk(const char *s);
void __sclp_early_printk(const char *s, unsigned int len);
void sclp_emergency_printk(const char *s);
int sclp_early_get_memsize(unsigned long *mem);
int sclp_early_get_hsa_size(unsigned long *hsa_size);
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_SERIAL_H
#define _ASM_S390_SERIAL_H
#define BASE_BAUD 0
#endif /* _ASM_S390_SERIAL_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* S390 version
*
* Derived from "include/asm-i386/shmparam.h"
*/
#ifndef _ASM_S390_SHMPARAM_H
#define _ASM_S390_SHMPARAM_H
#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
#endif /* _ASM_S390_SHMPARAM_H */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_S390_VGA_H
#define _ASM_S390_VGA_H
/* Avoid compile errors due to missing asm/vga.h */
#endif /* _ASM_S390_VGA_H */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Support for Vector Instructions
*
* Assembler macros to generate .byte/.word code for particular
* vector instructions that are supported by recent binutils (>= 2.26) only.
*
* Copyright IBM Corp. 2015
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#ifndef __ASM_S390_VX_INSN_INTERNAL_H
#define __ASM_S390_VX_INSN_INTERNAL_H
#ifndef __ASM_S390_VX_INSN_H
#error only <asm/vx-insn.h> can be included directly
#endif
#ifdef __ASSEMBLY__
/* Macros to generate vector instruction byte code */
/* GR_NUM - Retrieve general-purpose register number
*
* @opd: Operand to store register number
* @r64: String designation register in the format "%rN"
*/
.macro GR_NUM opd gr
\opd = 255
.ifc \gr,%r0
\opd = 0
.endif
.ifc \gr,%r1
\opd = 1
.endif
.ifc \gr,%r2
\opd = 2
.endif
.ifc \gr,%r3
\opd = 3
.endif
.ifc \gr,%r4
\opd = 4
.endif
.ifc \gr,%r5
\opd = 5
.endif
.ifc \gr,%r6
\opd = 6
.endif
.ifc \gr,%r7
\opd = 7
.endif
.ifc \gr,%r8
\opd = 8
.endif
.ifc \gr,%r9
\opd = 9
.endif
.ifc \gr,%r10
\opd = 10
.endif
.ifc \gr,%r11
\opd = 11
.endif
.ifc \gr,%r12
\opd = 12
.endif
.ifc \gr,%r13
\opd = 13
.endif
.ifc \gr,%r14
\opd = 14
.endif
.ifc \gr,%r15
\opd = 15
.endif
.if \opd == 255
\opd = \gr
.endif
.endm
/* VX_NUM - Retrieve vector register number
*
* @opd: Operand to store register number
* @vxr: String designation register in the format "%vN"
*
* The vector register number is used for as input number to the
* instruction and, as well as, to compute the RXB field of the
* instruction.
*/
.macro VX_NUM opd vxr
\opd = 255
.ifc \vxr,%v0
\opd = 0
.endif
.ifc \vxr,%v1
\opd = 1
.endif
.ifc \vxr,%v2
\opd = 2
.endif
.ifc \vxr,%v3
\opd = 3
.endif
.ifc \vxr,%v4
\opd = 4
.endif
.ifc \vxr,%v5
\opd = 5
.endif
.ifc \vxr,%v6
\opd = 6
.endif
.ifc \vxr,%v7
\opd = 7
.endif
.ifc \vxr,%v8
\opd = 8
.endif
.ifc \vxr,%v9
\opd = 9
.endif
.ifc \vxr,%v10
\opd = 10
.endif
.ifc \vxr,%v11
\opd = 11
.endif
.ifc \vxr,%v12
\opd = 12
.endif
.ifc \vxr,%v13
\opd = 13
.endif
.ifc \vxr,%v14
\opd = 14
.endif
.ifc \vxr,%v15
\opd = 15
.endif
.ifc \vxr,%v16
\opd = 16
.endif
.ifc \vxr,%v17
\opd = 17
.endif
.ifc \vxr,%v18
\opd = 18
.endif
.ifc \vxr,%v19
\opd = 19
.endif
.ifc \vxr,%v20
\opd = 20
.endif
.ifc \vxr,%v21
\opd = 21
.endif
.ifc \vxr,%v22
\opd = 22
.endif
.ifc \vxr,%v23
\opd = 23
.endif
.ifc \vxr,%v24
\opd = 24
.endif
.ifc \vxr,%v25
\opd = 25
.endif
.ifc \vxr,%v26
\opd = 26
.endif
.ifc \vxr,%v27
\opd = 27
.endif
.ifc \vxr,%v28
\opd = 28
.endif
.ifc \vxr,%v29
\opd = 29
.endif
.ifc \vxr,%v30
\opd = 30
.endif
.ifc \vxr,%v31
\opd = 31
.endif
.if \opd == 255
\opd = \vxr
.endif
.endm
/* RXB - Compute most significant bit used vector registers
*
* @rxb: Operand to store computed RXB value
* @v1: First vector register designated operand
* @v2: Second vector register designated operand
* @v3: Third vector register designated operand
* @v4: Fourth vector register designated operand
*/
.macro RXB rxb v1 v2=0 v3=0 v4=0
\rxb = 0
.if \v1 & 0x10
\rxb = \rxb | 0x08
.endif
.if \v2 & 0x10
\rxb = \rxb | 0x04
.endif
.if \v3 & 0x10
\rxb = \rxb | 0x02
.endif
.if \v4 & 0x10
\rxb = \rxb | 0x01
.endif
.endm
/* MRXB - Generate Element Size Control and RXB value
*
* @m: Element size control
* @v1: First vector register designated operand (for RXB)
* @v2: Second vector register designated operand (for RXB)
* @v3: Third vector register designated operand (for RXB)
* @v4: Fourth vector register designated operand (for RXB)
*/
.macro MRXB m v1 v2=0 v3=0 v4=0
rxb = 0
RXB rxb, \v1, \v2, \v3, \v4
.byte (\m << 4) | rxb
.endm
/* MRXBOPC - Generate Element Size Control, RXB, and final Opcode fields
*
* @m: Element size control
* @opc: Opcode
* @v1: First vector register designated operand (for RXB)
* @v2: Second vector register designated operand (for RXB)
* @v3: Third vector register designated operand (for RXB)
* @v4: Fourth vector register designated operand (for RXB)
*/
.macro MRXBOPC m opc v1 v2=0 v3=0 v4=0
MRXB \m, \v1, \v2, \v3, \v4
.byte \opc
.endm
/* Vector support instructions */
/* VECTOR GENERATE BYTE MASK */
.macro VGBM vr imm2
VX_NUM v1, \vr
.word (0xE700 | ((v1&15) << 4))
.word \imm2
MRXBOPC 0, 0x44, v1
.endm
.macro VZERO vxr
VGBM \vxr, 0
.endm
.macro VONE vxr
VGBM \vxr, 0xFFFF
.endm
/* VECTOR LOAD VR ELEMENT FROM GR */
.macro VLVG v, gr, disp, m
VX_NUM v1, \v
GR_NUM b2, "%r0"
GR_NUM r3, \gr
.word 0xE700 | ((v1&15) << 4) | r3
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x22, v1
.endm
.macro VLVGB v, gr, index, base
VLVG \v, \gr, \index, \base, 0
.endm
.macro VLVGH v, gr, index
VLVG \v, \gr, \index, 1
.endm
.macro VLVGF v, gr, index
VLVG \v, \gr, \index, 2
.endm
.macro VLVGG v, gr, index
VLVG \v, \gr, \index, 3
.endm
/* VECTOR LOAD REGISTER */
.macro VLR v1, v2
VX_NUM v1, \v1
VX_NUM v2, \v2
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word 0
MRXBOPC 0, 0x56, v1, v2
.endm
/* VECTOR LOAD */
.macro VL v, disp, index="%r0", base
VX_NUM v1, \v
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | x2
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x06, v1
.endm
/* VECTOR LOAD ELEMENT */
.macro VLEx vr1, disp, index="%r0", base, m3, opc
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | x2
.word (b2 << 12) | (\disp)
MRXBOPC \m3, \opc, v1
.endm
.macro VLEB vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x00
.endm
.macro VLEH vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x01
.endm
.macro VLEF vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x03
.endm
.macro VLEG vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x02
.endm
/* VECTOR LOAD ELEMENT IMMEDIATE */
.macro VLEIx vr1, imm2, m3, opc
VX_NUM v1, \vr1
.word 0xE700 | ((v1&15) << 4)
.word \imm2
MRXBOPC \m3, \opc, v1
.endm
.macro VLEIB vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x40
.endm
.macro VLEIH vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x41
.endm
.macro VLEIF vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x43
.endm
.macro VLEIG vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x42
.endm
/* VECTOR LOAD GR FROM VR ELEMENT */
.macro VLGV gr, vr, disp, base="%r0", m
GR_NUM r1, \gr
GR_NUM b2, \base
VX_NUM v3, \vr
.word 0xE700 | (r1 << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x21, v3
.endm
.macro VLGVB gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 0
.endm
.macro VLGVH gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 1
.endm
.macro VLGVF gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 2
.endm
.macro VLGVG gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 3
.endm
/* VECTOR LOAD MULTIPLE */
.macro VLM vfrom, vto, disp, base, hint=3
VX_NUM v1, \vfrom
VX_NUM v3, \vto
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \hint, 0x36, v1, v3
.endm
/* VECTOR STORE */
.macro VST vr1, disp, index="%r0", base
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (x2&15)
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x0E, v1
.endm
/* VECTOR STORE MULTIPLE */
.macro VSTM vfrom, vto, disp, base, hint=3
VX_NUM v1, \vfrom
VX_NUM v3, \vto
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \hint, 0x3E, v1, v3
.endm
/* VECTOR PERMUTE */
.macro VPERM vr1, vr2, vr3, vr4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
VX_NUM v4, \vr4
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC (v4&15), 0x8C, v1, v2, v3, v4
.endm
/* VECTOR UNPACK LOGICAL LOW */
.macro VUPLL vr1, vr2, m3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word 0x0000
MRXBOPC \m3, 0xD4, v1, v2
.endm
.macro VUPLLB vr1, vr2
VUPLL \vr1, \vr2, 0
.endm
.macro VUPLLH vr1, vr2
VUPLL \vr1, \vr2, 1
.endm
.macro VUPLLF vr1, vr2
VUPLL \vr1, \vr2, 2
.endm
/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
.macro VPDI vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x84, v1, v2, v3
.endm
/* VECTOR REPLICATE */
.macro VREP vr1, vr3, imm2, m4
VX_NUM v1, \vr1
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word \imm2
MRXBOPC \m4, 0x4D, v1, v3
.endm
.macro VREPB vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 0
.endm
.macro VREPH vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 1
.endm
.macro VREPF vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 2
.endm
.macro VREPG vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 3
.endm
/* VECTOR MERGE HIGH */
.macro VMRH vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x61, v1, v2, v3
.endm
.macro VMRHB vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 0
.endm
.macro VMRHH vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 1
.endm
.macro VMRHF vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 2
.endm
.macro VMRHG vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 3
.endm
/* VECTOR MERGE LOW */
.macro VMRL vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x60, v1, v2, v3
.endm
.macro VMRLB vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 0
.endm
.macro VMRLH vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 1
.endm
.macro VMRLF vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 2
.endm
.macro VMRLG vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 3
.endm
/* Vector integer instructions */
/* VECTOR AND */
.macro VN vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x68, v1, v2, v3
.endm
/* VECTOR EXCLUSIVE OR */
.macro VX vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x6D, v1, v2, v3
.endm
/* VECTOR GALOIS FIELD MULTIPLY SUM */
.macro VGFM vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0xB4, v1, v2, v3
.endm
.macro VGFMB vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 0
.endm
.macro VGFMH vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 1
.endm
.macro VGFMF vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 2
.endm
.macro VGFMG vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 3
.endm
/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
.macro VGFMA vr1, vr2, vr3, vr4, m5
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
VX_NUM v4, \vr4
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12) | (\m5 << 8)
MRXBOPC (v4&15), 0xBC, v1, v2, v3, v4
.endm
.macro VGFMAB vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 0
.endm
.macro VGFMAH vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 1
.endm
.macro VGFMAF vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 2
.endm
.macro VGFMAG vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 3
.endm
/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
.macro VSRLB vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x7D, v1, v2, v3
.endm
/* VECTOR REPLICATE IMMEDIATE */
.macro VREPI vr1, imm2, m3
VX_NUM v1, \vr1
.word 0xE700 | ((v1&15) << 4)
.word \imm2
MRXBOPC \m3, 0x45, v1
.endm
.macro VREPIB vr1, imm2
VREPI \vr1, \imm2, 0
.endm
.macro VREPIH vr1, imm2
VREPI \vr1, \imm2, 1
.endm
.macro VREPIF vr1, imm2
VREPI \vr1, \imm2, 2
.endm
.macro VREPIG vr1, imm2
VREP \vr1, \imm2, 3
.endm
/* VECTOR ADD */
.macro VA vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0xF3, v1, v2, v3
.endm
.macro VAB vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 0
.endm
.macro VAH vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 1
.endm
.macro VAF vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 2
.endm
.macro VAG vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 3
.endm
.macro VAQ vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 4
.endm
/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
.macro VESRAV vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x7A, v1, v2, v3
.endm
.macro VESRAVB vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 0
.endm
.macro VESRAVH vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 1
.endm
.macro VESRAVF vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 2
.endm
.macro VESRAVG vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 3
.endm
/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
.macro VERLL vr1, vr3, disp, base="%r0", m4
VX_NUM v1, \vr1
VX_NUM v3, \vr3
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m4, 0x33, v1, v3
.endm
.macro VERLLB vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 0
.endm
.macro VERLLH vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 1
.endm
.macro VERLLF vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 2
.endm
.macro VERLLG vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 3
.endm
/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
.macro VSLDB vr1, vr2, vr3, imm4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12) | (\imm4)
MRXBOPC 0, 0x77, v1, v2, v3
.endm
#endif /* __ASSEMBLY__ */
#endif /* __ASM_S390_VX_INSN_INTERNAL_H */
......@@ -2,677 +2,18 @@
/*
* Support for Vector Instructions
*
* Assembler macros to generate .byte/.word code for particular
* vector instructions that are supported by recent binutils (>= 2.26) only.
*
* Copyright IBM Corp. 2015
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
* This wrapper header file allows to use the vector instruction macros in
* both assembler files as well as in inline assemblies in C files.
*/
#ifndef __ASM_S390_VX_INSN_H
#define __ASM_S390_VX_INSN_H
#ifdef __ASSEMBLY__
/* Macros to generate vector instruction byte code */
/* GR_NUM - Retrieve general-purpose register number
*
* @opd: Operand to store register number
* @r64: String designation register in the format "%rN"
*/
.macro GR_NUM opd gr
\opd = 255
.ifc \gr,%r0
\opd = 0
.endif
.ifc \gr,%r1
\opd = 1
.endif
.ifc \gr,%r2
\opd = 2
.endif
.ifc \gr,%r3
\opd = 3
.endif
.ifc \gr,%r4
\opd = 4
.endif
.ifc \gr,%r5
\opd = 5
.endif
.ifc \gr,%r6
\opd = 6
.endif
.ifc \gr,%r7
\opd = 7
.endif
.ifc \gr,%r8
\opd = 8
.endif
.ifc \gr,%r9
\opd = 9
.endif
.ifc \gr,%r10
\opd = 10
.endif
.ifc \gr,%r11
\opd = 11
.endif
.ifc \gr,%r12
\opd = 12
.endif
.ifc \gr,%r13
\opd = 13
.endif
.ifc \gr,%r14
\opd = 14
.endif
.ifc \gr,%r15
\opd = 15
.endif
.if \opd == 255
\opd = \gr
.endif
.endm
/* VX_NUM - Retrieve vector register number
*
* @opd: Operand to store register number
* @vxr: String designation register in the format "%vN"
*
* The vector register number is used for as input number to the
* instruction and, as well as, to compute the RXB field of the
* instruction.
*/
.macro VX_NUM opd vxr
\opd = 255
.ifc \vxr,%v0
\opd = 0
.endif
.ifc \vxr,%v1
\opd = 1
.endif
.ifc \vxr,%v2
\opd = 2
.endif
.ifc \vxr,%v3
\opd = 3
.endif
.ifc \vxr,%v4
\opd = 4
.endif
.ifc \vxr,%v5
\opd = 5
.endif
.ifc \vxr,%v6
\opd = 6
.endif
.ifc \vxr,%v7
\opd = 7
.endif
.ifc \vxr,%v8
\opd = 8
.endif
.ifc \vxr,%v9
\opd = 9
.endif
.ifc \vxr,%v10
\opd = 10
.endif
.ifc \vxr,%v11
\opd = 11
.endif
.ifc \vxr,%v12
\opd = 12
.endif
.ifc \vxr,%v13
\opd = 13
.endif
.ifc \vxr,%v14
\opd = 14
.endif
.ifc \vxr,%v15
\opd = 15
.endif
.ifc \vxr,%v16
\opd = 16
.endif
.ifc \vxr,%v17
\opd = 17
.endif
.ifc \vxr,%v18
\opd = 18
.endif
.ifc \vxr,%v19
\opd = 19
.endif
.ifc \vxr,%v20
\opd = 20
.endif
.ifc \vxr,%v21
\opd = 21
.endif
.ifc \vxr,%v22
\opd = 22
.endif
.ifc \vxr,%v23
\opd = 23
.endif
.ifc \vxr,%v24
\opd = 24
.endif
.ifc \vxr,%v25
\opd = 25
.endif
.ifc \vxr,%v26
\opd = 26
.endif
.ifc \vxr,%v27
\opd = 27
.endif
.ifc \vxr,%v28
\opd = 28
.endif
.ifc \vxr,%v29
\opd = 29
.endif
.ifc \vxr,%v30
\opd = 30
.endif
.ifc \vxr,%v31
\opd = 31
.endif
.if \opd == 255
\opd = \vxr
.endif
.endm
/* RXB - Compute most significant bit used vector registers
*
* @rxb: Operand to store computed RXB value
* @v1: First vector register designated operand
* @v2: Second vector register designated operand
* @v3: Third vector register designated operand
* @v4: Fourth vector register designated operand
*/
.macro RXB rxb v1 v2=0 v3=0 v4=0
\rxb = 0
.if \v1 & 0x10
\rxb = \rxb | 0x08
.endif
.if \v2 & 0x10
\rxb = \rxb | 0x04
.endif
.if \v3 & 0x10
\rxb = \rxb | 0x02
.endif
.if \v4 & 0x10
\rxb = \rxb | 0x01
.endif
.endm
/* MRXB - Generate Element Size Control and RXB value
*
* @m: Element size control
* @v1: First vector register designated operand (for RXB)
* @v2: Second vector register designated operand (for RXB)
* @v3: Third vector register designated operand (for RXB)
* @v4: Fourth vector register designated operand (for RXB)
*/
.macro MRXB m v1 v2=0 v3=0 v4=0
rxb = 0
RXB rxb, \v1, \v2, \v3, \v4
.byte (\m << 4) | rxb
.endm
/* MRXBOPC - Generate Element Size Control, RXB, and final Opcode fields
*
* @m: Element size control
* @opc: Opcode
* @v1: First vector register designated operand (for RXB)
* @v2: Second vector register designated operand (for RXB)
* @v3: Third vector register designated operand (for RXB)
* @v4: Fourth vector register designated operand (for RXB)
*/
.macro MRXBOPC m opc v1 v2=0 v3=0 v4=0
MRXB \m, \v1, \v2, \v3, \v4
.byte \opc
.endm
/* Vector support instructions */
/* VECTOR GENERATE BYTE MASK */
.macro VGBM vr imm2
VX_NUM v1, \vr
.word (0xE700 | ((v1&15) << 4))
.word \imm2
MRXBOPC 0, 0x44, v1
.endm
.macro VZERO vxr
VGBM \vxr, 0
.endm
.macro VONE vxr
VGBM \vxr, 0xFFFF
.endm
/* VECTOR LOAD VR ELEMENT FROM GR */
.macro VLVG v, gr, disp, m
VX_NUM v1, \v
GR_NUM b2, "%r0"
GR_NUM r3, \gr
.word 0xE700 | ((v1&15) << 4) | r3
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x22, v1
.endm
.macro VLVGB v, gr, index, base
VLVG \v, \gr, \index, \base, 0
.endm
.macro VLVGH v, gr, index
VLVG \v, \gr, \index, 1
.endm
.macro VLVGF v, gr, index
VLVG \v, \gr, \index, 2
.endm
.macro VLVGG v, gr, index
VLVG \v, \gr, \index, 3
.endm
/* VECTOR LOAD REGISTER */
.macro VLR v1, v2
VX_NUM v1, \v1
VX_NUM v2, \v2
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word 0
MRXBOPC 0, 0x56, v1, v2
.endm
/* VECTOR LOAD */
.macro VL v, disp, index="%r0", base
VX_NUM v1, \v
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | x2
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x06, v1
.endm
/* VECTOR LOAD ELEMENT */
.macro VLEx vr1, disp, index="%r0", base, m3, opc
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | x2
.word (b2 << 12) | (\disp)
MRXBOPC \m3, \opc, v1
.endm
.macro VLEB vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x00
.endm
.macro VLEH vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x01
.endm
.macro VLEF vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x03
.endm
.macro VLEG vr1, disp, index="%r0", base, m3
VLEx \vr1, \disp, \index, \base, \m3, 0x02
.endm
/* VECTOR LOAD ELEMENT IMMEDIATE */
.macro VLEIx vr1, imm2, m3, opc
VX_NUM v1, \vr1
.word 0xE700 | ((v1&15) << 4)
.word \imm2
MRXBOPC \m3, \opc, v1
.endm
.macro VLEIB vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x40
.endm
.macro VLEIH vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x41
.endm
.macro VLEIF vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x43
.endm
.macro VLEIG vr1, imm2, index
VLEIx \vr1, \imm2, \index, 0x42
.endm
/* VECTOR LOAD GR FROM VR ELEMENT */
.macro VLGV gr, vr, disp, base="%r0", m
GR_NUM r1, \gr
GR_NUM b2, \base
VX_NUM v3, \vr
.word 0xE700 | (r1 << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m, 0x21, v3
.endm
.macro VLGVB gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 0
.endm
.macro VLGVH gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 1
.endm
.macro VLGVF gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 2
.endm
.macro VLGVG gr, vr, disp, base="%r0"
VLGV \gr, \vr, \disp, \base, 3
.endm
/* VECTOR LOAD MULTIPLE */
.macro VLM vfrom, vto, disp, base, hint=3
VX_NUM v1, \vfrom
VX_NUM v3, \vto
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \hint, 0x36, v1, v3
.endm
/* VECTOR STORE */
.macro VST vr1, disp, index="%r0", base
VX_NUM v1, \vr1
GR_NUM x2, \index
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (x2&15)
.word (b2 << 12) | (\disp)
MRXBOPC 0, 0x0E, v1
.endm
/* VECTOR STORE MULTIPLE */
.macro VSTM vfrom, vto, disp, base, hint=3
VX_NUM v1, \vfrom
VX_NUM v3, \vto
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \hint, 0x3E, v1, v3
.endm
/* VECTOR PERMUTE */
.macro VPERM vr1, vr2, vr3, vr4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
VX_NUM v4, \vr4
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC (v4&15), 0x8C, v1, v2, v3, v4
.endm
/* VECTOR UNPACK LOGICAL LOW */
.macro VUPLL vr1, vr2, m3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word 0x0000
MRXBOPC \m3, 0xD4, v1, v2
.endm
.macro VUPLLB vr1, vr2
VUPLL \vr1, \vr2, 0
.endm
.macro VUPLLH vr1, vr2
VUPLL \vr1, \vr2, 1
.endm
.macro VUPLLF vr1, vr2
VUPLL \vr1, \vr2, 2
.endm
/* VECTOR PERMUTE DOUBLEWORD IMMEDIATE */
.macro VPDI vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x84, v1, v2, v3
.endm
/* VECTOR REPLICATE */
.macro VREP vr1, vr3, imm2, m4
VX_NUM v1, \vr1
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word \imm2
MRXBOPC \m4, 0x4D, v1, v3
.endm
.macro VREPB vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 0
.endm
.macro VREPH vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 1
.endm
.macro VREPF vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 2
.endm
.macro VREPG vr1, vr3, imm2
VREP \vr1, \vr3, \imm2, 3
.endm
/* VECTOR MERGE HIGH */
.macro VMRH vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x61, v1, v2, v3
.endm
.macro VMRHB vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 0
.endm
.macro VMRHH vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 1
.endm
.macro VMRHF vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 2
.endm
.macro VMRHG vr1, vr2, vr3
VMRH \vr1, \vr2, \vr3, 3
.endm
/* VECTOR MERGE LOW */
.macro VMRL vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x60, v1, v2, v3
.endm
.macro VMRLB vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 0
.endm
.macro VMRLH vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 1
.endm
.macro VMRLF vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 2
.endm
.macro VMRLG vr1, vr2, vr3
VMRL \vr1, \vr2, \vr3, 3
.endm
/* Vector integer instructions */
/* VECTOR AND */
.macro VN vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x68, v1, v2, v3
.endm
/* VECTOR EXCLUSIVE OR */
.macro VX vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x6D, v1, v2, v3
.endm
/* VECTOR GALOIS FIELD MULTIPLY SUM */
.macro VGFM vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0xB4, v1, v2, v3
.endm
.macro VGFMB vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 0
.endm
.macro VGFMH vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 1
.endm
.macro VGFMF vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 2
.endm
.macro VGFMG vr1, vr2, vr3
VGFM \vr1, \vr2, \vr3, 3
.endm
/* VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE */
.macro VGFMA vr1, vr2, vr3, vr4, m5
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
VX_NUM v4, \vr4
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12) | (\m5 << 8)
MRXBOPC (v4&15), 0xBC, v1, v2, v3, v4
.endm
.macro VGFMAB vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 0
.endm
.macro VGFMAH vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 1
.endm
.macro VGFMAF vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 2
.endm
.macro VGFMAG vr1, vr2, vr3, vr4
VGFMA \vr1, \vr2, \vr3, \vr4, 3
.endm
/* VECTOR SHIFT RIGHT LOGICAL BY BYTE */
.macro VSRLB vr1, vr2, vr3
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC 0, 0x7D, v1, v2, v3
.endm
/* VECTOR REPLICATE IMMEDIATE */
.macro VREPI vr1, imm2, m3
VX_NUM v1, \vr1
.word 0xE700 | ((v1&15) << 4)
.word \imm2
MRXBOPC \m3, 0x45, v1
.endm
.macro VREPIB vr1, imm2
VREPI \vr1, \imm2, 0
.endm
.macro VREPIH vr1, imm2
VREPI \vr1, \imm2, 1
.endm
.macro VREPIF vr1, imm2
VREPI \vr1, \imm2, 2
.endm
.macro VREPIG vr1, imm2
VREP \vr1, \imm2, 3
.endm
/* VECTOR ADD */
.macro VA vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0xF3, v1, v2, v3
.endm
.macro VAB vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 0
.endm
.macro VAH vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 1
.endm
.macro VAF vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 2
.endm
.macro VAG vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 3
.endm
.macro VAQ vr1, vr2, vr3
VA \vr1, \vr2, \vr3, 4
.endm
/* VECTOR ELEMENT SHIFT RIGHT ARITHMETIC */
.macro VESRAV vr1, vr2, vr3, m4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12)
MRXBOPC \m4, 0x7A, v1, v2, v3
.endm
.macro VESRAVB vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 0
.endm
.macro VESRAVH vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 1
.endm
.macro VESRAVF vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 2
.endm
.macro VESRAVG vr1, vr2, vr3
VESRAV \vr1, \vr2, \vr3, 3
.endm
#include <asm/vx-insn-asm.h>
/* VECTOR ELEMENT ROTATE LEFT LOGICAL */
.macro VERLL vr1, vr3, disp, base="%r0", m4
VX_NUM v1, \vr1
VX_NUM v3, \vr3
GR_NUM b2, \base
.word 0xE700 | ((v1&15) << 4) | (v3&15)
.word (b2 << 12) | (\disp)
MRXBOPC \m4, 0x33, v1, v3
.endm
.macro VERLLB vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 0
.endm
.macro VERLLH vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 1
.endm
.macro VERLLF vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 2
.endm
.macro VERLLG vr1, vr3, disp, base="%r0"
VERLL \vr1, \vr3, \disp, \base, 3
.endm
#ifndef __ASSEMBLY__
/* VECTOR SHIFT LEFT DOUBLE BY BYTE */
.macro VSLDB vr1, vr2, vr3, imm4
VX_NUM v1, \vr1
VX_NUM v2, \vr2
VX_NUM v3, \vr3
.word 0xE700 | ((v1&15) << 4) | (v2&15)
.word ((v3&15) << 12) | (\imm4)
MRXBOPC 0, 0x77, v1, v2, v3
.endm
asm(".include \"asm/vx-insn-asm.h\"\n");
#endif /* __ASSEMBLY__ */
#endif /* __ASSEMBLY__ */
#endif /* __ASM_S390_VX_INSN_H */
......@@ -27,6 +27,7 @@ enum ipl_pbt {
IPL_PBT_FCP = 0,
IPL_PBT_SCP_DATA = 1,
IPL_PBT_CCW = 2,
IPL_PBT_ECKD = 3,
IPL_PBT_NVME = 4,
};
......@@ -111,6 +112,34 @@ struct ipl_pb0_ccw {
__u8 reserved5[8];
} __packed;
/* IPL Parameter Block 0 for ECKD */
struct ipl_pb0_eckd {
__u32 len;
__u8 pbt;
__u8 reserved1[3];
__u32 reserved2[78];
__u8 opt;
__u8 reserved4[4];
__u8 reserved5:5;
__u8 ssid:3;
__u16 devno;
__u32 reserved6[5];
__u32 bootprog;
__u8 reserved7[12];
struct {
__u16 cyl;
__u8 head;
__u8 record;
__u32 reserved;
} br_chr __packed;
__u32 scp_data_len;
__u8 reserved8[260];
__u8 scp_data[];
} __packed;
#define IPL_PB0_ECKD_OPT_IPL 0x10
#define IPL_PB0_ECKD_OPT_DUMP 0x20
#define IPL_PB0_CCW_VM_FLAG_NSS 0x80
#define IPL_PB0_CCW_VM_FLAG_VP 0x40
......
......@@ -92,7 +92,7 @@ static int debug_input_flush_fn(debug_info_t *id, struct debug_view *view,
static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
char *out_buf, const char *in_buf);
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
char *out_buf, debug_sprintf_entry_t *curr_event);
char *out_buf, const char *inbuf);
static void debug_areas_swap(debug_info_t *a, debug_info_t *b);
static void debug_events_append(debug_info_t *dest, debug_info_t *src);
......@@ -139,7 +139,7 @@ struct debug_view debug_sprintf_view = {
"sprintf",
NULL,
&debug_dflt_header_fn,
(debug_format_proc_t *)&debug_sprintf_format_fn,
&debug_sprintf_format_fn,
NULL,
NULL
};
......@@ -1532,8 +1532,9 @@ EXPORT_SYMBOL(debug_dflt_header_fn);
#define DEBUG_SPRINTF_MAX_ARGS 10
static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
char *out_buf, debug_sprintf_entry_t *curr_event)
char *out_buf, const char *inbuf)
{
debug_sprintf_entry_t *curr_event = (debug_sprintf_entry_t *)inbuf;
int num_longs, num_used_args = 0, i, rc = 0;
int index[DEBUG_SPRINTF_MAX_ARGS];
......
......@@ -122,24 +122,6 @@ _LPP_OFFSET = __LC_LPP
"jnz .+8; .insn rrf,0xb2e80000,0,0,13,0", 82
.endm
/*
* The CHKSTG macro jumps to the provided label in case the
* machine check interruption code reports one of unrecoverable
* storage errors:
* - Storage error uncorrected
* - Storage key error uncorrected
* - Storage degradation with Failing-storage-address validity
*/
.macro CHKSTG errlabel
TSTMSK __LC_MCCK_CODE,(MCCK_CODE_STG_ERROR|MCCK_CODE_STG_KEY_ERROR)
jnz \errlabel
TSTMSK __LC_MCCK_CODE,MCCK_CODE_STG_DEGRAD
jz .Loklabel\@
TSTMSK __LC_MCCK_CODE,MCCK_CODE_STG_FAIL_ADDR
jnz \errlabel
.Loklabel\@:
.endm
#if IS_ENABLED(CONFIG_KVM)
/*
* The OUTSIDE macro jumps to the provided label in case the value
......@@ -546,26 +528,18 @@ ENTRY(mcck_int_handler)
3: TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_MWP_VALID
jno .Lmcck_panic
tmhh %r8,0x0001 # interrupting from user ?
jnz 6f
jnz .Lmcck_user
TSTMSK __LC_MCCK_CODE,MCCK_CODE_PSW_IA_VALID
jno .Lmcck_panic
#if IS_ENABLED(CONFIG_KVM)
OUTSIDE %r9,.Lsie_gmap,.Lsie_done,6f
OUTSIDE %r9,.Lsie_gmap,.Lsie_done,.Lmcck_stack
OUTSIDE %r9,.Lsie_entry,.Lsie_leave,4f
oi __LC_CPU_FLAGS+7, _CIF_MCCK_GUEST
j 5f
4: CHKSTG .Lmcck_panic
5: larl %r14,.Lstosm_tmp
stosm 0(%r14),0x04 # turn dat on, keep irqs off
BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
4: BPENTER __SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
SIEEXIT
j .Lmcck_stack
#endif
6: CHKSTG .Lmcck_panic
larl %r14,.Lstosm_tmp
stosm 0(%r14),0x04 # turn dat on, keep irqs off
tmhh %r8,0x0001 # interrupting from user ?
jz .Lmcck_stack
.Lmcck_user:
BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
.Lmcck_stack:
lg %r15,__LC_MCCK_STACK
......
......@@ -10,8 +10,7 @@
#include <linux/sched.h>
#include <asm/fpu/types.h>
#include <asm/fpu/api.h>
asm(".include \"asm/vx-insn.h\"\n");
#include <asm/vx-insn.h>
void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
{
......
......@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/kstrtox.h>
#include <linux/panic_notifier.h>
#include <linux/reboot.h>
#include <linux/ctype.h>
......@@ -39,6 +40,8 @@
#define IPL_UNKNOWN_STR "unknown"
#define IPL_CCW_STR "ccw"
#define IPL_ECKD_STR "eckd"
#define IPL_ECKD_DUMP_STR "eckd_dump"
#define IPL_FCP_STR "fcp"
#define IPL_FCP_DUMP_STR "fcp_dump"
#define IPL_NVME_STR "nvme"
......@@ -46,6 +49,7 @@
#define IPL_NSS_STR "nss"
#define DUMP_CCW_STR "ccw"
#define DUMP_ECKD_STR "eckd"
#define DUMP_FCP_STR "fcp"
#define DUMP_NVME_STR "nvme"
#define DUMP_NONE_STR "none"
......@@ -92,6 +96,10 @@ static char *ipl_type_str(enum ipl_type type)
switch (type) {
case IPL_TYPE_CCW:
return IPL_CCW_STR;
case IPL_TYPE_ECKD:
return IPL_ECKD_STR;
case IPL_TYPE_ECKD_DUMP:
return IPL_ECKD_DUMP_STR;
case IPL_TYPE_FCP:
return IPL_FCP_STR;
case IPL_TYPE_FCP_DUMP:
......@@ -113,6 +121,7 @@ enum dump_type {
DUMP_TYPE_CCW = 2,
DUMP_TYPE_FCP = 4,
DUMP_TYPE_NVME = 8,
DUMP_TYPE_ECKD = 16,
};
static char *dump_type_str(enum dump_type type)
......@@ -122,6 +131,8 @@ static char *dump_type_str(enum dump_type type)
return DUMP_NONE_STR;
case DUMP_TYPE_CCW:
return DUMP_CCW_STR;
case DUMP_TYPE_ECKD:
return DUMP_ECKD_STR;
case DUMP_TYPE_FCP:
return DUMP_FCP_STR;
case DUMP_TYPE_NVME:
......@@ -147,6 +158,7 @@ static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
static struct ipl_parameter_block *reipl_block_fcp;
static struct ipl_parameter_block *reipl_block_nvme;
static struct ipl_parameter_block *reipl_block_ccw;
static struct ipl_parameter_block *reipl_block_eckd;
static struct ipl_parameter_block *reipl_block_nss;
static struct ipl_parameter_block *reipl_block_actual;
......@@ -155,12 +167,14 @@ static enum dump_type dump_type = DUMP_TYPE_NONE;
static struct ipl_parameter_block *dump_block_fcp;
static struct ipl_parameter_block *dump_block_nvme;
static struct ipl_parameter_block *dump_block_ccw;
static struct ipl_parameter_block *dump_block_eckd;
static struct sclp_ipl_info sclp_ipl_info;
static bool reipl_nvme_clear;
static bool reipl_fcp_clear;
static bool reipl_ccw_clear;
static bool reipl_eckd_clear;
static inline int __diag308(unsigned long subcode, void *addr)
{
......@@ -218,14 +232,14 @@ IPL_ATTR_SHOW_FN(_prefix, _name, "0.%x.%04x\n", \
_ipl_blk.ssid, _ipl_blk.devno); \
IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk); \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name, (S_IRUGO | S_IWUSR), \
__ATTR(_name, 0644, \
sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store) \
#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value) \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL)
__ATTR(_name, 0444, sys_##_prefix##_##_name##_show, NULL)
#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
IPL_ATTR_SHOW_FN(_prefix, _name, _fmt_out, (unsigned long long) _value) \
......@@ -240,7 +254,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
return len; \
} \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name,(S_IRUGO | S_IWUSR), \
__ATTR(_name, 0644, \
sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store)
......@@ -255,7 +269,7 @@ static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
return len; \
} \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name,(S_IRUGO | S_IWUSR), \
__ATTR(_name, 0644, \
sys_##_prefix##_##_name##_show, \
sys_##_prefix##_##_name##_store)
......@@ -281,6 +295,11 @@ static __init enum ipl_type get_ipl_type(void)
return IPL_TYPE_NVME_DUMP;
else
return IPL_TYPE_NVME;
case IPL_PBT_ECKD:
if (ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
return IPL_TYPE_ECKD_DUMP;
else
return IPL_TYPE_ECKD;
}
return IPL_TYPE_UNKNOWN;
}
......@@ -325,7 +344,7 @@ static ssize_t ipl_vm_parm_show(struct kobject *kobj,
}
static struct kobj_attribute sys_ipl_vm_parm_attr =
__ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL);
__ATTR(parm, 0444, ipl_vm_parm_show, NULL);
static ssize_t sys_ipl_device_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
......@@ -334,6 +353,10 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
case IPL_TYPE_CCW:
return sprintf(page, "0.%x.%04x\n", ipl_block.ccw.ssid,
ipl_block.ccw.devno);
case IPL_TYPE_ECKD:
case IPL_TYPE_ECKD_DUMP:
return sprintf(page, "0.%x.%04x\n", ipl_block.eckd.ssid,
ipl_block.eckd.devno);
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
......@@ -346,7 +369,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
}
static struct kobj_attribute sys_ipl_device_attr =
__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
__ATTR(device, 0444, sys_ipl_device_show, NULL);
static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
......@@ -356,7 +379,7 @@ static ssize_t ipl_parameter_read(struct file *filp, struct kobject *kobj,
ipl_block.hdr.len);
}
static struct bin_attribute ipl_parameter_attr =
__BIN_ATTR(binary_parameter, S_IRUGO, ipl_parameter_read, NULL,
__BIN_ATTR(binary_parameter, 0444, ipl_parameter_read, NULL,
PAGE_SIZE);
static ssize_t ipl_scp_data_read(struct file *filp, struct kobject *kobj,
......@@ -379,11 +402,24 @@ static ssize_t ipl_nvme_scp_data_read(struct file *filp, struct kobject *kobj,
return memory_read_from_buffer(buf, count, &off, scp_data, size);
}
static ssize_t ipl_eckd_scp_data_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
unsigned int size = ipl_block.eckd.scp_data_len;
void *scp_data = &ipl_block.eckd.scp_data;
return memory_read_from_buffer(buf, count, &off, scp_data, size);
}
static struct bin_attribute ipl_scp_data_attr =
__BIN_ATTR(scp_data, S_IRUGO, ipl_scp_data_read, NULL, PAGE_SIZE);
__BIN_ATTR(scp_data, 0444, ipl_scp_data_read, NULL, PAGE_SIZE);
static struct bin_attribute ipl_nvme_scp_data_attr =
__BIN_ATTR(scp_data, S_IRUGO, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
__BIN_ATTR(scp_data, 0444, ipl_nvme_scp_data_read, NULL, PAGE_SIZE);
static struct bin_attribute ipl_eckd_scp_data_attr =
__BIN_ATTR(scp_data, 0444, ipl_eckd_scp_data_read, NULL, PAGE_SIZE);
static struct bin_attribute *ipl_fcp_bin_attrs[] = {
&ipl_parameter_attr,
......@@ -397,6 +433,12 @@ static struct bin_attribute *ipl_nvme_bin_attrs[] = {
NULL,
};
static struct bin_attribute *ipl_eckd_bin_attrs[] = {
&ipl_parameter_attr,
&ipl_eckd_scp_data_attr,
NULL,
};
/* FCP ipl device attributes */
DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n",
......@@ -418,6 +460,84 @@ DEFINE_IPL_ATTR_RO(ipl_nvme, bootprog, "%lld\n",
DEFINE_IPL_ATTR_RO(ipl_nvme, br_lba, "%lld\n",
(unsigned long long)ipl_block.nvme.br_lba);
/* ECKD ipl device attributes */
DEFINE_IPL_ATTR_RO(ipl_eckd, bootprog, "%lld\n",
(unsigned long long)ipl_block.eckd.bootprog);
#define IPL_ATTR_BR_CHR_SHOW_FN(_name, _ipb) \
static ssize_t eckd_##_name##_br_chr_show(struct kobject *kobj, \
struct kobj_attribute *attr, \
char *buf) \
{ \
struct ipl_pb0_eckd *ipb = &(_ipb); \
\
if (!ipb->br_chr.cyl && \
!ipb->br_chr.head && \
!ipb->br_chr.record) \
return sprintf(buf, "auto\n"); \
\
return sprintf(buf, "0x%x,0x%x,0x%x\n", \
ipb->br_chr.cyl, \
ipb->br_chr.head, \
ipb->br_chr.record); \
}
#define IPL_ATTR_BR_CHR_STORE_FN(_name, _ipb) \
static ssize_t eckd_##_name##_br_chr_store(struct kobject *kobj, \
struct kobj_attribute *attr, \
const char *buf, size_t len) \
{ \
struct ipl_pb0_eckd *ipb = &(_ipb); \
unsigned long args[3] = { 0 }; \
char *p, *p1, *tmp = NULL; \
int i, rc; \
\
if (!strncmp(buf, "auto", 4)) \
goto out; \
\
tmp = kstrdup(buf, GFP_KERNEL); \
p = tmp; \
for (i = 0; i < 3; i++) { \
p1 = strsep(&p, ", "); \
if (!p1) { \
rc = -EINVAL; \
goto err; \
} \
rc = kstrtoul(p1, 0, args + i); \
if (rc) \
goto err; \
} \
\
rc = -EINVAL; \
if (i != 3) \
goto err; \
\
if ((args[0] || args[1]) && !args[2]) \
goto err; \
\
if (args[0] > UINT_MAX || args[1] > 255 || args[2] > 255) \
goto err; \
\
out: \
ipb->br_chr.cyl = args[0]; \
ipb->br_chr.head = args[1]; \
ipb->br_chr.record = args[2]; \
rc = len; \
err: \
kfree(tmp); \
return rc; \
}
IPL_ATTR_BR_CHR_SHOW_FN(ipl, ipl_block.eckd);
static struct kobj_attribute sys_ipl_eckd_br_chr_attr =
__ATTR(br_chr, 0644, eckd_ipl_br_chr_show, NULL);
IPL_ATTR_BR_CHR_SHOW_FN(reipl, reipl_block_eckd->eckd);
IPL_ATTR_BR_CHR_STORE_FN(reipl, reipl_block_eckd->eckd);
static struct kobj_attribute sys_reipl_eckd_br_chr_attr =
__ATTR(br_chr, 0644, eckd_reipl_br_chr_show, eckd_reipl_br_chr_store);
static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
......@@ -469,6 +589,20 @@ static struct attribute_group ipl_nvme_attr_group = {
.bin_attrs = ipl_nvme_bin_attrs,
};
static struct attribute *ipl_eckd_attrs[] = {
&sys_ipl_type_attr.attr,
&sys_ipl_eckd_bootprog_attr.attr,
&sys_ipl_eckd_br_chr_attr.attr,
&sys_ipl_device_attr.attr,
&sys_ipl_secure_attr.attr,
&sys_ipl_has_secure_attr.attr,
NULL,
};
static struct attribute_group ipl_eckd_attr_group = {
.attrs = ipl_eckd_attrs,
.bin_attrs = ipl_eckd_bin_attrs,
};
/* CCW ipl device attributes */
......@@ -541,6 +675,9 @@ static int __init ipl_init(void)
rc = sysfs_create_group(&ipl_kset->kobj,
&ipl_ccw_attr_group_lpar);
break;
case IPL_TYPE_ECKD:
rc = sysfs_create_group(&ipl_kset->kobj, &ipl_eckd_attr_group);
break;
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
......@@ -642,11 +779,11 @@ static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_nss_vmparm_attr =
__ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show,
reipl_nss_vmparm_store);
__ATTR(parm, 0644, reipl_nss_vmparm_show,
reipl_nss_vmparm_store);
static struct kobj_attribute sys_reipl_ccw_vmparm_attr =
__ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show,
reipl_ccw_vmparm_store);
__ATTR(parm, 0644, reipl_ccw_vmparm_show,
reipl_ccw_vmparm_store);
/* FCP reipl device attributes */
......@@ -686,7 +823,7 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
return count;
}
static struct bin_attribute sys_reipl_fcp_scp_data_attr =
__BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_fcp_scpdata_read,
__BIN_ATTR(scp_data, 0644, reipl_fcp_scpdata_read,
reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_fcp_bin_attrs[] = {
......@@ -766,8 +903,8 @@ static ssize_t reipl_fcp_loadparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_fcp_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_fcp_loadparm_show,
reipl_fcp_loadparm_store);
__ATTR(loadparm, 0644, reipl_fcp_loadparm_show,
reipl_fcp_loadparm_store);
static ssize_t reipl_fcp_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
......@@ -779,7 +916,7 @@ static ssize_t reipl_fcp_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
if (strtobool(buf, &reipl_fcp_clear) < 0)
if (kstrtobool(buf, &reipl_fcp_clear) < 0)
return -EINVAL;
return len;
}
......@@ -840,7 +977,7 @@ static ssize_t reipl_nvme_scpdata_write(struct file *filp, struct kobject *kobj,
}
static struct bin_attribute sys_reipl_nvme_scp_data_attr =
__BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_nvme_scpdata_read,
__BIN_ATTR(scp_data, 0644, reipl_nvme_scpdata_read,
reipl_nvme_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_nvme_bin_attrs[] = {
......@@ -872,8 +1009,8 @@ static ssize_t reipl_nvme_loadparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_nvme_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nvme_loadparm_show,
reipl_nvme_loadparm_store);
__ATTR(loadparm, 0644, reipl_nvme_loadparm_show,
reipl_nvme_loadparm_store);
static struct attribute *reipl_nvme_attrs[] = {
&sys_reipl_nvme_fid_attr.attr,
......@@ -899,7 +1036,7 @@ static ssize_t reipl_nvme_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
if (strtobool(buf, &reipl_nvme_clear) < 0)
if (kstrtobool(buf, &reipl_nvme_clear) < 0)
return -EINVAL;
return len;
}
......@@ -939,8 +1076,8 @@ static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_ccw_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show,
reipl_ccw_loadparm_store);
__ATTR(loadparm, 0644, reipl_ccw_loadparm_show,
reipl_ccw_loadparm_store);
static ssize_t reipl_ccw_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
......@@ -952,7 +1089,7 @@ static ssize_t reipl_ccw_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
if (strtobool(buf, &reipl_ccw_clear) < 0)
if (kstrtobool(buf, &reipl_ccw_clear) < 0)
return -EINVAL;
return len;
}
......@@ -985,6 +1122,85 @@ static struct attribute_group reipl_ccw_attr_group_lpar = {
.attrs = reipl_ccw_attrs_lpar,
};
/* ECKD reipl device attributes */
static ssize_t reipl_eckd_scpdata_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
size_t size = reipl_block_eckd->eckd.scp_data_len;
void *scp_data = reipl_block_eckd->eckd.scp_data;
return memory_read_from_buffer(buf, count, &off, scp_data, size);
}
static ssize_t reipl_eckd_scpdata_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
size_t scpdata_len = count;
size_t padding;
if (off)
return -EINVAL;
memcpy(reipl_block_eckd->eckd.scp_data, buf, count);
if (scpdata_len % 8) {
padding = 8 - (scpdata_len % 8);
memset(reipl_block_eckd->eckd.scp_data + scpdata_len,
0, padding);
scpdata_len += padding;
}
reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN + scpdata_len;
reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN + scpdata_len;
reipl_block_eckd->eckd.scp_data_len = scpdata_len;
return count;
}
static struct bin_attribute sys_reipl_eckd_scp_data_attr =
__BIN_ATTR(scp_data, 0644, reipl_eckd_scpdata_read,
reipl_eckd_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_eckd_bin_attrs[] = {
&sys_reipl_eckd_scp_data_attr,
NULL,
};
DEFINE_IPL_CCW_ATTR_RW(reipl_eckd, device, reipl_block_eckd->eckd);
DEFINE_IPL_ATTR_RW(reipl_eckd, bootprog, "%lld\n", "%lld\n",
reipl_block_eckd->eckd.bootprog);
static struct attribute *reipl_eckd_attrs[] = {
&sys_reipl_eckd_device_attr.attr,
&sys_reipl_eckd_bootprog_attr.attr,
&sys_reipl_eckd_br_chr_attr.attr,
NULL,
};
static struct attribute_group reipl_eckd_attr_group = {
.attrs = reipl_eckd_attrs,
.bin_attrs = reipl_eckd_bin_attrs
};
static ssize_t reipl_eckd_clear_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
{
return sprintf(page, "%u\n", reipl_eckd_clear);
}
static ssize_t reipl_eckd_clear_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t len)
{
if (strtobool(buf, &reipl_eckd_clear) < 0)
return -EINVAL;
return len;
}
static struct kobj_attribute sys_reipl_eckd_clear_attr =
__ATTR(clear, 0644, reipl_eckd_clear_show, reipl_eckd_clear_store);
/* NSS reipl device attributes */
static void reipl_get_ascii_nss_name(char *dst,
......@@ -1032,12 +1248,12 @@ static ssize_t reipl_nss_name_store(struct kobject *kobj,
}
static struct kobj_attribute sys_reipl_nss_name_attr =
__ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show,
reipl_nss_name_store);
__ATTR(name, 0644, reipl_nss_name_show,
reipl_nss_name_store);
static struct kobj_attribute sys_reipl_nss_loadparm_attr =
__ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show,
reipl_nss_loadparm_store);
__ATTR(loadparm, 0644, reipl_nss_loadparm_show,
reipl_nss_loadparm_store);
static struct attribute *reipl_nss_attrs[] = {
&sys_reipl_nss_name_attr.attr,
......@@ -1068,6 +1284,9 @@ static int reipl_set_type(enum ipl_type type)
case IPL_TYPE_CCW:
reipl_block_actual = reipl_block_ccw;
break;
case IPL_TYPE_ECKD:
reipl_block_actual = reipl_block_eckd;
break;
case IPL_TYPE_FCP:
reipl_block_actual = reipl_block_fcp;
break;
......@@ -1098,6 +1317,8 @@ static ssize_t reipl_type_store(struct kobject *kobj,
if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_CCW);
else if (strncmp(buf, IPL_ECKD_STR, strlen(IPL_ECKD_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_ECKD);
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
rc = reipl_set_type(IPL_TYPE_FCP);
else if (strncmp(buf, IPL_NVME_STR, strlen(IPL_NVME_STR)) == 0)
......@@ -1113,6 +1334,7 @@ static struct kobj_attribute reipl_type_attr =
static struct kset *reipl_kset;
static struct kset *reipl_fcp_kset;
static struct kset *reipl_nvme_kset;
static struct kset *reipl_eckd_kset;
static void __reipl_run(void *unused)
{
......@@ -1124,6 +1346,13 @@ static void __reipl_run(void *unused)
else
diag308(DIAG308_LOAD_NORMAL_DUMP, NULL);
break;
case IPL_TYPE_ECKD:
diag308(DIAG308_SET, reipl_block_eckd);
if (reipl_eckd_clear)
diag308(DIAG308_LOAD_CLEAR, NULL);
else
diag308(DIAG308_LOAD_NORMAL, NULL);
break;
case IPL_TYPE_FCP:
diag308(DIAG308_SET, reipl_block_fcp);
if (reipl_fcp_clear)
......@@ -1147,6 +1376,7 @@ static void __reipl_run(void *unused)
break;
case IPL_TYPE_FCP_DUMP:
case IPL_TYPE_NVME_DUMP:
case IPL_TYPE_ECKD_DUMP:
break;
}
disabled_wait();
......@@ -1344,6 +1574,58 @@ static int __init reipl_nvme_init(void)
return rc;
}
static int __init reipl_eckd_init(void)
{
int rc;
if (!sclp.has_sipl_eckd)
return 0;
reipl_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
if (!reipl_block_eckd)
return -ENOMEM;
/* sysfs: create kset for mixing attr group and bin attrs */
reipl_eckd_kset = kset_create_and_add(IPL_ECKD_STR, NULL,
&reipl_kset->kobj);
if (!reipl_eckd_kset) {
free_page((unsigned long)reipl_block_eckd);
return -ENOMEM;
}
rc = sysfs_create_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
if (rc)
goto out1;
if (test_facility(141)) {
rc = sysfs_create_file(&reipl_eckd_kset->kobj,
&sys_reipl_eckd_clear_attr.attr);
if (rc)
goto out2;
} else {
reipl_eckd_clear = true;
}
if (ipl_info.type == IPL_TYPE_ECKD) {
memcpy(reipl_block_eckd, &ipl_block, sizeof(ipl_block));
} else {
reipl_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
reipl_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
reipl_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
reipl_block_eckd->eckd.pbt = IPL_PBT_ECKD;
reipl_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_IPL;
}
reipl_capabilities |= IPL_TYPE_ECKD;
return 0;
out2:
sysfs_remove_group(&reipl_eckd_kset->kobj, &reipl_eckd_attr_group);
out1:
kset_unregister(reipl_eckd_kset);
free_page((unsigned long)reipl_block_eckd);
return rc;
}
static int __init reipl_type_init(void)
{
enum ipl_type reipl_type = ipl_info.type;
......@@ -1365,6 +1647,9 @@ static int __init reipl_type_init(void)
} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_CCW) {
memcpy(reipl_block_ccw, reipl_block, size);
reipl_type = IPL_TYPE_CCW;
} else if (reipl_block->pb0_hdr.pbt == IPL_PBT_ECKD) {
memcpy(reipl_block_eckd, reipl_block, size);
reipl_type = IPL_TYPE_ECKD;
}
out:
return reipl_set_type(reipl_type);
......@@ -1383,6 +1668,9 @@ static int __init reipl_init(void)
return rc;
}
rc = reipl_ccw_init();
if (rc)
return rc;
rc = reipl_eckd_init();
if (rc)
return rc;
rc = reipl_fcp_init();
......@@ -1457,6 +1745,29 @@ static struct attribute_group dump_nvme_attr_group = {
.attrs = dump_nvme_attrs,
};
/* ECKD dump device attributes */
DEFINE_IPL_CCW_ATTR_RW(dump_eckd, device, dump_block_eckd->eckd);
DEFINE_IPL_ATTR_RW(dump_eckd, bootprog, "%lld\n", "%llx\n",
dump_block_eckd->eckd.bootprog);
IPL_ATTR_BR_CHR_SHOW_FN(dump, dump_block_eckd->eckd);
IPL_ATTR_BR_CHR_STORE_FN(dump, dump_block_eckd->eckd);
static struct kobj_attribute sys_dump_eckd_br_chr_attr =
__ATTR(br_chr, 0644, eckd_dump_br_chr_show, eckd_dump_br_chr_store);
static struct attribute *dump_eckd_attrs[] = {
&sys_dump_eckd_device_attr.attr,
&sys_dump_eckd_bootprog_attr.attr,
&sys_dump_eckd_br_chr_attr.attr,
NULL,
};
static struct attribute_group dump_eckd_attr_group = {
.name = IPL_ECKD_STR,
.attrs = dump_eckd_attrs,
};
/* CCW dump device attributes */
DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ccw);
......@@ -1496,6 +1807,8 @@ static ssize_t dump_type_store(struct kobject *kobj,
rc = dump_set_type(DUMP_TYPE_NONE);
else if (strncmp(buf, DUMP_CCW_STR, strlen(DUMP_CCW_STR)) == 0)
rc = dump_set_type(DUMP_TYPE_CCW);
else if (strncmp(buf, DUMP_ECKD_STR, strlen(DUMP_ECKD_STR)) == 0)
rc = dump_set_type(DUMP_TYPE_ECKD);
else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
rc = dump_set_type(DUMP_TYPE_FCP);
else if (strncmp(buf, DUMP_NVME_STR, strlen(DUMP_NVME_STR)) == 0)
......@@ -1524,6 +1837,9 @@ static void __dump_run(void *unused)
case DUMP_TYPE_CCW:
diag308_dump(dump_block_ccw);
break;
case DUMP_TYPE_ECKD:
diag308_dump(dump_block_eckd);
break;
case DUMP_TYPE_FCP:
diag308_dump(dump_block_fcp);
break;
......@@ -1609,6 +1925,29 @@ static int __init dump_nvme_init(void)
return 0;
}
static int __init dump_eckd_init(void)
{
int rc;
if (!sclp_ipl_info.has_dump || !sclp.has_sipl_eckd)
return 0; /* LDIPL DUMP is not installed */
dump_block_eckd = (void *)get_zeroed_page(GFP_KERNEL);
if (!dump_block_eckd)
return -ENOMEM;
rc = sysfs_create_group(&dump_kset->kobj, &dump_eckd_attr_group);
if (rc) {
free_page((unsigned long)dump_block_eckd);
return rc;
}
dump_block_eckd->hdr.len = IPL_BP_ECKD_LEN;
dump_block_eckd->hdr.version = IPL_PARM_BLOCK_VERSION;
dump_block_eckd->eckd.len = IPL_BP0_ECKD_LEN;
dump_block_eckd->eckd.pbt = IPL_PBT_ECKD;
dump_block_eckd->eckd.opt = IPL_PB0_ECKD_OPT_DUMP;
dump_capabilities |= DUMP_TYPE_ECKD;
return 0;
}
static int __init dump_init(void)
{
int rc;
......@@ -1622,6 +1961,9 @@ static int __init dump_init(void)
return rc;
}
rc = dump_ccw_init();
if (rc)
return rc;
rc = dump_eckd_init();
if (rc)
return rc;
rc = dump_fcp_init();
......@@ -2057,6 +2399,11 @@ void __init setup_ipl(void)
ipl_info.data.ccw.dev_id.ssid = ipl_block.ccw.ssid;
ipl_info.data.ccw.dev_id.devno = ipl_block.ccw.devno;
break;
case IPL_TYPE_ECKD:
case IPL_TYPE_ECKD_DUMP:
ipl_info.data.eckd.dev_id.ssid = ipl_block.eckd.ssid;
ipl_info.data.eckd.dev_id.devno = ipl_block.eckd.devno;
break;
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
ipl_info.data.fcp.dev_id.ssid = 0;
......
......@@ -24,6 +24,7 @@
#include <asm/set_memory.h>
#include <asm/sections.h>
#include <asm/dis.h>
#include "kprobes.h"
#include "entry.h"
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
......@@ -31,8 +32,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
struct kretprobe_blackpoint kretprobe_blacklist[] = { };
DEFINE_INSN_CACHE_OPS(s390_insn);
static int insn_page_in_use;
void *alloc_insn_page(void)
......
/* SPDX-License-Identifier: GPL-2.0+ */
#ifndef _ARCH_S390_KPROBES_H
#define _ARCH_S390_KPROBES_H
#include <linux/kprobes.h>
DEFINE_INSN_CACHE_OPS(s390_insn);
#endif
......@@ -19,7 +19,7 @@
#include <linux/time.h>
#include <linux/module.h>
#include <linux/sched/signal.h>
#include <linux/kvm_host.h>
#include <linux/export.h>
#include <asm/lowcore.h>
#include <asm/smp.h>
......@@ -31,8 +31,7 @@
#include <asm/ctl_reg.h>
#include <asm/asm-offsets.h>
#include <asm/pai.h>
#include <linux/kvm_host.h>
#include <asm/vx-insn.h>
struct mcck_struct {
unsigned int kill_task : 1;
......@@ -43,21 +42,12 @@ struct mcck_struct {
};
static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
static struct kmem_cache *mcesa_cache;
static unsigned long mcesa_origin_lc;
static inline int nmi_needs_mcesa(void)
{
return MACHINE_HAS_VX || MACHINE_HAS_GS;
}
static inline unsigned long nmi_get_mcesa_size(void)
{
if (MACHINE_HAS_GS)
return MCESA_MAX_SIZE;
return MCESA_MIN_SIZE;
}
/*
* The initial machine check extended save area for the boot CPU.
* It will be replaced on the boot CPU reinit with an allocated
......@@ -75,36 +65,23 @@ void __init nmi_alloc_mcesa_early(u64 *mcesad)
*mcesad |= ilog2(MCESA_MAX_SIZE);
}
static void __init nmi_alloc_cache(void)
int nmi_alloc_mcesa(u64 *mcesad)
{
unsigned long size;
if (!nmi_needs_mcesa())
return;
size = nmi_get_mcesa_size();
if (size > MCESA_MIN_SIZE)
mcesa_origin_lc = ilog2(size);
/* create slab cache for the machine-check-extended-save-areas */
mcesa_cache = kmem_cache_create("nmi_save_areas", size, size, 0, NULL);
if (!mcesa_cache)
panic("Couldn't create nmi save area cache");
}
int __ref nmi_alloc_mcesa(u64 *mcesad)
{
unsigned long origin;
void *origin;
*mcesad = 0;
if (!nmi_needs_mcesa())
return 0;
if (!mcesa_cache)
nmi_alloc_cache();
origin = (unsigned long) kmem_cache_alloc(mcesa_cache, GFP_KERNEL);
size = MACHINE_HAS_GS ? MCESA_MAX_SIZE : MCESA_MIN_SIZE;
origin = kmalloc(size, GFP_KERNEL);
if (!origin)
return -ENOMEM;
/* The pointer is stored with mcesa_bits ORed in */
kmemleak_not_leak((void *) origin);
*mcesad = __pa(origin) | mcesa_origin_lc;
kmemleak_not_leak(origin);
*mcesad = __pa(origin);
if (MACHINE_HAS_GS)
*mcesad |= ilog2(MCESA_MAX_SIZE);
return 0;
}
......@@ -112,12 +89,64 @@ void nmi_free_mcesa(u64 *mcesad)
{
if (!nmi_needs_mcesa())
return;
kmem_cache_free(mcesa_cache, __va(*mcesad & MCESA_ORIGIN_MASK));
kfree(__va(*mcesad & MCESA_ORIGIN_MASK));
}
static __always_inline char *nmi_puts(char *dest, const char *src)
{
while (*src)
*dest++ = *src++;
*dest = 0;
return dest;
}
static __always_inline char *u64_to_hex(char *dest, u64 val)
{
int i, num;
for (i = 1; i <= 16; i++) {
num = (val >> (64 - 4 * i)) & 0xf;
if (num >= 10)
*dest++ = 'A' + num - 10;
else
*dest++ = '0' + num;
}
*dest = 0;
return dest;
}
static notrace void s390_handle_damage(void)
{
union ctlreg0 cr0, cr0_new;
char message[100];
psw_t psw_save;
char *ptr;
smp_emergency_stop();
diag_amode31_ops.diag308_reset();
ptr = nmi_puts(message, "System stopped due to unrecoverable machine check, code: 0x");
u64_to_hex(ptr, S390_lowcore.mcck_interruption_code);
/*
* Disable low address protection and make machine check new PSW a
* disabled wait PSW. Any additional machine check cannot be handled.
*/
__ctl_store(cr0.val, 0, 0);
cr0_new = cr0;
cr0_new.lap = 0;
__ctl_load(cr0_new.val, 0, 0);
psw_save = S390_lowcore.mcck_new_psw;
psw_bits(S390_lowcore.mcck_new_psw).io = 0;
psw_bits(S390_lowcore.mcck_new_psw).ext = 0;
psw_bits(S390_lowcore.mcck_new_psw).wait = 1;
sclp_emergency_printk(message);
/*
* Restore machine check new PSW and control register 0 to original
* values. This makes possible system dump analysis easier.
*/
S390_lowcore.mcck_new_psw = psw_save;
__ctl_load(cr0.val, 0, 0);
disabled_wait();
while (1);
}
......@@ -181,10 +210,10 @@ void noinstr s390_handle_mcck(struct pt_regs *regs)
trace_hardirqs_on();
}
/*
* returns 0 if all required registers are available
* returns 0 if register contents could be validated
* returns 1 otherwise
*/
static int notrace s390_validate_registers(union mci mci, int umode)
static int notrace s390_validate_registers(union mci mci)
{
struct mcesa *mcesa;
void *fpt_save_area;
......@@ -195,45 +224,15 @@ static int notrace s390_validate_registers(union mci mci, int umode)
kill_task = 0;
zero = 0;
if (!mci.gr) {
/*
* General purpose registers couldn't be restored and have
* unknown contents. Stop system or terminate process.
*/
if (!umode)
s390_handle_damage();
if (!mci.gr || !mci.fp)
kill_task = 1;
}
if (!mci.fp) {
/*
* Floating point registers can't be restored. If the
* kernel currently uses floating point registers the
* system is stopped. If the process has its floating
* pointer registers loaded it is terminated.
*/
if (S390_lowcore.fpu_flags & KERNEL_VXR_V0V7)
s390_handle_damage();
if (!test_cpu_flag(CIF_FPU))
kill_task = 1;
}
fpt_save_area = &S390_lowcore.floating_pt_save_area;
if (!mci.fc) {
/*
* Floating point control register can't be restored.
* If the kernel currently uses the floating pointer
* registers and needs the FPC register the system is
* stopped. If the process has its floating pointer
* registers loaded it is terminated. Otherwise the
* FPC is just validated.
*/
if (S390_lowcore.fpu_flags & KERNEL_FPC)
s390_handle_damage();
kill_task = 1;
asm volatile(
" lfpc %0\n"
:
: "Q" (zero));
if (!test_cpu_flag(CIF_FPU))
kill_task = 1;
} else {
asm volatile(
" lfpc %0\n"
......@@ -275,26 +274,15 @@ static int notrace s390_validate_registers(union mci mci, int umode)
* appropriate actions. The host vector or FPU values have been
* saved by KVM and will be restored by KVM.
*/
if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST)) {
/*
* Vector registers can't be restored. If the kernel
* currently uses vector registers the system is
* stopped. If the process has its vector registers
* loaded it is terminated. Otherwise just validate
* the registers.
*/
if (S390_lowcore.fpu_flags & KERNEL_VXR)
s390_handle_damage();
if (!test_cpu_flag(CIF_FPU))
kill_task = 1;
}
if (!mci.vr && !test_cpu_flag(CIF_MCCK_GUEST))
kill_task = 1;
cr0.val = S390_lowcore.cregs_save_area[0];
cr0.afp = cr0.vx = 1;
__ctl_load(cr0.val, 0, 0);
asm volatile(
" la 1,%0\n"
" .word 0xe70f,0x1000,0x0036\n" /* vlm 0,15,0(1) */
" .word 0xe70f,0x1100,0x0c36\n" /* vlm 16,31,256(1) */
" VLM 0,15,0,1\n"
" VLM 16,31,256,1\n"
:
: "Q" (*(struct vx_array *)mcesa->vector_save_area)
: "1");
......@@ -306,13 +294,8 @@ static int notrace s390_validate_registers(union mci mci, int umode)
:
: "a" (&S390_lowcore.access_regs_save_area)
: "memory");
if (!mci.ar) {
/*
* Access registers have unknown contents.
* Terminating task.
*/
if (!mci.ar)
kill_task = 1;
}
/* Validate guarded storage registers */
cr2.val = S390_lowcore.cregs_save_area[2];
if (cr2.gse) {
......@@ -451,7 +434,9 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
s390_handle_damage();
}
}
if (s390_validate_registers(mci, user_mode(regs))) {
if (s390_validate_registers(mci)) {
if (!user_mode(regs))
s390_handle_damage();
/*
* Couldn't restore all register contents for the
* user space process -> mark task for termination.
......@@ -480,7 +465,21 @@ int notrace s390_do_machine_check(struct pt_regs *regs)
mcck->stp_queue |= stp_island_check();
mcck_pending = 1;
}
/*
* Reinject storage related machine checks into the guest if they
* happen when the guest is running.
*/
if (!test_cpu_flag(CIF_MCCK_GUEST)) {
/* Storage error uncorrected */
if (mci.se)
s390_handle_damage();
/* Storage key-error uncorrected */
if (mci.ke)
s390_handle_damage();
/* Storage degradation */
if (mci.ds && mci.fa)
s390_handle_damage();
}
if (mci.cp) {
/* Channel report word pending */
mcck->channel_report = 1;
......
......@@ -35,9 +35,9 @@ struct pai_userdata {
struct paicrypt_map {
unsigned long *page; /* Page for CPU to store counters */
struct pai_userdata *save; /* Page to store no-zero counters */
unsigned int users; /* # of PAI crypto users */
unsigned int sampler; /* # of PAI crypto samplers */
unsigned int counter; /* # of PAI crypto counters */
unsigned int active_events; /* # of PAI crypto users */
unsigned int refcnt; /* Reference count mapped buffers */
enum paievt_mode mode; /* Type of event */
struct perf_event *event; /* Perf event for sampling */
};
......@@ -56,15 +56,11 @@ static void paicrypt_event_destroy(struct perf_event *event)
cpump->event = NULL;
static_branch_dec(&pai_key);
mutex_lock(&pai_reserve_mutex);
if (event->attr.sample_period)
cpump->sampler -= 1;
else
cpump->counter -= 1;
debug_sprintf_event(cfm_dbg, 5, "%s event %#llx cpu %d"
" sampler %d counter %d\n", __func__,
event->attr.config, event->cpu, cpump->sampler,
cpump->counter);
if (!cpump->counter && !cpump->sampler) {
debug_sprintf_event(cfm_dbg, 5, "%s event %#llx cpu %d users %d"
" mode %d refcnt %d\n", __func__,
event->attr.config, event->cpu,
cpump->active_events, cpump->mode, cpump->refcnt);
if (!--cpump->refcnt) {
debug_sprintf_event(cfm_dbg, 4, "%s page %#lx save %p\n",
__func__, (unsigned long)cpump->page,
cpump->save);
......@@ -72,6 +68,7 @@ static void paicrypt_event_destroy(struct perf_event *event)
cpump->page = NULL;
kvfree(cpump->save);
cpump->save = NULL;
cpump->mode = PAI_MODE_NONE;
}
mutex_unlock(&pai_reserve_mutex);
}
......@@ -136,17 +133,14 @@ static u64 paicrypt_getall(struct perf_event *event)
*/
static int paicrypt_busy(struct perf_event_attr *a, struct paicrypt_map *cpump)
{
unsigned int *use_ptr;
int rc = 0;
mutex_lock(&pai_reserve_mutex);
if (a->sample_period) { /* Sampling requested */
use_ptr = &cpump->sampler;
if (cpump->counter || cpump->sampler)
if (cpump->mode != PAI_MODE_NONE)
rc = -EBUSY; /* ... sampling/counting active */
} else { /* Counting requested */
use_ptr = &cpump->counter;
if (cpump->sampler)
if (cpump->mode == PAI_MODE_SAMPLING)
rc = -EBUSY; /* ... and sampling active */
}
if (rc)
......@@ -172,12 +166,16 @@ static int paicrypt_busy(struct perf_event_attr *a, struct paicrypt_map *cpump)
rc = 0;
unlock:
/* If rc is non-zero, do not increment counter/sampler. */
if (!rc)
*use_ptr += 1;
debug_sprintf_event(cfm_dbg, 5, "%s sample_period %#llx sampler %d"
" counter %d page %#lx save %p rc %d\n", __func__,
a->sample_period, cpump->sampler, cpump->counter,
/* If rc is non-zero, do not set mode and reference count */
if (!rc) {
cpump->refcnt++;
cpump->mode = a->sample_period ? PAI_MODE_SAMPLING
: PAI_MODE_COUNTING;
}
debug_sprintf_event(cfm_dbg, 5, "%s sample_period %#llx users %d"
" mode %d refcnt %d page %#lx save %p rc %d\n",
__func__, a->sample_period, cpump->active_events,
cpump->mode, cpump->refcnt,
(unsigned long)cpump->page, cpump->save, rc);
mutex_unlock(&pai_reserve_mutex);
return rc;
......@@ -262,7 +260,7 @@ static int paicrypt_add(struct perf_event *event, int flags)
struct paicrypt_map *cpump = this_cpu_ptr(&paicrypt_map);
unsigned long ccd;
if (cpump->users++ == 0) {
if (++cpump->active_events == 1) {
ccd = virt_to_phys(cpump->page) | PAI_CRYPTO_KERNEL_OFFSET;
WRITE_ONCE(S390_lowcore.ccd, ccd);
__ctl_set_bit(0, 50);
......@@ -293,7 +291,7 @@ static void paicrypt_del(struct perf_event *event, int flags)
if (!event->attr.sample_period)
/* Only counting needs to read counter */
paicrypt_stop(event, PERF_EF_UPDATE);
if (cpump->users-- == 1) {
if (--cpump->active_events == 0) {
__ctl_clear_bit(0, 50);
WRITE_ONCE(S390_lowcore.ccd, 0);
}
......
......@@ -28,12 +28,6 @@
static debug_info_t *paiext_dbg;
static unsigned int paiext_cnt; /* Extracted with QPACI instruction */
enum paiext_mode {
PAI_MODE_NONE,
PAI_MODE_SAMPLING,
PAI_MODE_COUNTER,
};
struct pai_userdata {
u16 num;
u64 value;
......@@ -54,7 +48,7 @@ struct paiext_cb { /* PAI extension 1 control block */
struct paiext_map {
unsigned long *area; /* Area for CPU to store counters */
struct pai_userdata *save; /* Area to store non-zero counters */
enum paiext_mode mode; /* Type of event */
enum paievt_mode mode; /* Type of event */
unsigned int active_events; /* # of PAI Extension users */
unsigned int refcnt;
struct perf_event *event; /* Perf event for sampling */
......@@ -192,14 +186,14 @@ static int paiext_alloc(struct perf_event_attr *a, struct perf_event *event)
goto unlock;
}
cpump->mode = a->sample_period ? PAI_MODE_SAMPLING
: PAI_MODE_COUNTER;
: PAI_MODE_COUNTING;
} else {
/* Multiple invocation, check whats active.
* Supported are multiple counter events or only one sampling
* event concurrently at any one time.
*/
if (cpump->mode == PAI_MODE_SAMPLING ||
(cpump->mode == PAI_MODE_COUNTER && a->sample_period)) {
(cpump->mode == PAI_MODE_COUNTING && a->sample_period)) {
rc = -EBUSY;
goto unlock;
}
......
......@@ -437,7 +437,7 @@ static void __init setup_lowcore_dat_off(void)
lc->svc_new_psw.addr = (unsigned long) system_call;
lc->program_new_psw.mask = int_psw_mask | PSW_MASK_MCHECK;
lc->program_new_psw.addr = (unsigned long) pgm_check_handler;
lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
lc->mcck_new_psw.mask = int_psw_mask;
lc->mcck_new_psw.addr = (unsigned long) mcck_int_handler;
lc->io_new_psw.mask = int_psw_mask | PSW_MASK_MCHECK;
lc->io_new_psw.addr = (unsigned long) io_int_handler;
......@@ -512,6 +512,7 @@ static void __init setup_lowcore_dat_on(void)
S390_lowcore.external_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.svc_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.program_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.mcck_new_psw.mask |= PSW_MASK_DAT;
S390_lowcore.io_new_psw.mask |= PSW_MASK_DAT;
__ctl_set_bit(0, 28);
__ctl_store(S390_lowcore.cregs_save_area, 0, 15);
......
......@@ -31,6 +31,7 @@
#include <linux/cma.h>
#include <linux/gfp.h>
#include <linux/dma-direct.h>
#include <linux/percpu.h>
#include <asm/processor.h>
#include <linux/uaccess.h>
#include <asm/pgalloc.h>
......@@ -207,9 +208,6 @@ void free_initmem(void)
__set_memory((unsigned long)_sinittext,
(unsigned long)(_einittext - _sinittext) >> PAGE_SHIFT,
SET_MEMORY_RW | SET_MEMORY_NX);
free_reserved_area(sclp_early_sccb,
sclp_early_sccb + EXT_SCCB_READ_SCP,
POISON_FREE_INITMEM, "unused early sccb");
free_initmem_default(POISON_FREE_INITMEM);
}
......@@ -222,6 +220,41 @@ unsigned long memory_block_size_bytes(void)
return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp.rzm);
}
unsigned long __per_cpu_offset[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(__per_cpu_offset);
static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
{
return LOCAL_DISTANCE;
}
static int __init pcpu_cpu_to_node(int cpu)
{
return 0;
}
void __init setup_per_cpu_areas(void)
{
unsigned long delta;
unsigned int cpu;
int rc;
/*
* Always reserve area for module percpu variables. That's
* what the legacy allocator did.
*/
rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,
PERCPU_DYNAMIC_RESERVE, PAGE_SIZE,
pcpu_cpu_distance,
pcpu_cpu_to_node);
if (rc < 0)
panic("Failed to initialize percpu areas.");
delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
for_each_possible_cpu(cpu)
__per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
}
#ifdef CONFIG_MEMORY_HOTPLUG
#ifdef CONFIG_CMA
......
......@@ -58,17 +58,6 @@ void __init cmma_init(void)
cmma_flag = 2;
}
static inline unsigned char get_page_state(struct page *page)
{
unsigned char state;
asm volatile(" .insn rrf,0xb9ab0000,%0,%1,%2,0"
: "=&d" (state)
: "a" (page_to_phys(page)),
"i" (ESSA_GET_STATE));
return state & 0x3f;
}
static inline void set_page_unused(struct page *page, int order)
{
int i, rc;
......
......@@ -132,7 +132,7 @@ static int zpci_clear_irq(struct zpci_dev *zdev)
static int zpci_set_irq_affinity(struct irq_data *data, const struct cpumask *dest,
bool force)
{
struct msi_desc *entry = irq_get_msi_desc(data->irq);
struct msi_desc *entry = irq_data_get_msi_desc(data);
struct msi_msg msg = entry->msg;
int cpu_addr = smp_cpu_get_cpu_address(cpumask_first(dest));
......
......@@ -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;
......@@ -446,14 +446,46 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
tty_kref_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);
......@@ -548,6 +594,14 @@ static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
/*
* 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.
......
......@@ -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.
*/
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
......@@ -240,6 +240,30 @@ void sclp_early_printk(const char *str)
__sclp_early_printk(str, strlen(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:
......
......@@ -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();
......
......@@ -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);
......
......@@ -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:
......
......@@ -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. */
......
......@@ -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;
......
......@@ -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. */
......
......@@ -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. */
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......@@ -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. */
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -13,8 +13,7 @@
#include <linux/raid/pq.h>
#include <asm/fpu/api.h>
asm(".include \"asm/vx-insn.h\"\n");
#include <asm/vx-insn.h>
#define NSIZE 16
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment