linux-can-next-for-5.12-20210114
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEK3kIWJt9yTYMP3ehqclaivrt76kFAl//+AATHG1rbEBwZW5n dXRyb25peC5kZQAKCRCpyVqK+u3vqcUHB/95XfZ9zFpizYDxEich0LZx9KDxNp93 104KJ0BAdgAqbe4cZaDN8Y7nZbsC1V7+aiq1wlAkY07P75V0fasd4WlB+a7F9IQv w/chycUkemmjjk8lNLMvCWZeKB4/i+e/BV78avJs0CFkzQer6RKLVL9j3FgRqtia RT7rrWDvRtfr2uGezBao7/vpFrlDqfp/sjZ0rnG/bhIMlq2uk5U/44F6dtKmgHR8 UxfN/6NT8LwTWOeIjXoR9tL8EI44AoCpjNQAgozbxmM+Nph17SE0eJdAYUUEBNDu Fogrwl8gqI1UbWRMkwDoEUZTurczXRUin+dTPZtTsQ+1iDLvItg+HKTg =0oq2 -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-5.12-20210114' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2021-01-14 The first two patches update the MAINTAINERS file, Lukas Bulwahn's patch fixes the files entry for the tcan4x5x driver, which was broken by me in net-next. A patch by me adds the a missing header file to the CAN Networking Layer. The next 5 patches are by me and split the the CAN driver related infrastructure code into more files in a separate subdir. The next two patches by me clean up the CAN length related code. This is followed by 6 patches by Vincent Mailhol and me, they add helper code for for CAN frame length calculation neede for BQL support. A patch by Vincent Mailhol adds software TX timestamp support. The last patch is by me, targets the tcan4x5x driver, and removes the unneeded __packed attribute from the struct tcan4x5x_map_buf. * tag 'linux-can-next-for-5.12-20210114' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: can: tcan4x5x: remove __packed attribute from struct tcan4x5x_map_buf can: dev: can_put_echo_skb(): add software tx timestamps can: dev: can_rx_offload_get_echo_skb(): extend to return can frame length can: dev: can_get_echo_skb(): extend to return can frame length can: dev: can_put_echo_skb(): extend to handle frame_len can: dev: extend struct can_skb_priv to hold CAN frame length can: length: can_skb_get_frame_len(): introduce function to get data length of frame in data link layer can: length: canfd_sanitize_len(): add function to sanitize CAN-FD data length can: length: can_fd_len2dlc(): simplify length calculcation can: length: convert to kernel coding style can: dev: move netlink related code into seperate file can: dev: move skb related into seperate file can: dev: move length related code into seperate file can: dev: move bittiming related code into seperate file can: dev: move driver related infrastructure into separate subdir MAINTAINERS: CAN network layer: add missing header file can-ml.h MAINTAINERS: adjust entry to tcan4x5x file split ==================== Link: https://lore.kernel.org/r/20210114075617.1402597-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
747fdd47ed
@ -3943,8 +3943,10 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
|
||||
F: Documentation/devicetree/bindings/net/can/
|
||||
F: drivers/net/can/
|
||||
F: include/linux/can/bittiming.h
|
||||
F: include/linux/can/dev.h
|
||||
F: include/linux/can/led.h
|
||||
F: include/linux/can/length.h
|
||||
F: include/linux/can/platform/
|
||||
F: include/linux/can/rx-offload.h
|
||||
F: include/uapi/linux/can/error.h
|
||||
@ -3960,6 +3962,7 @@ W: https://github.com/linux-can
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
|
||||
F: Documentation/networking/can.rst
|
||||
F: include/linux/can/can-ml.h
|
||||
F: include/linux/can/core.h
|
||||
F: include/linux/can/skb.h
|
||||
F: include/net/netns/can.h
|
||||
@ -17839,7 +17842,7 @@ M: Dan Murphy <dmurphy@ti.com>
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/can/tcan4x5x.txt
|
||||
F: drivers/net/can/m_can/tcan4x5x.c
|
||||
F: drivers/net/can/m_can/tcan4x5x*
|
||||
|
||||
TI TRF7970A NFC DRIVER
|
||||
M: Mark Greer <mgreer@animalcreek.com>
|
||||
|
@ -7,12 +7,7 @@ obj-$(CONFIG_CAN_VCAN) += vcan.o
|
||||
obj-$(CONFIG_CAN_VXCAN) += vxcan.o
|
||||
obj-$(CONFIG_CAN_SLCAN) += slcan.o
|
||||
|
||||
obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||
can-dev-y += dev.o
|
||||
can-dev-y += rx-offload.o
|
||||
|
||||
can-dev-$(CONFIG_CAN_LEDS) += led.o
|
||||
|
||||
obj-y += dev/
|
||||
obj-y += rcar/
|
||||
obj-y += spi/
|
||||
obj-y += usb/
|
||||
|
@ -484,7 +484,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
stats->tx_bytes += cf->len;
|
||||
|
||||
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
|
||||
can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv));
|
||||
can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv), 0);
|
||||
|
||||
/*
|
||||
* we have to stop the queue and deliver all messages in case
|
||||
@ -856,7 +856,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
|
||||
if (likely(reg_msr & AT91_MSR_MRDY &&
|
||||
~reg_msr & AT91_MSR_MABT)) {
|
||||
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
|
||||
can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
|
||||
can_get_echo_skb(dev, mb - get_mb_tx_first(priv), NULL);
|
||||
dev->stats.tx_packets++;
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
}
|
||||
|
@ -476,7 +476,7 @@ static netdev_tx_t c_can_start_xmit(struct sk_buff *skb,
|
||||
*/
|
||||
c_can_setup_tx_object(dev, IF_TX, frame, idx);
|
||||
priv->dlc[idx] = frame->len;
|
||||
can_put_echo_skb(skb, dev, idx);
|
||||
can_put_echo_skb(skb, dev, idx, 0);
|
||||
|
||||
/* Update the active bits */
|
||||
atomic_add((1 << idx), &priv->tx_active);
|
||||
@ -733,7 +733,7 @@ static void c_can_do_tx(struct net_device *dev)
|
||||
pend &= ~(1 << idx);
|
||||
obj = idx + C_CAN_MSG_OBJ_TX_FIRST;
|
||||
c_can_inval_tx_object(dev, IF_RX, obj);
|
||||
can_get_echo_skb(dev, idx);
|
||||
can_get_echo_skb(dev, idx, NULL);
|
||||
bytes += priv->dlc[idx];
|
||||
pkts++;
|
||||
}
|
||||
|
@ -702,8 +702,8 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
|
||||
stats->tx_bytes += cf->len;
|
||||
stats->tx_packets++;
|
||||
|
||||
can_put_echo_skb(priv->tx_skb, dev, 0);
|
||||
can_get_echo_skb(dev, 0);
|
||||
can_put_echo_skb(priv->tx_skb, dev, 0, 0);
|
||||
can_get_echo_skb(dev, 0, NULL);
|
||||
priv->tx_skb = NULL;
|
||||
|
||||
netif_wake_queue(dev);
|
||||
|
File diff suppressed because it is too large
Load Diff
11
drivers/net/can/dev/Makefile
Normal file
11
drivers/net/can/dev/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
# 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
|
||||
|
||||
can-dev-$(CONFIG_CAN_LEDS) += led.o
|
261
drivers/net/can/dev/bittiming.c
Normal file
261
drivers/net/can/dev/bittiming.c
Normal file
@ -0,0 +1,261 @@
|
||||
// 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/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,
|
||||
unsigned int sample_point_nominal, 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(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 > 800000)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500000)
|
||||
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;
|
||||
}
|
||||
#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
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
int tseg1, alltseg;
|
||||
u64 brp64;
|
||||
|
||||
tseg1 = bt->prop_seg + bt->phase_seg1;
|
||||
if (!bt->sjw)
|
||||
bt->sjw = 1;
|
||||
if (bt->sjw > btc->sjw_max ||
|
||||
tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
|
||||
bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
|
||||
return -ERANGE;
|
||||
|
||||
brp64 = (u64)priv->clock.freq * (u64)bt->tq;
|
||||
if (btc->brp_inc > 1)
|
||||
do_div(brp64, btc->brp_inc);
|
||||
brp64 += 500000000UL - 1;
|
||||
do_div(brp64, 1000000000UL); /* the practicable BRP */
|
||||
if (btc->brp_inc > 1)
|
||||
brp64 *= btc->brp_inc;
|
||||
bt->brp = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
return -EINVAL;
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Checks the validity of predefined bitrate settings */
|
||||
static int
|
||||
can_validate_bitrate(struct net_device *dev, struct can_bittiming *bt,
|
||||
const u32 *bitrate_const,
|
||||
const unsigned int bitrate_const_cnt)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < bitrate_const_cnt; i++) {
|
||||
if (bt->bitrate == bitrate_const[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= priv->bitrate_const_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc,
|
||||
const u32 *bitrate_const,
|
||||
const unsigned int bitrate_const_cnt)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Depending on the given can_bittiming parameter structure the CAN
|
||||
* timing parameters are calculated based on the provided bitrate OR
|
||||
* alternatively the CAN timing parameters (tq, prop_seg, etc.) are
|
||||
* provided directly which are then checked and fixed up.
|
||||
*/
|
||||
if (!bt->tq && bt->bitrate && btc)
|
||||
err = can_calc_bittiming(dev, bt, btc);
|
||||
else if (bt->tq && !bt->bitrate && btc)
|
||||
err = can_fixup_bittiming(dev, bt, btc);
|
||||
else if (!bt->tq && bt->bitrate && bitrate_const)
|
||||
err = can_validate_bitrate(dev, bt, bitrate_const,
|
||||
bitrate_const_cnt);
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
return err;
|
||||
}
|
467
drivers/net/can/dev/dev.c
Normal file
467
drivers/net/can/dev/dev.c
Normal file
@ -0,0 +1,467 @@
|
||||
// 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/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/can-ml.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/led.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)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (new_state <= priv->state)
|
||||
return;
|
||||
|
||||
switch (new_state) {
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
priv->can_stats.error_warning++;
|
||||
break;
|
||||
case CAN_STATE_ERROR_PASSIVE:
|
||||
priv->can_stats.error_passive++;
|
||||
break;
|
||||
case CAN_STATE_BUS_OFF:
|
||||
priv->can_stats.bus_off++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
return CAN_ERR_CRTL_ACTIVE;
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
return CAN_ERR_CRTL_TX_WARNING;
|
||||
case CAN_STATE_ERROR_PASSIVE:
|
||||
return CAN_ERR_CRTL_TX_PASSIVE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int can_rx_state_to_frame(struct net_device *dev, enum can_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
return CAN_ERR_CRTL_ACTIVE;
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
return CAN_ERR_CRTL_RX_WARNING;
|
||||
case CAN_STATE_ERROR_PASSIVE:
|
||||
return CAN_ERR_CRTL_RX_PASSIVE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *can_get_state_str(const enum can_state state)
|
||||
{
|
||||
switch (state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
return "Error Active";
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
return "Error Warning";
|
||||
case CAN_STATE_ERROR_PASSIVE:
|
||||
return "Error Passive";
|
||||
case CAN_STATE_BUS_OFF:
|
||||
return "Bus Off";
|
||||
case CAN_STATE_STOPPED:
|
||||
return "Stopped";
|
||||
case CAN_STATE_SLEEPING:
|
||||
return "Sleeping";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
void can_change_state(struct net_device *dev, struct can_frame *cf,
|
||||
enum can_state tx_state, enum can_state rx_state)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
enum can_state new_state = max(tx_state, rx_state);
|
||||
|
||||
if (unlikely(new_state == priv->state)) {
|
||||
netdev_warn(dev, "%s: oops, state did not change", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
netdev_dbg(dev, "Controller changed from %s State (%d) into %s State (%d).\n",
|
||||
can_get_state_str(priv->state), priv->state,
|
||||
can_get_state_str(new_state), new_state);
|
||||
|
||||
can_update_state_error_stats(dev, new_state);
|
||||
priv->state = new_state;
|
||||
|
||||
if (!cf)
|
||||
return;
|
||||
|
||||
if (unlikely(new_state == CAN_STATE_BUS_OFF)) {
|
||||
cf->can_id |= CAN_ERR_BUSOFF;
|
||||
return;
|
||||
}
|
||||
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] |= tx_state >= rx_state ?
|
||||
can_tx_state_to_frame(dev, tx_state) : 0;
|
||||
cf->data[1] |= tx_state <= rx_state ?
|
||||
can_rx_state_to_frame(dev, rx_state) : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_change_state);
|
||||
|
||||
/* CAN device restart for bus-off recovery */
|
||||
static void can_restart(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf;
|
||||
int err;
|
||||
|
||||
BUG_ON(netif_carrier_ok(dev));
|
||||
|
||||
/* No synchronization needed because the device is bus-off and
|
||||
* no messages can come in or go out.
|
||||
*/
|
||||
can_flush_echo_skb(dev);
|
||||
|
||||
/* send restart message upstream */
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
if (!skb)
|
||||
goto restart;
|
||||
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
|
||||
netif_rx_ni(skb);
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->len;
|
||||
|
||||
restart:
|
||||
netdev_dbg(dev, "restarted\n");
|
||||
priv->can_stats.restarts++;
|
||||
|
||||
/* Now restart the device */
|
||||
err = priv->do_set_mode(dev, CAN_MODE_START);
|
||||
|
||||
netif_carrier_on(dev);
|
||||
if (err)
|
||||
netdev_err(dev, "Error %d during restart", err);
|
||||
}
|
||||
|
||||
static void can_restart_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork = to_delayed_work(work);
|
||||
struct can_priv *priv = container_of(dwork, struct can_priv,
|
||||
restart_work);
|
||||
|
||||
can_restart(priv->dev);
|
||||
}
|
||||
|
||||
int can_restart_now(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
/* A manual restart is only permitted if automatic restart is
|
||||
* disabled and the device is in the bus-off state
|
||||
*/
|
||||
if (priv->restart_ms)
|
||||
return -EINVAL;
|
||||
if (priv->state != CAN_STATE_BUS_OFF)
|
||||
return -EBUSY;
|
||||
|
||||
cancel_delayed_work_sync(&priv->restart_work);
|
||||
can_restart(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CAN bus-off
|
||||
*
|
||||
* This functions should be called when the device goes bus-off to
|
||||
* tell the netif layer that no more packets can be sent or received.
|
||||
* If enabled, a timer is started to trigger bus-off recovery.
|
||||
*/
|
||||
void can_bus_off(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->restart_ms)
|
||||
netdev_info(dev, "bus-off, scheduling restart in %d ms\n",
|
||||
priv->restart_ms);
|
||||
else
|
||||
netdev_info(dev, "bus-off\n");
|
||||
|
||||
netif_carrier_off(dev);
|
||||
|
||||
if (priv->restart_ms)
|
||||
schedule_delayed_work(&priv->restart_work,
|
||||
msecs_to_jiffies(priv->restart_ms));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_bus_off);
|
||||
|
||||
void can_setup(struct net_device *dev)
|
||||
{
|
||||
dev->type = ARPHRD_CAN;
|
||||
dev->mtu = CAN_MTU;
|
||||
dev->hard_header_len = 0;
|
||||
dev->addr_len = 0;
|
||||
dev->tx_queue_len = 10;
|
||||
|
||||
/* New-style flags. */
|
||||
dev->flags = IFF_NOARP;
|
||||
dev->features = NETIF_F_HW_CSUM;
|
||||
}
|
||||
|
||||
/* Allocate and setup space for the CAN network device */
|
||||
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
|
||||
unsigned int txqs, unsigned int rxqs)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct can_priv *priv;
|
||||
int size;
|
||||
|
||||
/* We put the driver's priv, the CAN mid layer priv and the
|
||||
* echo skb into the netdevice's priv. The memory layout for
|
||||
* the netdev_priv is like this:
|
||||
*
|
||||
* +-------------------------+
|
||||
* | driver's priv |
|
||||
* +-------------------------+
|
||||
* | struct can_ml_priv |
|
||||
* +-------------------------+
|
||||
* | array of struct sk_buff |
|
||||
* +-------------------------+
|
||||
*/
|
||||
|
||||
size = ALIGN(sizeof_priv, NETDEV_ALIGN) + sizeof(struct can_ml_priv);
|
||||
|
||||
if (echo_skb_max)
|
||||
size = ALIGN(size, sizeof(struct sk_buff *)) +
|
||||
echo_skb_max * sizeof(struct sk_buff *);
|
||||
|
||||
dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup,
|
||||
txqs, rxqs);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
priv = netdev_priv(dev);
|
||||
priv->dev = dev;
|
||||
|
||||
dev->ml_priv = (void *)priv + ALIGN(sizeof_priv, NETDEV_ALIGN);
|
||||
|
||||
if (echo_skb_max) {
|
||||
priv->echo_skb_max = echo_skb_max;
|
||||
priv->echo_skb = (void *)priv +
|
||||
(size - echo_skb_max * sizeof(struct sk_buff *));
|
||||
}
|
||||
|
||||
priv->state = CAN_STATE_STOPPED;
|
||||
|
||||
INIT_DELAYED_WORK(&priv->restart_work, can_restart_work);
|
||||
|
||||
return dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_candev_mqs);
|
||||
|
||||
/* Free space of the CAN network device */
|
||||
void free_candev(struct net_device *dev)
|
||||
{
|
||||
free_netdev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(free_candev);
|
||||
|
||||
/* changing MTU and control mode for CAN/CANFD devices */
|
||||
int can_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
/* Do not allow changing the MTU while running */
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
/* allow change of MTU according to the CANFD ability of the device */
|
||||
switch (new_mtu) {
|
||||
case CAN_MTU:
|
||||
/* 'CANFD-only' controllers can not switch to CAN_MTU */
|
||||
if (priv->ctrlmode_static & CAN_CTRLMODE_FD)
|
||||
return -EINVAL;
|
||||
|
||||
priv->ctrlmode &= ~CAN_CTRLMODE_FD;
|
||||
break;
|
||||
|
||||
case CANFD_MTU:
|
||||
/* check for potential CANFD ability */
|
||||
if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD) &&
|
||||
!(priv->ctrlmode_static & CAN_CTRLMODE_FD))
|
||||
return -EINVAL;
|
||||
|
||||
priv->ctrlmode |= CAN_CTRLMODE_FD;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev->mtu = new_mtu;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_change_mtu);
|
||||
|
||||
/* Common open function when the device gets opened.
|
||||
*
|
||||
* This function should be called in the open function of the device
|
||||
* driver.
|
||||
*/
|
||||
int open_candev(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (!priv->bittiming.bitrate) {
|
||||
netdev_err(dev, "bit-timing not yet defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* For CAN FD the data bitrate has to be >= the arbitration bitrate */
|
||||
if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
|
||||
(!priv->data_bittiming.bitrate ||
|
||||
priv->data_bittiming.bitrate < priv->bittiming.bitrate)) {
|
||||
netdev_err(dev, "incorrect/missing data bit-timing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Switch carrier on if device was stopped while in bus-off state */
|
||||
if (!netif_carrier_ok(dev))
|
||||
netif_carrier_on(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(open_candev);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* Common function that can be used to understand the limitation of
|
||||
* a transceiver when it provides no means to determine these limitations
|
||||
* at runtime.
|
||||
*/
|
||||
void of_can_transceiver(struct net_device *dev)
|
||||
{
|
||||
struct device_node *dn;
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
struct device_node *np = dev->dev.parent->of_node;
|
||||
int ret;
|
||||
|
||||
dn = of_get_child_by_name(np, "can-transceiver");
|
||||
if (!dn)
|
||||
return;
|
||||
|
||||
ret = of_property_read_u32(dn, "max-bitrate", &priv->bitrate_max);
|
||||
of_node_put(dn);
|
||||
if ((ret && ret != -EINVAL) || (!ret && !priv->bitrate_max))
|
||||
netdev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit.\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_can_transceiver);
|
||||
#endif
|
||||
|
||||
/* Common close function for cleanup before the device gets closed.
|
||||
*
|
||||
* This function should be called in the close function of the device
|
||||
* driver.
|
||||
*/
|
||||
void close_candev(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
cancel_delayed_work_sync(&priv->restart_work);
|
||||
can_flush_echo_skb(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(close_candev);
|
||||
|
||||
/* Register the CAN network device */
|
||||
int register_candev(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
/* Ensure termination_const, termination_const_cnt and
|
||||
* do_set_termination consistency. All must be either set or
|
||||
* unset.
|
||||
*/
|
||||
if ((!priv->termination_const != !priv->termination_const_cnt) ||
|
||||
(!priv->termination_const != !priv->do_set_termination))
|
||||
return -EINVAL;
|
||||
|
||||
if (!priv->bitrate_const != !priv->bitrate_const_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
dev->rtnl_link_ops = &can_link_ops;
|
||||
netif_carrier_off(dev);
|
||||
|
||||
return register_netdev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_candev);
|
||||
|
||||
/* Unregister the CAN network device */
|
||||
void unregister_candev(struct net_device *dev)
|
||||
{
|
||||
unregister_netdev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_candev);
|
||||
|
||||
/* Test if a network device is a candev based device
|
||||
* and return the can_priv* if so.
|
||||
*/
|
||||
struct can_priv *safe_candev_priv(struct net_device *dev)
|
||||
{
|
||||
if (dev->type != ARPHRD_CAN || dev->rtnl_link_ops != &can_link_ops)
|
||||
return NULL;
|
||||
|
||||
return netdev_priv(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(safe_candev_priv);
|
||||
|
||||
static __init int can_dev_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
can_led_notifier_init();
|
||||
|
||||
err = can_netlink_register();
|
||||
if (!err)
|
||||
pr_info(MOD_DESC "\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
module_init(can_dev_init);
|
||||
|
||||
static __exit void can_dev_exit(void)
|
||||
{
|
||||
can_netlink_unregister();
|
||||
|
||||
can_led_notifier_exit();
|
||||
}
|
||||
module_exit(can_dev_exit);
|
||||
|
||||
MODULE_ALIAS_RTNL_LINK("can");
|
90
drivers/net/can/dev/length.c
Normal file
90
drivers/net/can/dev/length.c
Normal file
@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2012, 2020 Oliver Hartkopp <socketcan@hartkopp.net>
|
||||
*/
|
||||
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
/* CAN DLC to real data length conversion helpers */
|
||||
|
||||
static const u8 dlc2len[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 12, 16, 20, 24, 32, 48, 64
|
||||
};
|
||||
|
||||
/* get data length from raw data length code (DLC) */
|
||||
u8 can_fd_dlc2len(u8 dlc)
|
||||
{
|
||||
return dlc2len[dlc & 0x0F];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_fd_dlc2len);
|
||||
|
||||
static const u8 len2dlc[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, /* 0 - 8 */
|
||||
9, 9, 9, 9, /* 9 - 12 */
|
||||
10, 10, 10, 10, /* 13 - 16 */
|
||||
11, 11, 11, 11, /* 17 - 20 */
|
||||
12, 12, 12, 12, /* 21 - 24 */
|
||||
13, 13, 13, 13, 13, 13, 13, 13, /* 25 - 32 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 33 - 40 */
|
||||
14, 14, 14, 14, 14, 14, 14, 14, /* 41 - 48 */
|
||||
};
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
u8 can_fd_len2dlc(u8 len)
|
||||
{
|
||||
if (len >= ARRAY_SIZE(len2dlc))
|
||||
return CANFD_MAX_DLC;
|
||||
|
||||
return len2dlc[len];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_fd_len2dlc);
|
||||
|
||||
/**
|
||||
* can_skb_get_frame_len() - Calculate the CAN Frame length in bytes
|
||||
* of a given skb.
|
||||
* @skb: socket buffer of a CAN message.
|
||||
*
|
||||
* Do a rough calculation: bit stuffing is ignored and length in bits
|
||||
* is rounded up to a length in bytes.
|
||||
*
|
||||
* Rationale: this function is to be used for the BQL functions
|
||||
* (netdev_sent_queue() and netdev_completed_queue()) which expect a
|
||||
* value in bytes. Just using skb->len is insufficient because it will
|
||||
* return the constant value of CAN(FD)_MTU. Doing the bit stuffing
|
||||
* calculation would be too expensive in term of computing resources
|
||||
* for no noticeable gain.
|
||||
*
|
||||
* Remarks: The payload of CAN FD frames with BRS flag are sent at a
|
||||
* different bitrate. Currently, the can-utils canbusload tool does
|
||||
* not support CAN-FD yet and so we could not run any benchmark to
|
||||
* measure the impact. There might be possible improvement here.
|
||||
*
|
||||
* Return: length in bytes.
|
||||
*/
|
||||
unsigned int can_skb_get_frame_len(const struct sk_buff *skb)
|
||||
{
|
||||
const struct canfd_frame *cf = (const struct canfd_frame *)skb->data;
|
||||
u8 len;
|
||||
|
||||
if (can_is_canfd_skb(skb))
|
||||
len = canfd_sanitize_len(cf->len);
|
||||
else if (cf->can_id & CAN_RTR_FLAG)
|
||||
len = 0;
|
||||
else
|
||||
len = cf->len;
|
||||
|
||||
if (can_is_canfd_skb(skb)) {
|
||||
if (cf->can_id & CAN_EFF_FLAG)
|
||||
len += CANFD_FRAME_OVERHEAD_EFF;
|
||||
else
|
||||
len += CANFD_FRAME_OVERHEAD_SFF;
|
||||
} else {
|
||||
if (cf->can_id & CAN_EFF_FLAG)
|
||||
len += CAN_FRAME_OVERHEAD_EFF;
|
||||
else
|
||||
len += CAN_FRAME_OVERHEAD_SFF;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_skb_get_frame_len);
|
379
drivers/net/can/dev/netlink.c
Normal file
379
drivers/net/can/dev/netlink.c
Normal file
@ -0,0 +1,379 @@
|
||||
// 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/can/dev.h>
|
||||
#include <net/rtnetlink.h>
|
||||
|
||||
static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
|
||||
[IFLA_CAN_STATE] = { .type = NLA_U32 },
|
||||
[IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
|
||||
[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
|
||||
[IFLA_CAN_RESTART] = { .type = NLA_U32 },
|
||||
[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
|
||||
[IFLA_CAN_BITTIMING_CONST]
|
||||
= { .len = sizeof(struct can_bittiming_const) },
|
||||
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
|
||||
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
|
||||
[IFLA_CAN_DATA_BITTIMING]
|
||||
= { .len = sizeof(struct can_bittiming) },
|
||||
[IFLA_CAN_DATA_BITTIMING_CONST]
|
||||
= { .len = sizeof(struct can_bittiming_const) },
|
||||
[IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
bool is_can_fd = false;
|
||||
|
||||
/* Make sure that valid CAN FD configurations always consist of
|
||||
* - nominal/arbitration bittiming
|
||||
* - data bittiming
|
||||
* - control mode with CAN_CTRLMODE_FD set
|
||||
*/
|
||||
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (data[IFLA_CAN_CTRLMODE]) {
|
||||
struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
||||
|
||||
is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
|
||||
}
|
||||
|
||||
if (is_can_fd) {
|
||||
if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_DATA_BITTIMING]) {
|
||||
if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
/* We need synchronization with dev->stop() */
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (data[IFLA_CAN_BITTIMING]) {
|
||||
struct can_bittiming bt;
|
||||
|
||||
/* Do not allow changing bittiming while running */
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
/* Calculate bittiming parameters based on
|
||||
* bittiming_const if set, otherwise pass bitrate
|
||||
* directly via do_set_bitrate(). Bail out if neither
|
||||
* is given.
|
||||
*/
|
||||
if (!priv->bittiming_const && !priv->do_set_bittiming)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
|
||||
err = can_get_bittiming(dev, &bt,
|
||||
priv->bittiming_const,
|
||||
priv->bitrate_const,
|
||||
priv->bitrate_const_cnt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
|
||||
netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
|
||||
priv->bitrate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&priv->bittiming, &bt, sizeof(bt));
|
||||
|
||||
if (priv->do_set_bittiming) {
|
||||
/* Finally, set the bit-timing registers */
|
||||
err = priv->do_set_bittiming(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_CTRLMODE]) {
|
||||
struct can_ctrlmode *cm;
|
||||
u32 ctrlstatic;
|
||||
u32 maskedflags;
|
||||
|
||||
/* Do not allow changing controller mode while running */
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
||||
ctrlstatic = priv->ctrlmode_static;
|
||||
maskedflags = cm->flags & cm->mask;
|
||||
|
||||
/* check whether provided bits are allowed to be passed */
|
||||
if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* do not check for static fd-non-iso if 'fd' is disabled */
|
||||
if (!(maskedflags & CAN_CTRLMODE_FD))
|
||||
ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
|
||||
|
||||
/* make sure static options are provided by configuration */
|
||||
if ((maskedflags & ctrlstatic) != ctrlstatic)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* clear bits to be modified and copy the flag values */
|
||||
priv->ctrlmode &= ~cm->mask;
|
||||
priv->ctrlmode |= maskedflags;
|
||||
|
||||
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
||||
if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
||||
dev->mtu = CANFD_MTU;
|
||||
else
|
||||
dev->mtu = CAN_MTU;
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_RESTART_MS]) {
|
||||
/* Do not allow changing restart delay while running */
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_RESTART]) {
|
||||
/* Do not allow a restart while not running */
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return -EINVAL;
|
||||
err = can_restart_now(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_DATA_BITTIMING]) {
|
||||
struct can_bittiming dbt;
|
||||
|
||||
/* Do not allow changing bittiming while running */
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
/* Calculate bittiming parameters based on
|
||||
* data_bittiming_const if set, otherwise pass bitrate
|
||||
* directly via do_set_bitrate(). Bail out if neither
|
||||
* is given.
|
||||
*/
|
||||
if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
|
||||
sizeof(dbt));
|
||||
err = can_get_bittiming(dev, &dbt,
|
||||
priv->data_bittiming_const,
|
||||
priv->data_bitrate_const,
|
||||
priv->data_bitrate_const_cnt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
|
||||
netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
|
||||
priv->bitrate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
|
||||
|
||||
if (priv->do_set_data_bittiming) {
|
||||
/* Finally, set the bit-timing registers */
|
||||
err = priv->do_set_data_bittiming(dev);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_TERMINATION]) {
|
||||
const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
|
||||
const unsigned int num_term = priv->termination_const_cnt;
|
||||
unsigned int i;
|
||||
|
||||
if (!priv->do_set_termination)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* check whether given value is supported by the interface */
|
||||
for (i = 0; i < num_term; i++) {
|
||||
if (termval == priv->termination_const[i])
|
||||
break;
|
||||
}
|
||||
if (i >= num_term)
|
||||
return -EINVAL;
|
||||
|
||||
/* Finally, set the termination value */
|
||||
err = priv->do_set_termination(dev, termval);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
priv->termination = termval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t can_get_size(const struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
size_t size = 0;
|
||||
|
||||
if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */
|
||||
size += nla_total_size(sizeof(struct can_bittiming));
|
||||
if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */
|
||||
size += nla_total_size(sizeof(struct can_bittiming_const));
|
||||
size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */
|
||||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_STATE */
|
||||
size += nla_total_size(sizeof(struct can_ctrlmode)); /* IFLA_CAN_CTRLMODE */
|
||||
size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */
|
||||
if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */
|
||||
size += nla_total_size(sizeof(struct can_berr_counter));
|
||||
if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */
|
||||
size += nla_total_size(sizeof(struct can_bittiming));
|
||||
if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */
|
||||
size += nla_total_size(sizeof(struct can_bittiming_const));
|
||||
if (priv->termination_const) {
|
||||
size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
|
||||
size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */
|
||||
priv->termination_const_cnt);
|
||||
}
|
||||
if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */
|
||||
size += nla_total_size(sizeof(*priv->bitrate_const) *
|
||||
priv->bitrate_const_cnt);
|
||||
if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */
|
||||
size += nla_total_size(sizeof(*priv->data_bitrate_const) *
|
||||
priv->data_bitrate_const_cnt);
|
||||
size += sizeof(priv->bitrate_max); /* IFLA_CAN_BITRATE_MAX */
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
struct can_ctrlmode cm = {.flags = priv->ctrlmode};
|
||||
struct can_berr_counter bec;
|
||||
enum can_state state = priv->state;
|
||||
|
||||
if (priv->do_get_state)
|
||||
priv->do_get_state(dev, &state);
|
||||
|
||||
if ((priv->bittiming.bitrate &&
|
||||
nla_put(skb, IFLA_CAN_BITTIMING,
|
||||
sizeof(priv->bittiming), &priv->bittiming)) ||
|
||||
|
||||
(priv->bittiming_const &&
|
||||
nla_put(skb, IFLA_CAN_BITTIMING_CONST,
|
||||
sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
|
||||
|
||||
nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
|
||||
nla_put_u32(skb, IFLA_CAN_STATE, state) ||
|
||||
nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
|
||||
nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
|
||||
|
||||
(priv->do_get_berr_counter &&
|
||||
!priv->do_get_berr_counter(dev, &bec) &&
|
||||
nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
|
||||
|
||||
(priv->data_bittiming.bitrate &&
|
||||
nla_put(skb, IFLA_CAN_DATA_BITTIMING,
|
||||
sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
|
||||
|
||||
(priv->data_bittiming_const &&
|
||||
nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
|
||||
sizeof(*priv->data_bittiming_const),
|
||||
priv->data_bittiming_const)) ||
|
||||
|
||||
(priv->termination_const &&
|
||||
(nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
|
||||
nla_put(skb, IFLA_CAN_TERMINATION_CONST,
|
||||
sizeof(*priv->termination_const) *
|
||||
priv->termination_const_cnt,
|
||||
priv->termination_const))) ||
|
||||
|
||||
(priv->bitrate_const &&
|
||||
nla_put(skb, IFLA_CAN_BITRATE_CONST,
|
||||
sizeof(*priv->bitrate_const) *
|
||||
priv->bitrate_const_cnt,
|
||||
priv->bitrate_const)) ||
|
||||
|
||||
(priv->data_bitrate_const &&
|
||||
nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
|
||||
sizeof(*priv->data_bitrate_const) *
|
||||
priv->data_bitrate_const_cnt,
|
||||
priv->data_bitrate_const)) ||
|
||||
|
||||
(nla_put(skb, IFLA_CAN_BITRATE_MAX,
|
||||
sizeof(priv->bitrate_max),
|
||||
&priv->bitrate_max))
|
||||
)
|
||||
|
||||
return -EMSGSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t can_get_xstats_size(const struct net_device *dev)
|
||||
{
|
||||
return sizeof(struct can_device_stats);
|
||||
}
|
||||
|
||||
static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (nla_put(skb, IFLA_INFO_XSTATS,
|
||||
sizeof(priv->can_stats), &priv->can_stats))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int can_newlink(struct net *src_net, struct net_device *dev,
|
||||
struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static void can_dellink(struct net_device *dev, struct list_head *head)
|
||||
{
|
||||
}
|
||||
|
||||
struct rtnl_link_ops can_link_ops __read_mostly = {
|
||||
.kind = "can",
|
||||
.maxtype = IFLA_CAN_MAX,
|
||||
.policy = can_policy,
|
||||
.setup = can_setup,
|
||||
.validate = can_validate,
|
||||
.newlink = can_newlink,
|
||||
.changelink = can_changelink,
|
||||
.dellink = can_dellink,
|
||||
.get_size = can_get_size,
|
||||
.fill_info = can_fill_info,
|
||||
.get_xstats_size = can_get_xstats_size,
|
||||
.fill_xstats = can_fill_xstats,
|
||||
};
|
||||
|
||||
int can_netlink_register(void)
|
||||
{
|
||||
return rtnl_link_register(&can_link_ops);
|
||||
}
|
||||
|
||||
void can_netlink_unregister(void)
|
||||
{
|
||||
rtnl_link_unregister(&can_link_ops);
|
||||
}
|
@ -263,7 +263,8 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
|
||||
|
||||
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
unsigned int idx, u32 timestamp)
|
||||
unsigned int idx, u32 timestamp,
|
||||
unsigned int *frame_len_ptr)
|
||||
{
|
||||
struct net_device *dev = offload->dev;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
@ -271,7 +272,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
u8 len;
|
||||
int err;
|
||||
|
||||
skb = __can_get_echo_skb(dev, idx, &len);
|
||||
skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
231
drivers/net/can/dev/skb.c
Normal file
231
drivers/net/can/dev/skb.c
Normal file
@ -0,0 +1,231 @@
|
||||
// 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/can/dev.h>
|
||||
|
||||
/* Local echo of CAN messages
|
||||
*
|
||||
* CAN network devices *should* support a local echo functionality
|
||||
* (see Documentation/networking/can.rst). To test the handling of CAN
|
||||
* interfaces that do not support the local echo both driver types are
|
||||
* implemented. In the case that the driver does not support the echo
|
||||
* the IFF_ECHO remains clear in dev->flags. This causes the PF_CAN core
|
||||
* to perform the echo as a fallback solution.
|
||||
*/
|
||||
void can_flush_echo_skb(struct net_device *dev)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->echo_skb_max; i++) {
|
||||
if (priv->echo_skb[i]) {
|
||||
kfree_skb(priv->echo_skb[i]);
|
||||
priv->echo_skb[i] = NULL;
|
||||
stats->tx_dropped++;
|
||||
stats->tx_aborted_errors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Put the skb on the stack to be looped backed locally lateron
|
||||
*
|
||||
* The function is typically called in the start_xmit function
|
||||
* of the device driver. The driver must protect access to
|
||||
* priv->echo_skb, if necessary.
|
||||
*/
|
||||
int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned int idx, unsigned int frame_len)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
BUG_ON(idx >= priv->echo_skb_max);
|
||||
|
||||
/* check flag whether this packet has to be looped back */
|
||||
if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
|
||||
(skb->protocol != htons(ETH_P_CAN) &&
|
||||
skb->protocol != htons(ETH_P_CANFD))) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!priv->echo_skb[idx]) {
|
||||
skb = can_create_echo_skb(skb);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
/* make settings for echo to reduce code in irq context */
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
skb->dev = dev;
|
||||
|
||||
/* save frame_len to reuse it when transmission is completed */
|
||||
can_skb_prv(skb)->frame_len = frame_len;
|
||||
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
/* save this skb for tx interrupt echo handling */
|
||||
priv->echo_skb[idx] = skb;
|
||||
} else {
|
||||
/* locking problem with netif_stop_queue() ?? */
|
||||
netdev_err(dev, "%s: BUG! echo_skb %d is occupied!\n", __func__, idx);
|
||||
kfree_skb(skb);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
||||
|
||||
struct sk_buff *
|
||||
__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
|
||||
unsigned int *frame_len_ptr)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (idx >= priv->echo_skb_max) {
|
||||
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
|
||||
__func__, idx, priv->echo_skb_max);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (priv->echo_skb[idx]) {
|
||||
/* Using "struct canfd_frame::len" for the frame
|
||||
* length is supported on both CAN and CANFD frames.
|
||||
*/
|
||||
struct sk_buff *skb = priv->echo_skb[idx];
|
||||
struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
|
||||
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
|
||||
|
||||
/* get the real payload length for netdev statistics */
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
*len_ptr = 0;
|
||||
else
|
||||
*len_ptr = cf->len;
|
||||
|
||||
if (frame_len_ptr)
|
||||
*frame_len_ptr = can_skb_priv->frame_len;
|
||||
|
||||
priv->echo_skb[idx] = NULL;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the skb from the stack and loop it back locally
|
||||
*
|
||||
* The function is typically called when the TX done interrupt
|
||||
* is handled in the device driver. The driver must protect
|
||||
* access to priv->echo_skb, if necessary.
|
||||
*/
|
||||
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
unsigned int *frame_len_ptr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 len;
|
||||
|
||||
skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
skb_get(skb);
|
||||
if (netif_rx(skb) == NET_RX_SUCCESS)
|
||||
dev_consume_skb_any(skb);
|
||||
else
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_get_echo_skb);
|
||||
|
||||
/* Remove the skb from the stack and free it.
|
||||
*
|
||||
* The function is typically called when TX failed.
|
||||
*/
|
||||
void can_free_echo_skb(struct net_device *dev, unsigned int idx)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
BUG_ON(idx >= priv->echo_skb_max);
|
||||
|
||||
if (priv->echo_skb[idx]) {
|
||||
dev_kfree_skb_any(priv->echo_skb[idx]);
|
||||
priv->echo_skb[idx] = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_free_echo_skb);
|
||||
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
||||
sizeof(struct can_frame));
|
||||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
*cf = skb_put_zero(skb, sizeof(struct can_frame));
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_can_skb);
|
||||
|
||||
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
struct canfd_frame **cfd)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
||||
sizeof(struct canfd_frame));
|
||||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
skb->protocol = htons(ETH_P_CANFD);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
*cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_canfd_skb);
|
||||
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = alloc_can_skb(dev, cf);
|
||||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
|
||||
(*cf)->can_id = CAN_ERR_FLAG;
|
||||
(*cf)->len = CAN_ERR_DLC;
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_can_err_skb);
|
@ -815,7 +815,7 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
|
||||
priv->write(data, &priv->tx_mb->data[i / sizeof(u32)]);
|
||||
}
|
||||
|
||||
can_put_echo_skb(skb, dev, 0);
|
||||
can_put_echo_skb(skb, dev, 0, 0);
|
||||
|
||||
priv->write(can_id, &priv->tx_mb->can_id);
|
||||
priv->write(ctrl, &priv->tx_mb->can_ctrl);
|
||||
@ -1122,8 +1122,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||||
u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload,
|
||||
0, reg_ctrl << 16);
|
||||
stats->tx_bytes +=
|
||||
can_rx_offload_get_echo_skb(&priv->offload, 0,
|
||||
reg_ctrl << 16, NULL);
|
||||
stats->tx_packets++;
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
|
||||
|
@ -517,7 +517,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += priv->txdlc[i];
|
||||
priv->txdlc[i] = 0;
|
||||
can_get_echo_skb(dev, i);
|
||||
can_get_echo_skb(dev, i, NULL);
|
||||
} else {
|
||||
/* For cleanup of untransmitted messages */
|
||||
can_free_echo_skb(dev, i);
|
||||
@ -1448,7 +1448,7 @@ static netdev_tx_t grcan_start_xmit(struct sk_buff *skb,
|
||||
* taken.
|
||||
*/
|
||||
priv->txdlc[slotindex] = cf->len; /* Store dlc for statistics */
|
||||
can_put_echo_skb(skb, dev, slotindex);
|
||||
can_put_echo_skb(skb, dev, slotindex, 0);
|
||||
|
||||
/* Make sure everything is written before allowing hardware to
|
||||
* read from the memory
|
||||
|
@ -629,7 +629,7 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
|
||||
|
||||
/* TX IRQ */
|
||||
if (isr & IFI_CANFD_INTERRUPT_TXFIFO_REMOVE) {
|
||||
stats->tx_bytes += can_get_echo_skb(ndev, 0);
|
||||
stats->tx_bytes += can_get_echo_skb(ndev, 0, NULL);
|
||||
stats->tx_packets++;
|
||||
can_led_event(ndev, CAN_LED_EVENT_TX);
|
||||
}
|
||||
@ -922,7 +922,7 @@ static netdev_tx_t ifi_canfd_start_xmit(struct sk_buff *skb,
|
||||
writel(0, priv->base + IFI_CANFD_TXFIFO_REPEATCOUNT);
|
||||
writel(0, priv->base + IFI_CANFD_TXFIFO_SUSPEND_US);
|
||||
|
||||
can_put_echo_skb(skb, ndev, 0);
|
||||
can_put_echo_skb(skb, ndev, 0, 0);
|
||||
|
||||
/* Start the transmission */
|
||||
writel(IFI_CANFD_TXSTCMD_ADD_MSG, priv->base + IFI_CANFD_TXSTCMD);
|
||||
|
@ -778,7 +778,7 @@ static netdev_tx_t kvaser_pciefd_start_xmit(struct sk_buff *skb,
|
||||
spin_lock_irqsave(&can->echo_lock, irq_flags);
|
||||
|
||||
/* Prepare and save echo skb in internal slot */
|
||||
can_put_echo_skb(skb, netdev, can->echo_idx);
|
||||
can_put_echo_skb(skb, netdev, can->echo_idx, 0);
|
||||
|
||||
/* Move echo index to the next slot */
|
||||
can->echo_idx = (can->echo_idx + 1) % can->can.echo_skb_max;
|
||||
@ -1467,7 +1467,7 @@ static int kvaser_pciefd_handle_eack_packet(struct kvaser_pciefd *pcie,
|
||||
can->reg_base + KVASER_PCIEFD_KCAN_CTRL_REG);
|
||||
} else {
|
||||
int echo_idx = p->header[0] & KVASER_PCIEFD_PACKET_SEQ_MSK;
|
||||
int dlc = can_get_echo_skb(can->can.dev, echo_idx);
|
||||
int dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL);
|
||||
struct net_device_stats *stats = &can->can.dev->stats;
|
||||
|
||||
stats->tx_bytes += dlc;
|
||||
@ -1533,7 +1533,7 @@ static int kvaser_pciefd_handle_ack_packet(struct kvaser_pciefd *pcie,
|
||||
netdev_dbg(can->can.dev, "Packet was flushed\n");
|
||||
} else {
|
||||
int echo_idx = p->header[0] & KVASER_PCIEFD_PACKET_SEQ_MSK;
|
||||
int dlc = can_get_echo_skb(can->can.dev, echo_idx);
|
||||
int dlc = can_get_echo_skb(can->can.dev, echo_idx, NULL);
|
||||
u8 count = ioread32(can->reg_base +
|
||||
KVASER_PCIEFD_KCAN_TX_NPACKETS_REG) & 0xff;
|
||||
|
||||
|
@ -930,7 +930,7 @@ static void m_can_echo_tx_event(struct net_device *dev)
|
||||
(fgi << TXEFA_EFAI_SHIFT)));
|
||||
|
||||
/* update stats */
|
||||
stats->tx_bytes += can_get_echo_skb(dev, msg_mark);
|
||||
stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL);
|
||||
stats->tx_packets++;
|
||||
}
|
||||
}
|
||||
@ -972,7 +972,7 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
|
||||
if (cdev->version == 30) {
|
||||
if (ir & IR_TC) {
|
||||
/* Transmission Complete Interrupt*/
|
||||
stats->tx_bytes += can_get_echo_skb(dev, 0);
|
||||
stats->tx_bytes += can_get_echo_skb(dev, 0, NULL);
|
||||
stats->tx_packets++;
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
netif_wake_queue(dev);
|
||||
@ -1483,7 +1483,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
|
||||
M_CAN_FIFO_DATA(i / 4),
|
||||
*(u32 *)(cf->data + i));
|
||||
|
||||
can_put_echo_skb(skb, dev, 0);
|
||||
can_put_echo_skb(skb, dev, 0, 0);
|
||||
|
||||
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD) {
|
||||
cccr = m_can_read(cdev, M_CAN_CCCR);
|
||||
@ -1554,7 +1554,7 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev)
|
||||
/* Push loopback echo.
|
||||
* Will be looped back on TX interrupt based on message marker
|
||||
*/
|
||||
can_put_echo_skb(skb, dev, putidx);
|
||||
can_put_echo_skb(skb, dev, putidx, 0);
|
||||
|
||||
/* Enable TX FIFO element to start transfer */
|
||||
m_can_write(cdev, M_CAN_TXBAR, (1 << putidx));
|
||||
|
@ -25,7 +25,7 @@ struct __packed tcan4x5x_buf_cmd {
|
||||
u8 len;
|
||||
};
|
||||
|
||||
struct __packed tcan4x5x_map_buf {
|
||||
struct tcan4x5x_map_buf {
|
||||
struct tcan4x5x_buf_cmd cmd;
|
||||
u8 data[256 * sizeof(u32)];
|
||||
} ____cacheline_aligned;
|
||||
|
@ -270,7 +270,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head);
|
||||
|
||||
can_put_echo_skb(skb, dev, buf_id);
|
||||
can_put_echo_skb(skb, dev, buf_id, 0);
|
||||
|
||||
/* Enable interrupt. */
|
||||
priv->tx_active |= 1 << buf_id;
|
||||
@ -448,7 +448,7 @@ static irqreturn_t mscan_isr(int irq, void *dev_id)
|
||||
out_8(®s->cantbsel, mask);
|
||||
stats->tx_bytes += in_8(®s->tx.dlr);
|
||||
stats->tx_packets++;
|
||||
can_get_echo_skb(dev, entry->id);
|
||||
can_get_echo_skb(dev, entry->id, NULL);
|
||||
priv->tx_active &= ~mask;
|
||||
list_del(pos);
|
||||
}
|
||||
|
@ -711,7 +711,7 @@ static void pch_can_tx_complete(struct net_device *ndev, u32 int_stat)
|
||||
struct net_device_stats *stats = &(priv->ndev->stats);
|
||||
u32 dlc;
|
||||
|
||||
can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_END - 1);
|
||||
can_get_echo_skb(ndev, int_stat - PCH_RX_OBJ_END - 1, NULL);
|
||||
iowrite32(PCH_CMASK_RX_TX_GET | PCH_CMASK_CLRINTPND,
|
||||
&priv->regs->ifregs[1].cmask);
|
||||
pch_can_rw_msg_obj(&priv->regs->ifregs[1].creq, int_stat);
|
||||
@ -924,7 +924,7 @@ static netdev_tx_t pch_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
&priv->regs->ifregs[1].data[i / 2]);
|
||||
}
|
||||
|
||||
can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1);
|
||||
can_put_echo_skb(skb, ndev, tx_obj_no - PCH_RX_OBJ_END - 1, 0);
|
||||
|
||||
/* Set the size of the data. Update if2_mcont */
|
||||
iowrite32(cf->len | PCH_IF_MCONT_NEWDAT | PCH_IF_MCONT_TXRQXT |
|
||||
|
@ -266,7 +266,7 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->echo_lock, flags);
|
||||
can_get_echo_skb(priv->ndev, msg->client);
|
||||
can_get_echo_skb(priv->ndev, msg->client, NULL);
|
||||
|
||||
/* count bytes of the echo instead of skb */
|
||||
stats->tx_bytes += cf_len;
|
||||
@ -716,7 +716,7 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
|
||||
spin_lock_irqsave(&priv->echo_lock, flags);
|
||||
|
||||
/* prepare and save echo skb in internal slot */
|
||||
can_put_echo_skb(skb, ndev, priv->echo_idx);
|
||||
can_put_echo_skb(skb, ndev, priv->echo_idx, 0);
|
||||
|
||||
/* move echo index to the next slot */
|
||||
priv->echo_idx = (priv->echo_idx + 1) % priv->can.echo_skb_max;
|
||||
|
@ -386,7 +386,7 @@ static void rcar_can_tx_done(struct net_device *ndev)
|
||||
stats->tx_bytes += priv->tx_dlc[priv->tx_tail %
|
||||
RCAR_CAN_FIFO_DEPTH];
|
||||
priv->tx_dlc[priv->tx_tail % RCAR_CAN_FIFO_DEPTH] = 0;
|
||||
can_get_echo_skb(ndev, priv->tx_tail % RCAR_CAN_FIFO_DEPTH);
|
||||
can_get_echo_skb(ndev, priv->tx_tail % RCAR_CAN_FIFO_DEPTH, NULL);
|
||||
priv->tx_tail++;
|
||||
netif_wake_queue(ndev);
|
||||
}
|
||||
@ -617,7 +617,7 @@ static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
|
||||
writeb(cf->len, &priv->regs->mb[RCAR_CAN_TX_FIFO_MBX].dlc);
|
||||
|
||||
priv->tx_dlc[priv->tx_head % RCAR_CAN_FIFO_DEPTH] = cf->len;
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH);
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % RCAR_CAN_FIFO_DEPTH, 0);
|
||||
priv->tx_head++;
|
||||
/* Start Tx: write 0xff to the TFPCR register to increment
|
||||
* the CPU-side pointer for the transmit FIFO to the next
|
||||
|
@ -1044,7 +1044,7 @@ static void rcar_canfd_tx_done(struct net_device *ndev)
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += priv->tx_len[sent];
|
||||
priv->tx_len[sent] = 0;
|
||||
can_get_echo_skb(ndev, sent);
|
||||
can_get_echo_skb(ndev, sent, NULL);
|
||||
|
||||
spin_lock_irqsave(&priv->tx_lock, flags);
|
||||
priv->tx_tail++;
|
||||
@ -1390,7 +1390,7 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
priv->tx_len[priv->tx_head % RCANFD_FIFO_DEPTH] = cf->len;
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % RCANFD_FIFO_DEPTH);
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % RCANFD_FIFO_DEPTH, 0);
|
||||
|
||||
spin_lock_irqsave(&priv->tx_lock, flags);
|
||||
priv->tx_head++;
|
||||
|
@ -318,7 +318,7 @@ static netdev_tx_t sja1000_start_xmit(struct sk_buff *skb,
|
||||
for (i = 0; i < cf->len; i++)
|
||||
priv->write_reg(priv, dreg++, cf->data[i]);
|
||||
|
||||
can_put_echo_skb(skb, dev, 0);
|
||||
can_put_echo_skb(skb, dev, 0, 0);
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
cmd_reg_val |= CMD_AT;
|
||||
@ -531,7 +531,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
|
||||
stats->tx_bytes +=
|
||||
priv->read_reg(priv, SJA1000_FI) & 0xf;
|
||||
stats->tx_packets++;
|
||||
can_get_echo_skb(dev, 0);
|
||||
can_get_echo_skb(dev, 0, NULL);
|
||||
}
|
||||
netif_wake_queue(dev);
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
|
@ -104,7 +104,7 @@ static netdev_tx_t softing_netdev_start_xmit(struct sk_buff *skb,
|
||||
card->tx.last_bus = priv->index;
|
||||
++card->tx.pending;
|
||||
++priv->tx.pending;
|
||||
can_put_echo_skb(skb, dev, priv->tx.echo_put);
|
||||
can_put_echo_skb(skb, dev, priv->tx.echo_put, 0);
|
||||
++priv->tx.echo_put;
|
||||
if (priv->tx.echo_put >= TX_ECHO_SKB_MAX)
|
||||
priv->tx.echo_put = 0;
|
||||
@ -284,7 +284,7 @@ static int softing_handle_1(struct softing *card)
|
||||
skb = priv->can.echo_skb[priv->tx.echo_get];
|
||||
if (skb)
|
||||
skb->tstamp = ktime;
|
||||
can_get_echo_skb(netdev, priv->tx.echo_get);
|
||||
can_get_echo_skb(netdev, priv->tx.echo_get, NULL);
|
||||
++priv->tx.echo_get;
|
||||
if (priv->tx.echo_get >= TX_ECHO_SKB_MAX)
|
||||
priv->tx.echo_get = 0;
|
||||
|
@ -586,7 +586,7 @@ static void hi3110_tx_work_handler(struct work_struct *ws)
|
||||
frame = (struct can_frame *)priv->tx_skb->data;
|
||||
hi3110_hw_tx(spi, frame);
|
||||
priv->tx_len = 1 + frame->len;
|
||||
can_put_echo_skb(priv->tx_skb, net, 0);
|
||||
can_put_echo_skb(priv->tx_skb, net, 0, 0);
|
||||
priv->tx_skb = NULL;
|
||||
}
|
||||
}
|
||||
@ -725,7 +725,7 @@ static irqreturn_t hi3110_can_ist(int irq, void *dev_id)
|
||||
net->stats.tx_bytes += priv->tx_len - 1;
|
||||
can_led_event(net, CAN_LED_EVENT_TX);
|
||||
if (priv->tx_len) {
|
||||
can_get_echo_skb(net, 0);
|
||||
can_get_echo_skb(net, 0, NULL);
|
||||
priv->tx_len = 0;
|
||||
}
|
||||
netif_wake_queue(net);
|
||||
|
@ -1002,7 +1002,7 @@ static void mcp251x_tx_work_handler(struct work_struct *ws)
|
||||
frame->len = CAN_FRAME_MAX_DATA_LEN;
|
||||
mcp251x_hw_tx(spi, frame, 0);
|
||||
priv->tx_len = 1 + frame->len;
|
||||
can_put_echo_skb(priv->tx_skb, net, 0);
|
||||
can_put_echo_skb(priv->tx_skb, net, 0, 0);
|
||||
priv->tx_skb = NULL;
|
||||
}
|
||||
}
|
||||
@ -1171,7 +1171,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
|
||||
net->stats.tx_bytes += priv->tx_len - 1;
|
||||
can_led_event(net, CAN_LED_EVENT_TX);
|
||||
if (priv->tx_len) {
|
||||
can_get_echo_skb(net, 0);
|
||||
can_get_echo_skb(net, 0, NULL);
|
||||
priv->tx_len = 0;
|
||||
}
|
||||
netif_wake_queue(net);
|
||||
|
@ -1271,7 +1271,7 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
|
||||
stats->tx_bytes +=
|
||||
can_rx_offload_get_echo_skb(&priv->offload,
|
||||
mcp251xfd_get_tef_tail(priv),
|
||||
hw_tef_obj->ts);
|
||||
hw_tef_obj->ts, NULL);
|
||||
stats->tx_packets++;
|
||||
priv->tef->tail++;
|
||||
|
||||
@ -2436,7 +2436,7 @@ static netdev_tx_t mcp251xfd_start_xmit(struct sk_buff *skb,
|
||||
if (tx_ring->head - tx_ring->tail >= tx_ring->obj_num)
|
||||
netif_stop_queue(ndev);
|
||||
|
||||
can_put_echo_skb(skb, ndev, tx_head);
|
||||
can_put_echo_skb(skb, ndev, tx_head, 0);
|
||||
|
||||
err = mcp251xfd_tx_obj_write(priv, tx_obj);
|
||||
if (err)
|
||||
|
@ -448,7 +448,7 @@ static netdev_tx_t sun4ican_start_xmit(struct sk_buff *skb, struct net_device *d
|
||||
|
||||
writel(msg_flag_n, priv->base + SUN4I_REG_BUF0_ADDR);
|
||||
|
||||
can_put_echo_skb(skb, dev, 0);
|
||||
can_put_echo_skb(skb, dev, 0, 0);
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
|
||||
sun4i_can_write_cmdreg(priv, SUN4I_CMD_SELF_RCV_REQ);
|
||||
@ -655,7 +655,7 @@ static irqreturn_t sun4i_can_interrupt(int irq, void *dev_id)
|
||||
readl(priv->base +
|
||||
SUN4I_REG_RBUF_RBACK_START_ADDR) & 0xf;
|
||||
stats->tx_packets++;
|
||||
can_get_echo_skb(dev, 0);
|
||||
can_get_echo_skb(dev, 0, NULL);
|
||||
netif_wake_queue(dev);
|
||||
can_led_event(dev, CAN_LED_EVENT_TX);
|
||||
}
|
||||
|
@ -513,7 +513,7 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
be32_to_cpu(*(__be32 *)(cf->data + 4)));
|
||||
else
|
||||
*(u32 *)(cf->data + 4) = 0;
|
||||
can_put_echo_skb(skb, ndev, mbxno);
|
||||
can_put_echo_skb(skb, ndev, mbxno, 0);
|
||||
|
||||
spin_lock_irqsave(&priv->mbx_lock, flags);
|
||||
--priv->tx_head;
|
||||
@ -757,7 +757,7 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
|
||||
stamp = hecc_read_stamp(priv, mbxno);
|
||||
stats->tx_bytes +=
|
||||
can_rx_offload_get_echo_skb(&priv->offload,
|
||||
mbxno, stamp);
|
||||
mbxno, stamp, NULL);
|
||||
stats->tx_packets++;
|
||||
can_led_event(ndev, CAN_LED_EVENT_TX);
|
||||
--priv->tx_tail;
|
||||
|
@ -518,7 +518,7 @@ static void ems_usb_write_bulk_callback(struct urb *urb)
|
||||
netdev->stats.tx_packets++;
|
||||
netdev->stats.tx_bytes += context->dlc;
|
||||
|
||||
can_get_echo_skb(netdev, context->echo_index);
|
||||
can_get_echo_skb(netdev, context->echo_index, NULL);
|
||||
|
||||
/* Release context */
|
||||
context->echo_index = MAX_TX_URBS;
|
||||
@ -801,7 +801,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
usb_anchor_urb(urb, &dev->tx_submitted);
|
||||
|
||||
can_put_echo_skb(skb, netdev, context->echo_index);
|
||||
can_put_echo_skb(skb, netdev, context->echo_index, 0);
|
||||
|
||||
atomic_inc(&dev->active_tx_urbs);
|
||||
|
||||
|
@ -357,7 +357,7 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
|
||||
if (!msg->msg.txdone.status) {
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += context->len;
|
||||
can_get_echo_skb(netdev, context->echo_index);
|
||||
can_get_echo_skb(netdev, context->echo_index, NULL);
|
||||
} else {
|
||||
stats->tx_errors++;
|
||||
can_free_echo_skb(netdev, context->echo_index);
|
||||
@ -783,7 +783,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
||||
|
||||
usb_anchor_urb(urb, &priv->tx_submitted);
|
||||
|
||||
can_put_echo_skb(skb, netdev, context->echo_index);
|
||||
can_put_echo_skb(skb, netdev, context->echo_index, 0);
|
||||
|
||||
atomic_inc(&priv->active_tx_jobs);
|
||||
|
||||
|
@ -370,7 +370,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
goto resubmit_urb;
|
||||
}
|
||||
|
||||
can_get_echo_skb(netdev, hf->echo_id);
|
||||
can_get_echo_skb(netdev, hf->echo_id, NULL);
|
||||
|
||||
gs_free_tx_context(txc);
|
||||
|
||||
@ -525,7 +525,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
usb_anchor_urb(urb, &dev->tx_submitted);
|
||||
|
||||
can_put_echo_skb(skb, netdev, idx);
|
||||
can_put_echo_skb(skb, netdev, idx, 0);
|
||||
|
||||
atomic_inc(&dev->active_tx_urbs);
|
||||
|
||||
|
@ -578,7 +578,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
|
||||
|
||||
context->priv = priv;
|
||||
|
||||
can_put_echo_skb(skb, netdev, context->echo_index);
|
||||
can_put_echo_skb(skb, netdev, context->echo_index, 0);
|
||||
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
usb_sndbulkpipe(dev->udev,
|
||||
|
@ -1151,7 +1151,7 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
|
||||
spin_lock_irqsave(&priv->tx_contexts_lock, irq_flags);
|
||||
|
||||
can_get_echo_skb(priv->netdev, context->echo_index);
|
||||
can_get_echo_skb(priv->netdev, context->echo_index, NULL);
|
||||
context->echo_index = dev->max_tx_urbs;
|
||||
--priv->active_tx_contexts;
|
||||
netif_wake_queue(priv->netdev);
|
||||
|
@ -594,7 +594,7 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
|
||||
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
|
||||
|
||||
can_get_echo_skb(priv->netdev, context->echo_index);
|
||||
can_get_echo_skb(priv->netdev, context->echo_index, NULL);
|
||||
context->echo_index = dev->max_tx_urbs;
|
||||
--priv->active_tx_contexts;
|
||||
netif_wake_queue(priv->netdev);
|
||||
|
@ -237,7 +237,7 @@ static void mcba_usb_write_bulk_callback(struct urb *urb)
|
||||
netdev->stats.tx_bytes += ctx->dlc;
|
||||
|
||||
can_led_event(netdev, CAN_LED_EVENT_TX);
|
||||
can_get_echo_skb(netdev, ctx->ndx);
|
||||
can_get_echo_skb(netdev, ctx->ndx, NULL);
|
||||
}
|
||||
|
||||
if (urb->status)
|
||||
@ -355,7 +355,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
usb_msg.dlc |= MCBA_DLC_RTR_MASK;
|
||||
|
||||
can_put_echo_skb(skb, priv->netdev, ctx->ndx);
|
||||
can_put_echo_skb(skb, priv->netdev, ctx->ndx, 0);
|
||||
|
||||
err = mcba_usb_xmit(priv, (struct mcba_usb_msg *)&usb_msg, ctx);
|
||||
if (err)
|
||||
|
@ -309,7 +309,7 @@ static void peak_usb_write_bulk_callback(struct urb *urb)
|
||||
}
|
||||
|
||||
/* should always release echo skb and corresponding context */
|
||||
can_get_echo_skb(netdev, context->echo_index);
|
||||
can_get_echo_skb(netdev, context->echo_index, NULL);
|
||||
context->echo_index = PCAN_USB_MAX_TX_URBS;
|
||||
|
||||
/* do wakeup tx queue in case of success only */
|
||||
@ -365,7 +365,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
|
||||
|
||||
usb_anchor_urb(urb, &dev->tx_submitted);
|
||||
|
||||
can_put_echo_skb(skb, netdev, context->echo_index);
|
||||
can_put_echo_skb(skb, netdev, context->echo_index, 0);
|
||||
|
||||
atomic_inc(&dev->active_tx_urbs);
|
||||
|
||||
|
@ -672,7 +672,7 @@ static void ucan_tx_complete_msg(struct ucan_priv *up,
|
||||
/* update statistics */
|
||||
up->netdev->stats.tx_packets++;
|
||||
up->netdev->stats.tx_bytes += dlc;
|
||||
can_get_echo_skb(up->netdev, echo_index);
|
||||
can_get_echo_skb(up->netdev, echo_index, NULL);
|
||||
} else {
|
||||
up->netdev->stats.tx_dropped++;
|
||||
can_free_echo_skb(up->netdev, echo_index);
|
||||
@ -1137,7 +1137,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
|
||||
|
||||
/* put the skb on can loopback stack */
|
||||
spin_lock_irqsave(&up->echo_skb_lock, flags);
|
||||
can_put_echo_skb(skb, up->netdev, echo_index);
|
||||
can_put_echo_skb(skb, up->netdev, echo_index, 0);
|
||||
spin_unlock_irqrestore(&up->echo_skb_lock, flags);
|
||||
|
||||
/* transmit it */
|
||||
|
@ -585,7 +585,7 @@ static void usb_8dev_write_bulk_callback(struct urb *urb)
|
||||
netdev->stats.tx_packets++;
|
||||
netdev->stats.tx_bytes += context->dlc;
|
||||
|
||||
can_get_echo_skb(netdev, context->echo_index);
|
||||
can_get_echo_skb(netdev, context->echo_index, NULL);
|
||||
|
||||
can_led_event(netdev, CAN_LED_EVENT_TX);
|
||||
|
||||
@ -664,7 +664,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
usb_anchor_urb(urb, &priv->tx_submitted);
|
||||
|
||||
can_put_echo_skb(skb, netdev, context->echo_index);
|
||||
can_put_echo_skb(skb, netdev, context->echo_index, 0);
|
||||
|
||||
atomic_inc(&priv->active_tx_urbs);
|
||||
|
||||
|
@ -592,9 +592,9 @@ static void xcan_write_frame(struct net_device *ndev, struct sk_buff *skb,
|
||||
|
||||
if (!(priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES) &&
|
||||
(priv->devtype.flags & XCAN_FLAG_TXFEMP))
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max);
|
||||
can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max, 0);
|
||||
else
|
||||
can_put_echo_skb(skb, ndev, 0);
|
||||
can_put_echo_skb(skb, ndev, 0, 0);
|
||||
|
||||
priv->tx_head++;
|
||||
|
||||
@ -1292,7 +1292,7 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr)
|
||||
|
||||
while (frames_sent--) {
|
||||
stats->tx_bytes += can_get_echo_skb(ndev, priv->tx_tail %
|
||||
priv->tx_max);
|
||||
priv->tx_max, NULL);
|
||||
priv->tx_tail++;
|
||||
stats->tx_packets++;
|
||||
}
|
||||
|
44
include/linux/can/bittiming.h
Normal file
44
include/linux/can/bittiming.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _CAN_BITTIMING_H
|
||||
#define _CAN_BITTIMING_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/can/netlink.h>
|
||||
|
||||
#define CAN_SYNC_SEG 1
|
||||
|
||||
#ifdef CONFIG_CAN_CALC_BITTIMING
|
||||
int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc);
|
||||
#else /* !CONFIG_CAN_CALC_BITTIMING */
|
||||
static inline int
|
||||
can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
netdev_err(dev, "bit-timing calculation not available\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* CONFIG_CAN_CALC_BITTIMING */
|
||||
|
||||
int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc,
|
||||
const u32 *bitrate_const,
|
||||
const unsigned int bitrate_const_cnt);
|
||||
|
||||
/*
|
||||
* can_bit_time() - Duration of one bit
|
||||
*
|
||||
* Please refer to ISO 11898-1:2015, section 11.3.1.1 "Bit time" for
|
||||
* additional information.
|
||||
*
|
||||
* Return: the number of time quanta in one bit.
|
||||
*/
|
||||
static inline unsigned int can_bit_time(const struct can_bittiming *bt)
|
||||
{
|
||||
return CAN_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2;
|
||||
}
|
||||
|
||||
#endif /* !_CAN_BITTIMING_H */
|
@ -15,8 +15,10 @@
|
||||
#define _CAN_DEV_H
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/bittiming.h>
|
||||
#include <linux/can/error.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <linux/can/length.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/netdevice.h>
|
||||
@ -82,118 +84,6 @@ struct can_priv {
|
||||
#endif
|
||||
};
|
||||
|
||||
#define CAN_SYNC_SEG 1
|
||||
|
||||
/*
|
||||
* can_bit_time() - Duration of one bit
|
||||
*
|
||||
* Please refer to ISO 11898-1:2015, section 11.3.1.1 "Bit time" for
|
||||
* additional information.
|
||||
*
|
||||
* Return: the number of time quanta in one bit.
|
||||
*/
|
||||
static inline unsigned int can_bit_time(const struct can_bittiming *bt)
|
||||
{
|
||||
return CAN_SYNC_SEG + bt->prop_seg + bt->phase_seg1 + bt->phase_seg2;
|
||||
}
|
||||
|
||||
/*
|
||||
* can_cc_dlc2len(value) - convert a given data length code (dlc) of a
|
||||
* Classical CAN frame into a valid data length of max. 8 bytes.
|
||||
*
|
||||
* To be used in the CAN netdriver receive path to ensure conformance with
|
||||
* ISO 11898-1 Chapter 8.4.2.3 (DLC field)
|
||||
*/
|
||||
#define can_cc_dlc2len(dlc) (min_t(u8, (dlc), CAN_MAX_DLEN))
|
||||
|
||||
/* 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 */
|
||||
return skb->len == CANFD_MTU;
|
||||
}
|
||||
|
||||
/* helper to get the data length code (DLC) for Classical CAN raw DLC access */
|
||||
static inline u8 can_get_cc_dlc(const struct can_frame *cf, const u32 ctrlmode)
|
||||
{
|
||||
/* return len8_dlc as dlc value only if all conditions apply */
|
||||
if ((ctrlmode & CAN_CTRLMODE_CC_LEN8_DLC) &&
|
||||
(cf->len == CAN_MAX_DLEN) &&
|
||||
(cf->len8_dlc > CAN_MAX_DLEN && cf->len8_dlc <= CAN_MAX_RAW_DLC))
|
||||
return cf->len8_dlc;
|
||||
|
||||
/* return the payload length as dlc value */
|
||||
return cf->len;
|
||||
}
|
||||
|
||||
/* helper to set len and len8_dlc value for Classical CAN raw DLC access */
|
||||
static inline void can_frame_set_cc_len(struct can_frame *cf, const u8 dlc,
|
||||
const u32 ctrlmode)
|
||||
{
|
||||
/* the caller already ensured that dlc is a value from 0 .. 15 */
|
||||
if (ctrlmode & CAN_CTRLMODE_CC_LEN8_DLC && dlc > CAN_MAX_DLEN)
|
||||
cf->len8_dlc = dlc;
|
||||
|
||||
/* limit the payload length 'len' to CAN_MAX_DLEN */
|
||||
cf->len = can_cc_dlc2len(dlc);
|
||||
}
|
||||
|
||||
/* helper to define static CAN controller features at device creation time */
|
||||
static inline void can_set_static_ctrlmode(struct net_device *dev,
|
||||
@ -210,11 +100,7 @@ static inline void can_set_static_ctrlmode(struct net_device *dev,
|
||||
dev->mtu = CANFD_MTU;
|
||||
}
|
||||
|
||||
/* get data length from raw data length code (DLC) */
|
||||
u8 can_fd_dlc2len(u8 dlc);
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
u8 can_fd_len2dlc(u8 len);
|
||||
void can_setup(struct net_device *dev);
|
||||
|
||||
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
|
||||
unsigned int txqs, unsigned int rxqs);
|
||||
@ -240,23 +126,14 @@ void can_bus_off(struct net_device *dev);
|
||||
void can_change_state(struct net_device *dev, struct can_frame *cf,
|
||||
enum can_state tx_state, enum can_state rx_state);
|
||||
|
||||
int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned int idx);
|
||||
struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
u8 *len_ptr);
|
||||
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx);
|
||||
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
void of_can_transceiver(struct net_device *dev);
|
||||
#else
|
||||
static inline void of_can_transceiver(struct net_device *dev) { }
|
||||
#endif
|
||||
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
|
||||
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);
|
||||
extern struct rtnl_link_ops can_link_ops;
|
||||
int can_netlink_register(void);
|
||||
void can_netlink_unregister(void);
|
||||
|
||||
#endif /* !_CAN_DEV_H */
|
||||
|
174
include/linux/can/length.h
Normal file
174
include/linux/can/length.h
Normal file
@ -0,0 +1,174 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (C) 2020 Oliver Hartkopp <socketcan@hartkopp.net>
|
||||
* Copyright (C) 2020 Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _CAN_LENGTH_H
|
||||
#define _CAN_LENGTH_H
|
||||
|
||||
/*
|
||||
* Size of a Classical CAN Standard Frame
|
||||
*
|
||||
* Name of Field Bits
|
||||
* ---------------------------------------------------------
|
||||
* Start-of-frame 1
|
||||
* Identifier 11
|
||||
* Remote transmission request (RTR) 1
|
||||
* Identifier extension bit (IDE) 1
|
||||
* Reserved bit (r0) 1
|
||||
* Data length code (DLC) 4
|
||||
* Data field 0...64
|
||||
* CRC 15
|
||||
* CRC delimiter 1
|
||||
* ACK slot 1
|
||||
* ACK delimiter 1
|
||||
* End-of-frame (EOF) 7
|
||||
* Inter frame spacing 3
|
||||
*
|
||||
* rounded up and ignoring bitstuffing
|
||||
*/
|
||||
#define CAN_FRAME_OVERHEAD_SFF DIV_ROUND_UP(47, 8)
|
||||
|
||||
/*
|
||||
* Size of a Classical CAN Extended Frame
|
||||
*
|
||||
* Name of Field Bits
|
||||
* ---------------------------------------------------------
|
||||
* Start-of-frame 1
|
||||
* Identifier A 11
|
||||
* Substitute remote request (SRR) 1
|
||||
* Identifier extension bit (IDE) 1
|
||||
* Identifier B 18
|
||||
* Remote transmission request (RTR) 1
|
||||
* Reserved bits (r1, r0) 2
|
||||
* Data length code (DLC) 4
|
||||
* Data field 0...64
|
||||
* CRC 15
|
||||
* CRC delimiter 1
|
||||
* ACK slot 1
|
||||
* ACK delimiter 1
|
||||
* End-of-frame (EOF) 7
|
||||
* Inter frame spacing 3
|
||||
*
|
||||
* rounded up and ignoring bitstuffing
|
||||
*/
|
||||
#define CAN_FRAME_OVERHEAD_EFF DIV_ROUND_UP(67, 8)
|
||||
|
||||
/*
|
||||
* Size of a CAN-FD Standard Frame
|
||||
*
|
||||
* Name of Field Bits
|
||||
* ---------------------------------------------------------
|
||||
* Start-of-frame 1
|
||||
* Identifier 11
|
||||
* Reserved bit (r1) 1
|
||||
* Identifier extension bit (IDE) 1
|
||||
* Flexible data rate format (FDF) 1
|
||||
* Reserved bit (r0) 1
|
||||
* Bit Rate Switch (BRS) 1
|
||||
* Error Status Indicator (ESI) 1
|
||||
* Data length code (DLC) 4
|
||||
* Data field 0...512
|
||||
* Stuff Bit Count (SBC) 0...16: 4 20...64:5
|
||||
* CRC 0...16: 17 20...64:21
|
||||
* CRC delimiter (CD) 1
|
||||
* ACK slot (AS) 1
|
||||
* ACK delimiter (AD) 1
|
||||
* End-of-frame (EOF) 7
|
||||
* Inter frame spacing 3
|
||||
*
|
||||
* assuming CRC21, rounded up and ignoring bitstuffing
|
||||
*/
|
||||
#define CANFD_FRAME_OVERHEAD_SFF DIV_ROUND_UP(61, 8)
|
||||
|
||||
/*
|
||||
* Size of a CAN-FD Extended Frame
|
||||
*
|
||||
* Name of Field Bits
|
||||
* ---------------------------------------------------------
|
||||
* Start-of-frame 1
|
||||
* Identifier A 11
|
||||
* Substitute remote request (SRR) 1
|
||||
* Identifier extension bit (IDE) 1
|
||||
* Identifier B 18
|
||||
* Reserved bit (r1) 1
|
||||
* Flexible data rate format (FDF) 1
|
||||
* Reserved bit (r0) 1
|
||||
* Bit Rate Switch (BRS) 1
|
||||
* Error Status Indicator (ESI) 1
|
||||
* Data length code (DLC) 4
|
||||
* Data field 0...512
|
||||
* Stuff Bit Count (SBC) 0...16: 4 20...64:5
|
||||
* CRC 0...16: 17 20...64:21
|
||||
* CRC delimiter (CD) 1
|
||||
* ACK slot (AS) 1
|
||||
* ACK delimiter (AD) 1
|
||||
* End-of-frame (EOF) 7
|
||||
* Inter frame spacing 3
|
||||
*
|
||||
* assuming CRC21, rounded up and ignoring bitstuffing
|
||||
*/
|
||||
#define CANFD_FRAME_OVERHEAD_EFF DIV_ROUND_UP(80, 8)
|
||||
|
||||
/*
|
||||
* Maximum size of a Classical CAN frame
|
||||
* (rounded up and ignoring bitstuffing)
|
||||
*/
|
||||
#define CAN_FRAME_LEN_MAX (CAN_FRAME_OVERHEAD_EFF + CAN_MAX_DLEN)
|
||||
|
||||
/*
|
||||
* Maximum size of a CAN-FD frame
|
||||
* (rounded up and ignoring bitstuffing)
|
||||
*/
|
||||
#define CANFD_FRAME_LEN_MAX (CANFD_FRAME_OVERHEAD_EFF + CANFD_MAX_DLEN)
|
||||
|
||||
/*
|
||||
* can_cc_dlc2len(value) - convert a given data length code (dlc) of a
|
||||
* Classical CAN frame into a valid data length of max. 8 bytes.
|
||||
*
|
||||
* To be used in the CAN netdriver receive path to ensure conformance with
|
||||
* ISO 11898-1 Chapter 8.4.2.3 (DLC field)
|
||||
*/
|
||||
#define can_cc_dlc2len(dlc) (min_t(u8, (dlc), CAN_MAX_DLEN))
|
||||
|
||||
/* helper to get the data length code (DLC) for Classical CAN raw DLC access */
|
||||
static inline u8 can_get_cc_dlc(const struct can_frame *cf, const u32 ctrlmode)
|
||||
{
|
||||
/* return len8_dlc as dlc value only if all conditions apply */
|
||||
if ((ctrlmode & CAN_CTRLMODE_CC_LEN8_DLC) &&
|
||||
(cf->len == CAN_MAX_DLEN) &&
|
||||
(cf->len8_dlc > CAN_MAX_DLEN && cf->len8_dlc <= CAN_MAX_RAW_DLC))
|
||||
return cf->len8_dlc;
|
||||
|
||||
/* return the payload length as dlc value */
|
||||
return cf->len;
|
||||
}
|
||||
|
||||
/* helper to set len and len8_dlc value for Classical CAN raw DLC access */
|
||||
static inline void can_frame_set_cc_len(struct can_frame *cf, const u8 dlc,
|
||||
const u32 ctrlmode)
|
||||
{
|
||||
/* the caller already ensured that dlc is a value from 0 .. 15 */
|
||||
if (ctrlmode & CAN_CTRLMODE_CC_LEN8_DLC && dlc > CAN_MAX_DLEN)
|
||||
cf->len8_dlc = dlc;
|
||||
|
||||
/* limit the payload length 'len' to CAN_MAX_DLEN */
|
||||
cf->len = can_cc_dlc2len(dlc);
|
||||
}
|
||||
|
||||
/* get data length from raw data length code (DLC) */
|
||||
u8 can_fd_dlc2len(u8 dlc);
|
||||
|
||||
/* map the sanitized data length to an appropriate data length code */
|
||||
u8 can_fd_len2dlc(u8 len);
|
||||
|
||||
/* calculate the CAN Frame length in bytes of a given skb */
|
||||
unsigned int can_skb_get_frame_len(const struct sk_buff *skb);
|
||||
|
||||
/* map the data length to an appropriate data link layer length */
|
||||
static inline u8 canfd_sanitize_len(u8 len)
|
||||
{
|
||||
return can_fd_dlc2len(can_fd_len2dlc(len));
|
||||
}
|
||||
|
||||
#endif /* !_CAN_LENGTH_H */
|
@ -44,7 +44,8 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload);
|
||||
int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||
struct sk_buff *skb, u32 timestamp);
|
||||
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
unsigned int idx, u32 timestamp);
|
||||
unsigned int idx, u32 timestamp,
|
||||
unsigned int *frame_len_ptr);
|
||||
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
||||
struct sk_buff *skb);
|
||||
void can_rx_offload_del(struct can_rx_offload *offload);
|
||||
|
@ -16,6 +16,20 @@
|
||||
#include <linux/can.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
void can_flush_echo_skb(struct net_device *dev);
|
||||
int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned int idx, unsigned int frame_len);
|
||||
struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
u8 *len_ptr, unsigned int *frame_len_ptr);
|
||||
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
unsigned int *frame_len_ptr);
|
||||
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
|
||||
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);
|
||||
|
||||
/*
|
||||
* The struct can_skb_priv is used to transport additional information along
|
||||
* with the stored struct can(fd)_frame that can not be contained in existing
|
||||
@ -29,11 +43,13 @@
|
||||
* struct can_skb_priv - private additional data inside CAN sk_buffs
|
||||
* @ifindex: ifindex of the first interface the CAN frame appeared on
|
||||
* @skbcnt: atomic counter to have an unique id together with skb pointer
|
||||
* @frame_len: length of CAN frame in data link layer
|
||||
* @cf: align to the following CAN frame at skb->data
|
||||
*/
|
||||
struct can_skb_priv {
|
||||
int ifindex;
|
||||
int skbcnt;
|
||||
unsigned int frame_len;
|
||||
struct can_frame cf[];
|
||||
};
|
||||
|
||||
@ -74,4 +90,68 @@ 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 */
|
||||
return skb->len == CANFD_MTU;
|
||||
}
|
||||
|
||||
#endif /* !_CAN_SKB_H */
|
||||
|
Loading…
Reference in New Issue
Block a user