Lines Matching full:margining
393 * struct tb_margining - Lane margining support
394 * @port: USB4 port through which the margining operations are run
398 * @caps: Port lane margining capabilities
399 * @results: Last lane margining results
411 * @voltage_time_offset: Offset for voltage / time for software margining
412 * @dwell_time: Dwell time for software margining (in ms)
413 * @error_counter: Error counter operation for software margining
415 * @software: %true if software margining is used instead of hardware
416 * @time: %true if time margining is used instead of voltage
446 static int margining_modify_error_counter(struct tb_margining *margining, in margining_modify_error_counter() argument
450 struct tb_port *port = margining->port; in margining_modify_error_counter()
460 return usb4_port_sw_margin(port, margining->target, margining->index, in margining_modify_error_counter()
464 static bool supports_software(const struct tb_margining *margining) in supports_software() argument
466 return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_SW; in supports_software()
469 static bool supports_hardware(const struct tb_margining *margining) in supports_hardware() argument
471 return margining->caps[0] & USB4_MARGIN_CAP_0_MODES_HW; in supports_hardware()
474 static bool both_lanes(const struct tb_margining *margining) in both_lanes() argument
476 return margining->caps[0] & USB4_MARGIN_CAP_0_2_LANES; in both_lanes()
480 independent_voltage_margins(const struct tb_margining *margining) in independent_voltage_margins() argument
482 return FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_INDP_MASK, margining->caps[0]); in independent_voltage_margins()
485 static bool supports_time(const struct tb_margining *margining) in supports_time() argument
487 return margining->caps[0] & USB4_MARGIN_CAP_0_TIME; in supports_time()
492 independent_time_margins(const struct tb_margining *margining) in independent_time_margins() argument
494 return FIELD_GET(USB4_MARGIN_CAP_1_TIME_INDP_MASK, margining->caps[1]); in independent_time_margins()
498 supports_optional_voltage_offset_range(const struct tb_margining *margining) in supports_optional_voltage_offset_range() argument
500 return margining->caps[0] & USB4_MARGIN_CAP_0_OPT_VOLTAGE_SUPPORT; in supports_optional_voltage_offset_range()
508 struct tb_margining *margining = s->private; in margining_ber_level_write() local
509 struct tb *tb = margining->port->sw->tb; in margining_ber_level_write()
517 if (margining->software) { in margining_ber_level_write()
534 if (val < margining->min_ber_level || in margining_ber_level_write()
535 val > margining->max_ber_level) { in margining_ber_level_write()
540 margining->ber_level = val; in margining_ber_level_write()
560 const struct tb_margining *margining = s->private; in margining_ber_level_show() local
562 if (margining->software) in margining_ber_level_show()
564 ber_level_show(s, margining->ber_level); in margining_ber_level_show()
571 struct tb_margining *margining = s->private; in margining_caps_show() local
572 struct tb *tb = margining->port->sw->tb; in margining_caps_show()
579 cap0 = margining->caps[0]; in margining_caps_show()
581 cap1 = margining->caps[1]; in margining_caps_show()
584 seq_printf(s, "# software margining: %s\n", in margining_caps_show()
585 supports_software(margining) ? "yes" : "no"); in margining_caps_show()
586 if (supports_hardware(margining)) { in margining_caps_show()
587 seq_puts(s, "# hardware margining: yes\n"); in margining_caps_show()
589 ber_level_show(s, margining->min_ber_level); in margining_caps_show()
591 ber_level_show(s, margining->max_ber_level); in margining_caps_show()
593 seq_puts(s, "# hardware margining: no\n"); in margining_caps_show()
597 both_lanes(margining) ? "yes" : "no"); in margining_caps_show()
599 margining->voltage_steps); in margining_caps_show()
601 margining->max_voltage_offset); in margining_caps_show()
603 str_yes_no(supports_optional_voltage_offset_range(margining))); in margining_caps_show()
604 if (supports_optional_voltage_offset_range(margining)) { in margining_caps_show()
606 margining->voltage_steps_optional_range); in margining_caps_show()
608 margining->max_voltage_offset_optional_range); in margining_caps_show()
611 switch (independent_voltage_margins(margining)) { in margining_caps_show()
623 if (supports_time(margining)) { in margining_caps_show()
624 seq_puts(s, "# time margining: yes\n"); in margining_caps_show()
625 seq_printf(s, "# time margining is destructive: %s\n", in margining_caps_show()
628 switch (independent_time_margins(margining)) { in margining_caps_show()
641 margining->time_steps); in margining_caps_show()
643 margining->max_time_offset); in margining_caps_show()
645 seq_puts(s, "# time margining: no\n"); in margining_caps_show()
658 struct tb_margining *margining = s->private; in margining_lanes_write() local
659 struct tb *tb = margining->port->sw->tb; in margining_lanes_write()
675 margining->lanes = 0; in margining_lanes_write()
677 margining->lanes = 1; in margining_lanes_write()
680 if (both_lanes(margining)) in margining_lanes_write()
681 margining->lanes = 7; in margining_lanes_write()
697 struct tb_margining *margining = s->private; in margining_lanes_show() local
698 struct tb *tb = margining->port->sw->tb; in margining_lanes_show()
704 lanes = margining->lanes; in margining_lanes_show()
705 if (both_lanes(margining)) { in margining_lanes_show()
730 struct tb_margining *margining = s->private; in margining_voltage_time_offset_write() local
731 struct tb *tb = margining->port->sw->tb; in margining_voltage_time_offset_write()
741 if (!margining->software) in margining_voltage_time_offset_write()
744 if (margining->time) in margining_voltage_time_offset_write()
745 max_margin = margining->time_steps; in margining_voltage_time_offset_write()
747 if (margining->optional_voltage_offset_range) in margining_voltage_time_offset_write()
748 max_margin = margining->voltage_steps_optional_range; in margining_voltage_time_offset_write()
750 max_margin = margining->voltage_steps; in margining_voltage_time_offset_write()
752 margining->voltage_time_offset = clamp(val, 0, max_margin); in margining_voltage_time_offset_write()
761 const struct tb_margining *margining = s->private; in margining_voltage_time_offset_show() local
762 struct tb *tb = margining->port->sw->tb; in margining_voltage_time_offset_show()
765 if (!margining->software) in margining_voltage_time_offset_show()
768 seq_printf(s, "%d\n", margining->voltage_time_offset); in margining_voltage_time_offset_show()
781 struct tb_margining *margining = s->private; in margining_error_counter_write() local
782 struct tb *tb = margining->port->sw->tb; in margining_error_counter_write()
803 if (!margining->software) in margining_error_counter_write()
806 margining->error_counter = error_counter; in margining_error_counter_write()
814 const struct tb_margining *margining = s->private; in margining_error_counter_show() local
815 struct tb *tb = margining->port->sw->tb; in margining_error_counter_show()
818 if (!margining->software) in margining_error_counter_show()
821 switch (margining->error_counter) { in margining_error_counter_show()
846 struct tb_margining *margining = s->private; in margining_dwell_time_write() local
847 struct tb *tb = margining->port->sw->tb; in margining_dwell_time_write()
856 if (!margining->software) in margining_dwell_time_write()
859 margining->dwell_time = clamp(val, MIN_DWELL_TIME, MAX_DWELL_TIME); in margining_dwell_time_write()
867 struct tb_margining *margining = s->private; in margining_dwell_time_show() local
868 struct tb *tb = margining->port->sw->tb; in margining_dwell_time_show()
871 if (!margining->software) in margining_dwell_time_show()
874 seq_printf(s, "%d\n", margining->dwell_time); in margining_dwell_time_show()
886 struct tb_margining *margining = s->private; in margining_optional_voltage_offset_write() local
887 struct tb *tb = margining->port->sw->tb; in margining_optional_voltage_offset_write()
896 margining->optional_voltage_offset_range = val; in margining_optional_voltage_offset_write()
905 struct tb_margining *margining = s->private; in margining_optional_voltage_offset_show() local
906 struct tb *tb = margining->port->sw->tb; in margining_optional_voltage_offset_show()
909 seq_printf(s, "%u\n", margining->optional_voltage_offset_range); in margining_optional_voltage_offset_show()
921 struct tb_margining *margining = s->private; in margining_mode_write() local
922 struct tb *tb = margining->port->sw->tb; in margining_mode_write()
938 if (supports_software(margining)) in margining_mode_write()
939 margining->software = true; in margining_mode_write()
943 if (supports_hardware(margining)) in margining_mode_write()
944 margining->software = false; in margining_mode_write()
960 struct tb_margining *margining = s->private; in margining_mode_show() local
961 struct tb *tb = margining->port->sw->tb; in margining_mode_show()
967 if (supports_software(margining)) { in margining_mode_show()
968 if (margining->software) in margining_mode_show()
974 if (supports_hardware(margining)) { in margining_mode_show()
975 if (margining->software) in margining_mode_show()
988 static int margining_run_sw(struct tb_margining *margining, in margining_run_sw() argument
991 u32 nsamples = margining->dwell_time / DWELL_SAMPLE_INTERVAL; in margining_run_sw()
994 ret = usb4_port_sw_margin(margining->port, margining->target, margining->index, in margining_run_sw()
995 params, margining->results); in margining_run_sw()
1002 ret = usb4_port_sw_margin_errors(margining->port, margining->target, in margining_run_sw()
1003 margining->index, &margining->results[1]); in margining_run_sw()
1007 if (margining->lanes == USB4_MARGIN_SW_LANE_0) in margining_run_sw()
1009 margining->results[1]); in margining_run_sw()
1010 else if (margining->lanes == USB4_MARGIN_SW_LANE_1) in margining_run_sw()
1012 margining->results[1]); in margining_run_sw()
1013 else if (margining->lanes == USB4_MARGIN_SW_ALL_LANES) in margining_run_sw()
1014 errors = margining->results[1]; in margining_run_sw()
1028 margining_modify_error_counter(margining, margining->lanes, in margining_run_sw()
1035 struct tb_margining *margining = data; in margining_run_write() local
1036 struct tb_port *port = margining->port; in margining_run_write()
1037 struct device *dev = margining->dev; in margining_run_write()
1062 * CL states may interfere with lane margining so in margining_run_write()
1074 memset(margining->results, 0, sizeof(margining->results)); in margining_run_write()
1076 if (margining->software) { in margining_run_write()
1079 .lanes = margining->lanes, in margining_run_write()
1080 .time = margining->time, in margining_run_write()
1081 .voltage_time_offset = margining->voltage_time_offset, in margining_run_write()
1082 .right_high = margining->right_high, in margining_run_write()
1083 .optional_voltage_offset_range = margining->optional_voltage_offset_range, in margining_run_write()
1087 "running software %s lane margining for %s lanes %u\n", in margining_run_write()
1088 margining->time ? "time" : "voltage", dev_name(dev), in margining_run_write()
1089 margining->lanes); in margining_run_write()
1091 ret = margining_run_sw(margining, ¶ms); in margining_run_write()
1094 .ber_level = margining->ber_level, in margining_run_write()
1095 .lanes = margining->lanes, in margining_run_write()
1096 .time = margining->time, in margining_run_write()
1097 .right_high = margining->right_high, in margining_run_write()
1098 .optional_voltage_offset_range = margining->optional_voltage_offset_range, in margining_run_write()
1102 "running hardware %s lane margining for %s lanes %u\n", in margining_run_write()
1103 margining->time ? "time" : "voltage", dev_name(dev), in margining_run_write()
1104 margining->lanes); in margining_run_write()
1106 ret = usb4_port_hw_margin(port, margining->target, margining->index, ¶ms, in margining_run_write()
1107 margining->results); in margining_run_write()
1128 struct tb_margining *margining = s->private; in margining_results_write() local
1129 struct tb *tb = margining->port->sw->tb; in margining_results_write()
1135 margining->results[0] = 0; in margining_results_write()
1136 margining->results[1] = 0; in margining_results_write()
1138 if (margining->software) { in margining_results_write()
1140 margining_modify_error_counter(margining, in margining_results_write()
1150 const struct tb_margining *margining, u8 val) in voltage_margin_show() argument
1155 voltage = tmp * margining->max_voltage_offset / margining->voltage_steps; in voltage_margin_show()
1160 if (margining->optional_voltage_offset_range) in voltage_margin_show()
1165 const struct tb_margining *margining, u8 val) in time_margin_show() argument
1170 interval = tmp * margining->max_time_offset / margining->time_steps; in time_margin_show()
1179 struct tb_margining *margining = s->private; in margining_results_show() local
1180 struct tb *tb = margining->port->sw->tb; in margining_results_show()
1186 seq_printf(s, "0x%08x\n", margining->results[0]); in margining_results_show()
1187 /* Only the hardware margining has two result dwords */ in margining_results_show()
1188 if (!margining->software) { in margining_results_show()
1191 seq_printf(s, "0x%08x\n", margining->results[1]); in margining_results_show()
1193 if (margining->time) { in margining_results_show()
1194 if (!margining->lanes || margining->lanes == 7) { in margining_results_show()
1195 val = margining->results[1]; in margining_results_show()
1197 time_margin_show(s, margining, val); in margining_results_show()
1198 val = margining->results[1] >> in margining_results_show()
1201 time_margin_show(s, margining, val); in margining_results_show()
1203 if (margining->lanes == 1 || margining->lanes == 7) { in margining_results_show()
1204 val = margining->results[1] >> in margining_results_show()
1207 time_margin_show(s, margining, val); in margining_results_show()
1208 val = margining->results[1] >> in margining_results_show()
1211 time_margin_show(s, margining, val); in margining_results_show()
1214 if (!margining->lanes || margining->lanes == 7) { in margining_results_show()
1215 val = margining->results[1]; in margining_results_show()
1217 voltage_margin_show(s, margining, val); in margining_results_show()
1218 val = margining->results[1] >> in margining_results_show()
1221 voltage_margin_show(s, margining, val); in margining_results_show()
1223 if (margining->lanes == 1 || margining->lanes == 7) { in margining_results_show()
1224 val = margining->results[1] >> in margining_results_show()
1227 voltage_margin_show(s, margining, val); in margining_results_show()
1228 val = margining->results[1] >> in margining_results_show()
1231 voltage_margin_show(s, margining, val); in margining_results_show()
1237 seq_printf(s, "0x%08x\n", margining->results[1]); in margining_results_show()
1238 result = FIELD_GET(USB4_MARGIN_SW_LANES_MASK, margining->results[0]); in margining_results_show()
1243 margining->results[1]); in margining_results_show()
1249 margining->results[1]); in margining_results_show()
1264 struct tb_margining *margining = s->private; in margining_test_write() local
1265 struct tb *tb = margining->port->sw->tb; in margining_test_write()
1280 if (!strcmp(buf, "time") && supports_time(margining)) in margining_test_write()
1281 margining->time = true; in margining_test_write()
1283 margining->time = false; in margining_test_write()
1296 struct tb_margining *margining = s->private; in margining_test_show() local
1297 struct tb *tb = margining->port->sw->tb; in margining_test_show()
1302 if (supports_time(margining)) { in margining_test_show()
1303 if (margining->time) in margining_test_show()
1321 struct tb_margining *margining = s->private; in margining_margin_write() local
1322 struct tb *tb = margining->port->sw->tb; in margining_margin_write()
1337 if (margining->time) { in margining_margin_write()
1339 margining->right_high = false; in margining_margin_write()
1341 margining->right_high = true; in margining_margin_write()
1346 margining->right_high = false; in margining_margin_write()
1348 margining->right_high = true; in margining_margin_write()
1362 struct tb_margining *margining = s->private; in margining_margin_show() local
1363 struct tb *tb = margining->port->sw->tb; in margining_margin_show()
1368 if (margining->time) { in margining_margin_show()
1369 if (margining->right_high) in margining_margin_show()
1374 if (margining->right_high) in margining_margin_show()
1390 struct tb_margining *margining; in margining_alloc() local
1395 margining = kzalloc(sizeof(*margining), GFP_KERNEL); in margining_alloc()
1396 if (!margining) in margining_alloc()
1399 margining->port = port; in margining_alloc()
1400 margining->target = target; in margining_alloc()
1401 margining->index = index; in margining_alloc()
1402 margining->dev = dev; in margining_alloc()
1404 ret = usb4_port_margining_caps(port, target, index, margining->caps); in margining_alloc()
1406 kfree(margining); in margining_alloc()
1411 if (supports_software(margining)) in margining_alloc()
1412 margining->software = true; in margining_alloc()
1414 val = FIELD_GET(USB4_MARGIN_CAP_0_VOLTAGE_STEPS_MASK, margining->caps[0]); in margining_alloc()
1415 margining->voltage_steps = val; in margining_alloc()
1416 val = FIELD_GET(USB4_MARGIN_CAP_0_MAX_VOLTAGE_OFFSET_MASK, margining->caps[0]); in margining_alloc()
1417 margining->max_voltage_offset = 74 + val * 2; in margining_alloc()
1419 if (supports_optional_voltage_offset_range(margining)) { in margining_alloc()
1421 margining->caps[0]); in margining_alloc()
1422 margining->voltage_steps_optional_range = val; in margining_alloc()
1424 margining->caps[1]); in margining_alloc()
1425 margining->max_voltage_offset_optional_range = 74 + val * 2; in margining_alloc()
1428 if (supports_time(margining)) { in margining_alloc()
1429 val = FIELD_GET(USB4_MARGIN_CAP_1_TIME_STEPS_MASK, margining->caps[1]); in margining_alloc()
1430 margining->time_steps = val; in margining_alloc()
1431 val = FIELD_GET(USB4_MARGIN_CAP_1_TIME_OFFSET_MASK, margining->caps[1]); in margining_alloc()
1436 margining->max_time_offset = 200 + 10 * val; in margining_alloc()
1439 dir = debugfs_create_dir("margining", parent); in margining_alloc()
1440 if (supports_hardware(margining)) { in margining_alloc()
1441 val = FIELD_GET(USB4_MARGIN_CAP_1_MIN_BER_MASK, margining->caps[1]); in margining_alloc()
1442 margining->min_ber_level = val; in margining_alloc()
1443 val = FIELD_GET(USB4_MARGIN_CAP_1_MAX_BER_MASK, margining->caps[1]); in margining_alloc()
1444 margining->max_ber_level = val; in margining_alloc()
1447 margining->ber_level = margining->min_ber_level; in margining_alloc()
1449 debugfs_create_file("ber_level_contour", 0400, dir, margining, in margining_alloc()
1452 debugfs_create_file("caps", 0400, dir, margining, &margining_caps_fops); in margining_alloc()
1453 debugfs_create_file("lanes", 0600, dir, margining, &margining_lanes_fops); in margining_alloc()
1454 debugfs_create_file("mode", 0600, dir, margining, &margining_mode_fops); in margining_alloc()
1455 debugfs_create_file("run", 0600, dir, margining, &margining_run_fops); in margining_alloc()
1456 debugfs_create_file("results", 0600, dir, margining, in margining_alloc()
1458 debugfs_create_file("test", 0600, dir, margining, &margining_test_fops); in margining_alloc()
1459 if (independent_voltage_margins(margining) == USB4_MARGIN_CAP_0_VOLTAGE_HL || in margining_alloc()
1460 (supports_time(margining) && in margining_alloc()
1461 independent_time_margins(margining) == USB4_MARGIN_CAP_1_TIME_LR)) in margining_alloc()
1462 debugfs_create_file("margin", 0600, dir, margining, in margining_alloc()
1465 margining->error_counter = USB4_MARGIN_SW_ERROR_COUNTER_CLEAR; in margining_alloc()
1466 margining->dwell_time = MIN_DWELL_TIME; in margining_alloc()
1468 if (supports_optional_voltage_offset_range(margining)) in margining_alloc()
1469 debugfs_create_file("optional_voltage_offset", DEBUGFS_MODE, dir, margining, in margining_alloc()
1472 if (supports_software(margining)) { in margining_alloc()
1473 debugfs_create_file("voltage_time_offset", DEBUGFS_MODE, dir, margining, in margining_alloc()
1475 debugfs_create_file("error_counter", DEBUGFS_MODE, dir, margining, in margining_alloc()
1477 debugfs_create_file("dwell_time", DEBUGFS_MODE, dir, margining, in margining_alloc()
1480 return margining; in margining_alloc()
1493 port->usb4->margining = margining_alloc(port, &port->usb4->dev, in margining_port_init()
1509 debugfs_lookup_and_remove("margining", parent); in margining_port_remove()
1511 kfree(port->usb4->margining); in margining_port_remove()
1512 port->usb4->margining = NULL; in margining_port_remove()
1572 rt->margining = margining_alloc(rt->port, &rt->dev, in margining_retimer_init()
1579 kfree(rt->margining); in margining_retimer_remove()
1580 rt->margining = NULL; in margining_retimer_remove()