File Index
Files and directories
Sign in
FILE

debugfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/soundwire/debugfs.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2// Copyright(c) 2017-2019 Intel Corporation.
  3
  4#include <linux/cleanup.h>
  5#include <linux/device.h>
  6#include <linux/debugfs.h>
  7#include <linux/firmware.h>
  8#include <linux/mod_devicetable.h>
  9#include <linux/pm_runtime.h>
 10#include <linux/slab.h>
 11#include <linux/soundwire/sdw.h>
 12#include <linux/soundwire/sdw_registers.h>
 13#include <linux/string_choices.h>
 14#include "bus.h"
 15
 16static struct dentry *sdw_debugfs_root;
 17
 18void sdw_bus_debugfs_init(struct sdw_bus *bus)
 19{
 20	char name[16];
 21
 22	if (!sdw_debugfs_root)
 23		return;
 24
 25	/* create the debugfs master-N */
 26	snprintf(name, sizeof(name), "master-%d-%d", bus->controller_id, bus->link_id);
 27	bus->debugfs = debugfs_create_dir(name, sdw_debugfs_root);
 28}
 29
 30void sdw_bus_debugfs_exit(struct sdw_bus *bus)
 31{
 32	debugfs_remove_recursive(bus->debugfs);
 33}
 34
 35#define RD_BUF (3 * PAGE_SIZE)
 36
 37static ssize_t sdw_sprintf(struct sdw_slave *slave,
 38			   char *buf, size_t pos, unsigned int reg)
 39{
 40	int value;
 41
 42	value = sdw_read_no_pm(slave, reg);
 43
 44	if (value < 0)
 45		return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
 46	else
 47		return scnprintf(buf + pos, RD_BUF - pos,
 48				"%3x\t%2x\n", reg, value);
 49}
 50
 51static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
 52{
 53	struct sdw_slave *slave = s_file->private;
 54	ssize_t ret;
 55	int i, j;
 56
 57	char *buf __free(kfree) = kzalloc(RD_BUF, GFP_KERNEL);
 58	if (!buf)
 59		return -ENOMEM;
 60
 61	ret = pm_runtime_get_sync(&slave->dev);
 62	if (ret < 0 && ret != -EACCES) {
 63		pm_runtime_put_noidle(&slave->dev);
 64		return ret;
 65	}
 66
 67	ret = scnprintf(buf, RD_BUF, "Register  Value\n");
 68
 69	/* DP0 non-banked registers */
 70	ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
 71	for (i = SDW_DP0_INT; i <= SDW_DP0_PREPARECTRL; i++)
 72		ret += sdw_sprintf(slave, buf, ret, i);
 73
 74	/* DP0 Bank 0 registers */
 75	ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
 76	ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
 77	for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
 78		ret += sdw_sprintf(slave, buf, ret, i);
 79
 80	/* DP0 Bank 1 registers */
 81	ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
 82	ret += sdw_sprintf(slave, buf, ret,
 83			SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
 84	for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
 85			i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
 86		ret += sdw_sprintf(slave, buf, ret, i);
 87
 88	/* SCP registers */
 89	ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
 90	for (i = SDW_SCP_INT1; i <= SDW_SCP_BUS_CLOCK_BASE; i++)
 91		ret += sdw_sprintf(slave, buf, ret, i);
 92	for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
 93		ret += sdw_sprintf(slave, buf, ret, i);
 94	for (i = SDW_SCP_SDCA_INT1; i <= SDW_SCP_SDCA_INTMASK4; i++)
 95		ret += sdw_sprintf(slave, buf, ret, i);
 96	for (i = SDW_SCP_FRAMECTRL_B0; i <= SDW_SCP_BUSCLOCK_SCALE_B0; i++)
 97		ret += sdw_sprintf(slave, buf, ret, i);
 98	for (i = SDW_SCP_FRAMECTRL_B1; i <= SDW_SCP_BUSCLOCK_SCALE_B1; i++)
 99		ret += sdw_sprintf(slave, buf, ret, i);
100	for (i = SDW_SCP_PHY_OUT_CTRL_0; i <= SDW_SCP_PHY_OUT_CTRL_7; i++)
101		ret += sdw_sprintf(slave, buf, ret, i);
102
103
104	/*
105	 * SCP Bank 0/1 registers are read-only and cannot be
106	 * retrieved from the Slave. The Master typically keeps track
107	 * of the current frame size so the information can be found
108	 * in other places
109	 */
110
111	/* DP1..14 registers */
112	for (i = 1; SDW_VALID_PORT_RANGE(i); i++) {
113
114		/* DPi registers */
115		ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
116		for (j = SDW_DPN_INT(i); j <= SDW_DPN_PREPARECTRL(i); j++)
117			ret += sdw_sprintf(slave, buf, ret, j);
118
119		/* DPi Bank0 registers */
120		ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
121		for (j = SDW_DPN_CHANNELEN_B0(i);
122		     j <= SDW_DPN_LANECTRL_B0(i); j++)
123			ret += sdw_sprintf(slave, buf, ret, j);
124
125		/* DPi Bank1 registers */
126		ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
127		for (j = SDW_DPN_CHANNELEN_B1(i);
128		     j <= SDW_DPN_LANECTRL_B1(i); j++)
129			ret += sdw_sprintf(slave, buf, ret, j);
130	}
131
132	seq_printf(s_file, "%s", buf);
133
134	pm_runtime_mark_last_busy(&slave->dev);
135	pm_runtime_put(&slave->dev);
136
137	return 0;
138}
139DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg);
140
141#define MAX_CMD_BYTES (1024 * 1024)
142
143static int cmd;
144static int cmd_type;
145static u32 start_addr;
146static size_t num_bytes;
147static u8 read_buffer[MAX_CMD_BYTES];
148static char *firmware_file;
149
150static int set_command(void *data, u64 value)
151{
152	struct sdw_slave *slave = data;
153
154	if (value > 1)
155		return -EINVAL;
156
157	/* Userspace changed the hardware state behind the kernel's back */
158	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
159
160	dev_dbg(&slave->dev, "command: %s\n", str_read_write(value));
161	cmd = value;
162
163	return 0;
164}
165DEFINE_DEBUGFS_ATTRIBUTE(set_command_fops, NULL,
166			 set_command, "%llu\n");
167
168static int set_command_type(void *data, u64 value)
169{
170	struct sdw_slave *slave = data;
171
172	if (value > 1)
173		return -EINVAL;
174
175	/* Userspace changed the hardware state behind the kernel's back */
176	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
177
178	dev_dbg(&slave->dev, "command type: %s\n", value ? "BRA" : "Column0");
179
180	cmd_type = (int)value;
181
182	return 0;
183}
184DEFINE_DEBUGFS_ATTRIBUTE(set_command_type_fops, NULL,
185			 set_command_type, "%llu\n");
186
187static int set_start_address(void *data, u64 value)
188{
189	struct sdw_slave *slave = data;
190
191	/* Userspace changed the hardware state behind the kernel's back */
192	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
193
194	dev_dbg(&slave->dev, "start address %#llx\n", value);
195
196	start_addr = value;
197
198	return 0;
199}
200DEFINE_DEBUGFS_ATTRIBUTE(set_start_address_fops, NULL,
201			 set_start_address, "%llu\n");
202
203static int set_num_bytes(void *data, u64 value)
204{
205	struct sdw_slave *slave = data;
206
207	if (value == 0 || value > MAX_CMD_BYTES)
208		return -EINVAL;
209
210	/* Userspace changed the hardware state behind the kernel's back */
211	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
212
213	dev_dbg(&slave->dev, "number of bytes %lld\n", value);
214
215	num_bytes = value;
216
217	return 0;
218}
219DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL,
220			 set_num_bytes, "%llu\n");
221
222static int do_bpt_sequence(struct sdw_slave *slave, bool write, u8 *buffer)
223{
224	struct sdw_bpt_msg msg = {0};
225	struct sdw_bpt_section *sec;
226
227	sec = kcalloc(1, sizeof(*sec), GFP_KERNEL);
228	if (!sec)
229		return -ENOMEM;
230	msg.sections = 1;
231
232	sec[0].addr = start_addr;
233	sec[0].len = num_bytes;
234
235	msg.sec = sec;
236	msg.dev_num = slave->dev_num;
237	if (write)
238		msg.flags = SDW_MSG_FLAG_WRITE;
239	else
240		msg.flags = SDW_MSG_FLAG_READ;
241	sec[0].buf = buffer;
242
243	return sdw_bpt_send_sync(slave->bus, slave, &msg);
244}
245
246static int cmd_go(void *data, u64 value)
247{
248	const struct firmware *fw = NULL;
249	struct sdw_slave *slave = data;
250	ktime_t start_t;
251	ktime_t finish_t;
252	int ret;
253
254	if (value != 1)
255		return -EINVAL;
256
257	/* one last check */
258	if (start_addr > SDW_REG_MAX ||
259	    num_bytes == 0 || num_bytes > MAX_CMD_BYTES)
260		return -EINVAL;
261
262	ret = pm_runtime_get_sync(&slave->dev);
263	if (ret < 0 && ret != -EACCES) {
264		pm_runtime_put_noidle(&slave->dev);
265		return ret;
266	}
267
268	if (cmd == 0) {
269		ret = request_firmware(&fw, firmware_file, &slave->dev);
270		if (ret < 0) {
271			dev_err(&slave->dev, "firmware %s not found\n", firmware_file);
272			goto out;
273		}
274		if (fw->size < num_bytes) {
275			dev_err(&slave->dev,
276				"firmware %s: firmware size %zd, desired %zd\n",
277				firmware_file, fw->size, num_bytes);
278			goto out;
279		}
280	}
281
282	/* Userspace changed the hardware state behind the kernel's back */
283	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
284
285	dev_dbg(&slave->dev, "starting command\n");
286	start_t = ktime_get();
287
288	if (cmd == 0) {
289		if (cmd_type)
290			ret = do_bpt_sequence(slave, true, (u8 *)fw->data);
291		else
292			ret = sdw_nwrite_no_pm(slave, start_addr, num_bytes, fw->data);
293	} else {
294		memset(read_buffer, 0, sizeof(read_buffer));
295
296		if (cmd_type)
297			ret = do_bpt_sequence(slave, false, read_buffer);
298		else
299			ret = sdw_nread_no_pm(slave, start_addr, num_bytes, read_buffer);
300	}
301
302	finish_t = ktime_get();
303
304	dev_dbg(&slave->dev, "command completed, num_byte %zu status %d, time %lld ms\n",
305		num_bytes, ret, div_u64(finish_t - start_t, NSEC_PER_MSEC));
306
307out:
308	if (fw)
309		release_firmware(fw);
310
311	pm_runtime_mark_last_busy(&slave->dev);
312	pm_runtime_put(&slave->dev);
313
314	return ret;
315}
316DEFINE_DEBUGFS_ATTRIBUTE(cmd_go_fops, NULL,
317			 cmd_go, "%llu\n");
318
319#define MAX_LINE_LEN 128
320
321static int read_buffer_show(struct seq_file *s_file, void *data)
322{
323	char buf[MAX_LINE_LEN];
324	int i;
325
326	if (num_bytes == 0 || num_bytes > MAX_CMD_BYTES)
327		return -EINVAL;
328
329	for (i = 0; i < num_bytes; i++) {
330		scnprintf(buf, MAX_LINE_LEN, "address %#x val 0x%02x\n",
331			  start_addr + i, read_buffer[i]);
332		seq_printf(s_file, "%s", buf);
333	}
334
335	return 0;
336}
337DEFINE_SHOW_ATTRIBUTE(read_buffer);
338
339void sdw_slave_debugfs_init(struct sdw_slave *slave)
340{
341	struct dentry *master;
342	struct dentry *d;
343	char name[32];
344
345	master = slave->bus->debugfs;
346
347	/* create the debugfs slave-name */
348	snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
349	d = debugfs_create_dir(name, master);
350
351	debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
352
353	/* interface to send arbitrary commands */
354	debugfs_create_file("command", 0200, d, slave, &set_command_fops);
355	debugfs_create_file("command_type", 0200, d, slave, &set_command_type_fops);
356	debugfs_create_file("start_address", 0200, d, slave, &set_start_address_fops);
357	debugfs_create_file("num_bytes", 0200, d, slave, &set_num_bytes_fops);
358	debugfs_create_file("go", 0200, d, slave, &cmd_go_fops);
359
360	debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops);
361	firmware_file = NULL;
362	debugfs_create_str("firmware_file", 0200, d, &firmware_file);
363
364	slave->debugfs = d;
365}
366
367void sdw_slave_debugfs_exit(struct sdw_slave *slave)
368{
369	debugfs_remove_recursive(slave->debugfs);
370}
371
372void sdw_debugfs_init(void)
373{
374	sdw_debugfs_root = debugfs_create_dir("soundwire", NULL);
375}
376
377void sdw_debugfs_exit(void)
378{
379	debugfs_remove_recursive(sdw_debugfs_root);
380}
~/ Read-only file preview.