Commit 2c14119a authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-next-for-6.12-20240806' of...

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.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents acd221a6 fa3c40b9
...@@ -17,6 +17,7 @@ properties: ...@@ -17,6 +17,7 @@ properties:
compatible: compatible:
oneOf: oneOf:
- enum: - enum:
- fsl,imx95-flexcan
- fsl,imx93-flexcan - fsl,imx93-flexcan
- fsl,imx8qm-flexcan - fsl,imx8qm-flexcan
- fsl,imx8mp-flexcan - fsl,imx8mp-flexcan
...@@ -38,9 +39,6 @@ properties: ...@@ -38,9 +39,6 @@ properties:
- fsl,imx6ul-flexcan - fsl,imx6ul-flexcan
- fsl,imx6sx-flexcan - fsl,imx6sx-flexcan
- const: fsl,imx6q-flexcan - const: fsl,imx6q-flexcan
- items:
- const: fsl,imx95-flexcan
- const: fsl,imx93-flexcan
- items: - items:
- enum: - enum:
- fsl,ls1028ar1-flexcan - fsl,ls1028ar1-flexcan
...@@ -80,6 +78,10 @@ properties: ...@@ -80,6 +78,10 @@ properties:
node then controller is assumed to be little endian. If this property is node then controller is assumed to be little endian. If this property is
present then controller is assumed to be big endian. present then controller is assumed to be big endian.
can-transceiver:
$ref: can-transceiver.yaml#
unevaluatedProperties: false
fsl,stop-mode: fsl,stop-mode:
description: | description: |
Register bits of stop mode control. Register bits of stop mode control.
......
...@@ -369,12 +369,13 @@ static int pci402_init_cores(struct pci_dev *pdev) ...@@ -369,12 +369,13 @@ static int pci402_init_cores(struct pci_dev *pdev)
SET_NETDEV_DEV(netdev, &pdev->dev); SET_NETDEV_DEV(netdev, &pdev->dev);
priv = netdev_priv(netdev); priv = netdev_priv(netdev);
priv->can.clock.freq = card->ov.core_frequency;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_CC_LEN8_DLC; CAN_CTRLMODE_CC_LEN8_DLC;
if (card->ov.features & ACC_OV_REG_FEAT_MASK_DAR)
priv->can.clock.freq = card->ov.core_frequency; priv->can.ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT;
if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD) if (card->ov.features & ACC_OV_REG_FEAT_MASK_CANFD)
priv->can.bittiming_const = &pci402_bittiming_const_canfd; priv->can.bittiming_const = &pci402_bittiming_const_canfd;
else else
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
/* esdACC DLC register layout */ /* esdACC DLC register layout */
#define ACC_DLC_DLC_MASK GENMASK(3, 0) #define ACC_DLC_DLC_MASK GENMASK(3, 0)
#define ACC_DLC_RTR_FLAG BIT(4) #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) #define ACC_DLC_TXD_FLAG BIT(5)
/* ecc value of esdACC equals SJA1000's ECC register */ /* ecc value of esdACC equals SJA1000's ECC register */
...@@ -43,8 +46,8 @@ ...@@ -43,8 +46,8 @@
static void acc_resetmode_enter(struct acc_core *core) static void acc_resetmode_enter(struct acc_core *core)
{ {
acc_set_bits(core, ACC_CORE_OF_CTRL_MODE, acc_set_bits(core, ACC_CORE_OF_CTRL,
ACC_REG_CONTROL_MASK_MODE_RESETMODE); ACC_REG_CTRL_MASK_RESETMODE);
/* Read back reset mode bit to flush PCI write posting */ /* Read back reset mode bit to flush PCI write posting */
acc_resetmode_entered(core); acc_resetmode_entered(core);
...@@ -52,14 +55,14 @@ static void acc_resetmode_enter(struct acc_core *core) ...@@ -52,14 +55,14 @@ static void acc_resetmode_enter(struct acc_core *core)
static void acc_resetmode_leave(struct acc_core *core) static void acc_resetmode_leave(struct acc_core *core)
{ {
acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE, acc_clear_bits(core, ACC_CORE_OF_CTRL,
ACC_REG_CONTROL_MASK_MODE_RESETMODE); ACC_REG_CTRL_MASK_RESETMODE);
/* Read back reset mode bit to flush PCI write posting */ /* Read back reset mode bit to flush PCI write posting */
acc_resetmode_entered(core); 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) const void *data)
{ {
acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1, acc_write32_noswap(core, ACC_CORE_OF_TXFIFO_DATA_1,
...@@ -172,7 +175,7 @@ int acc_open(struct net_device *netdev) ...@@ -172,7 +175,7 @@ int acc_open(struct net_device *netdev)
struct acc_net_priv *priv = netdev_priv(netdev); struct acc_net_priv *priv = netdev_priv(netdev);
struct acc_core *core = priv->core; struct acc_core *core = priv->core;
u32 tx_fifo_status; u32 tx_fifo_status;
u32 ctrl_mode; u32 ctrl;
int err; int err;
/* Retry to enter RESET mode if out of sync. */ /* Retry to enter RESET mode if out of sync. */
...@@ -187,19 +190,19 @@ int acc_open(struct net_device *netdev) ...@@ -187,19 +190,19 @@ int acc_open(struct net_device *netdev)
if (err) if (err)
return err; return err;
ctrl_mode = ACC_REG_CONTROL_MASK_IE_RXTX | ctrl = ACC_REG_CTRL_MASK_IE_RXTX |
ACC_REG_CONTROL_MASK_IE_TXERROR | ACC_REG_CTRL_MASK_IE_TXERROR |
ACC_REG_CONTROL_MASK_IE_ERRWARN | ACC_REG_CTRL_MASK_IE_ERRWARN |
ACC_REG_CONTROL_MASK_IE_OVERRUN | ACC_REG_CTRL_MASK_IE_OVERRUN |
ACC_REG_CONTROL_MASK_IE_ERRPASS; ACC_REG_CTRL_MASK_IE_ERRPASS;
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) 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) 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); acc_resetmode_leave(core);
priv->can.state = CAN_STATE_ERROR_ACTIVE; priv->can.state = CAN_STATE_ERROR_ACTIVE;
...@@ -218,13 +221,13 @@ int acc_close(struct net_device *netdev) ...@@ -218,13 +221,13 @@ int acc_close(struct net_device *netdev)
struct acc_net_priv *priv = netdev_priv(netdev); struct acc_net_priv *priv = netdev_priv(netdev);
struct acc_core *core = priv->core; struct acc_core *core = priv->core;
acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE, acc_clear_bits(core, ACC_CORE_OF_CTRL,
ACC_REG_CONTROL_MASK_IE_RXTX | ACC_REG_CTRL_MASK_IE_RXTX |
ACC_REG_CONTROL_MASK_IE_TXERROR | ACC_REG_CTRL_MASK_IE_TXERROR |
ACC_REG_CONTROL_MASK_IE_ERRWARN | ACC_REG_CTRL_MASK_IE_ERRWARN |
ACC_REG_CONTROL_MASK_IE_OVERRUN | ACC_REG_CTRL_MASK_IE_OVERRUN |
ACC_REG_CONTROL_MASK_IE_ERRPASS | ACC_REG_CTRL_MASK_IE_ERRPASS |
ACC_REG_CONTROL_MASK_IE_BUSERR); ACC_REG_CTRL_MASK_IE_BUSERR);
netif_stop_queue(netdev); netif_stop_queue(netdev);
acc_resetmode_enter(core); acc_resetmode_enter(core);
...@@ -233,9 +236,9 @@ int acc_close(struct net_device *netdev) ...@@ -233,9 +236,9 @@ int acc_close(struct net_device *netdev)
/* Mark pending TX requests to be aborted after controller restart. */ /* Mark pending TX requests to be aborted after controller restart. */
acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff); acc_write32(core, ACC_CORE_OF_TX_ABORT_MASK, 0xffff);
/* ACC_REG_CONTROL_MASK_MODE_LOM is only accessible in RESET mode */ /* ACC_REG_CTRL_MASK_LOM is only accessible in RESET mode */
acc_clear_bits(core, ACC_CORE_OF_CTRL_MODE, acc_clear_bits(core, ACC_CORE_OF_CTRL,
ACC_REG_CONTROL_MASK_MODE_LOM); ACC_REG_CTRL_MASK_LOM);
close_candev(netdev); close_candev(netdev);
return 0; return 0;
...@@ -249,7 +252,7 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -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; u8 tx_fifo_head = core->tx_fifo_head;
int fifo_usage; int fifo_usage;
u32 acc_id; u32 acc_id;
u8 acc_dlc; u32 acc_dlc;
if (can_dropped_invalid_skb(netdev, skb)) if (can_dropped_invalid_skb(netdev, skb))
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -274,6 +277,8 @@ netdev_tx_t acc_start_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -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); acc_dlc = can_get_cc_dlc(cf, priv->can.ctrlmode);
if (cf->can_id & CAN_RTR_FLAG) if (cf->can_id & CAN_RTR_FLAG)
acc_dlc |= ACC_DLC_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) { if (cf->can_id & CAN_EFF_FLAG) {
acc_id = cf->can_id & CAN_EFF_MASK; acc_id = cf->can_id & CAN_EFF_MASK;
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
*/ */
#define ACC_OV_REG_FEAT_MASK_CANFD BIT(27 - 16) #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_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_ENDIAN_LITTLE BIT(0)
#define ACC_OV_REG_MODE_MASK_BM_ENABLE BIT(1) #define ACC_OV_REG_MODE_MASK_BM_ENABLE BIT(1)
...@@ -50,7 +51,7 @@ ...@@ -50,7 +51,7 @@
#define ACC_OV_REG_MODE_MASK_FPGA_RESET BIT(31) #define ACC_OV_REG_MODE_MASK_FPGA_RESET BIT(31)
/* esdACC CAN Core Module */ /* 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_STATUS_IRQ 0x0008
#define ACC_CORE_OF_BRP 0x000c #define ACC_CORE_OF_BRP 0x000c
#define ACC_CORE_OF_BTR 0x0010 #define ACC_CORE_OF_BTR 0x0010
...@@ -66,21 +67,22 @@ ...@@ -66,21 +67,22 @@
#define ACC_CORE_OF_TXFIFO_DATA_0 0x00c8 #define ACC_CORE_OF_TXFIFO_DATA_0 0x00c8
#define ACC_CORE_OF_TXFIFO_DATA_1 0x00cc #define ACC_CORE_OF_TXFIFO_DATA_1 0x00cc
#define ACC_REG_CONTROL_MASK_MODE_RESETMODE BIT(0) /* CTRL register layout */
#define ACC_REG_CONTROL_MASK_MODE_LOM BIT(1) #define ACC_REG_CTRL_MASK_RESETMODE BIT(0)
#define ACC_REG_CONTROL_MASK_MODE_STM BIT(2) #define ACC_REG_CTRL_MASK_LOM BIT(1)
#define ACC_REG_CONTROL_MASK_MODE_TRANSEN BIT(5) #define ACC_REG_CTRL_MASK_STM BIT(2)
#define ACC_REG_CONTROL_MASK_MODE_TS BIT(6) #define ACC_REG_CTRL_MASK_TRANSEN BIT(5)
#define ACC_REG_CONTROL_MASK_MODE_SCHEDULE BIT(7) #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_CTRL_MASK_IE_RXTX BIT(8)
#define ACC_REG_CONTROL_MASK_IE_ERRWARN BIT(10) #define ACC_REG_CTRL_MASK_IE_TXERROR BIT(9)
#define ACC_REG_CONTROL_MASK_IE_OVERRUN BIT(11) #define ACC_REG_CTRL_MASK_IE_ERRWARN BIT(10)
#define ACC_REG_CONTROL_MASK_IE_TSI BIT(12) #define ACC_REG_CTRL_MASK_IE_OVERRUN BIT(11)
#define ACC_REG_CONTROL_MASK_IE_ERRPASS BIT(13) #define ACC_REG_CTRL_MASK_IE_TSI BIT(12)
#define ACC_REG_CONTROL_MASK_IE_ALI BIT(14) #define ACC_REG_CTRL_MASK_IE_ERRPASS BIT(13)
#define ACC_REG_CONTROL_MASK_IE_BUSERR BIT(15) #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 */ /* BRP and BTR register layout for CAN-Classic version */
#define ACC_REG_BRP_CL_MASK_BRP GENMASK(8, 0) #define ACC_REG_BRP_CL_MASK_BRP GENMASK(8, 0)
...@@ -300,9 +302,9 @@ static inline void acc_clear_bits(struct acc_core *core, ...@@ -300,9 +302,9 @@ static inline void acc_clear_bits(struct acc_core *core,
static inline int acc_resetmode_entered(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) 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 = { ...@@ -354,6 +354,14 @@ static struct flexcan_devtype_data fsl_imx93_devtype_data = {
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR, 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 = { static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS | .quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
...@@ -544,6 +552,13 @@ static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv) ...@@ -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) { } else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) {
regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr, regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
1 << priv->stm.req_bit, 1 << priv->stm.req_bit); 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); return flexcan_low_power_enter_ack(priv);
...@@ -555,7 +570,11 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv) ...@@ -555,7 +570,11 @@ static inline int flexcan_exit_stop_mode(struct flexcan_priv *priv)
u32 reg_mcr; u32 reg_mcr;
int ret; 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) { if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW) {
ret = flexcan_stop_mode_enable_scfw(priv, false); ret = flexcan_stop_mode_enable_scfw(priv, false);
if (ret < 0) if (ret < 0)
...@@ -1983,6 +2002,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev) ...@@ -1983,6 +2002,9 @@ static int flexcan_setup_stop_mode(struct platform_device *pdev)
ret = flexcan_setup_stop_mode_scfw(pdev); ret = flexcan_setup_stop_mode_scfw(pdev);
else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR) else if (priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR)
ret = flexcan_setup_stop_mode_gpr(pdev); 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 else
/* return 0 directly if doesn't support stop mode feature */ /* return 0 directly if doesn't support stop mode feature */
return 0; return 0;
...@@ -2009,6 +2031,7 @@ static const struct of_device_id flexcan_of_match[] = { ...@@ -2009,6 +2031,7 @@ static const struct of_device_id flexcan_of_match[] = {
{ .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, }, { .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
{ .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, }, { .compatible = "fsl,imx8mp-flexcan", .data = &fsl_imx8mp_devtype_data, },
{ .compatible = "fsl,imx93-flexcan", .data = &fsl_imx93_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,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
{ .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, }, { .compatible = "fsl,imx28-flexcan", .data = &fsl_imx28_devtype_data, },
{ .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, }, { .compatible = "fsl,imx53-flexcan", .data = &fsl_imx25_devtype_data, },
...@@ -2309,10 +2332,20 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device) ...@@ -2309,10 +2332,20 @@ static int __maybe_unused flexcan_noirq_suspend(struct device *device)
if (device_may_wakeup(device)) if (device_may_wakeup(device))
flexcan_enable_wakeup_irq(priv, true); flexcan_enable_wakeup_irq(priv, true);
/* 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); err = pm_runtime_force_suspend(device);
if (err) if (err)
return err; return err;
} }
}
return 0; return 0;
} }
...@@ -2325,9 +2358,12 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device) ...@@ -2325,9 +2358,12 @@ static int __maybe_unused flexcan_noirq_resume(struct device *device)
if (netif_running(dev)) { if (netif_running(dev)) {
int err; int err;
if (!(device_may_wakeup(device) &&
priv->devtype_data.quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE_SCMI)) {
err = pm_runtime_force_resume(device); err = pm_runtime_force_resume(device);
if (err) if (err)
return err; return err;
}
if (device_may_wakeup(device)) if (device_may_wakeup(device))
flexcan_enable_wakeup_irq(priv, false); flexcan_enable_wakeup_irq(priv, false);
......
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
#define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15) #define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15)
/* Device supports RX via FIFO */ /* Device supports RX via FIFO */
#define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16) #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 { struct flexcan_devtype_data {
u32 quirks; /* quirks needed for different IP cores */ u32 quirks; /* quirks needed for different IP cores */
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
*/ */
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/ktime.h>
#include <linux/math64.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/usb.h> #include <linux/usb.h>
...@@ -39,7 +41,6 @@ ...@@ -39,7 +41,6 @@
#define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0) #define KVASER_USB_QUIRK_HAS_SILENT_MODE BIT(0)
#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1) #define KVASER_USB_QUIRK_HAS_TXRX_ERRORS BIT(1)
#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2) #define KVASER_USB_QUIRK_IGNORE_CLK_FREQ BIT(2)
#define KVASER_USB_QUIRK_HAS_HARDWARE_TIMESTAMP BIT(3)
/* Device capabilities */ /* Device capabilities */
#define KVASER_USB_CAP_BERR_CAP 0x01 #define KVASER_USB_CAP_BERR_CAP 0x01
...@@ -68,6 +69,7 @@ struct kvaser_usb_dev_card_data { ...@@ -68,6 +69,7 @@ struct kvaser_usb_dev_card_data {
u32 ctrlmode_supported; u32 ctrlmode_supported;
u32 capabilities; u32 capabilities;
struct kvaser_usb_dev_card_data_hydra hydra; struct kvaser_usb_dev_card_data_hydra hydra;
u32 usbcan_timestamp_msb;
}; };
/* Context for an outstanding, not yet ACKed, transmission */ /* Context for an outstanding, not yet ACKed, transmission */
...@@ -216,4 +218,26 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev); ...@@ -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; 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 */ #endif /* KVASER_USB_H */
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
#define USB_MINI_PCIE_1XCAN_PRODUCT_ID 0x011B #define USB_MINI_PCIE_1XCAN_PRODUCT_ID 0x011B
static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = { 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, .ops = &kvaser_usb_hydra_dev_ops,
}; };
...@@ -754,13 +754,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, ...@@ -754,13 +754,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
} }
static const struct net_device_ops kvaser_usb_netdev_ops = { 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_open = kvaser_usb_open,
.ndo_stop = kvaser_usb_close, .ndo_stop = kvaser_usb_close,
.ndo_eth_ioctl = can_eth_ioctl_hwts, .ndo_eth_ioctl = can_eth_ioctl_hwts,
...@@ -769,10 +762,6 @@ static const struct net_device_ops kvaser_usb_netdev_ops_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 = { 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, .get_ts_info = can_ethtool_op_get_ts_info_hwts,
}; };
...@@ -858,14 +847,8 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel) ...@@ -858,14 +847,8 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
netdev->flags |= IFF_ECHO; 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->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); SET_NETDEV_DEV(netdev, &dev->intf->dev);
netdev->dev_id = channel; netdev->dev_id = channel;
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
* - Transition from CAN_STATE_ERROR_WARNING to CAN_STATE_ERROR_ACTIVE is only * - 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 * reported after a call to do_get_berr_counter(), since firmware does not
* distinguish between ERROR_WARNING and ERROR_ACTIVE. * distinguish between ERROR_WARNING and ERROR_ACTIVE.
* - Hardware timestamps are not set for CAN Tx frames.
*/ */
#include <linux/completion.h> #include <linux/completion.h>
...@@ -261,6 +260,15 @@ struct kvaser_cmd_tx_can { ...@@ -261,6 +260,15 @@ struct kvaser_cmd_tx_can {
u8 reserved[11]; u8 reserved[11];
} __packed; } __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 { struct kvaser_cmd_header {
u8 cmd_no; u8 cmd_no;
/* The destination HE address is stored in 0..5 of he_addr. /* The destination HE address is stored in 0..5 of he_addr.
...@@ -297,6 +305,7 @@ struct kvaser_cmd { ...@@ -297,6 +305,7 @@ struct kvaser_cmd {
struct kvaser_cmd_rx_can rx_can; struct kvaser_cmd_rx_can rx_can;
struct kvaser_cmd_tx_can tx_can; struct kvaser_cmd_tx_can tx_can;
struct kvaser_cmd_tx_ack tx_ack;
} __packed; } __packed;
} __packed; } __packed;
...@@ -522,23 +531,25 @@ kvaser_usb_hydra_net_priv_from_cmd(const struct kvaser_usb *dev, ...@@ -522,23 +531,25 @@ kvaser_usb_hydra_net_priv_from_cmd(const struct kvaser_usb *dev,
return priv; return priv;
} }
static ktime_t static ktime_t kvaser_usb_hydra_ktime_from_cmd(const struct kvaser_usb_dev_cfg *cfg,
kvaser_usb_hydra_ktime_from_rx_cmd(const struct kvaser_usb_dev_cfg *cfg,
const struct kvaser_cmd *cmd) const struct kvaser_cmd *cmd)
{ {
u64 ticks; ktime_t hwtstamp = 0;
if (cmd->header.cmd_no == CMD_EXTENDED) { if (cmd->header.cmd_no == CMD_EXTENDED) {
struct kvaser_cmd_ext *cmd_ext = (struct kvaser_cmd_ext *)cmd; struct kvaser_cmd_ext *cmd_ext = (struct kvaser_cmd_ext *)cmd;
ticks = le64_to_cpu(cmd_ext->rx_can.timestamp); if (cmd_ext->cmd_no_ext == CMD_RX_MESSAGE_FD)
} else { hwtstamp = kvaser_usb_timestamp64_to_ktime(cfg, cmd_ext->rx_can.timestamp);
ticks = le16_to_cpu(cmd->rx_can.timestamp[0]); else if (cmd_ext->cmd_no_ext == CMD_TX_ACKNOWLEDGE_FD)
ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[1])) << 16; hwtstamp = kvaser_usb_timestamp64_to_ktime(cfg, cmd_ext->tx_ack.timestamp);
ticks += (u64)(le16_to_cpu(cmd->rx_can.timestamp[2])) << 32; } 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, 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, ...@@ -1175,6 +1186,7 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev,
bool one_shot_fail = false; bool one_shot_fail = false;
bool is_err_frame = false; bool is_err_frame = false;
u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd); u16 transid = kvaser_usb_hydra_get_cmd_transid(cmd);
struct sk_buff *skb;
priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd); priv = kvaser_usb_hydra_net_priv_from_cmd(dev, cmd);
if (!priv) if (!priv)
...@@ -1201,6 +1213,9 @@ static void kvaser_usb_hydra_tx_acknowledge(const struct kvaser_usb *dev, ...@@ -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); 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); len = can_get_echo_skb(priv->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;
...@@ -1234,7 +1249,7 @@ static void kvaser_usb_hydra_rx_msg_std(const struct kvaser_usb *dev, ...@@ -1234,7 +1249,7 @@ static void kvaser_usb_hydra_rx_msg_std(const struct kvaser_usb *dev,
stats = &priv->netdev->stats; stats = &priv->netdev->stats;
flags = cmd->rx_can.flags; 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) { if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data, 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, ...@@ -1302,7 +1317,7 @@ static void kvaser_usb_hydra_rx_msg_ext(const struct kvaser_usb *dev,
KVASER_USB_KCAN_DATA_DLC_SHIFT; KVASER_USB_KCAN_DATA_DLC_SHIFT;
flags = le32_to_cpu(cmd->rx_can.flags); 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) { if (flags & KVASER_USB_HYDRA_CF_FLAG_ERROR_FRAME) {
kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data, kvaser_usb_hydra_error_frame(priv, &cmd->rx_can.err_frame_data,
......
...@@ -119,6 +119,10 @@ ...@@ -119,6 +119,10 @@
/* Extended CAN identifier flag */ /* Extended CAN identifier flag */
#define KVASER_EXTENDED_FRAME BIT(31) #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 { struct kvaser_cmd_simple {
u8 tid; u8 tid;
u8 channel; u8 channel;
...@@ -235,6 +239,20 @@ struct kvaser_cmd_tx_acknowledge_header { ...@@ -235,6 +239,20 @@ struct kvaser_cmd_tx_acknowledge_header {
u8 tid; u8 tid;
} __packed; } __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 { struct leaf_cmd_can_error_event {
u8 tid; u8 tid;
u8 flags; u8 flags;
...@@ -281,6 +299,12 @@ struct usbcan_cmd_error_event { ...@@ -281,6 +299,12 @@ struct usbcan_cmd_error_event {
__le16 padding; __le16 padding;
} __packed; } __packed;
struct usbcan_cmd_clk_overflow_event {
u8 tid;
u8 padding;
__le32 time;
} __packed;
struct kvaser_cmd_ctrl_mode { struct kvaser_cmd_ctrl_mode {
u8 tid; u8 tid;
u8 channel; u8 channel;
...@@ -347,6 +371,7 @@ struct kvaser_cmd { ...@@ -347,6 +371,7 @@ struct kvaser_cmd {
struct leaf_cmd_error_event error_event; struct leaf_cmd_error_event error_event;
struct kvaser_cmd_cap_req cap_req; struct kvaser_cmd_cap_req cap_req;
struct kvaser_cmd_cap_res cap_res; struct kvaser_cmd_cap_res cap_res;
struct leaf_cmd_tx_acknowledge tx_ack;
} __packed leaf; } __packed leaf;
union { union {
...@@ -355,6 +380,8 @@ struct kvaser_cmd { ...@@ -355,6 +380,8 @@ struct kvaser_cmd {
struct usbcan_cmd_chip_state_event chip_state_event; struct usbcan_cmd_chip_state_event chip_state_event;
struct usbcan_cmd_can_error_event can_error_event; struct usbcan_cmd_can_error_event can_error_event;
struct usbcan_cmd_error_event 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; } __packed usbcan;
struct kvaser_cmd_tx_can tx_can; struct kvaser_cmd_tx_can tx_can;
...@@ -370,7 +397,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = { ...@@ -370,7 +397,7 @@ static const u8 kvaser_usb_leaf_cmd_sizes_leaf[] = {
[CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple), [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple), [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo), [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_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.leaf.softinfo),
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can), [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.leaf.rx_can),
[CMD_RX_EXT_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[] = { ...@@ -388,15 +415,14 @@ static const u8 kvaser_usb_leaf_cmd_sizes_usbcan[] = {
[CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple), [CMD_START_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple), [CMD_STOP_CHIP_REPLY] = kvaser_fsize(u.simple),
[CMD_GET_CARD_INFO_REPLY] = kvaser_fsize(u.cardinfo), [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_GET_SOFTWARE_INFO_REPLY] = kvaser_fsize(u.usbcan.softinfo),
[CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can), [CMD_RX_STD_MESSAGE] = kvaser_fsize(u.usbcan.rx_can),
[CMD_RX_EXT_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_CHIP_STATE_EVENT] = kvaser_fsize(u.usbcan.chip_state_event),
[CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event), [CMD_CAN_ERROR_EVENT] = kvaser_fsize(u.usbcan.can_error_event),
[CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event), [CMD_ERROR_EVENT] = kvaser_fsize(u.usbcan.error_event),
/* ignored events: */ [CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = kvaser_fsize(u.usbcan.clk_overflow_event),
[CMD_USBCAN_CLOCK_OVERFLOW_EVENT] = CMD_SIZE_ANY,
}; };
/* Summary of a kvaser error event, for a unified Leaf/Usbcan error /* 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 = { ...@@ -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, .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 = { .clock = {
.freq = 16 * MEGA /* Hz */, .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, .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 = { ...@@ -475,7 +517,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
.clock = { .clock = {
.freq = 16 * MEGA /* Hz */, .freq = 16 * MEGA /* Hz */,
}, },
.timestamp_freq = 1, .timestamp_freq = 16,
.bittiming_const = &kvaser_usb_flexc_bittiming_const, .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 = { ...@@ -483,7 +525,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
.clock = { .clock = {
.freq = 24 * MEGA /* Hz */, .freq = 24 * MEGA /* Hz */,
}, },
.timestamp_freq = 1, .timestamp_freq = 24,
.bittiming_const = &kvaser_usb_flexc_bittiming_const, .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 = { ...@@ -491,10 +533,19 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
.clock = { .clock = {
.freq = 32 * MEGA /* Hz */, .freq = 32 * MEGA /* Hz */,
}, },
.timestamp_freq = 1, .timestamp_freq = 32,
.bittiming_const = &kvaser_usb_flexc_bittiming_const, .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, static int kvaser_usb_leaf_verify_size(const struct kvaser_usb *dev,
const struct kvaser_cmd *cmd) const struct kvaser_cmd *cmd)
{ {
...@@ -678,8 +729,19 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev, ...@@ -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) { if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
/* Firmware expects bittiming parameters calculated for 16MHz /* Firmware expects bittiming parameters calculated for 16MHz
* clock, regardless of the actual clock * 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 { } else {
switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) { switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK: 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, ...@@ -880,6 +942,8 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
struct kvaser_usb_net_priv *priv; struct kvaser_usb_net_priv *priv;
unsigned long flags; unsigned long flags;
u8 channel, tid; u8 channel, tid;
struct sk_buff *skb;
ktime_t hwtstamp = 0;
channel = cmd->u.tx_acknowledge_header.channel; channel = cmd->u.tx_acknowledge_header.channel;
tid = cmd->u.tx_acknowledge_header.tid; tid = cmd->u.tx_acknowledge_header.tid;
...@@ -901,14 +965,14 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev, ...@@ -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 */ /* Sometimes the state change doesn't come after a bus-off event */
if (priv->can.restart_ms && priv->can.state == CAN_STATE_BUS_OFF) { 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; struct can_frame *cf;
skb = alloc_can_err_skb(priv->netdev, &cf); err_skb = alloc_can_err_skb(priv->netdev, &cf);
if (skb) { if (err_skb) {
cf->can_id |= CAN_ERR_RESTARTED; cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb); netif_rx(err_skb);
} else { } else {
netdev_err(priv->netdev, netdev_err(priv->netdev,
"No memory left for err_skb\n"); "No memory left for err_skb\n");
...@@ -919,9 +983,20 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev, ...@@ -919,9 +983,20 @@ static void kvaser_usb_leaf_tx_acknowledge(const struct kvaser_usb *dev,
priv->can.state = CAN_STATE_ERROR_ACTIVE; 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); 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_packets++;
stats->tx_bytes += can_get_echo_skb(priv->netdev, stats->tx_bytes += can_get_echo_skb(priv->netdev,
context->echo_index, NULL); context->echo_index, NULL);
...@@ -1299,6 +1374,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev, ...@@ -1299,6 +1374,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
struct net_device_stats *stats; struct net_device_stats *stats;
u8 channel = cmd->u.rx_can_header.channel; u8 channel = cmd->u.rx_can_header.channel;
const u8 *rx_data = NULL; /* GCC */ const u8 *rx_data = NULL; /* GCC */
ktime_t hwtstamp = 0;
if (channel >= dev->nchannels) { if (channel >= dev->nchannels) {
dev_err(&dev->intf->dev, dev_err(&dev->intf->dev,
...@@ -1329,9 +1405,11 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev, ...@@ -1329,9 +1405,11 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
switch (dev->driver_info->family) { switch (dev->driver_info->family) {
case KVASER_LEAF: case KVASER_LEAF:
rx_data = cmd->u.leaf.rx_can.data; rx_data = cmd->u.leaf.rx_can.data;
hwtstamp = kvaser_usb_timestamp48_to_ktime(dev->cfg, cmd->u.leaf.rx_can.time);
break; break;
case KVASER_USBCAN: case KVASER_USBCAN:
rx_data = cmd->u.usbcan.rx_can.data; rx_data = cmd->u.usbcan.rx_can.data;
hwtstamp = kvaser_usb_usbcan_timestamp_to_ktime(dev, cmd->u.usbcan.rx_can.time);
break; break;
} }
...@@ -1375,6 +1453,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev, ...@@ -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); memcpy(cf->data, &rx_data[6], cf->len);
} }
skb_hwtstamps(skb)->hwtstamp = hwtstamp;
stats->rx_packets++; stats->rx_packets++;
if (!(cf->can_id & CAN_RTR_FLAG)) if (!(cf->can_id & CAN_RTR_FLAG))
stats->rx_bytes += cf->len; stats->rx_bytes += cf->len;
...@@ -1508,7 +1587,7 @@ static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev, ...@@ -1508,7 +1587,7 @@ static void kvaser_usb_leaf_get_busparams_reply(const struct kvaser_usb *dev,
complete(&priv->get_busparams_comp); 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) const struct kvaser_cmd *cmd)
{ {
if (kvaser_usb_leaf_verify_size(dev, cmd) < 0) 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, ...@@ -1554,12 +1633,15 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
kvaser_usb_leaf_get_busparams_reply(dev, cmd); kvaser_usb_leaf_get_busparams_reply(dev, cmd);
break; break;
/* Ignored commands */
case CMD_USBCAN_CLOCK_OVERFLOW_EVENT: case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
if (dev->driver_info->family != KVASER_USBCAN) if (dev->driver_info->family != KVASER_USBCAN)
goto warn; 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; break;
/* Ignored commands */
case CMD_FLUSH_QUEUE_REPLY: case CMD_FLUSH_QUEUE_REPLY:
if (dev->driver_info->family != KVASER_LEAF) if (dev->driver_info->family != KVASER_LEAF)
goto warn; goto warn;
......
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