Skip to content

Commit fe46d2a

Browse files
plbossartvinodkoul
authored andcommitted
soundwire: debugfs: add interface to read/write commands
We have an existing debugfs files to read standard registers (DP0/SCP/DPn). This patch provides a more generic interface to ANY set of read/write contiguous registers in a peripheral device. In follow-up patches, this interface will be extended to use BRA transfers. The sequence is to use the following files added under the existing debugsfs directory for each peripheral device: command (write 0, read 1) num_bytes start_address firmware_file (only for writes) read_buffer (only for reads) Example for a read command - this checks the 6 bytes used for enumeration. cd /sys/kernel/debug/soundwire/master-0-0/sdw\:0\:025d\:0711\:01/ echo 1 > command echo 6 > num_bytes echo 0x50 > start_address echo 1 > go cat read_buffer address 0x50 val 0x30 address 0x51 val 0x02 address 0x52 val 0x5d address 0x53 val 0x07 address 0x54 val 0x11 address 0x55 val 0x01 Example with a 2-byte firmware file written in DP0 address 0x22 od -x /lib/firmware/test_firmware 0000000 0a37 0000002 cd /sys/kernel/debug/soundwire/master-0-0/sdw\:0\:025d\:0711\:01/ echo 0 > command echo 2 > num_bytes echo 0x22 > start_address echo "test_firmware" > firmware_file echo 1 > go cd /sys/kernel/debug/soundwire/master-0-0/sdw\:0\:025d\:0711\:01/ echo 1 > command echo 2 > num_bytes echo 0x22 > start_address echo 1 > go cat read_buffer address 0x22 val 0x37 address 0x23 val 0x0a Signed-off-by: Pierre-Louis Bossart <[email protected]> Reviewed-by: Rander Wang <[email protected]> Signed-off-by: Bard Liao <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 1613e60 commit fe46d2a

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

drivers/soundwire/debugfs.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include <linux/device.h>
55
#include <linux/debugfs.h>
6+
#include <linux/firmware.h>
67
#include <linux/mod_devicetable.h>
78
#include <linux/pm_runtime.h>
89
#include <linux/slab.h>
@@ -137,6 +138,145 @@ static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
137138
}
138139
DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg);
139140

141+
#define MAX_CMD_BYTES 256
142+
143+
static int cmd;
144+
static u32 start_addr;
145+
static size_t num_bytes;
146+
static u8 read_buffer[MAX_CMD_BYTES];
147+
static char *firmware_file;
148+
149+
static int set_command(void *data, u64 value)
150+
{
151+
struct sdw_slave *slave = data;
152+
153+
if (value > 1)
154+
return -EINVAL;
155+
156+
/* Userspace changed the hardware state behind the kernel's back */
157+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
158+
159+
dev_dbg(&slave->dev, "command: %s\n", value ? "read" : "write");
160+
cmd = value;
161+
162+
return 0;
163+
}
164+
DEFINE_DEBUGFS_ATTRIBUTE(set_command_fops, NULL,
165+
set_command, "%llu\n");
166+
167+
static int set_start_address(void *data, u64 value)
168+
{
169+
struct sdw_slave *slave = data;
170+
171+
/* Userspace changed the hardware state behind the kernel's back */
172+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
173+
174+
dev_dbg(&slave->dev, "start address %#llx\n", value);
175+
176+
start_addr = value;
177+
178+
return 0;
179+
}
180+
DEFINE_DEBUGFS_ATTRIBUTE(set_start_address_fops, NULL,
181+
set_start_address, "%llu\n");
182+
183+
static int set_num_bytes(void *data, u64 value)
184+
{
185+
struct sdw_slave *slave = data;
186+
187+
if (value == 0 || value > MAX_CMD_BYTES)
188+
return -EINVAL;
189+
190+
/* Userspace changed the hardware state behind the kernel's back */
191+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
192+
193+
dev_dbg(&slave->dev, "number of bytes %lld\n", value);
194+
195+
num_bytes = value;
196+
197+
return 0;
198+
}
199+
DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL,
200+
set_num_bytes, "%llu\n");
201+
202+
static int cmd_go(void *data, u64 value)
203+
{
204+
struct sdw_slave *slave = data;
205+
int ret;
206+
207+
if (value != 1)
208+
return -EINVAL;
209+
210+
/* one last check */
211+
if (start_addr > SDW_REG_MAX ||
212+
num_bytes == 0 || num_bytes > MAX_CMD_BYTES)
213+
return -EINVAL;
214+
215+
ret = pm_runtime_get_sync(&slave->dev);
216+
if (ret < 0 && ret != -EACCES) {
217+
pm_runtime_put_noidle(&slave->dev);
218+
return ret;
219+
}
220+
221+
/* Userspace changed the hardware state behind the kernel's back */
222+
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
223+
224+
dev_dbg(&slave->dev, "starting command\n");
225+
226+
if (cmd == 0) {
227+
const struct firmware *fw;
228+
229+
ret = request_firmware(&fw, firmware_file, &slave->dev);
230+
if (ret < 0) {
231+
dev_err(&slave->dev, "firmware %s not found\n", firmware_file);
232+
goto out;
233+
}
234+
235+
if (fw->size != num_bytes) {
236+
dev_err(&slave->dev,
237+
"firmware %s: unexpected size %zd, desired %zd\n",
238+
firmware_file, fw->size, num_bytes);
239+
release_firmware(fw);
240+
goto out;
241+
}
242+
243+
ret = sdw_nwrite_no_pm(slave, start_addr, num_bytes, fw->data);
244+
release_firmware(fw);
245+
} else {
246+
ret = sdw_nread_no_pm(slave, start_addr, num_bytes, read_buffer);
247+
}
248+
249+
dev_dbg(&slave->dev, "command completed %d\n", ret);
250+
251+
out:
252+
pm_runtime_mark_last_busy(&slave->dev);
253+
pm_runtime_put(&slave->dev);
254+
255+
return ret;
256+
}
257+
DEFINE_DEBUGFS_ATTRIBUTE(cmd_go_fops, NULL,
258+
cmd_go, "%llu\n");
259+
260+
#define MAX_LINE_LEN 128
261+
262+
static int read_buffer_show(struct seq_file *s_file, void *data)
263+
{
264+
char buf[MAX_LINE_LEN];
265+
int i;
266+
267+
if (num_bytes == 0 || num_bytes > MAX_CMD_BYTES)
268+
return -EINVAL;
269+
270+
for (i = 0; i < num_bytes; i++) {
271+
scnprintf(buf, MAX_LINE_LEN, "address %#x val 0x%02x\n",
272+
start_addr + i, read_buffer[i]);
273+
seq_printf(s_file, "%s", buf);
274+
}
275+
276+
return 0;
277+
}
278+
DEFINE_SHOW_ATTRIBUTE(read_buffer);
279+
140280
void sdw_slave_debugfs_init(struct sdw_slave *slave)
141281
{
142282
struct dentry *master;
@@ -151,6 +291,16 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave)
151291

152292
debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
153293

294+
/* interface to send arbitrary commands */
295+
debugfs_create_file("command", 0200, d, slave, &set_command_fops);
296+
debugfs_create_file("start_address", 0200, d, slave, &set_start_address_fops);
297+
debugfs_create_file("num_bytes", 0200, d, slave, &set_num_bytes_fops);
298+
debugfs_create_file("go", 0200, d, slave, &cmd_go_fops);
299+
300+
debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops);
301+
firmware_file = NULL;
302+
debugfs_create_str("firmware_file", 0200, d, &firmware_file);
303+
154304
slave->debugfs = d;
155305
}
156306

0 commit comments

Comments
 (0)