linux-can-next-for-6.6-20230728
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEDs2BvajyNKlf9TJQvlAcSiqKBOgFAmTDclgTHG1rbEBwZW5n dXRyb25peC5kZQAKCRC+UBxKKooE6C9xB/40NJBrFJknDzF9hVHL7aynsJAi3qJ1 T5U061NIVWSjPKOcIbKHX9I7c9KBh+jv+GhxLSlpDq0f+6JYNlNXykowVIaq76Kk gVYXxBu1MXJqkxKH9qy4WxpNZVa7XjXOzRm/wEg34cMsN9S5EX9BNsJgvHH+/6OH S9UUpbr0AfngsYxPGMcoXUMDBD0o2Cf5orp+Ml9o9IdwbgGlojgRtMYK6G/BL+TF vZCS6jb6bBe5VSnoD5qDMRExtgIyCvXHG2s8BYk/4XkKfMBKKJoFFMZD+2z3HAk8 02de5h/eqMbta03w/+4DaQklb2Gvk8wkT3w1Nn67+lEutC/xyMiNL89D =lD7D -----END PGP SIGNATURE----- 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>
This commit is contained in:
commit
8ad228b1ab
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -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.
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "sja1000.h"
|
||||
|
||||
|
@ -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++;
|
||||
|
||||
|
@ -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[] = {
|
||||
@ -784,6 +795,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)");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
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 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[] = {
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user