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 ...@@ -10910,8 +10910,7 @@ T: git git://linuxtv.org/media_tree.git
F: drivers/media/radio/radio-maxiradio* F: drivers/media/radio/radio-maxiradio*
MCAN MMIO DEVICE DRIVER MCAN MMIO DEVICE DRIVER
M: Dan Murphy <dmurphy@ti.com> M: Chandrasekar Ramakrishnan <rcsekar@samsung.com>
M: Pankaj Sharma <pankj.sharma@samsung.com>
L: linux-can@vger.kernel.org L: linux-can@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml F: Documentation/devicetree/bindings/net/can/bosch,m_can.yaml
...@@ -17983,13 +17982,6 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) ...@@ -17983,13 +17982,6 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Odd Fixes S: Odd Fixes
F: sound/soc/codecs/tas571x* 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 TI TRF7970A NFC DRIVER
M: Mark Greer <mgreer@animalcreek.com> M: Mark Greer <mgreer@animalcreek.com>
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
......
...@@ -103,7 +103,7 @@ config CAN_FLEXCAN ...@@ -103,7 +103,7 @@ config CAN_FLEXCAN
config CAN_GRCAN config CAN_GRCAN
tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices" tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices"
depends on OF && HAS_DMA depends on OF && HAS_DMA && HAS_IOMEM
help help
Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN. Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN.
Note that the driver supports little endian, even though little Note that the driver supports little endian, even though little
......
This diff is collapsed.
...@@ -22,23 +22,6 @@ ...@@ -22,23 +22,6 @@
#ifndef C_CAN_H #ifndef C_CAN_H
#define 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 { enum reg {
C_CAN_CTRL_REG = 0, C_CAN_CTRL_REG = 0,
C_CAN_CTRL_EX_REG, C_CAN_CTRL_EX_REG,
...@@ -76,6 +59,7 @@ enum reg { ...@@ -76,6 +59,7 @@ enum reg {
C_CAN_NEWDAT2_REG, C_CAN_NEWDAT2_REG,
C_CAN_INTPND1_REG, C_CAN_INTPND1_REG,
C_CAN_INTPND2_REG, C_CAN_INTPND2_REG,
C_CAN_INTPND3_REG,
C_CAN_MSGVAL1_REG, C_CAN_MSGVAL1_REG,
C_CAN_MSGVAL2_REG, C_CAN_MSGVAL2_REG,
C_CAN_FUNCTION_REG, C_CAN_FUNCTION_REG,
...@@ -137,6 +121,7 @@ static const u16 __maybe_unused reg_map_d_can[] = { ...@@ -137,6 +121,7 @@ static const u16 __maybe_unused reg_map_d_can[] = {
[C_CAN_NEWDAT2_REG] = 0x9E, [C_CAN_NEWDAT2_REG] = 0x9E,
[C_CAN_INTPND1_REG] = 0xB0, [C_CAN_INTPND1_REG] = 0xB0,
[C_CAN_INTPND2_REG] = 0xB2, [C_CAN_INTPND2_REG] = 0xB2,
[C_CAN_INTPND3_REG] = 0xB4,
[C_CAN_MSGVAL1_REG] = 0xC4, [C_CAN_MSGVAL1_REG] = 0xC4,
[C_CAN_MSGVAL2_REG] = 0xC6, [C_CAN_MSGVAL2_REG] = 0xC6,
[C_CAN_IF1_COMREQ_REG] = 0x100, [C_CAN_IF1_COMREQ_REG] = 0x100,
...@@ -176,6 +161,7 @@ struct raminit_bits { ...@@ -176,6 +161,7 @@ struct raminit_bits {
struct c_can_driver_data { struct c_can_driver_data {
enum c_can_dev_id id; enum c_can_dev_id id;
unsigned int msg_obj_num;
/* RAMINIT register description. Optional. */ /* RAMINIT register description. Optional. */
const struct raminit_bits *raminit_bits; /* Array of START/DONE bit positions */ const struct raminit_bits *raminit_bits; /* Array of START/DONE bit positions */
...@@ -197,26 +183,34 @@ struct c_can_priv { ...@@ -197,26 +183,34 @@ struct c_can_priv {
struct napi_struct napi; struct napi_struct napi;
struct net_device *dev; struct net_device *dev;
struct device *device; 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 tx_active;
atomic_t sie_pending; atomic_t sie_pending;
unsigned long tx_dir; unsigned long tx_dir;
int last_status; int last_status;
u16 (*read_reg) (const struct c_can_priv *priv, enum reg index); 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); 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); 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 (*write_reg32)(const struct c_can_priv *priv, enum reg index, u32 val);
void __iomem *base; void __iomem *base;
const u16 *regs; const u16 *regs;
void *priv; /* for board-specific data */ void *priv; /* for board-specific data */
enum c_can_dev_id type; enum c_can_dev_id type;
struct c_can_raminit raminit_sys; /* RAMINIT via syscon regmap */ 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 comm_rcv_high;
u32 rxmasked; 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); void free_c_can_dev(struct net_device *dev);
int register_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); void unregister_c_can_dev(struct net_device *dev);
......
...@@ -31,6 +31,8 @@ enum c_can_pci_reg_align { ...@@ -31,6 +31,8 @@ enum c_can_pci_reg_align {
struct c_can_pci_data { struct c_can_pci_data {
/* Specify if is C_CAN or D_CAN */ /* Specify if is C_CAN or D_CAN */
enum c_can_dev_id type; enum c_can_dev_id type;
/* Number of message objects */
unsigned int msg_obj_num;
/* Set the register alignment in the memory */ /* Set the register alignment in the memory */
enum c_can_pci_reg_align reg_align; enum c_can_pci_reg_align reg_align;
/* Set the frequency */ /* Set the frequency */
...@@ -41,8 +43,7 @@ struct c_can_pci_data { ...@@ -41,8 +43,7 @@ struct c_can_pci_data {
void (*init)(const struct c_can_priv *priv, bool enable); 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 * architecture of different implementations. For example: 16-bit
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc. * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface. * Handle the same by providing a common read/write interface.
...@@ -88,7 +89,7 @@ static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index) ...@@ -88,7 +89,7 @@ static u32 c_can_pci_read_reg32(const struct c_can_priv *priv, enum reg index)
u32 val; u32 val;
val = priv->read_reg(priv, index); 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; return val;
} }
...@@ -142,14 +143,13 @@ static int c_can_pci_probe(struct pci_dev *pdev, ...@@ -142,14 +143,13 @@ static int c_can_pci_probe(struct pci_dev *pdev,
pci_resource_len(pdev, c_can_pci_data->bar)); pci_resource_len(pdev, c_can_pci_data->bar));
if (!addr) { if (!addr) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"device has no PCI memory resources, " "device has no PCI memory resources, failing adapter\n");
"failing adapter\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out_release_regions; goto out_release_regions;
} }
/* allocate the c_can device */ /* allocate the c_can device */
dev = alloc_c_can_dev(); dev = alloc_c_can_dev(c_can_pci_data->msg_obj_num);
if (!dev) { if (!dev) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_iounmap; goto out_iounmap;
...@@ -252,8 +252,9 @@ static void c_can_pci_remove(struct pci_dev *pdev) ...@@ -252,8 +252,9 @@ static void c_can_pci_remove(struct pci_dev *pdev)
pci_disable_device(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, .type = BOSCH_C_CAN,
.msg_obj_num = 32,
.reg_align = C_CAN_REG_ALIGN_32, .reg_align = C_CAN_REG_ALIGN_32,
.freq = 52000000, /* 52 Mhz */ .freq = 52000000, /* 52 Mhz */
.bar = 0, .bar = 0,
...@@ -261,6 +262,7 @@ static const struct c_can_pci_data c_can_sta2x11= { ...@@ -261,6 +262,7 @@ static const struct c_can_pci_data c_can_sta2x11= {
static const struct c_can_pci_data c_can_pch = { static const struct c_can_pci_data c_can_pch = {
.type = BOSCH_C_CAN, .type = BOSCH_C_CAN,
.msg_obj_num = 32,
.reg_align = C_CAN_REG_32, .reg_align = C_CAN_REG_32,
.freq = 50000000, /* 50 MHz */ .freq = 50000000, /* 50 MHz */
.init = c_can_pci_reset_pch, .init = c_can_pci_reset_pch,
...@@ -269,7 +271,7 @@ static const struct c_can_pci_data c_can_pch = { ...@@ -269,7 +271,7 @@ static const struct c_can_pci_data c_can_pch = {
#define C_CAN_ID(_vend, _dev, _driverdata) { \ #define C_CAN_ID(_vend, _dev, _driverdata) { \
PCI_DEVICE(_vend, _dev), \ PCI_DEVICE(_vend, _dev), \
.driver_data = (unsigned long)&_driverdata, \ .driver_data = (unsigned long)&(_driverdata), \
} }
static const struct pci_device_id c_can_pci_tbl[] = { static const struct pci_device_id c_can_pci_tbl[] = {
...@@ -279,6 +281,7 @@ 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), c_can_pch),
{}, {},
}; };
static struct pci_driver c_can_pci_driver = { static struct pci_driver c_can_pci_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.id_table = c_can_pci_tbl, .id_table = c_can_pci_tbl,
......
...@@ -193,10 +193,12 @@ static void c_can_hw_raminit(const struct c_can_priv *priv, bool enable) ...@@ -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 = { static const struct c_can_driver_data c_can_drvdata = {
.id = BOSCH_C_CAN, .id = BOSCH_C_CAN,
.msg_obj_num = 32,
}; };
static const struct c_can_driver_data d_can_drvdata = { static const struct c_can_driver_data d_can_drvdata = {
.id = BOSCH_D_CAN, .id = BOSCH_D_CAN,
.msg_obj_num = 32,
}; };
static const struct raminit_bits dra7_raminit_bits[] = { static const struct raminit_bits dra7_raminit_bits[] = {
...@@ -206,6 +208,7 @@ 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 = { static const struct c_can_driver_data dra7_dcan_drvdata = {
.id = BOSCH_D_CAN, .id = BOSCH_D_CAN,
.msg_obj_num = 64,
.raminit_num = ARRAY_SIZE(dra7_raminit_bits), .raminit_num = ARRAY_SIZE(dra7_raminit_bits),
.raminit_bits = dra7_raminit_bits, .raminit_bits = dra7_raminit_bits,
.raminit_pulse = true, .raminit_pulse = true,
...@@ -218,6 +221,7 @@ static const struct raminit_bits am3352_raminit_bits[] = { ...@@ -218,6 +221,7 @@ static const struct raminit_bits am3352_raminit_bits[] = {
static const struct c_can_driver_data am3352_dcan_drvdata = { static const struct c_can_driver_data am3352_dcan_drvdata = {
.id = BOSCH_D_CAN, .id = BOSCH_D_CAN,
.msg_obj_num = 64,
.raminit_num = ARRAY_SIZE(am3352_raminit_bits), .raminit_num = ARRAY_SIZE(am3352_raminit_bits),
.raminit_bits = am3352_raminit_bits, .raminit_bits = am3352_raminit_bits,
}; };
...@@ -294,7 +298,7 @@ static int c_can_plat_probe(struct platform_device *pdev) ...@@ -294,7 +298,7 @@ static int c_can_plat_probe(struct platform_device *pdev)
} }
/* allocate the c_can device */ /* allocate the c_can device */
dev = alloc_c_can_dev(); dev = alloc_c_can_dev(drvdata->msg_obj_num);
if (!dev) { if (!dev) {
ret = -ENOMEM; ret = -ENOMEM;
goto exit; goto exit;
......
...@@ -81,9 +81,9 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -81,9 +81,9 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
if (bt->sample_point) { if (bt->sample_point) {
sample_point_nominal = bt->sample_point; sample_point_nominal = bt->sample_point;
} else { } else {
if (bt->bitrate > 800000) if (bt->bitrate > 800 * CAN_KBPS)
sample_point_nominal = 750; sample_point_nominal = 750;
else if (bt->bitrate > 500000) else if (bt->bitrate > 500 * CAN_KBPS)
sample_point_nominal = 800; sample_point_nominal = 800;
else else
sample_point_nominal = 875; sample_point_nominal = 875;
...@@ -174,6 +174,30 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, ...@@ -174,6 +174,30 @@ int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
return 0; 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 */ #endif /* CONFIG_CAN_CALC_BITTIMING */
/* Checks the validity of the specified bit-timing parameters prop_seg, /* Checks the validity of the specified bit-timing parameters prop_seg,
......
...@@ -13,14 +13,11 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { ...@@ -13,14 +13,11 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 }, [IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
[IFLA_CAN_RESTART] = { .type = NLA_U32 }, [IFLA_CAN_RESTART] = { .type = NLA_U32 },
[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
[IFLA_CAN_BITTIMING_CONST] [IFLA_CAN_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
[IFLA_CAN_DATA_BITTIMING] [IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) },
= { .len = sizeof(struct can_bittiming) }, [IFLA_CAN_DATA_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_DATA_BITTIMING_CONST]
= { .len = sizeof(struct can_bittiming_const) },
[IFLA_CAN_TERMINATION] = { .type = NLA_U16 }, [IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
}; };
...@@ -189,6 +186,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], ...@@ -189,6 +186,8 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
can_calc_tdco(dev);
if (priv->do_set_data_bittiming) { if (priv->do_set_data_bittiming) {
/* Finally, set the bit-timing registers */ /* Finally, set the bit-timing registers */
err = priv->do_set_data_bittiming(dev); err = priv->do_set_data_bittiming(dev);
......
...@@ -45,7 +45,7 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *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); BUG_ON(idx >= priv->echo_skb_max);
/* check flag whether this packet has to be looped back */ /* 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_CAN) &&
skb->protocol != htons(ETH_P_CANFD))) { skb->protocol != htons(ETH_P_CANFD))) {
kfree_skb(skb); kfree_skb(skb);
...@@ -58,7 +58,6 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -58,7 +58,6 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
return -ENOMEM; return -ENOMEM;
/* make settings for echo to reduce code in irq context */ /* make settings for echo to reduce code in irq context */
skb->pkt_type = PACKET_BROADCAST;
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb->dev = dev; skb->dev = dev;
...@@ -111,6 +110,13 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr, ...@@ -111,6 +110,13 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
priv->echo_skb[idx] = NULL; 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; return skb;
} }
...@@ -147,14 +153,25 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb); ...@@ -147,14 +153,25 @@ EXPORT_SYMBOL_GPL(can_get_echo_skb);
* *
* The function is typically called when TX failed. * 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); 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]) { 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; priv->echo_skb[idx] = NULL;
} }
} }
......
...@@ -520,7 +520,7 @@ static int catch_up_echo_skb(struct net_device *dev, int budget, bool echo) ...@@ -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); can_get_echo_skb(dev, i, NULL);
} else { } else {
/* For cleanup of untransmitted messages */ /* 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, priv->eskbp = grcan_ring_add(priv->eskbp, GRCAN_MSG_SIZE,
......
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/led.h> #include <linux/can/led.h>
#include <linux/can/rx-offload.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
...@@ -71,6 +72,7 @@ struct m_can_ops { ...@@ -71,6 +72,7 @@ struct m_can_ops {
struct m_can_classdev { struct m_can_classdev {
struct can_priv can; struct can_priv can;
struct can_rx_offload offload;
struct napi_struct napi; struct napi_struct napi;
struct net_device *net; struct net_device *net;
struct device *dev; struct device *dev;
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
......
...@@ -217,7 +217,7 @@ static void tx_failure_cleanup(struct net_device *ndev) ...@@ -217,7 +217,7 @@ static void tx_failure_cleanup(struct net_device *ndev)
int i; int i;
for (i = 0; i < RCAR_CAN_FIFO_DEPTH; 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) static void rcar_can_error(struct net_device *ndev)
......
...@@ -617,7 +617,7 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev) ...@@ -617,7 +617,7 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev)
u32 i; u32 i;
for (i = 0; i < RCANFD_FIFO_DEPTH; 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) static int rcar_canfd_reset_controller(struct rcar_canfd_global *gpriv)
......
...@@ -525,7 +525,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id) ...@@ -525,7 +525,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT && if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT &&
!(status & SR_TCS)) { !(status & SR_TCS)) {
stats->tx_errors++; stats->tx_errors++;
can_free_echo_skb(dev, 0); can_free_echo_skb(dev, 0, NULL);
} else { } else {
/* transmission complete */ /* transmission complete */
stats->tx_bytes += stats->tx_bytes +=
......
...@@ -179,7 +179,7 @@ static void hi3110_clean(struct net_device *net) ...@@ -179,7 +179,7 @@ static void hi3110_clean(struct net_device *net)
net->stats.tx_errors++; net->stats.tx_errors++;
dev_kfree_skb(priv->tx_skb); dev_kfree_skb(priv->tx_skb);
if (priv->tx_len) 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_skb = NULL;
priv->tx_len = 0; priv->tx_len = 0;
} }
......
...@@ -276,7 +276,7 @@ static void mcp251x_clean(struct net_device *net) ...@@ -276,7 +276,7 @@ static void mcp251x_clean(struct net_device *net)
net->stats.tx_errors++; net->stats.tx_errors++;
dev_kfree_skb(priv->tx_skb); dev_kfree_skb(priv->tx_skb);
if (priv->tx_len) 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_skb = NULL;
priv->tx_len = 0; priv->tx_len = 0;
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
config CAN_MCP251XFD config CAN_MCP251XFD
tristate "Microchip MCP251xFD SPI CAN controllers" tristate "Microchip MCP251xFD SPI CAN controllers"
select REGMAP select REGMAP
select WANT_DEV_COREDUMP
help help
Driver for the Microchip MCP251XFD SPI FD-CAN controller Driver for the Microchip MCP251XFD SPI FD-CAN controller
family. family.
......
...@@ -6,3 +6,6 @@ mcp251xfd-objs := ...@@ -6,3 +6,6 @@ mcp251xfd-objs :=
mcp251xfd-objs += mcp251xfd-core.o mcp251xfd-objs += mcp251xfd-core.o
mcp251xfd-objs += mcp251xfd-crc16.o mcp251xfd-objs += mcp251xfd-crc16.o
mcp251xfd-objs += mcp251xfd-regmap.o mcp251xfd-objs += mcp251xfd-regmap.o
mcp251xfd-objs += mcp251xfd-timestamp.o
mcp251xfd-$(CONFIG_DEV_COREDUMP) += mcp251xfd-dump.o
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// //
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
// //
// Copyright (c) 2019, 2020 Pengutronix, // Copyright (c) 2019, 2020, 2021 Pengutronix,
// Marc Kleine-Budde <kernel@pengutronix.de> // Marc Kleine-Budde <kernel@pengutronix.de>
// //
// Based on: // Based on:
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -330,6 +329,7 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -330,6 +329,7 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
struct mcp251xfd_tx_ring *tx_ring; struct mcp251xfd_tx_ring *tx_ring;
struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL; struct mcp251xfd_rx_ring *rx_ring, *prev_rx_ring = NULL;
struct mcp251xfd_tx_obj *tx_obj; struct mcp251xfd_tx_obj *tx_obj;
struct spi_transfer *xfer;
u32 val; u32 val;
u16 addr; u16 addr;
u8 len; u8 len;
...@@ -347,8 +347,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -347,8 +347,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
addr, val, val); addr, val, val);
for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) { for (j = 0; j < ARRAY_SIZE(tef_ring->uinc_xfer); j++) {
struct spi_transfer *xfer;
xfer = &tef_ring->uinc_xfer[j]; xfer = &tef_ring->uinc_xfer[j];
xfer->tx_buf = &tef_ring->uinc_buf; xfer->tx_buf = &tef_ring->uinc_buf;
xfer->len = len; xfer->len = len;
...@@ -357,6 +355,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -357,6 +355,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; 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 */
tx_ring = priv->tx; tx_ring = priv->tx;
tx_ring->head = 0; tx_ring->head = 0;
...@@ -397,8 +404,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -397,8 +404,6 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
addr, val, val); addr, val, val);
for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) { for (j = 0; j < ARRAY_SIZE(rx_ring->uinc_xfer); j++) {
struct spi_transfer *xfer;
xfer = &rx_ring->uinc_xfer[j]; xfer = &rx_ring->uinc_xfer[j];
xfer->tx_buf = &rx_ring->uinc_buf; xfer->tx_buf = &rx_ring->uinc_buf;
xfer->len = len; xfer->len = len;
...@@ -406,6 +411,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -406,6 +411,15 @@ static void mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
xfer->cs_change_delay.value = 0; xfer->cs_change_delay.value = 0;
xfer->cs_change_delay.unit = SPI_DELAY_UNIT_NSECS; 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) ...@@ -1097,6 +1111,7 @@ static int mcp251xfd_chip_start(struct mcp251xfd_priv *priv)
return 0; return 0;
out_chip_stop: out_chip_stop:
mcp251xfd_dump(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
return err; return err;
...@@ -1250,7 +1265,8 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, ...@@ -1250,7 +1265,8 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
const struct mcp251xfd_hw_tef_obj *hw_tef_obj) const struct mcp251xfd_hw_tef_obj *hw_tef_obj)
{ {
struct net_device_stats *stats = &priv->ndev->stats; 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, seq = FIELD_GET(MCP251XFD_OBJ_FLAGS_SEQ_MCP2518FD_MASK,
hw_tef_obj->flags); hw_tef_obj->flags);
...@@ -1266,9 +1282,13 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, ...@@ -1266,9 +1282,13 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv,
if (seq_masked != tef_tail_masked) if (seq_masked != tef_tail_masked)
return mcp251xfd_handle_tefif_recover(priv, seq); 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 += stats->tx_bytes +=
can_rx_offload_get_echo_skb(&priv->offload, can_rx_offload_get_echo_skb(&priv->offload,
mcp251xfd_get_tef_tail(priv), tef_tail,
hw_tef_obj->ts, NULL); hw_tef_obj->ts, NULL);
stats->tx_packets++; stats->tx_packets++;
priv->tef->tail++; priv->tef->tail++;
...@@ -1365,25 +1385,20 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) ...@@ -1365,25 +1385,20 @@ static int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
if (len) { if (len) {
struct mcp251xfd_tef_ring *ring = priv->tef; struct mcp251xfd_tef_ring *ring = priv->tef;
struct mcp251xfd_tx_ring *tx_ring = priv->tx; struct mcp251xfd_tx_ring *tx_ring = priv->tx;
struct spi_transfer *last_xfer; int offset;
/* Increment the TEF FIFO tail pointer 'len' times in /* Increment the TEF FIFO tail pointer 'len' times in
* a single SPI message. * a single SPI message.
* *
* Note: * Note:
* * Calculate offset, so that the SPI transfer ends on
* "cs_change == 1" on the last transfer results in an * the last message of the uinc_xfer array, which has
* active chip select after the complete SPI * "cs_change == 0", to properly deactivate the chip
* message. This causes the controller to interpret * select.
* 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.
*/ */
last_xfer = &ring->uinc_xfer[len - 1]; offset = ARRAY_SIZE(ring->uinc_xfer) - len;
last_xfer->cs_change = 0; err = spi_sync_transfer(priv->spi,
err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len); ring->uinc_xfer + offset, len);
last_xfer->cs_change = 1;
if (err) if (err)
return err; return err;
...@@ -1432,7 +1447,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv, ...@@ -1432,7 +1447,7 @@ mcp251xfd_rx_ring_update(const struct mcp251xfd_priv *priv,
} }
static void 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, const struct mcp251xfd_hw_rx_obj_canfd *hw_rx_obj,
struct sk_buff *skb) struct sk_buff *skb)
{ {
...@@ -1475,6 +1490,8 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv, ...@@ -1475,6 +1490,8 @@ mcp251xfd_hw_rx_obj_to_skb(const struct mcp251xfd_priv *priv,
if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR)) if (!(hw_rx_obj->flags & MCP251XFD_OBJ_FLAGS_RTR))
memcpy(cfd->data, hw_rx_obj->data, cfd->len); memcpy(cfd->data, hw_rx_obj->data, cfd->len);
mcp251xfd_skb_set_timestamp(priv, skb, hw_rx_obj->ts);
} }
static int static int
...@@ -1535,7 +1552,7 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, ...@@ -1535,7 +1552,7 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
return err; return err;
while ((len = mcp251xfd_get_rx_linear_len(ring))) { while ((len = mcp251xfd_get_rx_linear_len(ring))) {
struct spi_transfer *last_xfer; int offset;
rx_tail = mcp251xfd_get_rx_tail(ring); rx_tail = mcp251xfd_get_rx_tail(ring);
...@@ -1556,19 +1573,14 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv, ...@@ -1556,19 +1573,14 @@ mcp251xfd_handle_rxif_ring(struct mcp251xfd_priv *priv,
* single SPI message. * single SPI message.
* *
* Note: * Note:
* * Calculate offset, so that the SPI transfer ends on
* "cs_change == 1" on the last transfer results in an * the last message of the uinc_xfer array, which has
* active chip select after the complete SPI * "cs_change == 0", to properly deactivate the chip
* message. This causes the controller to interpret * select.
* 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.
*/ */
last_xfer = &ring->uinc_xfer[len - 1]; offset = ARRAY_SIZE(ring->uinc_xfer) - len;
last_xfer->cs_change = 0; err = spi_sync_transfer(priv->spi,
err = spi_sync_transfer(priv->spi, ring->uinc_xfer, len); ring->uinc_xfer + offset, len);
last_xfer->cs_change = 1;
if (err) if (err)
return err; return err;
...@@ -1592,23 +1604,22 @@ static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv) ...@@ -1592,23 +1604,22 @@ static int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
return 0; 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 * 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 can_frame **cf, u32 *timestamp)
{ {
struct sk_buff *skb;
int err; int err;
err = mcp251xfd_get_timestamp(priv, timestamp); err = mcp251xfd_get_timestamp(priv, timestamp);
if (err) if (err)
return NULL; 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) static int mcp251xfd_handle_rxovif(struct mcp251xfd_priv *priv)
...@@ -1760,6 +1771,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv) ...@@ -1760,6 +1771,7 @@ static int mcp251xfd_handle_ivmif(struct mcp251xfd_priv *priv)
if (!cf) if (!cf)
return 0; return 0;
mcp251xfd_skb_set_timestamp(priv, skb, timestamp);
err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp); err = can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
if (err) if (err)
stats->rx_fifo_errors++; stats->rx_fifo_errors++;
...@@ -2277,6 +2289,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id) ...@@ -2277,6 +2289,7 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
out_fail: out_fail:
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n", netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
err, priv->regs_status.intf); err, priv->regs_status.intf);
mcp251xfd_dump(priv);
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
return handled; return handled;
...@@ -2493,6 +2506,7 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -2493,6 +2506,7 @@ static int mcp251xfd_open(struct net_device *ndev)
if (err) if (err)
goto out_transceiver_disable; goto out_transceiver_disable;
mcp251xfd_timestamp_init(priv);
can_rx_offload_enable(&priv->offload); can_rx_offload_enable(&priv->offload);
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq, err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
...@@ -2513,6 +2527,7 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -2513,6 +2527,7 @@ static int mcp251xfd_open(struct net_device *ndev)
free_irq(spi->irq, priv); free_irq(spi->irq, priv);
out_can_rx_offload_disable: out_can_rx_offload_disable:
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
out_transceiver_disable: out_transceiver_disable:
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
out_mcp251xfd_ring_free: out_mcp251xfd_ring_free:
...@@ -2534,6 +2549,7 @@ static int mcp251xfd_stop(struct net_device *ndev) ...@@ -2534,6 +2549,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
free_irq(ndev->irq, priv); free_irq(ndev->irq, priv);
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
mcp251xfd_timestamp_stop(priv);
mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED); mcp251xfd_chip_stop(priv, CAN_STATE_STOPPED);
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
mcp251xfd_ring_free(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 @@ ...@@ -15,9 +15,12 @@
#include <linux/can/rx-offload.h> #include <linux/can/rx-offload.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/timecounter.h>
#include <linux/workqueue.h>
/* MPC251x registers */ /* MPC251x registers */
...@@ -394,6 +397,9 @@ ...@@ -394,6 +397,9 @@
#define MCP251XFD_SYSCLOCK_HZ_MAX 40000000 #define MCP251XFD_SYSCLOCK_HZ_MAX 40000000
#define MCP251XFD_SYSCLOCK_HZ_MIN 1000000 #define MCP251XFD_SYSCLOCK_HZ_MIN 1000000
#define MCP251XFD_SPICLOCK_HZ_MAX 20000000 #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_PLL_MULTIPLIER 10
#define MCP251XFD_OSC_STAB_SLEEP_US (3 * USEC_PER_MSEC) #define MCP251XFD_OSC_STAB_SLEEP_US (3 * USEC_PER_MSEC)
#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US) #define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
...@@ -595,6 +601,10 @@ struct mcp251xfd_priv { ...@@ -595,6 +601,10 @@ struct mcp251xfd_priv {
struct mcp251xfd_ecc ecc; struct mcp251xfd_ecc ecc;
struct mcp251xfd_regs_status regs_status; struct mcp251xfd_regs_status regs_status;
struct cyclecounter cc;
struct timecounter tc;
struct delayed_work timestamp;
struct gpio_desc *rx_int; struct gpio_desc *rx_int;
struct clk *clk; struct clk *clk;
struct regulator *reg_vdd; struct regulator *reg_vdd;
...@@ -727,6 +737,12 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv, ...@@ -727,6 +737,12 @@ mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
return data; 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) static inline u16 mcp251xfd_get_tef_obj_addr(u8 n)
{ {
return MCP251XFD_RAM_START + return MCP251XFD_RAM_START +
...@@ -837,5 +853,17 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv); ...@@ -837,5 +853,17 @@ int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv);
u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size, u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
const void *data, size_t data_size); const void *data, size_t data_size);
u16 mcp251xfd_crc16_compute(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 #endif
...@@ -807,7 +807,7 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne ...@@ -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); err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err)) { 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_unanchor_urb(urb);
usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); 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, ...@@ -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); can_get_echo_skb(netdev, context->echo_index, NULL);
} else { } else {
stats->tx_errors++; stats->tx_errors++;
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
} }
/* Release context */ /* Release context */
...@@ -793,7 +793,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb, ...@@ -793,7 +793,7 @@ static netdev_tx_t esd_usb2_start_xmit(struct sk_buff *skb,
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) { 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); atomic_dec(&priv->active_tx_jobs);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
......
...@@ -533,7 +533,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, ...@@ -533,7 +533,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
if (unlikely(rc)) { /* usb send failed */ if (unlikely(rc)) { /* usb send failed */
atomic_dec(&dev->active_tx_urbs); atomic_dec(&dev->active_tx_urbs);
can_free_echo_skb(netdev, idx); can_free_echo_skb(netdev, idx, NULL);
gs_free_tx_context(txc); gs_free_tx_context(txc);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
......
...@@ -593,7 +593,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, ...@@ -593,7 +593,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
if (unlikely(err)) { if (unlikely(err)) {
spin_lock_irqsave(&priv->tx_contexts_lock, flags); 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; context->echo_index = dev->max_tx_urbs;
--priv->active_tx_contexts; --priv->active_tx_contexts;
netif_wake_queue(netdev); netif_wake_queue(netdev);
......
...@@ -364,7 +364,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb, ...@@ -364,7 +364,7 @@ static netdev_tx_t mcba_usb_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
xmit_failed: xmit_failed:
can_free_echo_skb(priv->netdev, ctx->ndx); can_free_echo_skb(priv->netdev, ctx->ndx, NULL);
mcba_usb_free_ctx(ctx); mcba_usb_free_ctx(ctx);
dev_kfree_skb(skb); dev_kfree_skb(skb);
stats->tx_dropped++; stats->tx_dropped++;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -40,6 +41,7 @@ ...@@ -40,6 +41,7 @@
#define PCAN_USB_CMD_REGISTER 9 #define PCAN_USB_CMD_REGISTER 9
#define PCAN_USB_CMD_EXT_VCC 10 #define PCAN_USB_CMD_EXT_VCC 10
#define PCAN_USB_CMD_ERR_FR 11 #define PCAN_USB_CMD_ERR_FR 11
#define PCAN_USB_CMD_LED 12
/* PCAN_USB_CMD_SET_BUS number arg */ /* PCAN_USB_CMD_SET_BUS number arg */
#define PCAN_USB_BUS_XCVER 2 #define PCAN_USB_BUS_XCVER 2
...@@ -248,6 +250,15 @@ static int pcan_usb_set_ext_vcc(struct peak_usb_device *dev, u8 onoff) ...@@ -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); 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 * set bittiming value to can
*/ */
...@@ -971,6 +982,40 @@ static int pcan_usb_probe(struct usb_interface *intf) ...@@ -971,6 +982,40 @@ static int pcan_usb_probe(struct usb_interface *intf)
return 0; 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 * describe the PCAN-USB adapter
*/ */
...@@ -1001,6 +1046,8 @@ const struct peak_usb_adapter pcan_usb = { ...@@ -1001,6 +1046,8 @@ const struct peak_usb_adapter pcan_usb = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb), .sizeof_dev_private = sizeof(struct pcan_usb),
.ethtool_ops = &pcan_usb_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 16, .ts_used_bits = 16,
.ts_period = 24575, /* calibration period in ts. */ .ts_period = 24575, /* calibration period in ts. */
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -371,7 +372,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb, ...@@ -371,7 +372,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) { if (err) {
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
...@@ -820,6 +821,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter, ...@@ -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 */ 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->rx_submitted);
init_usb_anchor(&dev->tx_submitted); init_usb_anchor(&dev->tx_submitted);
......
...@@ -46,6 +46,8 @@ struct peak_usb_adapter { ...@@ -46,6 +46,8 @@ struct peak_usb_adapter {
const struct can_bittiming_const * const data_bittiming_const; const struct can_bittiming_const * const data_bittiming_const;
unsigned int ctrl_count; unsigned int ctrl_count;
const struct ethtool_ops *ethtool_ops;
int (*intf_probe)(struct usb_interface *intf); int (*intf_probe)(struct usb_interface *intf);
int (*dev_init)(struct peak_usb_device *dev); int (*dev_init)(struct peak_usb_device *dev);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -773,6 +774,10 @@ static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev, ...@@ -773,6 +774,10 @@ static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev,
tx_msg_flags |= PUCAN_MSG_RTR; 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->flags = cpu_to_le16(tx_msg_flags);
tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, dlc); tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, dlc);
memcpy(tx_msg->d, cfd->data, cfd->len); memcpy(tx_msg->d, cfd->data, cfd->len);
...@@ -1006,6 +1011,31 @@ static void pcan_usb_fd_free(struct peak_usb_device *dev) ...@@ -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 */ /* describes the PCAN-USB FD adapter */
static const struct can_bittiming_const pcan_usb_fd_const = { static const struct can_bittiming_const pcan_usb_fd_const = {
.name = "pcan_usb_fd", .name = "pcan_usb_fd",
...@@ -1037,7 +1067,7 @@ const struct peak_usb_adapter pcan_usb_fd = { ...@@ -1037,7 +1067,7 @@ const struct peak_usb_adapter pcan_usb_fd = {
.ctrl_count = PCAN_USBFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1047,6 +1077,8 @@ const struct peak_usb_adapter pcan_usb_fd = { ...@@ -1047,6 +1077,8 @@ const struct peak_usb_adapter pcan_usb_fd = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
...@@ -1110,7 +1142,7 @@ const struct peak_usb_adapter pcan_usb_chip = { ...@@ -1110,7 +1142,7 @@ const struct peak_usb_adapter pcan_usb_chip = {
.ctrl_count = PCAN_USBFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1120,6 +1152,8 @@ const struct peak_usb_adapter pcan_usb_chip = { ...@@ -1120,6 +1152,8 @@ const struct peak_usb_adapter pcan_usb_chip = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
...@@ -1183,7 +1217,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = { ...@@ -1183,7 +1217,7 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1193,6 +1227,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = { ...@@ -1193,6 +1227,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
...@@ -1256,7 +1292,7 @@ const struct peak_usb_adapter pcan_usb_x6 = { ...@@ -1256,7 +1292,7 @@ const struct peak_usb_adapter pcan_usb_x6 = {
.ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT, .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
.ctrlmode_supported = CAN_CTRLMODE_FD | .ctrlmode_supported = CAN_CTRLMODE_FD |
CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_CC_LEN8_DLC, CAN_CTRLMODE_ONE_SHOT | CAN_CTRLMODE_CC_LEN8_DLC,
.clock = { .clock = {
.freq = PCAN_UFD_CRYSTAL_HZ, .freq = PCAN_UFD_CRYSTAL_HZ,
}, },
...@@ -1266,6 +1302,8 @@ const struct peak_usb_adapter pcan_usb_x6 = { ...@@ -1266,6 +1302,8 @@ const struct peak_usb_adapter pcan_usb_x6 = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_fd_device), .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
.ethtool_ops = &pcan_usb_fd_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/can.h> #include <linux/can.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -36,6 +37,7 @@ ...@@ -36,6 +37,7 @@
#define PCAN_USBPRO_RTR 0x01 #define PCAN_USBPRO_RTR 0x01
#define PCAN_USBPRO_EXT 0x02 #define PCAN_USBPRO_EXT 0x02
#define PCAN_USBPRO_SS 0x08
#define PCAN_USBPRO_CMD_BUFFER_SIZE 512 #define PCAN_USBPRO_CMD_BUFFER_SIZE 512
...@@ -776,9 +778,13 @@ static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev, ...@@ -776,9 +778,13 @@ static int pcan_usb_pro_encode_msg(struct peak_usb_device *dev,
flags = 0; flags = 0;
if (cf->can_id & CAN_EFF_FLAG) if (cf->can_id & CAN_EFF_FLAG)
flags |= 0x02; flags |= PCAN_USBPRO_EXT;
if (cf->can_id & CAN_RTR_FLAG) 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, pcan_msg_add_rec(&usb_msg, data_type, 0, flags, len, cf->can_id,
cf->data); cf->data);
...@@ -906,7 +912,7 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev) ...@@ -906,7 +912,7 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
usb_if->dev[dev->ctrl_idx] = dev; usb_if->dev[dev->ctrl_idx] = dev;
/* set LED in default state (end of init phase) */ /* 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(bi);
kfree(fi); kfree(fi);
...@@ -990,6 +996,35 @@ int pcan_usb_pro_probe(struct usb_interface *intf) ...@@ -990,6 +996,35 @@ int pcan_usb_pro_probe(struct usb_interface *intf)
return 0; 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 * describe the PCAN-USB Pro adapter
*/ */
...@@ -1009,7 +1044,8 @@ const struct peak_usb_adapter pcan_usb_pro = { ...@@ -1009,7 +1044,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
.name = "PCAN-USB Pro", .name = "PCAN-USB Pro",
.device_id = PCAN_USBPRO_PRODUCT_ID, .device_id = PCAN_USBPRO_PRODUCT_ID,
.ctrl_count = PCAN_USBPRO_CHANNEL_COUNT, .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 = { .clock = {
.freq = PCAN_USBPRO_CRYSTAL_HZ, .freq = PCAN_USBPRO_CRYSTAL_HZ,
}, },
...@@ -1018,6 +1054,8 @@ const struct peak_usb_adapter pcan_usb_pro = { ...@@ -1018,6 +1054,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
/* size of device private data */ /* size of device private data */
.sizeof_dev_private = sizeof(struct pcan_usb_pro_device), .sizeof_dev_private = sizeof(struct pcan_usb_pro_device),
.ethtool_ops = &pcan_usb_pro_ethtool_ops,
/* timestamps usage */ /* timestamps usage */
.ts_used_bits = 32, .ts_used_bits = 32,
.ts_period = 1000000, /* calibration period in ts. */ .ts_period = 1000000, /* calibration period in ts. */
......
...@@ -115,6 +115,12 @@ struct __packed pcan_usb_pro_devid { ...@@ -115,6 +115,12 @@ struct __packed pcan_usb_pro_devid {
__le32 serial_num; __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 { struct __packed pcan_usb_pro_setled {
u8 data_type; u8 data_type;
u8 channel; u8 channel;
......
...@@ -246,7 +246,7 @@ struct ucan_message_in { ...@@ -246,7 +246,7 @@ struct ucan_message_in {
*/ */
struct ucan_tx_complete_entry_t can_tx_complete_msg[0]; struct ucan_tx_complete_entry_t can_tx_complete_msg[0];
} __aligned(0x4) msg; } __aligned(0x4) msg;
} __packed; } __packed __aligned(0x4);
/* Macros to calculate message lengths */ /* Macros to calculate message lengths */
#define UCAN_OUT_HDR_SIZE offsetof(struct ucan_message_out, msg) #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, ...@@ -675,7 +675,7 @@ static void ucan_tx_complete_msg(struct ucan_priv *up,
can_get_echo_skb(up->netdev, echo_index, NULL); can_get_echo_skb(up->netdev, echo_index, NULL);
} else { } else {
up->netdev->stats.tx_dropped++; 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); spin_unlock_irqrestore(&up->echo_skb_lock, flags);
} }
...@@ -843,7 +843,7 @@ static void ucan_write_bulk_callback(struct urb *urb) ...@@ -843,7 +843,7 @@ static void ucan_write_bulk_callback(struct urb *urb)
/* update counters an cleanup */ /* update counters an cleanup */
spin_lock_irqsave(&up->echo_skb_lock, flags); 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); spin_unlock_irqrestore(&up->echo_skb_lock, flags);
up->netdev->stats.tx_dropped++; up->netdev->stats.tx_dropped++;
...@@ -1157,7 +1157,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb, ...@@ -1157,7 +1157,7 @@ static netdev_tx_t ucan_start_xmit(struct sk_buff *skb,
* frees the skb * frees the skb
*/ */
spin_lock_irqsave(&up->echo_skb_lock, flags); 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); spin_unlock_irqrestore(&up->echo_skb_lock, flags);
if (ret == -ENODEV) { if (ret == -ENODEV) {
......
...@@ -691,7 +691,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, ...@@ -691,7 +691,7 @@ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
failed: failed:
can_free_echo_skb(netdev, context->echo_index); can_free_echo_skb(netdev, context->echo_index, NULL);
usb_unanchor_urb(urb); usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); usb_free_coherent(priv->udev, size, buf, urb->transfer_dma);
......
...@@ -1772,17 +1772,15 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1772,17 +1772,15 @@ static int xcan_probe(struct platform_device *pdev)
/* Getting the CAN can_clk info */ /* Getting the CAN can_clk info */
priv->can_clk = devm_clk_get(&pdev->dev, "can_clk"); priv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
if (IS_ERR(priv->can_clk)) { if (IS_ERR(priv->can_clk)) {
if (PTR_ERR(priv->can_clk) != -EPROBE_DEFER) ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
dev_err(&pdev->dev, "Device clock not found.\n"); "device clock not found\n");
ret = PTR_ERR(priv->can_clk);
goto err_free; goto err_free;
} }
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) { if (IS_ERR(priv->bus_clk)) {
if (PTR_ERR(priv->bus_clk) != -EPROBE_DEFER) ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
dev_err(&pdev->dev, "bus clock not found\n"); "bus clock not found\n");
ret = PTR_ERR(priv->bus_clk);
goto err_free; goto err_free;
} }
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> /* Copyright (c) 2020 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
* Copyright (c) 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
*/ */
#ifndef _CAN_BITTIMING_H #ifndef _CAN_BITTIMING_H
...@@ -10,9 +11,83 @@ ...@@ -10,9 +11,83 @@
#define CAN_SYNC_SEG 1 #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 #ifdef CONFIG_CAN_CALC_BITTIMING
int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc); const struct can_bittiming_const *btc);
void can_calc_tdco(struct net_device *dev);
#else /* !CONFIG_CAN_CALC_BITTIMING */ #else /* !CONFIG_CAN_CALC_BITTIMING */
static inline int static inline int
can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, 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, ...@@ -21,6 +96,10 @@ can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
netdev_err(dev, "bit-timing calculation not available\n"); netdev_err(dev, "bit-timing calculation not available\n");
return -EINVAL; return -EINVAL;
} }
static inline void can_calc_tdco(struct net_device *dev)
{
}
#endif /* CONFIG_CAN_CALC_BITTIMING */ #endif /* CONFIG_CAN_CALC_BITTIMING */
int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
......
...@@ -39,19 +39,23 @@ struct can_priv { ...@@ -39,19 +39,23 @@ struct can_priv {
struct net_device *dev; struct net_device *dev;
struct can_device_stats can_stats; struct can_device_stats can_stats;
struct can_bittiming bittiming, data_bittiming;
const struct can_bittiming_const *bittiming_const, const struct can_bittiming_const *bittiming_const,
*data_bittiming_const; *data_bittiming_const;
const u16 *termination_const; struct can_bittiming bittiming, data_bittiming;
unsigned int termination_const_cnt; const struct can_tdc_const *tdc_const;
u16 termination; struct can_tdc tdc;
const u32 *bitrate_const;
unsigned int bitrate_const_cnt; unsigned int bitrate_const_cnt;
const u32 *bitrate_const;
const u32 *data_bitrate_const; const u32 *data_bitrate_const;
unsigned int data_bitrate_const_cnt; unsigned int data_bitrate_const_cnt;
u32 bitrate_max; u32 bitrate_max;
struct can_clock clock; struct can_clock clock;
unsigned int termination_const_cnt;
const u16 *termination_const;
u16 termination;
enum can_state state; enum can_state state;
/* CAN controller features - see include/uapi/linux/can/netlink.h */ /* 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, ...@@ -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); u8 *len_ptr, unsigned int *frame_len_ptr);
unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx, unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
unsigned int *frame_len_ptr); 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_can_skb(struct net_device *dev, struct can_frame **cf);
struct sk_buff *alloc_canfd_skb(struct net_device *dev, struct sk_buff *alloc_canfd_skb(struct net_device *dev,
struct canfd_frame **cfd); 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