diff options
| author | Oliver Hartkopp <socketcan@hartkopp.net> | 2016-03-21 15:18:21 -0400 |
|---|---|---|
| committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2016-05-09 05:07:28 -0400 |
| commit | bb208f144cf3f59d8f89a09a80efd04389718907 (patch) | |
| tree | dbf6d52a61a76aafa28e907d6d419464aa3fba89 | |
| parent | b6fd3aba6041922e115bd8e10539b8545f4120ac (diff) | |
can: fix handling of unmodifiable configuration options
As described in 'can: m_can: tag current CAN FD controllers as non-ISO'
(6cfda7fbebe) it is possible to define fixed configuration options by
setting the according bit in 'ctrlmode' and clear it in 'ctrlmode_supported'.
This leads to the incovenience that the fixed configuration bits can not be
passed by netlink even when they have the correct values (e.g. non-ISO, FD).
This patch fixes that issue and not only allows fixed set bit values to be set
again but now requires(!) to provide these fixed values at configuration time.
A valid CAN FD configuration consists of a nominal/arbitration bittiming, a
data bittiming and a control mode with CAN_CTRLMODE_FD set - which is now
enforced by a new can_validate() function. This fix additionally removed the
inconsistency that was prohibiting the support of 'CANFD-only' controller
drivers, like the RCar CAN FD.
For this reason a new helper can_set_static_ctrlmode() has been introduced to
provide a proper interface to handle static enabled CAN controller options.
Reported-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Reviewed-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
Cc: <stable@vger.kernel.org> # >= 3.18
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
| -rw-r--r-- | drivers/net/can/dev.c | 56 | ||||
| -rw-r--r-- | drivers/net/can/m_can/m_can.c | 2 | ||||
| -rw-r--r-- | include/linux/can/dev.h | 22 |
3 files changed, 73 insertions, 7 deletions
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 141c2a42d7ed..910c12e2638e 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c | |||
| @@ -696,11 +696,17 @@ int can_change_mtu(struct net_device *dev, int new_mtu) | |||
| 696 | /* allow change of MTU according to the CANFD ability of the device */ | 696 | /* allow change of MTU according to the CANFD ability of the device */ |
| 697 | switch (new_mtu) { | 697 | switch (new_mtu) { |
| 698 | case CAN_MTU: | 698 | case CAN_MTU: |
| 699 | /* 'CANFD-only' controllers can not switch to CAN_MTU */ | ||
| 700 | if (priv->ctrlmode_static & CAN_CTRLMODE_FD) | ||
| 701 | return -EINVAL; | ||
| 702 | |||
| 699 | priv->ctrlmode &= ~CAN_CTRLMODE_FD; | 703 | priv->ctrlmode &= ~CAN_CTRLMODE_FD; |
| 700 | break; | 704 | break; |
| 701 | 705 | ||
| 702 | case CANFD_MTU: | 706 | case CANFD_MTU: |
| 703 | if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD)) | 707 | /* check for potential CANFD ability */ |
| 708 | if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) && | ||
| 709 | !(priv->ctrlmode_static & CAN_CTRLMODE_FD)) | ||
| 704 | return -EINVAL; | 710 | return -EINVAL; |
| 705 | 711 | ||
| 706 | priv->ctrlmode |= CAN_CTRLMODE_FD; | 712 | priv->ctrlmode |= CAN_CTRLMODE_FD; |
| @@ -782,6 +788,35 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { | |||
| 782 | = { .len = sizeof(struct can_bittiming_const) }, | 788 | = { .len = sizeof(struct can_bittiming_const) }, |
| 783 | }; | 789 | }; |
| 784 | 790 | ||
| 791 | static int can_validate(struct nlattr *tb[], struct nlattr *data[]) | ||
| 792 | { | ||
| 793 | bool is_can_fd = false; | ||
| 794 | |||
| 795 | /* Make sure that valid CAN FD configurations always consist of | ||
| 796 | * - nominal/arbitration bittiming | ||
| 797 | * - data bittiming | ||
| 798 | * - control mode with CAN_CTRLMODE_FD set | ||
| 799 | */ | ||
| 800 | |||
| 801 | if (data[IFLA_CAN_CTRLMODE]) { | ||
| 802 | struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]); | ||
| 803 | |||
| 804 | is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD; | ||
| 805 | } | ||
| 806 | |||
| 807 | if (is_can_fd) { | ||
| 808 | if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING]) | ||
| 809 | return -EOPNOTSUPP; | ||
| 810 | } | ||
| 811 | |||
| 812 | if (data[IFLA_CAN_DATA_BITTIMING]) { | ||
| 813 | if (!is_can_fd || !data[IFLA_CAN_BITTIMING]) | ||
| 814 | return -EOPNOTSUPP; | ||
| 815 | } | ||
| 816 | |||
| 817 | return 0; | ||
| 818 | } | ||
| 819 | |||
| 785 | static int can_changelink(struct net_device *dev, | 820 | static int can_changelink(struct net_device *dev, |
| 786 | struct nlattr *tb[], struct nlattr *data[]) | 821 | struct nlattr *tb[], struct nlattr *data[]) |
| 787 | { | 822 | { |
| @@ -813,19 +848,31 @@ static int can_changelink(struct net_device *dev, | |||
| 813 | 848 | ||
| 814 | if (data[IFLA_CAN_CTRLMODE]) { | 849 | if (data[IFLA_CAN_CTRLMODE]) { |
| 815 | struct can_ctrlmode *cm; | 850 | struct can_ctrlmode *cm; |
| 851 | u32 ctrlstatic; | ||
| 852 | u32 maskedflags; | ||
| 816 | 853 | ||
| 817 | /* Do not allow changing controller mode while running */ | 854 | /* Do not allow changing controller mode while running */ |
| 818 | if (dev->flags & IFF_UP) | 855 | if (dev->flags & IFF_UP) |
| 819 | return -EBUSY; | 856 | return -EBUSY; |
| 820 | cm = nla_data(data[IFLA_CAN_CTRLMODE]); | 857 | cm = nla_data(data[IFLA_CAN_CTRLMODE]); |
| 858 | ctrlstatic = priv->ctrlmode_static; | ||
| 859 | maskedflags = cm->flags & cm->mask; | ||
| 860 | |||
| 861 | /* check whether provided bits are allowed to be passed */ | ||
| 862 | if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic)) | ||
| 863 | return -EOPNOTSUPP; | ||
| 864 | |||
| 865 | /* do not check for static fd-non-iso if 'fd' is disabled */ | ||
| 866 | if (!(maskedflags & CAN_CTRLMODE_FD)) | ||
| 867 | ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO; | ||
| 821 | 868 | ||
| 822 | /* check whether changed bits are allowed to be modified */ | 869 | /* make sure static options are provided by configuration */ |
| 823 | if (cm->mask & ~priv->ctrlmode_supported) | 870 | if ((maskedflags & ctrlstatic) != ctrlstatic) |
| 824 | return -EOPNOTSUPP; | 871 | return -EOPNOTSUPP; |
| 825 | 872 | ||
| 826 | /* clear bits to be modified and copy the flag values */ | 873 | /* clear bits to be modified and copy the flag values */ |
| 827 | priv->ctrlmode &= ~cm->mask; | 874 | priv->ctrlmode &= ~cm->mask; |
| 828 | priv->ctrlmode |= (cm->flags & cm->mask); | 875 | priv->ctrlmode |= maskedflags; |
| 829 | 876 | ||
| 830 | /* CAN_CTRLMODE_FD can only be set when driver supports FD */ | 877 | /* CAN_CTRLMODE_FD can only be set when driver supports FD */ |
| 831 | if (priv->ctrlmode & CAN_CTRLMODE_FD) | 878 | if (priv->ctrlmode & CAN_CTRLMODE_FD) |
| @@ -966,6 +1013,7 @@ static struct rtnl_link_ops can_link_ops __read_mostly = { | |||
| 966 | .maxtype = IFLA_CAN_MAX, | 1013 | .maxtype = IFLA_CAN_MAX, |
| 967 | .policy = can_policy, | 1014 | .policy = can_policy, |
| 968 | .setup = can_setup, | 1015 | .setup = can_setup, |
| 1016 | .validate = can_validate, | ||
| 969 | .newlink = can_newlink, | 1017 | .newlink = can_newlink, |
| 970 | .changelink = can_changelink, | 1018 | .changelink = can_changelink, |
| 971 | .get_size = can_get_size, | 1019 | .get_size = can_get_size, |
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 39cf911f7a1e..195f15edb32e 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c | |||
| @@ -955,7 +955,7 @@ static struct net_device *alloc_m_can_dev(void) | |||
| 955 | priv->can.do_get_berr_counter = m_can_get_berr_counter; | 955 | priv->can.do_get_berr_counter = m_can_get_berr_counter; |
| 956 | 956 | ||
| 957 | /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ | 957 | /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */ |
| 958 | priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; | 958 | can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO); |
| 959 | 959 | ||
| 960 | /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */ | 960 | /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */ |
| 961 | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | | 961 | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | |
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h index 735f9f8c4e43..5261751f6bd4 100644 --- a/include/linux/can/dev.h +++ b/include/linux/can/dev.h | |||
| @@ -40,8 +40,11 @@ struct can_priv { | |||
| 40 | struct can_clock clock; | 40 | struct can_clock clock; |
| 41 | 41 | ||
| 42 | enum can_state state; | 42 | enum can_state state; |
| 43 | u32 ctrlmode; | 43 | |
| 44 | u32 ctrlmode_supported; | 44 | /* CAN controller features - see include/uapi/linux/can/netlink.h */ |
| 45 | u32 ctrlmode; /* current options setting */ | ||
| 46 | u32 ctrlmode_supported; /* options that can be modified by netlink */ | ||
| 47 | u32 ctrlmode_static; /* static enabled options for driver/hardware */ | ||
| 45 | 48 | ||
| 46 | int restart_ms; | 49 | int restart_ms; |
| 47 | struct timer_list restart_timer; | 50 | struct timer_list restart_timer; |
| @@ -108,6 +111,21 @@ static inline bool can_is_canfd_skb(const struct sk_buff *skb) | |||
| 108 | return skb->len == CANFD_MTU; | 111 | return skb->len == CANFD_MTU; |
| 109 | } | 112 | } |
| 110 | 113 | ||
| 114 | /* helper to define static CAN controller features at device creation time */ | ||
| 115 | static inline void can_set_static_ctrlmode(struct net_device *dev, | ||
| 116 | u32 static_mode) | ||
| 117 | { | ||
| 118 | struct can_priv *priv = netdev_priv(dev); | ||
| 119 | |||
| 120 | /* alloc_candev() succeeded => netdev_priv() is valid at this point */ | ||
| 121 | priv->ctrlmode = static_mode; | ||
| 122 | priv->ctrlmode_static = static_mode; | ||
| 123 | |||
| 124 | /* override MTU which was set by default in can_setup()? */ | ||
| 125 | if (static_mode & CAN_CTRLMODE_FD) | ||
| 126 | dev->mtu = CANFD_MTU; | ||
| 127 | } | ||
| 128 | |||
| 111 | /* get data length from can_dlc with sanitized can_dlc */ | 129 | /* get data length from can_dlc with sanitized can_dlc */ |
| 112 | u8 can_dlc2len(u8 can_dlc); | 130 | u8 can_dlc2len(u8 can_dlc); |
| 113 | 131 | ||
