Commit 9c0ee085 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-5.13-20210330' of...

Merge tag 'linux-can-next-for-5.13-20210330' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2021-03-30

this is a pull request of 39 patches for net-next/master.

The first two patches update the MAINTAINERS file. One is by me and
removes Dan Murphy from the from m_can and tcan4x5x. The other one is
by Pankaj Sharma and updates the maintainership of the m-can mmio
driver.

The next three patches are by me and update the CAN echo skb handling.

Vincent Mailhol provides 5 patches where Transmitter Delay
Compensation is added CAN bittiming calculation is cleaned up.

The next patch is by me and adds a missing HAS_IOMEM to the grcan
driver.

Michal Simek's patch for the xilinx driver add dev_err_probe()
support.

Arnd Bergmann's patch for the ucan driver fixes a compiler warning.

Stephane Grosjean provides 3 patches for the peak USB drivers, which
add ethtool set_phys_id and CAN one-shot mode.

Xulin Sun's patch removes a not needed return check in the m-can
driver. Torin Cooper-Bennun provides 3 patches for the m-can driver
that add rx-offload support to ensure that skbs are sent from softirq
context. Wan Jiabing's patch for the tcan4x5x driver removes a
duplicate include.

The next 6 patches are by me and target the mcp251xfd driver. They add
devcoredump support, simplify the UINC handling, and add HW timestamp
support.

The remaining 12 patches target the c_can driver. The first 6 are by
me and do generic checkpatch related cleanup work. Dario Binacchi's
patches bring some cleanups and increase the number of usable message
objects from 16 to 64.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 402a66ed 132f2d45
......@@ -10910,8 +10910,7 @@ T: git git://linuxtv.org/media_tree.git
F: drivers/media/radio/radio-maxiradio*
MCAN MMIO DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com>
M: Pankaj Sharma <pankj.sharma@samsung.com>
M: Chandrasekar Ramakrishnan <rcsekar@samsung.com>
L: linux-can@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml
......@@ -17983,13 +17982,6 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes
F: sound/soc/codecs/tas571x*
TI TCAN4X5X DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com>
L: linux-can@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/can/tcan4x5x.txt
F: drivers/net/can/m_can/tcan4x5x*
TI TRF7970A NFC DRIVER
M: Mark Greer <mgreer@animalcreek.com>
L: linux-wireless@vger.kernel.org
......
......@@ -103,7 +103,7 @@ config CAN_FLEXCAN
config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on OF && HAS_DMA
depends on OF && HAS_DMA && HAS_IOMEM
help
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little
......
This diff is collapsed.
......@@ -22,23 +22,6 @@
#ifndef C_CAN_H
#define C_CAN_H
/* message object split */
#define C_CAN_NO_OF_OBJECTS 32
#define C_CAN_MSG_OBJ_RX_NUM 16
#define C_CAN_MSG_OBJ_TX_NUM 16
#define C_CAN_MSG_OBJ_RX_FIRST 1
#define C_CAN_MSG_OBJ_RX_LAST (C_CAN_MSG_OBJ_RX_FIRST + \
C_CAN_MSG_OBJ_RX_NUM - 1)
#define C_CAN_MSG_OBJ_TX_FIRST (C_CAN_MSG_OBJ_RX_LAST + 1)
#define C_CAN_MSG_OBJ_TX_LAST (C_CAN_MSG_OBJ_TX_FIRST + \
C_CAN_MSG_OBJ_TX_NUM - 1)
#define C_CAN_MSG_OBJ_RX_SPLIT 9
#define C_CAN_MSG_RX_LOW_LAST (C_CAN_MSG_OBJ_RX_SPLIT - 1)
#define RECEIVE_OBJECT_BITS 0x0000ffff
enum reg {
C_CAN_CTRL_REG = 0,
C_CAN_CTRL_EX_REG,
......@@ -76,6 +59,7 @@ enum reg {
C_CAN_NEWDAT2_REG,
C_CAN_INTPND1_REG,
C_CAN_INTPND2_REG,
C_CAN_INTPND3_REG,
C_CAN_MSGVAL1_REG,
C_CAN_MSGVAL2_REG,
C_CAN_FUNCTION_REG,
......@@ -137,6 +121,7 @@ static const u16 __maybe_unused reg_map_d_can[] = {
[C_CAN_NEWDAT2_REG] = 0x9E,
[C_CAN_INTPND1_REG] = 0xB0,
[C_CAN_INTPND2_REG] = 0xB2,
[C_CAN_INTPND3_REG] = 0xB4,
[C_CAN_MSGVAL1_REG] = 0xC4,
[C_CAN_MSGVAL2_REG] = 0xC6,
[C_CAN_IF1_COMREQ_REG] = 0x100,
......@@ -176,6 +161,7 @@ struct raminit_bits {
struct c_can_driver_data {
enum c_can_dev_id id;
unsigned int msg_obj_num;
/* RAMINIT register description. Optional. */
const struct raminit_bits *raminit_bits; /* Array of START/DONE bit positions */
......@@ -197,26 +183,34 @@ struct c_can_priv {
struct napi_struct napi;
struct net_device *dev;
struct device *device;
unsigned int msg_obj_num;
unsigned int msg_obj_rx_num;
unsigned int msg_obj_tx_num;
unsigned int msg_obj_rx_first;
unsigned int msg_obj_rx_last;
unsigned int msg_obj_tx_first;
unsigned int msg_obj_tx_last;
u32 msg_obj_rx_mask;
atomic_t tx_active;
atomic_t sie_pending;
unsigned long tx_dir;
int last_status;
u16 (*read_reg) (const struct c_can_priv *priv, enum reg index);
void (*write_reg) (const struct c_can_priv *priv, enum reg index, u16 val);
u32 (*read_reg32) (const struct c_can_priv *priv, enum reg index);
void (*write_reg32) (const struct c_can_priv *priv, enum reg index, u32 val);
u16 (*read_reg)(const struct c_can_priv *priv, enum reg index);
void (*write_reg)(const struct c_can_priv *priv, enum reg index, u16 val);
u32 (*read_reg32)(const struct c_can_priv *priv, enum reg index);
void (*write_reg32)(const struct c_can_priv *priv, enum reg index, u32 val);
void __iomem *base;
const u16 *regs;
void *priv; /* for board-specific data */
enum c_can_dev_id type;
struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */
void (*raminit) (const struct c_can_priv *priv, bool enable);
void (*raminit)(const struct c_can_priv *priv, bool enable);
u32 comm_rcv_high;
u32 rxmasked;
u32 dlc[C_CAN_MSG_OBJ_TX_NUM];
u32 dlc[];
};
struct net_device *alloc_c_can_dev(void);
struct net_device *alloc_c_can_dev(int msg_obj_num);
void free_c_can_dev(struct net_device *dev);
int register_c_can_dev(struct net_device *dev);
void unregister_c_can_dev(struct net_device *dev);
......
......@@ -31,6 +31,8 @@ enum c_can_pci_reg_align {
struct c_can_pci_data {
/* Specify if is C_CAN or D_CAN */
enum c_can_dev_id type;
/* Number of message objects */
unsigned int msg_obj_num;
/* Set the register alignment in the memory */
enum c_can_pci_reg_align reg_align;
/* Set the frequency */
......@@ -41,32 +43,31 @@ struct c_can_pci_data {
void (*init)(const struct c_can_priv *priv, bool enable);
};
/*
* 16-bit c_can registers can be arranged differently in the memory
/* 16-bit c_can registers can be arranged differently in the memory
* architecture of different implementations. For example: 16-bit
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface.
*/
static u16 c_can_pci_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index)
enum reg index)
{
return readw(priv->base + priv->regs[index]);
}
static void c_can_pci_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
enum reg index, u16 val)
enum reg index, u16 val)
{
writew(val, priv->base + priv->regs[index]);
}
static u16 c_can_pci_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index)
enum reg index)
{
return readw(priv->base + 2 * priv->regs[index]);
}
static void c_can_pci_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
enum reg index, u16 val)
enum reg index, u16 val)
{
writew(val, priv->base + 2 * priv->regs[index]);
}
......@@ -88,13 +89,13 @@ static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index)
u32 val;
val = priv->read_reg(priv, index);
val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
val |= ((u32)priv->read_reg(priv, index + 1)) << 16;
return val;
}
static void c_can_pci_write_reg32(const struct c_can_priv *priv, enum reg index,
u32 val)
u32 val)
{
priv->write_reg(priv, index + 1, val >> 16);
priv->write_reg(priv, index, val);
......@@ -142,14 +143,13 @@ static int c_can_pci_probe(struct pci_dev *pdev,
pci_resource_len(pdev, c_can_pci_data->bar));
if (!addr) {
dev_err(&pdev->dev,
"device has no PCI memory resources, "
"failing adapter\n");
"device has no PCI memory resources, failing adapter\n");
ret = -ENOMEM;
goto out_release_regions;
}
/* allocate the c_can device */
dev = alloc_c_can_dev();
dev = alloc_c_can_dev(c_can_pci_data->msg_obj_num);
if (!dev) {
ret = -ENOMEM;
goto out_iounmap;
......@@ -217,7 +217,7 @@ static int c_can_pci_probe(struct pci_dev *pdev,
}
dev_dbg(&pdev->dev, "%s device registered (regs=%p, irq=%d)\n",
KBUILD_MODNAME, priv->regs, dev->irq);
KBUILD_MODNAME, priv->regs, dev->irq);
return 0;
......@@ -252,8 +252,9 @@ static void c_can_pci_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
static const struct c_can_pci_data c_can_sta2x11= {
static const struct c_can_pci_data c_can_sta2x11 = {
.type = BOSCH_C_CAN,
.msg_obj_num = 32,
.reg_align = C_CAN_REG_ALIGN_32,
.freq = 52000000, /* 52 Mhz */
.bar = 0,
......@@ -261,6 +262,7 @@ static const struct c_can_pci_data c_can_sta2x11= {
static const struct c_can_pci_data c_can_pch = {
.type = BOSCH_C_CAN,
.msg_obj_num = 32,
.reg_align = C_CAN_REG_32,
.freq = 50000000, /* 50 MHz */
.init = c_can_pci_reset_pch,
......@@ -269,7 +271,7 @@ static const struct c_can_pci_data c_can_pch = {
#define C_CAN_ID(_vend, _dev, _driverdata) { \
PCI_DEVICE(_vend, _dev), \
.driver_data = (unsigned long)&_driverdata, \
.driver_data = (unsigned long)&(_driverdata), \
}
static const struct pci_device_id c_can_pci_tbl[] = {
......@@ -279,6 +281,7 @@ static const struct pci_device_id c_can_pci_tbl[] = {
c_can_pch),
{},
};
static struct pci_driver c_can_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = c_can_pci_tbl,
......
......@@ -193,10 +193,12 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable)
static const struct c_can_driver_data c_can_drvdata = {
.id = BOSCH_C_CAN,
.msg_obj_num = 32,
};
static const struct c_can_driver_data d_can_drvdata = {
.id = BOSCH_D_CAN,
.msg_obj_num = 32,
};
static const struct raminit_bits dra7_raminit_bits[] = {
......@@ -206,6 +208,7 @@ static const struct raminit_bits dra7_raminit_bits[] = {
static const struct c_can_driver_data dra7_dcan_drvdata = {
.id = BOSCH_D_CAN,
.msg_obj_num = 64,
.raminit_num = ARRAY_SIZE(dra7_raminit_bits),
.raminit_bits = dra7_raminit_bits,
.raminit_pulse = true,
......@@ -218,6 +221,7 @@ static const struct raminit_bits am3352_raminit_bits[] = {
static const struct c_can_driver_data am3352_dcan_drvdata = {
.id = BOSCH_D_CAN,
.msg_obj_num = 64,
.raminit_num = ARRAY_SIZE(am3352_raminit_bits),
.raminit_bits = am3352_raminit_bits,
};
......@@ -294,7 +298,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
}
/* allocate the c_can device */
dev = alloc_c_can_dev();
dev = alloc_c_can_dev(drvdata->msg_obj_num);
if (!dev) {
ret = -ENOMEM;
goto exit;
......
......@@ -81,9 +81,9 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
if (bt->sample_point) {
sample_point_nominal = bt->sample_point;
} else {
if (bt->bitrate > 800000)
if (bt->bitrate > 800 * CAN_KBPS)
sample_point_nominal = 750;
else if (bt->bitrate > 500000)
else if (bt->bitrate > 500 * CAN_KBPS)
sample_point_nominal = 800;
else
sample_point_nominal = 875;
......@@ -174,6 +174,30 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
return 0;
}
void can_calc_tdco(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
const struct can_bittiming *dbt = &priv->data_bittiming;
struct can_tdc *tdc = &priv->tdc;
const struct can_tdc_const *tdc_const = priv->tdc_const;
if (!tdc_const)
return;
/* As specified in ISO 11898-1 section 11.3.3 "Transmitter
* delay compensation" (TDC) is only applicable if data BRP is
* one or two.
*/
if (dbt->brp == 1 || dbt->brp == 2) {
/* Reuse "normal" sample point and convert it to time quanta */
u32 sample_point_in_tq = can_bit_time(dbt) * dbt->sample_point / 1000;
tdc->tdco = min(sample_point_in_tq, tdc_const->tdco_max);
} else {
tdc->tdco = 0;
}
}
#endif /* CONFIG_CAN_CALC_BITTIMING */
/* Checks the validity of the specified bit-timing parameters prop_seg,
......
......@@ -8,20 +8,17 @@
#include <net/rtnetlink.h>
static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_STATE] = { .type = NLA_U32 },
[IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
[IFLA_CAN_RESTART] = { .type = NLA_U32 },
[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
[IFLA_CAN_DATA_BITTIMING]
= { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_DATA_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
[IFLA_CAN_STATE] = { .type = NLA_U32 },
[IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
[IFLA_CAN_RESTART] = { .type = NLA_U32 },
[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
[IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
};
static int can_validate(struct nlattr *tb[], struct nlattr *data[],
......@@ -189,6 +186,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
can_calc_tdco(dev);
if (priv->do_set_data_bittiming) {
/* Finally, set the bit-timing registers */
err = priv->do_set_data_bittiming(dev);
......
......@@ -45,7 +45,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
BUG_ON(idx >= priv->echo_skb_max);
/* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
if (!(dev->flags & IFF_ECHO) ||
(skb->protocol != htons(ETH_P_CAN) &&
skb->protocol != htons(ETH_P_CANFD))) {
kfree_skb(skb);
......@@ -58,7 +58,6 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
return -ENOMEM;
/* make settings for echo to reduce code in irq context */
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev;
......@@ -111,6 +110,13 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
priv->echo_skb[idx] = NULL;
if (skb->pkt_type == PACKET_LOOPBACK) {
skb->pkt_type = PACKET_BROADCAST;
} else {
dev_consume_skb_any(skb);
return NULL;
}
return skb;
}
......@@ -147,14 +153,25 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb);
*
* The function is typically called when TX failed.
*/
void can_free_echo_skb(struct net_device *dev, unsigned int idx)
void can_free_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr)
{
struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max);
if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
return;
}
if (priv->echo_skb[idx]) {
dev_kfree_skb_any(priv->echo_skb[idx]);
struct sk_buff *skb = priv->echo_skb[idx];
struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
if (frame_len_ptr)
*frame_len_ptr = can_skb_priv->frame_len;
dev_kfree_skb_any(skb);
priv->echo_skb[idx] = NULL;
}
}
......
......@@ -520,7 +520,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo)
can_get_echo_skb(dev, i, NULL);
} else {
/* For cleanup of untransmitted messages */
can_free_echo_skb(dev, i);
can_free_echo_skb(dev, i, NULL);
}
priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
......
This diff is collapsed.
......@@ -8,6 +8,7 @@
#include <linux/can/core.h>
#include <linux/can/led.h>
#include <linux/can/rx-offload.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
......@@ -71,6 +72,7 @@ struct m_can_ops {
struct m_can_classdev {
struct can_priv can;
struct can_rx_offload offload;
struct napi_struct napi;
struct net_device *net;
struct device *dev;
......
......@@ -11,7 +11,6 @@
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
......
......@@ -217,7 +217,7 @@ static void tx_failure_cleanup(struct net_device *ndev)
int i;
for (i = 0; i < RCAR_CAN_FIFO_DEPTH; i++)
can_free_echo_skb(ndev, i);
can_free_echo_skb(ndev, i, NULL);
}
static void rcar_can_error(struct net_device *ndev)
......
......@@ -617,7 +617,7 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev)
u32 i;
for (i = 0; i < RCANFD_FIFO_DEPTH; i++)
can_free_echo_skb(ndev, i);
can_free_echo_skb(ndev, i, NULL);
}
static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
......
......@@ -525,7 +525,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
!(status & SR_TCS)) {
stats->tx_errors++;
can_free_echo_skb(dev, 0);
can_free_echo_skb(dev, 0, NULL);
} else {
/* transmission complete */
stats->tx_bytes +=
......
......@@ -179,7 +179,7 @@ static void hi3110_clean(struct net_device *net)
net->stats.tx_errors++;
dev_kfree_skb(priv->tx_skb);
if (priv->tx_len)
can_free_echo_skb(priv->net, 0);
can_free_echo_skb(priv->net, 0, NULL);
priv->tx_skb = NULL;
priv->tx_len = 0;
}
......
......@@ -276,7 +276,7 @@ static void mcp251x_clean(struct net_device *net)
net->stats.tx_errors++;
dev_kfree_skb(priv->tx_skb);
if (priv->tx_len)
can_free_echo_skb(priv->net, 0);
can_free_echo_skb(priv->net, 0, NULL);
priv->tx_skb = NULL;
priv->tx_len = 0;
}
......
......@@ -3,6 +3,7 @@
config CAN_MCP251XFD
tristate "Microchip MCP251xFD SPI CAN controllers"
select REGMAP
select WANT_DEV_COREDUMP
help
Driver for the Microchip MCP251XFD SPI FD-CAN controller
family.
......
......@@ -6,3 +6,6 @@ mcp251xfd-objs :=
mcp251xfd-objs += mcp251xfd-core.o
mcp251xfd-objs += mcp251xfd-crc16.o
mcp251xfd-objs += mcp251xfd-regmap.o
mcp251xfd-objs += mcp251xfd-timestamp.o
mcp251xfd-$(CONFIG_DEV_COREDUMP) += mcp251xfd-dump.o
......@@ -2,8 +2,8 @@
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2019, 2020 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (c) 2019, 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
// Based on:
//
......@@ -16,7 +16,6 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
......@@ -330,6 +329,7 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
struct mcp251xfd_tx_ring *tx_ring;
struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL;
struct mcp251xfd_tx_obj *tx_obj;
struct spi_transfer *xfer;
u32 val;
u16 addr;
u8 len;
......@@ -347,8 +347,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
addr, val, val);
for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) {
struct spi_transfer *xfer;
xfer = &tef_ring->uinc_xfer[j];
xfer->tx_buf = &tef_ring->uinc_buf;
xfer->len = len;
......@@ -357,6 +355,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
}
/* "cs_change == 1" on the last transfer results in an active
* chip select after the complete SPI message. This causes the
* controller to interpret the next register access as
* data. Set "cs_change" of the last transfer to "0" to
* properly deactivate the chip select at the end of the
* message.
*/
xfer->cs_change = 0;
/* TX */
tx_ring = priv->tx;
tx_ring->head = 0;
......@@ -397,8 +404,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
addr, val, val);
for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) {
struct spi_transfer *xfer;
xfer = &rx_ring->uinc_xfer[j];
xfer->tx_buf = &rx_ring->uinc_buf;
xfer->len = len;
......@@ -406,6 +411,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
xfer->cs_change_delay.value = 0;
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS;
}
/* "cs_change == 1" on the last transfer results in an
* active chip select after the complete SPI
* message. This causes the controller to interpret
* the next register access as data. Set "cs_change"
* of the last transfer to "0" to properly deactivate
* the chip select at the end of the message.
*/
xfer->cs_change = 0;
}
}
......@@ -1097,6 +1111,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
return 0;
out_chip_stop:
mcp251xfd_dump(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
return err;
......@@ -1250,7 +1265,8 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_tef_obj *hw_tef_obj)
{
struct net_device_stats *stats = &priv->ndev->stats;
u32 seq, seq_masked, tef_tail_masked;
struct sk_buff *skb;
u32 seq, seq_masked, tef_tail_masked, tef_tail;
seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
hw_tef_obj->flags);
......@@ -1266,9 +1282,13 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
if (seq_masked != tef_tail_masked)
return mcp251xfd_handle_tefif_recover(priv, seq);
tef_tail = mcp251xfd_get_tef_tail(priv);
skb = priv->can.echo_skb[tef_tail];
if (skb)
mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts);
stats->tx_bytes +=
can_rx_offload_get_echo_skb(&priv->offload,
mcp251xfd_get_tef_tail(priv),
tef_tail,
hw_tef_obj->ts, NULL);
stats->tx_packets++;
priv->tef->tail++;
......@@ -1365,25 +1385,20 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
if (len) {
struct mcp251xfd_tef_ring *ring = priv->tef;
struct mcp251xfd_tx_ring *tx_ring = priv->tx;
struct spi_transfer *last_xfer;
int offset;
/* Increment the TEF FIFO tail pointer 'len' times in
* a single SPI message.
*
* Note:
*
* "cs_change == 1" on the last transfer results in an
* active chip select after the complete SPI
* message. This causes the controller to interpret
* the next register access as data. Temporary set
* "cs_change" of the last transfer to "0" to properly
* deactivate the chip select at the end of the
* message.
* Calculate offset, so that the SPI transfer ends on
* the last message of the uinc_xfer array, which has
* "cs_change == 0", to properly deactivate the chip
* select.
*/
last_xfer = &ring->uinc_xfer[len - 1];
last_xfer->cs_change = 0;
err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len);
last_xfer->cs_change = 1;
offset = ARRAY_SIZE(ring->uinc_xfer) - len;
err = spi_sync_transfer(priv->spi,
ring->uinc_xfer + offset, len);
if (err)
return err;
......@@ -1432,7 +1447,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
}
static void
mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
mcp251xfd_hw_rx_obj_to_skb(struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
struct sk_buff *skb)
{
......@@ -1475,6 +1490,8 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
memcpy(cfd->data, hw_rx_obj->data, cfd->len);
mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
}
static int
......@@ -1535,7 +1552,7 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
return err;
while ((len = mcp251xfd_get_rx_linear_len(ring))) {
struct spi_transfer *last_xfer;
int offset;
rx_tail = mcp251xfd_get_rx_tail(ring);
......@@ -1556,19 +1573,14 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
* single SPI message.
*
* Note:
*
* "cs_change == 1" on the last transfer results in an
* active chip select after the complete SPI
* message. This causes the controller to interpret
* the next register access as data. Temporary set
* "cs_change" of the last transfer to "0" to properly
* deactivate the chip select at the end of the
* message.
* Calculate offset, so that the SPI transfer ends on
* the last message of the uinc_xfer array, which has
* "cs_change == 0", to properly deactivate the chip
* select.
*/
last_xfer = &ring->uinc_xfer[len - 1];
last_xfer->cs_change = 0;
err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len);
last_xfer->cs_change = 1;
offset = ARRAY_SIZE(ring->uinc_xfer) - len;
err = spi_sync_transfer(priv->spi,
ring->uinc_xfer + offset, len);
if (err)
return err;
......@@ -1592,23 +1604,22 @@ static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
return 0;
}
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv,
u32 *timestamp)
{
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp);
}
static struct sk_buff *
mcp251xfd_alloc_can_err_skb(const struct mcp251xfd_priv *priv,
mcp251xfd_alloc_can_err_skb(struct mcp251xfd_priv *priv,
struct can_frame **cf, u32 *timestamp)
{
struct sk_buff *skb;
int err;
err = mcp251xfd_get_timestamp(priv, timestamp);
if (err)
return NULL;
return alloc_can_err_skb(priv->ndev, cf);
skb = alloc_can_err_skb(priv->ndev, cf);
if (skb)
mcp251xfd_skb_set_timestamp(priv, skb, *timestamp);
return skb;
}
static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
......@@ -1760,6 +1771,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
if (!cf)
return 0;
mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
if (err)
stats->rx_fifo_errors++;
......@@ -2277,6 +2289,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
out_fail:
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
err, priv->regs_status.intf);
mcp251xfd_dump(priv);
mcp251xfd_chip_interrupts_disable(priv);
return handled;
......@@ -2493,6 +2506,7 @@ static int mcp251xfd_open(struct net_device *ndev)
if (err)
goto out_transceiver_disable;
mcp251xfd_timestamp_init(priv);
can_rx_offload_enable(&priv->offload);
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
......@@ -2513,6 +2527,7 @@ static int mcp251xfd_open(struct net_device *ndev)
free_irq(spi->irq, priv);
out_can_rx_offload_disable:
can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
out_transceiver_disable:
mcp251xfd_transceiver_disable(priv);
out_mcp251xfd_ring_free:
......@@ -2534,6 +2549,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
mcp251xfd_chip_interrupts_disable(priv);
free_irq(ndev->irq, priv);
can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
mcp251xfd_transceiver_disable(priv);
mcp251xfd_ring_free(priv);
......
// SPDX-License-Identifier: GPL-2.0
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (C) 2015-2018 Etnaviv Project
//
#include <linux/devcoredump.h>
#include "mcp251xfd.h"
#include "mcp251xfd-dump.h"
struct mcp251xfd_dump_iter {
void *start;
struct mcp251xfd_dump_object_header *hdr;
void *data;
};
struct mcp251xfd_dump_reg_space {
u16 base;
u16 size;
};
struct mcp251xfd_dump_ring {
enum mcp251xfd_dump_object_ring_key key;
u32 val;
};
static const struct mcp251xfd_dump_reg_space mcp251xfd_dump_reg_space[] = {
{
.base = MCP251XFD_REG_CON,
.size = MCP251XFD_REG_FLTOBJ(32) - MCP251XFD_REG_CON,
}, {
.base = MCP251XFD_RAM_START,
.size = MCP251XFD_RAM_SIZE,
}, {
.base = MCP251XFD_REG_OSC,
.size = MCP251XFD_REG_DEVID - MCP251XFD_REG_OSC,
},
};
static void mcp251xfd_dump_header(struct mcp251xfd_dump_iter *iter,
enum mcp251xfd_dump_object_type object_type,
const void *data_end)
{
struct mcp251xfd_dump_object_header *hdr = iter->hdr;
unsigned int len;
len = data_end - iter->data;
if (!len)
return;
hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
hdr->type = cpu_to_le32(object_type);
hdr->offset = cpu_to_le32(iter->data - iter->start);
hdr->len = cpu_to_le32(len);
iter->hdr++;
iter->data += len;
}
static void mcp251xfd_dump_registers(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
const int val_bytes = regmap_get_val_bytes(priv->map_rx);
struct mcp251xfd_dump_object_reg *reg = iter->data;
unsigned int i, j;
int err;
for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++) {
const struct mcp251xfd_dump_reg_space *reg_space;
void *buf;
reg_space = &mcp251xfd_dump_reg_space[i];
buf = kmalloc(reg_space->size, GFP_KERNEL);
if (!buf)
goto out;
err = regmap_bulk_read(priv->map_reg, reg_space->base,
buf, reg_space->size / val_bytes);
if (err) {
kfree(buf);
continue;
}
for (j = 0; j < reg_space->size; j += sizeof(u32), reg++) {
reg->reg = cpu_to_le32(reg_space->base + j);
reg->val = cpu_to_le32p(buf + j);
}
kfree(buf);
}
out:
mcp251xfd_dump_header(iter, MCP251XFD_DUMP_OBJECT_TYPE_REG, reg);
}
static void mcp251xfd_dump_ring(struct mcp251xfd_dump_iter *iter,
enum mcp251xfd_dump_object_type object_type,
const struct mcp251xfd_dump_ring *dump_ring,
unsigned int len)
{
struct mcp251xfd_dump_object_reg *reg = iter->data;
unsigned int i;
for (i = 0; i < len; i++, reg++) {
reg->reg = cpu_to_le32(dump_ring[i].key);
reg->val = cpu_to_le32(dump_ring[i].val);
}
mcp251xfd_dump_header(iter, object_type, reg);
}
static void mcp251xfd_dump_tef_ring(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
const struct mcp251xfd_tef_ring *tef = priv->tef;
const struct mcp251xfd_tx_ring *tx = priv->tx;
const struct mcp251xfd_dump_ring dump_ring[] = {
{
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
.val = tef->head,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
.val = tef->tail,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
.val = tx->obj_num,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
.val = sizeof(struct mcp251xfd_hw_tef_obj),
},
};
mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TEF,
dump_ring, ARRAY_SIZE(dump_ring));
}
static void mcp251xfd_dump_rx_ring_one(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter,
const struct mcp251xfd_rx_ring *rx)
{
const struct mcp251xfd_dump_ring dump_ring[] = {
{
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
.val = rx->head,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
.val = rx->tail,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
.val = rx->base,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
.val = rx->nr,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
.val = rx->fifo_nr,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
.val = rx->obj_num,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
.val = rx->obj_size,
},
};
mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_RX,
dump_ring, ARRAY_SIZE(dump_ring));
}
static void mcp251xfd_dump_rx_ring(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
struct mcp251xfd_rx_ring *rx_ring;
unsigned int i;
mcp251xfd_for_each_rx_ring(priv, rx_ring, i)
mcp251xfd_dump_rx_ring_one(priv, iter, rx_ring);
}
static void mcp251xfd_dump_tx_ring(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
const struct mcp251xfd_tx_ring *tx = priv->tx;
const struct mcp251xfd_dump_ring dump_ring[] = {
{
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
.val = tx->head,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
.val = tx->tail,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
.val = tx->base,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
.val = 0,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
.val = MCP251XFD_TX_FIFO,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
.val = tx->obj_num,
}, {
.key = MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
.val = tx->obj_size,
},
};
mcp251xfd_dump_ring(iter, MCP251XFD_DUMP_OBJECT_TYPE_TX,
dump_ring, ARRAY_SIZE(dump_ring));
}
static void mcp251xfd_dump_end(const struct mcp251xfd_priv *priv,
struct mcp251xfd_dump_iter *iter)
{
struct mcp251xfd_dump_object_header *hdr = iter->hdr;
hdr->magic = cpu_to_le32(MCP251XFD_DUMP_MAGIC);
hdr->type = cpu_to_le32(MCP251XFD_DUMP_OBJECT_TYPE_END);
hdr->offset = cpu_to_le32(0);
hdr->len = cpu_to_le32(0);
/* provoke NULL pointer access, if used after END object */
iter->hdr = NULL;
}
void mcp251xfd_dump(const struct mcp251xfd_priv *priv)
{
struct mcp251xfd_dump_iter iter;
unsigned int rings_num, obj_num;
unsigned int file_size = 0;
unsigned int i;
/* register space + end marker */
obj_num = 2;
/* register space */
for (i = 0; i < ARRAY_SIZE(mcp251xfd_dump_reg_space); i++)
file_size += mcp251xfd_dump_reg_space[i].size / sizeof(u32) *
sizeof(struct mcp251xfd_dump_object_reg);
/* TEF ring, RX ring, TX rings */
rings_num = 1 + priv->rx_ring_num + 1;
obj_num += rings_num;
file_size += rings_num * __MCP251XFD_DUMP_OBJECT_RING_KEY_MAX *
sizeof(struct mcp251xfd_dump_object_reg);
/* size of the headers */
file_size += sizeof(*iter.hdr) * obj_num;
/* allocate the file in vmalloc memory, it's likely to be big */
iter.start = __vmalloc(file_size, GFP_KERNEL | __GFP_NOWARN |
__GFP_ZERO | __GFP_NORETRY);
if (!iter.start) {
netdev_warn(priv->ndev, "Failed to allocate devcoredump file.\n");
return;
}
/* point the data member after the headers */
iter.hdr = iter.start;
iter.data = &iter.hdr[obj_num];
mcp251xfd_dump_registers(priv, &iter);
mcp251xfd_dump_tef_ring(priv, &iter);
mcp251xfd_dump_rx_ring(priv, &iter);
mcp251xfd_dump_tx_ring(priv, &iter);
mcp251xfd_dump_end(priv, &iter);
dev_coredumpv(&priv->spi->dev, iter.start,
iter.data - iter.start, GFP_KERNEL);
}
/* SPDX-License-Identifier: GPL-2.0
*
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
*
* Copyright (c) 2019, 2020, 2021 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
*/
#ifndef _MCP251XFD_DUMP_H
#define _MCP251XFD_DUMP_H
#define MCP251XFD_DUMP_MAGIC 0x1825434d
enum mcp251xfd_dump_object_type {
MCP251XFD_DUMP_OBJECT_TYPE_REG,
MCP251XFD_DUMP_OBJECT_TYPE_TEF,
MCP251XFD_DUMP_OBJECT_TYPE_RX,
MCP251XFD_DUMP_OBJECT_TYPE_TX,
MCP251XFD_DUMP_OBJECT_TYPE_END = -1,
};
enum mcp251xfd_dump_object_ring_key {
MCP251XFD_DUMP_OBJECT_RING_KEY_HEAD,
MCP251XFD_DUMP_OBJECT_RING_KEY_TAIL,
MCP251XFD_DUMP_OBJECT_RING_KEY_BASE,
MCP251XFD_DUMP_OBJECT_RING_KEY_NR,
MCP251XFD_DUMP_OBJECT_RING_KEY_FIFO_NR,
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_NUM,
MCP251XFD_DUMP_OBJECT_RING_KEY_OBJ_SIZE,
__MCP251XFD_DUMP_OBJECT_RING_KEY_MAX,
};
struct mcp251xfd_dump_object_header {
__le32 magic;
__le32 type;
__le32 offset;
__le32 len;
};
struct mcp251xfd_dump_object_reg {
__le32 reg;
__le32 val;
};
#endif
// SPDX-License-Identifier: GPL-2.0
//
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
//
// Copyright (c) 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de>
//
#include <linux/clocksource.h>
#include <linux/workqueue.h>
#include "mcp251xfd.h"
static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc)
{
struct mcp251xfd_priv *priv;
u32 timestamp = 0;
int err;
priv = container_of(cc, struct mcp251xfd_priv, cc);
err = mcp251xfd_get_timestamp(priv, &timestamp);
if (err)
netdev_err(priv->ndev,
"Error %d while reading timestamp. HW timestamps may be inaccurate.",
err);
return timestamp;
}
static void mcp251xfd_timestamp_work(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
struct mcp251xfd_priv *priv;
priv = container_of(delayed_work, struct mcp251xfd_priv, timestamp);
timecounter_read(&priv->tc);
schedule_delayed_work(&priv->timestamp,
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
}
void mcp251xfd_skb_set_timestamp(struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp)
{
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
u64 ns;
ns = timecounter_cyc2time(&priv->tc, timestamp);
hwtstamps->hwtstamp = ns_to_ktime(ns);
}
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv)
{
struct cyclecounter *cc = &priv->cc;
cc->read = mcp251xfd_timestamp_read;
cc->mask = CYCLECOUNTER_MASK(32);
cc->shift = 1;
cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift);
timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns());
INIT_DELAYED_WORK(&priv->timestamp, mcp251xfd_timestamp_work);
schedule_delayed_work(&priv->timestamp,
MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ);
}
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv)
{
cancel_delayed_work_sync(&priv->timestamp);
}
......@@ -15,9 +15,12 @@
#include <linux/can/rx-offload.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/timecounter.h>
#include <linux/workqueue.h>
/* MPC251x registers */
......@@ -394,6 +397,9 @@
#define MCP251XFD_SYSCLOCK_HZ_MAX 40000000
#define MCP251XFD_SYSCLOCK_HZ_MIN 1000000
#define MCP251XFD_SPICLOCK_HZ_MAX 20000000
#define MCP251XFD_TIMESTAMP_WORK_DELAY_SEC 45
static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
CYCLECOUNTER_MASK(32) / MCP251XFD_SYSCLOCK_HZ_MAX / 2);
#define MCP251XFD_OSC_PLL_MULTIPLIER 10
#define MCP251XFD_OSC_STAB_SLEEP_US (3 * USEC_PER_MSEC)
#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
......@@ -595,6 +601,10 @@ struct mcp251xfd_priv {
struct mcp251xfd_ecc ecc;
struct mcp251xfd_regs_status regs_status;
struct cyclecounter cc;
struct timecounter tc;
struct delayed_work timestamp;
struct gpio_desc *rx_int;
struct clk *clk;
struct regulator *reg_vdd;
......@@ -727,6 +737,12 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
return data;
}
static inline int mcp251xfd_get_timestamp(const struct mcp251xfd_priv *priv,
u32 *timestamp)
{
return regmap_read(priv->map_reg, MCP251XFD_REG_TBC, timestamp);
}
static inline u16 mcp251xfd_get_tef_obj_addr(u8 n)
{
return MCP251XFD_RAM_START +
......@@ -837,5 +853,17 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv);
u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
const void *data, size_t data_size);
u16 mcp251xfd_crc16_compute(const void *data, size_t data_size);
void mcp251xfd_skb_set_timestamp(struct mcp251xfd_priv *priv,
struct sk_buff *skb, u32 timestamp);
void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv);
void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv);
#if IS_ENABLED(CONFIG_DEV_COREDUMP)
void mcp251xfd_dump(const struct mcp251xfd_priv *priv);
#else
static inline void mcp251xfd_dump(const struct mcp251xfd_priv *priv)
{
}
#endif
#endif
......@@ -807,7 +807,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err)) {
can_free_echo_skb(netdev, context->echo_index);
can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma);
......
......@@ -360,7 +360,7 @@ static void esd_usb2_tx_done_msg(struct esd_usb2_net_priv *priv,
can_get_echo_skb(netdev, context->echo_index, NULL);
} else {
stats->tx_errors++;
can_free_echo_skb(netdev, context->echo_index);
can_free_echo_skb(netdev, context->echo_index, NULL);
}
/* Release context */
......@@ -793,7 +793,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
can_free_echo_skb(netdev, context->echo_index);
can_free_echo_skb(netdev, context->echo_index, NULL);
atomic_dec(&priv->active_tx_jobs);
usb_unanchor_urb(urb);
......
......@@ -533,7 +533,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
if (unlikely(rc)) { /* usb send failed */
atomic_dec(&dev->active_tx_urbs);
can_free_echo_skb(netdev, idx);
can_free_echo_skb(netdev, idx, NULL);
gs_free_tx_context(txc);
usb_unanchor_urb(urb);
......
......@@ -593,7 +593,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
if (unlikely(err)) {
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
can_free_echo_skb(netdev, context->echo_index);
can_free_echo_skb(netdev, context->echo_index, NULL);
context->echo_index = dev->max_tx_urbs;
--priv->active_tx_contexts;
netif_wake_queue(netdev);
......
......@@ -364,7 +364,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
xmit_failed:
can_free_echo_skb(priv->netdev, ctx->ndx);
can_free_echo_skb(priv->netdev, ctx->ndx, NULL);
mcba_usb_free_ctx(ctx);
dev_kfree_skb(skb);
stats->tx_dropped++;
......
......@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h>
#include <linux/can/dev.h>
......@@ -40,6 +41,7 @@
#define PCAN_USB_CMD_REGISTER 9
#define PCAN_USB_CMD_EXT_VCC 10
#define PCAN_USB_CMD_ERR_FR 11
#define PCAN_USB_CMD_LED 12
/* PCAN_USB_CMD_SET_BUS number arg */
#define PCAN_USB_BUS_XCVER 2
......@@ -248,6 +250,15 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff)
return pcan_usb_send_cmd(dev, PCAN_USB_CMD_EXT_VCC, PCAN_USB_SET, args);
}
static int pcan_usb_set_led(struct peak_usb_device *dev, u8 onoff)
{
u8 args[PCAN_USB_CMD_ARGS_LEN] = {
[0] = !!onoff,
};
return pcan_usb_send_cmd(dev, PCAN_USB_CMD_LED, PCAN_USB_SET, args);
}
/*
* set bittiming value to can
*/
......@@ -971,6 +982,40 @@ static int pcan_usb_probe(struct usb_interface *intf)
return 0;
}
static int pcan_usb_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
/* call ON/OFF twice a second */
return 2;
case ETHTOOL_ID_OFF:
err = pcan_usb_set_led(dev, 0);
break;
case ETHTOOL_ID_ON:
fallthrough;
case ETHTOOL_ID_INACTIVE:
/* restore LED default */
err = pcan_usb_set_led(dev, 1);
break;
default:
break;
}
return err;
}
static const struct ethtool_ops pcan_usb_ethtool_ops = {
.set_phys_id = pcan_usb_set_phys_id,
};
/*
* describe the PCAN-USB adapter
*/
......@@ -1001,6 +1046,8 @@ const struct peak_usb_adapter pcan_usb = {
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb),
.ethtool_ops = &pcan_usb_ethtool_ops,
/* timestamps usage */
.ts_used_bits = 16,
.ts_period = 24575, /* calibration period in ts. */
......
......@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/ethtool.h>
#include <linux/can.h>
#include <linux/can/dev.h>
......@@ -371,7 +372,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
can_free_echo_skb(netdev, context->echo_index);
can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb);
......@@ -820,6 +821,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
netdev->flags |= IFF_ECHO; /* we support local echo */
/* add ethtool support */
netdev->ethtool_ops = peak_usb_adapter->ethtool_ops;
init_usb_anchor(&dev->rx_submitted);
init_usb_anchor(&dev->tx_submitted);
......
......@@ -46,6 +46,8 @@ struct peak_usb_adapter {
const struct can_bittiming_const * const data_bittiming_const;
unsigned int ctrl_count;
const struct ethtool_ops *ethtool_ops;
int (*intf_probe)(struct usb_interface *intf);
int (*dev_init)(struct peak_usb_device *dev);
......
......@@ -7,6 +7,7 @@
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h>
#include <linux/can/dev.h>
......@@ -773,6 +774,10 @@ static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev,
tx_msg_flags |= PUCAN_MSG_RTR;
}
/* Single-Shot frame */
if (dev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
tx_msg_flags |= PUCAN_MSG_SINGLE_SHOT;
tx_msg->flags = cpu_to_le16(tx_msg_flags);
tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, dlc);
memcpy(tx_msg->d, cfd->data, cfd->len);
......@@ -1006,6 +1011,31 @@ static void pcan_usb_fd_free(struct peak_usb_device *dev)
}
}
/* blink LED's */
static int pcan_usb_fd_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
err = pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_FAST);
break;
case ETHTOOL_ID_INACTIVE:
err = pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF);
break;
default:
break;
}
return err;
}
static const struct ethtool_ops pcan_usb_fd_ethtool_ops = {
.set_phys_id = pcan_usb_fd_set_phys_id,
};
/* describes the PCAN-USB FD adapter */
static const struct can_bittiming_const pcan_usb_fd_const = {
.name = "pcan_usb_fd",
......@@ -1037,7 +1067,7 @@ const struct peak_usb_adapter pcan_usb_fd = {
.ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC,
CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = {
.freq = PCAN_UFD_CRYSTAL_HZ,
},
......@@ -1047,6 +1077,8 @@ const struct peak_usb_adapter pcan_usb_fd = {
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
......@@ -1110,7 +1142,7 @@ const struct peak_usb_adapter pcan_usb_chip = {
.ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC,
CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = {
.freq = PCAN_UFD_CRYSTAL_HZ,
},
......@@ -1120,6 +1152,8 @@ const struct peak_usb_adapter pcan_usb_chip = {
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
......@@ -1183,7 +1217,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC,
CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = {
.freq = PCAN_UFD_CRYSTAL_HZ,
},
......@@ -1193,6 +1227,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
......@@ -1256,7 +1292,7 @@ const struct peak_usb_adapter pcan_usb_x6 = {
.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC,
CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = {
.freq = PCAN_UFD_CRYSTAL_HZ,
},
......@@ -1266,6 +1302,8 @@ const struct peak_usb_adapter pcan_usb_x6 = {
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
......
......@@ -9,6 +9,7 @@
#include <linux/netdevice.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h>
#include <linux/can/dev.h>
......@@ -36,6 +37,7 @@
#define PCAN_USBPRO_RTR 0x01
#define PCAN_USBPRO_EXT 0x02
#define PCAN_USBPRO_SS 0x08
#define PCAN_USBPRO_CMD_BUFFER_SIZE 512
......@@ -776,9 +778,13 @@ static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev,
flags = 0;
if (cf->can_id & CAN_EFF_FLAG)
flags |= 0x02;
flags |= PCAN_USBPRO_EXT;
if (cf->can_id & CAN_RTR_FLAG)
flags |= 0x01;
flags |= PCAN_USBPRO_RTR;
/* Single-Shot frame */
if (dev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
flags |= PCAN_USBPRO_SS;
pcan_msg_add_rec(&usb_msg, data_type, 0, flags, len, cf->can_id,
cf->data);
......@@ -906,7 +912,7 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
usb_if->dev[dev->ctrl_idx] = dev;
/* set LED in default state (end of init phase) */
pcan_usb_pro_set_led(dev, 0, 1);
pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
kfree(bi);
kfree(fi);
......@@ -990,6 +996,35 @@ int pcan_usb_pro_probe(struct usb_interface *intf)
return 0;
}
static int pcan_usb_pro_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct peak_usb_device *dev = netdev_priv(netdev);
int err = 0;
switch (state) {
case ETHTOOL_ID_ACTIVE:
/* fast blinking forever */
err = pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_BLINK_FAST,
0xffffffff);
break;
case ETHTOOL_ID_INACTIVE:
/* restore LED default */
err = pcan_usb_pro_set_led(dev, PCAN_USBPRO_LED_DEVICE, 1);
break;
default:
break;
}
return err;
}
static const struct ethtool_ops pcan_usb_pro_ethtool_ops = {
.set_phys_id = pcan_usb_pro_set_phys_id,
};
/*
* describe the PCAN-USB Pro adapter
*/
......@@ -1009,7 +1044,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
.name = "PCAN-USB Pro",
.device_id = PCAN_USBPRO_PRODUCT_ID,
.ctrl_count = PCAN_USBPRO_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY,
.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_ONE_SHOT,
.clock = {
.freq = PCAN_USBPRO_CRYSTAL_HZ,
},
......@@ -1018,6 +1054,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
/* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_pro_device),
.ethtool_ops = &pcan_usb_pro_ethtool_ops,
/* timestamps usage */
.ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */
......
......@@ -115,6 +115,12 @@ struct __packed pcan_usb_pro_devid {
__le32 serial_num;
};
#define PCAN_USBPRO_LED_DEVICE 0x00
#define PCAN_USBPRO_LED_BLINK_FAST 0x01
#define PCAN_USBPRO_LED_BLINK_SLOW 0x02
#define PCAN_USBPRO_LED_ON 0x03
#define PCAN_USBPRO_LED_OFF 0x04
struct __packed pcan_usb_pro_setled {
u8 data_type;
u8 channel;
......
......@@ -246,7 +246,7 @@ struct ucan_message_in {
*/
struct ucan_tx_complete_entry_t can_tx_complete_msg[0];
} __aligned(0x4) msg;
} __packed;
} __packed __aligned(0x4);
/* Macros to calculate message lengths */
#define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg)
......@@ -675,7 +675,7 @@ static void ucan_tx_complete_msg(struct ucan_priv *up,
can_get_echo_skb(up->netdev, echo_index, NULL);
} else {
up->netdev->stats.tx_dropped++;
can_free_echo_skb(up->netdev, echo_index);
can_free_echo_skb(up->netdev, echo_index, NULL);
}
spin_unlock_irqrestore(&up->echo_skb_lock, flags);
}
......@@ -843,7 +843,7 @@ static void ucan_write_bulk_callback(struct urb *urb)
/* update counters an cleanup */
spin_lock_irqsave(&up->echo_skb_lock, flags);
can_free_echo_skb(up->netdev, context - up->context_array);
can_free_echo_skb(up->netdev, context - up->context_array, NULL);
spin_unlock_irqrestore(&up->echo_skb_lock, flags);
up->netdev->stats.tx_dropped++;
......@@ -1157,7 +1157,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
* frees the skb
*/
spin_lock_irqsave(&up->echo_skb_lock, flags);
can_free_echo_skb(up->netdev, echo_index);
can_free_echo_skb(up->netdev, echo_index, NULL);
spin_unlock_irqrestore(&up->echo_skb_lock, flags);
if (ret == -ENODEV) {
......
......@@ -691,7 +691,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
failed:
can_free_echo_skb(netdev, context->echo_index);
can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
......
......@@ -1772,17 +1772,15 @@ static int xcan_probe(struct platform_device *pdev)
/* Getting the CAN can_clk info */
priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
if (IS_ERR(priv->can_clk)) {
if (PTR_ERR(priv->can_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "Device clock not found.\n");
ret = PTR_ERR(priv->can_clk);
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
"device clock not found\n");
goto err_free;
}
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) {
if (PTR_ERR(priv->bus_clk) != -EPROBE_DEFER)
dev_err(&pdev->dev, "bus clock not found\n");
ret = PTR_ERR(priv->bus_clk);
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
"bus clock not found\n");
goto err_free;
}
......
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
* Copyright (c) 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/
#ifndef _CAN_BITTIMING_H
......@@ -10,9 +11,83 @@
#define CAN_SYNC_SEG 1
/* Kilobits and Megabits per second */
#define CAN_KBPS 1000UL
#define CAN_MBPS 1000000UL
/* Megahertz */
#define CAN_MHZ 1000000UL
/*
* struct can_tdc - CAN FD Transmission Delay Compensation parameters
*
* At high bit rates, the propagation delay from the TX pin to the RX
* pin of the transceiver causes measurement errors: the sample point
* on the RX pin might occur on the previous bit.
*
* To solve this issue, ISO 11898-1 introduces in section 11.3.3
* "Transmitter delay compensation" a SSP (Secondary Sample Point)
* equal to the distance, in time quanta, from the start of the bit
* time on the TX pin to the actual measurement on the RX pin.
*
* This structure contains the parameters to calculate that SSP.
*
* @tdcv: Transmitter Delay Compensation Value. Distance, in time
* quanta, from when the bit is sent on the TX pin to when it is
* received on the RX pin of the transmitter. Possible options:
*
* O: automatic mode. The controller dynamically measure @tdcv
* for each transmitted CAN FD frame.
*
* Other values: manual mode. Use the fixed provided value.
*
* @tdco: Transmitter Delay Compensation Offset. Offset value, in time
* quanta, defining the distance between the start of the bit
* reception on the RX pin of the transceiver and the SSP
* position such as SSP = @tdcv + @tdco.
*
* If @tdco is zero, then TDC is disabled and both @tdcv and
* @tdcf should be ignored.
*
* @tdcf: Transmitter Delay Compensation Filter window. Defines the
* minimum value for the SSP position in time quanta. If SSP is
* less than @tdcf, then no delay compensations occur and the
* normal sampling point is used instead. The feature is enabled
* if and only if @tdcv is set to zero (automatic mode) and @tdcf
* is configured to a value greater than @tdco.
*/
struct can_tdc {
u32 tdcv;
u32 tdco;
u32 tdcf;
};
/*
* struct can_tdc_const - CAN hardware-dependent constant for
* Transmission Delay Compensation
*
* @tdcv_max: Transmitter Delay Compensation Value maximum value.
* Should be set to zero if the controller does not support
* manual mode for tdcv.
* @tdco_max: Transmitter Delay Compensation Offset maximum value.
* Should not be zero. If the controller does not support TDC,
* then the pointer to this structure should be NULL.
* @tdcf_max: Transmitter Delay Compensation Filter window maximum
* value. Should be set to zero if the controller does not
* support this feature.
*/
struct can_tdc_const {
u32 tdcv_max;
u32 tdco_max;
u32 tdcf_max;
};
#ifdef CONFIG_CAN_CALC_BITTIMING
int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc);
void can_calc_tdco(struct net_device *dev);
#else /* !CONFIG_CAN_CALC_BITTIMING */
static inline int
can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
......@@ -21,6 +96,10 @@ can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
netdev_err(dev, "bit-timing calculation not available\n");
return -EINVAL;
}
static inline void can_calc_tdco(struct net_device *dev)
{
}
#endif /* CONFIG_CAN_CALC_BITTIMING */
int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
......
......@@ -39,19 +39,23 @@ struct can_priv {
struct net_device *dev;
struct can_device_stats can_stats;
struct can_bittiming bittiming, data_bittiming;
const struct can_bittiming_const *bittiming_const,
*data_bittiming_const;
const u16 *termination_const;
unsigned int termination_const_cnt;
u16 termination;
const u32 *bitrate_const;
struct can_bittiming bittiming, data_bittiming;
const struct can_tdc_const *tdc_const;
struct can_tdc tdc;
unsigned int bitrate_const_cnt;
const u32 *bitrate_const;
const u32 *data_bitrate_const;
unsigned int data_bitrate_const_cnt;
u32 bitrate_max;
struct can_clock clock;
unsigned int termination_const_cnt;
const u16 *termination_const;
u16 termination;
enum can_state state;
/* CAN controller features - see include/uapi/linux/can/netlink.h */
......
......@@ -23,7 +23,8 @@ struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
u8 *len_ptr, unsigned int *frame_len_ptr);
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr);
void can_free_echo_skb(struct net_device *dev, unsigned int idx);
void can_free_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr);
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
struct canfd_frame **cfd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment