diff options
author | David S. Miller <davem@davemloft.net> | 2023-07-28 09:58:53 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2023-07-28 09:58:53 +0100 |
commit | 8ad228b1abe97b92100dcaef74cda86378874698 (patch) | |
tree | 03e747923d0fec624364a37aaa5dc23f5e345b27 | |
parent | 91fcb99c565dbc51a0917e353e923f485668bc6d (diff) | |
parent | 52be626ccbd7421f6124429b6d9fea9e31ae602f (diff) |
Merge tag 'linux-can-next-for-6.6-20230728' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next
linux-can-next-for-6.6-20230728
Marc Kleine-Budde says:
====================
Hello netdev-team,
this is a pull request of 21 patches for net-next/master.
The 1st patch is by Gerhard Uttenthaler, which adds Gerhard as the
maintainer ems_pci driver.
Peter Seiderer's patch removes a unused function from the peak_usb
driver.
The next 4 patches are by John Watts and add support for the sun4i_can
driver on the Allwinner D1.
Rob Herring's patch corrects the DT includes in various CAN drivers.
Followed by 14 patches from me concerning the gs_usb driver. The first
11 are various cleanups consisting of coding style improvements, error
path printout cleanups, and removal of unneeded
usb_kill_anchored_urbs(). The last 3 convert the driver to use NAPI to
avoid out-of-order reception of CAN frames.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml | 6 | ||||
-rw-r--r-- | MAINTAINERS | 7 | ||||
-rw-r--r-- | arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 30 | ||||
-rw-r--r-- | drivers/net/can/Kconfig | 4 | ||||
-rw-r--r-- | drivers/net/can/bxcan.c | 1 | ||||
-rw-r--r-- | drivers/net/can/dev/rx-offload.c | 36 | ||||
-rw-r--r-- | drivers/net/can/flexcan/flexcan-core.c | 4 | ||||
-rw-r--r-- | drivers/net/can/ifi_canfd/ifi_canfd.c | 1 | ||||
-rw-r--r-- | drivers/net/can/m_can/m_can.c | 9 | ||||
-rw-r--r-- | drivers/net/can/m_can/m_can.h | 1 | ||||
-rw-r--r-- | drivers/net/can/rcar/rcar_canfd.c | 1 | ||||
-rw-r--r-- | drivers/net/can/sja1000/sja1000_platform.c | 1 | ||||
-rw-r--r-- | drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c | 6 | ||||
-rw-r--r-- | drivers/net/can/sun4i_can.c | 23 | ||||
-rw-r--r-- | drivers/net/can/ti_hecc.c | 5 | ||||
-rw-r--r-- | drivers/net/can/usb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/can/usb/gs_usb.c | 187 | ||||
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_core.c | 13 | ||||
-rw-r--r-- | drivers/net/can/usb/peak_usb/pcan_usb_core.h | 2 | ||||
-rw-r--r-- | include/linux/can/rx-offload.h | 11 |
20 files changed, 225 insertions, 124 deletions
diff --git a/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml b/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml index 9c494957a07a..e42ea28d6ab4 100644 --- a/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml +++ b/Documentation/devicetree/bindings/net/can/allwinner,sun4i-a10-can.yaml @@ -21,6 +21,7 @@ properties: - const: allwinner,sun4i-a10-can - const: allwinner,sun4i-a10-can - const: allwinner,sun8i-r40-can + - const: allwinner,sun20i-d1-can reg: maxItems: 1 @@ -37,8 +38,9 @@ properties: if: properties: compatible: - contains: - const: allwinner,sun8i-r40-can + enum: + - allwinner,sun8i-r40-can + - allwinner,sun20i-d1-can then: required: diff --git a/MAINTAINERS b/MAINTAINERS index 24eb7ed6211f..c4f95a9d03b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7606,6 +7606,13 @@ L: linux-mmc@vger.kernel.org S: Supported F: drivers/mmc/host/cqhci* +EMS CPC-PCI CAN DRIVER +M: Gerhard Uttenthaler <uttenthaler@ems-wuensche.com> +M: support@ems-wuensche.com +L: linux-can@vger.kernel.org +S: Maintained +F: drivers/net/can/sja1000/ems_pci.c + EMULEX 10Gbps iSCSI - OneConnect DRIVER M: Ketan Mukadam <ketan.mukadam@broadcom.com> L: linux-scsi@vger.kernel.org diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi index 1bb1e5cae602..4086c0cc0f9d 100644 --- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi +++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi @@ -131,6 +131,18 @@ pins = "PB6", "PB7"; function = "uart3"; }; + + /omit-if-no-ref/ + can0_pins: can0-pins { + pins = "PB2", "PB3"; + function = "can0"; + }; + + /omit-if-no-ref/ + can1_pins: can1-pins { + pins = "PB4", "PB5"; + function = "can1"; + }; }; ccu: clock-controller@2001000 { @@ -879,5 +891,23 @@ clock-names = "bus", "hosc", "ahb"; #clock-cells = <1>; }; + + can0: can@2504000 { + compatible = "allwinner,sun20i-d1-can"; + reg = <0x02504000 0x400>; + interrupts = <SOC_PERIPHERAL_IRQ(21) IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CAN0>; + resets = <&ccu RST_BUS_CAN0>; + status = "disabled"; + }; + + can1: can@2504400 { + compatible = "allwinner,sun20i-d1-can"; + reg = <0x02504400 0x400>; + interrupts = <SOC_PERIPHERAL_IRQ(22) IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu CLK_BUS_CAN1>; + resets = <&ccu RST_BUS_CAN1>; + status = "disabled"; + }; }; }; diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 18e4a6e94ba9..649453a3c858 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -190,10 +190,10 @@ config CAN_SLCAN config CAN_SUN4I tristate "Allwinner A10 CAN controller" - depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST + depends on MACH_SUN4I || MACH_SUN7I || RISCV || COMPILE_TEST help Say Y here if you want to use CAN controller found on Allwinner - A10/A20 SoCs. + A10/A20/D1 SoCs. To compile this driver as a module, choose M here: the module will be called sun4i_can. diff --git a/drivers/net/can/bxcan.c b/drivers/net/can/bxcan.c index 39de7164bc4e..49cf9682b925 100644 --- a/drivers/net/can/bxcan.c +++ b/drivers/net/can/bxcan.c @@ -23,7 +23,6 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> diff --git a/drivers/net/can/dev/rx-offload.c b/drivers/net/can/dev/rx-offload.c index 161e45a7e8c1..77091f7d1fa7 100644 --- a/drivers/net/can/dev/rx-offload.c +++ b/drivers/net/can/dev/rx-offload.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2014 Protonic Holland, * David Jander - * Copyright (C) 2014-2021 Pengutronix, + * Copyright (C) 2014-2021, 2023 Pengutronix, * Marc Kleine-Budde <kernel@pengutronix.de> */ @@ -240,9 +240,10 @@ int can_rx_offload_queue_timestamp(struct can_rx_offload *offload, } EXPORT_SYMBOL_GPL(can_rx_offload_queue_timestamp); -unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, - unsigned int idx, u32 timestamp, - unsigned int *frame_len_ptr) +unsigned int +can_rx_offload_get_echo_skb_queue_timestamp(struct can_rx_offload *offload, + unsigned int idx, u32 timestamp, + unsigned int *frame_len_ptr) { struct net_device *dev = offload->dev; struct net_device_stats *stats = &dev->stats; @@ -262,7 +263,7 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, return len; } -EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb); +EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb_queue_timestamp); int can_rx_offload_queue_tail(struct can_rx_offload *offload, struct sk_buff *skb) @@ -279,6 +280,31 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload, } EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail); +unsigned int +can_rx_offload_get_echo_skb_queue_tail(struct can_rx_offload *offload, + unsigned int idx, + unsigned int *frame_len_ptr) +{ + struct net_device *dev = offload->dev; + struct net_device_stats *stats = &dev->stats; + struct sk_buff *skb; + unsigned int len; + int err; + + skb = __can_get_echo_skb(dev, idx, &len, frame_len_ptr); + if (!skb) + return 0; + + err = can_rx_offload_queue_tail(offload, skb); + if (err) { + stats->rx_errors++; + stats->tx_fifo_errors++; + } + + return len; +} +EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb_queue_tail); + void can_rx_offload_irq_finish(struct can_rx_offload *offload) { unsigned long flags; diff --git a/drivers/net/can/flexcan/flexcan-core.c b/drivers/net/can/flexcan/flexcan-core.c index ff0fc18baf13..48273d51f271 100644 --- a/drivers/net/can/flexcan/flexcan-core.c +++ b/drivers/net/can/flexcan/flexcan-core.c @@ -1097,8 +1097,8 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) handled = IRQ_HANDLED; stats->tx_bytes += - can_rx_offload_get_echo_skb(&priv->offload, 0, - reg_ctrl << 16, NULL); + can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload, 0, + reg_ctrl << 16, NULL); stats->tx_packets++; /* after sending a RTR frame MB is in RX mode */ diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index 1d6642c94f2f..72307297d75e 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/can/dev.h> diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index 13fd84b2e2dd..d204703521d2 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -19,7 +19,6 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> @@ -1017,10 +1016,10 @@ static void m_can_tx_update_stats(struct m_can_classdev *cdev, if (cdev->is_peripheral) stats->tx_bytes += - can_rx_offload_get_echo_skb(&cdev->offload, - msg_mark, - timestamp, - NULL); + can_rx_offload_get_echo_skb_queue_timestamp(&cdev->offload, + msg_mark, + timestamp, + NULL); else stats->tx_bytes += can_get_echo_skb(dev, msg_mark, NULL); diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h index 2ac18ac867a4..c543928c756f 100644 --- a/drivers/net/can/m_can/m_can.h +++ b/drivers/net/can/m_can/m_can.h @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/netdevice.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> diff --git a/drivers/net/can/rcar/rcar_canfd.c b/drivers/net/can/rcar/rcar_canfd.c index e4d748913439..b82842718735 100644 --- a/drivers/net/can/rcar/rcar_canfd.c +++ b/drivers/net/can/rcar/rcar_canfd.c @@ -34,7 +34,6 @@ #include <linux/moduleparam.h> #include <linux/netdevice.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/reset.h> diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 4e59952c66d4..33f0e46ab1c2 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -17,7 +17,6 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> #include "sja1000.h" diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c index 237617b0c125..e5bd57b65aaf 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c @@ -111,9 +111,9 @@ mcp251xfd_handle_tefif_one(struct mcp251xfd_priv *priv, if (skb) mcp251xfd_skb_set_timestamp(priv, skb, hw_tef_obj->ts); stats->tx_bytes += - can_rx_offload_get_echo_skb(&priv->offload, - tef_tail, hw_tef_obj->ts, - frame_len_ptr); + can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload, + tef_tail, hw_tef_obj->ts, + frame_len_ptr); stats->tx_packets++; priv->tef->tail++; diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c index 0827830bbf28..ab8d01784686 100644 --- a/drivers/net/can/sun4i_can.c +++ b/drivers/net/can/sun4i_can.c @@ -59,7 +59,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/reset.h> @@ -91,6 +90,8 @@ #define SUN4I_REG_BUF12_ADDR 0x0070 /* CAN Tx/Rx Buffer 12 */ #define SUN4I_REG_ACPC_ADDR 0x0040 /* CAN Acceptance Code 0 */ #define SUN4I_REG_ACPM_ADDR 0x0044 /* CAN Acceptance Mask 0 */ +#define SUN4I_REG_ACPC_ADDR_D1 0x0028 /* CAN Acceptance Code 0 on the D1 */ +#define SUN4I_REG_ACPM_ADDR_D1 0x002C /* CAN Acceptance Mask 0 on the D1 */ #define SUN4I_REG_RBUF_RBACK_START_ADDR 0x0180 /* CAN transmit buffer start */ #define SUN4I_REG_RBUF_RBACK_END_ADDR 0x01b0 /* CAN transmit buffer end */ @@ -205,9 +206,11 @@ * struct sun4ican_quirks - Differences between SoC variants. * * @has_reset: SoC needs reset deasserted. + * @acp_offset: Offset of ACPC and ACPM registers */ struct sun4ican_quirks { bool has_reset; + int acp_offset; }; struct sun4ican_priv { @@ -216,6 +219,7 @@ struct sun4ican_priv { struct clk *clk; struct reset_control *reset; spinlock_t cmdreg_lock; /* lock for concurrent cmd register writes */ + int acp_offset; }; static const struct can_bittiming_const sun4ican_bittiming_const = { @@ -338,8 +342,8 @@ static int sun4i_can_start(struct net_device *dev) } /* set filters - we accept all */ - writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR); - writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR); + writel(0x00000000, priv->base + SUN4I_REG_ACPC_ADDR + priv->acp_offset); + writel(0xFFFFFFFF, priv->base + SUN4I_REG_ACPM_ADDR + priv->acp_offset); /* clear error counters and error code capture */ writel(0, priv->base + SUN4I_REG_ERRC_ADDR); @@ -768,10 +772,17 @@ static const struct ethtool_ops sun4ican_ethtool_ops = { static const struct sun4ican_quirks sun4ican_quirks_a10 = { .has_reset = false, + .acp_offset = 0, }; static const struct sun4ican_quirks sun4ican_quirks_r40 = { .has_reset = true, + .acp_offset = 0, +}; + +static const struct sun4ican_quirks sun4ican_quirks_d1 = { + .has_reset = true, + .acp_offset = (SUN4I_REG_ACPC_ADDR_D1 - SUN4I_REG_ACPC_ADDR), }; static const struct of_device_id sun4ican_of_match[] = { @@ -785,6 +796,9 @@ static const struct of_device_id sun4ican_of_match[] = { .compatible = "allwinner,sun8i-r40-can", .data = &sun4ican_quirks_r40 }, { + .compatible = "allwinner,sun20i-d1-can", + .data = &sun4ican_quirks_d1 + }, { /* sentinel */ }, }; @@ -870,6 +884,7 @@ static int sun4ican_probe(struct platform_device *pdev) priv->base = addr; priv->clk = clk; priv->reset = reset; + priv->acp_offset = quirks->acp_offset; spin_lock_init(&priv->cmdreg_lock); platform_set_drvdata(pdev, dev); @@ -907,4 +922,4 @@ module_platform_driver(sun4i_can_driver); MODULE_AUTHOR("Peter Chen <xingkongcp@gmail.com>"); MODULE_AUTHOR("Gerhard Bertelsmann <info@gerhard-bertelsmann.de>"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20)"); +MODULE_DESCRIPTION("CAN driver for Allwinner SoCs (A10/A20/D1)"); diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 54284661992e..5aab440074c6 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -21,7 +21,6 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/regulator/consumer.h> #include <linux/can/dev.h> @@ -748,8 +747,8 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id) spin_unlock_irqrestore(&priv->mbx_lock, flags); stamp = hecc_read_stamp(priv, mbxno); stats->tx_bytes += - can_rx_offload_get_echo_skb(&priv->offload, - mbxno, stamp, NULL); + can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload, + mbxno, stamp, NULL); stats->tx_packets++; --priv->tx_tail; } diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig index 58fcd2b34820..d1450722cb3c 100644 --- a/drivers/net/can/usb/Kconfig +++ b/drivers/net/can/usb/Kconfig @@ -52,6 +52,7 @@ config CAN_F81604 config CAN_GS_USB tristate "Geschwister Schneider UG and candleLight compatible interfaces" + select CAN_RX_OFFLOAD help This driver supports the Geschwister Schneider and bytewerk.org candleLight compatible diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index bd9eb066ecf1..95b0fdb602c8 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -5,6 +5,7 @@ * Copyright (C) 2013-2016 Geschwister Schneider Technologie-, * Entwicklungs- und Vertriebs UG (Haftungsbeschränkt). * Copyright (C) 2016 Hubert Denkmair + * Copyright (c) 2023 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> * * Many thanks to all socketcan devs! */ @@ -24,6 +25,7 @@ #include <linux/can.h> #include <linux/can/dev.h> #include <linux/can/error.h> +#include <linux/can/rx-offload.h> /* Device specific constants */ #define USB_GS_USB_1_VENDOR_ID 0x1d50 @@ -282,6 +284,8 @@ struct gs_host_frame { #define GS_MAX_TX_URBS 10 /* Only launch a max of GS_MAX_RX_URBS usb requests at a time. */ #define GS_MAX_RX_URBS 30 +#define GS_NAPI_WEIGHT 32 + /* Maximum number of interfaces the driver supports per device. * Current hardware only supports 3 interfaces. The future may vary. */ @@ -295,6 +299,7 @@ struct gs_tx_context { struct gs_can { struct can_priv can; /* must be the first member */ + struct can_rx_offload offload; struct gs_usb *parent; struct net_device *netdev; @@ -506,27 +511,64 @@ static void gs_update_state(struct gs_can *dev, struct can_frame *cf) } } -static void gs_usb_set_timestamp(struct gs_can *dev, struct sk_buff *skb, - const struct gs_host_frame *hf) +static u32 gs_usb_set_timestamp(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); + if (skb) + gs_usb_skb_set_timestamp(dev, skb, timestamp); + + return timestamp; +} + +static void gs_usb_rx_offload(struct gs_can *dev, struct sk_buff *skb, + const struct gs_host_frame *hf) +{ + struct can_rx_offload *offload = &dev->offload; + int rc; + + if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) { + const u32 ts = gs_usb_set_timestamp(dev, skb, hf); + + rc = can_rx_offload_queue_timestamp(offload, skb, ts); + } else { + rc = can_rx_offload_queue_tail(offload, skb); + } + + if (rc) + dev->netdev->stats.rx_fifo_errors++; +} + +static unsigned int +gs_usb_get_echo_skb(struct gs_can *dev, struct sk_buff *skb, + const struct gs_host_frame *hf) +{ + struct can_rx_offload *offload = &dev->offload; + const u32 echo_id = hf->echo_id; + unsigned int len; + + if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) { + const u32 ts = gs_usb_set_timestamp(dev, skb, hf); + + len = can_rx_offload_get_echo_skb_queue_timestamp(offload, echo_id, + ts, NULL); + } else { + len = can_rx_offload_get_echo_skb_queue_tail(offload, echo_id, + NULL); + } - return; + return len; } static void gs_usb_receive_bulk_callback(struct urb *urb) { - struct gs_usb *usbcan = urb->context; + struct gs_usb *parent = urb->context; struct gs_can *dev; struct net_device *netdev; int rc; @@ -537,7 +579,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) struct canfd_frame *cfd; struct sk_buff *skb; - BUG_ON(!usbcan); + BUG_ON(!parent); switch (urb->status) { case 0: /* success */ @@ -554,7 +596,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) if (hf->channel >= GS_MAX_INTF) goto device_detach; - dev = usbcan->canch[hf->channel]; + dev = parent->canch[hf->channel]; netdev = dev->netdev; stats = &netdev->stats; @@ -567,7 +609,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) if (hf->echo_id == -1) { /* normal rx */ if (hf->flags & GS_CAN_FLAG_FD) { - skb = alloc_canfd_skb(dev->netdev, &cfd); + skb = alloc_canfd_skb(netdev, &cfd); if (!skb) return; @@ -580,7 +622,7 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) memcpy(cfd->data, hf->canfd->data, cfd->len); } else { - skb = alloc_can_skb(dev->netdev, &cf); + skb = alloc_can_skb(netdev, &cf); if (!skb) return; @@ -594,12 +636,7 @@ 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; - - netif_rx(skb); + gs_usb_rx_offload(dev, skb, hf); } else { /* echo_id == hf->echo_id */ if (hf->echo_id >= GS_MAX_TX_URBS) { netdev_err(netdev, @@ -619,12 +656,8 @@ static void gs_usb_receive_bulk_callback(struct urb *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); - + stats->tx_packets++; + stats->tx_bytes += gs_usb_get_echo_skb(dev, skb, hf); gs_free_tx_context(txc); atomic_dec(&dev->active_tx_urbs); @@ -633,6 +666,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) } if (hf->flags & GS_CAN_FLAG_OVERFLOW) { + stats->rx_over_errors++; + stats->rx_errors++; + skb = alloc_can_err_skb(netdev, &cf); if (!skb) goto resubmit_urb; @@ -640,25 +676,26 @@ static void gs_usb_receive_bulk_callback(struct urb *urb) cf->can_id |= CAN_ERR_CRTL; cf->len = CAN_ERR_DLC; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; - stats->rx_over_errors++; - stats->rx_errors++; - netif_rx(skb); + + gs_usb_rx_offload(dev, skb, hf); } - resubmit_urb: - usb_fill_bulk_urb(urb, usbcan->udev, - usb_rcvbulkpipe(usbcan->udev, GS_USB_ENDPOINT_IN), + can_rx_offload_irq_finish(&dev->offload); + +resubmit_urb: + usb_fill_bulk_urb(urb, parent->udev, + usb_rcvbulkpipe(parent->udev, GS_USB_ENDPOINT_IN), hf, dev->parent->hf_size_rx, - gs_usb_receive_bulk_callback, usbcan); + gs_usb_receive_bulk_callback, parent); rc = usb_submit_urb(urb, GFP_ATOMIC); /* USB failure take down all interfaces */ if (rc == -ENODEV) { - device_detach: +device_detach: for (rc = 0; rc < GS_MAX_INTF; rc++) { - if (usbcan->canch[rc]) - netif_device_detach(usbcan->canch[rc]->netdev); + if (parent->canch[rc]) + netif_device_detach(parent->canch[rc]->netdev); } } } @@ -742,10 +779,8 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, goto nomem_urb; hf = kmalloc(dev->hf_size_tx, GFP_ATOMIC); - if (!hf) { - netdev_err(netdev, "No memory left for USB buffer\n"); + if (!hf) goto nomem_hf; - } idx = txc->echo_id; @@ -818,12 +853,12 @@ static netdev_tx_t gs_can_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; - badidx: +badidx: kfree(hf); - nomem_hf: +nomem_hf: usb_free_urb(urb); - nomem_urb: +nomem_urb: gs_free_tx_context(txc); dev_kfree_skb(skb); stats->tx_dropped++; @@ -860,6 +895,8 @@ static int gs_can_open(struct net_device *netdev) dev->hf_size_tx = struct_size(hf, classic_can, 1); } + can_rx_offload_enable(&dev->offload); + if (!parent->active_channels) { if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) gs_usb_timestamp_init(parent); @@ -878,8 +915,6 @@ static int gs_can_open(struct net_device *netdev) buf = kmalloc(dev->parent->hf_size_rx, GFP_KERNEL); if (!buf) { - netdev_err(netdev, - "No memory left for USB buffer\n"); rc = -ENOMEM; goto out_usb_free_urb; } @@ -902,7 +937,8 @@ static int gs_can_open(struct net_device *netdev) netif_device_detach(dev->netdev); netdev_err(netdev, - "usb_submit failed (err=%d)\n", rc); + "usb_submit_urb() failed, error %pe\n", + ERR_PTR(rc)); goto out_usb_unanchor_urb; } @@ -969,6 +1005,7 @@ out_usb_kill_anchored_urbs: gs_usb_timestamp_stop(parent); } + can_rx_offload_disable(&dev->offload); close_candev(netdev); return rc; @@ -1033,9 +1070,7 @@ static int gs_can_close(struct net_device *netdev) dev->can.state = CAN_STATE_STOPPED; /* reset the device */ - rc = gs_cmd_reset(dev); - if (rc < 0) - netdev_warn(netdev, "Couldn't shutdown device (err=%d)", rc); + gs_cmd_reset(dev); /* reset tx contexts */ for (rc = 0; rc < GS_MAX_TX_URBS; rc++) { @@ -1043,6 +1078,8 @@ static int gs_can_close(struct net_device *netdev) dev->tx_context[rc].echo_id = GS_MAX_TX_URBS; } + can_rx_offload_disable(&dev->offload); + /* close the netdev */ close_candev(netdev); @@ -1342,6 +1379,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, dev->can.data_bittiming_const = &dev->data_bt_const; } + can_rx_offload_add_manual(netdev, &dev->offload, GS_NAPI_WEIGHT); SET_NETDEV_DEV(netdev, &intf->dev); rc = register_candev(dev->netdev); @@ -1349,12 +1387,14 @@ static struct gs_can *gs_make_candev(unsigned int channel, dev_err(&intf->dev, "Couldn't register candev for channel %d (%pe)\n", channel, ERR_PTR(rc)); - goto out_free_candev; + goto out_can_rx_offload_del; } return dev; - out_free_candev: +out_can_rx_offload_del: + can_rx_offload_del(&dev->offload); +out_free_candev: free_candev(dev->netdev); return ERR_PTR(rc); } @@ -1362,7 +1402,7 @@ static struct gs_can *gs_make_candev(unsigned int channel, static void gs_destroy_candev(struct gs_can *dev) { unregister_candev(dev->netdev); - usb_kill_anchored_urbs(&dev->tx_submitted); + can_rx_offload_del(&dev->offload); free_candev(dev->netdev); } @@ -1371,7 +1411,7 @@ static int gs_usb_probe(struct usb_interface *intf, { struct usb_device *udev = interface_to_usbdev(intf); struct gs_host_frame *hf; - struct gs_usb *dev; + struct gs_usb *parent; struct gs_host_config hconf = { .byte_order = cpu_to_le32(0x0000beef), }; @@ -1414,49 +1454,49 @@ static int gs_usb_probe(struct usb_interface *intf, return -EINVAL; } - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + parent = kzalloc(sizeof(*parent), GFP_KERNEL); + if (!parent) return -ENOMEM; - init_usb_anchor(&dev->rx_submitted); + init_usb_anchor(&parent->rx_submitted); - usb_set_intfdata(intf, dev); - dev->udev = udev; + usb_set_intfdata(intf, parent); + parent->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])) { + parent->canch[i] = gs_make_candev(i, intf, &dconf); + if (IS_ERR_OR_NULL(parent->canch[i])) { /* save error code to return later */ - rc = PTR_ERR(dev->canch[i]); + rc = PTR_ERR(parent->canch[i]); /* on failure destroy previously created candevs */ icount = i; for (i = 0; i < icount; i++) - gs_destroy_candev(dev->canch[i]); + gs_destroy_candev(parent->canch[i]); - usb_kill_anchored_urbs(&dev->rx_submitted); - kfree(dev); + usb_kill_anchored_urbs(&parent->rx_submitted); + kfree(parent); return rc; } - dev->canch[i]->parent = dev; + parent->canch[i]->parent = parent; /* 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) + * timestamps are supported. + */ + if (parent->canch[i]->can.ctrlmode_supported & CAN_CTRLMODE_FD) { + if (parent->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) + if (parent->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); + parent->hf_size_rx = max(parent->hf_size_rx, hf_size_rx); } return 0; @@ -1464,22 +1504,21 @@ static int gs_usb_probe(struct usb_interface *intf, static void gs_usb_disconnect(struct usb_interface *intf) { - struct gs_usb *dev = usb_get_intfdata(intf); + struct gs_usb *parent = usb_get_intfdata(intf); unsigned int i; usb_set_intfdata(intf, NULL); - if (!dev) { + if (!parent) { dev_err(&intf->dev, "Disconnect (nodata)\n"); return; } for (i = 0; i < GS_MAX_INTF; i++) - if (dev->canch[i]) - gs_destroy_candev(dev->canch[i]); + if (parent->canch[i]) + gs_destroy_candev(parent->canch[i]); - usb_kill_anchored_urbs(&dev->rx_submitted); - kfree(dev); + kfree(parent); } static const struct usb_device_id gs_usb_table[] = { diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c index d881e1d30183..24ad9f593a77 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c @@ -214,19 +214,6 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time) } } -/* - * post received skb after having set any hw timestamp - */ -int peak_usb_netif_rx(struct sk_buff *skb, - struct peak_time_ref *time_ref, u32 ts_low) -{ - struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); - - peak_usb_get_ts_time(time_ref, ts_low, &hwts->hwtstamp); - - return netif_rx(skb); -} - /* post received skb with native 64-bit hw timestamp */ int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high) { diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h index 980e315186cf..f6cf84bb718f 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h @@ -142,8 +142,6 @@ void peak_usb_init_time_ref(struct peak_time_ref *time_ref, void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now); void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *tv); -int peak_usb_netif_rx(struct sk_buff *skb, - struct peak_time_ref *time_ref, u32 ts_low); int peak_usb_netif_rx_64(struct sk_buff *skb, u32 ts_low, u32 ts_high); void peak_usb_async_complete(struct urb *urb); void peak_usb_restart_complete(struct peak_usb_device *dev); diff --git a/include/linux/can/rx-offload.h b/include/linux/can/rx-offload.h index c205c51d79c9..d29bb4521947 100644 --- a/include/linux/can/rx-offload.h +++ b/include/linux/can/rx-offload.h @@ -3,7 +3,7 @@ * linux/can/rx-offload.h * * Copyright (c) 2014 David Jander, Protonic Holland - * Copyright (c) 2014-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> + * Copyright (c) 2014-2017, 2023 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> */ #ifndef _CAN_RX_OFFLOAD_H @@ -44,11 +44,14 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload); int can_rx_offload_queue_timestamp(struct can_rx_offload *offload, struct sk_buff *skb, u32 timestamp); -unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, - unsigned int idx, u32 timestamp, - unsigned int *frame_len_ptr); +unsigned int can_rx_offload_get_echo_skb_queue_timestamp(struct can_rx_offload *offload, + unsigned int idx, u32 timestamp, + unsigned int *frame_len_ptr); int can_rx_offload_queue_tail(struct can_rx_offload *offload, struct sk_buff *skb); +unsigned int can_rx_offload_get_echo_skb_queue_tail(struct can_rx_offload *offload, + unsigned int idx, + unsigned int *frame_len_ptr); void can_rx_offload_irq_finish(struct can_rx_offload *offload); void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload); void can_rx_offload_del(struct can_rx_offload *offload); |