Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git

This commit is contained in:
Stephen Rothwell 2024-12-20 14:19:59 +11:00
commit 02f8f5ccba

View File

@ -168,6 +168,13 @@ static bool parse_line(char **line, u32 *offs, u32 *val, int short_fmt_len,
* offset relative_offset cap_id vs_cap_id value\n
* v[0] v[1] v[2] v[3] v[4]
*
* For Path configuration space:
* Short format is: offset value\n
* v[0] v[1]
* Long format as produced from the read side:
* offset relative_offset in_hop_id value\n
* v[0] v[1] v[2] v[3]
*
* For Counter configuration space:
* Short format is: offset\n
* v[0]
@ -191,14 +198,33 @@ static bool parse_line(char **line, u32 *offs, u32 *val, int short_fmt_len,
}
#if IS_ENABLED(CONFIG_USB4_DEBUGFS_WRITE)
static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port,
const char __user *user_buf, size_t count,
loff_t *ppos)
/*
* Path registers need to be written in double word pairs and they both must be
* read before written. This writes one double word in patch config space
* following the spec flow.
*/
static int path_write_one(struct tb_port *port, u32 val, u32 offset)
{
u32 index = offset % PATH_LEN;
u32 offs = offset - index;
u32 data[PATH_LEN];
int ret;
ret = tb_port_read(port, data, TB_CFG_HOPS, offs, PATH_LEN);
if (ret)
return ret;
data[index] = val;
return tb_port_write(port, data, TB_CFG_HOPS, offs, PATH_LEN);
}
static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port,
enum tb_cfg_space space, const char __user *user_buf,
size_t count, loff_t *ppos)
{
int long_fmt_len, ret = 0;
struct tb *tb = sw->tb;
char *line, *buf;
u32 val, offset;
int ret = 0;
buf = validate_and_copy_from_user(user_buf, &count);
if (IS_ERR(buf))
@ -214,12 +240,21 @@ static ssize_t regs_write(struct tb_switch *sw, struct tb_port *port,
/* User did hardware changes behind the driver's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
if (space == TB_CFG_HOPS)
long_fmt_len = 4;
else
long_fmt_len = 5;
line = buf;
while (parse_line(&line, &offset, &val, 2, 5)) {
if (port)
ret = tb_port_write(port, &val, TB_CFG_PORT, offset, 1);
else
while (parse_line(&line, &offset, &val, 2, long_fmt_len)) {
if (port) {
if (space == TB_CFG_HOPS)
ret = path_write_one(port, val, offset);
else
ret = tb_port_write(port, &val, space, offset, 1);
} else {
ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, offset, 1);
}
if (ret)
break;
}
@ -240,7 +275,16 @@ static ssize_t port_regs_write(struct file *file, const char __user *user_buf,
struct seq_file *s = file->private_data;
struct tb_port *port = s->private;
return regs_write(port->sw, port, user_buf, count, ppos);
return regs_write(port->sw, port, TB_CFG_PORT, user_buf, count, ppos);
}
static ssize_t path_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct seq_file *s = file->private_data;
struct tb_port *port = s->private;
return regs_write(port->sw, port, TB_CFG_HOPS, user_buf, count, ppos);
}
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,
struct seq_file *s = file->private_data;
struct tb_switch *sw = s->private;
return regs_write(sw, NULL, user_buf, count, ppos);
return regs_write(sw, NULL, TB_CFG_SWITCH, user_buf, count, ppos);
}
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,
#define DEBUGFS_MODE 0600
#else
#define port_regs_write NULL
#define path_write NULL
#define switch_regs_write NULL
#define port_sb_regs_write NULL
#define retimer_sb_regs_write NULL
@ -2243,7 +2288,7 @@ static int path_show(struct seq_file *s, void *not_used)
return ret;
}
DEBUGFS_ATTR_RO(path);
DEBUGFS_ATTR_RW(path);
static int counter_set_regs_show(struct tb_port *port, struct seq_file *s,
int counter)