forked from Minki/linux
linux-can-next-for-5.20-20220625
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEBsvAIBsPu6mG7thcrX5LkNig010FAmK28FETHG1rbEBwZW5n dXRyb25peC5kZQAKCRCtfkuQ2KDTXdl9B/4h4emFRjxz0BuorLEPezEHbW3ULFES CqPOgEOj7YalEqECOYrZLf4tmQQEbWcRrKIRmBp7vVLDfSwVtY7fsjUlh0rrbpDh zXF3uCQDkm07Sy1upBbIXFCU7OBETSbtPKWF87YOcJVWpQbkwacPiokapAnnNy/J 21Sn4dyGADnYxis5QBTu7r5sCF3rxAOBJ+2SrdOeYQ+gdJYlWxPSGL4X+87fYkOE 3b5qR/8gzkGzDEG5PDnyiYgVCprUioE4WZiY7hKmcjGQBAy2q3NOgtz8m71PMI7v IdDapf85SeLZbO96CXpJBokUthb2HefFMJv0FWwF3uHV93kWSp8ge+VY =TWdX -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-5.20-20220625' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2022-06-25 this is a pull request of 22 patches for net-next/master. The first 2 patches target the xilinx driver. Srinivas Neeli's patch adds Transmitter Delay Compensation (TDC) support, a patch by me fixes a typo. The next patch is by me and fixes a typo in the m_can driver. Another patch by me allows the configuration of fixed bit rates without need for do_set_bittiming callback. The following 7 patches are by Vincent Mailhol and refactor the can-dev module and Kbuild, de-inline the can_dropped_invalid_skb() function, which has grown over the time, and drop outgoing skbs if the controller is in listen only mode. Max Staudt's patch fixes a reference in the networking/can.rst documentation. Vincent Mailhol provides 2 patches with cleanups for the etas_es58x driver. Conor Dooley adds bindings for the mpfs-can to the PolarFire SoC dtsi. Another patch by me allows the configuration of fixed data bit rates without need for do_set_data_bittiming callback. The last 5 patches are by Frank Jungclaus. They prepare the esd_usb driver to add support for the the CAN-USB/3 device in a later series. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
9dd094ee14
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/can/microchip,mpfs-can.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title:
|
||||
Microchip PolarFire SoC (MPFS) can controller
|
||||
|
||||
maintainers:
|
||||
- Conor Dooley <conor.dooley@microchip.com>
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,mpfs-can
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
can@2010c000 {
|
||||
compatible = "microchip,mpfs-can";
|
||||
reg = <0x2010c000 0x1000>;
|
||||
clocks = <&clkcfg 17>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <56>;
|
||||
};
|
@ -168,7 +168,7 @@ reflect the correct [#f1]_ traffic on the node the loopback of the sent
|
||||
data has to be performed right after a successful transmission. If
|
||||
the CAN network interface is not capable of performing the loopback for
|
||||
some reason the SocketCAN core can do this task as a fallback solution.
|
||||
See :ref:`socketcan-local-loopback1` for details (recommended).
|
||||
See :ref:`socketcan-local-loopback2` for details (recommended).
|
||||
|
||||
The loopback functionality is enabled by default to reflect standard
|
||||
networking behaviour for CAN applications. Due to some requests from
|
||||
|
@ -7420,6 +7420,13 @@ S: Maintained
|
||||
F: include/linux/errseq.h
|
||||
F: lib/errseq.c
|
||||
|
||||
ESD CAN/USB DRIVERS
|
||||
M: Frank Jungclaus <frank.jungclaus@esd.eu>
|
||||
R: socketcan@esd.eu
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/can/usb/esd_usb.c
|
||||
|
||||
ET131X NETWORK DRIVER
|
||||
M: Mark Einon <mark.einon@gmail.com>
|
||||
S: Odd Fixes
|
||||
|
@ -339,6 +339,24 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
can0: can@2010c000 {
|
||||
compatible = "microchip,mpfs-can";
|
||||
reg = <0x0 0x2010c000 0x0 0x1000>;
|
||||
clocks = <&clkcfg CLK_CAN0>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <56>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
can1: can@2010d000 {
|
||||
compatible = "microchip,mpfs-can";
|
||||
reg = <0x0 0x2010d000 0x0 0x1000>;
|
||||
clocks = <&clkcfg CLK_CAN1>;
|
||||
interrupt-parent = <&plic>;
|
||||
interrupts = <57>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
mac0: ethernet@20110000 {
|
||||
compatible = "cdns,macb";
|
||||
reg = <0x0 0x20110000 0x0 0x2000>;
|
||||
|
@ -499,6 +499,8 @@ config NET_SB1000
|
||||
|
||||
source "drivers/net/phy/Kconfig"
|
||||
|
||||
source "drivers/net/can/Kconfig"
|
||||
|
||||
source "drivers/net/mctp/Kconfig"
|
||||
|
||||
source "drivers/net/mdio/Kconfig"
|
||||
|
@ -1,5 +1,26 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menu "CAN Device Drivers"
|
||||
|
||||
menuconfig CAN_DEV
|
||||
tristate "CAN Device Drivers"
|
||||
default y
|
||||
depends on CAN
|
||||
help
|
||||
Controller Area Network (CAN) is serial communications protocol up to
|
||||
1Mbit/s for its original release (now known as Classical CAN) and up
|
||||
to 8Mbit/s for the more recent CAN with Flexible Data-Rate
|
||||
(CAN-FD). The CAN bus was originally mainly for automotive, but is now
|
||||
widely used in marine (NMEA2000), industrial, and medical
|
||||
applications. More information on the CAN network protocol family
|
||||
PF_CAN is contained in <Documentation/networking/can.rst>.
|
||||
|
||||
This section contains all the CAN(-FD) device drivers including the
|
||||
virtual ones. If you own such devices or plan to use the virtual CAN
|
||||
interfaces to develop applications, say Y here.
|
||||
|
||||
To compile as a module, choose M here: the module will be called
|
||||
can-dev.
|
||||
|
||||
if CAN_DEV
|
||||
|
||||
config CAN_VCAN
|
||||
tristate "Virtual Local CAN Interface (vcan)"
|
||||
@ -48,15 +69,22 @@ config CAN_SLCAN
|
||||
can be changed by the 'maxdev=xx' module option. This driver can
|
||||
also be built as a module. If so, the module will be called slcan.
|
||||
|
||||
config CAN_DEV
|
||||
tristate "Platform CAN drivers with Netlink support"
|
||||
config CAN_NETLINK
|
||||
bool "CAN device drivers with Netlink support"
|
||||
default y
|
||||
help
|
||||
Enables the common framework for platform CAN drivers with Netlink
|
||||
support. This is the standard library for CAN drivers.
|
||||
If unsure, say Y.
|
||||
Enables the common framework for CAN device drivers. This is the
|
||||
standard library and provides features for the Netlink interface such
|
||||
as bittiming validation, support of CAN error states, device restart
|
||||
and others.
|
||||
|
||||
if CAN_DEV
|
||||
The additional features selected by this option will be added to the
|
||||
can-dev module.
|
||||
|
||||
This is required by all platform and hardware CAN drivers. If you
|
||||
plan to use such devices or if unsure, say Y.
|
||||
|
||||
if CAN_NETLINK
|
||||
|
||||
config CAN_CALC_BITTIMING
|
||||
bool "CAN bit-timing calculation"
|
||||
@ -69,8 +97,15 @@ config CAN_CALC_BITTIMING
|
||||
source clock frequencies. Disabling saves some space, but then the
|
||||
bit-timing parameters must be specified directly using the Netlink
|
||||
arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw".
|
||||
|
||||
The additional features selected by this option will be added to the
|
||||
can-dev module.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config CAN_RX_OFFLOAD
|
||||
bool
|
||||
|
||||
config CAN_AT91
|
||||
tristate "Atmel AT91 onchip CAN controller"
|
||||
depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM
|
||||
@ -82,6 +117,7 @@ config CAN_FLEXCAN
|
||||
tristate "Support for Freescale FLEXCAN based chips"
|
||||
depends on OF || COLDFIRE || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
select CAN_RX_OFFLOAD
|
||||
help
|
||||
Say Y here if you want to support for Freescale FlexCAN.
|
||||
|
||||
@ -131,6 +167,7 @@ config CAN_SUN4I
|
||||
config CAN_TI_HECC
|
||||
depends on ARM
|
||||
tristate "TI High End CAN Controller"
|
||||
select CAN_RX_OFFLOAD
|
||||
help
|
||||
Driver for TI HECC (High End CAN Controller) module found on many
|
||||
TI devices. The device specifications are available from www.ti.com
|
||||
@ -164,7 +201,7 @@ source "drivers/net/can/softing/Kconfig"
|
||||
source "drivers/net/can/spi/Kconfig"
|
||||
source "drivers/net/can/usb/Kconfig"
|
||||
|
||||
endif
|
||||
endif #CAN_NETLINK
|
||||
|
||||
config CAN_DEBUG_DEVICES
|
||||
bool "CAN devices debugging messages"
|
||||
@ -174,4 +211,4 @@ config CAN_DEBUG_DEVICES
|
||||
a problem with CAN support and want to see more of what is going
|
||||
on.
|
||||
|
||||
endmenu
|
||||
endif #CAN_DEV
|
||||
|
@ -1,9 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||
can-dev-y += bittiming.o
|
||||
can-dev-y += dev.o
|
||||
can-dev-y += length.o
|
||||
can-dev-y += netlink.o
|
||||
can-dev-y += rx-offload.o
|
||||
can-dev-y += skb.o
|
||||
obj-$(CONFIG_CAN_DEV) += can-dev.o
|
||||
|
||||
can-dev-y += skb.o
|
||||
|
||||
can-dev-$(CONFIG_CAN_CALC_BITTIMING) += calc_bittiming.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += bittiming.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += dev.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += length.o
|
||||
can-dev-$(CONFIG_CAN_NETLINK) += netlink.o
|
||||
can-dev-$(CONFIG_CAN_RX_OFFLOAD) += rx-offload.o
|
||||
|
@ -4,205 +4,8 @@
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
#include <linux/units.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#ifdef CONFIG_CAN_CALC_BITTIMING
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
|
||||
/* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int
|
||||
can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
const unsigned int sample_point_nominal, const unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_SYNC_SEG -
|
||||
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
||||
1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
||||
(tseg + CAN_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if (sample_point <= sample_point_nominal &&
|
||||
sample_point_error < best_sample_point_error) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_nominal; /* nominal sample point */
|
||||
unsigned int best_tseg = 0; /* current best value for tseg */
|
||||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800 * KILO /* BPS */)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500 * KILO /* BPS */)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if (brp < btc->brp_min || brp > btc->brp_max)
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error >= best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
||||
best_tseg, &tseg1, &tseg2,
|
||||
NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
|
||||
const struct can_bittiming *dbt,
|
||||
u32 *ctrlmode, u32 ctrlmode_supported)
|
||||
|
||||
{
|
||||
if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
|
||||
return;
|
||||
|
||||
*ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
|
||||
|
||||
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
|
||||
* delay compensation" (TDC) is only applicable if data BRP is
|
||||
* one or two.
|
||||
*/
|
||||
if (dbt->brp == 1 || dbt->brp == 2) {
|
||||
/* Sample point in clock periods */
|
||||
u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
|
||||
dbt->phase_seg1) * dbt->brp;
|
||||
|
||||
if (sample_point_in_tc < tdc_const->tdco_min)
|
||||
return;
|
||||
tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
|
||||
*ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_CAN_CALC_BITTIMING */
|
||||
|
||||
/* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
|
202
drivers/net/can/dev/calc_bittiming.c
Normal file
202
drivers/net/can/dev/calc_bittiming.c
Normal file
@ -0,0 +1,202 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
|
||||
* Copyright (C) 2006 Andrey Volkov, Varma Electronics
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
#include <linux/units.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
#define CAN_CALC_MAX_ERROR 50 /* in one-tenth of a percent */
|
||||
|
||||
/* Bit-timing calculation derived from:
|
||||
*
|
||||
* Code based on LinCAN sources and H8S2638 project
|
||||
* Copyright 2004-2006 Pavel Pisa - DCE FELK CVUT cz
|
||||
* Copyright 2005 Stanislav Marek
|
||||
* email: pisa@cmp.felk.cvut.cz
|
||||
*
|
||||
* Calculates proper bit-timing parameters for a specified bit-rate
|
||||
* and sample-point, which can then be used to set the bit-timing
|
||||
* registers of the CAN controller. You can find more information
|
||||
* in the header file linux/can/netlink.h.
|
||||
*/
|
||||
static int
|
||||
can_update_sample_point(const struct can_bittiming_const *btc,
|
||||
const unsigned int sample_point_nominal, const unsigned int tseg,
|
||||
unsigned int *tseg1_ptr, unsigned int *tseg2_ptr,
|
||||
unsigned int *sample_point_error_ptr)
|
||||
{
|
||||
unsigned int sample_point_error, best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point, best_sample_point = 0;
|
||||
unsigned int tseg1, tseg2;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= 1; i++) {
|
||||
tseg2 = tseg + CAN_SYNC_SEG -
|
||||
(sample_point_nominal * (tseg + CAN_SYNC_SEG)) /
|
||||
1000 - i;
|
||||
tseg2 = clamp(tseg2, btc->tseg2_min, btc->tseg2_max);
|
||||
tseg1 = tseg - tseg2;
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
tseg1 = btc->tseg1_max;
|
||||
tseg2 = tseg - tseg1;
|
||||
}
|
||||
|
||||
sample_point = 1000 * (tseg + CAN_SYNC_SEG - tseg2) /
|
||||
(tseg + CAN_SYNC_SEG);
|
||||
sample_point_error = abs(sample_point_nominal - sample_point);
|
||||
|
||||
if (sample_point <= sample_point_nominal &&
|
||||
sample_point_error < best_sample_point_error) {
|
||||
best_sample_point = sample_point;
|
||||
best_sample_point_error = sample_point_error;
|
||||
*tseg1_ptr = tseg1;
|
||||
*tseg2_ptr = tseg2;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_point_error_ptr)
|
||||
*sample_point_error_ptr = best_sample_point_error;
|
||||
|
||||
return best_sample_point;
|
||||
}
|
||||
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
unsigned int bitrate_error; /* difference between current and nominal value */
|
||||
unsigned int best_bitrate_error = UINT_MAX;
|
||||
unsigned int sample_point_error; /* difference between current and nominal value */
|
||||
unsigned int best_sample_point_error = UINT_MAX;
|
||||
unsigned int sample_point_nominal; /* nominal sample point */
|
||||
unsigned int best_tseg = 0; /* current best value for tseg */
|
||||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
sample_point_nominal = bt->sample_point;
|
||||
} else {
|
||||
if (bt->bitrate > 800 * KILO /* BPS */)
|
||||
sample_point_nominal = 750;
|
||||
else if (bt->bitrate > 500 * KILO /* BPS */)
|
||||
sample_point_nominal = 800;
|
||||
else
|
||||
sample_point_nominal = 875;
|
||||
}
|
||||
|
||||
/* tseg even = round down, odd = round up */
|
||||
for (tseg = (btc->tseg1_max + btc->tseg2_max) * 2 + 1;
|
||||
tseg >= (btc->tseg1_min + btc->tseg2_min) * 2; tseg--) {
|
||||
tsegall = CAN_SYNC_SEG + tseg / 2;
|
||||
|
||||
/* Compute all possible tseg choices (tseg=tseg1+tseg2) */
|
||||
brp = priv->clock.freq / (tsegall * bt->bitrate) + tseg % 2;
|
||||
|
||||
/* choose brp step which is possible in system */
|
||||
brp = (brp / btc->brp_inc) * btc->brp_inc;
|
||||
if (brp < btc->brp_min || brp > btc->brp_max)
|
||||
continue;
|
||||
|
||||
bitrate = priv->clock.freq / (brp * tsegall);
|
||||
bitrate_error = abs(bt->bitrate - bitrate);
|
||||
|
||||
/* tseg brp biterror */
|
||||
if (bitrate_error > best_bitrate_error)
|
||||
continue;
|
||||
|
||||
/* reset sample point error if we have a better bitrate */
|
||||
if (bitrate_error < best_bitrate_error)
|
||||
best_sample_point_error = UINT_MAX;
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error >= best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
best_bitrate_error = bitrate_error;
|
||||
best_tseg = tseg / 2;
|
||||
best_brp = brp;
|
||||
|
||||
if (bitrate_error == 0 && sample_point_error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (best_bitrate_error) {
|
||||
/* Error in one-tenth of a percent */
|
||||
v64 = (u64)best_bitrate_error * 1000;
|
||||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
bt->sample_point = can_update_sample_point(btc, sample_point_nominal,
|
||||
best_tseg, &tseg1, &tseg2,
|
||||
NULL);
|
||||
|
||||
v64 = (u64)best_brp * 1000 * 1000 * 1000;
|
||||
do_div(v64, priv->clock.freq);
|
||||
bt->tq = (u32)v64;
|
||||
bt->prop_seg = tseg1 / 2;
|
||||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
|
||||
const struct can_bittiming *dbt,
|
||||
u32 *ctrlmode, u32 ctrlmode_supported)
|
||||
|
||||
{
|
||||
if (!tdc_const || !(ctrlmode_supported & CAN_CTRLMODE_TDC_AUTO))
|
||||
return;
|
||||
|
||||
*ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
|
||||
|
||||
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
|
||||
* delay compensation" (TDC) is only applicable if data BRP is
|
||||
* one or two.
|
||||
*/
|
||||
if (dbt->brp == 1 || dbt->brp == 2) {
|
||||
/* Sample point in clock periods */
|
||||
u32 sample_point_in_tc = (CAN_SYNC_SEG + dbt->prop_seg +
|
||||
dbt->phase_seg1) * dbt->brp;
|
||||
|
||||
if (sample_point_in_tc < tdc_const->tdco_min)
|
||||
return;
|
||||
tdc->tdco = min(sample_point_in_tc, tdc_const->tdco_max);
|
||||
*ctrlmode |= CAN_CTRLMODE_TDC_AUTO;
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
* Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/netdevice.h>
|
||||
@ -17,12 +16,6 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define MOD_DESC "CAN device driver interface"
|
||||
|
||||
MODULE_DESCRIPTION(MOD_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
||||
|
||||
static void can_update_state_error_stats(struct net_device *dev,
|
||||
enum can_state new_state)
|
||||
{
|
||||
@ -513,7 +506,7 @@ static __init int can_dev_init(void)
|
||||
|
||||
err = can_netlink_register();
|
||||
if (!err)
|
||||
pr_info(MOD_DESC "\n");
|
||||
pr_info("CAN device driver interface\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -176,7 +176,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
* directly via do_set_bitrate(). Bail out if neither
|
||||
* is given.
|
||||
*/
|
||||
if (!priv->bittiming_const && !priv->do_set_bittiming)
|
||||
if (!priv->bittiming_const && !priv->do_set_bittiming &&
|
||||
!priv->bitrate_const)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
|
||||
@ -278,7 +279,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
* directly via do_set_bitrate(). Bail out if neither
|
||||
* is given.
|
||||
*/
|
||||
if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
|
||||
if (!priv->data_bittiming_const && !priv->do_set_data_bittiming &&
|
||||
!priv->data_bitrate_const)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
|
||||
|
@ -5,6 +5,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/netlink.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define MOD_DESC "CAN device driver interface"
|
||||
|
||||
MODULE_DESCRIPTION(MOD_DESC);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
|
||||
|
||||
/* Local echo of CAN messages
|
||||
*
|
||||
@ -252,3 +260,67 @@ struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_can_err_skb);
|
||||
|
||||
/* Check for outgoing skbs that have not been created by the CAN subsystem */
|
||||
static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
|
||||
return false;
|
||||
|
||||
/* af_packet does not apply CAN skb specific settings */
|
||||
if (skb->ip_summed == CHECKSUM_NONE) {
|
||||
/* init headroom */
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
/* perform proper loopback on capable devices */
|
||||
if (dev->flags & IFF_ECHO)
|
||||
skb->pkt_type = PACKET_LOOPBACK;
|
||||
else
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (skb->protocol == htons(ETH_P_CAN)) {
|
||||
if (unlikely(skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->protocol == htons(ETH_P_CANFD)) {
|
||||
if (unlikely(skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else {
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
if (!can_skb_headroom_valid(dev, skb)) {
|
||||
goto inval_skb;
|
||||
} else if (priv->ctrlmode & CAN_CTRLMODE_LISTENONLY) {
|
||||
netdev_info_once(dev,
|
||||
"interface in listen only mode, dropping skb\n");
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
inval_skb:
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_dropped_invalid_skb);
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
menuconfig CAN_M_CAN
|
||||
tristate "Bosch M_CAN support"
|
||||
select CAN_RX_OFFLOAD
|
||||
help
|
||||
Say Y here if you want support for Bosch M_CAN controller framework.
|
||||
This is common support for devices that embed the Bosch M_CAN IP.
|
||||
|
@ -1348,8 +1348,8 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
/* set bittiming params */
|
||||
m_can_set_bittiming(dev);
|
||||
|
||||
/* enable internal timestamp generation, with a prescalar of 16. The
|
||||
* prescalar is applied to the nominal bit timing
|
||||
/* enable internal timestamp generation, with a prescaler of 16. The
|
||||
* prescaler is applied to the nominal bit timing
|
||||
*/
|
||||
m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
config CAN_MCP251XFD
|
||||
tristate "Microchip MCP251xFD SPI CAN controllers"
|
||||
select CAN_RX_OFFLOAD
|
||||
select REGMAP
|
||||
select WANT_DEV_COREDUMP
|
||||
help
|
||||
|
@ -14,11 +14,18 @@ config CAN_EMS_USB
|
||||
This driver is for the one channel CPC-USB/ARM7 CAN/USB interface
|
||||
from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
|
||||
|
||||
config CAN_ESD_USB2
|
||||
tristate "ESD USB/2 CAN/USB interface"
|
||||
config CAN_ESD_USB
|
||||
tristate "esd electronics gmbh CAN/USB interfaces"
|
||||
help
|
||||
This driver supports the CAN-USB/2 interface
|
||||
from esd electronic system design gmbh (http://www.esd.eu).
|
||||
This driver adds supports for several CAN/USB interfaces
|
||||
from esd electronics gmbh (https://www.esd.eu).
|
||||
|
||||
The drivers supports the following devices:
|
||||
- esd CAN-USB/2
|
||||
- esd CAN-USB/Micro
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called esd_usb.
|
||||
|
||||
config CAN_ETAS_ES58X
|
||||
tristate "ETAS ES58X CAN/USB interfaces"
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
|
||||
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
|
||||
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
|
||||
obj-$(CONFIG_CAN_ESD_USB) += esd_usb.o
|
||||
obj-$(CONFIG_CAN_ETAS_ES58X) += etas_es58x/
|
||||
obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
|
||||
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* CAN driver for esd CAN-USB/2 and CAN-USB/Micro
|
||||
* CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro
|
||||
*
|
||||
* Copyright (C) 2010-2012 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
|
||||
* Copyright (C) 2010-2012 esd electronic system design gmbh, Matthias Fuchs <socketcan@esd.eu>
|
||||
* Copyright (C) 2022 esd electronics gmbh, Frank Jungclaus <frank.jungclaus@esd.eu>
|
||||
*/
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
@ -14,20 +15,24 @@
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
|
||||
MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd.eu>");
|
||||
MODULE_DESCRIPTION("CAN driver for esd CAN-USB/2 and CAN-USB/Micro interfaces");
|
||||
MODULE_AUTHOR("Matthias Fuchs <socketcan@esd.eu>");
|
||||
MODULE_AUTHOR("Frank Jungclaus <frank.jungclaus@esd.eu>");
|
||||
MODULE_DESCRIPTION("CAN driver for esd electronics gmbh CAN-USB/2 and CAN-USB/Micro interfaces");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
/* Define these values to match your devices */
|
||||
/* USB vendor and product ID */
|
||||
#define USB_ESDGMBH_VENDOR_ID 0x0ab4
|
||||
#define USB_CANUSB2_PRODUCT_ID 0x0010
|
||||
#define USB_CANUSBM_PRODUCT_ID 0x0011
|
||||
|
||||
/* CAN controller clock frequencies */
|
||||
#define ESD_USB2_CAN_CLOCK 60000000
|
||||
#define ESD_USBM_CAN_CLOCK 36000000
|
||||
#define ESD_USB2_MAX_NETS 2
|
||||
|
||||
/* USB2 commands */
|
||||
/* Maximum number of CAN nets */
|
||||
#define ESD_USB_MAX_NETS 2
|
||||
|
||||
/* USB commands */
|
||||
#define CMD_VERSION 1 /* also used for VERSION_REPLY */
|
||||
#define CMD_CAN_RX 2 /* device to host only */
|
||||
#define CMD_CAN_TX 3 /* also used for TX_DONE */
|
||||
@ -43,13 +48,15 @@ MODULE_LICENSE("GPL v2");
|
||||
#define ESD_EVENT 0x40000000
|
||||
#define ESD_IDMASK 0x1fffffff
|
||||
|
||||
/* esd CAN event ids used by this driver */
|
||||
#define ESD_EV_CAN_ERROR_EXT 2
|
||||
/* esd CAN event ids */
|
||||
#define ESD_EV_CAN_ERROR_EXT 2 /* CAN controller specific diagnostic data */
|
||||
|
||||
/* baudrate message flags */
|
||||
#define ESD_USB2_UBR 0x80000000
|
||||
#define ESD_USB2_LOM 0x40000000
|
||||
#define ESD_USB2_NO_BAUDRATE 0x7fffffff
|
||||
#define ESD_USB_UBR 0x80000000
|
||||
#define ESD_USB_LOM 0x40000000
|
||||
#define ESD_USB_NO_BAUDRATE 0x7fffffff
|
||||
|
||||
/* bit timing CAN-USB/2 */
|
||||
#define ESD_USB2_TSEG1_MIN 1
|
||||
#define ESD_USB2_TSEG1_MAX 16
|
||||
#define ESD_USB2_TSEG1_SHIFT 16
|
||||
@ -68,7 +75,7 @@ MODULE_LICENSE("GPL v2");
|
||||
#define ESD_ID_ENABLE 0x80
|
||||
#define ESD_MAX_ID_SEGMENT 64
|
||||
|
||||
/* SJA1000 ECC register (emulated by usb2 firmware) */
|
||||
/* SJA1000 ECC register (emulated by usb firmware) */
|
||||
#define SJA1000_ECC_SEG 0x1F
|
||||
#define SJA1000_ECC_DIR 0x20
|
||||
#define SJA1000_ECC_ERR 0x06
|
||||
@ -158,7 +165,7 @@ struct set_baudrate_msg {
|
||||
};
|
||||
|
||||
/* Main message type used between library and application */
|
||||
struct __attribute__ ((packed)) esd_usb2_msg {
|
||||
struct __packed esd_usb_msg {
|
||||
union {
|
||||
struct header_msg hdr;
|
||||
struct version_msg version;
|
||||
@ -171,23 +178,23 @@ struct __attribute__ ((packed)) esd_usb2_msg {
|
||||
} msg;
|
||||
};
|
||||
|
||||
static struct usb_device_id esd_usb2_table[] = {
|
||||
static struct usb_device_id esd_usb_table[] = {
|
||||
{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSB2_PRODUCT_ID)},
|
||||
{USB_DEVICE(USB_ESDGMBH_VENDOR_ID, USB_CANUSBM_PRODUCT_ID)},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, esd_usb2_table);
|
||||
MODULE_DEVICE_TABLE(usb, esd_usb_table);
|
||||
|
||||
struct esd_usb2_net_priv;
|
||||
struct esd_usb_net_priv;
|
||||
|
||||
struct esd_tx_urb_context {
|
||||
struct esd_usb2_net_priv *priv;
|
||||
struct esd_usb_net_priv *priv;
|
||||
u32 echo_index;
|
||||
};
|
||||
|
||||
struct esd_usb2 {
|
||||
struct esd_usb {
|
||||
struct usb_device *udev;
|
||||
struct esd_usb2_net_priv *nets[ESD_USB2_MAX_NETS];
|
||||
struct esd_usb_net_priv *nets[ESD_USB_MAX_NETS];
|
||||
|
||||
struct usb_anchor rx_submitted;
|
||||
|
||||
@ -198,22 +205,22 @@ struct esd_usb2 {
|
||||
dma_addr_t rxbuf_dma[MAX_RX_URBS];
|
||||
};
|
||||
|
||||
struct esd_usb2_net_priv {
|
||||
struct esd_usb_net_priv {
|
||||
struct can_priv can; /* must be the first member */
|
||||
|
||||
atomic_t active_tx_jobs;
|
||||
struct usb_anchor tx_submitted;
|
||||
struct esd_tx_urb_context tx_contexts[MAX_TX_URBS];
|
||||
|
||||
struct esd_usb2 *usb2;
|
||||
struct esd_usb *usb;
|
||||
struct net_device *netdev;
|
||||
int index;
|
||||
u8 old_state;
|
||||
struct can_berr_counter bec;
|
||||
};
|
||||
|
||||
static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
|
||||
struct esd_usb2_msg *msg)
|
||||
static void esd_usb_rx_event(struct esd_usb_net_priv *priv,
|
||||
struct esd_usb_msg *msg)
|
||||
{
|
||||
struct net_device_stats *stats = &priv->netdev->stats;
|
||||
struct can_frame *cf;
|
||||
@ -296,8 +303,8 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
|
||||
}
|
||||
}
|
||||
|
||||
static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
|
||||
struct esd_usb2_msg *msg)
|
||||
static void esd_usb_rx_can_msg(struct esd_usb_net_priv *priv,
|
||||
struct esd_usb_msg *msg)
|
||||
{
|
||||
struct net_device_stats *stats = &priv->netdev->stats;
|
||||
struct can_frame *cf;
|
||||
@ -311,7 +318,7 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
|
||||
id = le32_to_cpu(msg->msg.rx.id);
|
||||
|
||||
if (id & ESD_EVENT) {
|
||||
esd_usb2_rx_event(priv, msg);
|
||||
esd_usb_rx_event(priv, msg);
|
||||
} else {
|
||||
skb = alloc_can_skb(priv->netdev, &cf);
|
||||
if (skb == NULL) {
|
||||
@ -338,12 +345,10 @@ static void esd_usb2_rx_can_msg(struct esd_usb2_net_priv *priv,
|
||||
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
|
||||
struct esd_usb2_msg *msg)
|
||||
static void esd_usb_tx_done_msg(struct esd_usb_net_priv *priv,
|
||||
struct esd_usb_msg *msg)
|
||||
{
|
||||
struct net_device_stats *stats = &priv->netdev->stats;
|
||||
struct net_device *netdev = priv->netdev;
|
||||
@ -370,9 +375,9 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
|
||||
netif_wake_queue(netdev);
|
||||
}
|
||||
|
||||
static void esd_usb2_read_bulk_callback(struct urb *urb)
|
||||
static void esd_usb_read_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct esd_usb2 *dev = urb->context;
|
||||
struct esd_usb *dev = urb->context;
|
||||
int retval;
|
||||
int pos = 0;
|
||||
int i;
|
||||
@ -394,9 +399,9 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
|
||||
}
|
||||
|
||||
while (pos < urb->actual_length) {
|
||||
struct esd_usb2_msg *msg;
|
||||
struct esd_usb_msg *msg;
|
||||
|
||||
msg = (struct esd_usb2_msg *)(urb->transfer_buffer + pos);
|
||||
msg = (struct esd_usb_msg *)(urb->transfer_buffer + pos);
|
||||
|
||||
switch (msg->msg.hdr.cmd) {
|
||||
case CMD_CAN_RX:
|
||||
@ -405,7 +410,7 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
|
||||
break;
|
||||
}
|
||||
|
||||
esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
|
||||
esd_usb_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
|
||||
break;
|
||||
|
||||
case CMD_CAN_TX:
|
||||
@ -414,8 +419,8 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
|
||||
break;
|
||||
}
|
||||
|
||||
esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
|
||||
msg);
|
||||
esd_usb_tx_done_msg(dev->nets[msg->msg.txdone.net],
|
||||
msg);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -430,7 +435,7 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
|
||||
resubmit_urb:
|
||||
usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
|
||||
urb->transfer_buffer, RX_BUFFER_SIZE,
|
||||
esd_usb2_read_bulk_callback, dev);
|
||||
esd_usb_read_bulk_callback, dev);
|
||||
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (retval == -ENODEV) {
|
||||
@ -442,19 +447,15 @@ resubmit_urb:
|
||||
dev_err(dev->udev->dev.parent,
|
||||
"failed resubmitting read bulk urb: %d\n", retval);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* callback for bulk IN urb
|
||||
*/
|
||||
static void esd_usb2_write_bulk_callback(struct urb *urb)
|
||||
/* callback for bulk IN urb */
|
||||
static void esd_usb_write_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct esd_tx_urb_context *context = urb->context;
|
||||
struct esd_usb2_net_priv *priv;
|
||||
struct esd_usb_net_priv *priv;
|
||||
struct net_device *netdev;
|
||||
size_t size = sizeof(struct esd_usb2_msg);
|
||||
size_t size = sizeof(struct esd_usb_msg);
|
||||
|
||||
WARN_ON(!context);
|
||||
|
||||
@ -478,7 +479,7 @@ static ssize_t firmware_show(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(d);
|
||||
struct esd_usb2 *dev = usb_get_intfdata(intf);
|
||||
struct esd_usb *dev = usb_get_intfdata(intf);
|
||||
|
||||
return sprintf(buf, "%d.%d.%d\n",
|
||||
(dev->version >> 12) & 0xf,
|
||||
@ -491,7 +492,7 @@ static ssize_t hardware_show(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(d);
|
||||
struct esd_usb2 *dev = usb_get_intfdata(intf);
|
||||
struct esd_usb *dev = usb_get_intfdata(intf);
|
||||
|
||||
return sprintf(buf, "%d.%d.%d\n",
|
||||
(dev->version >> 28) & 0xf,
|
||||
@ -504,13 +505,13 @@ static ssize_t nets_show(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(d);
|
||||
struct esd_usb2 *dev = usb_get_intfdata(intf);
|
||||
struct esd_usb *dev = usb_get_intfdata(intf);
|
||||
|
||||
return sprintf(buf, "%d", dev->net_count);
|
||||
}
|
||||
static DEVICE_ATTR_RO(nets);
|
||||
|
||||
static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
|
||||
static int esd_usb_send_msg(struct esd_usb *dev, struct esd_usb_msg *msg)
|
||||
{
|
||||
int actual_length;
|
||||
|
||||
@ -522,8 +523,8 @@ static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
|
||||
1000);
|
||||
}
|
||||
|
||||
static int esd_usb2_wait_msg(struct esd_usb2 *dev,
|
||||
struct esd_usb2_msg *msg)
|
||||
static int esd_usb_wait_msg(struct esd_usb *dev,
|
||||
struct esd_usb_msg *msg)
|
||||
{
|
||||
int actual_length;
|
||||
|
||||
@ -535,7 +536,7 @@ static int esd_usb2_wait_msg(struct esd_usb2 *dev,
|
||||
1000);
|
||||
}
|
||||
|
||||
static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
|
||||
static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
@ -568,7 +569,7 @@ static int esd_usb2_setup_rx_urbs(struct esd_usb2 *dev)
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev, 1),
|
||||
buf, RX_BUFFER_SIZE,
|
||||
esd_usb2_read_bulk_callback, dev);
|
||||
esd_usb_read_bulk_callback, dev);
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
usb_anchor_urb(urb, &dev->rx_submitted);
|
||||
|
||||
@ -606,14 +607,12 @@ freeurb:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Start interface
|
||||
*/
|
||||
static int esd_usb2_start(struct esd_usb2_net_priv *priv)
|
||||
/* Start interface */
|
||||
static int esd_usb_start(struct esd_usb_net_priv *priv)
|
||||
{
|
||||
struct esd_usb2 *dev = priv->usb2;
|
||||
struct esd_usb *dev = priv->usb;
|
||||
struct net_device *netdev = priv->netdev;
|
||||
struct esd_usb2_msg *msg;
|
||||
struct esd_usb_msg *msg;
|
||||
int err, i;
|
||||
|
||||
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
|
||||
@ -622,8 +621,7 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable all IDs
|
||||
/* Enable all IDs
|
||||
* The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
|
||||
* Each bit represents one 11 bit CAN identifier. A set bit
|
||||
* enables reception of the corresponding CAN identifier. A cleared
|
||||
@ -644,11 +642,11 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
|
||||
/* enable 29bit extended IDs */
|
||||
msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
|
||||
|
||||
err = esd_usb2_send_msg(dev, msg);
|
||||
err = esd_usb_send_msg(dev, msg);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = esd_usb2_setup_rx_urbs(dev);
|
||||
err = esd_usb_setup_rx_urbs(dev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -664,9 +662,9 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void unlink_all_urbs(struct esd_usb2 *dev)
|
||||
static void unlink_all_urbs(struct esd_usb *dev)
|
||||
{
|
||||
struct esd_usb2_net_priv *priv;
|
||||
struct esd_usb_net_priv *priv;
|
||||
int i, j;
|
||||
|
||||
usb_kill_anchored_urbs(&dev->rx_submitted);
|
||||
@ -687,9 +685,9 @@ static void unlink_all_urbs(struct esd_usb2 *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static int esd_usb2_open(struct net_device *netdev)
|
||||
static int esd_usb_open(struct net_device *netdev)
|
||||
{
|
||||
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb_net_priv *priv = netdev_priv(netdev);
|
||||
int err;
|
||||
|
||||
/* common open */
|
||||
@ -698,7 +696,7 @@ static int esd_usb2_open(struct net_device *netdev)
|
||||
return err;
|
||||
|
||||
/* finally start device */
|
||||
err = esd_usb2_start(priv);
|
||||
err = esd_usb_start(priv);
|
||||
if (err) {
|
||||
netdev_warn(netdev, "couldn't start device: %d\n", err);
|
||||
close_candev(netdev);
|
||||
@ -710,20 +708,20 @@ static int esd_usb2_open(struct net_device *netdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
||||
static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb2 *dev = priv->usb2;
|
||||
struct esd_usb_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb *dev = priv->usb;
|
||||
struct esd_tx_urb_context *context = NULL;
|
||||
struct net_device_stats *stats = &netdev->stats;
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
struct esd_usb2_msg *msg;
|
||||
struct esd_usb_msg *msg;
|
||||
struct urb *urb;
|
||||
u8 *buf;
|
||||
int i, err;
|
||||
int ret = NETDEV_TX_OK;
|
||||
size_t size = sizeof(struct esd_usb2_msg);
|
||||
size_t size = sizeof(struct esd_usb_msg);
|
||||
|
||||
if (can_dropped_invalid_skb(netdev, skb))
|
||||
return NETDEV_TX_OK;
|
||||
@ -745,7 +743,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
||||
goto nobufmem;
|
||||
}
|
||||
|
||||
msg = (struct esd_usb2_msg *)buf;
|
||||
msg = (struct esd_usb_msg *)buf;
|
||||
|
||||
msg->msg.hdr.len = 3; /* minimal length */
|
||||
msg->msg.hdr.cmd = CMD_CAN_TX;
|
||||
@ -771,9 +769,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This may never happen.
|
||||
*/
|
||||
/* This may never happen */
|
||||
if (!context) {
|
||||
netdev_warn(netdev, "couldn't find free context\n");
|
||||
ret = NETDEV_TX_BUSY;
|
||||
@ -788,7 +784,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
||||
|
||||
usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
|
||||
msg->msg.hdr.len << 2,
|
||||
esd_usb2_write_bulk_callback, context);
|
||||
esd_usb_write_bulk_callback, context);
|
||||
|
||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
@ -821,8 +817,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
|
||||
|
||||
netif_trans_update(netdev);
|
||||
|
||||
/*
|
||||
* Release our reference to this URB, the USB core will eventually free
|
||||
/* Release our reference to this URB, the USB core will eventually free
|
||||
* it entirely.
|
||||
*/
|
||||
usb_free_urb(urb);
|
||||
@ -839,24 +834,24 @@ nourbmem:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int esd_usb2_close(struct net_device *netdev)
|
||||
static int esd_usb_close(struct net_device *netdev)
|
||||
{
|
||||
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb2_msg *msg;
|
||||
struct esd_usb_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb_msg *msg;
|
||||
int i;
|
||||
|
||||
msg = kmalloc(sizeof(*msg), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Disable all IDs (see esd_usb2_start()) */
|
||||
/* Disable all IDs (see esd_usb_start()) */
|
||||
msg->msg.hdr.cmd = CMD_IDADD;
|
||||
msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
|
||||
msg->msg.filter.net = priv->index;
|
||||
msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
|
||||
for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
|
||||
msg->msg.filter.mask[i] = 0;
|
||||
if (esd_usb2_send_msg(priv->usb2, msg) < 0)
|
||||
if (esd_usb_send_msg(priv->usb, msg) < 0)
|
||||
netdev_err(netdev, "sending idadd message failed\n");
|
||||
|
||||
/* set CAN controller to reset mode */
|
||||
@ -864,8 +859,8 @@ static int esd_usb2_close(struct net_device *netdev)
|
||||
msg->msg.hdr.cmd = CMD_SETBAUD;
|
||||
msg->msg.setbaud.net = priv->index;
|
||||
msg->msg.setbaud.rsvd = 0;
|
||||
msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
|
||||
if (esd_usb2_send_msg(priv->usb2, msg) < 0)
|
||||
msg->msg.setbaud.baud = cpu_to_le32(ESD_USB_NO_BAUDRATE);
|
||||
if (esd_usb_send_msg(priv->usb, msg) < 0)
|
||||
netdev_err(netdev, "sending setbaud message failed\n");
|
||||
|
||||
priv->can.state = CAN_STATE_STOPPED;
|
||||
@ -879,10 +874,10 @@ static int esd_usb2_close(struct net_device *netdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct net_device_ops esd_usb2_netdev_ops = {
|
||||
.ndo_open = esd_usb2_open,
|
||||
.ndo_stop = esd_usb2_close,
|
||||
.ndo_start_xmit = esd_usb2_start_xmit,
|
||||
static const struct net_device_ops esd_usb_netdev_ops = {
|
||||
.ndo_open = esd_usb_open,
|
||||
.ndo_stop = esd_usb_close,
|
||||
.ndo_start_xmit = esd_usb_start_xmit,
|
||||
.ndo_change_mtu = can_change_mtu,
|
||||
};
|
||||
|
||||
@ -900,20 +895,20 @@ static const struct can_bittiming_const esd_usb2_bittiming_const = {
|
||||
|
||||
static int esd_usb2_set_bittiming(struct net_device *netdev)
|
||||
{
|
||||
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb_net_priv *priv = netdev_priv(netdev);
|
||||
struct can_bittiming *bt = &priv->can.bittiming;
|
||||
struct esd_usb2_msg *msg;
|
||||
struct esd_usb_msg *msg;
|
||||
int err;
|
||||
u32 canbtr;
|
||||
int sjw_shift;
|
||||
|
||||
canbtr = ESD_USB2_UBR;
|
||||
canbtr = ESD_USB_UBR;
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
|
||||
canbtr |= ESD_USB2_LOM;
|
||||
canbtr |= ESD_USB_LOM;
|
||||
|
||||
canbtr |= (bt->brp - 1) & (ESD_USB2_BRP_MAX - 1);
|
||||
|
||||
if (le16_to_cpu(priv->usb2->udev->descriptor.idProduct) ==
|
||||
if (le16_to_cpu(priv->usb->udev->descriptor.idProduct) ==
|
||||
USB_CANUSBM_PRODUCT_ID)
|
||||
sjw_shift = ESD_USBM_SJW_SHIFT;
|
||||
else
|
||||
@ -941,16 +936,16 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
|
||||
|
||||
netdev_info(netdev, "setting BTR=%#x\n", canbtr);
|
||||
|
||||
err = esd_usb2_send_msg(priv->usb2, msg);
|
||||
err = esd_usb_send_msg(priv->usb, msg);
|
||||
|
||||
kfree(msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int esd_usb2_get_berr_counter(const struct net_device *netdev,
|
||||
struct can_berr_counter *bec)
|
||||
static int esd_usb_get_berr_counter(const struct net_device *netdev,
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
|
||||
struct esd_usb_net_priv *priv = netdev_priv(netdev);
|
||||
|
||||
bec->txerr = priv->bec.txerr;
|
||||
bec->rxerr = priv->bec.rxerr;
|
||||
@ -958,7 +953,7 @@ static int esd_usb2_get_berr_counter(const struct net_device *netdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
|
||||
static int esd_usb_set_mode(struct net_device *netdev, enum can_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case CAN_MODE_START:
|
||||
@ -972,11 +967,11 @@ static int esd_usb2_set_mode(struct net_device *netdev, enum can_mode mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
|
||||
static int esd_usb_probe_one_net(struct usb_interface *intf, int index)
|
||||
{
|
||||
struct esd_usb2 *dev = usb_get_intfdata(intf);
|
||||
struct esd_usb *dev = usb_get_intfdata(intf);
|
||||
struct net_device *netdev;
|
||||
struct esd_usb2_net_priv *priv;
|
||||
struct esd_usb_net_priv *priv;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
@ -995,7 +990,7 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
|
||||
for (i = 0; i < MAX_TX_URBS; i++)
|
||||
priv->tx_contexts[i].echo_index = MAX_TX_URBS;
|
||||
|
||||
priv->usb2 = dev;
|
||||
priv->usb = dev;
|
||||
priv->netdev = netdev;
|
||||
priv->index = index;
|
||||
|
||||
@ -1013,12 +1008,12 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
|
||||
|
||||
priv->can.bittiming_const = &esd_usb2_bittiming_const;
|
||||
priv->can.do_set_bittiming = esd_usb2_set_bittiming;
|
||||
priv->can.do_set_mode = esd_usb2_set_mode;
|
||||
priv->can.do_get_berr_counter = esd_usb2_get_berr_counter;
|
||||
priv->can.do_set_mode = esd_usb_set_mode;
|
||||
priv->can.do_get_berr_counter = esd_usb_get_berr_counter;
|
||||
|
||||
netdev->flags |= IFF_ECHO; /* we support local echo */
|
||||
|
||||
netdev->netdev_ops = &esd_usb2_netdev_ops;
|
||||
netdev->netdev_ops = &esd_usb_netdev_ops;
|
||||
|
||||
SET_NETDEV_DEV(netdev, &intf->dev);
|
||||
netdev->dev_id = index;
|
||||
@ -1038,17 +1033,16 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* probe function for new USB2 devices
|
||||
/* probe function for new USB devices
|
||||
*
|
||||
* check version information and number of available
|
||||
* CAN interfaces
|
||||
*/
|
||||
static int esd_usb2_probe(struct usb_interface *intf,
|
||||
static int esd_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct esd_usb2 *dev;
|
||||
struct esd_usb2_msg *msg;
|
||||
struct esd_usb *dev;
|
||||
struct esd_usb_msg *msg;
|
||||
int i, err;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
@ -1076,13 +1070,13 @@ static int esd_usb2_probe(struct usb_interface *intf,
|
||||
msg->msg.version.flags = 0;
|
||||
msg->msg.version.drv_version = 0;
|
||||
|
||||
err = esd_usb2_send_msg(dev, msg);
|
||||
err = esd_usb_send_msg(dev, msg);
|
||||
if (err < 0) {
|
||||
dev_err(&intf->dev, "sending version message failed\n");
|
||||
goto free_msg;
|
||||
}
|
||||
|
||||
err = esd_usb2_wait_msg(dev, msg);
|
||||
err = esd_usb_wait_msg(dev, msg);
|
||||
if (err < 0) {
|
||||
dev_err(&intf->dev, "no version message answer\n");
|
||||
goto free_msg;
|
||||
@ -1105,7 +1099,7 @@ static int esd_usb2_probe(struct usb_interface *intf,
|
||||
|
||||
/* do per device probing */
|
||||
for (i = 0; i < dev->net_count; i++)
|
||||
esd_usb2_probe_one_net(intf, i);
|
||||
esd_usb_probe_one_net(intf, i);
|
||||
|
||||
free_msg:
|
||||
kfree(msg);
|
||||
@ -1115,12 +1109,10 @@ done:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* called by the usb core when the device is removed from the system
|
||||
*/
|
||||
static void esd_usb2_disconnect(struct usb_interface *intf)
|
||||
/* called by the usb core when the device is removed from the system */
|
||||
static void esd_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct esd_usb2 *dev = usb_get_intfdata(intf);
|
||||
struct esd_usb *dev = usb_get_intfdata(intf);
|
||||
struct net_device *netdev;
|
||||
int i;
|
||||
|
||||
@ -1144,11 +1136,11 @@ static void esd_usb2_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver esd_usb2_driver = {
|
||||
.name = "esd_usb2",
|
||||
.probe = esd_usb2_probe,
|
||||
.disconnect = esd_usb2_disconnect,
|
||||
.id_table = esd_usb2_table,
|
||||
static struct usb_driver esd_usb_driver = {
|
||||
.name = "esd_usb",
|
||||
.probe = esd_usb_probe,
|
||||
.disconnect = esd_usb_disconnect,
|
||||
.id_table = esd_usb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(esd_usb2_driver);
|
||||
module_usb_driver(esd_usb_driver);
|
@ -1707,7 +1707,7 @@ static int es58x_alloc_rx_urbs(struct es58x_device *es58x_dev)
|
||||
{
|
||||
const struct device *dev = es58x_dev->dev;
|
||||
const struct es58x_parameters *param = es58x_dev->param;
|
||||
size_t rx_buf_len = es58x_dev->rx_max_packet_size;
|
||||
u16 rx_buf_len = usb_maxpacket(es58x_dev->udev, es58x_dev->rx_pipe);
|
||||
struct urb *urb;
|
||||
u8 *buf;
|
||||
int i;
|
||||
@ -1739,7 +1739,7 @@ static int es58x_alloc_rx_urbs(struct es58x_device *es58x_dev)
|
||||
dev_err(dev, "%s: Could not setup any rx URBs\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
dev_dbg(dev, "%s: Allocated %d rx URBs each of size %zu\n",
|
||||
dev_dbg(dev, "%s: Allocated %d rx URBs each of size %u\n",
|
||||
__func__, i, rx_buf_len);
|
||||
|
||||
return ret;
|
||||
@ -2223,7 +2223,6 @@ static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf,
|
||||
ep_in->bEndpointAddress);
|
||||
es58x_dev->tx_pipe = usb_sndbulkpipe(es58x_dev->udev,
|
||||
ep_out->bEndpointAddress);
|
||||
es58x_dev->rx_max_packet_size = le16_to_cpu(ep_in->wMaxPacketSize);
|
||||
|
||||
return es58x_dev;
|
||||
}
|
||||
|
@ -380,7 +380,6 @@ struct es58x_operators {
|
||||
* @timestamps: a temporary buffer to store the time stamps before
|
||||
* feeding them to es58x_can_get_echo_skb(). Can only be used
|
||||
* in RX branches.
|
||||
* @rx_max_packet_size: Maximum length of bulk-in URB.
|
||||
* @num_can_ch: Number of CAN channel (i.e. number of elements of @netdev).
|
||||
* @opened_channel_cnt: number of channels opened. Free of race
|
||||
* conditions because its two users (net_device_ops:ndo_open()
|
||||
@ -401,8 +400,8 @@ struct es58x_device {
|
||||
const struct es58x_parameters *param;
|
||||
const struct es58x_operators *ops;
|
||||
|
||||
int rx_pipe;
|
||||
int tx_pipe;
|
||||
unsigned int rx_pipe;
|
||||
unsigned int tx_pipe;
|
||||
|
||||
struct usb_anchor rx_urbs;
|
||||
struct usb_anchor tx_urbs_busy;
|
||||
@ -414,7 +413,6 @@ struct es58x_device {
|
||||
|
||||
u64 timestamps[ES58X_ECHO_BULK_MAX];
|
||||
|
||||
u16 rx_max_packet_size;
|
||||
u8 num_can_ch;
|
||||
u8 opened_channel_cnt;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Xilinx CAN device driver
|
||||
*
|
||||
* Copyright (C) 2012 - 2014 Xilinx, Inc.
|
||||
* Copyright (C) 2012 - 2022 Xilinx, Inc.
|
||||
* Copyright (C) 2009 PetaLogix. All rights reserved.
|
||||
* Copyright (C) 2017 - 2018 Sandvik Mining and Construction Oy
|
||||
*
|
||||
@ -9,6 +9,7 @@
|
||||
* This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
@ -50,7 +51,7 @@ enum xcan_reg {
|
||||
|
||||
/* only on CAN FD cores */
|
||||
XCAN_F_BRPR_OFFSET = 0x088, /* Data Phase Baud Rate
|
||||
* Prescalar
|
||||
* Prescaler
|
||||
*/
|
||||
XCAN_F_BTR_OFFSET = 0x08C, /* Data Phase Bit Timing */
|
||||
XCAN_TRR_OFFSET = 0x0090, /* TX Buffer Ready Request */
|
||||
@ -86,6 +87,8 @@ enum xcan_reg {
|
||||
#define XCAN_MSR_LBACK_MASK 0x00000002 /* Loop back mode select */
|
||||
#define XCAN_MSR_SLEEP_MASK 0x00000001 /* Sleep mode select */
|
||||
#define XCAN_BRPR_BRP_MASK 0x000000FF /* Baud rate prescaler */
|
||||
#define XCAN_BRPR_TDCO_MASK GENMASK(12, 8) /* TDCO */
|
||||
#define XCAN_2_BRPR_TDCO_MASK GENMASK(13, 8) /* TDCO for CANFD 2.0 */
|
||||
#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */
|
||||
#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */
|
||||
#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */
|
||||
@ -99,6 +102,7 @@ enum xcan_reg {
|
||||
#define XCAN_ESR_STER_MASK 0x00000004 /* Stuff error */
|
||||
#define XCAN_ESR_FMER_MASK 0x00000002 /* Form error */
|
||||
#define XCAN_ESR_CRCER_MASK 0x00000001 /* CRC error */
|
||||
#define XCAN_SR_TDCV_MASK GENMASK(22, 16) /* TDCV Value */
|
||||
#define XCAN_SR_TXFLL_MASK 0x00000400 /* TX FIFO is full */
|
||||
#define XCAN_SR_ESTAT_MASK 0x00000180 /* Error status */
|
||||
#define XCAN_SR_ERRWRN_MASK 0x00000040 /* Error warning */
|
||||
@ -132,6 +136,7 @@ enum xcan_reg {
|
||||
#define XCAN_DLCR_BRS_MASK 0x04000000 /* BRS Mask in DLC */
|
||||
|
||||
/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
|
||||
#define XCAN_BRPR_TDC_ENABLE BIT(16) /* Transmitter Delay Compensation (TDC) Enable */
|
||||
#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */
|
||||
#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */
|
||||
#define XCAN_BTR_SJW_SHIFT_CANFD 16 /* Synchronous jump width */
|
||||
@ -276,6 +281,26 @@ static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
|
||||
.brp_inc = 1,
|
||||
};
|
||||
|
||||
/* Transmission Delay Compensation constants for CANFD 1.0 */
|
||||
static const struct can_tdc_const xcan_tdc_const_canfd = {
|
||||
.tdcv_min = 0,
|
||||
.tdcv_max = 0, /* Manual mode not supported. */
|
||||
.tdco_min = 0,
|
||||
.tdco_max = 32,
|
||||
.tdcf_min = 0, /* Filter window not supported */
|
||||
.tdcf_max = 0,
|
||||
};
|
||||
|
||||
/* Transmission Delay Compensation constants for CANFD 2.0 */
|
||||
static const struct can_tdc_const xcan_tdc_const_canfd2 = {
|
||||
.tdcv_min = 0,
|
||||
.tdcv_max = 0, /* Manual mode not supported. */
|
||||
.tdco_min = 0,
|
||||
.tdco_max = 64,
|
||||
.tdcf_min = 0, /* Filter window not supported */
|
||||
.tdcf_max = 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* xcan_write_reg_le - Write a value to the device register little endian
|
||||
* @priv: Driver private data structure
|
||||
@ -405,7 +430,7 @@ static int xcan_set_bittiming(struct net_device *ndev)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Setting Baud Rate prescalar value in BRPR Register */
|
||||
/* Setting Baud Rate prescaler value in BRPR Register */
|
||||
btr0 = (bt->brp - 1);
|
||||
|
||||
/* Setting Time Segment 1 in BTR Register */
|
||||
@ -422,8 +447,16 @@ static int xcan_set_bittiming(struct net_device *ndev)
|
||||
|
||||
if (priv->devtype.cantype == XAXI_CANFD ||
|
||||
priv->devtype.cantype == XAXI_CANFD_2_0) {
|
||||
/* Setting Baud Rate prescalar value in F_BRPR Register */
|
||||
/* Setting Baud Rate prescaler value in F_BRPR Register */
|
||||
btr0 = dbt->brp - 1;
|
||||
if (can_tdc_is_enabled(&priv->can)) {
|
||||
if (priv->devtype.cantype == XAXI_CANFD)
|
||||
btr0 |= FIELD_PREP(XCAN_BRPR_TDCO_MASK, priv->can.tdc.tdco) |
|
||||
XCAN_BRPR_TDC_ENABLE;
|
||||
else
|
||||
btr0 |= FIELD_PREP(XCAN_2_BRPR_TDCO_MASK, priv->can.tdc.tdco) |
|
||||
XCAN_BRPR_TDC_ENABLE;
|
||||
}
|
||||
|
||||
/* Setting Time Segment 1 in BTR Register */
|
||||
btr1 = dbt->prop_seg + dbt->phase_seg1 - 1;
|
||||
@ -1483,6 +1516,22 @@ static int xcan_get_berr_counter(const struct net_device *ndev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* xcan_get_auto_tdcv - Get Transmitter Delay Compensation Value
|
||||
* @ndev: Pointer to net_device structure
|
||||
* @tdcv: Pointer to TDCV value
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
static int xcan_get_auto_tdcv(const struct net_device *ndev, u32 *tdcv)
|
||||
{
|
||||
struct xcan_priv *priv = netdev_priv(ndev);
|
||||
|
||||
*tdcv = FIELD_GET(XCAN_SR_TDCV_MASK, priv->read_reg(priv, XCAN_SR_OFFSET));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct net_device_ops xcan_netdev_ops = {
|
||||
.ndo_open = xcan_open,
|
||||
.ndo_stop = xcan_close,
|
||||
@ -1735,17 +1784,24 @@ static int xcan_probe(struct platform_device *pdev)
|
||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_BERR_REPORTING;
|
||||
|
||||
if (devtype->cantype == XAXI_CANFD)
|
||||
if (devtype->cantype == XAXI_CANFD) {
|
||||
priv->can.data_bittiming_const =
|
||||
&xcan_data_bittiming_const_canfd;
|
||||
priv->can.tdc_const = &xcan_tdc_const_canfd;
|
||||
}
|
||||
|
||||
if (devtype->cantype == XAXI_CANFD_2_0)
|
||||
if (devtype->cantype == XAXI_CANFD_2_0) {
|
||||
priv->can.data_bittiming_const =
|
||||
&xcan_data_bittiming_const_canfd2;
|
||||
priv->can.tdc_const = &xcan_tdc_const_canfd2;
|
||||
}
|
||||
|
||||
if (devtype->cantype == XAXI_CANFD ||
|
||||
devtype->cantype == XAXI_CANFD_2_0)
|
||||
priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD;
|
||||
devtype->cantype == XAXI_CANFD_2_0) {
|
||||
priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_TDC_AUTO;
|
||||
priv->can.do_get_auto_tdcv = xcan_get_auto_tdcv;
|
||||
}
|
||||
|
||||
priv->reg_base = addr;
|
||||
priv->tx_max = tx_max;
|
||||
|
@ -31,6 +31,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
struct canfd_frame **cfd);
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev,
|
||||
struct can_frame **cf);
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);
|
||||
|
||||
/*
|
||||
* The struct can_skb_priv is used to transport additional information along
|
||||
@ -96,64 +97,6 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
|
||||
return nskb;
|
||||
}
|
||||
|
||||
/* Check for outgoing skbs that have not been created by the CAN subsystem */
|
||||
static inline bool can_skb_headroom_valid(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
|
||||
return false;
|
||||
|
||||
/* af_packet does not apply CAN skb specific settings */
|
||||
if (skb->ip_summed == CHECKSUM_NONE) {
|
||||
/* init headroom */
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
/* perform proper loopback on capable devices */
|
||||
if (dev->flags & IFF_ECHO)
|
||||
skb->pkt_type = PACKET_LOOPBACK;
|
||||
else
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
|
||||
static inline bool can_dropped_invalid_skb(struct net_device *dev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (skb->protocol == htons(ETH_P_CAN)) {
|
||||
if (unlikely(skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->protocol == htons(ETH_P_CANFD)) {
|
||||
if (unlikely(skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else
|
||||
goto inval_skb;
|
||||
|
||||
if (!can_skb_headroom_valid(dev, skb))
|
||||
goto inval_skb;
|
||||
|
||||
return false;
|
||||
|
||||
inval_skb:
|
||||
kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool can_is_canfd_skb(const struct sk_buff *skb)
|
||||
{
|
||||
/* the CAN specific type of skb is identified by its data length */
|
||||
|
@ -15,7 +15,8 @@ menuconfig CAN
|
||||
PF_CAN is contained in <Documentation/networking/can.rst>.
|
||||
|
||||
If you want CAN support you should say Y here and also to the
|
||||
specific driver for your controller(s) below.
|
||||
specific driver for your controller(s) under the Network device
|
||||
support section.
|
||||
|
||||
if CAN
|
||||
|
||||
@ -69,6 +70,4 @@ config CAN_ISOTP
|
||||
If you want to perform automotive vehicle diagnostic services (UDS),
|
||||
say 'y'.
|
||||
|
||||
source "drivers/net/can/Kconfig"
|
||||
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user