Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  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
 21static DEFINE_SPINLOCK(crw_inject_lock);
 22DEFINE_STATIC_KEY_FALSE(cio_inject_enabled);
 23static 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 */
 34static 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 */
 67int 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 */
 85static 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*/
128static 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
150static const struct file_operations crw_fops = {
151	.owner = THIS_MODULE,
152	.write = crw_inject_write,
153};
154
155static const struct file_operations cio_en_fops = {
156	.owner = THIS_MODULE,
157	.write = enable_inject_write,
158};
159
160static 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
171device_initcall(cio_inject_init);