Merge tag 'linux-can-next-for-6.12-20240806' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
Marc Kleine-Budde says:
====================
pull-request: can-next 2024-08-06
The first patch is by Frank Li and adds the can-transceiver property
to the flexcan device-tree bindings.
Haibo Chen contributes 2 patches for the flexcan driver to add wakeup
support for the imx95.
The 2 patches by Stefan Mätje for the esd_402_pci driver clean up the
driver and add support for the one-shot mode.
The last 15 patches are by Jimmy Assarsson and add hardware timestamp
support for all devices covered by the kvaser_usb driver.
* tag 'linux-can-next-for-6.12-20240806' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next:
can: kvaser_usb: Rename kvaser_usb_{ethtool,netdev}_ops_hwts to kvaser_usb_{ethtool,netdev}_ops
can: kvaser_usb: Remove struct variables kvaser_usb_{ethtool,netdev}_ops
can: kvaser_usb: Remove KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP
can: kvaser_usb: leaf: Add hardware timestamp support to usbcan devices
can: kvaser_usb: leaf: Store MSB of timestamp
can: kvaser_usb: leaf: Add structs for Tx ACK and clock overflow commands
can: kvaser_usb: leaf: Add hardware timestamp support to leaf based devices
can: kvaser_usb: leaf: kvaser_usb_leaf_tx_acknowledge: Rename local variable
can: kvaser_usb: leaf: Replace kvaser_usb_leaf_m32c_dev_cfg with kvaser_usb_leaf_m32c_dev_cfg_{16,24,32}mhz
can: kvaser_usb: leaf: Assign correct timestamp_freq for kvaser_usb_leaf_imx_dev_cfg_{16,24,32}mhz
can: kvaser_usb: leaf: Add struct for Tx ACK commands
can: kvaser_usb: hydra: Set hardware timestamp on transmitted packets
can: kvaser_usb: hydra: Add struct for Tx ACK commands
can: kvaser_usb: hydra: kvaser_usb_hydra_ktime_from_rx_cmd: Drop {rx_} in function name
can: kvaser_usb: Add helper functions to convert device timestamp into ktime
can: esd_402_pci: Add support for one-shot mode
can: esd_402_pci: Rename esdACC CTRL register macros
can: flexcan: add wakeup support for imx95
dt-bindings: can: fsl,flexcan: move fsl,imx95-flexcan standalone
dt-bindings: can: fsl,flexcan: add common 'can-transceiver' for fsl,flexcan
====================
Link: https://patch.msgid.link/20240806074731.1905378-1-mkl@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -17,6 +17,7 @@ properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl,imx95-flexcan
|
||||
- fsl,imx93-flexcan
|
||||
- fsl,imx8qm-flexcan
|
||||
- fsl,imx8mp-flexcan
|
||||
@@ -38,9 +39,6 @@ properties:
|
||||
- fsl,imx6ul-flexcan
|
||||
- fsl,imx6sx-flexcan
|
||||
- const: fsl,imx6q-flexcan
|
||||
- items:
|
||||
- const: fsl,imx95-flexcan
|
||||
- const: fsl,imx93-flexcan
|
||||
- items:
|
||||
- enum:
|
||||
- fsl,ls1028ar1-flexcan
|
||||
@@ -80,6 +78,10 @@ properties:
|
||||
node then controller is assumed to be little endian. If this property is
|
||||
present then controller is assumed to be big endian.
|
||||
|
||||
can-transceiver:
|
||||
$ref: can-transceiver.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
fsl,stop-mode:
|
||||
description: |
|
||||
Register bits of stop mode control.
|
||||
|
||||
@@ -369,12 +369,13 @@ static int pci402_init_cores(struct pci_dev *pdev)
|
||||
SET_NETDEV_DEV(netdev, &pdev->dev);
|
||||
|
||||
priv = netdev_priv(netdev);
|
||||
priv->can.clock.freq = card->ov.core_frequency;
|
||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_LISTENONLY |
|
||||
CAN_CTRLMODE_BERR_REPORTING |
|
||||
CAN_CTRLMODE_CC_LEN8_DLC;
|
||||
|
||||
priv->can.clock.freq = card->ov.core_frequency;
|
||||
if (card->ov.features & ACC_OV_REG_FEAT_MASK_DAR)
|
||||
priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
|
||||
if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD)
|
||||
priv->can.bittiming_const = &pci402_bittiming_const_canfd;
|
||||
else
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
/* esdACC DLC register layout */
|
||||
#define ACC_DLC_DLC_MASK GENMASK(3, 0)
|
||||
#define ACC_DLC_RTR_FLAG BIT(4)
|
||||
#define ACC_DLC_SSTX_FLAG BIT(24) /* Single Shot TX */
|
||||
|
||||
/* esdACC DLC in struct acc_bmmsg_rxtxdone::acc_dlc.len only! */
|
||||
#define ACC_DLC_TXD_FLAG BIT(5)
|
||||
|
||||
/* ecc value of esdACC equals SJA1000's ECC register */
|
||||
@@ -43,8 +46,8 @@
|
||||
|
||||
static void acc_resetmode_enter(struct acc_core *core)
|
||||
{
|
||||
acc_set_bits(core, ACC_CORE_OF_CTRL_MODE,
|
||||
ACC_REG_CONTROL_MASK_MODE_RESETMODE);
|
||||
acc_set_bits(core, ACC_CORE_OF_CTRL,
|
||||
ACC_REG_CTRL_MASK_RESETMODE);
|
||||
|
||||
/* Read back reset mode bit to flush PCI write posting */
|
||||
acc_resetmode_entered(core);
|
||||
@@ -52,14 +55,14 @@ static void acc_resetmode_enter(struct acc_core *core)
|
||||
|
||||
static void acc_resetmode_leave(struct acc_core *core)
|
||||
{
|
||||
acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE,
|
||||
ACC_REG_CONTROL_MASK_MODE_RESETMODE);
|
||||
acc_clear_bits(core, ACC_CORE_OF_CTRL,
|
||||
ACC_REG_CTRL_MASK_RESETMODE);
|
||||
|
||||
/* Read back reset mode bit to flush PCI write posting */
|
||||
acc_resetmode_entered(core);
|
||||
}
|
||||
|
||||
static void acc_txq_put(struct acc_core *core, u32 acc_id, u8 acc_dlc,
|
||||
static void acc_txq_put(struct acc_core *core, u32 acc_id, u32 acc_dlc,
|
||||
const void *data)
|
||||
{
|
||||
acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1,
|
||||
@@ -172,7 +175,7 @@ int acc_open(struct net_device *netdev)
|
||||
struct acc_net_priv *priv = netdev_priv(netdev);
|
||||
struct acc_core *core = priv->core;
|
||||
u32 tx_fifo_status;
|
||||
u32 ctrl_mode;
|
||||
u32 ctrl;
|
||||
int err;
|
||||
|
||||
/* Retry to enter RESET mode if out of sync. */
|
||||
@@ -187,19 +190,19 @@ int acc_open(struct net_device *netdev)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ctrl_mode = ACC_REG_CONTROL_MASK_IE_RXTX |
|
||||
ACC_REG_CONTROL_MASK_IE_TXERROR |
|
||||
ACC_REG_CONTROL_MASK_IE_ERRWARN |
|
||||
ACC_REG_CONTROL_MASK_IE_OVERRUN |
|
||||
ACC_REG_CONTROL_MASK_IE_ERRPASS;
|
||||
ctrl = ACC_REG_CTRL_MASK_IE_RXTX |
|
||||
ACC_REG_CTRL_MASK_IE_TXERROR |
|
||||
ACC_REG_CTRL_MASK_IE_ERRWARN |
|
||||
ACC_REG_CTRL_MASK_IE_OVERRUN |
|
||||
ACC_REG_CTRL_MASK_IE_ERRPASS;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
||||
ctrl_mode |= ACC_REG_CONTROL_MASK_IE_BUSERR;
|
||||
ctrl |= ACC_REG_CTRL_MASK_IE_BUSERR;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
|
||||
ctrl_mode |= ACC_REG_CONTROL_MASK_MODE_LOM;
|
||||
ctrl |= ACC_REG_CTRL_MASK_LOM;
|
||||
|
||||
acc_set_bits(core, ACC_CORE_OF_CTRL_MODE, ctrl_mode);
|
||||
acc_set_bits(core, ACC_CORE_OF_CTRL, ctrl);
|
||||
|
||||
acc_resetmode_leave(core);
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
@@ -218,13 +221,13 @@ int acc_close(struct net_device *netdev)
|
||||
struct acc_net_priv *priv = netdev_priv(netdev);
|
||||
struct acc_core *core = priv->core;
|
||||
|
||||
acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE,
|
||||
ACC_REG_CONTROL_MASK_IE_RXTX |
|
||||
ACC_REG_CONTROL_MASK_IE_TXERROR |
|
||||
ACC_REG_CONTROL_MASK_IE_ERRWARN |
|
||||
ACC_REG_CONTROL_MASK_IE_OVERRUN |
|
||||
ACC_REG_CONTROL_MASK_IE_ERRPASS |
|
||||
ACC_REG_CONTROL_MASK_IE_BUSERR);
|
||||
acc_clear_bits(core, ACC_CORE_OF_CTRL,
|
||||
ACC_REG_CTRL_MASK_IE_RXTX |
|
||||
ACC_REG_CTRL_MASK_IE_TXERROR |
|
||||
ACC_REG_CTRL_MASK_IE_ERRWARN |
|
||||
ACC_REG_CTRL_MASK_IE_OVERRUN |
|
||||
ACC_REG_CTRL_MASK_IE_ERRPASS |
|
||||
ACC_REG_CTRL_MASK_IE_BUSERR);
|
||||
|
||||
netif_stop_queue(netdev);
|
||||
acc_resetmode_enter(core);
|
||||
@@ -233,9 +236,9 @@ int acc_close(struct net_device *netdev)
|
||||
/* Mark pending TX requests to be aborted after controller restart. */
|
||||
acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff);
|
||||
|
||||
/* ACC_REG_CONTROL_MASK_MODE_LOM is only accessible in RESET mode */
|
||||
acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE,
|
||||
ACC_REG_CONTROL_MASK_MODE_LOM);
|
||||
/* ACC_REG_CTRL_MASK_LOM is only accessible in RESET mode */
|
||||
acc_clear_bits(core, ACC_CORE_OF_CTRL,
|
||||
ACC_REG_CTRL_MASK_LOM);
|
||||
|
||||
close_candev(netdev);
|
||||
return 0;
|
||||
@@ -249,7 +252,7 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
u8 tx_fifo_head = core->tx_fifo_head;
|
||||
int fifo_usage;
|
||||
u32 acc_id;
|
||||
u8 acc_dlc;
|
||||
u32 acc_dlc;
|
||||
|
||||
if (can_dropped_invalid_skb(netdev, skb))
|
||||
return NETDEV_TX_OK;
|
||||
@@ -274,6 +277,8 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
acc_dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
acc_dlc |= ACC_DLC_RTR_FLAG;
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
acc_dlc |= ACC_DLC_SSTX_FLAG;
|
||||
|
||||
if (cf->can_id & CAN_EFF_FLAG) {
|
||||
acc_id = cf->can_id & CAN_EFF_MASK;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
*/
|
||||
#define ACC_OV_REG_FEAT_MASK_CANFD BIT(27 - 16)
|
||||
#define ACC_OV_REG_FEAT_MASK_NEW_PSC BIT(28 - 16)
|
||||
#define ACC_OV_REG_FEAT_MASK_DAR BIT(30 - 16)
|
||||
|
||||
#define ACC_OV_REG_MODE_MASK_ENDIAN_LITTLE BIT(0)
|
||||
#define ACC_OV_REG_MODE_MASK_BM_ENABLE BIT(1)
|
||||
@@ -50,7 +51,7 @@
|
||||
#define ACC_OV_REG_MODE_MASK_FPGA_RESET BIT(31)
|
||||
|
||||
/* esdACC CAN Core Module */
|
||||
#define ACC_CORE_OF_CTRL_MODE 0x0000
|
||||
#define ACC_CORE_OF_CTRL 0x0000
|
||||
#define ACC_CORE_OF_STATUS_IRQ 0x0008
|
||||
#define ACC_CORE_OF_BRP 0x000c
|
||||
#define ACC_CORE_OF_BTR 0x0010
|
||||
@@ -66,21 +67,22 @@
|
||||
#define ACC_CORE_OF_TXFIFO_DATA_0 0x00c8
|
||||
#define ACC_CORE_OF_TXFIFO_DATA_1 0x00cc
|
||||
|
||||
#define ACC_REG_CONTROL_MASK_MODE_RESETMODE BIT(0)
|
||||
#define ACC_REG_CONTROL_MASK_MODE_LOM BIT(1)
|
||||
#define ACC_REG_CONTROL_MASK_MODE_STM BIT(2)
|
||||
#define ACC_REG_CONTROL_MASK_MODE_TRANSEN BIT(5)
|
||||
#define ACC_REG_CONTROL_MASK_MODE_TS BIT(6)
|
||||
#define ACC_REG_CONTROL_MASK_MODE_SCHEDULE BIT(7)
|
||||
/* CTRL register layout */
|
||||
#define ACC_REG_CTRL_MASK_RESETMODE BIT(0)
|
||||
#define ACC_REG_CTRL_MASK_LOM BIT(1)
|
||||
#define ACC_REG_CTRL_MASK_STM BIT(2)
|
||||
#define ACC_REG_CTRL_MASK_TRANSEN BIT(5)
|
||||
#define ACC_REG_CTRL_MASK_TS BIT(6)
|
||||
#define ACC_REG_CTRL_MASK_SCHEDULE BIT(7)
|
||||
|
||||
#define ACC_REG_CONTROL_MASK_IE_RXTX BIT(8)
|
||||
#define ACC_REG_CONTROL_MASK_IE_TXERROR BIT(9)
|
||||
#define ACC_REG_CONTROL_MASK_IE_ERRWARN BIT(10)
|
||||
#define ACC_REG_CONTROL_MASK_IE_OVERRUN BIT(11)
|
||||
#define ACC_REG_CONTROL_MASK_IE_TSI BIT(12)
|
||||
#define ACC_REG_CONTROL_MASK_IE_ERRPASS BIT(13)
|
||||
#define ACC_REG_CONTROL_MASK_IE_ALI BIT(14)
|
||||
#define ACC_REG_CONTROL_MASK_IE_BUSERR BIT(15)
|
||||
#define ACC_REG_CTRL_MASK_IE_RXTX BIT(8)
|
||||
#define ACC_REG_CTRL_MASK_IE_TXERROR BIT(9)
|
||||
#define ACC_REG_CTRL_MASK_IE_ERRWARN BIT(10)
|
||||
#define ACC_REG_CTRL_MASK_IE_OVERRUN BIT(11)
|
||||
#define ACC_REG_CTRL_MASK_IE_TSI BIT(12)
|
||||
#define ACC_REG_CTRL_MASK_IE_ERRPASS BIT(13)
|
||||
#define ACC_REG_CTRL_MASK_IE_ALI BIT(14)
|
||||
#define ACC_REG_CTRL_MASK_IE_BUSERR BIT(15)
|
||||
|
||||
/* BRP and BTR register layout for CAN-Classic version */
|
||||
#define ACC_REG_BRP_CL_MASK_BRP GENMASK(8, 0)
|
||||
@@ -300,9 +302,9 @@ static inline void acc_clear_bits(struct acc_core *core,
|
||||
|
||||
static inline int acc_resetmode_entered(struct acc_core *core)
|
||||
{
|
||||
u32 ctrl = acc_read32(core, ACC_CORE_OF_CTRL_MODE);
|
||||
u32 ctrl = acc_read32(core, ACC_CORE_OF_CTRL);
|
||||
|
||||
return (ctrl & ACC_REG_CONTROL_MASK_MODE_RESETMODE) != 0;
|
||||
return (ctrl & ACC_REG_CTRL_MASK_RESETMODE) != 0;
|
||||
}
|
||||
|
||||
static inline u32 acc_ov_read32(struct acc_ov *ov, unsigned short offs)
|
||||
|
||||
@@ -354,6 +354,14 @@ static struct flexcan_devtype_data fsl_imx93_devtype_data = {
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_imx95_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_FD |
|
||||
FLEXCAN_QUIRK_SUPPORT_ECC | FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR | FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
@@ -544,6 +552,13 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
|
||||
} else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
|
||||
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
|
||||
1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
|
||||
} else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI) {
|
||||
/* For the SCMI mode, driver do nothing, ATF will send request to
|
||||
* SM(system manager, M33 core) through SCMI protocol after linux
|
||||
* suspend. Once SM get this request, it will send IPG_STOP signal
|
||||
* to Flex_CAN, let CAN in STOP mode.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
return flexcan_low_power_enter_ack(priv);
|
||||
@@ -555,7 +570,11 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
|
||||
u32 reg_mcr;
|
||||
int ret;
|
||||
|
||||
/* remove stop request */
|
||||
/* Remove stop request, for FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI,
|
||||
* do nothing here, because ATF already send request to SM before
|
||||
* linux resume. Once SM get this request, it will deassert the
|
||||
* IPG_STOP signal to Flex_CAN.
|
||||
*/
|
||||
if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) {
|
||||
ret = flexcan_stop_mode_enable_scfw(priv, false);
|
||||
if (ret < 0)
|
||||
@@ -1983,6 +2002,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
|
||||
ret = flexcan_setup_stop_mode_scfw(pdev);
|
||||
else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR)
|
||||
ret = flexcan_setup_stop_mode_gpr(pdev);
|
||||
else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI)
|
||||
/* ATF will handle all STOP_IPG related work */
|
||||
ret = 0;
|
||||
else
|
||||
/* return 0 directly if doesn't support stop mode feature */
|
||||
return 0;
|
||||
@@ -2009,6 +2031,7 @@ static const struct of_device_id flexcan_of_match[] = {
|
||||
{ .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
|
||||
{ .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, },
|
||||
{ .compatible = "fsl,imx93-flexcan", .data = &fsl_imx93_devtype_data, },
|
||||
{ .compatible = "fsl,imx95-flexcan", .data = &fsl_imx95_devtype_data, },
|
||||
{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
|
||||
{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
|
||||
{ .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, },
|
||||
@@ -2309,9 +2332,19 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device)
|
||||
if (device_may_wakeup(device))
|
||||
flexcan_enable_wakeup_irq(priv, true);
|
||||
|
||||
err = pm_runtime_force_suspend(device);
|
||||
if (err)
|
||||
return err;
|
||||
/* For FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI, it need ATF to send
|
||||
* to SM through SCMI protocol, SM will assert the IPG_STOP
|
||||
* signal. But all this works need the CAN clocks keep on.
|
||||
* After the CAN module get the IPG_STOP mode, and switch to
|
||||
* STOP mode, whether still keep the CAN clocks on or gate them
|
||||
* off depend on the Hardware design.
|
||||
*/
|
||||
if (!(device_may_wakeup(device) &&
|
||||
priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI)) {
|
||||
err = pm_runtime_force_suspend(device);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -2325,9 +2358,12 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
|
||||
if (netif_running(dev)) {
|
||||
int err;
|
||||
|
||||
err = pm_runtime_force_resume(device);
|
||||
if (err)
|
||||
return err;
|
||||
if (!(device_may_wakeup(device) &&
|
||||
priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI)) {
|
||||
err = pm_runtime_force_resume(device);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (device_may_wakeup(device))
|
||||
flexcan_enable_wakeup_irq(priv, false);
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15)
|
||||
/* Device supports RX via FIFO */
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16)
|
||||
/* Setup stop mode with ATF SCMI protocol to support wakeup */
|
||||
#define FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI BIT(17)
|
||||
|
||||
struct flexcan_devtype_data {
|
||||
u32 quirks; /* quirks needed for different IP cores */
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/usb.h>
|
||||
@@ -39,7 +41,6 @@
|
||||
#define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0)
|
||||
#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1)
|
||||
#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2)
|
||||
#define KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP BIT(3)
|
||||
|
||||
/* Device capabilities */
|
||||
#define KVASER_USB_CAP_BERR_CAP 0x01
|
||||
@@ -68,6 +69,7 @@ struct kvaser_usb_dev_card_data {
|
||||
u32 ctrlmode_supported;
|
||||
u32 capabilities;
|
||||
struct kvaser_usb_dev_card_data_hydra hydra;
|
||||
u32 usbcan_timestamp_msb;
|
||||
};
|
||||
|
||||
/* Context for an outstanding, not yet ACKed, transmission */
|
||||
@@ -216,4 +218,26 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev);
|
||||
|
||||
extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
|
||||
|
||||
static inline ktime_t kvaser_usb_ticks_to_ktime(const struct kvaser_usb_dev_cfg *cfg,
|
||||
u64 ticks)
|
||||
{
|
||||
return ns_to_ktime(div_u64(ticks * 1000, cfg->timestamp_freq));
|
||||
}
|
||||
|
||||
static inline ktime_t kvaser_usb_timestamp48_to_ktime(const struct kvaser_usb_dev_cfg *cfg,
|
||||
const __le16 *timestamp)
|
||||
{
|
||||
u64 ticks = le16_to_cpu(timestamp[0]) |
|
||||
(u64)(le16_to_cpu(timestamp[1])) << 16 |
|
||||
(u64)(le16_to_cpu(timestamp[2])) << 32;
|
||||
|
||||
return kvaser_usb_ticks_to_ktime(cfg, ticks);
|
||||
}
|
||||
|
||||
static inline ktime_t kvaser_usb_timestamp64_to_ktime(const struct kvaser_usb_dev_cfg *cfg,
|
||||
__le64 timestamp)
|
||||
{
|
||||
return kvaser_usb_ticks_to_ktime(cfg, le64_to_cpu(timestamp));
|
||||
}
|
||||
|
||||
#endif /* KVASER_USB_H */
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
#define USB_MINI_PCIE_1XCAN_PRODUCT_ID 0x011B
|
||||
|
||||
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
|
||||
.quirks = KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP,
|
||||
.quirks = 0,
|
||||
.ops = &kvaser_usb_hydra_dev_ops,
|
||||
};
|
||||
|
||||
@@ -754,13 +754,6 @@ freeurb:
|
||||
}
|
||||
|
||||
static const struct net_device_ops kvaser_usb_netdev_ops = {
|
||||
.ndo_open = kvaser_usb_open,
|
||||
.ndo_stop = kvaser_usb_close,
|
||||
.ndo_start_xmit = kvaser_usb_start_xmit,
|
||||
.ndo_change_mtu = can_change_mtu,
|
||||
};
|
||||
|
||||
static const struct net_device_ops kvaser_usb_netdev_ops_hwts = {
|
||||
.ndo_open = kvaser_usb_open,
|
||||
.ndo_stop = kvaser_usb_close,
|
||||
.ndo_eth_ioctl = can_eth_ioctl_hwts,
|
||||
@@ -769,10 +762,6 @@ static const struct net_device_ops kvaser_usb_netdev_ops_hwts = {
|
||||
};
|
||||
|
||||
static const struct ethtool_ops kvaser_usb_ethtool_ops = {
|
||||
.get_ts_info = ethtool_op_get_ts_info,
|
||||
};
|
||||
|
||||
static const struct ethtool_ops kvaser_usb_ethtool_ops_hwts = {
|
||||
.get_ts_info = can_ethtool_op_get_ts_info_hwts,
|
||||
};
|
||||
|
||||
@@ -859,13 +848,7 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
|
||||
netdev->flags |= IFF_ECHO;
|
||||
|
||||
netdev->netdev_ops = &kvaser_usb_netdev_ops;
|
||||
if (driver_info->quirks & KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP) {
|
||||
netdev->netdev_ops = &kvaser_usb_netdev_ops_hwts;
|
||||
netdev->ethtool_ops = &kvaser_usb_ethtool_ops_hwts;
|
||||
} else {
|
||||
netdev->netdev_ops = &kvaser_usb_netdev_ops;
|
||||
netdev->ethtool_ops = &kvaser_usb_ethtool_ops;
|
||||
}
|
||||
netdev->ethtool_ops = &kvaser_usb_ethtool_ops;
|
||||
SET_NETDEV_DEV(netdev, &dev->intf->dev);
|
||||
netdev->dev_id = channel;
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
* - Transition from CAN_STATE_ERROR_WARNING to CAN_STATE_ERROR_ACTIVE is only
|
||||
* reported after a call to do_get_berr_counter(), since firmware does not
|
||||
* distinguish between ERROR_WARNING and ERROR_ACTIVE.
|
||||
* - Hardware timestamps are not set for CAN Tx frames.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
@@ -261,6 +260,15 @@ struct kvaser_cmd_tx_can {
|
||||
u8 reserved[11];
|
||||
} __packed;
|
||||
|
||||
struct kvaser_cmd_tx_ack {
|
||||
__le32 id;
|
||||
u8 data[8];
|
||||
u8 dlc;
|
||||
u8 flags;
|
||||
__le16 timestamp[3];
|
||||
u8 reserved0[8];
|
||||
} __packed;
|
||||
|
||||
struct kvaser_cmd_header {
|
||||
u8 cmd_no;
|
||||
/* The destination HE address is stored in 0..5 of he_addr.
|
||||
@@ -297,6 +305,7 @@ struct kvaser_cmd {
|
||||
|
||||
struct kvaser_cmd_rx_can rx_can;
|
||||
struct kvaser_cmd_tx_can tx_can;
|
||||
struct kvaser_cmd_tx_ack tx_ack;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
@@ -522,23 +531,25 @@ kvaser_usb_hydra_net_priv_from_cmd(const struct kvaser_usb *dev,
|
||||
return priv;
|
||||
}
|
||||
|
||||
static ktime_t
|
||||
kvaser_usb_hydra_ktime_from_rx_cmd(const struct kvaser_usb_dev_cfg *cfg,
|
||||
const struct kvaser_cmd *cmd)
|
||||
static ktime_t kvaser_usb_hydra_ktime_from_cmd(const struct kvaser_usb_dev_cfg *cfg,
|
||||
const struct kvaser_cmd *cmd)
|
||||
{
|
||||
u64 ticks;
|
||||
ktime_t hwtstamp = 0;
|
||||
|
||||
if (cmd->header.cmd_no == CMD_EXTENDED) {
|
||||
struct kvaser_cmd_ext *cmd_ext = (struct kvaser_cmd_ext *)cmd;
|
||||
|
||||
ticks = le64_to_cpu(cmd_ext->rx_can.timestamp);
|
||||
} else {
|
||||
ticks = le16_to_cpu(cmd->rx_can.timestamp[0]);
|
||||
ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[1])) << 16;
|
||||
ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[2])) << 32;
|
||||
if (cmd_ext->cmd_no_ext == CMD_RX_MESSAGE_FD)
|
||||
hwtstamp = kvaser_usb_timestamp64_to_ktime(cfg, cmd_ext->rx_can.timestamp);
|
||||
else if (cmd_ext->cmd_no_ext == CMD_TX_ACKNOWLEDGE_FD)
|
||||
hwtstamp = kvaser_usb_timestamp64_to_ktime(cfg, cmd_ext->tx_ack.timestamp);
|
||||
} else if (cmd->header.cmd_no == CMD_RX_MESSAGE) {
|
||||
hwtstamp = kvaser_usb_timestamp48_to_ktime(cfg, cmd->rx_can.timestamp);
|
||||
} else if (cmd->header.cmd_no == CMD_TX_ACKNOWLEDGE) {
|
||||
hwtstamp = kvaser_usb_timestamp48_to_ktime(cfg, cmd->tx_ack.timestamp);
|
||||
}
|
||||
|
||||
return ns_to_ktime(div_u64(ticks * 1000, cfg->timestamp_freq));
|
||||
return hwtstamp;
|
||||
}
|
||||
|
||||
static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev,
|
||||
@@ -1175,6 +1186,7 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
bool one_shot_fail = false;
|
||||
bool is_err_frame = false;
|
||||
u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd);
|
||||
struct sk_buff *skb;
|
||||
|
||||
priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd);
|
||||
if (!priv)
|
||||
@@ -1201,6 +1213,9 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
|
||||
spin_lock_irqsave(&priv->tx_contexts_lock, irq_flags);
|
||||
|
||||
skb = priv->can.echo_skb[context->echo_index];
|
||||
if (skb)
|
||||
skb_hwtstamps(skb)->hwtstamp = kvaser_usb_hydra_ktime_from_cmd(dev->cfg, cmd);
|
||||
len = can_get_echo_skb(priv->netdev, context->echo_index, NULL);
|
||||
context->echo_index = dev->max_tx_urbs;
|
||||
--priv->active_tx_contexts;
|
||||
@@ -1234,7 +1249,7 @@ static void kvaser_usb_hydra_rx_msg_std(const struct kvaser_usb *dev,
|
||||
stats = &priv->netdev->stats;
|
||||
|
||||
flags = cmd->rx_can.flags;
|
||||
hwtstamp = kvaser_usb_hydra_ktime_from_rx_cmd(dev->cfg, cmd);
|
||||
hwtstamp = kvaser_usb_hydra_ktime_from_cmd(dev->cfg, cmd);
|
||||
|
||||
if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
|
||||
kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data,
|
||||
@@ -1302,7 +1317,7 @@ static void kvaser_usb_hydra_rx_msg_ext(const struct kvaser_usb *dev,
|
||||
KVASER_USB_KCAN_DATA_DLC_SHIFT;
|
||||
|
||||
flags = le32_to_cpu(cmd->rx_can.flags);
|
||||
hwtstamp = kvaser_usb_hydra_ktime_from_rx_cmd(dev->cfg, std_cmd);
|
||||
hwtstamp = kvaser_usb_hydra_ktime_from_cmd(dev->cfg, std_cmd);
|
||||
|
||||
if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
|
||||
kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data,
|
||||
|
||||
@@ -119,6 +119,10 @@
|
||||
/* Extended CAN identifier flag */
|
||||
#define KVASER_EXTENDED_FRAME BIT(31)
|
||||
|
||||
/* USBCanII timestamp */
|
||||
#define KVASER_USB_USBCAN_CLK_OVERFLOW_MASK GENMASK(31, 16)
|
||||
#define KVASER_USB_USBCAN_TIMESTAMP_FACTOR 10
|
||||
|
||||
struct kvaser_cmd_simple {
|
||||
u8 tid;
|
||||
u8 channel;
|
||||
@@ -235,6 +239,20 @@ struct kvaser_cmd_tx_acknowledge_header {
|
||||
u8 tid;
|
||||
} __packed;
|
||||
|
||||
struct leaf_cmd_tx_acknowledge {
|
||||
u8 channel;
|
||||
u8 tid;
|
||||
__le16 time[3];
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
struct usbcan_cmd_tx_acknowledge {
|
||||
u8 channel;
|
||||
u8 tid;
|
||||
__le16 time;
|
||||
u8 padding[2];
|
||||
} __packed;
|
||||
|
||||
struct leaf_cmd_can_error_event {
|
||||
u8 tid;
|
||||
u8 flags;
|
||||
@@ -281,6 +299,12 @@ struct usbcan_cmd_error_event {
|
||||
__le16 padding;
|
||||
} __packed;
|
||||
|
||||
struct usbcan_cmd_clk_overflow_event {
|
||||
u8 tid;
|
||||
u8 padding;
|
||||
__le32 time;
|
||||
} __packed;
|
||||
|
||||
struct kvaser_cmd_ctrl_mode {
|
||||
u8 tid;
|
||||
u8 channel;
|
||||
@@ -347,6 +371,7 @@ struct kvaser_cmd {
|
||||
struct leaf_cmd_error_event error_event;
|
||||
struct kvaser_cmd_cap_req cap_req;
|
||||
struct kvaser_cmd_cap_res cap_res;
|
||||
struct leaf_cmd_tx_acknowledge tx_ack;
|
||||
} __packed leaf;
|
||||
|
||||
union {
|
||||
@@ -355,6 +380,8 @@ struct kvaser_cmd {
|
||||
struct usbcan_cmd_chip_state_event chip_state_event;
|
||||
struct usbcan_cmd_can_error_event can_error_event;
|
||||
struct usbcan_cmd_error_event error_event;
|
||||
struct usbcan_cmd_tx_acknowledge tx_ack;
|
||||
struct usbcan_cmd_clk_overflow_event clk_overflow_event;
|
||||
} __packed usbcan;
|
||||
|
||||
struct kvaser_cmd_tx_can tx_can;
|
||||
@@ -370,7 +397,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
|
||||
[CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
|
||||
[CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
|
||||
[CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
|
||||
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
|
||||
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.leaf.tx_ack),
|
||||
[CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.leaf.softinfo),
|
||||
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
|
||||
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
|
||||
@@ -388,15 +415,14 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
|
||||
[CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
|
||||
[CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
|
||||
[CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo),
|
||||
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.tx_acknowledge_header),
|
||||
[CMD_TX_ACKNOWLEDGE] = kvaser_fsize(u.usbcan.tx_ack),
|
||||
[CMD_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.usbcan.softinfo),
|
||||
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
|
||||
[CMD_RX_EXT_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
|
||||
[CMD_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
|
||||
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event),
|
||||
[CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
|
||||
/* ignored events: */
|
||||
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
|
||||
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = kvaser_fsize(u.usbcan.clk_overflow_event),
|
||||
};
|
||||
|
||||
/* Summary of a kvaser error event, for a unified Leaf/Usbcan error
|
||||
@@ -463,11 +489,27 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
|
||||
.bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_16mhz = {
|
||||
.clock = {
|
||||
.freq = 16 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.timestamp_freq = 16,
|
||||
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_24mhz = {
|
||||
.clock = {
|
||||
.freq = 16 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 24,
|
||||
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
|
||||
};
|
||||
|
||||
static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg_32mhz = {
|
||||
.clock = {
|
||||
.freq = 16 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 32,
|
||||
.bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
|
||||
};
|
||||
|
||||
@@ -475,7 +517,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
|
||||
.clock = {
|
||||
.freq = 16 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.timestamp_freq = 16,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
@@ -483,7 +525,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
|
||||
.clock = {
|
||||
.freq = 24 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.timestamp_freq = 24,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
@@ -491,10 +533,19 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
|
||||
.clock = {
|
||||
.freq = 32 * MEGA /* Hz */,
|
||||
},
|
||||
.timestamp_freq = 1,
|
||||
.timestamp_freq = 32,
|
||||
.bittiming_const = &kvaser_usb_flexc_bittiming_const,
|
||||
};
|
||||
|
||||
static inline ktime_t kvaser_usb_usbcan_timestamp_to_ktime(const struct kvaser_usb *dev,
|
||||
__le16 timestamp)
|
||||
{
|
||||
u64 ticks = le16_to_cpu(timestamp) |
|
||||
dev->card_data.usbcan_timestamp_msb;
|
||||
|
||||
return kvaser_usb_ticks_to_ktime(dev->cfg, ticks * KVASER_USB_USBCAN_TIMESTAMP_FACTOR);
|
||||
}
|
||||
|
||||
static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
|
||||
const struct kvaser_cmd *cmd)
|
||||
{
|
||||
@@ -678,8 +729,19 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
|
||||
if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
|
||||
/* Firmware expects bittiming parameters calculated for 16MHz
|
||||
* clock, regardless of the actual clock
|
||||
* Though, the reported freq is used for timestamps
|
||||
*/
|
||||
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
|
||||
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_16mhz;
|
||||
break;
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_24mhz;
|
||||
break;
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
|
||||
dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg_32mhz;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
|
||||
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
|
||||
@@ -880,6 +942,8 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
struct kvaser_usb_net_priv *priv;
|
||||
unsigned long flags;
|
||||
u8 channel, tid;
|
||||
struct sk_buff *skb;
|
||||
ktime_t hwtstamp = 0;
|
||||
|
||||
channel = cmd->u.tx_acknowledge_header.channel;
|
||||
tid = cmd->u.tx_acknowledge_header.tid;
|
||||
@@ -901,14 +965,14 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
|
||||
/* Sometimes the state change doesn't come after a bus-off event */
|
||||
if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) {
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *err_skb;
|
||||
struct can_frame *cf;
|
||||
|
||||
skb = alloc_can_err_skb(priv->netdev, &cf);
|
||||
if (skb) {
|
||||
err_skb = alloc_can_err_skb(priv->netdev, &cf);
|
||||
if (err_skb) {
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
|
||||
netif_rx(skb);
|
||||
netif_rx(err_skb);
|
||||
} else {
|
||||
netdev_err(priv->netdev,
|
||||
"No memory left for err_skb\n");
|
||||
@@ -919,9 +983,20 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
|
||||
|
||||
priv->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.tx_ack.time);
|
||||
break;
|
||||
case KVASER_USBCAN:
|
||||
hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.tx_ack.time);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
|
||||
|
||||
skb = priv->can.echo_skb[context->echo_index];
|
||||
if (skb)
|
||||
skb_hwtstamps(skb)->hwtstamp = hwtstamp;
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += can_get_echo_skb(priv->netdev,
|
||||
context->echo_index, NULL);
|
||||
@@ -1299,6 +1374,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
|
||||
struct net_device_stats *stats;
|
||||
u8 channel = cmd->u.rx_can_header.channel;
|
||||
const u8 *rx_data = NULL; /* GCC */
|
||||
ktime_t hwtstamp = 0;
|
||||
|
||||
if (channel >= dev->nchannels) {
|
||||
dev_err(&dev->intf->dev,
|
||||
@@ -1329,9 +1405,11 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
rx_data = cmd->u.leaf.rx_can.data;
|
||||
hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.rx_can.time);
|
||||
break;
|
||||
case KVASER_USBCAN:
|
||||
rx_data = cmd->u.usbcan.rx_can.data;
|
||||
hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.rx_can.time);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1375,6 +1453,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
|
||||
memcpy(cf->data, &rx_data[6], cf->len);
|
||||
}
|
||||
|
||||
skb_hwtstamps(skb)->hwtstamp = hwtstamp;
|
||||
stats->rx_packets++;
|
||||
if (!(cf->can_id & CAN_RTR_FLAG))
|
||||
stats->rx_bytes += cf->len;
|
||||
@@ -1508,7 +1587,7 @@ static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev,
|
||||
complete(&priv->get_busparams_comp);
|
||||
}
|
||||
|
||||
static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
||||
static void kvaser_usb_leaf_handle_command(struct kvaser_usb *dev,
|
||||
const struct kvaser_cmd *cmd)
|
||||
{
|
||||
if (kvaser_usb_leaf_verify_size(dev, cmd) < 0)
|
||||
@@ -1554,12 +1633,15 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
|
||||
kvaser_usb_leaf_get_busparams_reply(dev, cmd);
|
||||
break;
|
||||
|
||||
/* Ignored commands */
|
||||
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
|
||||
if (dev->driver_info->family != KVASER_USBCAN)
|
||||
goto warn;
|
||||
dev->card_data.usbcan_timestamp_msb =
|
||||
le32_to_cpu(cmd->u.usbcan.clk_overflow_event.time) &
|
||||
KVASER_USB_USBCAN_CLK_OVERFLOW_MASK;
|
||||
break;
|
||||
|
||||
/* Ignored commands */
|
||||
case CMD_FLUSH_QUEUE_REPLY:
|
||||
if (dev->driver_info->family != KVASER_LEAF)
|
||||
goto warn;
|
||||
|
||||
Reference in New Issue
Block a user