mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2025-01-20 12:54:36 +08:00
Merge branch 'can-refactoring-of-can-dev-module-and-of-Kbuild'
Vincent Mailhol says ==================== Aside of calc_bittiming.o which can be configured with CAN_CALC_BITTIMING, all objects from drivers/net/can/dev/ get linked unconditionally to can-dev.o even if not needed by the user. This series first goal it to split the can-dev modules so that the only the needed features get built in during compilation. Additionally, the CAN Device Drivers menu is moved from the "Networking support" category to the "Device Drivers" category (where all drivers are supposed to be). * menu before this series * CAN bus subsystem support symbol: CONFIG_CAN | +-> CAN Device Drivers (no symbol) | +-> software/virtual CAN device drivers | (at time of writing: slcan, vcan, vxcan) | +-> Platform CAN drivers with Netlink support symbol: CONFIG_CAN_DEV | +-> CAN bit-timing calculation (optional for hardware drivers) | symbol: CONFIG_CAN_CALC_BITTIMING | +-> All other CAN devices drivers * menu after this series * Network device support symbol: CONFIG_NETDEVICES | +-> CAN Device Drivers symbol: CONFIG_CAN_DEV | +-> software/virtual CAN device drivers | (at time of writing: slcan, vcan, vxcan) | +-> CAN device drivers with Netlink support symbol: CONFIG_CAN_NETLINK (matches previous CONFIG_CAN_DEV) | +-> CAN bit-timing calculation (optional for all drivers) | symbol: CONFIG_CAN_CALC_BITTIMING | +-> All other CAN devices drivers (some may select CONFIG_CAN_RX_OFFLOAD) | +-> CAN rx offload (automatically selected by some drivers) (hidden symbol: CONFIG_CAN_RX_OFFLOAD) Patches 1 to 5 of this series do above modification. The last two patches add a check toward CAN_CTRLMODE_LISTENONLY in can_dropped_invalid_skb() to discard tx skb (such skb can potentially reach the driver if injected via the packet socket). In more details, patch 6 moves can_dropped_invalid_skb() from skb.h to skb.o and patch 7 is the actual change. Those last two patches are actually connected to the first five ones: because slcan and v(x)can requires can_dropped_invalid_skb(), it was necessary to add those three devices to the scope of can-dev before moving the function to skb.o. This design results from the lengthy discussion in [1]. [1] https://lore.kernel.org/linux-can/20220514141650.1109542-1-mailhol.vincent@wanadoo.fr/ ** Changelog ** v5 -> v6: * fix typo in patch #1's title: Kbuild -> Kconfig. * make CONFIG_RX_CAN an hidden config symbol and modify the diagram in the cover letter accordingly. @Oliver, with CONFIG_CAN_RX_OFFLOAD now being an hidden config, that option fully depends on the drivers. So contrary to your suggestion, I put CONFIG_CAN_RX_OFFLOAD below the device drivers in the diagram. * fix typo in cover letter: CONFIG_CAN_BITTIMING -> CONFIG_CAN_CALC_BITTIMING. v4 -> v5: * m_can is also requires RX offload. Add the "select CAN_RX_OFFLOAD" to its Makefile. * Reorder the lines of drivers/net/can/dev/Makefile. * Remove duplicated rx-offload.o target in drivers/net/can/dev/Makefile * Remove the Nota Bene in the cover letter. v3 -> v4: * Five additional patches added to split can-dev module and refactor Kbuild. c.f. below (lengthy) thread: https://lore.kernel.org/linux-can/20220514141650.1109542-1-mailhol.vincent@wanadoo.fr/ v2 -> v3: * Apply can_dropped_invalid_skb() to slcan. * Make vcan, vxcan and slcan dependent of CONFIG_CAN_DEV by modifying Kbuild. * fix small typos. v1 -> v2: * move can_dropped_invalid_skb() to skb.c instead of dev.h * also move can_skb_headroom_valid() to skb.c ==================== Link: https://lore.kernel.org/all/20220610143009.323579-1-mailhol.vincent@wanadoo.fr Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
commit
6914df1891
@ -499,6 +499,8 @@ config NET_SB1000
|
||||
|
||||
source "drivers/net/phy/Kconfig"
|
||||
|
||||
source "drivers/net/can/Kconfig"
|
||||
|
||||
source "drivers/net/mctp/Kconfig"
|
||||
|
||||
source "drivers/net/mdio/Kconfig"
|
||||
|
@ -1,5 +1,26 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menu "CAN Device Drivers"
|
||||
|
||||
menuconfig CAN_DEV
|
||||
tristate "CAN Device Drivers"
|
||||
default y
|
||||
depends on CAN
|
||||
help
|
||||
Controller Area Network (CAN) is serial communications protocol up to
|
||||
1Mbit/s for its original release (now known as Classical CAN) and up
|
||||
to 8Mbit/s for the more recent CAN with Flexible Data-Rate
|
||||
(CAN-FD). The CAN bus was originally mainly for automotive, but is now
|
||||
widely used in marine (NMEA2000), industrial, and medical
|
||||
applications. More information on the CAN network protocol family
|
||||
PF_CAN is contained in <Documentation/networking/can.rst>.
|
||||
|
||||
This section contains all the CAN(-FD) device drivers including the
|
||||
virtual ones. If you own such devices or plan to use the virtual CAN
|
||||
interfaces to develop applications, say Y here.
|
||||
|
||||
To compile as a module, choose M here: the module will be called
|
||||
can-dev.
|
||||
|
||||
if CAN_DEV
|
||||
|
||||
config CAN_VCAN
|
||||
tristate "Virtual Local CAN Interface (vcan)"
|
||||
@ -48,15 +69,22 @@ config CAN_SLCAN
|
||||
can be changed by the 'maxdev=xx' module option. This driver can
|
||||
also be built as a module. If so, the module will be called slcan.
|
||||
|
||||
config CAN_DEV
|
||||
tristate "Platform CAN drivers with Netlink support"
|
||||
config CAN_NETLINK
|
||||
bool "CAN device drivers with Netlink support"
|
||||
default y
|
||||
help
|
||||
Enables the common framework for platform CAN drivers with Netlink
|
||||
support. This is the standard library for CAN drivers.
|
||||
If unsure, say Y.
|
||||
Enables the common framework for CAN device drivers. This is the
|
||||
standard library and provides features for the Netlink interface such
|
||||
as bittiming validation, support of CAN error states, device restart
|
||||
and others.
|
||||
|
||||
if CAN_DEV
|
||||
The additional features selected by this option will be added to the
|
||||
can-dev module.
|
||||
|
||||
This is required by all platform and hardware CAN drivers. If you
|
||||
plan to use such devices or if unsure, say Y.
|
||||
|
||||
if CAN_NETLINK
|
||||
|
||||
config CAN_CALC_BITTIMING
|
||||
bool "CAN bit-timing calculation"
|
||||
@ -69,8 +97,15 @@ config CAN_CALC_BITTIMING
|
||||
source clock frequencies. Disabling saves some space, but then the
|
||||
bit-timing parameters must be specified directly using the Netlink
|
||||
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
|
||||
|
||||
The additional features selected by this option will be added to the
|
||||
can-dev module.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config CAN_RX_OFFLOAD
|
||||
bool
|
||||
|
||||
config CAN_AT91
|
||||
tristate "Atmel AT91 onchip CAN controller"
|
||||
depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM
|
||||
@ -82,6 +117,7 @@ config CAN_FLEXCAN
|
||||
tristate "Support for Freescale FLEXCAN based chips"
|
||||
depends on OF || COLDFIRE || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
select CAN_RX_OFFLOAD
|
||||
help
|
||||
Say Y here if you want to support for Freescale FlexCAN.
|
||||
|
||||
@ -131,6 +167,7 @@ config CAN_SUN4I
|
||||
config CAN_TI_HECC
|
||||
depends on ARM
|
||||
tristate "TI High End CAN Controller"
|
||||
select CAN_RX_OFFLOAD
|
||||
help
|
||||
Driver for TI HECC (High End CAN Controller) module found on many
|
||||
TI devices. The device specifications are available from www.ti.com
|
||||
@ -164,7 +201,7 @@ source "drivers/net/can/softing/Kconfig"
|
||||
source "drivers/net/can/spi/Kconfig"
|
||||
source "drivers/net/can/usb/Kconfig"
|
||||
|
||||
endif
|
||||
endif #CAN_NETLINK
|
||||
|
||||
config CAN_DEBUG_DEVICES
|
||||
bool "CAN devices debugging messages"
|
||||
@ -174,4 +211,4 @@ config CAN_DEBUG_DEVICES
|
||||
a problem with CAN support and want to see more of what is going
|
||||
on.
|
||||
|
||||
endmenu
|
||||
endif #CAN_DEV
|
||||
|
@ -1,9 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||
can-dev-y += bittiming.o
|
||||
can-dev-y += dev.o
|
||||
can-dev-y += length.o
|
||||
can-dev-y += netlink.o
|
||||
can-dev-y += rx-offload.o
|
||||
can-dev-y += skb.o
|
||||
obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||
|
||||
can-dev-y += skb.o
|
||||
|
||||
can-dev-$(CONFIG_CAN_CALC_BITTIMING) += calc_bittiming.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += bittiming.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += dev.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += length.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += netlink.o
|
||||
can-dev-$(CONFIG_CAN_RX_OFFLOAD) += rx-offload.o
|
||||
|
@ -4,205 +4,8 @@
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
#include <linux/units.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#ifdef CONFIG_CAN_CALC_BITTIMING
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
|
||||
/* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int
|
||||
can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
const unsigned int sample_point_nominal, const unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_SYNC_SEG -
|
||||
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
||||
1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
||||
(tseg + CAN_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if (sample_point <= sample_point_nominal &&
|
||||
sample_point_error < best_sample_point_error) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_nominal; /* nominal sample point */
|
||||
unsigned int best_tseg = 0; /* current best value for tseg */
|
||||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800 * KILO /* BPS */)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500 * KILO /* BPS */)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if (brp < btc->brp_min || brp > btc->brp_max)
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error >= best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
||||
best_tseg, &tseg1, &tseg2,
|
||||
NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
|
||||
const struct can_bittiming *dbt,
|
||||
u32 *ctrlmode, u32 ctrlmode_supported)
|
||||
|
||||
{
|
||||
if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
|
||||
return;
|
||||
|
||||
*ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
|
||||
|
||||
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
|
||||
* delay compensation" (TDC) is only applicable if data BRP is
|
||||
* one or two.
|
||||
*/
|
||||
if (dbt->brp == 1 || dbt->brp == 2) {
|
||||
/* Sample point in clock periods */
|
||||
u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
|
||||
dbt->phase_seg1) * dbt->brp;
|
||||
|
||||
if (sample_point_in_tc < tdc_const->tdco_min)
|
||||
return;
|
||||
tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
|
||||
*ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_CAN_CALC_BITTIMING */
|
||||
|
||||
/* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
|
202
drivers/net/can/dev/calc_bittiming.c
Normal file
202
drivers/net/can/dev/calc_bittiming.c
Normal file
@ -0,0 +1,202 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
#include <linux/units.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
|
||||
/* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int
|
||||
can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
const unsigned int sample_point_nominal, const unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_SYNC_SEG -
|
||||
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
||||
1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
||||
(tseg + CAN_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if (sample_point <= sample_point_nominal &&
|
||||
sample_point_error < best_sample_point_error) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_nominal; /* nominal sample point */
|
||||
unsigned int best_tseg = 0; /* current best value for tseg */
|
||||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800 * KILO /* BPS */)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500 * KILO /* BPS */)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if (brp < btc->brp_min || brp > btc->brp_max)
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error >= best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
||||
best_tseg, &tseg1, &tseg2,
|
||||
NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
|
||||
const struct can_bittiming *dbt,
|
||||
u32 *ctrlmode, u32 ctrlmode_supported)
|
||||
|
||||
{
|
||||
if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
|
||||
return;
|
||||
|
||||
*ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
|
||||
|
||||
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
|
||||
* delay compensation" (TDC) is only applicable if data BRP is
|
||||
* one or two.
|
||||
*/
|
||||
if (dbt->brp == 1 || dbt->brp == 2) {
|
||||
/* Sample point in clock periods */
|
||||
u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
|
||||
dbt->phase_seg1) * dbt->brp;
|
||||
|
||||
if (sample_point_in_tc < tdc_const->tdco_min)
|
||||
return;
|
||||
tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
|
||||
*ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
@ -17,12 +16,6 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define MOD_DESC "CAN device driver interface"
|
||||
|
||||
MODULE_DESCRIPTION(MOD_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
||||
|
||||
static void can_update_state_error_stats(struct net_device *dev,
|
||||
enum can_state new_state)
|
||||
{
|
||||
@ -513,7 +506,7 @@ static __init int can_dev_init(void)
|
||||
|
||||
err = can_netlink_register();
|
||||
if (!err)
|
||||
pr_info(MOD_DESC "\n");
|
||||
pr_info("CAN device driver interface\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -5,6 +5,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define MOD_DESC "CAN device driver interface"
|
||||
|
||||
MODULE_DESCRIPTION(MOD_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
||||
|
||||
/* Local echo of CAN messages
|
||||
*
|
||||
@ -252,3 +260,67 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_can_err_skb);
|
||||
|
||||
/* Check for outgoing skbs that have not been created by the CAN subsystem */
|
||||
static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
|
||||
return false;
|
||||
|
||||
/* af_packet does not apply CAN skb specific settings */
|
||||
if (skb->ip_summed == CHECKSUM_NONE) {
|
||||
/* init headroom */
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
/* perform proper loopback on capable devices */
|
||||
if (dev->flags & IFF_ECHO)
|
||||
skb->pkt_type = PACKET_LOOPBACK;
|
||||
else
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (skb->protocol == htons(ETH_P_CAN)) {
|
||||
if (unlikely(skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->protocol == htons(ETH_P_CANFD)) {
|
||||
if (unlikely(skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else {
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
if (!can_skb_headroom_valid(dev, skb)) {
|
||||
goto inval_skb;
|
||||
} else if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) {
|
||||
netdev_info_once(dev,
|
||||
"interface in listen only mode, dropping skb\n");
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
inval_skb:
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_dropped_invalid_skb);
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menuconfig CAN_M_CAN
|
||||
tristate "Bosch M_CAN support"
|
||||
select CAN_RX_OFFLOAD
|
||||
help
|
||||
Say Y here if you want support for Bosch M_CAN controller framework.
|
||||
This is common support for devices that embed the Bosch M_CAN IP.
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
config CAN_MCP251XFD
|
||||
tristate "Microchip MCP251xFD SPI CAN controllers"
|
||||
select CAN_RX_OFFLOAD
|
||||
select REGMAP
|
||||
select WANT_DEV_COREDUMP
|
||||
help
|
||||
|
@ -31,6 +31,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
struct canfd_frame **cfd);
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev,
|
||||
struct can_frame **cf);
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);
|
||||
|
||||
/*
|
||||
* The struct can_skb_priv is used to transport additional information along
|
||||
@ -96,64 +97,6 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
|
||||
return nskb;
|
||||
}
|
||||
|
||||
/* Check for outgoing skbs that have not been created by the CAN subsystem */
|
||||
static inline bool can_skb_headroom_valid(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
|
||||
return false;
|
||||
|
||||
/* af_packet does not apply CAN skb specific settings */
|
||||
if (skb->ip_summed == CHECKSUM_NONE) {
|
||||
/* init headroom */
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
/* perform proper loopback on capable devices */
|
||||
if (dev->flags & IFF_ECHO)
|
||||
skb->pkt_type = PACKET_LOOPBACK;
|
||||
else
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
|
||||
static inline bool can_dropped_invalid_skb(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (skb->protocol == htons(ETH_P_CAN)) {
|
||||
if (unlikely(skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->protocol == htons(ETH_P_CANFD)) {
|
||||
if (unlikely(skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else
|
||||
goto inval_skb;
|
||||
|
||||
if (!can_skb_headroom_valid(dev, skb))
|
||||
goto inval_skb;
|
||||
|
||||
return false;
|
||||
|
||||
inval_skb:
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool can_is_canfd_skb(const struct sk_buff *skb)
|
||||
{
|
||||
/* the CAN specific type of skb is identified by its data length */
|
||||
|
@ -15,7 +15,8 @@ menuconfig CAN
|
||||
PF_CAN is contained in <Documentation/networking/can.rst>.
|
||||
|
||||
If you want CAN support you should say Y here and also to the
|
||||
specific driver for your controller(s) below.
|
||||
specific driver for your controller(s) under the Network device
|
||||
support section.
|
||||
|
||||
if CAN
|
||||
|
||||
@ -69,6 +70,4 @@ config CAN_ISOTP
|
||||
If you want to perform automotive vehicle diagnostic services (UDS),
|
||||
say 'y'.
|
||||
|
||||
source "drivers/net/can/Kconfig"
|
||||
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user