* [RFC PATCH v2 1/3] iplink_can: add CAN XL support RFC based on Vincent cleanups
@ 2024-12-04 7:57 Oliver Hartkopp
2024-12-04 7:57 ` [RFC PATCH v2 2/3] iplink_can: canxl: support Remote Request Substitution bit access Oliver Hartkopp
2024-12-04 7:57 ` [RFC PATCH v2 3/3] iplink_can: canxl: support CAN XL transceiver switching in data phase Oliver Hartkopp
0 siblings, 2 replies; 3+ messages in thread
From: Oliver Hartkopp @ 2024-12-04 7:57 UTC (permalink / raw)
To: linux-can; +Cc: Oliver Hartkopp
Fixes from Oliver:
- remove newline before tdc information to increase readability
- fix copy/paste issue in CAN_CTRLMODE_XL_TDC_ definitions
Based on the iproute2 CAN XL preparations patch set at
https://lore.kernel.org/linux-can/173194923075.4109060.18408610499610779344.git-patchwork-notify@kernel.org/T/#t
which was already merged into iproute2-next tree:
https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=7b4d64895f7c58a12c01d2f394f75b0d1938eb9c
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
include/uapi/linux/can/netlink.h | 21 ++-
ip/iplink_can.c | 223 ++++++++++++++++++++++++++++---
2 files changed, 216 insertions(+), 28 deletions(-)
diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h
index 8ec98c21..416e2feb 100644
--- a/include/uapi/linux/can/netlink.h
+++ b/include/uapi/linux/can/netlink.h
@@ -99,12 +99,15 @@ struct can_ctrlmode {
#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */
#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */
-#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically calculates TDCV */
-#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */
+#define CAN_CTRLMODE_TDC_AUTO 0x200 /* FD transceiver automatically calculates TDCV */
+#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* FD TDCV is manually set up by user */
+#define CAN_CTRLMODE_XL 0x800 /* CAN XL mode */
+#define CAN_CTRLMODE_XL_TDC_AUTO 0x1000 /* XL transceiver automatically calculates TDCV */
+#define CAN_CTRLMODE_XL_TDC_MANUAL 0x2000 /* XL TDCV is manually set up by user */
/*
* CAN device statistics
*/
struct can_device_stats {
@@ -127,27 +130,31 @@ enum {
IFLA_CAN_STATE,
IFLA_CAN_CTRLMODE,
IFLA_CAN_RESTART_MS,
IFLA_CAN_RESTART,
IFLA_CAN_BERR_COUNTER,
- IFLA_CAN_DATA_BITTIMING,
- IFLA_CAN_DATA_BITTIMING_CONST,
+ IFLA_CAN_DATA_BITTIMING, /* FD */
+ IFLA_CAN_DATA_BITTIMING_CONST, /* FD */
IFLA_CAN_TERMINATION,
IFLA_CAN_TERMINATION_CONST,
IFLA_CAN_BITRATE_CONST,
- IFLA_CAN_DATA_BITRATE_CONST,
+ IFLA_CAN_DATA_BITRATE_CONST, /* FD */
IFLA_CAN_BITRATE_MAX,
- IFLA_CAN_TDC,
+ IFLA_CAN_TDC, /* FD */
IFLA_CAN_CTRLMODE_EXT,
+ IFLA_CAN_XL_DATA_BITTIMING,
+ IFLA_CAN_XL_DATA_BITTIMING_CONST,
+ IFLA_CAN_XL_DATA_BITRATE_CONST,
+ IFLA_CAN_XL_TDC,
/* add new constants above here */
__IFLA_CAN_MAX,
IFLA_CAN_MAX = __IFLA_CAN_MAX - 1
};
/*
- * CAN FD Transmitter Delay Compensation (TDC)
+ * CAN FD/XL Transmitter Delay Compensation (TDC)
*
* Please refer to struct can_tdc_const and can_tdc in
* include/linux/can/bittiming.h for further details.
*/
enum {
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index fcffa852..8dc9229b 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -13,16 +13,10 @@
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
-struct can_tdc {
- __u32 tdcv;
- __u32 tdco;
- __u32 tdcf;
-};
-
static void print_usage(FILE *f)
{
fprintf(f,
"Usage: ip link set DEVICE type can\n"
"\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |\n"
@@ -30,20 +24,26 @@ static void print_usage(FILE *f)
"\n"
"\t[ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |\n"
"\t[ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n \t dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]\n"
"\t[ tdcv TDCV tdco TDCO tdcf TDCF ]\n"
"\n"
+ "\t[ xbitrate BITRATE [ xsample-point SAMPLE-POINT] ] |\n"
+ "\t[ xtq TQ xprop-seg PROP_SEG xphase-seg1 PHASE-SEG1\n \t xphase-seg2 PHASE-SEG2 [ xsjw SJW ] ]\n"
+ "\t[ xtdcv TDCV xtdco TDCO xtdcf TDCF ]\n"
+ "\n"
"\t[ loopback { on | off } ]\n"
"\t[ listen-only { on | off } ]\n"
"\t[ triple-sampling { on | off } ]\n"
"\t[ one-shot { on | off } ]\n"
"\t[ berr-reporting { on | off } ]\n"
"\t[ fd { on | off } ]\n"
"\t[ fd-non-iso { on | off } ]\n"
"\t[ presume-ack { on | off } ]\n"
"\t[ cc-len8-dlc { on | off } ]\n"
"\t[ tdc-mode { auto | manual | off } ]\n"
+ "\t[ xl { on | off } ]\n"
+ "\t[ xtdc-mode { auto | manual | off } ]\n"
"\n"
"\t[ restart-ms TIME-MS ]\n"
"\t[ restart ]\n"
"\n"
"\t[ termination { 0..65535 } ]\n"
@@ -120,23 +120,33 @@ static void print_ctrlmode(enum output_type t, __u32 flags, const char* key)
print_flag(t, &flags, CAN_CTRLMODE_FD_NON_ISO, "FD-NON-ISO");
print_flag(t, &flags, CAN_CTRLMODE_PRESUME_ACK, "PRESUME-ACK");
print_flag(t, &flags, CAN_CTRLMODE_CC_LEN8_DLC, "CC-LEN8-DLC");
print_flag(t, &flags, CAN_CTRLMODE_TDC_AUTO, "TDC-AUTO");
print_flag(t, &flags, CAN_CTRLMODE_TDC_MANUAL, "TDC-MANUAL");
+ print_flag(t, &flags, CAN_CTRLMODE_XL, "XL");
+ print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_AUTO, "XL-TDC-AUTO");
+ print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_MANUAL, "XL-TDC-MANUAL");
if (flags)
print_hex(t, NULL, "%x", flags);
close_json_array(t, "> ");
}
+struct can_tdc {
+ __u32 tdcv;
+ __u32 tdco;
+ __u32 tdcf;
+};
+
static int can_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
- struct can_bittiming bt = {}, fd_dbt = {};
+ struct can_bittiming bt = {}, fd_dbt = {}, xl_dbt = {};
struct can_ctrlmode cm = { 0 };
struct can_tdc fd = { .tdcv = -1, .tdco = -1, .tdcf = -1 };
+ struct can_tdc xl = { .tdcv = -1, .tdco = -1, .tdcf = -1 };
while (argc > 0) {
if (matches(*argv, "bitrate") == 0) {
NEXT_ARG();
if (get_u32(&bt.bitrate, *argv, 0))
@@ -210,10 +220,57 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
invarg("invalid \"tdco\" value", *argv);
} else if (matches(*argv, "tdcf") == 0) {
NEXT_ARG();
if (get_u32(&fd.tdcf, *argv, 0))
invarg("invalid \"tdcf\" value", *argv);
+ } else if (matches(*argv, "xl") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("xl", *argv, &cm,
+ CAN_CTRLMODE_XL);
+ } else if (matches(*argv, "xbitrate") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl_dbt.bitrate, *argv, 0))
+ invarg("invalid \"xbitrate\" value", *argv);
+ } else if (matches(*argv, "xsample-point") == 0) {
+ float sp;
+
+ NEXT_ARG();
+ if (get_float(&sp, *argv))
+ invarg("invalid \"xsample-point\" value", *argv);
+ xl_dbt.sample_point = (__u32)(sp * 1000);
+ } else if (matches(*argv, "xtq") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl_dbt.tq, *argv, 0))
+ invarg("invalid \"xtq\" value", *argv);
+ } else if (matches(*argv, "xprop-seg") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl_dbt.prop_seg, *argv, 0))
+ invarg("invalid \"xprop-seg\" value", *argv);
+ } else if (matches(*argv, "xphase-seg1") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl_dbt.phase_seg1, *argv, 0))
+ invarg("invalid \"xphase-seg1\" value", *argv);
+ } else if (matches(*argv, "xphase-seg2") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl_dbt.phase_seg2, *argv, 0))
+ invarg("invalid \"xphase-seg2\" value", *argv);
+ } else if (matches(*argv, "xsjw") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl_dbt.sjw, *argv, 0))
+ invarg("invalid \"xsjw\" value", *argv);
+ } else if (matches(*argv, "xtdcv") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl.tdcv, *argv, 0))
+ invarg("invalid \"xtdcv\" value", *argv);
+ } else if (matches(*argv, "xtdco") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl.tdco, *argv, 0))
+ invarg("invalid \"xtdco\" value", *argv);
+ } else if (matches(*argv, "xtdcf") == 0) {
+ NEXT_ARG();
+ if (get_u32(&xl.tdcf, *argv, 0))
+ invarg("invalid \"xtdcf\" value", *argv);
} else if (matches(*argv, "loopback") == 0) {
NEXT_ARG();
set_ctrlmode("loopback", *argv, &cm,
CAN_CTRLMODE_LOOPBACK);
} else if (matches(*argv, "listen-only") == 0) {
@@ -261,10 +318,25 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
CAN_CTRLMODE_TDC_MANUAL;
} else {
invarg("\"tdc-mode\" must be either of \"auto\", \"manual\" or \"off\"",
*argv);
}
+ } else if (matches(*argv, "xtdc-mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "auto") == 0) {
+ cm.flags |= CAN_CTRLMODE_XL_TDC_AUTO;
+ cm.mask |= CAN_CTRLMODE_XL_TDC_AUTO;
+ } else if (strcmp(*argv, "manual") == 0) {
+ cm.flags |= CAN_CTRLMODE_XL_TDC_MANUAL;
+ cm.mask |= CAN_CTRLMODE_XL_TDC_MANUAL;
+ } else if (strcmp(*argv, "off") == 0) {
+ cm.mask |= CAN_CTRLMODE_XL_TDC_AUTO |
+ CAN_CTRLMODE_XL_TDC_MANUAL;
+ } else {
+ invarg("\"xtdc-mode\" must be either of \"auto\", \"manual\" or \"off\"",
+ *argv);
+ }
} else if (matches(*argv, "restart") == 0) {
__u32 val = 1;
addattr32(n, 1024, IFLA_CAN_RESTART, val);
} else if (matches(*argv, "restart-ms") == 0) {
@@ -295,10 +367,12 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
if (bt.bitrate || bt.tq)
addattr_l(n, 1024, IFLA_CAN_BITTIMING, &bt, sizeof(bt));
if (fd_dbt.bitrate || fd_dbt.tq)
addattr_l(n, 1024, IFLA_CAN_DATA_BITTIMING, &fd_dbt, sizeof(fd_dbt));
+ if (xl_dbt.bitrate || xl_dbt.tq)
+ addattr_l(n, 1024, IFLA_CAN_XL_DATA_BITTIMING, &xl_dbt, sizeof(xl_dbt));
if (cm.mask)
addattr_l(n, 1024, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
if (fd.tdcv != -1 || fd.tdco != -1 || fd.tdcf != -1) {
struct rtattr *tdc = addattr_nest(n, 1024,
@@ -310,10 +384,22 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
addattr32(n, 1024, IFLA_CAN_TDC_TDCO, fd.tdco);
if (fd.tdcf != -1)
addattr32(n, 1024, IFLA_CAN_TDC_TDCF, fd.tdcf);
addattr_nest_end(n, tdc);
}
+ if (xl.tdcv != -1 || xl.tdco != -1 || xl.tdcf != -1) {
+ struct rtattr *tdc = addattr_nest(n, 1024,
+ IFLA_CAN_XL_TDC | NLA_F_NESTED);
+
+ if (xl.tdcv != -1)
+ addattr32(n, 1024, IFLA_CAN_TDC_TDCV, xl.tdcv);
+ if (xl.tdco != -1)
+ addattr32(n, 1024, IFLA_CAN_TDC_TDCO, xl.tdco);
+ if (xl.tdcf != -1)
+ addattr32(n, 1024, IFLA_CAN_TDC_TDCF, xl.tdcf);
+ addattr_nest_end(n, tdc);
+ }
return 0;
}
static const char *can_state_names[CAN_STATE_MAX] = {
@@ -340,62 +426,69 @@ can_print_timing_min_max(const char *json_attr, const char *fp_attr,
print_uint(PRINT_ANY, "min", " %d", min);
print_uint(PRINT_ANY, "max", "..%d", max);
close_json_object();
}
-static void can_print_tdc_opt(struct rtattr *tdc_attr)
+static void can_print_tdc_opt(struct rtattr *tdc_attr, bool is_xl)
{
struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr);
if (tb[IFLA_CAN_TDC_TDCV] || tb[IFLA_CAN_TDC_TDCO] ||
tb[IFLA_CAN_TDC_TDCF]) {
- open_json_object("tdc");
- can_print_nl_indent();
+ const char *tdc = is_xl ? "xtdc" : "tdc";
+
+ open_json_object(tdc);
if (tb[IFLA_CAN_TDC_TDCV]) {
+ const char *tdcv_fmt = is_xl ? " xtdcv %u" : " tdcv %u";
__u32 *tdcv = RTA_DATA(tb[IFLA_CAN_TDC_TDCV]);
- print_uint(PRINT_ANY, "tdcv", " tdcv %u", *tdcv);
+ print_uint(PRINT_ANY, "tdcv", tdcv_fmt, *tdcv);
}
if (tb[IFLA_CAN_TDC_TDCO]) {
+ const char *tdco_fmt = is_xl ? " xtdco %u" : " tdco %u";
__u32 *tdco = RTA_DATA(tb[IFLA_CAN_TDC_TDCO]);
- print_uint(PRINT_ANY, "tdco", " tdco %u", *tdco);
+ print_uint(PRINT_ANY, "tdco", tdco_fmt, *tdco);
}
if (tb[IFLA_CAN_TDC_TDCF]) {
+ const char *tdcf_fmt = is_xl ? " xtdcf %u" : " tdcf %u";
__u32 *tdcf = RTA_DATA(tb[IFLA_CAN_TDC_TDCF]);
- print_uint(PRINT_ANY, "tdcf", " tdcf %u", *tdcf);
+ print_uint(PRINT_ANY, "tdcf", tdcf_fmt, *tdcf);
}
close_json_object();
}
}
-static void can_print_tdc_const_opt(struct rtattr *tdc_attr)
+static void can_print_tdc_const_opt(struct rtattr *tdc_attr, bool is_xl)
{
+ const char *tdc = is_xl ? "xtdc" : "tdc";
struct rtattr *tb[IFLA_CAN_TDC_MAX + 1];
parse_rtattr_nested(tb, IFLA_CAN_TDC_MAX, tdc_attr);
- open_json_object("tdc");
- can_print_nl_indent();
+ open_json_object(tdc);
if (tb[IFLA_CAN_TDC_TDCV_MIN] && tb[IFLA_CAN_TDC_TDCV_MAX]) {
__u32 *tdcv_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCV_MIN]);
__u32 *tdcv_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCV_MAX]);
+ const char *tdcv = is_xl ? " xtdcv" : " tdcv";
- can_print_timing_min_max("tdcv", " tdcv", *tdcv_min, *tdcv_max);
+ can_print_timing_min_max("tdcv", tdcv, *tdcv_min, *tdcv_max);
}
if (tb[IFLA_CAN_TDC_TDCO_MIN] && tb[IFLA_CAN_TDC_TDCO_MAX]) {
__u32 *tdco_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCO_MIN]);
__u32 *tdco_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCO_MAX]);
+ const char *tdco = is_xl ? " xtdco" : " tdco";
- can_print_timing_min_max("tdco", " tdco", *tdco_min, *tdco_max);
+ can_print_timing_min_max("tdco", tdco, *tdco_min, *tdco_max);
}
if (tb[IFLA_CAN_TDC_TDCF_MIN] && tb[IFLA_CAN_TDC_TDCF_MAX]) {
__u32 *tdcf_min = RTA_DATA(tb[IFLA_CAN_TDC_TDCF_MIN]);
__u32 *tdcf_max = RTA_DATA(tb[IFLA_CAN_TDC_TDCF_MAX]);
+ const char *tdcf = is_xl ? " xtdcf" : " tdcf";
- can_print_timing_min_max("tdcf", " tdcf", *tdcf_min, *tdcf_max);
+ can_print_timing_min_max("tdcf", tdcf, *tdcf_min, *tdcf_max);
}
close_json_object();
}
static void can_print_ctrlmode_ext(struct rtattr *ctrlmode_ext_attr,
@@ -545,11 +638,11 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
dbt->phase_seg2);
print_uint(PRINT_ANY, "sjw", " dsjw %u", dbt->sjw);
print_uint(PRINT_ANY, "brp", " dbrp %u", dbt->brp);
if (tb[IFLA_CAN_TDC])
- can_print_tdc_opt(tb[IFLA_CAN_TDC]);
+ can_print_tdc_opt(tb[IFLA_CAN_TDC], false);
close_json_object();
}
/* data bittiming const is irrelevant if fixed bitrate is defined */
@@ -569,11 +662,11 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
can_print_timing_min_max("brp", " dbrp",
dbtc->brp_min, dbtc->brp_max);
print_uint(PRINT_ANY, "brp_inc", " dbrp_inc %u", dbtc->brp_inc);
if (tb[IFLA_CAN_TDC])
- can_print_tdc_const_opt(tb[IFLA_CAN_TDC]);
+ can_print_tdc_const_opt(tb[IFLA_CAN_TDC], false);
close_json_object();
}
if (tb[IFLA_CAN_DATA_BITRATE_CONST]) {
@@ -608,10 +701,98 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
dbitrate_const[i]);
}
close_json_array(PRINT_ANY, " ]");
}
+ /* data bittiming is irrelevant if fixed bitrate is defined */
+ if (tb[IFLA_CAN_XL_DATA_BITTIMING] &&
+ !tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) {
+ struct can_bittiming *dbt =
+ RTA_DATA(tb[IFLA_CAN_XL_DATA_BITTIMING]);
+ char dsp[6];
+
+ open_json_object("xl_data_bittiming");
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "bitrate", " xbitrate %u", dbt->bitrate);
+ snprintf(dsp, sizeof(dsp), "%.3f", dbt->sample_point / 1000.);
+ print_string(PRINT_ANY, "sample_point", " xsample-point %s",
+ dsp);
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "tq", " xtq %u", dbt->tq);
+ print_uint(PRINT_ANY, "prop_seg", " xprop-seg %u",
+ dbt->prop_seg);
+ print_uint(PRINT_ANY, "phase_seg1", " xphase-seg1 %u",
+ dbt->phase_seg1);
+ print_uint(PRINT_ANY, "phase_seg2", " xphase-seg2 %u",
+ dbt->phase_seg2);
+ print_uint(PRINT_ANY, "sjw", " xsjw %u", dbt->sjw);
+ print_uint(PRINT_ANY, "brp", " xbrp %u", dbt->brp);
+
+ if (tb[IFLA_CAN_XL_TDC])
+ can_print_tdc_opt(tb[IFLA_CAN_XL_TDC], true);
+
+ close_json_object();
+ }
+
+ /* data bittiming const is irrelevant if fixed bitrate is defined */
+ if (tb[IFLA_CAN_XL_DATA_BITTIMING_CONST] &&
+ !tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) {
+ struct can_bittiming_const *dbtc =
+ RTA_DATA(tb[IFLA_CAN_XL_DATA_BITTIMING_CONST]);
+
+ open_json_object("xl_data_bittiming_const");
+ can_print_nl_indent();
+ print_string(PRINT_ANY, "name", " %s:", dbtc->name);
+ can_print_timing_min_max("tseg1", " xtseg1",
+ dbtc->tseg1_min, dbtc->tseg1_max);
+ can_print_timing_min_max("tseg2", " xtseg2",
+ dbtc->tseg2_min, dbtc->tseg2_max);
+ can_print_timing_min_max("sjw", " xsjw", 1, dbtc->sjw_max);
+ can_print_timing_min_max("brp", " xbrp",
+ dbtc->brp_min, dbtc->brp_max);
+ print_uint(PRINT_ANY, "brp_inc", " xbrp_inc %u", dbtc->brp_inc);
+
+ if (tb[IFLA_CAN_XL_TDC])
+ can_print_tdc_const_opt(tb[IFLA_CAN_XL_TDC], true);
+
+ close_json_object();
+ }
+
+ if (tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) {
+ __u32 *dbitrate_const =
+ RTA_DATA(tb[IFLA_CAN_XL_DATA_BITRATE_CONST]);
+ int dbitrate_cnt =
+ RTA_PAYLOAD(tb[IFLA_CAN_XL_DATA_BITRATE_CONST]) /
+ sizeof(*dbitrate_const);
+ int i;
+ __u32 dbitrate = 0;
+
+ if (tb[IFLA_CAN_XL_DATA_BITTIMING]) {
+ struct can_bittiming *dbt =
+ RTA_DATA(tb[IFLA_CAN_XL_DATA_BITTIMING]);
+ dbitrate = dbt->bitrate;
+ }
+
+ can_print_nl_indent();
+ print_uint(PRINT_ANY, "xl_data_bittiming_bitrate", " xbitrate %u",
+ dbitrate);
+ can_print_nl_indent();
+ open_json_array(PRINT_ANY, is_json_context() ?
+ "data_bitrate_const" : " [");
+ for (i = 0; i < dbitrate_cnt; ++i) {
+ /* This will keep lines below 80 signs */
+ if (!(i % 6) && i) {
+ can_print_nl_indent();
+ print_string(PRINT_FP, NULL, "%s", " ");
+ }
+ print_uint(PRINT_ANY, NULL,
+ i < dbitrate_cnt - 1 ? "%8u, " : "%8u",
+ dbitrate_const[i]);
+ }
+ close_json_array(PRINT_ANY, " ]");
+ }
+
if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) {
__u16 *trm = RTA_DATA(tb[IFLA_CAN_TERMINATION]);
__u16 *trm_const = RTA_DATA(tb[IFLA_CAN_TERMINATION_CONST]);
int trm_cnt = RTA_PAYLOAD(tb[IFLA_CAN_TERMINATION_CONST]) /
sizeof(*trm_const);
--
2.45.2
^ permalink raw reply related [flat|nested] 3+ messages in thread* [RFC PATCH v2 2/3] iplink_can: canxl: support Remote Request Substitution bit access
2024-12-04 7:57 [RFC PATCH v2 1/3] iplink_can: add CAN XL support RFC based on Vincent cleanups Oliver Hartkopp
@ 2024-12-04 7:57 ` Oliver Hartkopp
2024-12-04 7:57 ` [RFC PATCH v2 3/3] iplink_can: canxl: support CAN XL transceiver switching in data phase Oliver Hartkopp
1 sibling, 0 replies; 3+ messages in thread
From: Oliver Hartkopp @ 2024-12-04 7:57 UTC (permalink / raw)
To: linux-can; +Cc: Oliver Hartkopp
The Remote Request Substitution bit is a dominant bit ("0") in the CAN XL
frame. As some CAN XL controllers support to access this bit a new
CANXL_RRS value has been defined for the canxl_frame.flags element.
To read/write the Remote Request Substitution (RRS) bit in the CAN XL
frame the CAN_CTRLMODE_XL_RRS has to be enabled in CAN driver.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
include/uapi/linux/can.h | 5 ++++-
include/uapi/linux/can/netlink.h | 1 +
ip/iplink_can.c | 6 ++++++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h
index 229a77ff..513d3d75 100644
--- a/include/uapi/linux/can.h
+++ b/include/uapi/linux/can.h
@@ -180,20 +180,23 @@ struct canfd_frame {
};
/*
* defined bits for canxl_frame.flags
*
- * The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
+ * The canxl_frame.flags element contains three bits CANXL_[XLF|SEC|RRS]
* and shares the relative position of the struct can[fd]_frame.len element.
* The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
* As a side effect setting this bit intentionally breaks the length checks
* for Classical CAN and CAN FD frames.
+ * To read/write the Remote Request Substitution (RRS) bit in the CAN XL
+ * frame the CAN_CTRLMODE_XL_RRS has to be enabled in CAN driver.
*
* Undefined bits in canxl_frame.flags are reserved and shall be set to zero.
*/
#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
+#define CANXL_RRS 0x02 /* Remote Request Substitution */
/* the 8-bit VCID is optionally placed in the canxl_frame.prio element */
#define CANXL_VCID_OFFSET 16 /* bit offset of VCID in prio element */
#define CANXL_VCID_VAL_MASK 0xFFUL /* VCID is an 8-bit value */
#define CANXL_VCID_MASK (CANXL_VCID_VAL_MASK << CANXL_VCID_OFFSET)
diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h
index 416e2feb..19267678 100644
--- a/include/uapi/linux/can/netlink.h
+++ b/include/uapi/linux/can/netlink.h
@@ -104,10 +104,11 @@ struct can_ctrlmode {
#define CAN_CTRLMODE_TDC_AUTO 0x200 /* FD transceiver automatically calculates TDCV */
#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* FD TDCV is manually set up by user */
#define CAN_CTRLMODE_XL 0x800 /* CAN XL mode */
#define CAN_CTRLMODE_XL_TDC_AUTO 0x1000 /* XL transceiver automatically calculates TDCV */
#define CAN_CTRLMODE_XL_TDC_MANUAL 0x2000 /* XL TDCV is manually set up by user */
+#define CAN_CTRLMODE_XL_RRS 0x4000 /* XL enable RRS bit access */
/*
* CAN device statistics
*/
struct can_device_stats {
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index 8dc9229b..9fe9ae6c 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -40,10 +40,11 @@ static void print_usage(FILE *f)
"\t[ presume-ack { on | off } ]\n"
"\t[ cc-len8-dlc { on | off } ]\n"
"\t[ tdc-mode { auto | manual | off } ]\n"
"\t[ xl { on | off } ]\n"
"\t[ xtdc-mode { auto | manual | off } ]\n"
+ "\t[ xlrrs { on | off } ]\n"
"\n"
"\t[ restart-ms TIME-MS ]\n"
"\t[ restart ]\n"
"\n"
"\t[ termination { 0..65535 } ]\n"
@@ -123,10 +124,11 @@ static void print_ctrlmode(enum output_type t, __u32 flags, const char* key)
print_flag(t, &flags, CAN_CTRLMODE_TDC_AUTO, "TDC-AUTO");
print_flag(t, &flags, CAN_CTRLMODE_TDC_MANUAL, "TDC-MANUAL");
print_flag(t, &flags, CAN_CTRLMODE_XL, "XL");
print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_AUTO, "XL-TDC-AUTO");
print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_MANUAL, "XL-TDC-MANUAL");
+ print_flag(t, &flags, CAN_CTRLMODE_XL_RRS, "XL-RRS");
if (flags)
print_hex(t, NULL, "%x", flags);
close_json_array(t, "> ");
@@ -333,10 +335,14 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
CAN_CTRLMODE_XL_TDC_MANUAL;
} else {
invarg("\"xtdc-mode\" must be either of \"auto\", \"manual\" or \"off\"",
*argv);
}
+ } else if (matches(*argv, "xlrrs") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("xlrrs", *argv, &cm,
+ CAN_CTRLMODE_XL_RRS);
} else if (matches(*argv, "restart") == 0) {
__u32 val = 1;
addattr32(n, 1024, IFLA_CAN_RESTART, val);
} else if (matches(*argv, "restart-ms") == 0) {
--
2.45.2
^ permalink raw reply related [flat|nested] 3+ messages in thread* [RFC PATCH v2 3/3] iplink_can: canxl: support CAN XL transceiver switching in data phase
2024-12-04 7:57 [RFC PATCH v2 1/3] iplink_can: add CAN XL support RFC based on Vincent cleanups Oliver Hartkopp
2024-12-04 7:57 ` [RFC PATCH v2 2/3] iplink_can: canxl: support Remote Request Substitution bit access Oliver Hartkopp
@ 2024-12-04 7:57 ` Oliver Hartkopp
1 sibling, 0 replies; 3+ messages in thread
From: Oliver Hartkopp @ 2024-12-04 7:57 UTC (permalink / raw)
To: linux-can; +Cc: Oliver Hartkopp
In the CAN XL data phase the CAN XL controller can advise the CAN XL
transceiver to switch the physical layer.
To enable this feature the CAN_CTRLMODE_XL_TRX has to be set in the
driver control mode.
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
---
include/uapi/linux/can/netlink.h | 1 +
ip/iplink_can.c | 6 ++++++
2 files changed, 7 insertions(+)
diff --git a/include/uapi/linux/can/netlink.h b/include/uapi/linux/can/netlink.h
index 19267678..bea58373 100644
--- a/include/uapi/linux/can/netlink.h
+++ b/include/uapi/linux/can/netlink.h
@@ -105,10 +105,11 @@ struct can_ctrlmode {
#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* FD TDCV is manually set up by user */
#define CAN_CTRLMODE_XL 0x800 /* CAN XL mode */
#define CAN_CTRLMODE_XL_TDC_AUTO 0x1000 /* XL transceiver automatically calculates TDCV */
#define CAN_CTRLMODE_XL_TDC_MANUAL 0x2000 /* XL TDCV is manually set up by user */
#define CAN_CTRLMODE_XL_RRS 0x4000 /* XL enable RRS bit access */
+#define CAN_CTRLMODE_XL_TRX 0x8000 /* XL switch trx in data phase */
/*
* CAN device statistics
*/
struct can_device_stats {
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index 9fe9ae6c..18854c2b 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -41,10 +41,11 @@ static void print_usage(FILE *f)
"\t[ cc-len8-dlc { on | off } ]\n"
"\t[ tdc-mode { auto | manual | off } ]\n"
"\t[ xl { on | off } ]\n"
"\t[ xtdc-mode { auto | manual | off } ]\n"
"\t[ xlrrs { on | off } ]\n"
+ "\t[ xltrx { on | off } ]\n"
"\n"
"\t[ restart-ms TIME-MS ]\n"
"\t[ restart ]\n"
"\n"
"\t[ termination { 0..65535 } ]\n"
@@ -125,10 +126,11 @@ static void print_ctrlmode(enum output_type t, __u32 flags, const char* key)
print_flag(t, &flags, CAN_CTRLMODE_TDC_MANUAL, "TDC-MANUAL");
print_flag(t, &flags, CAN_CTRLMODE_XL, "XL");
print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_AUTO, "XL-TDC-AUTO");
print_flag(t, &flags, CAN_CTRLMODE_XL_TDC_MANUAL, "XL-TDC-MANUAL");
print_flag(t, &flags, CAN_CTRLMODE_XL_RRS, "XL-RRS");
+ print_flag(t, &flags, CAN_CTRLMODE_XL_TRX, "XL-TRX");
if (flags)
print_hex(t, NULL, "%x", flags);
close_json_array(t, "> ");
@@ -339,10 +341,14 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv,
}
} else if (matches(*argv, "xlrrs") == 0) {
NEXT_ARG();
set_ctrlmode("xlrrs", *argv, &cm,
CAN_CTRLMODE_XL_RRS);
+ } else if (matches(*argv, "xltrx") == 0) {
+ NEXT_ARG();
+ set_ctrlmode("xltrx", *argv, &cm,
+ CAN_CTRLMODE_XL_TRX);
} else if (matches(*argv, "restart") == 0) {
__u32 val = 1;
addattr32(n, 1024, IFLA_CAN_RESTART, val);
} else if (matches(*argv, "restart-ms") == 0) {
--
2.45.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-12-04 7:57 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-12-04 7:57 [RFC PATCH v2 1/3] iplink_can: add CAN XL support RFC based on Vincent cleanups Oliver Hartkopp
2024-12-04 7:57 ` [RFC PATCH v2 2/3] iplink_can: canxl: support Remote Request Substitution bit access Oliver Hartkopp
2024-12-04 7:57 ` [RFC PATCH v2 3/3] iplink_can: canxl: support CAN XL transceiver switching in data phase Oliver Hartkopp
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox