Skip to content

Commit 398da8e

Browse files
Gil Finewesteri
authored andcommitted
thunderbolt: debugfs: Add write capability to path config space
Currently debugfs interface allows writing of router, adapter and counters config spaces but not for paths. However, it can be useful during debugging to modify path config space so for this reason add this support to the debugfs interface as well. Signed-off-by: Gil Fine <[email protected]> Signed-off-by: Mika Westerberg <[email protected]>
1 parent 4bbf902 commit 398da8e

File tree

1 file changed

+55
-10
lines changed

1 file changed

+55
-10
lines changed

drivers/thunderbolt/debugfs.c

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ static bool parse_line(char **line, u32 *offs, u32 *val, int short_fmt_len,
168168
* offset relative_offset cap_id vs_cap_id value\n
169169
* v[0] v[1] v[2] v[3] v[4]
170170
*
171+
* For Path configuration space:
172+
* Short format is: offset value\n
173+
* v[0] v[1]
174+
* Long format as produced from the read side:
175+
* offset relative_offset in_hop_id value\n
176+
* v[0] v[1] v[2] v[3]
177+
*
171178
* For Counter configuration space:
172179
* Short format is: offset\n
173180
* v[0]
@@ -191,14 +198,33 @@ static bool parse_line(char **line, u32 *offs, u32 *val, int short_fmt_len,
191198
}
192199

193200
#if IS_ENABLED(CONFIG_USB4_DEBUGFS_WRITE)
201+
/*
202+
* Path registers need to be written in double word pairs and they both must be
203+
* read before written. This writes one double word in patch config space
204+
* following the spec flow.
205+
*/
206+
static int path_write_one(struct tb_port *port, u32 val, u32 offset)
207+
{
208+
u32 index = offset % PATH_LEN;
209+
u32 offs = offset - index;
210+
u32 data[PATH_LEN];
211+
int ret;
212+
213+
ret = tb_port_read(port, data, TB_CFG_HOPS, offs, PATH_LEN);
214+
if (ret)
215+
return ret;
216+
data[index] = val;
217+
return tb_port_write(port, data, TB_CFG_HOPS, offs, PATH_LEN);
218+
}
219+
194220
static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port,
195-
const char __user *user_buf, size_t count,
196-
loff_t *ppos)
221+
enum tb_cfg_space space, const char __user *user_buf,
222+
size_t count, loff_t *ppos)
197223
{
224+
int long_fmt_len, ret = 0;
198225
struct tb *tb = sw->tb;
199226
char *line, *buf;
200227
u32 val, offset;
201-
int ret = 0;
202228

203229
buf = validate_and_copy_from_user(user_buf, &count);
204230
if (IS_ERR(buf))
@@ -214,12 +240,21 @@ static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port,
214240
/* User did hardware changes behind the driver's back */
215241
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
216242

243+
if (space == TB_CFG_HOPS)
244+
long_fmt_len = 4;
245+
else
246+
long_fmt_len = 5;
247+
217248
line = buf;
218-
while (parse_line(&line, &offset, &val, 2, 5)) {
219-
if (port)
220-
ret = tb_port_write(port, &val, TB_CFG_PORT, offset, 1);
221-
else
249+
while (parse_line(&line, &offset, &val, 2, long_fmt_len)) {
250+
if (port) {
251+
if (space == TB_CFG_HOPS)
252+
ret = path_write_one(port, val, offset);
253+
else
254+
ret = tb_port_write(port, &val, space, offset, 1);
255+
} else {
222256
ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, offset, 1);
257+
}
223258
if (ret)
224259
break;
225260
}
@@ -240,7 +275,16 @@ static ssize_t port_regs_write(struct file *file, const char __user *user_buf,
240275
struct seq_file *s = file->private_data;
241276
struct tb_port *port = s->private;
242277

243-
return regs_write(port->sw, port, user_buf, count, ppos);
278+
return regs_write(port->sw, port, TB_CFG_PORT, user_buf, count, ppos);
279+
}
280+
281+
static ssize_t path_write(struct file *file, const char __user *user_buf,
282+
size_t count, loff_t *ppos)
283+
{
284+
struct seq_file *s = file->private_data;
285+
struct tb_port *port = s->private;
286+
287+
return regs_write(port->sw, port, TB_CFG_HOPS, user_buf, count, ppos);
244288
}
245289

246290
static ssize_t switch_regs_write(struct file *file, const char __user *user_buf,
@@ -249,7 +293,7 @@ static ssize_t switch_regs_write(struct file *file, const char __user *user_buf,
249293
struct seq_file *s = file->private_data;
250294
struct tb_switch *sw = s->private;
251295

252-
return regs_write(sw, NULL, user_buf, count, ppos);
296+
return regs_write(sw, NULL, TB_CFG_SWITCH, user_buf, count, ppos);
253297
}
254298

255299
static bool parse_sb_line(char **line, u8 *reg, u8 *data, size_t data_size,
@@ -401,6 +445,7 @@ static ssize_t retimer_sb_regs_write(struct file *file,
401445
#define DEBUGFS_MODE 0600
402446
#else
403447
#define port_regs_write NULL
448+
#define path_write NULL
404449
#define switch_regs_write NULL
405450
#define port_sb_regs_write NULL
406451
#define retimer_sb_regs_write NULL
@@ -2243,7 +2288,7 @@ static int path_show(struct seq_file *s, void *not_used)
22432288

22442289
return ret;
22452290
}
2246-
DEBUGFS_ATTR_RO(path);
2291+
DEBUGFS_ATTR_RW(path);
22472292

22482293
static int counter_set_regs_show(struct tb_port *port, struct seq_file *s,
22492294
int counter)

0 commit comments

Comments
 (0)