mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
linux-can-next-for-6.1-20220915
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEBsvAIBsPu6mG7thcrX5LkNig010FAmMi3OwTHG1rbEBwZW5n dXRyb25peC5kZQAKCRCtfkuQ2KDTXafhCACHLzDn9otKPWe+w6Lt1RSuhKvhbuhO XywQ4EBEUddOrqYarEuFiuWZMq1/PLGnkWVQotzElZR9HtkTUUetXgfsWHv39uo+ SqUK7P+DnuT9AvvUkk1ZoyVYxs8FnVWoPlcBli+zXZCjtg/XYn/2qPGJlaNPovLv hzVokS/RVxlPIrQiNWVmkHyTb6LyLdLit802dtdaxKmQcUCgYVAiz+DwR0PwBEWs e1K046RIfl5QejpkVq+pIXpTGu1C4m2bv1umPCts1OLtBGkHf7Dwu9HmgWPDwY91 0oJt/00NpQLgg77vnOJnv0M/TZE9cP9gp7zFh7b43qg0TpIzHhJJYJut =UEkq -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-6.1-20220915' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== Sept. 15, 2022, 8:19 a.m. UTC Hello Jakub, hello David, this is a pull request of 23 patches for net-next/master. the first 2 patches are by me and fix a typo in the rx-offload helper and the flexcan driver. Christophe JAILLET's patch cleans up the error handling in rcar_canfd driver's probe function. Kenneth Lee's patch converts the kvaser_usb driver from kcalloc() to kzalloc(). Biju Das contributes 2 patches to the sja1000 driver which update the DT bindings and support for the RZ/N1 SJA1000 CAN controller. Jinpeng Cui provides 2 patches that remove redundant variables from the sja1000 and kvaser_pciefd driver. 2 patches by John Whittington and me add hardware timestamp support to the gs_usb driver. Gustavo A. R. Silva's patch converts the etas_es58x driver to make use of DECLARE_FLEX_ARRAY(). Krzysztof Kozlowski's patch cleans up the sja1000 DT bindings. Dario Binacchi fixes his invalid email in the flexcan driver documentation. Ziyang Xuan contributes 2 patches that clean up the CAN RAW protocol. Yang Yingliang's patch switches the flexcan driver to dev_err_probe(). The last 7 patches are by Oliver Hartkopp and add support for the next generation of the CAN protocol: CAN with eXtended data Length (CAN XL). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
5947b7f794
@ -30,8 +30,10 @@ properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
reg-io-width:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: I/O register width (in bytes) implemented by this device
|
||||
default: 1
|
||||
enum: [ 1, 2, 4 ]
|
||||
@ -105,6 +107,7 @@ allOf:
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
- power-domains
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
@ -129,4 +132,5 @@ examples:
|
||||
reg-io-width = <4>;
|
||||
interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&sysctrl R9A06G032_HCLK_CAN0>;
|
||||
power-domains = <&sysctrl>;
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ Flexcan CAN Controller driver
|
||||
=============================
|
||||
|
||||
Authors: Marc Kleine-Budde <mkl@pengutronix.de>,
|
||||
Dario Binacchi <dario.binacchi@amarula.solutions.com>
|
||||
Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
||||
|
||||
On/off RTR frames reception
|
||||
===========================
|
||||
|
@ -657,7 +657,6 @@ static void ctucan_read_rx_frame(struct ctucan_priv *priv, struct canfd_frame *c
|
||||
cf->can_id = (idw >> 18) & CAN_SFF_MASK;
|
||||
|
||||
/* BRS, ESI, RTR Flags */
|
||||
cf->flags = 0;
|
||||
if (FIELD_GET(REG_FRAME_FORMAT_W_FDF, ffw)) {
|
||||
if (FIELD_GET(REG_FRAME_FORMAT_W_BRS, ffw))
|
||||
cf->flags |= CANFD_BRS;
|
||||
|
@ -247,7 +247,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
struct net_device *dev = offload->dev;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
struct sk_buff *skb;
|
||||
u8 len;
|
||||
unsigned int len;
|
||||
int err;
|
||||
|
||||
skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
|
||||
@ -329,7 +329,7 @@ static int can_rx_offload_init_queue(struct net_device *dev,
|
||||
{
|
||||
offload->dev = dev;
|
||||
|
||||
/* Limit queue len to 4x the weight (rounted to next power of two) */
|
||||
/* Limit queue len to 4x the weight (rounded to next power of two) */
|
||||
offload->skb_queue_len_max = 2 << fls(weight);
|
||||
offload->skb_queue_len_max *= 4;
|
||||
skb_queue_head_init(&offload->skb_queue);
|
||||
|
@ -91,8 +91,8 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||
EXPORT_SYMBOL_GPL(can_put_echo_skb);
|
||||
|
||||
struct sk_buff *
|
||||
__can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
|
||||
unsigned int *frame_len_ptr)
|
||||
__can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
unsigned int *len_ptr, unsigned int *frame_len_ptr)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
@ -108,16 +108,12 @@ __can_get_echo_skb(struct net_device *dev, unsigned int idx, u8 *len_ptr,
|
||||
*/
|
||||
struct sk_buff *skb = priv->echo_skb[idx];
|
||||
struct can_skb_priv *can_skb_priv = can_skb_prv(skb);
|
||||
struct canfd_frame *cf = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)
|
||||
skb_tstamp_tx(skb, skb_hwtstamps(skb));
|
||||
|
||||
/* get the real payload length for netdev statistics */
|
||||
if (cf->can_id & CAN_RTR_FLAG)
|
||||
*len_ptr = 0;
|
||||
else
|
||||
*len_ptr = cf->len;
|
||||
*len_ptr = can_skb_get_data_len(skb);
|
||||
|
||||
if (frame_len_ptr)
|
||||
*frame_len_ptr = can_skb_priv->frame_len;
|
||||
@ -147,7 +143,7 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
unsigned int *frame_len_ptr)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 len;
|
||||
unsigned int len;
|
||||
|
||||
skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr);
|
||||
if (!skb)
|
||||
@ -191,6 +187,20 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_free_echo_skb);
|
||||
|
||||
/* fill common values for CAN sk_buffs */
|
||||
static void init_can_skb_reserve(struct sk_buff *skb)
|
||||
{
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
}
|
||||
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -204,16 +214,8 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
init_can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
*cf = skb_put_zero(skb, sizeof(struct can_frame));
|
||||
|
||||
@ -235,23 +237,51 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
}
|
||||
|
||||
skb->protocol = htons(ETH_P_CANFD);
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
can_skb_reserve(skb);
|
||||
init_can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
*cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
|
||||
|
||||
/* set CAN FD flag by default */
|
||||
(*cfd)->flags = CANFD_FDF;
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_canfd_skb);
|
||||
|
||||
struct sk_buff *alloc_canxl_skb(struct net_device *dev,
|
||||
struct canxl_frame **cxl,
|
||||
unsigned int data_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (data_len < CANXL_MIN_DLEN || data_len > CANXL_MAX_DLEN)
|
||||
goto out_error;
|
||||
|
||||
skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
|
||||
CANXL_HDR_SIZE + data_len);
|
||||
if (unlikely(!skb))
|
||||
goto out_error;
|
||||
|
||||
skb->protocol = htons(ETH_P_CANXL);
|
||||
init_can_skb_reserve(skb);
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
|
||||
*cxl = skb_put_zero(skb, CANXL_HDR_SIZE + data_len);
|
||||
|
||||
/* set CAN XL flag and length information by default */
|
||||
(*cxl)->flags = CANXL_XLF;
|
||||
(*cxl)->len = data_len;
|
||||
|
||||
return skb;
|
||||
|
||||
out_error:
|
||||
*cxl = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(alloc_canxl_skb);
|
||||
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -291,6 +321,14 @@ static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
|
||||
skb_reset_mac_header(skb);
|
||||
skb_reset_network_header(skb);
|
||||
skb_reset_transport_header(skb);
|
||||
|
||||
/* set CANFD_FDF flag for CAN FD frames */
|
||||
if (can_is_canfd_skb(skb)) {
|
||||
struct canfd_frame *cfd;
|
||||
|
||||
cfd = (struct canfd_frame *)skb->data;
|
||||
cfd->flags |= CANFD_FDF;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -299,18 +337,25 @@ static bool can_skb_headroom_valid(struct net_device *dev, struct sk_buff *skb)
|
||||
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (skb->protocol == htons(ETH_P_CAN)) {
|
||||
if (unlikely(skb->len != CAN_MTU ||
|
||||
cfd->len > CAN_MAX_DLEN))
|
||||
switch (ntohs(skb->protocol)) {
|
||||
case ETH_P_CAN:
|
||||
if (!can_is_can_skb(skb))
|
||||
goto inval_skb;
|
||||
} else if (skb->protocol == htons(ETH_P_CANFD)) {
|
||||
if (unlikely(skb->len != CANFD_MTU ||
|
||||
cfd->len > CANFD_MAX_DLEN))
|
||||
break;
|
||||
|
||||
case ETH_P_CANFD:
|
||||
if (!can_is_canfd_skb(skb))
|
||||
goto inval_skb;
|
||||
} else {
|
||||
break;
|
||||
|
||||
case ETH_P_CANXL:
|
||||
if (!can_is_canxl_skb(skb))
|
||||
goto inval_skb;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
|
@ -295,45 +295,45 @@ static_assert(sizeof(struct flexcan_regs) == 0x4 * 18 + 0xfb8);
|
||||
static const struct flexcan_devtype_data fsl_mcf5441x_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_NR_MB_16 |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_FIFO,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_FIFO,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_p1010_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_FIFO,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_FIFO,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_imx25_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_FIFO,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_FIFO,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_imx28_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_FIFO,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_FIFO,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
|
||||
@ -341,23 +341,23 @@ static struct flexcan_devtype_data fsl_imx8mp_devtype_data = {
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SETUP_STOP_MODE_GPR |
|
||||
FLEXCAN_QUIRK_SUPPORT_FD | FLEXCAN_QUIRK_SUPPORT_ECC |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
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 |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_SUPPORT_ECC |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE | FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = {
|
||||
@ -365,8 +365,8 @@ static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = {
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_SUPPORT_FD |
|
||||
FLEXCAN_QUIRK_SUPPORT_ECC |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR,
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct can_bittiming_const flexcan_bittiming_const = {
|
||||
@ -2085,20 +2085,20 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) &&
|
||||
!((devtype_data->quirks &
|
||||
(FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_FIFO)) ==
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_FIFO)) ==
|
||||
(FLEXCAN_QUIRK_USE_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR))) {
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR))) {
|
||||
dev_err(&pdev->dev, "CAN-FD mode doesn't work in RX-FIFO mode!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((devtype_data->quirks &
|
||||
(FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR)) ==
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR) {
|
||||
(FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR)) ==
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR) {
|
||||
dev_err(&pdev->dev,
|
||||
"Quirks (0x%08x) inconsistent: RX_MAILBOX_RX supported but not RX_MAILBOX\n",
|
||||
devtype_data->quirks);
|
||||
@ -2177,8 +2177,7 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
|
||||
err = flexcan_setup_stop_mode(pdev);
|
||||
if (err < 0) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "setup stop mode failed\n");
|
||||
dev_err_probe(&pdev->dev, err, "setup stop mode failed\n");
|
||||
goto failed_setup_stop_mode;
|
||||
}
|
||||
|
||||
|
@ -63,11 +63,11 @@
|
||||
/* Setup 16 mailboxes */
|
||||
#define FLEXCAN_QUIRK_NR_MB_16 BIT(13)
|
||||
/* Device supports RX via mailboxes */
|
||||
#define FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX BIT(14)
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX BIT(14)
|
||||
/* Device supports RTR reception via mailboxes */
|
||||
#define FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR BIT(15)
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR BIT(15)
|
||||
/* Device supports RX via FIFO */
|
||||
#define FLEXCAN_QUIRK_SUPPPORT_RX_FIFO BIT(16)
|
||||
#define FLEXCAN_QUIRK_SUPPORT_RX_FIFO BIT(16)
|
||||
|
||||
struct flexcan_devtype_data {
|
||||
u32 quirks; /* quirks needed for different IP cores */
|
||||
@ -121,7 +121,7 @@ flexcan_supports_rx_mailbox(const struct flexcan_priv *priv)
|
||||
{
|
||||
const u32 quirks = priv->devtype_data.quirks;
|
||||
|
||||
return quirks & FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX;
|
||||
return quirks & FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -129,10 +129,10 @@ flexcan_supports_rx_mailbox_rtr(const struct flexcan_priv *priv)
|
||||
{
|
||||
const u32 quirks = priv->devtype_data.quirks;
|
||||
|
||||
return (quirks & (FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR)) ==
|
||||
(FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR);
|
||||
return (quirks & (FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR)) ==
|
||||
(FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX |
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -140,7 +140,7 @@ flexcan_supports_rx_fifo(const struct flexcan_priv *priv)
|
||||
{
|
||||
const u32 quirks = priv->devtype_data.quirks;
|
||||
|
||||
return quirks & FLEXCAN_QUIRK_SUPPPORT_RX_FIFO;
|
||||
return quirks & FLEXCAN_QUIRK_SUPPORT_RX_FIFO;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@ -149,7 +149,7 @@ flexcan_active_rx_rtr(const struct flexcan_priv *priv)
|
||||
const u32 quirks = priv->devtype_data.quirks;
|
||||
|
||||
if (quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) {
|
||||
if (quirks & FLEXCAN_QUIRK_SUPPPORT_RX_MAILBOX_RTR)
|
||||
if (quirks & FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR)
|
||||
return true;
|
||||
} else {
|
||||
/* RX-FIFO is always RTR capable */
|
||||
|
@ -329,12 +329,9 @@ MODULE_DEVICE_TABLE(pci, kvaser_pciefd_id_table);
|
||||
static int kvaser_pciefd_spi_wait_loop(struct kvaser_pciefd *pcie, int msk)
|
||||
{
|
||||
u32 res;
|
||||
int ret;
|
||||
|
||||
ret = readl_poll_timeout(pcie->reg_base + KVASER_PCIEFD_SPI_STATUS_REG,
|
||||
res, res & msk, 0, 10);
|
||||
|
||||
return ret;
|
||||
return readl_poll_timeout(pcie->reg_base + KVASER_PCIEFD_SPI_STATUS_REG,
|
||||
res, res & msk, 0, 10);
|
||||
}
|
||||
|
||||
static int kvaser_pciefd_spi_cmd(struct kvaser_pciefd *pcie, const u8 *tx,
|
||||
|
@ -1880,10 +1880,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
|
||||
/* Global controller context */
|
||||
gpriv = devm_kzalloc(&pdev->dev, sizeof(*gpriv), GFP_KERNEL);
|
||||
if (!gpriv) {
|
||||
err = -ENOMEM;
|
||||
goto fail_dev;
|
||||
}
|
||||
if (!gpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
gpriv->pdev = pdev;
|
||||
gpriv->channels_mask = channels_mask;
|
||||
gpriv->fdmode = fdmode;
|
||||
@ -1904,12 +1903,9 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
|
||||
/* Peripheral clock */
|
||||
gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(gpriv->clkp)) {
|
||||
err = PTR_ERR(gpriv->clkp);
|
||||
dev_err(&pdev->dev, "cannot get peripheral clock, error %d\n",
|
||||
err);
|
||||
goto fail_dev;
|
||||
}
|
||||
if (IS_ERR(gpriv->clkp))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->clkp),
|
||||
"cannot get peripheral clock\n");
|
||||
|
||||
/* fCAN clock: Pick External clock. If not available fallback to
|
||||
* CANFD clock
|
||||
@ -1917,12 +1913,10 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
gpriv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
|
||||
if (IS_ERR(gpriv->can_clk) || (clk_get_rate(gpriv->can_clk) == 0)) {
|
||||
gpriv->can_clk = devm_clk_get(&pdev->dev, "canfd");
|
||||
if (IS_ERR(gpriv->can_clk)) {
|
||||
err = PTR_ERR(gpriv->can_clk);
|
||||
dev_err(&pdev->dev,
|
||||
"cannot get canfd clock, error %d\n", err);
|
||||
goto fail_dev;
|
||||
}
|
||||
if (IS_ERR(gpriv->can_clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->can_clk),
|
||||
"cannot get canfd clock\n");
|
||||
|
||||
gpriv->fcan = RCANFD_CANFDCLK;
|
||||
|
||||
} else {
|
||||
|
@ -661,8 +661,6 @@ static const struct ethtool_ops sja1000_ethtool_ops = {
|
||||
|
||||
int register_sja1000dev(struct net_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!sja1000_probe_chip(dev))
|
||||
return -ENODEV;
|
||||
|
||||
@ -673,9 +671,7 @@ int register_sja1000dev(struct net_device *dev)
|
||||
set_reset_mode(dev);
|
||||
chipset_init(dev);
|
||||
|
||||
ret = register_candev(dev);
|
||||
|
||||
return ret;
|
||||
return register_candev(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_sja1000dev);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/irq.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/platform/sja1000.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
@ -103,6 +104,11 @@ static void sp_technologic_init(struct sja1000_priv *priv, struct device_node *o
|
||||
spin_lock_init(&tp->io_lock);
|
||||
}
|
||||
|
||||
static void sp_rzn1_init(struct sja1000_priv *priv, struct device_node *of)
|
||||
{
|
||||
priv->flags = SJA1000_QUIRK_NO_CDR_REG;
|
||||
}
|
||||
|
||||
static void sp_populate(struct sja1000_priv *priv,
|
||||
struct sja1000_platform_data *pdata,
|
||||
unsigned long resource_mem_flags)
|
||||
@ -153,11 +159,13 @@ static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
|
||||
priv->write_reg = sp_write_reg8;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
|
||||
if (!err)
|
||||
priv->can.clock.freq = prop / 2;
|
||||
else
|
||||
priv->can.clock.freq = SP_CAN_CLOCK; /* default */
|
||||
if (!priv->can.clock.freq) {
|
||||
err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
|
||||
if (!err)
|
||||
priv->can.clock.freq = prop / 2;
|
||||
else
|
||||
priv->can.clock.freq = SP_CAN_CLOCK; /* default */
|
||||
}
|
||||
|
||||
err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
|
||||
if (!err)
|
||||
@ -192,8 +200,13 @@ static struct sja1000_of_data technologic_data = {
|
||||
.init = sp_technologic_init,
|
||||
};
|
||||
|
||||
static struct sja1000_of_data renesas_data = {
|
||||
.init = sp_rzn1_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id sp_of_table[] = {
|
||||
{ .compatible = "nxp,sja1000", .data = NULL, },
|
||||
{ .compatible = "renesas,rzn1-sja1000", .data = &renesas_data, },
|
||||
{ .compatible = "technologic,sja1000", .data = &technologic_data, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
@ -210,6 +223,7 @@ static int sp_probe(struct platform_device *pdev)
|
||||
struct device_node *of = pdev->dev.of_node;
|
||||
const struct sja1000_of_data *of_data = NULL;
|
||||
size_t priv_sz = 0;
|
||||
struct clk *clk;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
if (!pdata && !of) {
|
||||
@ -234,6 +248,11 @@ static int sp_probe(struct platform_device *pdev)
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(clk),
|
||||
"CAN clk operation failed");
|
||||
} else {
|
||||
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res_irq)
|
||||
@ -262,6 +281,15 @@ static int sp_probe(struct platform_device *pdev)
|
||||
priv->reg_base = addr;
|
||||
|
||||
if (of) {
|
||||
if (clk) {
|
||||
priv->can.clock.freq = clk_get_rate(clk) / 2;
|
||||
if (!priv->can.clock.freq) {
|
||||
err = -EINVAL;
|
||||
dev_err(&pdev->dev, "Zero CAN clk rate");
|
||||
goto exit_free;
|
||||
}
|
||||
}
|
||||
|
||||
sp_populate_of(priv, of);
|
||||
|
||||
if (of_data && of_data->init)
|
||||
|
@ -222,7 +222,7 @@ union es58x_urb_cmd {
|
||||
u8 cmd_type;
|
||||
u8 cmd_id;
|
||||
} __packed;
|
||||
u8 raw_cmd[0];
|
||||
DECLARE_FLEX_ARRAY(u8, raw_cmd);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -10,20 +10,24 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/error.h>
|
||||
|
||||
/* Device specific constants */
|
||||
#define USB_GSUSB_1_VENDOR_ID 0x1d50
|
||||
#define USB_GSUSB_1_PRODUCT_ID 0x606f
|
||||
#define USB_GS_USB_1_VENDOR_ID 0x1d50
|
||||
#define USB_GS_USB_1_PRODUCT_ID 0x606f
|
||||
|
||||
#define USB_CANDLELIGHT_VENDOR_ID 0x1209
|
||||
#define USB_CANDLELIGHT_PRODUCT_ID 0x2323
|
||||
@ -34,8 +38,16 @@
|
||||
#define USB_ABE_CANDEBUGGER_FD_VENDOR_ID 0x16d0
|
||||
#define USB_ABE_CANDEBUGGER_FD_PRODUCT_ID 0x10b8
|
||||
|
||||
#define GSUSB_ENDPOINT_IN 1
|
||||
#define GSUSB_ENDPOINT_OUT 2
|
||||
#define GS_USB_ENDPOINT_IN 1
|
||||
#define GS_USB_ENDPOINT_OUT 2
|
||||
|
||||
/* Timestamp 32 bit timer runs at 1 MHz (1 µs tick). Worker accounts
|
||||
* for timer overflow (will be after ~71 minutes)
|
||||
*/
|
||||
#define GS_USB_TIMESTAMP_TIMER_HZ (1 * HZ_PER_MHZ)
|
||||
#define GS_USB_TIMESTAMP_WORK_DELAY_SEC 1800
|
||||
static_assert(GS_USB_TIMESTAMP_WORK_DELAY_SEC <
|
||||
CYCLECOUNTER_MASK(32) / GS_USB_TIMESTAMP_TIMER_HZ / 2);
|
||||
|
||||
/* Device specific constants */
|
||||
enum gs_usb_breq {
|
||||
@ -199,6 +211,11 @@ struct classic_can {
|
||||
u8 data[8];
|
||||
} __packed;
|
||||
|
||||
struct classic_can_ts {
|
||||
u8 data[8];
|
||||
__le32 timestamp_us;
|
||||
} __packed;
|
||||
|
||||
struct classic_can_quirk {
|
||||
u8 data[8];
|
||||
u8 quirk;
|
||||
@ -208,6 +225,11 @@ struct canfd {
|
||||
u8 data[64];
|
||||
} __packed;
|
||||
|
||||
struct canfd_ts {
|
||||
u8 data[64];
|
||||
__le32 timestamp_us;
|
||||
} __packed;
|
||||
|
||||
struct canfd_quirk {
|
||||
u8 data[64];
|
||||
u8 quirk;
|
||||
@ -224,8 +246,10 @@ struct gs_host_frame {
|
||||
|
||||
union {
|
||||
DECLARE_FLEX_ARRAY(struct classic_can, classic_can);
|
||||
DECLARE_FLEX_ARRAY(struct classic_can_ts, classic_can_ts);
|
||||
DECLARE_FLEX_ARRAY(struct classic_can_quirk, classic_can_quirk);
|
||||
DECLARE_FLEX_ARRAY(struct canfd, canfd);
|
||||
DECLARE_FLEX_ARRAY(struct canfd_ts, canfd_ts);
|
||||
DECLARE_FLEX_ARRAY(struct canfd_quirk, canfd_quirk);
|
||||
};
|
||||
} __packed;
|
||||
@ -259,6 +283,11 @@ struct gs_can {
|
||||
struct can_bittiming_const bt_const, data_bt_const;
|
||||
unsigned int channel; /* channel number */
|
||||
|
||||
/* time counter for hardware timestamps */
|
||||
struct cyclecounter cc;
|
||||
struct timecounter tc;
|
||||
struct delayed_work timestamp;
|
||||
|
||||
u32 feature;
|
||||
unsigned int hf_size_tx;
|
||||
|
||||
@ -351,6 +380,87 @@ static int gs_cmd_reset(struct gs_can *gsdev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int gs_usb_get_timestamp(const struct gs_can *dev,
|
||||
u32 *timestamp_p)
|
||||
{
|
||||
__le32 timestamp;
|
||||
int rc;
|
||||
|
||||
rc = usb_control_msg_recv(interface_to_usbdev(dev->iface),
|
||||
usb_sndctrlpipe(interface_to_usbdev(dev->iface), 0),
|
||||
GS_USB_BREQ_TIMESTAMP,
|
||||
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
|
||||
dev->channel, 0,
|
||||
×tamp, sizeof(timestamp),
|
||||
USB_CTRL_GET_TIMEOUT,
|
||||
GFP_KERNEL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
*timestamp_p = le32_to_cpu(timestamp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 gs_usb_timestamp_read(const struct cyclecounter *cc)
|
||||
{
|
||||
const struct gs_can *dev;
|
||||
u32 timestamp = 0;
|
||||
int err;
|
||||
|
||||
dev = container_of(cc, struct gs_can, cc);
|
||||
err = gs_usb_get_timestamp(dev, ×tamp);
|
||||
if (err)
|
||||
netdev_err(dev->netdev,
|
||||
"Error %d while reading timestamp. HW timestamps may be inaccurate.",
|
||||
err);
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
static void gs_usb_timestamp_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct gs_can *dev;
|
||||
|
||||
dev = container_of(delayed_work, struct gs_can, timestamp);
|
||||
timecounter_read(&dev->tc);
|
||||
|
||||
schedule_delayed_work(&dev->timestamp,
|
||||
GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
|
||||
}
|
||||
|
||||
static void gs_usb_skb_set_timestamp(const struct gs_can *dev,
|
||||
struct sk_buff *skb, u32 timestamp)
|
||||
{
|
||||
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
|
||||
u64 ns;
|
||||
|
||||
ns = timecounter_cyc2time(&dev->tc, timestamp);
|
||||
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
||||
}
|
||||
|
||||
static void gs_usb_timestamp_init(struct gs_can *dev)
|
||||
{
|
||||
struct cyclecounter *cc = &dev->cc;
|
||||
|
||||
cc->read = gs_usb_timestamp_read;
|
||||
cc->mask = CYCLECOUNTER_MASK(32);
|
||||
cc->shift = 32 - bits_per(NSEC_PER_SEC / GS_USB_TIMESTAMP_TIMER_HZ);
|
||||
cc->mult = clocksource_hz2mult(GS_USB_TIMESTAMP_TIMER_HZ, cc->shift);
|
||||
|
||||
timecounter_init(&dev->tc, &dev->cc, ktime_get_real_ns());
|
||||
|
||||
INIT_DELAYED_WORK(&dev->timestamp, gs_usb_timestamp_work);
|
||||
schedule_delayed_work(&dev->timestamp,
|
||||
GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
|
||||
}
|
||||
|
||||
static void gs_usb_timestamp_stop(struct gs_can *dev)
|
||||
{
|
||||
cancel_delayed_work_sync(&dev->timestamp);
|
||||
}
|
||||
|
||||
static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
|
||||
{
|
||||
struct can_device_stats *can_stats = &dev->can.can_stats;
|
||||
@ -376,6 +486,24 @@ static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
|
||||
}
|
||||
}
|
||||
|
||||
static void gs_usb_set_timestamp(const struct gs_can *dev, struct sk_buff *skb,
|
||||
const struct gs_host_frame *hf)
|
||||
{
|
||||
u32 timestamp;
|
||||
|
||||
if (!(dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP))
|
||||
return;
|
||||
|
||||
if (hf->flags & GS_CAN_FLAG_FD)
|
||||
timestamp = le32_to_cpu(hf->canfd_ts->timestamp_us);
|
||||
else
|
||||
timestamp = le32_to_cpu(hf->classic_can_ts->timestamp_us);
|
||||
|
||||
gs_usb_skb_set_timestamp(dev, skb, timestamp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
{
|
||||
struct gs_usb *usbcan = urb->context;
|
||||
@ -443,6 +571,8 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
gs_update_state(dev, cf);
|
||||
}
|
||||
|
||||
gs_usb_set_timestamp(dev, skb, hf);
|
||||
|
||||
netdev->stats.rx_packets++;
|
||||
netdev->stats.rx_bytes += hf->can_dlc;
|
||||
|
||||
@ -465,6 +595,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
goto resubmit_urb;
|
||||
}
|
||||
|
||||
skb = dev->can.echo_skb[hf->echo_id];
|
||||
gs_usb_set_timestamp(dev, skb, hf);
|
||||
|
||||
netdev->stats.tx_packets++;
|
||||
netdev->stats.tx_bytes += can_get_echo_skb(netdev, hf->echo_id,
|
||||
NULL);
|
||||
@ -491,7 +624,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
|
||||
|
||||
resubmit_urb:
|
||||
usb_fill_bulk_urb(urb, usbcan->udev,
|
||||
usb_rcvbulkpipe(usbcan->udev, GSUSB_ENDPOINT_IN),
|
||||
usb_rcvbulkpipe(usbcan->udev, GS_USB_ENDPOINT_IN),
|
||||
hf, dev->parent->hf_size_rx,
|
||||
gs_usb_receive_bulk_callback, usbcan);
|
||||
|
||||
@ -659,7 +792,7 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
usb_fill_bulk_urb(urb, dev->udev,
|
||||
usb_sndbulkpipe(dev->udev, GSUSB_ENDPOINT_OUT),
|
||||
usb_sndbulkpipe(dev->udev, GS_USB_ENDPOINT_OUT),
|
||||
hf, dev->hf_size_tx,
|
||||
gs_usb_xmit_callback, txc);
|
||||
|
||||
@ -769,7 +902,7 @@ static int gs_can_open(struct net_device *netdev)
|
||||
usb_fill_bulk_urb(urb,
|
||||
dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev,
|
||||
GSUSB_ENDPOINT_IN),
|
||||
GS_USB_ENDPOINT_IN),
|
||||
buf,
|
||||
dev->parent->hf_size_rx,
|
||||
gs_usb_receive_bulk_callback, parent);
|
||||
@ -823,6 +956,10 @@ static int gs_can_open(struct net_device *netdev)
|
||||
if (ctrlmode & CAN_CTRLMODE_3_SAMPLES)
|
||||
flags |= GS_CAN_MODE_TRIPLE_SAMPLE;
|
||||
|
||||
/* if hardware supports timestamps, enable it */
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
flags |= GS_CAN_MODE_HW_TIMESTAMP;
|
||||
|
||||
/* finally start device */
|
||||
dm->mode = cpu_to_le32(GS_CAN_MODE_START);
|
||||
dm->flags = cpu_to_le32(flags);
|
||||
@ -840,6 +977,10 @@ static int gs_can_open(struct net_device *netdev)
|
||||
|
||||
kfree(dm);
|
||||
|
||||
/* start polling timestamp */
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_init(dev);
|
||||
|
||||
dev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
parent->active_channels++;
|
||||
@ -858,6 +999,10 @@ static int gs_can_close(struct net_device *netdev)
|
||||
|
||||
netif_stop_queue(netdev);
|
||||
|
||||
/* stop polling timestamp */
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
gs_usb_timestamp_stop(dev);
|
||||
|
||||
/* Stop polling */
|
||||
parent->active_channels--;
|
||||
if (!parent->active_channels) {
|
||||
@ -890,11 +1035,22 @@ static int gs_can_close(struct net_device *netdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gs_can_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
const struct gs_can *dev = netdev_priv(netdev);
|
||||
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
return can_eth_ioctl_hwts(netdev, ifr, cmd);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct net_device_ops gs_usb_netdev_ops = {
|
||||
.ndo_open = gs_can_open,
|
||||
.ndo_stop = gs_can_close,
|
||||
.ndo_start_xmit = gs_can_start_xmit,
|
||||
.ndo_change_mtu = can_change_mtu,
|
||||
.ndo_eth_ioctl = gs_can_eth_ioctl,
|
||||
};
|
||||
|
||||
static int gs_usb_set_identify(struct net_device *netdev, bool do_identify)
|
||||
@ -944,9 +1100,21 @@ static int gs_usb_set_phys_id(struct net_device *dev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gs_usb_get_ts_info(struct net_device *netdev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
struct gs_can *dev = netdev_priv(netdev);
|
||||
|
||||
/* report if device supports HW timestamps */
|
||||
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
return can_ethtool_op_get_ts_info_hwts(netdev, info);
|
||||
|
||||
return ethtool_op_get_ts_info(netdev, info);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops gs_usb_ethtool_ops = {
|
||||
.set_phys_id = gs_usb_set_phys_id,
|
||||
.get_ts_info = ethtool_op_get_ts_info,
|
||||
.get_ts_info = gs_usb_get_ts_info,
|
||||
};
|
||||
|
||||
static struct gs_can *gs_make_candev(unsigned int channel,
|
||||
@ -1063,8 +1231,8 @@ static struct gs_can *gs_make_candev(unsigned int channel,
|
||||
* GS_CAN_FEATURE_QUIRK_BREQ_CANTACT_PRO to workaround this
|
||||
* issue.
|
||||
*/
|
||||
if (dev->udev->descriptor.idVendor == cpu_to_le16(USB_GSUSB_1_VENDOR_ID) &&
|
||||
dev->udev->descriptor.idProduct == cpu_to_le16(USB_GSUSB_1_PRODUCT_ID) &&
|
||||
if (dev->udev->descriptor.idVendor == cpu_to_le16(USB_GS_USB_1_VENDOR_ID) &&
|
||||
dev->udev->descriptor.idProduct == cpu_to_le16(USB_GS_USB_1_PRODUCT_ID) &&
|
||||
dev->udev->manufacturer && dev->udev->product &&
|
||||
!strcmp(dev->udev->manufacturer, "LinkLayer Labs") &&
|
||||
!strcmp(dev->udev->product, "CANtact Pro") &&
|
||||
@ -1202,15 +1370,13 @@ static int gs_usb_probe(struct usb_interface *intf,
|
||||
}
|
||||
|
||||
init_usb_anchor(&dev->rx_submitted);
|
||||
/* default to classic CAN, switch to CAN-FD if at least one of
|
||||
* our channels support CAN-FD.
|
||||
*/
|
||||
dev->hf_size_rx = struct_size(hf, classic_can, 1);
|
||||
|
||||
usb_set_intfdata(intf, dev);
|
||||
dev->udev = udev;
|
||||
|
||||
for (i = 0; i < icount; i++) {
|
||||
unsigned int hf_size_rx = 0;
|
||||
|
||||
dev->canch[i] = gs_make_candev(i, intf, dconf);
|
||||
if (IS_ERR_OR_NULL(dev->canch[i])) {
|
||||
/* save error code to return later */
|
||||
@ -1228,8 +1394,21 @@ static int gs_usb_probe(struct usb_interface *intf,
|
||||
}
|
||||
dev->canch[i]->parent = dev;
|
||||
|
||||
if (dev->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD)
|
||||
dev->hf_size_rx = struct_size(hf, canfd, 1);
|
||||
/* set RX packet size based on FD and if hardware
|
||||
* timestamps are supported.
|
||||
*/
|
||||
if (dev->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
|
||||
if (dev->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
hf_size_rx = struct_size(hf, canfd_ts, 1);
|
||||
else
|
||||
hf_size_rx = struct_size(hf, canfd, 1);
|
||||
} else {
|
||||
if (dev->canch[i]->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
|
||||
hf_size_rx = struct_size(hf, classic_can_ts, 1);
|
||||
else
|
||||
hf_size_rx = struct_size(hf, classic_can, 1);
|
||||
}
|
||||
dev->hf_size_rx = max(dev->hf_size_rx, hf_size_rx);
|
||||
}
|
||||
|
||||
kfree(dconf);
|
||||
@ -1258,8 +1437,8 @@ static void gs_usb_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static const struct usb_device_id gs_usb_table[] = {
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_GSUSB_1_VENDOR_ID,
|
||||
USB_GSUSB_1_PRODUCT_ID, 0) },
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_GS_USB_1_VENDOR_ID,
|
||||
USB_GS_USB_1_PRODUCT_ID, 0) },
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_CANDLELIGHT_VENDOR_ID,
|
||||
USB_CANDLELIGHT_PRODUCT_ID, 0) },
|
||||
{ USB_DEVICE_INTERFACE_NUMBER(USB_CES_CANEXT_FD_VENDOR_ID,
|
||||
|
@ -534,7 +534,7 @@ static int kvaser_usb_hydra_send_simple_cmd(struct kvaser_usb *dev,
|
||||
struct kvaser_cmd *cmd;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -573,7 +573,7 @@ kvaser_usb_hydra_send_simple_cmd_async(struct kvaser_usb_net_priv *priv,
|
||||
struct kvaser_usb *dev = priv->dev;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_ATOMIC);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -694,7 +694,7 @@ static int kvaser_usb_hydra_map_channel(struct kvaser_usb *dev, u16 transid,
|
||||
struct kvaser_cmd *cmd;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -735,7 +735,7 @@ static int kvaser_usb_hydra_get_single_capability(struct kvaser_usb *dev,
|
||||
int err;
|
||||
int i;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1394,7 +1394,7 @@ kvaser_usb_hydra_frame_to_cmd_ext(const struct kvaser_usb_net_priv *priv,
|
||||
u32 kcan_id;
|
||||
u32 kcan_header;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd_ext), GFP_ATOMIC);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
@ -1468,7 +1468,7 @@ kvaser_usb_hydra_frame_to_cmd_std(const struct kvaser_usb_net_priv *priv,
|
||||
u32 flags;
|
||||
u32 id;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_ATOMIC);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
@ -1533,7 +1533,7 @@ static int kvaser_usb_hydra_set_bittiming(struct net_device *netdev)
|
||||
int sjw = bt->sjw;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1567,7 +1567,7 @@ static int kvaser_usb_hydra_set_data_bittiming(struct net_device *netdev)
|
||||
int sjw = dbt->sjw;
|
||||
int err;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1711,7 +1711,7 @@ static int kvaser_usb_hydra_get_software_details(struct kvaser_usb *dev)
|
||||
u32 flags;
|
||||
struct kvaser_usb_dev_card_data *card_data = &dev->card_data;
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -1851,7 +1851,7 @@ static int kvaser_usb_hydra_set_opt_mode(const struct kvaser_usb_net_priv *priv)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd = kcalloc(1, sizeof(struct kvaser_cmd), GFP_KERNEL);
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -71,11 +71,10 @@ MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)");
|
||||
|
||||
static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cfd->len;
|
||||
stats->rx_bytes += can_skb_get_data_len(skb);
|
||||
|
||||
skb->pkt_type = PACKET_BROADCAST;
|
||||
skb->dev = dev;
|
||||
@ -86,14 +85,14 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
int loop, len;
|
||||
unsigned int len;
|
||||
int loop;
|
||||
|
||||
if (can_dropped_invalid_skb(dev, skb))
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
len = cfd->can_id & CAN_RTR_FLAG ? 0 : cfd->len;
|
||||
len = can_skb_get_data_len(skb);
|
||||
stats->tx_packets++;
|
||||
stats->tx_bytes += len;
|
||||
|
||||
@ -137,7 +136,8 @@ static int vcan_change_mtu(struct net_device *dev, int new_mtu)
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
|
||||
if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU &&
|
||||
!can_is_canxl_dev_mtu(new_mtu))
|
||||
return -EINVAL;
|
||||
|
||||
dev->mtu = new_mtu;
|
||||
|
@ -38,10 +38,9 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
|
||||
{
|
||||
struct vxcan_priv *priv = netdev_priv(dev);
|
||||
struct net_device *peer;
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
|
||||
struct net_device_stats *peerstats, *srcstats = &dev->stats;
|
||||
struct sk_buff *skb;
|
||||
u8 len;
|
||||
unsigned int len;
|
||||
|
||||
if (can_dropped_invalid_skb(dev, oskb))
|
||||
return NETDEV_TX_OK;
|
||||
@ -70,7 +69,7 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
|
||||
skb->dev = peer;
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
len = cfd->can_id & CAN_RTR_FLAG ? 0 : cfd->len;
|
||||
len = can_skb_get_data_len(skb);
|
||||
if (netif_rx(skb) == NET_RX_SUCCESS) {
|
||||
srcstats->tx_packets++;
|
||||
srcstats->tx_bytes += len;
|
||||
@ -132,7 +131,8 @@ static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
|
||||
if (dev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU)
|
||||
if (new_mtu != CAN_MTU && new_mtu != CANFD_MTU &&
|
||||
!can_is_canxl_dev_mtu(new_mtu))
|
||||
return -EINVAL;
|
||||
|
||||
dev->mtu = new_mtu;
|
||||
|
@ -147,6 +147,11 @@ static inline u32 can_get_static_ctrlmode(struct can_priv *priv)
|
||||
return priv->ctrlmode & ~priv->ctrlmode_supported;
|
||||
}
|
||||
|
||||
static inline bool can_is_canxl_dev_mtu(unsigned int mtu)
|
||||
{
|
||||
return (mtu >= CANXL_MIN_MTU && mtu <= CANXL_MAX_MTU);
|
||||
}
|
||||
|
||||
void can_setup(struct net_device *dev);
|
||||
|
||||
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
|
||||
|
@ -20,7 +20,8 @@ void can_flush_echo_skb(struct net_device *dev);
|
||||
int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned int idx, unsigned int frame_len);
|
||||
struct sk_buff *__can_get_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
u8 *len_ptr, unsigned int *frame_len_ptr);
|
||||
unsigned int *len_ptr,
|
||||
unsigned int *frame_len_ptr);
|
||||
unsigned int __must_check can_get_echo_skb(struct net_device *dev,
|
||||
unsigned int idx,
|
||||
unsigned int *frame_len_ptr);
|
||||
@ -29,6 +30,9 @@ void can_free_echo_skb(struct net_device *dev, unsigned int idx,
|
||||
struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
|
||||
struct sk_buff *alloc_canfd_skb(struct net_device *dev,
|
||||
struct canfd_frame **cfd);
|
||||
struct sk_buff *alloc_canxl_skb(struct net_device *dev,
|
||||
struct canxl_frame **cxl,
|
||||
unsigned int data_len);
|
||||
struct sk_buff *alloc_can_err_skb(struct net_device *dev,
|
||||
struct can_frame **cf);
|
||||
bool can_dropped_invalid_skb(struct net_device *dev, struct sk_buff *skb);
|
||||
@ -97,10 +101,59 @@ static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
|
||||
return nskb;
|
||||
}
|
||||
|
||||
static inline bool can_is_can_skb(const struct sk_buff *skb)
|
||||
{
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
|
||||
/* the CAN specific type of skb is identified by its data length */
|
||||
return (skb->len == CAN_MTU && cf->len <= CAN_MAX_DLEN);
|
||||
}
|
||||
|
||||
static inline bool can_is_canfd_skb(const struct sk_buff *skb)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
/* the CAN specific type of skb is identified by its data length */
|
||||
return skb->len == CANFD_MTU;
|
||||
return (skb->len == CANFD_MTU && cfd->len <= CANFD_MAX_DLEN);
|
||||
}
|
||||
|
||||
static inline bool can_is_canxl_skb(const struct sk_buff *skb)
|
||||
{
|
||||
const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
|
||||
|
||||
if (skb->len < CANXL_HDR_SIZE + CANXL_MIN_DLEN || skb->len > CANXL_MTU)
|
||||
return false;
|
||||
|
||||
/* this also checks valid CAN XL data length boundaries */
|
||||
if (skb->len != CANXL_HDR_SIZE + cxl->len)
|
||||
return false;
|
||||
|
||||
return cxl->flags & CANXL_XLF;
|
||||
}
|
||||
|
||||
/* get length element value from can[|fd|xl]_frame structure */
|
||||
static inline unsigned int can_skb_get_len_val(struct sk_buff *skb)
|
||||
{
|
||||
const struct canxl_frame *cxl = (struct canxl_frame *)skb->data;
|
||||
const struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (can_is_canxl_skb(skb))
|
||||
return cxl->len;
|
||||
|
||||
return cfd->len;
|
||||
}
|
||||
|
||||
/* get needed data length inside CAN frame for all frame types (RTR aware) */
|
||||
static inline unsigned int can_skb_get_data_len(struct sk_buff *skb)
|
||||
{
|
||||
unsigned int len = can_skb_get_len_val(skb);
|
||||
const struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
|
||||
/* RTR frames have an actual length of zero */
|
||||
if (can_is_can_skb(skb) && cf->can_id & CAN_RTR_FLAG)
|
||||
return 0;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* !_CAN_SKB_H */
|
||||
|
@ -48,6 +48,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/stddef.h> /* for offsetof */
|
||||
|
||||
/* controller area network (CAN) kernel definitions */
|
||||
|
||||
@ -60,6 +61,7 @@
|
||||
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
|
||||
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
|
||||
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
|
||||
#define CANXL_PRIO_MASK CAN_SFF_MASK /* 11 bit priority mask */
|
||||
|
||||
/*
|
||||
* Controller Area Network Identifier structure
|
||||
@ -73,6 +75,7 @@ typedef __u32 canid_t;
|
||||
|
||||
#define CAN_SFF_ID_BITS 11
|
||||
#define CAN_EFF_ID_BITS 29
|
||||
#define CANXL_PRIO_BITS CAN_SFF_ID_BITS
|
||||
|
||||
/*
|
||||
* Controller Area Network Error Message Frame Mask structure
|
||||
@ -91,6 +94,16 @@ typedef __u32 can_err_mask_t;
|
||||
#define CANFD_MAX_DLC 15
|
||||
#define CANFD_MAX_DLEN 64
|
||||
|
||||
/*
|
||||
* CAN XL payload length and DLC definitions according to ISO 11898-1
|
||||
* CAN XL DLC ranges from 0 .. 2047 => data length from 1 .. 2048 byte
|
||||
*/
|
||||
#define CANXL_MIN_DLC 0
|
||||
#define CANXL_MAX_DLC 2047
|
||||
#define CANXL_MAX_DLC_MASK 0x07FF
|
||||
#define CANXL_MIN_DLEN 1
|
||||
#define CANXL_MAX_DLEN 2048
|
||||
|
||||
/**
|
||||
* struct can_frame - Classical CAN frame structure (aka CAN 2.0B)
|
||||
* @can_id: CAN ID of the frame and CAN_*_FLAG flags, see canid_t definition
|
||||
@ -141,8 +154,8 @@ struct can_frame {
|
||||
* When this is done the former differentiation via CAN_MTU / CANFD_MTU gets
|
||||
* lost. CANFD_FDF allows programmers to mark CAN FD frames in the case of
|
||||
* using struct canfd_frame for mixed CAN / CAN FD content (dual use).
|
||||
* N.B. the Kernel APIs do NOT provide mixed CAN / CAN FD content inside of
|
||||
* struct canfd_frame therefore the CANFD_FDF flag is disregarded by Linux.
|
||||
* Since the introduction of CAN XL the CANFD_FDF flag is set in all CAN FD
|
||||
* frame structures provided by the CAN subsystem of the Linux kernel.
|
||||
*/
|
||||
#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
|
||||
#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
|
||||
@ -166,8 +179,46 @@ struct canfd_frame {
|
||||
__u8 data[CANFD_MAX_DLEN] __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
/*
|
||||
* defined bits for canxl_frame.flags
|
||||
*
|
||||
* The canxl_frame.flags element contains two bits CANXL_XLF and CANXL_SEC
|
||||
* and shares the relative position of the struct can[fd]_frame.len element.
|
||||
* The CANXL_XLF bit ALWAYS needs to be set to indicate a valid CAN XL frame.
|
||||
* As a side effect setting this bit intentionally breaks the length checks
|
||||
* for Classical CAN and CAN FD frames.
|
||||
*
|
||||
* Undefined bits in canxl_frame.flags are reserved and shall be set to zero.
|
||||
*/
|
||||
#define CANXL_XLF 0x80 /* mandatory CAN XL frame flag (must always be set!) */
|
||||
#define CANXL_SEC 0x01 /* Simple Extended Content (security/segmentation) */
|
||||
|
||||
/**
|
||||
* struct canxl_frame - CAN with e'X'tended frame 'L'ength frame structure
|
||||
* @prio: 11 bit arbitration priority with zero'ed CAN_*_FLAG flags
|
||||
* @flags: additional flags for CAN XL
|
||||
* @sdt: SDU (service data unit) type
|
||||
* @len: frame payload length in byte (CANXL_MIN_DLEN .. CANXL_MAX_DLEN)
|
||||
* @af: acceptance field
|
||||
* @data: CAN XL frame payload (CANXL_MIN_DLEN .. CANXL_MAX_DLEN byte)
|
||||
*
|
||||
* @prio shares the same position as @can_id from struct can[fd]_frame.
|
||||
*/
|
||||
struct canxl_frame {
|
||||
canid_t prio; /* 11 bit priority for arbitration (canid_t) */
|
||||
__u8 flags; /* additional flags for CAN XL */
|
||||
__u8 sdt; /* SDU (service data unit) type */
|
||||
__u16 len; /* frame payload length in byte */
|
||||
__u32 af; /* acceptance field */
|
||||
__u8 data[CANXL_MAX_DLEN];
|
||||
};
|
||||
|
||||
#define CAN_MTU (sizeof(struct can_frame))
|
||||
#define CANFD_MTU (sizeof(struct canfd_frame))
|
||||
#define CANXL_MTU (sizeof(struct canxl_frame))
|
||||
#define CANXL_HDR_SIZE (offsetof(struct canxl_frame, data))
|
||||
#define CANXL_MIN_MTU (CANXL_HDR_SIZE + 64)
|
||||
#define CANXL_MAX_MTU CANXL_MTU
|
||||
|
||||
/* particular protocols of the protocol family PF_CAN */
|
||||
#define CAN_RAW 1 /* RAW sockets */
|
||||
|
@ -62,6 +62,7 @@ enum {
|
||||
CAN_RAW_RECV_OWN_MSGS, /* receive my own msgs (default:off) */
|
||||
CAN_RAW_FD_FRAMES, /* allow CAN FD frames (default:off) */
|
||||
CAN_RAW_JOIN_FILTERS, /* all filters must match to trigger */
|
||||
CAN_RAW_XL_FRAMES, /* allow CAN XL frames (default:off) */
|
||||
};
|
||||
|
||||
#endif /* !_UAPI_CAN_RAW_H */
|
||||
|
@ -138,6 +138,7 @@
|
||||
#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
|
||||
#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
|
||||
#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/
|
||||
#define ETH_P_CANXL 0x000E /* CANXL: eXtended frame Length */
|
||||
#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
|
||||
#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
|
||||
#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
|
||||
|
@ -199,27 +199,26 @@ static int can_create(struct net *net, struct socket *sock, int protocol,
|
||||
int can_send(struct sk_buff *skb, int loop)
|
||||
{
|
||||
struct sk_buff *newskb = NULL;
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
struct can_pkg_stats *pkg_stats = dev_net(skb->dev)->can.pkg_stats;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (skb->len == CAN_MTU) {
|
||||
if (can_is_canxl_skb(skb)) {
|
||||
skb->protocol = htons(ETH_P_CANXL);
|
||||
} else if (can_is_can_skb(skb)) {
|
||||
skb->protocol = htons(ETH_P_CAN);
|
||||
if (unlikely(cfd->len > CAN_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
} else if (skb->len == CANFD_MTU) {
|
||||
} else if (can_is_canfd_skb(skb)) {
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
skb->protocol = htons(ETH_P_CANFD);
|
||||
if (unlikely(cfd->len > CANFD_MAX_DLEN))
|
||||
goto inval_skb;
|
||||
|
||||
/* set CAN FD flag for CAN FD frames by default */
|
||||
cfd->flags |= CANFD_FDF;
|
||||
} else {
|
||||
goto inval_skb;
|
||||
}
|
||||
|
||||
/* Make sure the CAN frame can pass the selected CAN netdevice.
|
||||
* As structs can_frame and canfd_frame are similar, we can provide
|
||||
* CAN FD frames to legacy CAN drivers as long as the length is <= 8
|
||||
*/
|
||||
if (unlikely(skb->len > skb->dev->mtu && cfd->len > CAN_MAX_DLEN)) {
|
||||
/* Make sure the CAN frame can pass the selected CAN netdevice. */
|
||||
if (unlikely(skb->len > skb->dev->mtu)) {
|
||||
err = -EMSGSIZE;
|
||||
goto inval_skb;
|
||||
}
|
||||
@ -678,53 +677,46 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev)
|
||||
static int can_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CAN_MTU)) {
|
||||
if (unlikely(dev->type != ARPHRD_CAN || (!can_is_can_skb(skb)))) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n",
|
||||
dev->type, skb->len);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
|
||||
if (unlikely(cfd->len > CAN_MAX_DLEN)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d, datalen %d\n",
|
||||
dev->type, skb->len, cfd->len);
|
||||
goto free_skb;
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
static int canfd_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
|
||||
|
||||
if (unlikely(dev->type != ARPHRD_CAN || skb->len != CANFD_MTU)) {
|
||||
if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canfd_skb(skb)))) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n",
|
||||
dev->type, skb->len);
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
/* This check is made separately since cfd->len would be uninitialized if skb->len = 0. */
|
||||
if (unlikely(cfd->len > CANFD_MAX_DLEN)) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d, datalen %d\n",
|
||||
dev->type, skb->len, cfd->len);
|
||||
goto free_skb;
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
static int canxl_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
if (unlikely(dev->type != ARPHRD_CAN || (!can_is_canxl_skb(skb)))) {
|
||||
pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n",
|
||||
dev->type, skb->len);
|
||||
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
can_receive(skb, dev);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
/* af_can protocol functions */
|
||||
@ -851,6 +843,11 @@ static struct packet_type canfd_packet __read_mostly = {
|
||||
.func = canfd_rcv,
|
||||
};
|
||||
|
||||
static struct packet_type canxl_packet __read_mostly = {
|
||||
.type = cpu_to_be16(ETH_P_CANXL),
|
||||
.func = canxl_rcv,
|
||||
};
|
||||
|
||||
static const struct net_proto_family can_family_ops = {
|
||||
.family = PF_CAN,
|
||||
.create = can_create,
|
||||
@ -890,6 +887,7 @@ static __init int can_init(void)
|
||||
|
||||
dev_add_pack(&can_packet);
|
||||
dev_add_pack(&canfd_packet);
|
||||
dev_add_pack(&canxl_packet);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -648,8 +648,13 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
|
||||
return;
|
||||
|
||||
/* make sure to handle the correct frame type (CAN / CAN FD) */
|
||||
if (skb->len != op->cfsiz)
|
||||
return;
|
||||
if (op->flags & CAN_FD_FRAME) {
|
||||
if (!can_is_canfd_skb(skb))
|
||||
return;
|
||||
} else {
|
||||
if (!can_is_can_skb(skb))
|
||||
return;
|
||||
}
|
||||
|
||||
/* disable timeout */
|
||||
hrtimer_cancel(&op->timer);
|
||||
|
@ -463,10 +463,10 @@ static void can_can_gw_rcv(struct sk_buff *skb, void *data)
|
||||
|
||||
/* process strictly Classic CAN or CAN FD frames */
|
||||
if (gwj->flags & CGW_FLAGS_CAN_FD) {
|
||||
if (skb->len != CANFD_MTU)
|
||||
if (!can_is_canfd_skb(skb))
|
||||
return;
|
||||
} else {
|
||||
if (skb->len != CAN_MTU)
|
||||
if (!can_is_can_skb(skb))
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -669,7 +669,7 @@ static void isotp_rcv(struct sk_buff *skb, void *data)
|
||||
if (cf->len <= CAN_MAX_DLEN) {
|
||||
isotp_rcv_sf(sk, cf, SF_PCI_SZ4 + ae, skb, sf_dl);
|
||||
} else {
|
||||
if (skb->len == CANFD_MTU) {
|
||||
if (can_is_canfd_skb(skb)) {
|
||||
/* We have a CAN FD frame and CAN_DL is greater than 8:
|
||||
* Only frames with the SF_DL == 0 ESC value are valid.
|
||||
*
|
||||
|
@ -42,6 +42,10 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data)
|
||||
struct j1939_sk_buff_cb *skcb, *iskcb;
|
||||
struct can_frame *cf;
|
||||
|
||||
/* make sure we only get Classical CAN frames */
|
||||
if (!can_is_can_skb(iskb))
|
||||
return;
|
||||
|
||||
/* create a copy of the skb
|
||||
* j1939 only delivers the real data bytes,
|
||||
* the header goes into sockaddr.
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/dev.h> /* for can_is_canxl_dev_mtu() */
|
||||
#include <linux/can/skb.h>
|
||||
#include <linux/can/raw.h>
|
||||
#include <net/sock.h>
|
||||
@ -87,6 +88,7 @@ struct raw_sock {
|
||||
int loopback;
|
||||
int recv_own_msgs;
|
||||
int fd_frames;
|
||||
int xl_frames;
|
||||
int join_filters;
|
||||
int count; /* number of active filters */
|
||||
struct can_filter dfilter; /* default/single filter */
|
||||
@ -129,21 +131,21 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
|
||||
if (!ro->recv_own_msgs && oskb->sk == sk)
|
||||
return;
|
||||
|
||||
/* do not pass non-CAN2.0 frames to a legacy socket */
|
||||
if (!ro->fd_frames && oskb->len != CAN_MTU)
|
||||
/* make sure to not pass oversized frames to the socket */
|
||||
if ((can_is_canfd_skb(oskb) && !ro->fd_frames && !ro->xl_frames) ||
|
||||
(can_is_canxl_skb(oskb) && !ro->xl_frames))
|
||||
return;
|
||||
|
||||
/* eliminate multiple filter matches for the same skb */
|
||||
if (this_cpu_ptr(ro->uniq)->skb == oskb &&
|
||||
this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) {
|
||||
if (ro->join_filters) {
|
||||
this_cpu_inc(ro->uniq->join_rx_count);
|
||||
/* drop frame until all enabled filters matched */
|
||||
if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count)
|
||||
return;
|
||||
} else {
|
||||
if (!ro->join_filters)
|
||||
return;
|
||||
|
||||
this_cpu_inc(ro->uniq->join_rx_count);
|
||||
/* drop frame until all enabled filters matched */
|
||||
if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count)
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this_cpu_ptr(ro->uniq)->skb = oskb;
|
||||
this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt;
|
||||
@ -346,6 +348,7 @@ static int raw_init(struct sock *sk)
|
||||
ro->loopback = 1;
|
||||
ro->recv_own_msgs = 0;
|
||||
ro->fd_frames = 0;
|
||||
ro->xl_frames = 0;
|
||||
ro->join_filters = 0;
|
||||
|
||||
/* alloc_percpu provides zero'ed memory */
|
||||
@ -669,6 +672,15 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
break;
|
||||
|
||||
case CAN_RAW_XL_FRAMES:
|
||||
if (optlen != sizeof(ro->xl_frames))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_sockptr(&ro->xl_frames, optval, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
break;
|
||||
|
||||
case CAN_RAW_JOIN_FILTERS:
|
||||
if (optlen != sizeof(ro->join_filters))
|
||||
return -EINVAL;
|
||||
@ -751,6 +763,12 @@ static int raw_getsockopt(struct socket *sock, int level, int optname,
|
||||
val = &ro->fd_frames;
|
||||
break;
|
||||
|
||||
case CAN_RAW_XL_FRAMES:
|
||||
if (len > sizeof(int))
|
||||
len = sizeof(int);
|
||||
val = &ro->xl_frames;
|
||||
break;
|
||||
|
||||
case CAN_RAW_JOIN_FILTERS:
|
||||
if (len > sizeof(int))
|
||||
len = sizeof(int);
|
||||
@ -776,7 +794,11 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
|
||||
struct sk_buff *skb;
|
||||
struct net_device *dev;
|
||||
int ifindex;
|
||||
int err;
|
||||
int err = -EINVAL;
|
||||
|
||||
/* check for valid CAN frame sizes */
|
||||
if (size < CANXL_HDR_SIZE + CANXL_MIN_DLEN || size > CANXL_MTU)
|
||||
return -EINVAL;
|
||||
|
||||
if (msg->msg_name) {
|
||||
DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name);
|
||||
@ -796,15 +818,6 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
|
||||
if (!dev)
|
||||
return -ENXIO;
|
||||
|
||||
err = -EINVAL;
|
||||
if (ro->fd_frames && dev->mtu == CANFD_MTU) {
|
||||
if (unlikely(size != CANFD_MTU && size != CAN_MTU))
|
||||
goto put_dev;
|
||||
} else {
|
||||
if (unlikely(size != CAN_MTU))
|
||||
goto put_dev;
|
||||
}
|
||||
|
||||
skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv),
|
||||
msg->msg_flags & MSG_DONTWAIT, &err);
|
||||
if (!skb)
|
||||
@ -814,10 +827,27 @@ static int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
|
||||
can_skb_prv(skb)->ifindex = dev->ifindex;
|
||||
can_skb_prv(skb)->skbcnt = 0;
|
||||
|
||||
/* fill the skb before testing for valid CAN frames */
|
||||
err = memcpy_from_msg(skb_put(skb, size), msg, size);
|
||||
if (err < 0)
|
||||
goto free_skb;
|
||||
|
||||
err = -EINVAL;
|
||||
if (ro->xl_frames && can_is_canxl_dev_mtu(dev->mtu)) {
|
||||
/* CAN XL, CAN FD and Classical CAN */
|
||||
if (!can_is_canxl_skb(skb) && !can_is_canfd_skb(skb) &&
|
||||
!can_is_can_skb(skb))
|
||||
goto free_skb;
|
||||
} else if (ro->fd_frames && dev->mtu == CANFD_MTU) {
|
||||
/* CAN FD and Classical CAN */
|
||||
if (!can_is_canfd_skb(skb) && !can_is_can_skb(skb))
|
||||
goto free_skb;
|
||||
} else {
|
||||
/* Classical CAN */
|
||||
if (!can_is_can_skb(skb))
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
sockcm_init(&sockc, sk);
|
||||
if (msg->msg_controllen) {
|
||||
err = sock_cmsg_send(sk, msg, &sockc);
|
||||
@ -942,12 +972,20 @@ static __init int raw_module_init(void)
|
||||
|
||||
pr_info("can: raw protocol\n");
|
||||
|
||||
err = can_proto_register(&raw_can_proto);
|
||||
if (err < 0)
|
||||
pr_err("can: registration of raw protocol failed\n");
|
||||
else
|
||||
register_netdevice_notifier(&canraw_notifier);
|
||||
err = register_netdevice_notifier(&canraw_notifier);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = can_proto_register(&raw_can_proto);
|
||||
if (err < 0) {
|
||||
pr_err("can: registration of raw protocol failed\n");
|
||||
goto register_proto_failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
register_proto_failed:
|
||||
unregister_netdevice_notifier(&canraw_notifier);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user