xref: /openbmc/linux/drivers/s390/cio/cio_inject.c (revision 1edd0337)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *   CIO inject interface
4  *
5  *    Copyright IBM Corp. 2021
6  *    Author(s): Vineeth Vijayan <vneethv@linux.ibm.com>
7  */
8 
9 #define KMSG_COMPONENT "cio"
10 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11 
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/mm.h>
15 #include <linux/debugfs.h>
16 #include <asm/chpid.h>
17 
18 #include "cio_inject.h"
19 #include "cio_debug.h"
20 
21 static DEFINE_SPINLOCK(crw_inject_lock);
22 DEFINE_STATIC_KEY_FALSE(cio_inject_enabled);
23 static struct crw *crw_inject_data;
24 
25 /**
26  * crw_inject : Initiate the artificial CRW inject
27  * @crw: The data which needs to be injected as new CRW.
28  *
29  * The CRW handler is called, which will use the provided artificial
30  * data instead of the CRW from the underlying hardware.
31  *
32  * Return: 0 on success
33  */
34 static int crw_inject(struct crw *crw)
35 {
36 	int rc = 0;
37 	struct crw *copy;
38 	unsigned long flags;
39 
40 	copy = kmemdup(crw, sizeof(*crw), GFP_KERNEL);
41 	if (!copy)
42 		return -ENOMEM;
43 
44 	spin_lock_irqsave(&crw_inject_lock, flags);
45 	if (crw_inject_data) {
46 		kfree(copy);
47 		rc = -EBUSY;
48 	} else {
49 		crw_inject_data = copy;
50 	}
51 	spin_unlock_irqrestore(&crw_inject_lock, flags);
52 
53 	if (!rc)
54 		crw_handle_channel_report();
55 
56 	return rc;
57 }
58 
59 /**
60  * stcrw_get_injected: Copy the artificial CRW data to CRW struct.
61  * @crw: The target CRW pointer.
62  *
63  * Retrieve an injected CRW data. Return 0 on success, 1 if no
64  * injected-CRW is available. The function reproduces the return
65  * code of the actual STCRW function.
66  */
67 int stcrw_get_injected(struct crw *crw)
68 {
69 	int rc = 1;
70 	unsigned long flags;
71 
72 	spin_lock_irqsave(&crw_inject_lock, flags);
73 	if (crw_inject_data) {
74 		memcpy(crw, crw_inject_data, sizeof(*crw));
75 		kfree(crw_inject_data);
76 		crw_inject_data = NULL;
77 		rc = 0;
78 	}
79 	spin_unlock_irqrestore(&crw_inject_lock, flags);
80 
81 	return rc;
82 }
83 
84 /* The debugfs write handler for crw_inject nodes operation */
85 static ssize_t crw_inject_write(struct file *file, const char __user *buf,
86 				size_t lbuf, loff_t *ppos)
87 {
88 	u32 slct, oflw, chn, rsc, anc, erc, rsid;
89 	struct crw crw;
90 	char *buffer;
91 	int rc;
92 
93 	if (!static_branch_likely(&cio_inject_enabled)) {
94 		pr_warn("CIO inject is not enabled - ignoring CRW inject\n");
95 		return -EINVAL;
96 	}
97 
98 	buffer = vmemdup_user(buf, lbuf);
99 	if (IS_ERR(buffer))
100 		return -ENOMEM;
101 
102 	rc = sscanf(buffer, "%x %x %x %x %x %x %x", &slct, &oflw, &chn, &rsc, &anc,
103 		    &erc, &rsid);
104 
105 	kvfree(buffer);
106 	if (rc != 7) {
107 		pr_warn("crw_inject: Invalid format (need <solicited> <overflow> <chaining> <rsc> <ancillary> <erc> <rsid>)\n");
108 		return -EINVAL;
109 	}
110 
111 	memset(&crw, 0, sizeof(crw));
112 	crw.slct = slct;
113 	crw.oflw = oflw;
114 	crw.chn = chn;
115 	crw.rsc = rsc;
116 	crw.anc = anc;
117 	crw.erc = erc;
118 	crw.rsid = rsid;
119 
120 	rc = crw_inject(&crw);
121 	if (rc)
122 		return rc;
123 
124 	return lbuf;
125 }
126 
127 /* Debugfs write handler for inject_enable node*/
128 static ssize_t enable_inject_write(struct file *file, const char __user *buf,
129 				   size_t lbuf, loff_t *ppos)
130 {
131 	unsigned long en = 0;
132 	int rc;
133 
134 	rc = kstrtoul_from_user(buf, lbuf, 10, &en);
135 	if (rc)
136 		return rc;
137 
138 	switch (en) {
139 	case 0:
140 		static_branch_disable(&cio_inject_enabled);
141 		break;
142 	case 1:
143 		static_branch_enable(&cio_inject_enabled);
144 		break;
145 	}
146 
147 	return lbuf;
148 }
149 
150 static const struct file_operations crw_fops = {
151 	.owner = THIS_MODULE,
152 	.write = crw_inject_write,
153 };
154 
155 static const struct file_operations cio_en_fops = {
156 	.owner = THIS_MODULE,
157 	.write = enable_inject_write,
158 };
159 
160 static int __init cio_inject_init(void)
161 {
162 	/* enable_inject node enables the static branching */
163 	debugfs_create_file("enable_inject", 0200, cio_debugfs_dir,
164 			    NULL, &cio_en_fops);
165 
166 	debugfs_create_file("crw_inject", 0200, cio_debugfs_dir,
167 			    NULL, &crw_fops);
168 	return 0;
169 }
170 
171 device_initcall(cio_inject_init);
172