Merge tag 'linux-can-next-for-5.19-20220419' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
Marc Kleine-Budde says: ==================== pull-request: can-next 2022-04-19 this is a pull request of 17 patches for net-next/master. The first 2 patches are by me and target the CAN driver infrastructure. One patch renames a function in the rx_offload helper the other one updates the CAN bitrate calculation to prefer small bit rate pre-scalers over larger ones, which is encouraged by the CAN in Automation. Kris Bahnsen contributes a patch to fix the links to Technologic Systems web resources in the sja1000 driver. Christophe Leroy's patch prepares the mpc5xxx_can driver for upcoming powerpc header cleanup. Minghao Chi's patch converts the flexcan driver to use pm_runtime_resume_and_get(). The next 2 patches target the Xilinx CAN driver. Lukas Bulwahn's patch fixes an entry in the MAINTAINERS file. A patch by me marks the bit timing constants as const. Wolfram Sang's patch documents r8a77961 support on the renesas,rcar-canfd bindings document. The next 2 patches are by me and add support for the mcp251863 chip to the mcp251xfd driver. The last 7 patches are by Pavel Pisa, Martin Jerabek et al. and add the ctucanfd driver for the CTU CAN FD IP Core. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
63
Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml
Normal file
63
Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml
Normal file
@@ -0,0 +1,63 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/can/ctu,ctucanfd.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: CTU CAN FD Open-source IP Core Device Tree Bindings
|
||||
|
||||
description: |
|
||||
Open-source CAN FD IP core developed at the Czech Technical University in Prague
|
||||
|
||||
The core sources and documentation on project page
|
||||
[1] sources : https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core
|
||||
[2] datasheet : https://canbus.pages.fel.cvut.cz/ctucanfd_ip_core/doc/Datasheet.pdf
|
||||
|
||||
Integration in Xilinx Zynq SoC based system together with
|
||||
OpenCores SJA1000 compatible controllers
|
||||
[3] project : https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top
|
||||
Martin Jerabek dimploma thesis with integration and testing
|
||||
framework description
|
||||
[4] PDF : https://dspace.cvut.cz/bitstream/handle/10467/80366/F3-DP-2019-Jerabek-Martin-Jerabek-thesis-2019-canfd.pdf
|
||||
|
||||
maintainers:
|
||||
- Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
- Ondrej Ille <ondrej.ille@gmail.com>
|
||||
- Martin Jerabek <martin.jerabek01@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: ctu,ctucanfd-2
|
||||
- const: ctu,ctucanfd
|
||||
- const: ctu,ctucanfd
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: |
|
||||
phandle of reference clock (100 MHz is appropriate
|
||||
for FPGA implementation on Zynq-7000 system).
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
ctu_can_fd_0: can@43c30000 {
|
||||
compatible = "ctu,ctucanfd";
|
||||
interrupts = <0 30 4>;
|
||||
clocks = <&clkc 15>;
|
||||
reg = <0x43c30000 0x10000>;
|
||||
};
|
||||
@@ -5,8 +5,8 @@ $id: http://devicetree.org/schemas/net/can/microchip,mcp251xfd.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title:
|
||||
Microchip MCP2517FD and MCP2518FD stand-alone CAN controller device tree
|
||||
bindings
|
||||
Microchip MCP2517FD, MCP2518FD and MCP251863 stand-alone CAN
|
||||
controller device tree bindings
|
||||
|
||||
maintainers:
|
||||
- Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
@@ -17,13 +17,14 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: microchip,mcp2517fd
|
||||
description: for MCP2517FD
|
||||
- const: microchip,mcp2518fd
|
||||
description: for MCP2518FD
|
||||
- const: microchip,mcp251xfd
|
||||
description: to autodetect chip variant
|
||||
|
||||
- enum:
|
||||
- microchip,mcp2517fd
|
||||
- microchip,mcp2518fd
|
||||
- microchip,mcp251xfd
|
||||
- items:
|
||||
- enum:
|
||||
- microchip,mcp251863
|
||||
- const: microchip,mcp2518fd
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ properties:
|
||||
- renesas,r8a774e1-canfd # RZ/G2H
|
||||
- renesas,r8a7795-canfd # R-Car H3
|
||||
- renesas,r8a7796-canfd # R-Car M3-W
|
||||
- renesas,r8a77961-canfd # R-Car M3-W+
|
||||
- renesas,r8a77965-canfd # R-Car M3-N
|
||||
- renesas,r8a77970-canfd # R-Car V3M
|
||||
- renesas,r8a77980-canfd # R-Car V3H
|
||||
|
||||
@@ -283,6 +283,8 @@ patternProperties:
|
||||
description: Shenzen Chuangsiqi Technology Co.,Ltd.
|
||||
"^ctera,.*":
|
||||
description: CTERA Networks Intl.
|
||||
"^ctu,.*":
|
||||
description: Czech Technical University in Prague
|
||||
"^cubietech,.*":
|
||||
description: Cubietech, Ltd.
|
||||
"^cui,.*":
|
||||
|
||||
@@ -0,0 +1,639 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
CTU CAN FD Driver
|
||||
=================
|
||||
|
||||
Author: Martin Jerabek <martin.jerabek01@gmail.com>
|
||||
|
||||
|
||||
About CTU CAN FD IP Core
|
||||
------------------------
|
||||
|
||||
`CTU CAN FD <https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core>`_
|
||||
is an open source soft core written in VHDL.
|
||||
It originated in 2015 as Ondrej Ille's project
|
||||
at the `Department of Measurement <https://meas.fel.cvut.cz/>`_
|
||||
of `FEE <http://www.fel.cvut.cz/en/>`_ at `CTU <https://www.cvut.cz/en>`_.
|
||||
|
||||
The SocketCAN driver for Xilinx Zynq SoC based MicroZed board
|
||||
`Vivado integration <https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top>`_
|
||||
and Intel Cyclone V 5CSEMA4U23C6 based DE0-Nano-SoC Terasic board
|
||||
`QSys integration <https://gitlab.fel.cvut.cz/canbus/intel-soc-ctucanfd>`_
|
||||
has been developed as well as support for
|
||||
`PCIe integration <https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd>`_ of the core.
|
||||
|
||||
In the case of Zynq, the core is connected via the APB system bus, which does
|
||||
not have enumeration support, and the device must be specified in Device Tree.
|
||||
This kind of devices is called platform device in the kernel and is
|
||||
handled by a platform device driver.
|
||||
|
||||
The basic functional model of the CTU CAN FD peripheral has been
|
||||
accepted into QEMU mainline. See QEMU `CAN emulation support <https://www.qemu.org/docs/master/system/devices/can.html>`_
|
||||
for CAN FD buses, host connection and CTU CAN FD core emulation. The development
|
||||
version of emulation support can be cloned from ctu-canfd branch of QEMU local
|
||||
development `repository <https://gitlab.fel.cvut.cz/canbus/qemu-canbus>`_.
|
||||
|
||||
|
||||
About SocketCAN
|
||||
---------------
|
||||
|
||||
SocketCAN is a standard common interface for CAN devices in the Linux
|
||||
kernel. As the name suggests, the bus is accessed via sockets, similarly
|
||||
to common network devices. The reasoning behind this is in depth
|
||||
described in `Linux SocketCAN <https://www.kernel.org/doc/html/latest/networking/can.html>`_.
|
||||
In short, it offers a
|
||||
natural way to implement and work with higher layer protocols over CAN,
|
||||
in the same way as, e.g., UDP/IP over Ethernet.
|
||||
|
||||
Device probe
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Before going into detail about the structure of a CAN bus device driver,
|
||||
let's reiterate how the kernel gets to know about the device at all.
|
||||
Some buses, like PCI or PCIe, support device enumeration. That is, when
|
||||
the system boots, it discovers all the devices on the bus and reads
|
||||
their configuration. The kernel identifies the device via its vendor ID
|
||||
and device ID, and if there is a driver registered for this identifier
|
||||
combination, its probe method is invoked to populate the driver's
|
||||
instance for the given hardware. A similar situation goes with USB, only
|
||||
it allows for device hot-plug.
|
||||
|
||||
The situation is different for peripherals which are directly embedded
|
||||
in the SoC and connected to an internal system bus (AXI, APB, Avalon,
|
||||
and others). These buses do not support enumeration, and thus the kernel
|
||||
has to learn about the devices from elsewhere. This is exactly what the
|
||||
Device Tree was made for.
|
||||
|
||||
Device tree
|
||||
~~~~~~~~~~~
|
||||
|
||||
An entry in device tree states that a device exists in the system, how
|
||||
it is reachable (on which bus it resides) and its configuration –
|
||||
registers address, interrupts and so on. An example of such a device
|
||||
tree is given in .
|
||||
|
||||
.. code:: raw
|
||||
|
||||
/ {
|
||||
/* ... */
|
||||
amba: amba {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "simple-bus";
|
||||
|
||||
CTU_CAN_FD_0: CTU_CAN_FD@43c30000 {
|
||||
compatible = "ctu,ctucanfd";
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <0 30 4>;
|
||||
clocks = <&clkc 15>;
|
||||
reg = <0x43c30000 0x10000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
.. _sec:socketcan:drv:
|
||||
|
||||
Driver structure
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The driver can be divided into two parts – platform-dependent device
|
||||
discovery and set up, and platform-independent CAN network device
|
||||
implementation.
|
||||
|
||||
.. _sec:socketcan:platdev:
|
||||
|
||||
Platform device driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the case of Zynq, the core is connected via the AXI system bus, which
|
||||
does not have enumeration support, and the device must be specified in
|
||||
Device Tree. This kind of devices is called *platform device* in the
|
||||
kernel and is handled by a *platform device driver*\ [1]_.
|
||||
|
||||
A platform device driver provides the following things:
|
||||
|
||||
- A *probe* function
|
||||
|
||||
- A *remove* function
|
||||
|
||||
- A table of *compatible* devices that the driver can handle
|
||||
|
||||
The *probe* function is called exactly once when the device appears (or
|
||||
the driver is loaded, whichever happens later). If there are more
|
||||
devices handled by the same driver, the *probe* function is called for
|
||||
each one of them. Its role is to allocate and initialize resources
|
||||
required for handling the device, as well as set up low-level functions
|
||||
for the platform-independent layer, e.g., *read_reg* and *write_reg*.
|
||||
After that, the driver registers the device to a higher layer, in our
|
||||
case as a *network device*.
|
||||
|
||||
The *remove* function is called when the device disappears, or the
|
||||
driver is about to be unloaded. It serves to free the resources
|
||||
allocated in *probe* and to unregister the device from higher layers.
|
||||
|
||||
Finally, the table of *compatible* devices states which devices the
|
||||
driver can handle. The Device Tree entry ``compatible`` is matched
|
||||
against the tables of all *platform drivers*.
|
||||
|
||||
.. code:: c
|
||||
|
||||
/* Match table for OF platform binding */
|
||||
static const struct of_device_id ctucan_of_match[] = {
|
||||
{ .compatible = "ctu,canfd-2", },
|
||||
{ .compatible = "ctu,ctucanfd", },
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ctucan_of_match);
|
||||
|
||||
static int ctucan_probe(struct platform_device *pdev);
|
||||
static int ctucan_remove(struct platform_device *pdev);
|
||||
|
||||
static struct platform_driver ctucanfd_driver = {
|
||||
.probe = ctucan_probe,
|
||||
.remove = ctucan_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = ctucan_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ctucanfd_driver);
|
||||
|
||||
|
||||
.. _sec:socketcan:netdev:
|
||||
|
||||
Network device driver
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Each network device must support at least these operations:
|
||||
|
||||
- Bring the device up: ``ndo_open``
|
||||
|
||||
- Bring the device down: ``ndo_close``
|
||||
|
||||
- Submit TX frames to the device: ``ndo_start_xmit``
|
||||
|
||||
- Signal TX completion and errors to the network subsystem: ISR
|
||||
|
||||
- Submit RX frames to the network subsystem: ISR and NAPI
|
||||
|
||||
There are two possible event sources: the device and the network
|
||||
subsystem. Device events are usually signaled via an interrupt, handled
|
||||
in an Interrupt Service Routine (ISR). Handlers for the events
|
||||
originating in the network subsystem are then specified in
|
||||
``struct net_device_ops``.
|
||||
|
||||
When the device is brought up, e.g., by calling ``ip link set can0 up``,
|
||||
the driver’s function ``ndo_open`` is called. It should validate the
|
||||
interface configuration and configure and enable the device. The
|
||||
analogous opposite is ``ndo_close``, called when the device is being
|
||||
brought down, be it explicitly or implicitly.
|
||||
|
||||
When the system should transmit a frame, it does so by calling
|
||||
``ndo_start_xmit``, which enqueues the frame into the device. If the
|
||||
device HW queue (FIFO, mailboxes or whatever the implementation is)
|
||||
becomes full, the ``ndo_start_xmit`` implementation informs the network
|
||||
subsystem that it should stop the TX queue (via ``netif_stop_queue``).
|
||||
It is then re-enabled later in ISR when the device has some space
|
||||
available again and is able to enqueue another frame.
|
||||
|
||||
All the device events are handled in ISR, namely:
|
||||
|
||||
#. **TX completion**. When the device successfully finishes transmitting
|
||||
a frame, the frame is echoed locally. On error, an informative error
|
||||
frame [2]_ is sent to the network subsystem instead. In both cases,
|
||||
the software TX queue is resumed so that more frames may be sent.
|
||||
|
||||
#. **Error condition**. If something goes wrong (e.g., the device goes
|
||||
bus-off or RX overrun happens), error counters are updated, and
|
||||
informative error frames are enqueued to SW RX queue.
|
||||
|
||||
#. **RX buffer not empty**. In this case, read the RX frames and enqueue
|
||||
them to SW RX queue. Usually NAPI is used as a middle layer (see ).
|
||||
|
||||
.. _sec:socketcan:napi:
|
||||
|
||||
NAPI
|
||||
~~~~
|
||||
|
||||
The frequency of incoming frames can be high and the overhead to invoke
|
||||
the interrupt service routine for each frame can cause significant
|
||||
system load. There are multiple mechanisms in the Linux kernel to deal
|
||||
with this situation. They evolved over the years of Linux kernel
|
||||
development and enhancements. For network devices, the current standard
|
||||
is NAPI – *the New API*. It is similar to classical top-half/bottom-half
|
||||
interrupt handling in that it only acknowledges the interrupt in the ISR
|
||||
and signals that the rest of the processing should be done in softirq
|
||||
context. On top of that, it offers the possibility to *poll* for new
|
||||
frames for a while. This has a potential to avoid the costly round of
|
||||
enabling interrupts, handling an incoming IRQ in ISR, re-enabling the
|
||||
softirq and switching context back to softirq.
|
||||
|
||||
More detailed documentation of NAPI may be found on the pages of Linux
|
||||
Foundation `<https://wiki.linuxfoundation.org/networking/napi>`_.
|
||||
|
||||
Integrating the core to Xilinx Zynq
|
||||
-----------------------------------
|
||||
|
||||
The core interfaces a simple subset of the Avalon
|
||||
(search for Intel **Avalon Interface Specifications**)
|
||||
bus as it was originally used on
|
||||
Alterra FPGA chips, yet Xilinx natively interfaces with AXI
|
||||
(search for ARM **AMBA AXI and ACE Protocol Specification AXI3,
|
||||
AXI4, and AXI4-Lite, ACE and ACE-Lite**).
|
||||
The most obvious solution would be to use
|
||||
an Avalon/AXI bridge or implement some simple conversion entity.
|
||||
However, the core’s interface is half-duplex with no handshake
|
||||
signaling, whereas AXI is full duplex with two-way signaling. Moreover,
|
||||
even AXI-Lite slave interface is quite resource-intensive, and the
|
||||
flexibility and speed of AXI are not required for a CAN core.
|
||||
|
||||
Thus a much simpler bus was chosen – APB (Advanced Peripheral Bus)
|
||||
(search for ARM **AMBA APB Protocol Specification**).
|
||||
APB-AXI bridge is directly available in
|
||||
Xilinx Vivado, and the interface adaptor entity is just a few simple
|
||||
combinatorial assignments.
|
||||
|
||||
Finally, to be able to include the core in a block diagram as a custom
|
||||
IP, the core, together with the APB interface, has been packaged as a
|
||||
Vivado component.
|
||||
|
||||
CTU CAN FD Driver design
|
||||
------------------------
|
||||
|
||||
The general structure of a CAN device driver has already been examined
|
||||
in . The next paragraphs provide a more detailed description of the CTU
|
||||
CAN FD core driver in particular.
|
||||
|
||||
Low-level driver
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The core is not intended to be used solely with SocketCAN, and thus it
|
||||
is desirable to have an OS-independent low-level driver. This low-level
|
||||
driver can then be used in implementations of OS driver or directly
|
||||
either on bare metal or in a user-space application. Another advantage
|
||||
is that if the hardware slightly changes, only the low-level driver
|
||||
needs to be modified.
|
||||
|
||||
The code [3]_ is in part automatically generated and in part written
|
||||
manually by the core author, with contributions of the thesis’ author.
|
||||
The low-level driver supports operations such as: set bit timing, set
|
||||
controller mode, enable/disable, read RX frame, write TX frame, and so
|
||||
on.
|
||||
|
||||
Configuring bit timing
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
On CAN, each bit is divided into four segments: SYNC, PROP, PHASE1, and
|
||||
PHASE2. Their duration is expressed in multiples of a Time Quantum
|
||||
(details in `CAN Specification, Version 2.0 <http://esd.cs.ucr.edu/webres/can20.pdf>`_, chapter 8).
|
||||
When configuring
|
||||
bitrate, the durations of all the segments (and time quantum) must be
|
||||
computed from the bitrate and Sample Point. This is performed
|
||||
independently for both the Nominal bitrate and Data bitrate for CAN FD.
|
||||
|
||||
SocketCAN is fairly flexible and offers either highly customized
|
||||
configuration by setting all the segment durations manually, or a
|
||||
convenient configuration by setting just the bitrate and sample point
|
||||
(and even that is chosen automatically per Bosch recommendation if not
|
||||
specified). However, each CAN controller may have different base clock
|
||||
frequency and different width of segment duration registers. The
|
||||
algorithm thus needs the minimum and maximum values for the durations
|
||||
(and clock prescaler) and tries to optimize the numbers to fit both the
|
||||
constraints and the requested parameters.
|
||||
|
||||
.. code:: c
|
||||
|
||||
struct can_bittiming_const {
|
||||
char name[16]; /* Name of the CAN controller hardware */
|
||||
__u32 tseg1_min; /* Time segment 1 = prop_seg + phase_seg1 */
|
||||
__u32 tseg1_max;
|
||||
__u32 tseg2_min; /* Time segment 2 = phase_seg2 */
|
||||
__u32 tseg2_max;
|
||||
__u32 sjw_max; /* Synchronisation jump width */
|
||||
__u32 brp_min; /* Bit-rate prescaler */
|
||||
__u32 brp_max;
|
||||
__u32 brp_inc;
|
||||
};
|
||||
|
||||
|
||||
[lst:can_bittiming_const]
|
||||
|
||||
A curious reader will notice that the durations of the segments PROP_SEG
|
||||
and PHASE_SEG1 are not determined separately but rather combined and
|
||||
then, by default, the resulting TSEG1 is evenly divided between PROP_SEG
|
||||
and PHASE_SEG1. In practice, this has virtually no consequences as the
|
||||
sample point is between PHASE_SEG1 and PHASE_SEG2. In CTU CAN FD,
|
||||
however, the duration registers ``PROP`` and ``PH1`` have different
|
||||
widths (6 and 7 bits, respectively), so the auto-computed values might
|
||||
overflow the shorter register and must thus be redistributed among the
|
||||
two [4]_.
|
||||
|
||||
Handling RX
|
||||
~~~~~~~~~~~
|
||||
|
||||
Frame reception is handled in NAPI queue, which is enabled from ISR when
|
||||
the RXNE (RX FIFO Not Empty) bit is set. Frames are read one by one
|
||||
until either no frame is left in the RX FIFO or the maximum work quota
|
||||
has been reached for the NAPI poll run (see ). Each frame is then passed
|
||||
to the network interface RX queue.
|
||||
|
||||
An incoming frame may be either a CAN 2.0 frame or a CAN FD frame. The
|
||||
way to distinguish between these two in the kernel is to allocate either
|
||||
``struct can_frame`` or ``struct canfd_frame``, the two having different
|
||||
sizes. In the controller, the information about the frame type is stored
|
||||
in the first word of RX FIFO.
|
||||
|
||||
This brings us a chicken-egg problem: we want to allocate the ``skb``
|
||||
for the frame, and only if it succeeds, fetch the frame from FIFO;
|
||||
otherwise keep it there for later. But to be able to allocate the
|
||||
correct ``skb``, we have to fetch the first work of FIFO. There are
|
||||
several possible solutions:
|
||||
|
||||
#. Read the word, then allocate. If it fails, discard the rest of the
|
||||
frame. When the system is low on memory, the situation is bad anyway.
|
||||
|
||||
#. Always allocate ``skb`` big enough for an FD frame beforehand. Then
|
||||
tweak the ``skb`` internals to look like it has been allocated for
|
||||
the smaller CAN 2.0 frame.
|
||||
|
||||
#. Add option to peek into the FIFO instead of consuming the word.
|
||||
|
||||
#. If the allocation fails, store the read word into driver’s data. On
|
||||
the next try, use the stored word instead of reading it again.
|
||||
|
||||
Option 1 is simple enough, but not very satisfying if we could do
|
||||
better. Option 2 is not acceptable, as it would require modifying the
|
||||
private state of an integral kernel structure. The slightly higher
|
||||
memory consumption is just a virtual cherry on top of the “cake”. Option
|
||||
3 requires non-trivial HW changes and is not ideal from the HW point of
|
||||
view.
|
||||
|
||||
Option 4 seems like a good compromise, with its disadvantage being that
|
||||
a partial frame may stay in the FIFO for a prolonged time. Nonetheless,
|
||||
there may be just one owner of the RX FIFO, and thus no one else should
|
||||
see the partial frame (disregarding some exotic debugging scenarios).
|
||||
Basides, the driver resets the core on its initialization, so the
|
||||
partial frame cannot be “adopted” either. In the end, option 4 was
|
||||
selected [5]_.
|
||||
|
||||
.. _subsec:ctucanfd:rxtimestamp:
|
||||
|
||||
Timestamping RX frames
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The CTU CAN FD core reports the exact timestamp when the frame has been
|
||||
received. The timestamp is by default captured at the sample point of
|
||||
the last bit of EOF but is configurable to be captured at the SOF bit.
|
||||
The timestamp source is external to the core and may be up to 64 bits
|
||||
wide. At the time of writing, passing the timestamp from kernel to
|
||||
userspace is not yet implemented, but is planned in the future.
|
||||
|
||||
Handling TX
|
||||
~~~~~~~~~~~
|
||||
|
||||
The CTU CAN FD core has 4 independent TX buffers, each with its own
|
||||
state and priority. When the core wants to transmit, a TX buffer in
|
||||
Ready state with the highest priority is selected.
|
||||
|
||||
The priorities are 3bit numbers in register TX_PRIORITY
|
||||
(nibble-aligned). This should be flexible enough for most use cases.
|
||||
SocketCAN, however, supports only one FIFO queue for outgoing
|
||||
frames [6]_. The buffer priorities may be used to simulate the FIFO
|
||||
behavior by assigning each buffer a distinct priority and *rotating* the
|
||||
priorities after a frame transmission is completed.
|
||||
|
||||
In addition to priority rotation, the SW must maintain head and tail
|
||||
pointers into the FIFO formed by the TX buffers to be able to determine
|
||||
which buffer should be used for next frame (``txb_head``) and which
|
||||
should be the first completed one (``txb_tail``). The actual buffer
|
||||
indices are (obviously) modulo 4 (number of TX buffers), but the
|
||||
pointers must be at least one bit wider to be able to distinguish
|
||||
between FIFO full and FIFO empty – in this situation,
|
||||
:math:`txb\_head \equiv txb\_tail\ (\textrm{mod}\ 4)`. An example of how
|
||||
the FIFO is maintained, together with priority rotation, is depicted in
|
||||
|
||||
|
|
||||
|
||||
+------+---+---+---+---+
|
||||
| TXB# | 0 | 1 | 2 | 3 |
|
||||
+======+===+===+===+===+
|
||||
| Seq | A | B | C | |
|
||||
+------+---+---+---+---+
|
||||
| Prio | 7 | 6 | 5 | 4 |
|
||||
+------+---+---+---+---+
|
||||
| | | T | | H |
|
||||
+------+---+---+---+---+
|
||||
|
||||
|
|
||||
|
||||
+------+---+---+---+---+
|
||||
| TXB# | 0 | 1 | 2 | 3 |
|
||||
+======+===+===+===+===+
|
||||
| Seq | | B | C | |
|
||||
+------+---+---+---+---+
|
||||
| Prio | 4 | 7 | 6 | 5 |
|
||||
+------+---+---+---+---+
|
||||
| | | T | | H |
|
||||
+------+---+---+---+---+
|
||||
|
||||
|
|
||||
|
||||
+------+---+---+---+---+----+
|
||||
| TXB# | 0 | 1 | 2 | 3 | 0’ |
|
||||
+======+===+===+===+===+====+
|
||||
| Seq | E | B | C | D | |
|
||||
+------+---+---+---+---+----+
|
||||
| Prio | 4 | 7 | 6 | 5 | |
|
||||
+------+---+---+---+---+----+
|
||||
| | | T | | | H |
|
||||
+------+---+---+---+---+----+
|
||||
|
||||
|
|
||||
|
||||
.. figure:: fsm_txt_buffer_user.svg
|
||||
|
||||
TX Buffer states with possible transitions
|
||||
|
||||
.. _subsec:ctucanfd:txtimestamp:
|
||||
|
||||
Timestamping TX frames
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When submitting a frame to a TX buffer, one may specify the timestamp at
|
||||
which the frame should be transmitted. The frame transmission may start
|
||||
later, but not sooner. Note that the timestamp does not participate in
|
||||
buffer prioritization – that is decided solely by the mechanism
|
||||
described above.
|
||||
|
||||
Support for time-based packet transmission was recently merged to Linux
|
||||
v4.19 `Time-based packet transmission <https://lwn.net/Articles/748879/>`_,
|
||||
but it remains yet to be researched
|
||||
whether this functionality will be practical for CAN.
|
||||
|
||||
Also similarly to retrieving the timestamp of RX frames, the core
|
||||
supports retrieving the timestamp of TX frames – that is the time when
|
||||
the frame was successfully delivered. The particulars are very similar
|
||||
to timestamping RX frames and are described in .
|
||||
|
||||
Handling RX buffer overrun
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When a received frame does no more fit into the hardware RX FIFO in its
|
||||
entirety, RX FIFO overrun flag (STATUS[DOR]) is set and Data Overrun
|
||||
Interrupt (DOI) is triggered. When servicing the interrupt, care must be
|
||||
taken first to clear the DOR flag (via COMMAND[CDO]) and after that
|
||||
clear the DOI interrupt flag. Otherwise, the interrupt would be
|
||||
immediately [7]_ rearmed.
|
||||
|
||||
**Note**: During development, it was discussed whether the internal HW
|
||||
pipelining cannot disrupt this clear sequence and whether an additional
|
||||
dummy cycle is necessary between clearing the flag and the interrupt. On
|
||||
the Avalon interface, it indeed proved to be the case, but APB being
|
||||
safe because it uses 2-cycle transactions. Essentially, the DOR flag
|
||||
would be cleared, but DOI register’s Preset input would still be high
|
||||
the cycle when the DOI clear request would also be applied (by setting
|
||||
the register’s Reset input high). As Set had higher priority than Reset,
|
||||
the DOI flag would not be reset. This has been already fixed by swapping
|
||||
the Set/Reset priority (see issue #187).
|
||||
|
||||
Reporting Error Passive and Bus Off conditions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It may be desirable to report when the node reaches *Error Passive*,
|
||||
*Error Warning*, and *Bus Off* conditions. The driver is notified about
|
||||
error state change by an interrupt (EPI, EWLI), and then proceeds to
|
||||
determine the core’s error state by reading its error counters.
|
||||
|
||||
There is, however, a slight race condition here – there is a delay
|
||||
between the time when the state transition occurs (and the interrupt is
|
||||
triggered) and when the error counters are read. When EPI is received,
|
||||
the node may be either *Error Passive* or *Bus Off*. If the node goes
|
||||
*Bus Off*, it obviously remains in the state until it is reset.
|
||||
Otherwise, the node is *or was* *Error Passive*. However, it may happen
|
||||
that the read state is *Error Warning* or even *Error Active*. It may be
|
||||
unclear whether and what exactly to report in that case, but I
|
||||
personally entertain the idea that the past error condition should still
|
||||
be reported. Similarly, when EWLI is received but the state is later
|
||||
detected to be *Error Passive*, *Error Passive* should be reported.
|
||||
|
||||
|
||||
CTU CAN FD Driver Sources Reference
|
||||
-----------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/net/can/ctucanfd/ctucanfd.h
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/net/can/ctucanfd/ctucanfd_base.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/net/can/ctucanfd/ctucanfd_pci.c
|
||||
:internal:
|
||||
|
||||
.. kernel-doc:: drivers/net/can/ctucanfd/ctucanfd_platform.c
|
||||
:internal:
|
||||
|
||||
CTU CAN FD IP Core and Driver Development Acknowledgment
|
||||
---------------------------------------------------------
|
||||
|
||||
* Odrej Ille <illeondr@fel.cvut.cz>
|
||||
|
||||
* started the project as student at Department of Measurement, FEE, CTU
|
||||
* invested great amount of personal time and enthusiasm to the project over years
|
||||
* worked on more funded tasks
|
||||
|
||||
* `Department of Measurement <https://meas.fel.cvut.cz/>`_,
|
||||
`Faculty of Electrical Engineering <http://www.fel.cvut.cz/en/>`_,
|
||||
`Czech Technical University <https://www.cvut.cz/en>`_
|
||||
|
||||
* is the main investor into the project over many years
|
||||
* uses project in their CAN/CAN FD diagnostics framework for `Skoda Auto <https://www.skoda-auto.cz/>`_
|
||||
|
||||
* `Digiteq Automotive <https://www.digiteqautomotive.com/en>`_
|
||||
|
||||
* funding of the project CAN FD Open Cores Support Linux Kernel Based Systems
|
||||
* negotiated and paid CTU to allow public access to the project
|
||||
* provided additional funding of the work
|
||||
|
||||
* `Department of Control Engineering <https://control.fel.cvut.cz/en>`_,
|
||||
`Faculty of Electrical Engineering <http://www.fel.cvut.cz/en/>`_,
|
||||
`Czech Technical University <https://www.cvut.cz/en>`_
|
||||
|
||||
* solving the project CAN FD Open Cores Support Linux Kernel Based Systems
|
||||
* providing GitLab management
|
||||
* virtual servers and computational power for continuous integration
|
||||
* providing hardware for HIL continuous integration tests
|
||||
|
||||
* `PiKRON Ltd. <http://pikron.com/>`_
|
||||
|
||||
* minor funding to initiate preparation of the project open-sourcing
|
||||
|
||||
* Petr Porazil <porazil@pikron.com>
|
||||
|
||||
* design of PCIe transceiver addon board and assembly of boards
|
||||
* design and assembly of MZ_APO baseboard for MicroZed/Zynq based system
|
||||
|
||||
* Martin Jerabek <martin.jerabek01@gmail.com>
|
||||
|
||||
* Linux driver development
|
||||
* continuous integration platform architect and GHDL updates
|
||||
* theses `Open-source and Open-hardware CAN FD Protocol Support <https://dspace.cvut.cz/bitstream/handle/10467/80366/F3-DP-2019-Jerabek-Martin-Jerabek-thesis-2019-canfd.pdf>`_
|
||||
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
|
||||
* project initiation, management and use at Department of Measurement, FEE, CTU
|
||||
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
|
||||
* initiate open-sourcing, project coordination, management at Department of Control Engineering, FEE, CTU
|
||||
|
||||
* Jaroslav Beran<jara.beran@gmail.com>
|
||||
|
||||
* system integration for Intel SoC, core and driver testing and updates
|
||||
|
||||
* Carsten Emde (`OSADL <https://www.osadl.org/>`_)
|
||||
|
||||
* provided OSADL expertise to discuss IP core licensing
|
||||
* pointed to possible deadlock for LGPL and CAN bus possible patent case which lead to relicense IP core design to BSD like license
|
||||
|
||||
* Reiner Zitzmann and Holger Zeltwanger (`CAN in Automation <https://www.can-cia.org/>`_)
|
||||
|
||||
* provided suggestions and help to inform community about the project and invited us to events focused on CAN bus future development directions
|
||||
|
||||
* Jan Charvat
|
||||
|
||||
* implemented CTU CAN FD functional model for QEMU which has been integrated into QEMU mainline (`docs/system/devices/can.rst <https://www.qemu.org/docs/master/system/devices/can.html>`_)
|
||||
* Bachelor theses Model of CAN FD Communication Controller for QEMU Emulator
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
|
||||
.. [1]
|
||||
Other buses have their own specific driver interface to set up the
|
||||
device.
|
||||
|
||||
.. [2]
|
||||
Not to be mistaken with CAN Error Frame. This is a ``can_frame`` with
|
||||
``CAN_ERR_FLAG`` set and some error info in its ``data`` field.
|
||||
|
||||
.. [3]
|
||||
Available in CTU CAN FD repository
|
||||
`<https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core>`_
|
||||
|
||||
.. [4]
|
||||
As is done in the low-level driver functions
|
||||
``ctucan_hw_set_nom_bittiming`` and
|
||||
``ctucan_hw_set_data_bittiming``.
|
||||
|
||||
.. [5]
|
||||
At the time of writing this thesis, option 1 is still being used and
|
||||
the modification is queued in gitlab issue #222
|
||||
|
||||
.. [6]
|
||||
Strictly speaking, multiple CAN TX queues are supported since v4.19
|
||||
`can: enable multi-queue for SocketCAN devices <https://lore.kernel.org/patchwork/patch/913526/>`_ but no mainline driver is using
|
||||
them yet.
|
||||
|
||||
.. [7]
|
||||
Or rather in the next clock cycle
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="113.611mm" height="86.6873mm" version="1.1" viewBox="0 0 113.611 86.6873" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<defs>
|
||||
<marker id="marker3667" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill="#28a4ff" fill-rule="evenodd" stroke="#28a4ff" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker3517" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker3373" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker3199" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill="#28a4ff" fill-rule="evenodd" stroke="#28a4ff" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker3037" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill="#28a4ff" fill-rule="evenodd" stroke="#28a4ff" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker2779" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill="#28a4ff" fill-rule="evenodd" stroke="#28a4ff" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker2477" overflow="visible" orient="auto">
|
||||
<path transform="scale(.6) rotate(180) translate(0)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill="#28a4ff" fill-rule="evenodd" stroke="#28a4ff" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker2074" overflow="visible" orient="auto">
|
||||
<path transform="scale(.6) rotate(180) translate(0)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker1964" overflow="visible" orient="auto">
|
||||
<path transform="scale(.6) rotate(180) translate(0)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="marker1856" overflow="visible" orient="auto">
|
||||
<path transform="scale(.6) rotate(180) translate(0)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<marker id="Arrow2Mend" overflow="visible" orient="auto">
|
||||
<path transform="scale(.6) rotate(180) translate(0)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<filter id="filter1204" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<marker id="marker2074-3" overflow="visible" orient="auto">
|
||||
<path transform="scale(-.6)" d="m8.71859 4.03374-10.9259-4.01772 10.9259-4.01772c-1.7455 2.37206-1.73544 5.61745-6e-7 8.03544z" fill="#28a4ff" fill-rule="evenodd" stroke="#28a4ff" stroke-linejoin="round" stroke-width=".625"/>
|
||||
</marker>
|
||||
<filter id="filter1204-6" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-9" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-2" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-2-9" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-2-9-4" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-2-9-1" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-2-9-1-3" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
<filter id="filter1204-6-2-9-1-3-1" x="-4.19953e-6" y="-5.60084e-6" width="1.00001" height="1.00001" color-interpolation-filters="sRGB">
|
||||
<feGaussianBlur stdDeviation="0.00018829868"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(-49.0277 -104.823)">
|
||||
<g>
|
||||
<path d="m130.534 165.429h-71.1816v-17.5315" fill="none" marker-end="url(#marker2477)" stroke="#28a4ff" stroke-width=".6"/>
|
||||
<path d="m145.034 122.959v-11.5914h-43.1215" fill="none" marker-end="url(#marker3037)" stroke="#28a4ff" stroke-width=".6"/>
|
||||
<rect x="130.679" y="122.933" width="28.2965" height="45.2319" rx="0" ry="0" fill="#e5e5e5" stroke="#717171" stroke-linecap="square" stroke-width=".499999"/>
|
||||
<path d="m102.044 116.236h23.3126l-0.13388 18.8185h19.9383v3.66603" fill="none" marker-end="url(#marker3199)" stroke="#28a4ff" stroke-width=".6"/>
|
||||
<path d="m59.5006 138.391v-24.2517h20.6338" fill="none" marker-end="url(#marker2779)" stroke="#28a4ff" stroke-width=".6"/>
|
||||
<rect x="78.1389" y="126.411" width="28.0037" height="35.0443" rx="0" ry="0" fill="#e5e5e5" stroke="#717171" stroke-linecap="square" stroke-width=".5"/>
|
||||
</g>
|
||||
<g fill="#ffcb35" stroke="#000" stroke-linecap="square">
|
||||
<ellipse cx="92.1408" cy="114.239" rx="10.8866" ry="4.39308" stroke-width=".5"/>
|
||||
<ellipse cx="92.1408" cy="134.185" rx="10.8866" ry="4.39308" stroke-width=".499999"/>
|
||||
<ellipse cx="92.1408" cy="152.199" rx="10.8866" ry="4.39308" stroke-width=".499999"/>
|
||||
</g>
|
||||
<g fill="#28a4ff" stroke="#000" stroke-linecap="square" stroke-width=".499999">
|
||||
<ellipse cx="144.827" cy="143.316" rx="10.8866" ry="4.39308"/>
|
||||
<ellipse cx="144.827" cy="159.143" rx="10.8866" ry="4.39308"/>
|
||||
<ellipse cx="59.4364" cy="142.823" rx="7.36455" ry="4.39308"/>
|
||||
<ellipse cx="144.827" cy="129.196" rx="10.8866" ry="4.39308"/>
|
||||
<ellipse cx="143.077" cy="180.53" rx="10.8866" ry="4.39308"/>
|
||||
</g>
|
||||
<ellipse cx="110.386" cy="180.53" rx="10.8866" ry="4.39308" fill="#ffcb35" stroke="#000" stroke-linecap="square" stroke-width=".499999"/>
|
||||
<text x="110.90907" y="179.42688" font-size="3.175px" xml:space="preserve"><tspan x="110.90907" y="179.42688" dy="0.60000002" text-align="center" text-anchor="middle">Accessible</tspan><tspan x="110.90907" y="183.39563"><tspan font-size="3.175px" text-align="center" text-anchor="middle">for S</tspan>W</tspan></text>
|
||||
<text x="143.5869" y="179.52795" xml:space="preserve"><tspan x="143.5869" y="179.52795" dy="1 0 0 0 0 0" font-family="sans-serif" font-size="2.82222px" text-align="center" text-anchor="middle" style="font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal">Inaccessible</tspan><tspan x="143.5869" y="183.36786" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">for S</tspan>W</tspan></text>
|
||||
<g font-size="3.175px">
|
||||
<text x="91.95018" y="115.29005" xml:space="preserve"><tspan x="91.95018" y="115.29005" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">Ready</tspan></tspan></text>
|
||||
<text x="145.25127" y="130.49019" xml:space="preserve"><tspan x="145.25127" y="130.49019" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">TX OK</tspan></tspan></text>
|
||||
<text x="145.31845" y="144.43121" xml:space="preserve"><tspan x="145.31845" y="144.43121" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">Aborted</tspan></tspan></text>
|
||||
<text x="145.40399" y="160.36035" xml:space="preserve"><tspan x="145.40399" y="160.36035" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">TX failed</tspan></tspan></text>
|
||||
<text x="91.823967" y="133.53941" text-align="center" text-anchor="middle" style="line-height:0.9" xml:space="preserve"><tspan x="91.823967" y="133.53941" text-align="center"><tspan font-size="3.175px" text-align="center" text-anchor="middle">TX in</tspan></tspan><tspan x="91.823967" y="136.39691" text-align="center">progress</tspan></text>
|
||||
<text x="91.648918" y="151.84813" text-align="center" text-anchor="middle" style="line-height:0.9" xml:space="preserve"><tspan x="91.648918" y="151.84813" text-align="center"><tspan font-size="3.175px" text-align="center" text-anchor="middle">Abort in</tspan></tspan><tspan x="91.648918" y="154.70563" text-align="center">progress</tspan></text>
|
||||
<text x="59.456043" y="143.91658" xml:space="preserve"><tspan x="59.456043" y="143.91658" font-size="3.175px"><tspan font-size="3.175px" text-align="center" text-anchor="middle">Empty</tspan></tspan></text>
|
||||
</g>
|
||||
<g fill="none">
|
||||
<g stroke="#000">
|
||||
<rect x="52.3943" y="171.63" width="106.581" height="16.601" rx="0" ry="0" stroke-linecap="square" stroke-width=".499999"/>
|
||||
<g stroke-width=".6">
|
||||
<path d="m106.383 159.046h26.4967" marker-end="url(#Arrow2Mend)"/>
|
||||
<path d="m103.138 152.268h41.5564v-3.92426" marker-end="url(#marker1856)"/>
|
||||
<path d="m106.38 129.354h17.7785"/>
|
||||
<path d="m125.818 129.359h7.2418" marker-end="url(#marker1964)"/>
|
||||
</g>
|
||||
<path d="m124.169 129.354a0.959514 0.97091 0 0 1 0.47587-0.84557 0.959514 0.97091 0 0 1 0.96164-3e-3 0.959514 0.97091 0 0 1 0.48149 0.84231" stroke-linecap="square" stroke-width=".600001"/>
|
||||
<path d="m55.7026 180.832h34.8131" marker-end="url(#marker2074)" stroke-width=".6"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="m55.6464 185.744h34.8131" marker-end="url(#marker2074-3)" stroke="#28a4ff" stroke-width=".600001"/>
|
||||
<g stroke-width=".6">
|
||||
<path d="m94.0487 129.889v-10.6493" marker-end="url(#marker3373)" stroke="#000"/>
|
||||
<path d="m89.7534 118.621v10.662" marker-end="url(#marker3517)" stroke="#000"/>
|
||||
<path d="m92.119 138.812v7.9718" marker-end="url(#marker3667)" stroke="#28a4ff"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<text transform="matrix(.264583 0 0 .264583 91.8919 139.964)" x="26.959213" y="9.11724" fill="#2aa1ff" filter="url(#filter1204-6-2-9-1-3-1)" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle" style="line-height:1.1" xml:space="preserve"><tspan x="26.959213" y="9.11724" text-align="center">Set</tspan><tspan x="26.959213" y="22.31724" text-align="center">abort</tspan></text>
|
||||
<text transform="translate(49.0277 104.823)" x="57.620724" y="16.855087" filter="url(#filter1204)" font-size="3.175px" text-align="center" text-anchor="middle" style="line-height:1.1" xml:space="preserve"><tspan x="57.620724" y="16.855087" text-align="center">Transmission</tspan><tspan x="57.620724" y="20.347588" text-align="center">unsuccesfull</tspan></text>
|
||||
<g font-size="12px" stroke-width="3.77953" text-anchor="middle">
|
||||
<text transform="matrix(.264583 0 0 .264583 68.5988 118.913)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">starts</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 106.802 130.509)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">succesfull</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 107.77 145.476)" x="38.824219" y="9.1171875" filter="url(#filter1204)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Transmission</tspan><tspan x="38.824219" y="22.317188" text-align="center">sborted</tspan></text>
|
||||
</g>
|
||||
<g stroke-width="3.77953" text-anchor="middle">
|
||||
<text transform="matrix(.264583 0 0 .264583 107.574 155.948)" x="38.824219" y="9.1171875" filter="url(#filter1204)" font-size="10.6667px" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824219" y="9.1171875" text-align="center">Retransmit</tspan><tspan x="38.824219" y="20.850557" text-align="center">limit reached or</tspan><tspan x="38.824219" y="32.583927" text-align="center">node went bus off</tspan><tspan x="38.824219" y="44.317299" text-align="center"/></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 60.7127 177.384)" x="38.824539" y="9.1173134" filter="url(#filter1204-6)" font-size="12px" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="38.824539" y="9.1173134" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">Transmission result</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 45.6885 173.226)" x="57.727047" y="9.11724" filter="url(#filter1204-6-9)" font-size="12px" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="57.727047" y="9.11724" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">Legend:</tspan></text>
|
||||
</g>
|
||||
<g fill="#2aa1ff" font-size="12px" stroke-width="3.77953" text-anchor="middle">
|
||||
<text transform="matrix(.264583 0 0 .264583 57.0045 182.079)" x="57.727047" y="9.11724" filter="url(#filter1204-6-2)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="57.727047" y="9.11724" fill="#2aa1ff" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">SW command</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 57.7865 110.104)" x="40.822609" y="9.11724" filter="url(#filter1204-6-2-9)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="40.822609" y="9.11724" fill="#2aa1ff" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">Set ready</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 116.893 107.491)" x="28.049065" y="9.1172523" filter="url(#filter1204-6-2-9-4)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="28.049065" y="9.1172523" fill="#2aa1ff" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">Set ready</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 87.5687 166.324)" x="28.049065" y="9.1172523" filter="url(#filter1204-6-2-9-1)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="28.049065" y="9.1172523" fill="#2aa1ff" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">Set empty</tspan></text>
|
||||
<text transform="matrix(.264583 0 0 .264583 106.53 113.074)" x="30.228771" y="8.9063139" filter="url(#filter1204-6-2-9-1-3)" text-align="center" style="line-height:1.1" xml:space="preserve"><tspan x="30.228771" y="8.9063139" fill="#2aa1ff" font-size="12px" stroke-width="3.77953" text-align="center" text-anchor="middle">Set abort</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
10
MAINTAINERS
10
MAINTAINERS
@@ -5234,6 +5234,14 @@ T: git git://linuxtv.org/media_tree.git
|
||||
F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
|
||||
F: drivers/media/platform/sunxi/sun6i-csi/
|
||||
|
||||
CTU CAN FD DRIVER
|
||||
M: Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
M: Ondrej Ille <ondrej.ille@gmail.com>
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/can/ctu,ctucanfd.yaml
|
||||
F: drivers/net/can/ctucanfd/
|
||||
|
||||
CW1200 WLAN driver
|
||||
M: Solomon Peachy <pizza@shaftnet.org>
|
||||
S: Maintained
|
||||
@@ -21632,7 +21640,7 @@ M: Appana Durga Kedareswara rao <appana.durga.rao@xilinx.com>
|
||||
R: Naga Sureshkumar Relli <naga.sureshkumar.relli@xilinx.com>
|
||||
L: linux-can@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/can/xilinx_can.txt
|
||||
F: Documentation/devicetree/bindings/net/can/xilinx,can.yaml
|
||||
F: drivers/net/can/xilinx_can.c
|
||||
|
||||
XILINX GPIO DRIVER
|
||||
|
||||
@@ -170,6 +170,7 @@ config PCH_CAN
|
||||
|
||||
source "drivers/net/can/c_can/Kconfig"
|
||||
source "drivers/net/can/cc770/Kconfig"
|
||||
source "drivers/net/can/ctucanfd/Kconfig"
|
||||
source "drivers/net/can/ifi_canfd/Kconfig"
|
||||
source "drivers/net/can/m_can/Kconfig"
|
||||
source "drivers/net/can/mscan/Kconfig"
|
||||
|
||||
@@ -16,6 +16,7 @@ obj-y += softing/
|
||||
obj-$(CONFIG_CAN_AT91) += at91_can.o
|
||||
obj-$(CONFIG_CAN_CC770) += cc770/
|
||||
obj-$(CONFIG_CAN_C_CAN) += c_can/
|
||||
obj-$(CONFIG_CAN_CTUCANFD) += ctucanfd/
|
||||
obj-$(CONFIG_CAN_FLEXCAN) += flexcan/
|
||||
obj-$(CONFIG_CAN_GRCAN) += grcan.o
|
||||
obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
|
||||
|
||||
34
drivers/net/can/ctucanfd/Kconfig
Normal file
34
drivers/net/can/ctucanfd/Kconfig
Normal file
@@ -0,0 +1,34 @@
|
||||
config CAN_CTUCANFD
|
||||
tristate "CTU CAN-FD IP core"
|
||||
help
|
||||
This driver adds support for the CTU CAN FD open-source IP core.
|
||||
More documentation and core sources at project page
|
||||
(https://gitlab.fel.cvut.cz/canbus/ctucanfd_ip_core).
|
||||
The core integration to Xilinx Zynq system as platform driver
|
||||
is available (https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top).
|
||||
Implementation on Intel FPGA-based PCI Express board is available
|
||||
from project (https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd) and
|
||||
on Intel SoC from project (https://gitlab.fel.cvut.cz/canbus/intel-soc-ctucanfd).
|
||||
Guidepost CTU FEE CAN bus projects page https://canbus.pages.fel.cvut.cz/ .
|
||||
|
||||
config CAN_CTUCANFD_PCI
|
||||
tristate "CTU CAN-FD IP core PCI/PCIe driver"
|
||||
depends on CAN_CTUCANFD
|
||||
depends on PCI
|
||||
help
|
||||
This driver adds PCI/PCIe support for CTU CAN-FD IP core.
|
||||
The project providing FPGA design for Intel EP4CGX15 based DB4CGX15
|
||||
PCIe board with PiKRON.com designed transceiver riser shield is available
|
||||
at https://gitlab.fel.cvut.cz/canbus/pcie-ctucanfd .
|
||||
|
||||
config CAN_CTUCANFD_PLATFORM
|
||||
tristate "CTU CAN-FD IP core platform (FPGA, SoC) driver"
|
||||
depends on CAN_CTUCANFD
|
||||
depends on OF || COMPILE_TEST
|
||||
help
|
||||
The core has been tested together with OpenCores SJA1000
|
||||
modified to be CAN FD frames tolerant on MicroZed Zynq based
|
||||
MZ_APO education kits designed by Petr Porazil from PiKRON.com
|
||||
company. FPGA design https://gitlab.fel.cvut.cz/canbus/zynq/zynq-can-sja1000-top.
|
||||
The kit description at the Computer Architectures course pages
|
||||
https://cw.fel.cvut.cz/wiki/courses/b35apo/documentation/mz_apo/start .
|
||||
10
drivers/net/can/ctucanfd/Makefile
Normal file
10
drivers/net/can/ctucanfd/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Makefile for the CTU CAN-FD IP module drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_CAN_CTUCANFD) := ctucanfd.o
|
||||
ctucanfd-y := ctucanfd_base.o
|
||||
|
||||
obj-$(CONFIG_CAN_CTUCANFD_PCI) += ctucanfd_pci.o
|
||||
obj-$(CONFIG_CAN_CTUCANFD_PLATFORM) += ctucanfd_platform.o
|
||||
82
drivers/net/can/ctucanfd/ctucanfd.h
Normal file
82
drivers/net/can/ctucanfd/ctucanfd.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __CTUCANFD__
|
||||
#define __CTUCANFD__
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
enum ctu_can_fd_can_registers;
|
||||
|
||||
struct ctucan_priv {
|
||||
struct can_priv can; /* must be first member! */
|
||||
|
||||
void __iomem *mem_base;
|
||||
u32 (*read_reg)(struct ctucan_priv *priv,
|
||||
enum ctu_can_fd_can_registers reg);
|
||||
void (*write_reg)(struct ctucan_priv *priv,
|
||||
enum ctu_can_fd_can_registers reg, u32 val);
|
||||
|
||||
unsigned int txb_head;
|
||||
unsigned int txb_tail;
|
||||
u32 txb_prio;
|
||||
unsigned int ntxbufs;
|
||||
spinlock_t tx_lock; /* spinlock to serialize allocation and processing of TX buffers */
|
||||
|
||||
struct napi_struct napi;
|
||||
struct device *dev;
|
||||
struct clk *can_clk;
|
||||
|
||||
int irq_flags;
|
||||
unsigned long drv_flags;
|
||||
|
||||
u32 rxfrm_first_word;
|
||||
|
||||
struct list_head peers_on_pdev;
|
||||
};
|
||||
|
||||
/**
|
||||
* ctucan_probe_common - Device type independent registration call
|
||||
*
|
||||
* This function does all the memory allocation and registration for the CAN
|
||||
* device.
|
||||
*
|
||||
* @dev: Handle to the generic device structure
|
||||
* @addr: Base address of CTU CAN FD core address
|
||||
* @irq: Interrupt number
|
||||
* @ntxbufs: Number of implemented Tx buffers
|
||||
* @can_clk_rate: Clock rate, if 0 then clock are taken from device node
|
||||
* @pm_enable_call: Whether pm_runtime_enable should be called
|
||||
* @set_drvdata_fnc: Function to set network driver data for physical device
|
||||
*
|
||||
* Return: 0 on success and failure value on error
|
||||
*/
|
||||
int ctucan_probe_common(struct device *dev, void __iomem *addr,
|
||||
int irq, unsigned int ntxbufs,
|
||||
unsigned long can_clk_rate,
|
||||
int pm_enable_call,
|
||||
void (*set_drvdata_fnc)(struct device *dev,
|
||||
struct net_device *ndev));
|
||||
|
||||
int ctucan_suspend(struct device *dev) __maybe_unused;
|
||||
int ctucan_resume(struct device *dev) __maybe_unused;
|
||||
|
||||
#endif /*__CTUCANFD__*/
|
||||
1490
drivers/net/can/ctucanfd/ctucanfd_base.c
Normal file
1490
drivers/net/can/ctucanfd/ctucanfd_base.c
Normal file
File diff suppressed because it is too large
Load Diff
77
drivers/net/can/ctucanfd/ctucanfd_kframe.h
Normal file
77
drivers/net/can/ctucanfd/ctucanfd_kframe.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
******************************************************************************/
|
||||
|
||||
/* This file is autogenerated, DO NOT EDIT! */
|
||||
|
||||
#ifndef __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__
|
||||
#define __CTU_CAN_FD_CAN_FD_FRAME_FORMAT__
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
/* CAN_Frame_format memory map */
|
||||
enum ctu_can_fd_can_frame_format {
|
||||
CTUCANFD_FRAME_FORMAT_W = 0x0,
|
||||
CTUCANFD_IDENTIFIER_W = 0x4,
|
||||
CTUCANFD_TIMESTAMP_L_W = 0x8,
|
||||
CTUCANFD_TIMESTAMP_U_W = 0xc,
|
||||
CTUCANFD_DATA_1_4_W = 0x10,
|
||||
CTUCANFD_DATA_5_8_W = 0x14,
|
||||
CTUCANFD_DATA_61_64_W = 0x4c,
|
||||
};
|
||||
|
||||
/* CAN_FD_Frame_format memory region */
|
||||
|
||||
/* FRAME_FORMAT_W registers */
|
||||
#define REG_FRAME_FORMAT_W_DLC GENMASK(3, 0)
|
||||
#define REG_FRAME_FORMAT_W_RTR BIT(5)
|
||||
#define REG_FRAME_FORMAT_W_IDE BIT(6)
|
||||
#define REG_FRAME_FORMAT_W_FDF BIT(7)
|
||||
#define REG_FRAME_FORMAT_W_BRS BIT(9)
|
||||
#define REG_FRAME_FORMAT_W_ESI_RSV BIT(10)
|
||||
#define REG_FRAME_FORMAT_W_RWCNT GENMASK(15, 11)
|
||||
|
||||
/* IDENTIFIER_W registers */
|
||||
#define REG_IDENTIFIER_W_IDENTIFIER_EXT GENMASK(17, 0)
|
||||
#define REG_IDENTIFIER_W_IDENTIFIER_BASE GENMASK(28, 18)
|
||||
|
||||
/* TIMESTAMP_L_W registers */
|
||||
#define REG_TIMESTAMP_L_W_TIME_STAMP_L_W GENMASK(31, 0)
|
||||
|
||||
/* TIMESTAMP_U_W registers */
|
||||
#define REG_TIMESTAMP_U_W_TIMESTAMP_U_W GENMASK(31, 0)
|
||||
|
||||
/* DATA_1_4_W registers */
|
||||
#define REG_DATA_1_4_W_DATA_1 GENMASK(7, 0)
|
||||
#define REG_DATA_1_4_W_DATA_2 GENMASK(15, 8)
|
||||
#define REG_DATA_1_4_W_DATA_3 GENMASK(23, 16)
|
||||
#define REG_DATA_1_4_W_DATA_4 GENMASK(31, 24)
|
||||
|
||||
/* DATA_5_8_W registers */
|
||||
#define REG_DATA_5_8_W_DATA_5 GENMASK(7, 0)
|
||||
#define REG_DATA_5_8_W_DATA_6 GENMASK(15, 8)
|
||||
#define REG_DATA_5_8_W_DATA_7 GENMASK(23, 16)
|
||||
#define REG_DATA_5_8_W_DATA_8 GENMASK(31, 24)
|
||||
|
||||
/* DATA_61_64_W registers */
|
||||
#define REG_DATA_61_64_W_DATA_61 GENMASK(7, 0)
|
||||
#define REG_DATA_61_64_W_DATA_62 GENMASK(15, 8)
|
||||
#define REG_DATA_61_64_W_DATA_63 GENMASK(23, 16)
|
||||
#define REG_DATA_61_64_W_DATA_64 GENMASK(31, 24)
|
||||
|
||||
#endif
|
||||
325
drivers/net/can/ctucanfd/ctucanfd_kregs.h
Normal file
325
drivers/net/can/ctucanfd/ctucanfd_kregs.h
Normal file
@@ -0,0 +1,325 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
******************************************************************************/
|
||||
|
||||
/* This file is autogenerated, DO NOT EDIT! */
|
||||
|
||||
#ifndef __CTU_CAN_FD_CAN_FD_REGISTER_MAP__
|
||||
#define __CTU_CAN_FD_CAN_FD_REGISTER_MAP__
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
/* CAN_Registers memory map */
|
||||
enum ctu_can_fd_can_registers {
|
||||
CTUCANFD_DEVICE_ID = 0x0,
|
||||
CTUCANFD_VERSION = 0x2,
|
||||
CTUCANFD_MODE = 0x4,
|
||||
CTUCANFD_SETTINGS = 0x6,
|
||||
CTUCANFD_STATUS = 0x8,
|
||||
CTUCANFD_COMMAND = 0xc,
|
||||
CTUCANFD_INT_STAT = 0x10,
|
||||
CTUCANFD_INT_ENA_SET = 0x14,
|
||||
CTUCANFD_INT_ENA_CLR = 0x18,
|
||||
CTUCANFD_INT_MASK_SET = 0x1c,
|
||||
CTUCANFD_INT_MASK_CLR = 0x20,
|
||||
CTUCANFD_BTR = 0x24,
|
||||
CTUCANFD_BTR_FD = 0x28,
|
||||
CTUCANFD_EWL = 0x2c,
|
||||
CTUCANFD_ERP = 0x2d,
|
||||
CTUCANFD_FAULT_STATE = 0x2e,
|
||||
CTUCANFD_REC = 0x30,
|
||||
CTUCANFD_TEC = 0x32,
|
||||
CTUCANFD_ERR_NORM = 0x34,
|
||||
CTUCANFD_ERR_FD = 0x36,
|
||||
CTUCANFD_CTR_PRES = 0x38,
|
||||
CTUCANFD_FILTER_A_MASK = 0x3c,
|
||||
CTUCANFD_FILTER_A_VAL = 0x40,
|
||||
CTUCANFD_FILTER_B_MASK = 0x44,
|
||||
CTUCANFD_FILTER_B_VAL = 0x48,
|
||||
CTUCANFD_FILTER_C_MASK = 0x4c,
|
||||
CTUCANFD_FILTER_C_VAL = 0x50,
|
||||
CTUCANFD_FILTER_RAN_LOW = 0x54,
|
||||
CTUCANFD_FILTER_RAN_HIGH = 0x58,
|
||||
CTUCANFD_FILTER_CONTROL = 0x5c,
|
||||
CTUCANFD_FILTER_STATUS = 0x5e,
|
||||
CTUCANFD_RX_MEM_INFO = 0x60,
|
||||
CTUCANFD_RX_POINTERS = 0x64,
|
||||
CTUCANFD_RX_STATUS = 0x68,
|
||||
CTUCANFD_RX_SETTINGS = 0x6a,
|
||||
CTUCANFD_RX_DATA = 0x6c,
|
||||
CTUCANFD_TX_STATUS = 0x70,
|
||||
CTUCANFD_TX_COMMAND = 0x74,
|
||||
CTUCANFD_TX_PRIORITY = 0x78,
|
||||
CTUCANFD_ERR_CAPT = 0x7c,
|
||||
CTUCANFD_ALC = 0x7e,
|
||||
CTUCANFD_TRV_DELAY = 0x80,
|
||||
CTUCANFD_SSP_CFG = 0x82,
|
||||
CTUCANFD_RX_FR_CTR = 0x84,
|
||||
CTUCANFD_TX_FR_CTR = 0x88,
|
||||
CTUCANFD_DEBUG_REGISTER = 0x8c,
|
||||
CTUCANFD_YOLO_REG = 0x90,
|
||||
CTUCANFD_TIMESTAMP_LOW = 0x94,
|
||||
CTUCANFD_TIMESTAMP_HIGH = 0x98,
|
||||
CTUCANFD_TXTB1_DATA_1 = 0x100,
|
||||
CTUCANFD_TXTB1_DATA_2 = 0x104,
|
||||
CTUCANFD_TXTB1_DATA_20 = 0x14c,
|
||||
CTUCANFD_TXTB2_DATA_1 = 0x200,
|
||||
CTUCANFD_TXTB2_DATA_2 = 0x204,
|
||||
CTUCANFD_TXTB2_DATA_20 = 0x24c,
|
||||
CTUCANFD_TXTB3_DATA_1 = 0x300,
|
||||
CTUCANFD_TXTB3_DATA_2 = 0x304,
|
||||
CTUCANFD_TXTB3_DATA_20 = 0x34c,
|
||||
CTUCANFD_TXTB4_DATA_1 = 0x400,
|
||||
CTUCANFD_TXTB4_DATA_2 = 0x404,
|
||||
CTUCANFD_TXTB4_DATA_20 = 0x44c,
|
||||
};
|
||||
|
||||
/* Control_registers memory region */
|
||||
|
||||
/* DEVICE_ID VERSION registers */
|
||||
#define REG_DEVICE_ID_DEVICE_ID GENMASK(15, 0)
|
||||
#define REG_DEVICE_ID_VER_MINOR GENMASK(23, 16)
|
||||
#define REG_DEVICE_ID_VER_MAJOR GENMASK(31, 24)
|
||||
|
||||
/* MODE SETTINGS registers */
|
||||
#define REG_MODE_RST BIT(0)
|
||||
#define REG_MODE_BMM BIT(1)
|
||||
#define REG_MODE_STM BIT(2)
|
||||
#define REG_MODE_AFM BIT(3)
|
||||
#define REG_MODE_FDE BIT(4)
|
||||
#define REG_MODE_ACF BIT(7)
|
||||
#define REG_MODE_TSTM BIT(8)
|
||||
#define REG_MODE_RTRLE BIT(16)
|
||||
#define REG_MODE_RTRTH GENMASK(20, 17)
|
||||
#define REG_MODE_ILBP BIT(21)
|
||||
#define REG_MODE_ENA BIT(22)
|
||||
#define REG_MODE_NISOFD BIT(23)
|
||||
#define REG_MODE_PEX BIT(24)
|
||||
#define REG_MODE_TBFBO BIT(25)
|
||||
#define REG_MODE_FDRF BIT(26)
|
||||
|
||||
/* STATUS registers */
|
||||
#define REG_STATUS_RXNE BIT(0)
|
||||
#define REG_STATUS_DOR BIT(1)
|
||||
#define REG_STATUS_TXNF BIT(2)
|
||||
#define REG_STATUS_EFT BIT(3)
|
||||
#define REG_STATUS_RXS BIT(4)
|
||||
#define REG_STATUS_TXS BIT(5)
|
||||
#define REG_STATUS_EWL BIT(6)
|
||||
#define REG_STATUS_IDLE BIT(7)
|
||||
#define REG_STATUS_PEXS BIT(8)
|
||||
|
||||
/* COMMAND registers */
|
||||
#define REG_COMMAND_RRB BIT(2)
|
||||
#define REG_COMMAND_CDO BIT(3)
|
||||
#define REG_COMMAND_ERCRST BIT(4)
|
||||
#define REG_COMMAND_RXFCRST BIT(5)
|
||||
#define REG_COMMAND_TXFCRST BIT(6)
|
||||
#define REG_COMMAND_CPEXS BIT(7)
|
||||
|
||||
/* INT_STAT registers */
|
||||
#define REG_INT_STAT_RXI BIT(0)
|
||||
#define REG_INT_STAT_TXI BIT(1)
|
||||
#define REG_INT_STAT_EWLI BIT(2)
|
||||
#define REG_INT_STAT_DOI BIT(3)
|
||||
#define REG_INT_STAT_FCSI BIT(4)
|
||||
#define REG_INT_STAT_ALI BIT(5)
|
||||
#define REG_INT_STAT_BEI BIT(6)
|
||||
#define REG_INT_STAT_OFI BIT(7)
|
||||
#define REG_INT_STAT_RXFI BIT(8)
|
||||
#define REG_INT_STAT_BSI BIT(9)
|
||||
#define REG_INT_STAT_RBNEI BIT(10)
|
||||
#define REG_INT_STAT_TXBHCI BIT(11)
|
||||
|
||||
/* INT_ENA_SET registers */
|
||||
#define REG_INT_ENA_SET_INT_ENA_SET GENMASK(11, 0)
|
||||
|
||||
/* INT_ENA_CLR registers */
|
||||
#define REG_INT_ENA_CLR_INT_ENA_CLR GENMASK(11, 0)
|
||||
|
||||
/* INT_MASK_SET registers */
|
||||
#define REG_INT_MASK_SET_INT_MASK_SET GENMASK(11, 0)
|
||||
|
||||
/* INT_MASK_CLR registers */
|
||||
#define REG_INT_MASK_CLR_INT_MASK_CLR GENMASK(11, 0)
|
||||
|
||||
/* BTR registers */
|
||||
#define REG_BTR_PROP GENMASK(6, 0)
|
||||
#define REG_BTR_PH1 GENMASK(12, 7)
|
||||
#define REG_BTR_PH2 GENMASK(18, 13)
|
||||
#define REG_BTR_BRP GENMASK(26, 19)
|
||||
#define REG_BTR_SJW GENMASK(31, 27)
|
||||
|
||||
/* BTR_FD registers */
|
||||
#define REG_BTR_FD_PROP_FD GENMASK(5, 0)
|
||||
#define REG_BTR_FD_PH1_FD GENMASK(11, 7)
|
||||
#define REG_BTR_FD_PH2_FD GENMASK(17, 13)
|
||||
#define REG_BTR_FD_BRP_FD GENMASK(26, 19)
|
||||
#define REG_BTR_FD_SJW_FD GENMASK(31, 27)
|
||||
|
||||
/* EWL ERP FAULT_STATE registers */
|
||||
#define REG_EWL_EW_LIMIT GENMASK(7, 0)
|
||||
#define REG_EWL_ERP_LIMIT GENMASK(15, 8)
|
||||
#define REG_EWL_ERA BIT(16)
|
||||
#define REG_EWL_ERP BIT(17)
|
||||
#define REG_EWL_BOF BIT(18)
|
||||
|
||||
/* REC TEC registers */
|
||||
#define REG_REC_REC_VAL GENMASK(8, 0)
|
||||
#define REG_REC_TEC_VAL GENMASK(24, 16)
|
||||
|
||||
/* ERR_NORM ERR_FD registers */
|
||||
#define REG_ERR_NORM_ERR_NORM_VAL GENMASK(15, 0)
|
||||
#define REG_ERR_NORM_ERR_FD_VAL GENMASK(31, 16)
|
||||
|
||||
/* CTR_PRES registers */
|
||||
#define REG_CTR_PRES_CTPV GENMASK(8, 0)
|
||||
#define REG_CTR_PRES_PTX BIT(9)
|
||||
#define REG_CTR_PRES_PRX BIT(10)
|
||||
#define REG_CTR_PRES_ENORM BIT(11)
|
||||
#define REG_CTR_PRES_EFD BIT(12)
|
||||
|
||||
/* FILTER_A_MASK registers */
|
||||
#define REG_FILTER_A_MASK_BIT_MASK_A_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_A_VAL registers */
|
||||
#define REG_FILTER_A_VAL_BIT_VAL_A_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_B_MASK registers */
|
||||
#define REG_FILTER_B_MASK_BIT_MASK_B_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_B_VAL registers */
|
||||
#define REG_FILTER_B_VAL_BIT_VAL_B_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_C_MASK registers */
|
||||
#define REG_FILTER_C_MASK_BIT_MASK_C_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_C_VAL registers */
|
||||
#define REG_FILTER_C_VAL_BIT_VAL_C_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_RAN_LOW registers */
|
||||
#define REG_FILTER_RAN_LOW_BIT_RAN_LOW_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_RAN_HIGH registers */
|
||||
#define REG_FILTER_RAN_HIGH_BIT_RAN_HIGH_VAL GENMASK(28, 0)
|
||||
|
||||
/* FILTER_CONTROL FILTER_STATUS registers */
|
||||
#define REG_FILTER_CONTROL_FANB BIT(0)
|
||||
#define REG_FILTER_CONTROL_FANE BIT(1)
|
||||
#define REG_FILTER_CONTROL_FAFB BIT(2)
|
||||
#define REG_FILTER_CONTROL_FAFE BIT(3)
|
||||
#define REG_FILTER_CONTROL_FBNB BIT(4)
|
||||
#define REG_FILTER_CONTROL_FBNE BIT(5)
|
||||
#define REG_FILTER_CONTROL_FBFB BIT(6)
|
||||
#define REG_FILTER_CONTROL_FBFE BIT(7)
|
||||
#define REG_FILTER_CONTROL_FCNB BIT(8)
|
||||
#define REG_FILTER_CONTROL_FCNE BIT(9)
|
||||
#define REG_FILTER_CONTROL_FCFB BIT(10)
|
||||
#define REG_FILTER_CONTROL_FCFE BIT(11)
|
||||
#define REG_FILTER_CONTROL_FRNB BIT(12)
|
||||
#define REG_FILTER_CONTROL_FRNE BIT(13)
|
||||
#define REG_FILTER_CONTROL_FRFB BIT(14)
|
||||
#define REG_FILTER_CONTROL_FRFE BIT(15)
|
||||
#define REG_FILTER_CONTROL_SFA BIT(16)
|
||||
#define REG_FILTER_CONTROL_SFB BIT(17)
|
||||
#define REG_FILTER_CONTROL_SFC BIT(18)
|
||||
#define REG_FILTER_CONTROL_SFR BIT(19)
|
||||
|
||||
/* RX_MEM_INFO registers */
|
||||
#define REG_RX_MEM_INFO_RX_BUFF_SIZE GENMASK(12, 0)
|
||||
#define REG_RX_MEM_INFO_RX_MEM_FREE GENMASK(28, 16)
|
||||
|
||||
/* RX_POINTERS registers */
|
||||
#define REG_RX_POINTERS_RX_WPP GENMASK(11, 0)
|
||||
#define REG_RX_POINTERS_RX_RPP GENMASK(27, 16)
|
||||
|
||||
/* RX_STATUS RX_SETTINGS registers */
|
||||
#define REG_RX_STATUS_RXE BIT(0)
|
||||
#define REG_RX_STATUS_RXF BIT(1)
|
||||
#define REG_RX_STATUS_RXMOF BIT(2)
|
||||
#define REG_RX_STATUS_RXFRC GENMASK(14, 4)
|
||||
#define REG_RX_STATUS_RTSOP BIT(16)
|
||||
|
||||
/* RX_DATA registers */
|
||||
#define REG_RX_DATA_RX_DATA GENMASK(31, 0)
|
||||
|
||||
/* TX_STATUS registers */
|
||||
#define REG_TX_STATUS_TX1S GENMASK(3, 0)
|
||||
#define REG_TX_STATUS_TX2S GENMASK(7, 4)
|
||||
#define REG_TX_STATUS_TX3S GENMASK(11, 8)
|
||||
#define REG_TX_STATUS_TX4S GENMASK(15, 12)
|
||||
|
||||
/* TX_COMMAND registers */
|
||||
#define REG_TX_COMMAND_TXCE BIT(0)
|
||||
#define REG_TX_COMMAND_TXCR BIT(1)
|
||||
#define REG_TX_COMMAND_TXCA BIT(2)
|
||||
#define REG_TX_COMMAND_TXB1 BIT(8)
|
||||
#define REG_TX_COMMAND_TXB2 BIT(9)
|
||||
#define REG_TX_COMMAND_TXB3 BIT(10)
|
||||
#define REG_TX_COMMAND_TXB4 BIT(11)
|
||||
|
||||
/* TX_PRIORITY registers */
|
||||
#define REG_TX_PRIORITY_TXT1P GENMASK(2, 0)
|
||||
#define REG_TX_PRIORITY_TXT2P GENMASK(6, 4)
|
||||
#define REG_TX_PRIORITY_TXT3P GENMASK(10, 8)
|
||||
#define REG_TX_PRIORITY_TXT4P GENMASK(14, 12)
|
||||
|
||||
/* ERR_CAPT ALC registers */
|
||||
#define REG_ERR_CAPT_ERR_POS GENMASK(4, 0)
|
||||
#define REG_ERR_CAPT_ERR_TYPE GENMASK(7, 5)
|
||||
#define REG_ERR_CAPT_ALC_BIT GENMASK(20, 16)
|
||||
#define REG_ERR_CAPT_ALC_ID_FIELD GENMASK(23, 21)
|
||||
|
||||
/* TRV_DELAY SSP_CFG registers */
|
||||
#define REG_TRV_DELAY_TRV_DELAY_VALUE GENMASK(6, 0)
|
||||
#define REG_TRV_DELAY_SSP_OFFSET GENMASK(23, 16)
|
||||
#define REG_TRV_DELAY_SSP_SRC GENMASK(25, 24)
|
||||
|
||||
/* RX_FR_CTR registers */
|
||||
#define REG_RX_FR_CTR_RX_FR_CTR_VAL GENMASK(31, 0)
|
||||
|
||||
/* TX_FR_CTR registers */
|
||||
#define REG_TX_FR_CTR_TX_FR_CTR_VAL GENMASK(31, 0)
|
||||
|
||||
/* DEBUG_REGISTER registers */
|
||||
#define REG_DEBUG_REGISTER_STUFF_COUNT GENMASK(2, 0)
|
||||
#define REG_DEBUG_REGISTER_DESTUFF_COUNT GENMASK(5, 3)
|
||||
#define REG_DEBUG_REGISTER_PC_ARB BIT(6)
|
||||
#define REG_DEBUG_REGISTER_PC_CON BIT(7)
|
||||
#define REG_DEBUG_REGISTER_PC_DAT BIT(8)
|
||||
#define REG_DEBUG_REGISTER_PC_STC BIT(9)
|
||||
#define REG_DEBUG_REGISTER_PC_CRC BIT(10)
|
||||
#define REG_DEBUG_REGISTER_PC_CRCD BIT(11)
|
||||
#define REG_DEBUG_REGISTER_PC_ACK BIT(12)
|
||||
#define REG_DEBUG_REGISTER_PC_ACKD BIT(13)
|
||||
#define REG_DEBUG_REGISTER_PC_EOF BIT(14)
|
||||
#define REG_DEBUG_REGISTER_PC_INT BIT(15)
|
||||
#define REG_DEBUG_REGISTER_PC_SUSP BIT(16)
|
||||
#define REG_DEBUG_REGISTER_PC_OVR BIT(17)
|
||||
#define REG_DEBUG_REGISTER_PC_SOF BIT(18)
|
||||
|
||||
/* YOLO_REG registers */
|
||||
#define REG_YOLO_REG_YOLO_VAL GENMASK(31, 0)
|
||||
|
||||
/* TIMESTAMP_LOW registers */
|
||||
#define REG_TIMESTAMP_LOW_TIMESTAMP_LOW GENMASK(31, 0)
|
||||
|
||||
/* TIMESTAMP_HIGH registers */
|
||||
#define REG_TIMESTAMP_HIGH_TIMESTAMP_HIGH GENMASK(31, 0)
|
||||
|
||||
#endif
|
||||
304
drivers/net/can/ctucanfd/ctucanfd_pci.c
Normal file
304
drivers/net/can/ctucanfd/ctucanfd_pci.c
Normal file
@@ -0,0 +1,304 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "ctucanfd.h"
|
||||
|
||||
#ifndef PCI_DEVICE_DATA
|
||||
#define PCI_DEVICE_DATA(vend, dev, data) \
|
||||
.vendor = PCI_VENDOR_ID_##vend, \
|
||||
.device = PCI_DEVICE_ID_##vend##_##dev, \
|
||||
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0, \
|
||||
.driver_data = (kernel_ulong_t)(data)
|
||||
#endif
|
||||
|
||||
#ifndef PCI_VENDOR_ID_TEDIA
|
||||
#define PCI_VENDOR_ID_TEDIA 0x1760
|
||||
#endif
|
||||
|
||||
#ifndef PCI_DEVICE_ID_TEDIA_CTUCAN_VER21
|
||||
#define PCI_DEVICE_ID_TEDIA_CTUCAN_VER21 0xff00
|
||||
#endif
|
||||
|
||||
#define CTUCAN_BAR0_CTUCAN_ID 0x0000
|
||||
#define CTUCAN_BAR0_CRA_BASE 0x4000
|
||||
#define CYCLONE_IV_CRA_A2P_IE (0x0050)
|
||||
|
||||
#define CTUCAN_WITHOUT_CTUCAN_ID 0
|
||||
#define CTUCAN_WITH_CTUCAN_ID 1
|
||||
|
||||
static bool use_msi = true;
|
||||
module_param(use_msi, bool, 0444);
|
||||
MODULE_PARM_DESC(use_msi, "PCIe implementation use MSI interrupts. Default: 1 (yes)");
|
||||
|
||||
static bool pci_use_second = true;
|
||||
module_param(pci_use_second, bool, 0444);
|
||||
MODULE_PARM_DESC(pci_use_second, "Use the second CAN core on PCIe card. Default: 1 (yes)");
|
||||
|
||||
struct ctucan_pci_board_data {
|
||||
void __iomem *bar0_base;
|
||||
void __iomem *cra_base;
|
||||
void __iomem *bar1_base;
|
||||
struct list_head ndev_list_head;
|
||||
int use_msi;
|
||||
};
|
||||
|
||||
static struct ctucan_pci_board_data *ctucan_pci_get_bdata(struct pci_dev *pdev)
|
||||
{
|
||||
return (struct ctucan_pci_board_data *)pci_get_drvdata(pdev);
|
||||
}
|
||||
|
||||
static void ctucan_pci_set_drvdata(struct device *dev,
|
||||
struct net_device *ndev)
|
||||
{
|
||||
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
|
||||
struct ctucan_priv *priv = netdev_priv(ndev);
|
||||
struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
|
||||
|
||||
list_add(&priv->peers_on_pdev, &bdata->ndev_list_head);
|
||||
priv->irq_flags = IRQF_SHARED;
|
||||
}
|
||||
|
||||
/**
|
||||
* ctucan_pci_probe - PCI registration call
|
||||
* @pdev: Handle to the pci device structure
|
||||
* @ent: Pointer to the entry from ctucan_pci_tbl
|
||||
*
|
||||
* This function does all the memory allocation and registration for the CAN
|
||||
* device.
|
||||
*
|
||||
* Return: 0 on success and failure value on error
|
||||
*/
|
||||
static int ctucan_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned long driver_data = ent->driver_data;
|
||||
struct ctucan_pci_board_data *bdata;
|
||||
void __iomem *addr;
|
||||
void __iomem *cra_addr;
|
||||
void __iomem *bar0_base;
|
||||
u32 cra_a2p_ie;
|
||||
u32 ctucan_id = 0;
|
||||
int ret;
|
||||
unsigned int ntxbufs;
|
||||
unsigned int num_cores = 1;
|
||||
unsigned int core_i = 0;
|
||||
int irq;
|
||||
int msi_ok = 0;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "pci_enable_device FAILED\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = pci_request_regions(pdev, KBUILD_MODNAME);
|
||||
if (ret) {
|
||||
dev_err(dev, "pci_request_regions FAILED\n");
|
||||
goto err_disable_device;
|
||||
}
|
||||
|
||||
if (use_msi) {
|
||||
ret = pci_enable_msi(pdev);
|
||||
if (!ret) {
|
||||
dev_info(dev, "MSI enabled\n");
|
||||
pci_set_master(pdev);
|
||||
msi_ok = 1;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "ctucan BAR0 0x%08llx 0x%08llx\n",
|
||||
(long long)pci_resource_start(pdev, 0),
|
||||
(long long)pci_resource_len(pdev, 0));
|
||||
|
||||
dev_info(dev, "ctucan BAR1 0x%08llx 0x%08llx\n",
|
||||
(long long)pci_resource_start(pdev, 1),
|
||||
(long long)pci_resource_len(pdev, 1));
|
||||
|
||||
addr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
|
||||
if (!addr) {
|
||||
dev_err(dev, "PCI BAR 1 cannot be mapped\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_release_regions;
|
||||
}
|
||||
|
||||
/* Cyclone IV PCI Express Control Registers Area */
|
||||
bar0_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
|
||||
if (!bar0_base) {
|
||||
dev_err(dev, "PCI BAR 0 cannot be mapped\n");
|
||||
ret = -EIO;
|
||||
goto err_pci_iounmap_bar1;
|
||||
}
|
||||
|
||||
if (driver_data == CTUCAN_WITHOUT_CTUCAN_ID) {
|
||||
cra_addr = bar0_base;
|
||||
num_cores = 2;
|
||||
} else {
|
||||
cra_addr = bar0_base + CTUCAN_BAR0_CRA_BASE;
|
||||
ctucan_id = ioread32(bar0_base + CTUCAN_BAR0_CTUCAN_ID);
|
||||
dev_info(dev, "ctucan_id 0x%08lx\n", (unsigned long)ctucan_id);
|
||||
num_cores = ctucan_id & 0xf;
|
||||
}
|
||||
|
||||
irq = pdev->irq;
|
||||
|
||||
ntxbufs = 4;
|
||||
|
||||
bdata = kzalloc(sizeof(*bdata), GFP_KERNEL);
|
||||
if (!bdata) {
|
||||
ret = -ENOMEM;
|
||||
goto err_pci_iounmap_bar0;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&bdata->ndev_list_head);
|
||||
bdata->bar0_base = bar0_base;
|
||||
bdata->cra_base = cra_addr;
|
||||
bdata->bar1_base = addr;
|
||||
bdata->use_msi = msi_ok;
|
||||
|
||||
pci_set_drvdata(pdev, bdata);
|
||||
|
||||
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
|
||||
0, ctucan_pci_set_drvdata);
|
||||
if (ret < 0)
|
||||
goto err_free_board;
|
||||
|
||||
core_i++;
|
||||
|
||||
while (pci_use_second && (core_i < num_cores)) {
|
||||
addr += 0x4000;
|
||||
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 100000000,
|
||||
0, ctucan_pci_set_drvdata);
|
||||
if (ret < 0) {
|
||||
dev_info(dev, "CTU CAN FD core %d initialization failed\n",
|
||||
core_i);
|
||||
break;
|
||||
}
|
||||
core_i++;
|
||||
}
|
||||
|
||||
/* enable interrupt in
|
||||
* Avalon-MM to PCI Express Interrupt Enable Register
|
||||
*/
|
||||
cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
|
||||
dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
|
||||
cra_a2p_ie |= 1;
|
||||
iowrite32(cra_a2p_ie, cra_addr + CYCLONE_IV_CRA_A2P_IE);
|
||||
cra_a2p_ie = ioread32(cra_addr + CYCLONE_IV_CRA_A2P_IE);
|
||||
dev_info(dev, "cra_a2p_ie 0x%08x\n", cra_a2p_ie);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_board:
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(bdata);
|
||||
err_pci_iounmap_bar0:
|
||||
pci_iounmap(pdev, cra_addr);
|
||||
err_pci_iounmap_bar1:
|
||||
pci_iounmap(pdev, addr);
|
||||
err_release_regions:
|
||||
if (msi_ok) {
|
||||
pci_disable_msi(pdev);
|
||||
pci_clear_master(pdev);
|
||||
}
|
||||
pci_release_regions(pdev);
|
||||
err_disable_device:
|
||||
pci_disable_device(pdev);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ctucan_pci_remove - Unregister the device after releasing the resources
|
||||
* @pdev: Handle to the pci device structure
|
||||
*
|
||||
* This function frees all the resources allocated to the device.
|
||||
* Return: 0 always
|
||||
*/
|
||||
static void ctucan_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *ndev;
|
||||
struct ctucan_priv *priv = NULL;
|
||||
struct ctucan_pci_board_data *bdata = ctucan_pci_get_bdata(pdev);
|
||||
|
||||
dev_dbg(&pdev->dev, "ctucan_remove");
|
||||
|
||||
if (!bdata) {
|
||||
dev_err(&pdev->dev, "%s: no list of devices\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* disable interrupt in
|
||||
* Avalon-MM to PCI Express Interrupt Enable Register
|
||||
*/
|
||||
if (bdata->cra_base)
|
||||
iowrite32(0, bdata->cra_base + CYCLONE_IV_CRA_A2P_IE);
|
||||
|
||||
while ((priv = list_first_entry_or_null(&bdata->ndev_list_head, struct ctucan_priv,
|
||||
peers_on_pdev)) != NULL) {
|
||||
ndev = priv->can.dev;
|
||||
|
||||
unregister_candev(ndev);
|
||||
|
||||
netif_napi_del(&priv->napi);
|
||||
|
||||
list_del_init(&priv->peers_on_pdev);
|
||||
free_candev(ndev);
|
||||
}
|
||||
|
||||
pci_iounmap(pdev, bdata->bar1_base);
|
||||
|
||||
if (bdata->use_msi) {
|
||||
pci_disable_msi(pdev);
|
||||
pci_clear_master(pdev);
|
||||
}
|
||||
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
pci_iounmap(pdev, bdata->bar0_base);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(bdata);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ctucan_pci_pm_ops, ctucan_suspend, ctucan_resume);
|
||||
|
||||
static const struct pci_device_id ctucan_pci_tbl[] = {
|
||||
{PCI_DEVICE_DATA(TEDIA, CTUCAN_VER21,
|
||||
CTUCAN_WITH_CTUCAN_ID)},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct pci_driver ctucan_pci_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = ctucan_pci_tbl,
|
||||
.probe = ctucan_pci_probe,
|
||||
.remove = ctucan_pci_remove,
|
||||
.driver.pm = &ctucan_pci_pm_ops,
|
||||
};
|
||||
|
||||
module_pci_driver(ctucan_pci_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Pavel Pisa <pisa@cmp.felk.cvut.cz>");
|
||||
MODULE_DESCRIPTION("CTU CAN FD for PCI bus");
|
||||
132
drivers/net/can/ctucanfd/ctucanfd_platform.c
Normal file
132
drivers/net/can/ctucanfd/ctucanfd_platform.c
Normal file
@@ -0,0 +1,132 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*******************************************************************************
|
||||
*
|
||||
* CTU CAN FD IP Core
|
||||
*
|
||||
* Copyright (C) 2015-2018 Ondrej Ille <ondrej.ille@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2021 Ondrej Ille <ondrej.ille@gmail.com> self-funded
|
||||
* Copyright (C) 2018-2019 Martin Jerabek <martin.jerabek01@gmail.com> FEE CTU
|
||||
* Copyright (C) 2018-2022 Pavel Pisa <pisa@cmp.felk.cvut.cz> FEE CTU/self-funded
|
||||
*
|
||||
* Project advisors:
|
||||
* Jiri Novak <jnovak@fel.cvut.cz>
|
||||
* Pavel Pisa <pisa@cmp.felk.cvut.cz>
|
||||
*
|
||||
* Department of Measurement (http://meas.fel.cvut.cz/)
|
||||
* Faculty of Electrical Engineering (http://www.fel.cvut.cz)
|
||||
* Czech Technical University (http://www.cvut.cz/)
|
||||
******************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "ctucanfd.h"
|
||||
|
||||
#define DRV_NAME "ctucanfd"
|
||||
|
||||
static void ctucan_platform_set_drvdata(struct device *dev,
|
||||
struct net_device *ndev)
|
||||
{
|
||||
struct platform_device *pdev = container_of(dev, struct platform_device,
|
||||
dev);
|
||||
|
||||
platform_set_drvdata(pdev, ndev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ctucan_platform_probe - Platform registration call
|
||||
* @pdev: Handle to the platform device structure
|
||||
*
|
||||
* This function does all the memory allocation and registration for the CAN
|
||||
* device.
|
||||
*
|
||||
* Return: 0 on success and failure value on error
|
||||
*/
|
||||
static int ctucan_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res; /* IO mem resources */
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *addr;
|
||||
int ret;
|
||||
unsigned int ntxbufs;
|
||||
int irq;
|
||||
|
||||
/* Get the virtual base address for the device */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(addr)) {
|
||||
dev_err(dev, "Cannot remap address.\n");
|
||||
ret = PTR_ERR(addr);
|
||||
goto err;
|
||||
}
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "Cannot find interrupt.\n");
|
||||
ret = irq;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Number of tx bufs might be change in HW for future. If so,
|
||||
* it will be passed as property via device tree
|
||||
*/
|
||||
ntxbufs = 4;
|
||||
ret = ctucan_probe_common(dev, addr, irq, ntxbufs, 0,
|
||||
1, ctucan_platform_set_drvdata);
|
||||
|
||||
if (ret < 0)
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ctucan_platform_remove - Unregister the device after releasing the resources
|
||||
* @pdev: Handle to the platform device structure
|
||||
*
|
||||
* This function frees all the resources allocated to the device.
|
||||
* Return: 0 always
|
||||
*/
|
||||
static int ctucan_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *ndev = platform_get_drvdata(pdev);
|
||||
struct ctucan_priv *priv = netdev_priv(ndev);
|
||||
|
||||
netdev_dbg(ndev, "ctucan_remove");
|
||||
|
||||
unregister_candev(ndev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
netif_napi_del(&priv->napi);
|
||||
free_candev(ndev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ctucan_platform_pm_ops, ctucan_suspend, ctucan_resume);
|
||||
|
||||
/* Match table for OF platform binding */
|
||||
static const struct of_device_id ctucan_of_match[] = {
|
||||
{ .compatible = "ctu,ctucanfd-2", },
|
||||
{ .compatible = "ctu,ctucanfd", },
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ctucan_of_match);
|
||||
|
||||
static struct platform_driver ctucanfd_driver = {
|
||||
.probe = ctucan_platform_probe,
|
||||
.remove = ctucan_platform_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.pm = &ctucan_platform_pm_ops,
|
||||
.of_match_table = ctucan_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(ctucanfd_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Martin Jerabek");
|
||||
MODULE_DESCRIPTION("CTU CAN FD for platform");
|
||||
@@ -116,7 +116,7 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
|
||||
can_update_sample_point(btc, sample_point_nominal, tseg / 2,
|
||||
&tseg1, &tseg2, &sample_point_error);
|
||||
if (sample_point_error > best_sample_point_error)
|
||||
if (sample_point_error >= best_sample_point_error)
|
||||
continue;
|
||||
|
||||
best_sample_point_error = sample_point_error;
|
||||
|
||||
@@ -221,7 +221,7 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
|
||||
|
||||
int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||
int can_rx_offload_queue_timestamp(struct can_rx_offload *offload,
|
||||
struct sk_buff *skb, u32 timestamp)
|
||||
{
|
||||
struct can_rx_offload_cb *cb;
|
||||
@@ -240,7 +240,7 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_queue_timestamp);
|
||||
|
||||
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
unsigned int idx, u32 timestamp,
|
||||
@@ -256,7 +256,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
err = can_rx_offload_queue_sorted(offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(offload, skb, timestamp);
|
||||
if (err) {
|
||||
stats->rx_errors++;
|
||||
stats->tx_fifo_errors++;
|
||||
|
||||
@@ -723,11 +723,9 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
|
||||
const struct flexcan_priv *priv = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
err = pm_runtime_get_sync(priv->dev);
|
||||
if (err < 0) {
|
||||
pm_runtime_put_noidle(priv->dev);
|
||||
err = pm_runtime_resume_and_get(priv->dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = __flexcan_get_berr_counter(dev, bec);
|
||||
|
||||
@@ -845,7 +843,7 @@ static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
|
||||
if (tx_errors)
|
||||
dev->stats.tx_errors++;
|
||||
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
if (err)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
}
|
||||
@@ -892,7 +890,7 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
||||
if (unlikely(new_state == CAN_STATE_BUS_OFF))
|
||||
can_bus_off(dev);
|
||||
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
if (err)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
}
|
||||
@@ -1700,11 +1698,9 @@ static int flexcan_open(struct net_device *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = pm_runtime_get_sync(priv->dev);
|
||||
if (err < 0) {
|
||||
pm_runtime_put_noidle(priv->dev);
|
||||
err = pm_runtime_resume_and_get(priv->dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = open_candev(dev);
|
||||
if (err)
|
||||
|
||||
@@ -464,7 +464,7 @@ static void m_can_receive_skb(struct m_can_classdev *cdev,
|
||||
struct net_device_stats *stats = &cdev->net->stats;
|
||||
int err;
|
||||
|
||||
err = can_rx_offload_queue_sorted(&cdev->offload, skb,
|
||||
err = can_rx_offload_queue_timestamp(&cdev->offload, skb,
|
||||
timestamp);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <sysdev/fsl_soc.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
@@ -107,7 +107,7 @@ config CAN_TSCAN1
|
||||
depends on ISA
|
||||
help
|
||||
This driver is for Technologic Systems' TSCAN-1 PC104 boards.
|
||||
http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1
|
||||
https://www.embeddedts.com/products/TS-CAN1
|
||||
The driver supports multiple boards and automatically configures them:
|
||||
PLD IO base addresses are read from jumpers JP1 and JP2,
|
||||
IRQ numbers are read from jumpers JP4 and JP5,
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
* Copyright 2010 Andre B. Oliveira
|
||||
*/
|
||||
|
||||
/*
|
||||
* References:
|
||||
* - Getting started with TS-CAN1, Technologic Systems, Jun 2009
|
||||
* http://www.embeddedarm.com/documentation/ts-can1-manual.pdf
|
||||
/* References:
|
||||
* - Getting started with TS-CAN1, Technologic Systems, Feb 2022
|
||||
* https://docs.embeddedts.com/TS-CAN1
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
|
||||
@@ -37,6 +37,12 @@ static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp2518fd = {
|
||||
.model = MCP251XFD_MODEL_MCP2518FD,
|
||||
};
|
||||
|
||||
static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251863 = {
|
||||
.quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX |
|
||||
MCP251XFD_QUIRK_CRC_TX | MCP251XFD_QUIRK_ECC,
|
||||
.model = MCP251XFD_MODEL_MCP251863,
|
||||
};
|
||||
|
||||
/* Autodetect model, start with CRC enabled. */
|
||||
static const struct mcp251xfd_devtype_data mcp251xfd_devtype_data_mcp251xfd = {
|
||||
.quirks = MCP251XFD_QUIRK_CRC_REG | MCP251XFD_QUIRK_CRC_RX |
|
||||
@@ -75,6 +81,8 @@ static const char *__mcp251xfd_get_model_str(enum mcp251xfd_model model)
|
||||
return "MCP2517FD";
|
||||
case MCP251XFD_MODEL_MCP2518FD:
|
||||
return "MCP2518FD";
|
||||
case MCP251XFD_MODEL_MCP251863:
|
||||
return "MCP251863";
|
||||
case MCP251XFD_MODEL_MCP251XFD:
|
||||
return "MCP251xFD";
|
||||
}
|
||||
@@ -916,7 +924,7 @@ static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
@@ -1021,7 +1029,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
|
||||
return 0;
|
||||
|
||||
mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
@@ -1094,7 +1102,7 @@ static int mcp251xfd_handle_cerrif(struct mcp251xfd_priv *priv)
|
||||
cf->data[7] = bec.rxerr;
|
||||
}
|
||||
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
@@ -1259,7 +1267,8 @@ mcp251xfd_handle_eccif_recover(struct mcp251xfd_priv *priv, u8 nr)
|
||||
* - for mcp2518fd: offset not 0 or 1
|
||||
*/
|
||||
if (chip_tx_tail != tx_tail ||
|
||||
!(offset == 0 || (offset == 1 && mcp251xfd_is_2518(priv)))) {
|
||||
!(offset == 0 || (offset == 1 && (mcp251xfd_is_2518FD(priv) ||
|
||||
mcp251xfd_is_251863(priv))))) {
|
||||
netdev_err(priv->ndev,
|
||||
"ECC Error information inconsistent (addr=0x%04x, nr=%d, tx_tail=0x%08x(%d), chip_tx_tail=%d, offset=%d).\n",
|
||||
addr, nr, tx_ring->tail, tx_tail, chip_tx_tail,
|
||||
@@ -1697,7 +1706,7 @@ static int mcp251xfd_register_chip_detect(struct mcp251xfd_priv *priv)
|
||||
else
|
||||
devtype_data = &mcp251xfd_devtype_data_mcp2517fd;
|
||||
|
||||
if (!mcp251xfd_is_251X(priv) &&
|
||||
if (!mcp251xfd_is_251XFD(priv) &&
|
||||
priv->devtype_data.model != devtype_data->model) {
|
||||
netdev_info(ndev,
|
||||
"Detected %s, but firmware specifies a %s. Fixing up.\n",
|
||||
@@ -1929,6 +1938,9 @@ static const struct of_device_id mcp251xfd_of_match[] = {
|
||||
}, {
|
||||
.compatible = "microchip,mcp2518fd",
|
||||
.data = &mcp251xfd_devtype_data_mcp2518fd,
|
||||
}, {
|
||||
.compatible = "microchip,mcp251863",
|
||||
.data = &mcp251xfd_devtype_data_mcp251863,
|
||||
}, {
|
||||
.compatible = "microchip,mcp251xfd",
|
||||
.data = &mcp251xfd_devtype_data_mcp251xfd,
|
||||
@@ -1945,6 +1957,9 @@ static const struct spi_device_id mcp251xfd_id_table[] = {
|
||||
}, {
|
||||
.name = "mcp2518fd",
|
||||
.driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp2518fd,
|
||||
}, {
|
||||
.name = "mcp251863",
|
||||
.driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251863,
|
||||
}, {
|
||||
.name = "mcp251xfd",
|
||||
.driver_data = (kernel_ulong_t)&mcp251xfd_devtype_data_mcp251xfd,
|
||||
|
||||
@@ -173,7 +173,7 @@ mcp251xfd_handle_rxif_one(struct mcp251xfd_priv *priv,
|
||||
}
|
||||
|
||||
mcp251xfd_hw_rx_obj_to_skb(priv, hw_rx_obj, skb);
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, hw_rx_obj->ts);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, hw_rx_obj->ts);
|
||||
if (err)
|
||||
stats->rx_fifo_errors++;
|
||||
|
||||
|
||||
@@ -586,7 +586,8 @@ struct mcp251xfd_regs_status {
|
||||
enum mcp251xfd_model {
|
||||
MCP251XFD_MODEL_MCP2517FD = 0x2517,
|
||||
MCP251XFD_MODEL_MCP2518FD = 0x2518,
|
||||
MCP251XFD_MODEL_MCP251XFD = 0xffff, /* autodetect model */
|
||||
MCP251XFD_MODEL_MCP251863 = 0x251863,
|
||||
MCP251XFD_MODEL_MCP251XFD = 0xffffffff, /* autodetect model */
|
||||
};
|
||||
|
||||
struct mcp251xfd_devtype_data {
|
||||
@@ -659,12 +660,13 @@ struct mcp251xfd_priv {
|
||||
static inline bool \
|
||||
mcp251xfd_is_##_model(const struct mcp251xfd_priv *priv) \
|
||||
{ \
|
||||
return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model##FD; \
|
||||
return priv->devtype_data.model == MCP251XFD_MODEL_MCP##_model; \
|
||||
}
|
||||
|
||||
MCP251XFD_IS(2517);
|
||||
MCP251XFD_IS(2518);
|
||||
MCP251XFD_IS(251X);
|
||||
MCP251XFD_IS(2517FD);
|
||||
MCP251XFD_IS(2518FD);
|
||||
MCP251XFD_IS(251863);
|
||||
MCP251XFD_IS(251XFD);
|
||||
|
||||
static inline bool mcp251xfd_is_fd_mode(const struct mcp251xfd_priv *priv)
|
||||
{
|
||||
|
||||
@@ -633,7 +633,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
|
||||
timestamp = hecc_read(priv, HECC_CANLNT);
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb,
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb,
|
||||
timestamp);
|
||||
if (err)
|
||||
ndev->stats.rx_fifo_errors++;
|
||||
@@ -668,7 +668,7 @@ static void ti_hecc_change_state(struct net_device *ndev,
|
||||
}
|
||||
|
||||
timestamp = hecc_read(priv, HECC_CANLNT);
|
||||
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
||||
err = can_rx_offload_queue_timestamp(&priv->offload, skb, timestamp);
|
||||
if (err)
|
||||
ndev->stats.rx_fifo_errors++;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd = {
|
||||
};
|
||||
|
||||
/* AXI CANFD Data Bittiming constants as per AXI CANFD 1.0 specs */
|
||||
static struct can_bittiming_const xcan_data_bittiming_const_canfd = {
|
||||
static const struct can_bittiming_const xcan_data_bittiming_const_canfd = {
|
||||
.name = DRIVER_NAME,
|
||||
.tseg1_min = 1,
|
||||
.tseg1_max = 16,
|
||||
@@ -265,7 +265,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
|
||||
};
|
||||
|
||||
/* AXI CANFD 2.0 Data Bittiming constants as per AXI CANFD 2.0 spec */
|
||||
static struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
|
||||
static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
|
||||
.name = DRIVER_NAME,
|
||||
.tseg1_min = 1,
|
||||
.tseg1_max = 32,
|
||||
|
||||
@@ -42,8 +42,8 @@ int can_rx_offload_add_manual(struct net_device *dev,
|
||||
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
|
||||
u64 reg);
|
||||
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);
|
||||
int can_rx_offload_queue_timestamp(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 *frame_len_ptr);
|
||||
|
||||
Reference in New Issue
Block a user