From: Vincent Mailhol <hidden> Date: 2021-10-25 17:23:17
The main purpose of this series is to report the CAN controller
capabilities. The proposed method reuses the existing struct
can_ctrlmode and thus do not need a new IFLA_CAN_* entry.
While doing so, I also realized that can_priv::ctrlmode_static could
actually be derived from the other ctrlmode fields. So I added three
extra patches to the series: one to replace that field with a
function, one to add a safeguard on can_set_static_ctrlmode() and one
to repack struct can_priv and fill the hole created after removing
can_priv::ctrlmode_priv.
Please note that the first three patches are not required by the
fourth one. I am just grouping everything in the same series because
the patches all revolve around the controller modes.
** Changelog **
v2 -> v3:
- Make can_set_static_ctrlmode() return an error and adjust the
drivers which use this helper function accordingly.
v1 -> v2:
- Add a first patch to replace can_priv::ctrlmode_static by the
inline function can_get_static_ctrlmode()
- Add a second patch to reorder the fields of struct can_priv for
better packing (save eight bytes on x86_64 \o/)
- Rewrite the comments of the third patch "can: netlink: report the
CAN controller mode supported flags" (no changes on the code
itself).
Vincent Mailhol (4):
can: dev: replace can_priv::ctrlmode_static by
can_get_static_ctrlmode()
can: dev: add sanity check in can_set_static_ctrlmode()
can: dev: reorder struct can_priv members for better packing
can: netlink: report the CAN controller mode supported flags
drivers/net/can/dev/dev.c | 5 +++--
drivers/net/can/dev/netlink.c | 7 +++++--
drivers/net/can/m_can/m_can.c | 10 +++++++---
drivers/net/can/rcar/rcar_canfd.c | 4 +++-
include/linux/can/dev.h | 24 +++++++++++++++++-------
include/uapi/linux/can/netlink.h | 5 ++++-
6 files changed, 39 insertions(+), 16 deletions(-)
--
2.32.0
From: Vincent Mailhol <hidden> Date: 2021-10-25 17:23:34
The statically enabled features of a CAN controller can be retrieved
using below formula:
| u32 ctrlmode_static = priv->ctrlmode & ~priv->ctrlmode_supported;
As such, there is no need to store this information. This patch
removes the field ctrlmode_static of struct can_priv and provides, in
replacement, the inline function can_get_static_ctrlmode() which
returns the same value.
Signed-off-by: Vincent Mailhol <redacted>
---
drivers/net/can/dev/dev.c | 5 +++--
drivers/net/can/dev/netlink.c | 2 +-
include/linux/can/dev.h | 7 +++++--
3 files changed, 9 insertions(+), 5 deletions(-)
@@ -300,6 +300,7 @@ EXPORT_SYMBOL_GPL(free_candev);intcan_change_mtu(structnet_device*dev,intnew_mtu){structcan_priv*priv=netdev_priv(dev);+u32ctrlmode_static=can_get_static_ctrlmode(priv);/* Do not allow changing the MTU while running */if(dev->flags&IFF_UP)
@@ -309,7 +310,7 @@ int can_change_mtu(struct net_device *dev, int new_mtu)switch(new_mtu){caseCAN_MTU:/* 'CANFD-only' controllers can not switch to CAN_MTU */-if(priv->ctrlmode_static&CAN_CTRLMODE_FD)+if(ctrlmode_static&CAN_CTRLMODE_FD)return-EINVAL;priv->ctrlmode&=~CAN_CTRLMODE_FD;
@@ -318,7 +319,7 @@ int can_change_mtu(struct net_device *dev, int new_mtu)caseCANFD_MTU:/* check for potential CANFD ability */if(!(priv->ctrlmode_supported&CAN_CTRLMODE_FD)&&-!(priv->ctrlmode_static&CAN_CTRLMODE_FD))+!(ctrlmode_static&CAN_CTRLMODE_FD))return-EINVAL;priv->ctrlmode|=CAN_CTRLMODE_FD;
@@ -69,7 +69,6 @@ struct can_priv {/* CAN controller features - see include/uapi/linux/can/netlink.h */u32ctrlmode;/* current options setting */u32ctrlmode_supported;/* options that can be modified by netlink */-u32ctrlmode_static;/* static enabled options for driver/hardware */intrestart_ms;structdelayed_workrestart_work;
@@ -139,13 +138,17 @@ static inline void can_set_static_ctrlmode(struct net_device *dev,/* alloc_candev() succeeded => netdev_priv() is valid at this point */priv->ctrlmode=static_mode;-priv->ctrlmode_static=static_mode;/* override MTU which was set by default in can_setup()? */if(static_mode&CAN_CTRLMODE_FD)dev->mtu=CANFD_MTU;}+staticinlineu32can_get_static_ctrlmode(structcan_priv*priv)+{+returnpriv->ctrlmode&~priv->ctrlmode_supported;+}+voidcan_setup(structnet_device*dev);structnet_device*alloc_candev_mqs(intsizeof_priv,unsignedintecho_skb_max,
From: Vincent Mailhol <hidden> Date: 2021-10-25 17:23:46
Previous patch removed can_priv::ctrlmode_static to replace it with
can_get_static_ctrlmode().
A condition sine qua non for this to work is that the controller
static modes should never be set in can_priv::ctrlmode_supported
(c.f. the comment on can_priv::ctrlmode_supported which states that it
is for "options that can be *modified* by netlink"). Also, this
condition is already correctly fulfilled by all existing drivers
which rely on the ctrlmode_static feature.
Nonetheless, we added an extra safeguard in can_set_static_ctrlmode()
to return an error value and to warn the developer who would be
adventurous enough to set to static a given feature that is already
set to supported.
The drivers which rely on the static controller mode are then updated
to check the return value of can_set_static_ctrlmode().
Signed-off-by: Vincent Mailhol <redacted>
---
Some few comments on how the rcar_canfd and m_can drivers free their
allocated resources when an error occurs during probing.
The function rcar_canfd_channel_probe() is quite inconsistent with the
way it handles errors. After the call to alloc_candev, there are
several "goto fail" statements that would directly exit without
calling free_candev()!
Nonetheless, later on the driver will check the return value of
rcar_canfd_channel_probe() and call rcar_canfd_channel_remove() which
will correctly call free_candev(). Even if this is inconsistent, there
is no sign of a memory leak. So I just applied the change the
can_set_static_ctrlmode() without bothering more (N.B. I do not own
that device so I am not willing to take the risk of making bigger
changes because I can not test).
On the other hand, m_can_dev_setup() is fine: the return value is
checked by the caller and necessary actions are taken.
As such, for both driver, we did a minimal change.
---
drivers/net/can/m_can/m_can.c | 10 +++++++---
drivers/net/can/rcar/rcar_canfd.c | 4 +++-
include/linux/can/dev.h | 11 +++++++++--
3 files changed, 19 insertions(+), 6 deletions(-)
@@ -1463,7 +1463,7 @@ static bool m_can_niso_supported(struct m_can_classdev *cdev)staticintm_can_dev_setup(structm_can_classdev*cdev){structnet_device*dev=cdev->net;-intm_can_version;+intm_can_version,err;m_can_version=m_can_check_core_release(cdev);/* return if unsupported version */
@@ -1493,13 +1493,17 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)switch(cdev->version){case30:/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */-can_set_static_ctrlmode(dev,CAN_CTRLMODE_FD_NON_ISO);+err=can_set_static_ctrlmode(dev,CAN_CTRLMODE_FD_NON_ISO);+if(err)+returnerr;cdev->can.bittiming_const=&m_can_bittiming_const_30X;cdev->can.data_bittiming_const=&m_can_data_bittiming_const_30X;break;case31:/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */-can_set_static_ctrlmode(dev,CAN_CTRLMODE_FD_NON_ISO);+err=can_set_static_ctrlmode(dev,CAN_CTRLMODE_FD_NON_ISO);+if(err)+returnerr;cdev->can.bittiming_const=&m_can_bittiming_const_31X;cdev->can.data_bittiming_const=&m_can_data_bittiming_const_31X;break;
@@ -1706,7 +1706,9 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,&rcar_canfd_data_bittiming_const;/* Controller starts in CAN FD only mode */-can_set_static_ctrlmode(ndev,CAN_CTRLMODE_FD);+err=can_set_static_ctrlmode(ndev,CAN_CTRLMODE_FD);+if(err)+gotofail;priv->can.ctrlmode_supported=CAN_CTRLMODE_BERR_REPORTING;}else{/* Controller starts in Classical CAN only mode */
@@ -131,17 +131,24 @@ static inline s32 can_get_relative_tdco(const struct can_priv *priv)}/* helper to define static CAN controller features at device creation time */-staticinlinevoidcan_set_static_ctrlmode(structnet_device*dev,-u32static_mode)+staticinlineint__must_checkcan_set_static_ctrlmode(structnet_device*dev,+u32static_mode){structcan_priv*priv=netdev_priv(dev);/* alloc_candev() succeeded => netdev_priv() is valid at this point */+if(priv->ctrlmode_supported&static_mode){+netdev_warn(dev,+"Controller features can not be supported and static at the same time\n");+return-EINVAL;+}priv->ctrlmode=static_mode;/* override MTU which was set by default in can_setup()? */if(static_mode&CAN_CTRLMODE_FD)dev->mtu=CANFD_MTU;++return0;}staticinlineu32can_get_static_ctrlmode(structcan_priv*priv)
@@ -64,6 +64,9 @@ struct can_priv {structgpio_desc*termination_gpio;u16termination_gpio_ohms[CAN_TERMINATION_GPIO_MAX];+unsignedintecho_skb_max;+structsk_buff**echo_skb;+enumcan_statestate;/* CAN controller features - see include/uapi/linux/can/netlink.h */
From: Vincent Mailhol <hidden> Date: 2021-10-25 17:24:00
This patch introduces a method for the user to check both the
supported and the static capabilities. The proposed method reuses the
existing struct can_ctrlmode and thus do not need a new IFLA_CAN_*
entry.
Currently, the CAN netlink interface provides no easy ways to check
the capabilities of a given controller. The only method from the
command line is to try each CAN_CTRLMODE_* individually to check
whether the netlink interface returns an -EOPNOTSUPP error or not
(alternatively, one may find it easier to directly check the source
code of the driver instead...)
It appears that can_ctrlmode::mask is only used in one direction: from
the userland to the kernel. So we can just reuse this field in the
other direction (from the kernel to userland). But, because the
semantic is different, we use a union to give this field a proper
name: "supported".
Below table explains how the two fields can_ctrlmode::supported and
can_ctrlmode::flags, when masked with any of the CAN_CTRLMODE_* bit
flags, allow us to identify both the supported and the static
capabilities:
supported & flags & Controller capabilities
CAN_CTRLMODE_* CAN_CTRLMODE_*
-----------------------------------------------------------------------
false false Feature not supported (always disabled)
false true Static feature (always enabled)
true false Feature supported but disabled
true true Feature supported and enabled
Signed-off-by: Vincent Mailhol <redacted>
---
Please refer to below link for the iproute2-next counterpart of this
patch:
https://lore.kernel.org/linux-can/20211003050147.569044-1-mailhol.vincent@wanadoo.fr/T/#t
---
drivers/net/can/dev/netlink.c | 5 ++++-
include/uapi/linux/can/netlink.h | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
From: Vincent MAILHOL <hidden> Date: 2021-10-26 03:30:10
On Tue. 26 Oct 2021 at 02:22, Vincent Mailhol
[off-list ref] wrote:
quoted hunk
This patch introduces a method for the user to check both the
supported and the static capabilities. The proposed method reuses the
existing struct can_ctrlmode and thus do not need a new IFLA_CAN_*
entry.
Currently, the CAN netlink interface provides no easy ways to check
the capabilities of a given controller. The only method from the
command line is to try each CAN_CTRLMODE_* individually to check
whether the netlink interface returns an -EOPNOTSUPP error or not
(alternatively, one may find it easier to directly check the source
code of the driver instead...)
It appears that can_ctrlmode::mask is only used in one direction: from
the userland to the kernel. So we can just reuse this field in the
other direction (from the kernel to userland). But, because the
semantic is different, we use a union to give this field a proper
name: "supported".
Below table explains how the two fields can_ctrlmode::supported and
can_ctrlmode::flags, when masked with any of the CAN_CTRLMODE_* bit
flags, allow us to identify both the supported and the static
capabilities:
supported & flags & Controller capabilities
CAN_CTRLMODE_* CAN_CTRLMODE_*
-----------------------------------------------------------------------
false false Feature not supported (always disabled)
false true Static feature (always enabled)
true false Feature supported but disabled
true true Feature supported and enabled
Signed-off-by: Vincent Mailhol <redacted>
---
Please refer to below link for the iproute2-next counterpart of this
patch:
https://lore.kernel.org/linux-can/20211003050147.569044-1-mailhol.vincent@wanadoo.fr/T/#t
---
drivers/net/can/dev/netlink.c | 5 ++++-
include/uapi/linux/can/netlink.h | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
@@ -88,7 +88,10 @@ struct can_berr_counter {*CANcontrollermode*/structcan_ctrlmode{-__u32mask;+union{+__u32mask;/* Userland to kernel */+__u32supported;/* Kernel to userland */+};
While daydreaming during my lunch break, I suddenly remembered
this thread [1] and was concerned that introducing the union
might break the UAPI.
As a matter of fact, the C standard allows the compiler to add
padding at the end of an union. c.f. ISO/IEC 9899-1999, section
6.7.2.1 "Structure and union specifiers", clause 15: "There may
be unnamed padding at the end of a structure or union."
For example, if the kernel were to be compiled with the
-mstructure-size-boundary=64 ARM option in GCC [2], 32 bits of
padding would be introduced after the union, thus breaking the
alignment of the next field: can_ctrlmode::flags.
As far as my knowledge goes, I am not sure whether or not
-mstructure-size-boundary=64 (or similar options on other
architectures) is actually used. Nonetheless, I think it is safer
to declare the union as __attribute__((packed)) to prevent such
padding from occuring.
I will send a v4 later today to address this.
[1] https://lore.kernel.org/linux-can/212c8bc3-89f9-9c33-ed1b-b50ac04e7532@hartkopp.net/T/#u
[2] https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html