mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
thunderbolt: Add extended error counter support for software lane margining
Add support for software margining extended error counters. Increase the results buffer size to accommodate the new dwords used for extended error counters for RX0, RX1 and RX2. Signed-off-by: Rene Sapiens <rene.sapiens@linux.intel.com> Co-developed-by: Anurag <anurag@intel.com> Signed-off-by: Anurag <anurag@intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
This commit is contained in:
parent
c4f71538ee
commit
879519402c
|
|
@ -38,6 +38,7 @@
|
|||
#define COUNTER_SET_LEN 3
|
||||
|
||||
#define HW_MARGINING_DWORDS 3
|
||||
#define SW_MARGINING_DWORDS 4
|
||||
|
||||
/*
|
||||
* USB4 spec doesn't specify dwell range, the range of 100 ms to 500 ms
|
||||
|
|
@ -496,7 +497,7 @@ struct tb_margining {
|
|||
unsigned int gen;
|
||||
bool asym_rx;
|
||||
u32 caps[3];
|
||||
u32 results[3];
|
||||
u32 results[5];
|
||||
enum usb4_margining_lane lanes;
|
||||
unsigned int min_ber_level;
|
||||
unsigned int max_ber_level;
|
||||
|
|
@ -614,6 +615,11 @@ supports_optional_voltage_offset_range(const struct tb_margining *margining)
|
|||
return margining->caps[0] & USB4_MARGIN_CAP_0_OPT_VOLTAGE_SUPPORT;
|
||||
}
|
||||
|
||||
static bool supports_extended_error_counter(const struct tb_margining *margining)
|
||||
{
|
||||
return margining->caps[0] & USB4_MARGIN_CAP_0_EXT_ERR_COUNTER;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
margining_ber_level_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
|
@ -703,6 +709,8 @@ static int margining_caps_show(struct seq_file *s, void *not_used)
|
|||
ber_level_show(s, margining->max_ber_level);
|
||||
} else {
|
||||
seq_puts(s, "# hardware margining: no\n");
|
||||
seq_printf(s, "# extended error counter: %s\n",
|
||||
str_yes_no(supports_extended_error_counter(margining)));
|
||||
}
|
||||
|
||||
seq_printf(s, "# all lanes simultaneously: %s\n",
|
||||
|
|
@ -1157,10 +1165,16 @@ static int margining_run_sw(struct tb_margining *margining,
|
|||
{
|
||||
u32 nsamples = margining->dwell_time / DWELL_SAMPLE_INTERVAL;
|
||||
int ret, i;
|
||||
u32 dwords;
|
||||
|
||||
if (params->error_counter != USB4_MARGIN_SW_ERROR_COUNTER_START)
|
||||
goto out_stop_or_clear;
|
||||
|
||||
if (supports_extended_error_counter(margining))
|
||||
dwords = SW_MARGINING_DWORDS;
|
||||
else
|
||||
dwords = 1;
|
||||
|
||||
ret = usb4_port_sw_margin(margining->port, margining->target, margining->index,
|
||||
params, margining->results);
|
||||
if (ret)
|
||||
|
|
@ -1170,7 +1184,8 @@ static int margining_run_sw(struct tb_margining *margining,
|
|||
u32 errors = 0;
|
||||
|
||||
ret = usb4_port_sw_margin_errors(margining->port, margining->target,
|
||||
margining->index, &margining->results[1]);
|
||||
margining->index, &margining->results[1],
|
||||
dwords);
|
||||
if (ret) {
|
||||
tb_port_warn(margining->port, "failed to read margining error counters\n");
|
||||
break;
|
||||
|
|
@ -1450,18 +1465,30 @@ static int margining_results_show(struct seq_file *s, void *not_used)
|
|||
u32 lane_errors, result;
|
||||
|
||||
seq_printf(s, "0x%08x\n", margining->results[1]);
|
||||
if (supports_extended_error_counter(margining)) {
|
||||
seq_printf(s, "0x%08x\n", margining->results[2]);
|
||||
seq_printf(s, "0x%08x\n", margining->results[3]);
|
||||
seq_printf(s, "0x%08x\n", margining->results[4]);
|
||||
}
|
||||
|
||||
|
||||
result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]);
|
||||
if (result == USB4_MARGINING_LANE_RX0 ||
|
||||
result == USB4_MARGINING_LANE_ALL) {
|
||||
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK,
|
||||
margining->results[1]);
|
||||
if (supports_extended_error_counter(margining))
|
||||
lane_errors |= FIELD_PREP(USB4_MARGIN_SW_EXT_ERR_COUNTER_MASK,
|
||||
margining->results[2]);
|
||||
seq_printf(s, "# lane 0 errors: %u\n", lane_errors);
|
||||
}
|
||||
if (result == USB4_MARGINING_LANE_RX1 ||
|
||||
result == USB4_MARGINING_LANE_ALL) {
|
||||
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK,
|
||||
margining->results[1]);
|
||||
if (supports_extended_error_counter(margining))
|
||||
lane_errors |= FIELD_PREP(USB4_MARGIN_SW_EXT_ERR_COUNTER_MASK,
|
||||
margining->results[3]);
|
||||
seq_printf(s, "# lane 1 errors: %u\n", lane_errors);
|
||||
}
|
||||
if (margining->asym_rx &&
|
||||
|
|
@ -1469,6 +1496,9 @@ static int margining_results_show(struct seq_file *s, void *not_used)
|
|||
result == USB4_MARGINING_LANE_ALL)) {
|
||||
lane_errors = FIELD_GET(USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK,
|
||||
margining->results[1]);
|
||||
if (supports_extended_error_counter(margining))
|
||||
lane_errors |= FIELD_PREP(USB4_MARGIN_SW_EXT_ERR_COUNTER_MASK,
|
||||
margining->results[4]);
|
||||
seq_printf(s, "# lane 2 errors: %u\n", lane_errors);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ enum usb4_sb_opcode {
|
|||
#define USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK GENMASK(18, 13)
|
||||
#define USB4_MARGIN_CAP_0_OPT_VOLTAGE_SUPPORT BIT(19)
|
||||
#define USB4_MARGIN_CAP_0_VOLT_STEPS_OPT_MASK GENMASK(26, 20)
|
||||
#define USB4_MARGIN_CAP_0_EXT_ERR_COUNTER BIT(28)
|
||||
#define USB4_MARGIN_CAP_1_MAX_VOLT_OFS_OPT_MASK GENMASK(7, 0)
|
||||
#define USB4_MARGIN_CAP_1_TIME_DESTR BIT(8)
|
||||
#define USB4_MARGIN_CAP_1_TIME_INDP_MASK GENMASK(10, 9)
|
||||
|
|
@ -108,5 +109,6 @@ enum usb4_sb_opcode {
|
|||
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_0_MASK GENMASK(3, 0)
|
||||
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_1_MASK GENMASK(7, 4)
|
||||
#define USB4_MARGIN_SW_ERR_COUNTER_LANE_2_MASK GENMASK(11, 8)
|
||||
#define USB4_MARGIN_SW_EXT_ERR_COUNTER_MASK GENMASK(15, 4)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1442,7 +1442,7 @@ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
|
|||
u8 index, const struct usb4_port_margining_params *params,
|
||||
u32 *results);
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *errors);
|
||||
u8 index, u32 *errors, size_t dwords);
|
||||
|
||||
int usb4_port_retimer_set_inbound_sbtx(struct tb_port *port, u8 index);
|
||||
int usb4_port_retimer_unset_inbound_sbtx(struct tb_port *port, u8 index);
|
||||
|
|
|
|||
|
|
@ -1826,13 +1826,14 @@ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target,
|
|||
* @target: Sideband target
|
||||
* @index: Retimer index if target is %USB4_SB_TARGET_RETIMER
|
||||
* @errors: Error metadata is copied here.
|
||||
* @dwords: Number of dwords to read error counter values
|
||||
*
|
||||
* This reads back the software margining error counters from the port.
|
||||
*
|
||||
* Return: %0 on success, negative errno otherwise.
|
||||
*/
|
||||
int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
|
||||
u8 index, u32 *errors)
|
||||
u8 index, u32 *errors, size_t dwords)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -1842,7 +1843,7 @@ int usb4_port_sw_margin_errors(struct tb_port *port, enum usb4_sb_target target,
|
|||
return ret;
|
||||
|
||||
return usb4_port_sb_read(port, target, index, USB4_SB_METADATA, errors,
|
||||
sizeof(*errors));
|
||||
sizeof(*errors) * dwords);
|
||||
}
|
||||
|
||||
static inline int usb4_port_retimer_op(struct tb_port *port, u8 index,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user