aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 13:16:16 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 13:16:16 -0800
commitcbd88cd4c07f9361914ab7fd7e21c9227986fe68 (patch)
tree8bc448d73f93f10ebd34ef38c911b06359000ed0 /drivers/s390/cio
parentMerge tag 'please-pull-fixefi' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux (diff)
parents390/sclp: fix possible control register corruption (diff)
downloadlinux-dev-cbd88cd4c07f9361914ab7fd7e21c9227986fe68.tar.xz
linux-dev-cbd88cd4c07f9361914ab7fd7e21c9227986fe68.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky: "Among the traditional bug fixes and cleanups are some improvements: - A tool to generated the facility lists, generating the bit fields by hand has been a source of bugs in the past - The spinlock loop is reordered to avoid bursts of hypervisor calls - Add support for the open-for-business interface to the service element - The get_cpu call is added to the vdso - A set of tracepoints is defined for the common I/O layer - The deprecated sclp_cpi module is removed - Update default configuration" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (56 commits) s390/sclp: fix possible control register corruption s390: fix normalization bug in exception table sorting s390/configs: update default configurations s390/vdso: optimize getcpu system call s390: drop smp_mb in vdso_init s390: rename struct _lowcore to struct lowcore s390/mem_detect: use unsigned longs s390/ptrace: get rid of long longs in psw_bits s390/sysinfo: add missing SYSIB 1.2.2 multithreading fields s390: get rid of CONFIG_SCHED_MC and CONFIG_SCHED_BOOK s390/Kconfig: remove pointless 64 bit dependencies s390/dasd: fix failfast for disconnected devices s390/con3270: testing return kzalloc retval s390/hmcdrv: constify hmcdrv_ftp_ops structs s390/cio: add NULL test s390/cio: Change I/O instructions from inline to normal functions s390/cio: Introduce common I/O layer tracepoints s390/cio: Consolidate inline assemblies and related data definitions s390/cio: Fix incorrect xsch opcode specification s390/cio: Remove unused inline assemblies ...
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r--drivers/s390/cio/Makefile5
-rw-r--r--drivers/s390/cio/airq.c1
-rw-r--r--drivers/s390/cio/chsc_sch.c5
-rw-r--r--drivers/s390/cio/cio.c37
-rw-r--r--drivers/s390/cio/cio.h12
-rw-r--r--drivers/s390/cio/crw.c1
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/cio/device_fsm.c2
-rw-r--r--drivers/s390/cio/io_sch.h45
-rw-r--r--drivers/s390/cio/ioasm.c224
-rw-r--r--drivers/s390/cio/ioasm.h169
-rw-r--r--drivers/s390/cio/qdio_debug.c6
-rw-r--r--drivers/s390/cio/trace.c24
-rw-r--r--drivers/s390/cio/trace.h363
14 files changed, 668 insertions, 228 deletions
diff --git a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
index 8c4a386e97f6..3ab9aedeb84a 100644
--- a/drivers/s390/cio/Makefile
+++ b/drivers/s390/cio/Makefile
@@ -2,8 +2,11 @@
# Makefile for the S/390 common i/o drivers
#
+# The following is required for define_trace.h to find ./trace.h
+CFLAGS_trace.o := -I$(src)
+
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o \
- fcx.o itcw.o crw.o ccwreq.o
+ fcx.o itcw.o crw.o ccwreq.o trace.o ioasm.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
index 56eb4ee4deba..99b5db469097 100644
--- a/drivers/s390/cio/airq.c
+++ b/drivers/s390/cio/airq.c
@@ -89,6 +89,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy)
set_cpu_flag(CIF_NOHZ_DELAY);
tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ trace_s390_cio_adapter_int(tpi_info);
head = &airq_lists[tpi_info->isc];
rcu_read_lock();
hlist_for_each_entry_rcu(airq, head, list)
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c
index 213159dec89e..b6f12c2bb114 100644
--- a/drivers/s390/cio/chsc_sch.c
+++ b/drivers/s390/cio/chsc_sch.c
@@ -133,7 +133,7 @@ static int chsc_subchannel_prepare(struct subchannel *sch)
* since we don't have a way to clear the subchannel and
* cannot disable it with a request running.
*/
- cc = stsch_err(sch->schid, &schib);
+ cc = stsch(sch->schid, &schib);
if (!cc && scsw_stctl(&schib.scsw))
return -EAGAIN;
return 0;
@@ -185,8 +185,7 @@ static int __init chsc_init_dbfs(void)
debug_set_level(chsc_debug_log_id, 2);
return 0;
out:
- if (chsc_debug_msg_id)
- debug_unregister(chsc_debug_msg_id);
+ debug_unregister(chsc_debug_msg_id);
return -ENOMEM;
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 690b8547e828..39a8ae54e9c1 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -41,6 +41,7 @@
#include "blacklist.h"
#include "cio_debug.h"
#include "chp.h"
+#include "trace.h"
debug_info_t *cio_debug_msg_id;
debug_info_t *cio_debug_trace_id;
@@ -76,12 +77,9 @@ static int __init cio_debug_init(void)
return 0;
out_unregister:
- if (cio_debug_msg_id)
- debug_unregister(cio_debug_msg_id);
- if (cio_debug_trace_id)
- debug_unregister(cio_debug_trace_id);
- if (cio_debug_crw_id)
- debug_unregister(cio_debug_crw_id);
+ debug_unregister(cio_debug_msg_id);
+ debug_unregister(cio_debug_trace_id);
+ debug_unregister(cio_debug_crw_id);
return -1;
}
@@ -348,18 +346,18 @@ int cio_commit_config(struct subchannel *sch)
struct schib schib;
struct irb irb;
- if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
for (retry = 0; retry < 5; retry++) {
/* copy desired changes to local schib */
cio_apply_config(sch, &schib);
- ccode = msch_err(sch->schid, &schib);
+ ccode = msch(sch->schid, &schib);
if (ccode < 0) /* -EIO if msch gets a program check. */
return ccode;
switch (ccode) {
case 0: /* successful */
- if (stsch_err(sch->schid, &schib) ||
+ if (stsch(sch->schid, &schib) ||
!css_sch_is_valid(&schib))
return -ENODEV;
if (cio_check_config(sch, &schib)) {
@@ -394,7 +392,7 @@ int cio_update_schib(struct subchannel *sch)
{
struct schib schib;
- if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
+ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib))
return -ENODEV;
memcpy(&sch->schib, &schib, sizeof(schib));
@@ -503,7 +501,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
* If stsch gets an exception, it means the current subchannel set
* is not valid.
*/
- ccode = stsch_err(schid, &sch->schib);
+ ccode = stsch(schid, &sch->schib);
if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode;
goto out;
@@ -542,6 +540,7 @@ static irqreturn_t do_cio_interrupt(int irq, void *dummy)
set_cpu_flag(CIF_NOHZ_DELAY);
tpi_info = (struct tpi_info *) &get_irq_regs()->int_code;
+ trace_s390_cio_interrupt(tpi_info);
irb = this_cpu_ptr(&cio_irb);
sch = (struct subchannel *)(unsigned long) tpi_info->intparm;
if (!sch) {
@@ -619,7 +618,7 @@ static int cio_test_for_console(struct subchannel_id schid, void *data)
{
struct schib schib;
- if (stsch_err(schid, &schib) != 0)
+ if (stsch(schid, &schib) != 0)
return -ENXIO;
if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv &&
(schib.pmcw.dev == console_devno)) {
@@ -638,7 +637,7 @@ static int cio_get_console_sch_no(void)
if (console_irq != -1) {
/* VM provided us with the irq number of the console. */
schid.sch_no = console_irq;
- if (stsch_err(schid, &schib) != 0 ||
+ if (stsch(schid, &schib) != 0 ||
(schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !schib.pmcw.dnv)
return -1;
console_devno = schib.pmcw.dev;
@@ -708,10 +707,10 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
cc = 0;
for (retry=0;retry<3;retry++) {
schib->pmcw.ena = 0;
- cc = msch_err(schid, schib);
+ cc = msch(schid, schib);
if (cc)
return (cc==3?-ENODEV:-EBUSY);
- if (stsch_err(schid, schib) || !css_sch_is_valid(schib))
+ if (stsch(schid, schib) || !css_sch_is_valid(schib))
return -ENODEV;
if (!schib->pmcw.ena)
return 0;
@@ -758,7 +757,7 @@ static int stsch_reset(struct subchannel_id schid, struct schib *addr)
pgm_check_occured = 0;
s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
- rc = stsch_err(schid, addr);
+ rc = stsch(schid, addr);
s390_base_pgm_handler_fn = NULL;
/* The program check handler could have changed pgm_check_occured. */
@@ -795,7 +794,7 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
/* No default clear strategy */
break;
}
- stsch_err(schid, &schib);
+ stsch(schid, &schib);
__disable_subchannel_easy(schid, &schib);
}
out:
@@ -917,7 +916,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
{
struct subchannel_id uninitialized_var(schid);
- s390_reset_system(NULL, NULL, NULL);
+ s390_reset_system();
if (reipl_find_schid(devid, &schid) != 0)
panic("IPL Device not found\n");
do_reipl_asm(*((__u32*)&schid));
@@ -943,7 +942,7 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS))
return -ENODEV;
}
- if (stsch_err(schid, &schib))
+ if (stsch(schid, &schib))
return -ENODEV;
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
return -ENODEV;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index a01376ae1749..93de0b46b489 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -45,6 +45,18 @@ struct pmcw {
/* ... in an operand exception. */
} __attribute__ ((packed));
+/* I/O-Interruption Code as stored by TEST PENDING INTERRUPTION (TPI). */
+struct tpi_info {
+ struct subchannel_id schid;
+ u32 intparm;
+ u32 adapter_IO:1;
+ u32 :1;
+ u32 isc:3;
+ u32 :27;
+ u32 type:3;
+ u32 :12;
+} __packed __aligned(4);
+
/* Target SCHIB configuration. */
struct schib_config {
u64 mba;
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index 0f8a25f98b10..3d3cd402b376 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -14,6 +14,7 @@
#include <linux/wait.h>
#include <asm/crw.h>
#include <asm/ctl_reg.h>
+#include "ioasm.h"
static DEFINE_MUTEX(crw_handler_mutex);
static crw_handler_t crw_handlers[NR_RSCS];
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 489e703dc82d..3d2b20ee613f 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -390,7 +390,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
/* Will be done on the slow path. */
return -EAGAIN;
}
- if (stsch_err(schid, &schib)) {
+ if (stsch(schid, &schib)) {
/* Subchannel is not provided. */
return -ENXIO;
}
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 92e03b42e661..8327d47e08b6 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -44,7 +44,7 @@ static void ccw_timeout_log(struct ccw_device *cdev)
sch = to_subchannel(cdev->dev.parent);
private = to_io_private(sch);
orb = &private->orb;
- cc = stsch_err(sch->schid, &schib);
+ cc = stsch(sch->schid, &schib);
printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
"device information:\n", get_tod_clock());
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h
index b108f4a5c7dd..8975060af96c 100644
--- a/drivers/s390/cio/io_sch.h
+++ b/drivers/s390/cio/io_sch.h
@@ -169,49 +169,4 @@ struct ccw_device_private {
enum interruption_class int_class;
};
-static inline int rsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " rsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc", "memory");
- return ccode;
-}
-
-static inline int hsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " hsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
-static inline int xsch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " .insn rre,0xb2760000,%1,0\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
#endif
diff --git a/drivers/s390/cio/ioasm.c b/drivers/s390/cio/ioasm.c
new file mode 100644
index 000000000000..98984818618f
--- /dev/null
+++ b/drivers/s390/cio/ioasm.c
@@ -0,0 +1,224 @@
+/*
+ * Channel subsystem I/O instructions.
+ */
+
+#include <linux/export.h>
+
+#include <asm/chpid.h>
+#include <asm/schid.h>
+#include <asm/crw.h>
+
+#include "ioasm.h"
+#include "orb.h"
+#include "cio.h"
+
+int stsch(struct subchannel_id schid, struct schib *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " stsch 0(%3)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
+ trace_s390_cio_stsch(schid, addr, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(stsch);
+
+int msch(struct subchannel_id schid, struct schib *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " msch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc");
+ trace_s390_cio_msch(schid, addr, ccode);
+
+ return ccode;
+}
+
+int tsch(struct subchannel_id schid, struct irb *addr)
+{
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " tsch 0(%3)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode), "=m" (*addr)
+ : "d" (reg1), "a" (addr)
+ : "cc");
+ trace_s390_cio_tsch(schid, addr, ccode);
+
+ return ccode;
+}
+
+int ssch(struct subchannel_id schid, union orb *addr)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode = -EIO;
+
+ asm volatile(
+ " ssch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (ccode)
+ : "d" (reg1), "a" (addr), "m" (*addr)
+ : "cc", "memory");
+ trace_s390_cio_ssch(schid, addr, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(ssch);
+
+int csch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " csch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_csch(schid, ccode);
+
+ return ccode;
+}
+EXPORT_SYMBOL(csch);
+
+int tpi(struct tpi_info *addr)
+{
+ int ccode;
+
+ asm volatile(
+ " tpi 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode), "=m" (*addr)
+ : "a" (addr)
+ : "cc");
+ trace_s390_cio_tpi(addr, ccode);
+
+ return ccode;
+}
+
+int chsc(void *chsc_area)
+{
+ typedef struct { char _[4096]; } addr_type;
+ int cc;
+
+ asm volatile(
+ " .insn rre,0xb25f0000,%2,0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (cc), "=m" (*(addr_type *) chsc_area)
+ : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
+ : "cc");
+ trace_s390_cio_chsc(chsc_area, cc);
+
+ return cc;
+}
+EXPORT_SYMBOL(chsc);
+
+int rchp(struct chp_id chpid)
+{
+ register struct chp_id reg1 asm ("1") = chpid;
+ int ccode;
+
+ asm volatile(
+ " lr 1,%1\n"
+ " rchp\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
+ trace_s390_cio_rchp(chpid, ccode);
+
+ return ccode;
+}
+
+int rsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " rsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc", "memory");
+ trace_s390_cio_rsch(schid, ccode);
+
+ return ccode;
+}
+
+int hsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " hsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_hsch(schid, ccode);
+
+ return ccode;
+}
+
+int xsch(struct subchannel_id schid)
+{
+ register struct subchannel_id reg1 asm("1") = schid;
+ int ccode;
+
+ asm volatile(
+ " xsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode)
+ : "d" (reg1)
+ : "cc");
+ trace_s390_cio_xsch(schid, ccode);
+
+ return ccode;
+}
+
+int stcrw(struct crw *crw)
+{
+ int ccode;
+
+ asm volatile(
+ " stcrw 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "=m" (*crw)
+ : "a" (crw)
+ : "cc");
+ trace_s390_cio_stcrw(crw, ccode);
+
+ return ccode;
+}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 4d80fc67a06b..b31ee6bff1e4 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -3,165 +3,26 @@
#include <asm/chpid.h>
#include <asm/schid.h>
+#include <asm/crw.h>
#include "orb.h"
#include "cio.h"
+#include "trace.h"
/*
- * TPI info structure
+ * Some S390 specific IO instructions
*/
-struct tpi_info {
- struct subchannel_id schid;
- __u32 intparm; /* interruption parameter */
- __u32 adapter_IO : 1;
- __u32 reserved2 : 1;
- __u32 isc : 3;
- __u32 reserved3 : 12;
- __u32 int_type : 3;
- __u32 reserved4 : 12;
-} __attribute__ ((packed));
-
-/*
- * Some S390 specific IO instructions as inline
- */
-
-static inline int stsch_err(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " stsch 0(%3)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "+d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int msch(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode;
-
- asm volatile(
- " msch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
- return ccode;
-}
-
-static inline int msch_err(struct subchannel_id schid, struct schib *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " msch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b,1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc");
- return ccode;
-}
-
-static inline int tsch(struct subchannel_id schid, struct irb *addr)
-{
- register struct subchannel_id reg1 asm ("1") = schid;
- int ccode;
-
- asm volatile(
- " tsch 0(%3)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "d" (reg1), "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int ssch(struct subchannel_id schid, union orb *addr)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode = -EIO;
-
- asm volatile(
- " ssch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1:\n"
- EX_TABLE(0b, 1b)
- : "+d" (ccode)
- : "d" (reg1), "a" (addr), "m" (*addr)
- : "cc", "memory");
- return ccode;
-}
-
-static inline int csch(struct subchannel_id schid)
-{
- register struct subchannel_id reg1 asm("1") = schid;
- int ccode;
-
- asm volatile(
- " csch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (reg1)
- : "cc");
- return ccode;
-}
-
-static inline int tpi(struct tpi_info *addr)
-{
- int ccode;
-
- asm volatile(
- " tpi 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode), "=m" (*addr)
- : "a" (addr)
- : "cc");
- return ccode;
-}
-
-static inline int chsc(void *chsc_area)
-{
- typedef struct { char _[4096]; } addr_type;
- int cc;
-
- asm volatile(
- " .insn rre,0xb25f0000,%2,0\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (cc), "=m" (*(addr_type *) chsc_area)
- : "d" (chsc_area), "m" (*(addr_type *) chsc_area)
- : "cc");
- return cc;
-}
-
-static inline int rchp(struct chp_id chpid)
-{
- register struct chp_id reg1 asm ("1") = chpid;
- int ccode;
-
- asm volatile(
- " lr 1,%1\n"
- " rchp\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode) : "d" (reg1) : "cc");
- return ccode;
-}
+int stsch(struct subchannel_id schid, struct schib *addr);
+int msch(struct subchannel_id schid, struct schib *addr);
+int tsch(struct subchannel_id schid, struct irb *addr);
+int ssch(struct subchannel_id schid, union orb *addr);
+int csch(struct subchannel_id schid);
+int tpi(struct tpi_info *addr);
+int chsc(void *chsc_area);
+int rchp(struct chp_id chpid);
+int rsch(struct subchannel_id schid);
+int hsch(struct subchannel_id schid);
+int xsch(struct subchannel_id schid);
+int stcrw(struct crw *crw);
#endif
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c
index f1f3baa8e6e4..b6fc147f83d8 100644
--- a/drivers/s390/cio/qdio_debug.c
+++ b/drivers/s390/cio/qdio_debug.c
@@ -366,8 +366,6 @@ void qdio_debug_exit(void)
{
qdio_clear_dbf_list();
debugfs_remove(debugfs_root);
- if (qdio_dbf_setup)
- debug_unregister(qdio_dbf_setup);
- if (qdio_dbf_error)
- debug_unregister(qdio_dbf_error);
+ debug_unregister(qdio_dbf_setup);
+ debug_unregister(qdio_dbf_error);
}
diff --git a/drivers/s390/cio/trace.c b/drivers/s390/cio/trace.c
new file mode 100644
index 000000000000..8e706669ac8b
--- /dev/null
+++ b/drivers/s390/cio/trace.c
@@ -0,0 +1,24 @@
+/*
+ * Tracepoint definitions for s390_cio
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+ */
+
+#include <asm/crw.h>
+#include "cio.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_stsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_msch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_tsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_tpi);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_ssch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_csch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_hsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_xsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_rsch);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_rchp);
+EXPORT_TRACEPOINT_SYMBOL(s390_cio_chsc);
diff --git a/drivers/s390/cio/trace.h b/drivers/s390/cio/trace.h
new file mode 100644
index 000000000000..5b807a09f21b
--- /dev/null
+++ b/drivers/s390/cio/trace.h
@@ -0,0 +1,363 @@
+/*
+ * Tracepoint header for the s390 Common I/O layer (CIO)
+ *
+ * Copyright IBM Corp. 2015
+ * Author(s): Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <asm/crw.h>
+#include <uapi/asm/chpid.h>
+#include <uapi/asm/schid.h>
+#include "cio.h"
+#include "orb.h"
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM s390
+
+#if !defined(_TRACE_S390_CIO_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_S390_CIO_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(s390_class_schib,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field(u16, devno)
+ __field_struct(struct schib, schib)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->devno = schib->pmcw.dev;
+ __entry->schib = *schib;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d ena=%d st=%d dnv=%d dev=%04x "
+ "lpm=0x%02x pnom=0x%02x lpum=0x%02x pim=0x%02x pam=0x%02x "
+ "pom=0x%02x chpids=%016llx",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ __entry->schib.pmcw.ena, __entry->schib.pmcw.st,
+ __entry->schib.pmcw.dnv, __entry->schib.pmcw.dev,
+ __entry->schib.pmcw.lpm, __entry->schib.pmcw.pnom,
+ __entry->schib.pmcw.lpum, __entry->schib.pmcw.pim,
+ __entry->schib.pmcw.pam, __entry->schib.pmcw.pom,
+ *((u64 *) __entry->schib.pmcw.chpid)
+ )
+);
+
+/**
+ * s390_cio_stsch - Store Subchannel instruction (STSCH) was performed
+ * @schid: Subchannel ID
+ * @schib: Subchannel-Information block
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schib, s390_cio_stsch,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc)
+);
+
+/**
+ * s390_cio_msch - Modify Subchannel instruction (MSCH) was performed
+ * @schid: Subchannel ID
+ * @schib: Subchannel-Information block
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schib, s390_cio_msch,
+ TP_PROTO(struct subchannel_id schid, struct schib *schib, int cc),
+ TP_ARGS(schid, schib, cc)
+);
+
+/**
+ * s390_cio_tsch - Test Subchannel instruction (TSCH) was performed
+ * @schid: Subchannel ID
+ * @irb: Interruption-Response Block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_tsch,
+ TP_PROTO(struct subchannel_id schid, struct irb *irb, int cc),
+ TP_ARGS(schid, irb, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field_struct(struct irb, irb)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->irb = *irb;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d dcc=%d pno=%d fctl=0x%x actl=0x%x "
+ "stctl=0x%x dstat=0x%x cstat=0x%x",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ scsw_cc(&__entry->irb.scsw), scsw_pno(&__entry->irb.scsw),
+ scsw_fctl(&__entry->irb.scsw), scsw_actl(&__entry->irb.scsw),
+ scsw_stctl(&__entry->irb.scsw),
+ scsw_dstat(&__entry->irb.scsw), scsw_cstat(&__entry->irb.scsw)
+ )
+);
+
+/**
+ * s390_cio_tpi - Test Pending Interruption instruction (TPI) was performed
+ * @addr: Address of the I/O interruption code or %NULL
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_tpi,
+ TP_PROTO(struct tpi_info *addr, int cc),
+ TP_ARGS(addr, cc),
+ TP_STRUCT__entry(
+ __field(int, cc)
+ __field_struct(struct tpi_info, tpi_info)
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ ),
+ TP_fast_assign(
+ __entry->cc = cc;
+ if (cc != 0)
+ memset(&__entry->tpi_info, 0, sizeof(struct tpi_info));
+ else if (addr)
+ __entry->tpi_info = *addr;
+ else {
+ memcpy(&__entry->tpi_info, &S390_lowcore.subchannel_id,
+ sizeof(struct tpi_info));
+ }
+ __entry->cssid = __entry->tpi_info.schid.cssid;
+ __entry->ssid = __entry->tpi_info.schid.ssid;
+ __entry->schno = __entry->tpi_info.schid.sch_no;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d a=%d isc=%d type=%d",
+ __entry->cssid, __entry->ssid, __entry->schno, __entry->cc,
+ __entry->tpi_info.adapter_IO, __entry->tpi_info.isc,
+ __entry->tpi_info.type
+ )
+);
+
+/**
+ * s390_cio_ssch - Start Subchannel instruction (SSCH) was performed
+ * @schid: Subchannel ID
+ * @orb: Operation-Request Block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_ssch,
+ TP_PROTO(struct subchannel_id schid, union orb *orb, int cc),
+ TP_ARGS(schid, orb, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field_struct(union orb, orb)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->orb = *orb;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d", __entry->cssid, __entry->ssid,
+ __entry->schno, __entry->cc
+ )
+);
+
+DECLARE_EVENT_CLASS(s390_class_schid,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = schid.cssid;
+ __entry->ssid = schid.ssid;
+ __entry->schno = schid.sch_no;
+ __entry->cc = cc;
+ ),
+ TP_printk("schid=%x.%x.%04x cc=%d", __entry->cssid, __entry->ssid,
+ __entry->schno, __entry->cc
+ )
+);
+
+/**
+ * s390_cio_csch - Clear Subchannel instruction (CSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_csch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_hsch - Halt Subchannel instruction (HSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_hsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_xsch - Cancel Subchannel instruction (XSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_xsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_rsch - Resume Subchannel instruction (RSCH) was performed
+ * @schid: Subchannel ID
+ * @cc: Condition code
+ */
+DEFINE_EVENT(s390_class_schid, s390_cio_rsch,
+ TP_PROTO(struct subchannel_id schid, int cc),
+ TP_ARGS(schid, cc)
+);
+
+/**
+ * s390_cio_rchp - Reset Channel Path (RCHP) instruction was performed
+ * @chpid: Channel-Path Identifier
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_rchp,
+ TP_PROTO(struct chp_id chpid, int cc),
+ TP_ARGS(chpid, cc),
+ TP_STRUCT__entry(
+ __field(u8, cssid)
+ __field(u8, id)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->cssid = chpid.cssid;
+ __entry->id = chpid.id;
+ __entry->cc = cc;
+ ),
+ TP_printk("chpid=%x.%02x cc=%d", __entry->cssid, __entry->id,
+ __entry->cc
+ )
+);
+
+#define CHSC_MAX_REQUEST_LEN 64
+#define CHSC_MAX_RESPONSE_LEN 64
+
+/**
+ * s390_cio_chsc - Channel Subsystem Call (CHSC) instruction was performed
+ * @chsc: CHSC block
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_chsc,
+ TP_PROTO(struct chsc_header *chsc, int cc),
+ TP_ARGS(chsc, cc),
+ TP_STRUCT__entry(
+ __field(int, cc)
+ __field(u16, code)
+ __field(u16, rcode)
+ __array(u8, request, CHSC_MAX_REQUEST_LEN)
+ __array(u8, response, CHSC_MAX_RESPONSE_LEN)
+ ),
+ TP_fast_assign(
+ __entry->cc = cc;
+ __entry->code = chsc->code;
+ memcpy(&entry->request, chsc,
+ min_t(u16, chsc->length, CHSC_MAX_REQUEST_LEN));
+ chsc = (struct chsc_header *) ((char *) chsc + chsc->length);
+ __entry->rcode = chsc->code;
+ memcpy(&entry->response, chsc,
+ min_t(u16, chsc->length, CHSC_MAX_RESPONSE_LEN));
+ ),
+ TP_printk("code=0x%04x cc=%d rcode=0x%04x", __entry->code,
+ __entry->cc, __entry->rcode)
+);
+
+/**
+ * s390_cio_interrupt - An I/O interrupt occurred
+ * @tpi_info: Address of the I/O interruption code
+ */
+TRACE_EVENT(s390_cio_interrupt,
+ TP_PROTO(struct tpi_info *tpi_info),
+ TP_ARGS(tpi_info),
+ TP_STRUCT__entry(
+ __field_struct(struct tpi_info, tpi_info)
+ __field(u8, cssid)
+ __field(u8, ssid)
+ __field(u16, schno)
+ ),
+ TP_fast_assign(
+ __entry->tpi_info = *tpi_info;
+ __entry->cssid = __entry->tpi_info.schid.cssid;
+ __entry->ssid = __entry->tpi_info.schid.ssid;
+ __entry->schno = __entry->tpi_info.schid.sch_no;
+ ),
+ TP_printk("schid=%x.%x.%04x isc=%d type=%d",
+ __entry->cssid, __entry->ssid, __entry->schno,
+ __entry->tpi_info.isc, __entry->tpi_info.type
+ )
+);
+
+/**
+ * s390_cio_adapter_int - An adapter interrupt occurred
+ * @tpi_info: Address of the I/O interruption code
+ */
+TRACE_EVENT(s390_cio_adapter_int,
+ TP_PROTO(struct tpi_info *tpi_info),
+ TP_ARGS(tpi_info),
+ TP_STRUCT__entry(
+ __field_struct(struct tpi_info, tpi_info)
+ ),
+ TP_fast_assign(
+ __entry->tpi_info = *tpi_info;
+ ),
+ TP_printk("isc=%d", __entry->tpi_info.isc)
+);
+
+/**
+ * s390_cio_stcrw - Store Channel Report Word (STCRW) was performed
+ * @crw: Channel Report Word
+ * @cc: Condition code
+ */
+TRACE_EVENT(s390_cio_stcrw,
+ TP_PROTO(struct crw *crw, int cc),
+ TP_ARGS(crw, cc),
+ TP_STRUCT__entry(
+ __field_struct(struct crw, crw)
+ __field(int, cc)
+ ),
+ TP_fast_assign(
+ __entry->crw = *crw;
+ __entry->cc = cc;
+ ),
+ TP_printk("cc=%d slct=%d oflw=%d chn=%d rsc=%d anc=%d erc=0x%x "
+ "rsid=0x%x",
+ __entry->cc, __entry->crw.slct, __entry->crw.oflw,
+ __entry->crw.chn, __entry->crw.rsc, __entry->crw.anc,
+ __entry->crw.erc, __entry->crw.rsid
+ )
+);
+
+#endif /* _TRACE_S390_CIO_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+#include <trace/define_trace.h>