* [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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.