Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next

Pull networking updates from David Miller:
 "Highlights:

   - Gustavo A. R. Silva keeps working on the implicit switch fallthru
     changes.

   - Support 802.11ax High-Efficiency wireless in cfg80211 et al, From
     Luca Coelho.

   - Re-enable ASPM in r8169, from Kai-Heng Feng.

   - Add virtual XFRM interfaces, which avoids all of the limitations of
     existing IPSEC tunnels. From Steffen Klassert.

   - Convert GRO over to use a hash table, so that when we have many
     flows active we don't traverse a long list during accumluation.

   - Many new self tests for routing, TC, tunnels, etc. Too many
     contributors to mention them all, but I'm really happy to keep
     seeing this stuff.

   - Hardware timestamping support for dpaa_eth/fsl-fman from Yangbo Lu.

   - Lots of cleanups and fixes in L2TP code from Guillaume Nault.

   - Add IPSEC offload support to netdevsim, from Shannon Nelson.

   - Add support for slotting with non-uniform distribution to netem
     packet scheduler, from Yousuk Seung.

   - Add UDP GSO support to mlx5e, from Boris Pismenny.

   - Support offloading of Team LAG in NFP, from John Hurley.

   - Allow to configure TX queue selection based upon RX queue, from
     Amritha Nambiar.

   - Support ethtool ring size configuration in aquantia, from Anton
     Mikaev.

   - Support DSCP and flowlabel per-transport in SCTP, from Xin Long.

   - Support list based batching and stack traversal of SKBs, this is
     very exciting work. From Edward Cree.

   - Busyloop optimizations in vhost_net, from Toshiaki Makita.

   - Introduce the ETF qdisc, which allows time based transmissions. IGB
     can offload this in hardware. From Vinicius Costa Gomes.

   - Add parameter support to devlink, from Moshe Shemesh.

   - Several multiplication and division optimizations for BPF JIT in
     nfp driver, from Jiong Wang.

   - Lots of prepatory work to make more of the packet scheduler layer
     lockless, when possible, from Vlad Buslov.

   - Add ACK filter and NAT awareness to sch_cake packet scheduler, from
     Toke Høiland-Jørgensen.

   - Support regions and region snapshots in devlink, from Alex Vesker.

   - Allow to attach XDP programs to both HW and SW at the same time on
     a given device, with initial support in nfp. From Jakub Kicinski.

   - Add TLS RX offload and support in mlx5, from Ilya Lesokhin.

   - Use PHYLIB in r8169 driver, from Heiner Kallweit.

   - All sorts of changes to support Spectrum 2 in mlxsw driver, from
     Ido Schimmel.

   - PTP support in mv88e6xxx DSA driver, from Andrew Lunn.

   - Make TCP_USER_TIMEOUT socket option more accurate, from Jon
     Maxwell.

   - Support for templates in packet scheduler classifier, from Jiri
     Pirko.

   - IPV6 support in RDS, from Ka-Cheong Poon.

   - Native tproxy support in nf_tables, from Máté Eckl.

   - Maintain IP fragment queue in an rbtree, but optimize properly for
     in-order frags. From Peter Oskolkov.

   - Improvde handling of ACKs on hole repairs, from Yuchung Cheng"

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1996 commits)
  bpf: test: fix spelling mistake "REUSEEPORT" -> "REUSEPORT"
  hv/netvsc: Fix NULL dereference at single queue mode fallback
  net: filter: mark expected switch fall-through
  xen-netfront: fix warn message as irq device name has '/'
  cxgb4: Add new T5 PCI device ids 0x50af and 0x50b0
  net: dsa: mv88e6xxx: missing unlock on error path
  rds: fix building with IPV6=m
  inet/connection_sock: prefer _THIS_IP_ to current_text_addr
  net: dsa: mv88e6xxx: bitwise vs logical bug
  net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd()
  ieee802154: hwsim: using right kind of iteration
  net: hns3: Add vlan filter setting by ethtool command -K
  net: hns3: Set tx ring' tc info when netdev is up
  net: hns3: Remove tx ring BD len register in hns3_enet
  net: hns3: Fix desc num set to default when setting channel
  net: hns3: Fix for phy link issue when using marvell phy driver
  net: hns3: Fix for information of phydev lost problem when down/up
  net: hns3: Fix for command format parsing error in hclge_is_all_function_id_zero
  net: hns3: Add support for serdes loopback selftest
  bnxt_en: take coredump_record structure off stack
  ...
This commit is contained in:
Linus Torvalds
2018-08-15 15:04:25 -07:00
1752 changed files with 119281 additions and 29178 deletions

View File

@@ -73,7 +73,7 @@ MODULE_PARM_DESC(msgobj15_eff, "Extended 29-bit frames for message object 15 "
static int i82527_compat;
module_param(i82527_compat, int, 0444);
MODULE_PARM_DESC(i82527_compat, "Strict Intel 82527 comptibility mode "
MODULE_PARM_DESC(i82527_compat, "Strict Intel 82527 compatibility mode "
"without using additional functions");
/*

View File

@@ -649,8 +649,7 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;
*cf = skb_put(skb, sizeof(struct can_frame));
memset(*cf, 0, sizeof(struct can_frame));
*cf = skb_put_zero(skb, sizeof(struct can_frame));
return skb;
}
@@ -678,8 +677,7 @@ struct sk_buff *alloc_canfd_skb(struct net_device *dev,
can_skb_prv(skb)->ifindex = dev->ifindex;
can_skb_prv(skb)->skbcnt = 0;
*cfd = skb_put(skb, sizeof(struct canfd_frame));
memset(*cfd, 0, sizeof(struct canfd_frame));
*cfd = skb_put_zero(skb, sizeof(struct canfd_frame));
return skb;
}
@@ -703,7 +701,8 @@ EXPORT_SYMBOL_GPL(alloc_can_err_skb);
/*
* Allocate and setup space for the CAN network device
*/
struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
unsigned int txqs, unsigned int rxqs)
{
struct net_device *dev;
struct can_priv *priv;
@@ -715,7 +714,8 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
else
size = sizeof_priv;
dev = alloc_netdev(size, "can%d", NET_NAME_UNKNOWN, can_setup);
dev = alloc_netdev_mqs(size, "can%d", NET_NAME_UNKNOWN, can_setup,
txqs, rxqs);
if (!dev)
return NULL;
@@ -734,7 +734,7 @@ struct net_device *alloc_candev(int sizeof_priv, unsigned int echo_skb_max)
return dev;
}
EXPORT_SYMBOL_GPL(alloc_candev);
EXPORT_SYMBOL_GPL(alloc_candev_mqs);
/*
* Free space of the CAN network device

View File

@@ -1,24 +1,13 @@
/*
* flexcan.c - FLEXCAN CAN controller driver
*
* Copyright (c) 2005-2006 Varma Electronics Oy
* Copyright (c) 2009 Sascha Hauer, Pengutronix
* Copyright (c) 2010-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
* Copyright (c) 2014 David Jander, Protonic Holland
*
* Based on code originally by Andrey Volkov <avolkov@varma-el.com>
*
* LICENCE:
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
// SPDX-License-Identifier: GPL-2.0
//
// flexcan.c - FLEXCAN CAN controller driver
//
// Copyright (c) 2005-2006 Varma Electronics Oy
// Copyright (c) 2009 Sascha Hauer, Pengutronix
// Copyright (c) 2010-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
// Copyright (c) 2014 David Jander, Protonic Holland
//
// Based on code originally by Andrey Volkov <avolkov@varma-el.com>
#include <linux/netdevice.h>
#include <linux/can.h>
@@ -523,7 +512,7 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
return err;
}
static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
const struct flexcan_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;

View File

@@ -1684,7 +1684,7 @@ static int ican3_stop(struct net_device *ndev)
return 0;
}
static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
static netdev_tx_t ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct ican3_dev *mod = netdev_priv(ndev);
struct can_frame *cf = (struct can_frame *)skb->data;

View File

@@ -486,7 +486,7 @@ int peak_canfd_handle_msgs_list(struct peak_canfd_priv *priv,
if (msg_size <= 0)
break;
msg_ptr += msg_size;
msg_ptr += ALIGN(msg_size, 4);
}
if (msg_size < 0)

View File

@@ -174,9 +174,6 @@ struct pciefd_page {
u32 size;
};
#define CANFD_IRQ_SET 0x00000001
#define CANFD_TX_PATH_SET 0x00000002
/* CAN-FD channel object */
struct pciefd_board;
struct pciefd_can {
@@ -418,7 +415,7 @@ static int pciefd_pre_cmd(struct peak_canfd_priv *ucan)
break;
/* going into operational mode: setup IRQ handler */
err = request_irq(priv->board->pci_dev->irq,
err = request_irq(priv->ucan.ndev->irq,
pciefd_irq_handler,
IRQF_SHARED,
PCIEFD_DRV_NAME,
@@ -491,15 +488,18 @@ static int pciefd_post_cmd(struct peak_canfd_priv *ucan)
/* controller now in reset mode: */
/* stop and reset DMA addresses in Tx/Rx engines */
pciefd_can_clear_tx_dma(priv);
pciefd_can_clear_rx_dma(priv);
/* disable IRQ for this CAN */
pciefd_can_writereg(priv, CANFD_CTL_IEN_BIT,
PCIEFD_REG_CAN_RX_CTL_CLR);
free_irq(priv->board->pci_dev->irq, priv);
/* stop and reset DMA addresses in Tx/Rx engines */
pciefd_can_clear_tx_dma(priv);
pciefd_can_clear_rx_dma(priv);
/* wait for above commands to complete (read cycle) */
(void)pciefd_sys_readreg(priv->board, PCIEFD_REG_SYS_VER1);
free_irq(priv->ucan.ndev->irq, priv);
ucan->can.state = CAN_STATE_STOPPED;
@@ -638,7 +638,7 @@ static int pciefd_can_probe(struct pciefd_board *pciefd)
GFP_KERNEL);
if (!priv->tx_dma_vaddr) {
dev_err(&pciefd->pci_dev->dev,
"Tx dmaim_alloc_coherent(%u) failure\n",
"Tx dmam_alloc_coherent(%u) failure\n",
PCIEFD_TX_DMA_SIZE);
goto err_free_candev;
}
@@ -691,7 +691,7 @@ static int pciefd_can_probe(struct pciefd_board *pciefd)
pciefd->can[pciefd->can_count] = priv;
dev_info(&pciefd->pci_dev->dev, "%s at reg_base=0x%p irq=%d\n",
ndev->name, priv->reg_base, pciefd->pci_dev->irq);
ndev->name, priv->reg_base, ndev->irq);
return 0;

View File

@@ -608,7 +608,7 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
writeb(0x00, cfg_base + PITA_GPIOICR);
/* Toggle reset */
writeb(0x05, cfg_base + PITA_MISC + 3);
mdelay(5);
usleep_range(5000, 6000);
/* Leave parport mux mode */
writeb(0x04, cfg_base + PITA_MISC + 3);

View File

@@ -530,7 +530,7 @@ static int pcan_add_channels(struct pcan_pccard *card)
pcan_write_reg(card, PCC_CCR, ccr);
/* wait 2ms before unresetting channels */
mdelay(2);
usleep_range(2000, 3000);
ccr &= ~PCC_CCR_RST_ALL;
pcan_write_reg(card, PCC_CCR, ccr);

View File

@@ -409,7 +409,7 @@ static int sun4ican_set_mode(struct net_device *dev, enum can_mode mode)
* xx xx xx xx ff ll 00 11 22 33 44 55 66 77
* [ can_id ] [flags] [len] [can data (up to 8 bytes]
*/
static int sun4ican_start_xmit(struct sk_buff *skb, struct net_device *dev)
static netdev_tx_t sun4ican_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sun4ican_priv *priv = netdev_priv(dev);
struct can_frame *cf = (struct can_frame *)skb->data;

View File

@@ -1,6 +1,12 @@
menu "CAN USB interfaces"
depends on USB
config CAN_8DEV_USB
tristate "8 devices USB2CAN interface"
---help---
This driver supports the USB2CAN interface
from 8 devices (http://www.8devices.com).
config CAN_EMS_USB
tristate "EMS CPC-USB/ARM7 CAN/USB interface"
---help---
@@ -26,7 +32,7 @@ config CAN_KVASER_USB
tristate "Kvaser CAN/USB interface"
---help---
This driver adds support for Kvaser CAN/USB devices like Kvaser
Leaf Light and Kvaser USBcan II.
Leaf Light, Kvaser USBcan II and Kvaser Memorator Pro 5xHS.
The driver provides support for the following devices:
- Kvaser Leaf Light
@@ -55,12 +61,30 @@ config CAN_KVASER_USB
- Kvaser Memorator HS/HS
- Kvaser Memorator HS/LS
- Scania VCI2 (if you have the Kvaser logo on top)
- Kvaser BlackBird v2
- Kvaser Leaf Pro HS v2
- Kvaser Hybrid 2xCAN/LIN
- Kvaser Hybrid Pro 2xCAN/LIN
- Kvaser Memorator 2xHS v2
- Kvaser Memorator Pro 2xHS v2
- Kvaser Memorator Pro 5xHS
- Kvaser USBcan Light 4xHS
- Kvaser USBcan Pro 2xHS v2
- Kvaser USBcan Pro 5xHS
- ATI Memorator Pro 2xHS v2
- ATI USBcan Pro 2xHS v2
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called kvaser_usb.
config CAN_MCBA_USB
tristate "Microchip CAN BUS Analyzer interface"
---help---
This driver supports the CAN BUS Analyzer interface
from Microchip (http://www.microchip.com/development-tools/).
config CAN_PEAK_USB
tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD"
---help---
@@ -77,16 +101,26 @@ config CAN_PEAK_USB
(see also http://www.peak-system.com).
config CAN_8DEV_USB
tristate "8 devices USB2CAN interface"
---help---
This driver supports the USB2CAN interface
from 8 devices (http://www.8devices.com).
config CAN_MCBA_USB
tristate "Microchip CAN BUS Analyzer interface"
---help---
This driver supports the CAN BUS Analyzer interface
from Microchip (http://www.microchip.com/development-tools/).
config CAN_UCAN
tristate "Theobroma Systems UCAN interface"
---help---
This driver supports the Theobroma Systems
UCAN USB-CAN interface.
The UCAN driver supports the microcontroller-based USB/CAN
adapters from Theobroma Systems. There are two form-factors
that run essentially the same firmware:
* Seal: standalone USB stick
https://www.theobroma-systems.com/seal)
* Mule: integrated on the PCB of various System-on-Modules
from Theobroma Systems like the A31-µQ7 and the RK3399-Q7
(https://www.theobroma-systems.com/rk3399-q7)
endmenu

View File

@@ -3,10 +3,11 @@
# Makefile for the Linux Controller Area Network USB drivers.
#
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
obj-$(CONFIG_CAN_GS_USB) += gs_usb.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
obj-$(CONFIG_CAN_8DEV_USB) += usb_8dev.o
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb/
obj-$(CONFIG_CAN_MCBA_USB) += mcba_usb.o
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
obj-$(CONFIG_CAN_UCAN) += ucan.o

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
kvaser_usb-y = kvaser_usb_core.o kvaser_usb_leaf.o kvaser_usb_hydra.o

View File

@@ -0,0 +1,188 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Parts of this driver are based on the following:
* - Kvaser linux leaf driver (version 4.78)
* - CAN driver for esd CAN-USB/2
* - Kvaser linux usbcanII driver (version 5.3)
* - Kvaser linux mhydra driver (version 5.24)
*
* Copyright (C) 2002-2018 KVASER AB, Sweden. All rights reserved.
* Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
* Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
* Copyright (C) 2015 Valeo S.A.
*/
#ifndef KVASER_USB_H
#define KVASER_USB_H
/* Kvaser USB CAN dongles are divided into three major platforms:
* - Hydra: Running firmware labeled as 'mhydra'
* - Leaf: Based on Renesas M32C or Freescale i.MX28, running firmware labeled
* as 'filo'
* - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
*/
#include <linux/completion.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#define KVASER_USB_MAX_RX_URBS 4
#define KVASER_USB_MAX_TX_URBS 128
#define KVASER_USB_TIMEOUT 1000 /* msecs */
#define KVASER_USB_RX_BUFFER_SIZE 3072
#define KVASER_USB_MAX_NET_DEVICES 5
/* USB devices features */
#define KVASER_USB_HAS_SILENT_MODE BIT(0)
#define KVASER_USB_HAS_TXRX_ERRORS BIT(1)
/* Device capabilities */
#define KVASER_USB_CAP_BERR_CAP 0x01
#define KVASER_USB_CAP_EXT_CAP 0x02
#define KVASER_USB_HYDRA_CAP_EXT_CMD 0x04
struct kvaser_usb_dev_cfg;
enum kvaser_usb_leaf_family {
KVASER_LEAF,
KVASER_USBCAN,
};
#define KVASER_USB_HYDRA_MAX_CMD_LEN 128
struct kvaser_usb_dev_card_data_hydra {
u8 channel_to_he[KVASER_USB_MAX_NET_DEVICES];
u8 sysdbg_he;
spinlock_t transid_lock; /* lock for transid */
u16 transid;
/* lock for usb_rx_leftover and usb_rx_leftover_len */
spinlock_t usb_rx_leftover_lock;
u8 usb_rx_leftover[KVASER_USB_HYDRA_MAX_CMD_LEN];
u8 usb_rx_leftover_len;
};
struct kvaser_usb_dev_card_data {
u32 ctrlmode_supported;
u32 capabilities;
union {
struct {
enum kvaser_usb_leaf_family family;
} leaf;
struct kvaser_usb_dev_card_data_hydra hydra;
};
};
/* Context for an outstanding, not yet ACKed, transmission */
struct kvaser_usb_tx_urb_context {
struct kvaser_usb_net_priv *priv;
u32 echo_index;
int dlc;
};
struct kvaser_usb {
struct usb_device *udev;
struct usb_interface *intf;
struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
const struct kvaser_usb_dev_ops *ops;
const struct kvaser_usb_dev_cfg *cfg;
struct usb_endpoint_descriptor *bulk_in, *bulk_out;
struct usb_anchor rx_submitted;
/* @max_tx_urbs: Firmware-reported maximum number of outstanding,
* not yet ACKed, transmissions on this device. This value is
* also used as a sentinel for marking free tx contexts.
*/
u32 fw_version;
unsigned int nchannels;
unsigned int max_tx_urbs;
struct kvaser_usb_dev_card_data card_data;
bool rxinitdone;
void *rxbuf[KVASER_USB_MAX_RX_URBS];
dma_addr_t rxbuf_dma[KVASER_USB_MAX_RX_URBS];
};
struct kvaser_usb_net_priv {
struct can_priv can;
struct can_berr_counter bec;
struct kvaser_usb *dev;
struct net_device *netdev;
int channel;
struct completion start_comp, stop_comp, flush_comp;
struct usb_anchor tx_submitted;
spinlock_t tx_contexts_lock; /* lock for active_tx_contexts */
int active_tx_contexts;
struct kvaser_usb_tx_urb_context tx_contexts[];
};
/**
* struct kvaser_usb_dev_ops - Device specific functions
* @dev_set_mode: used for can.do_set_mode
* @dev_set_bittiming: used for can.do_set_bittiming
* @dev_set_data_bittiming: used for can.do_set_data_bittiming
* @dev_get_berr_counter: used for can.do_get_berr_counter
*
* @dev_setup_endpoints: setup USB in and out endpoints
* @dev_init_card: initialize card
* @dev_get_software_info: get software info
* @dev_get_software_details: get software details
* @dev_get_card_info: get card info
* @dev_get_capabilities: discover device capabilities
*
* @dev_set_opt_mode: set ctrlmod
* @dev_start_chip: start the CAN controller
* @dev_stop_chip: stop the CAN controller
* @dev_reset_chip: reset the CAN controller
* @dev_flush_queue: flush outstanding CAN messages
* @dev_read_bulk_callback: handle incoming commands
* @dev_frame_to_cmd: translate struct can_frame into device command
*/
struct kvaser_usb_dev_ops {
int (*dev_set_mode)(struct net_device *netdev, enum can_mode mode);
int (*dev_set_bittiming)(struct net_device *netdev);
int (*dev_set_data_bittiming)(struct net_device *netdev);
int (*dev_get_berr_counter)(const struct net_device *netdev,
struct can_berr_counter *bec);
int (*dev_setup_endpoints)(struct kvaser_usb *dev);
int (*dev_init_card)(struct kvaser_usb *dev);
int (*dev_get_software_info)(struct kvaser_usb *dev);
int (*dev_get_software_details)(struct kvaser_usb *dev);
int (*dev_get_card_info)(struct kvaser_usb *dev);
int (*dev_get_capabilities)(struct kvaser_usb *dev);
int (*dev_set_opt_mode)(const struct kvaser_usb_net_priv *priv);
int (*dev_start_chip)(struct kvaser_usb_net_priv *priv);
int (*dev_stop_chip)(struct kvaser_usb_net_priv *priv);
int (*dev_reset_chip)(struct kvaser_usb *dev, int channel);
int (*dev_flush_queue)(struct kvaser_usb_net_priv *priv);
void (*dev_read_bulk_callback)(struct kvaser_usb *dev, void *buf,
int len);
void *(*dev_frame_to_cmd)(const struct kvaser_usb_net_priv *priv,
const struct sk_buff *skb, int *frame_len,
int *cmd_len, u16 transid);
};
struct kvaser_usb_dev_cfg {
const struct can_clock clock;
const unsigned int timestamp_freq;
const struct can_bittiming_const * const bittiming_const;
const struct can_bittiming_const * const data_bittiming_const;
};
extern const struct kvaser_usb_dev_ops kvaser_usb_hydra_dev_ops;
extern const struct kvaser_usb_dev_ops kvaser_usb_leaf_dev_ops;
int kvaser_usb_recv_cmd(const struct kvaser_usb *dev, void *cmd, int len,
int *actual_len);
int kvaser_usb_send_cmd(const struct kvaser_usb *dev, void *cmd, int len);
int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
int len);
int kvaser_usb_can_rx_over_error(struct net_device *netdev);
#endif /* KVASER_USB_H */

View File

@@ -0,0 +1,835 @@
// SPDX-License-Identifier: GPL-2.0
/* Parts of this driver are based on the following:
* - Kvaser linux leaf driver (version 4.78)
* - CAN driver for esd CAN-USB/2
* - Kvaser linux usbcanII driver (version 5.3)
* - Kvaser linux mhydra driver (version 5.24)
*
* Copyright (C) 2002-2018 KVASER AB, Sweden. All rights reserved.
* Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
* Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
* Copyright (C) 2015 Valeo S.A.
*/
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/gfp.h>
#include <linux/if.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/usb.h>
#include <linux/can.h>
#include <linux/can/dev.h>
#include <linux/can/error.h>
#include <linux/can/netlink.h>
#include "kvaser_usb.h"
/* Kvaser USB vendor id. */
#define KVASER_VENDOR_ID 0x0bfd
/* Kvaser Leaf USB devices product ids */
#define USB_LEAF_DEVEL_PRODUCT_ID 10
#define USB_LEAF_LITE_PRODUCT_ID 11
#define USB_LEAF_PRO_PRODUCT_ID 12
#define USB_LEAF_SPRO_PRODUCT_ID 14
#define USB_LEAF_PRO_LS_PRODUCT_ID 15
#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
#define USB_MEMO2_DEVEL_PRODUCT_ID 22
#define USB_MEMO2_HSHS_PRODUCT_ID 23
#define USB_UPRO_HSHS_PRODUCT_ID 24
#define USB_LEAF_LITE_GI_PRODUCT_ID 25
#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
#define USB_MEMO2_HSLS_PRODUCT_ID 27
#define USB_LEAF_LITE_CH_PRODUCT_ID 28
#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
#define USB_OEM_MERCURY_PRODUCT_ID 34
#define USB_OEM_LEAF_PRODUCT_ID 35
#define USB_CAN_R_PRODUCT_ID 39
#define USB_LEAF_LITE_V2_PRODUCT_ID 288
#define USB_MINI_PCIE_HS_PRODUCT_ID 289
#define USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID 290
#define USB_USBCAN_LIGHT_2HS_PRODUCT_ID 291
#define USB_MINI_PCIE_2HS_PRODUCT_ID 292
/* Kvaser USBCan-II devices product ids */
#define USB_USBCAN_REVB_PRODUCT_ID 2
#define USB_VCI2_PRODUCT_ID 3
#define USB_USBCAN2_PRODUCT_ID 4
#define USB_MEMORATOR_PRODUCT_ID 5
/* Kvaser Minihydra USB devices product ids */
#define USB_BLACKBIRD_V2_PRODUCT_ID 258
#define USB_MEMO_PRO_5HS_PRODUCT_ID 260
#define USB_USBCAN_PRO_5HS_PRODUCT_ID 261
#define USB_USBCAN_LIGHT_4HS_PRODUCT_ID 262
#define USB_LEAF_PRO_HS_V2_PRODUCT_ID 263
#define USB_USBCAN_PRO_2HS_V2_PRODUCT_ID 264
#define USB_MEMO_2HS_PRODUCT_ID 265
#define USB_MEMO_PRO_2HS_V2_PRODUCT_ID 266
#define USB_HYBRID_CANLIN_PRODUCT_ID 267
#define USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID 268
#define USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID 269
#define USB_HYBRID_PRO_CANLIN_PRODUCT_ID 270
static inline bool kvaser_is_leaf(const struct usb_device_id *id)
{
return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
(id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
id->idProduct <= USB_MINI_PCIE_2HS_PRODUCT_ID);
}
static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
{
return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
}
static inline bool kvaser_is_hydra(const struct usb_device_id *id)
{
return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
id->idProduct <= USB_HYBRID_PRO_CANLIN_PRODUCT_ID;
}
static const struct usb_device_id kvaser_usb_table[] = {
/* Leaf USB product IDs */
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS |
KVASER_USB_HAS_SILENT_MODE },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
/* USBCANII USB product IDs */
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
.driver_info = KVASER_USB_HAS_TXRX_ERRORS },
/* Minihydra USB product IDs */
{ USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
{ }
};
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
int kvaser_usb_send_cmd(const struct kvaser_usb *dev, void *cmd, int len)
{
int actual_len; /* Not used */
return usb_bulk_msg(dev->udev,
usb_sndbulkpipe(dev->udev,
dev->bulk_out->bEndpointAddress),
cmd, len, &actual_len, KVASER_USB_TIMEOUT);
}
int kvaser_usb_recv_cmd(const struct kvaser_usb *dev, void *cmd, int len,
int *actual_len)
{
return usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev,
dev->bulk_in->bEndpointAddress),
cmd, len, actual_len, KVASER_USB_TIMEOUT);
}
static void kvaser_usb_send_cmd_callback(struct urb *urb)
{
struct net_device *netdev = urb->context;
kfree(urb->transfer_buffer);
if (urb->status)
netdev_warn(netdev, "urb status received: %d\n", urb->status);
}
int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
int len)
{
struct kvaser_usb *dev = priv->dev;
struct net_device *netdev = priv->netdev;
struct urb *urb;
int err;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
return -ENOMEM;
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev,
dev->bulk_out->bEndpointAddress),
cmd, len, kvaser_usb_send_cmd_callback, netdev);
usb_anchor_urb(urb, &priv->tx_submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
netdev_err(netdev, "Error transmitting URB\n");
usb_unanchor_urb(urb);
}
usb_free_urb(urb);
return 0;
}
int kvaser_usb_can_rx_over_error(struct net_device *netdev)
{
struct net_device_stats *stats = &netdev->stats;
struct can_frame *cf;
struct sk_buff *skb;
stats->rx_over_errors++;
stats->rx_errors++;
skb = alloc_can_err_skb(netdev, &cf);
if (!skb) {
stats->rx_dropped++;
netdev_warn(netdev, "No memory left for err_skb\n");
return -ENOMEM;
}
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
return 0;
}
static void kvaser_usb_read_bulk_callback(struct urb *urb)
{
struct kvaser_usb *dev = urb->context;
int err;
unsigned int i;
switch (urb->status) {
case 0:
break;
case -ENOENT:
case -EPIPE:
case -EPROTO:
case -ESHUTDOWN:
return;
default:
dev_info(&dev->intf->dev, "Rx URB aborted (%d)\n", urb->status);
goto resubmit_urb;
}
dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
urb->actual_length);
resubmit_urb:
usb_fill_bulk_urb(urb, dev->udev,
usb_rcvbulkpipe(dev->udev,
dev->bulk_in->bEndpointAddress),
urb->transfer_buffer, KVASER_USB_RX_BUFFER_SIZE,
kvaser_usb_read_bulk_callback, dev);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err == -ENODEV) {
for (i = 0; i < dev->nchannels; i++) {
if (!dev->nets[i])
continue;
netif_device_detach(dev->nets[i]->netdev);
}
} else if (err) {
dev_err(&dev->intf->dev,
"Failed resubmitting read bulk urb: %d\n", err);
}
}
static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
{
int i, err = 0;
if (dev->rxinitdone)
return 0;
for (i = 0; i < KVASER_USB_MAX_RX_URBS; i++) {
struct urb *urb = NULL;
u8 *buf = NULL;
dma_addr_t buf_dma;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
err = -ENOMEM;
break;
}
buf = usb_alloc_coherent(dev->udev, KVASER_USB_RX_BUFFER_SIZE,
GFP_KERNEL, &buf_dma);
if (!buf) {
dev_warn(&dev->intf->dev,
"No memory left for USB buffer\n");
usb_free_urb(urb);
err = -ENOMEM;
break;
}
usb_fill_bulk_urb(urb, dev->udev,
usb_rcvbulkpipe
(dev->udev,
dev->bulk_in->bEndpointAddress),
buf, KVASER_USB_RX_BUFFER_SIZE,
kvaser_usb_read_bulk_callback, dev);
urb->transfer_dma = buf_dma;
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &dev->rx_submitted);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
usb_unanchor_urb(urb);
usb_free_coherent(dev->udev,
KVASER_USB_RX_BUFFER_SIZE, buf,
buf_dma);
usb_free_urb(urb);
break;
}
dev->rxbuf[i] = buf;
dev->rxbuf_dma[i] = buf_dma;
usb_free_urb(urb);
}
if (i == 0) {
dev_warn(&dev->intf->dev, "Cannot setup read URBs, error %d\n",
err);
return err;
} else if (i < KVASER_USB_MAX_RX_URBS) {
dev_warn(&dev->intf->dev, "RX performances may be slow\n");
}
dev->rxinitdone = true;
return 0;
}
static int kvaser_usb_open(struct net_device *netdev)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
struct kvaser_usb *dev = priv->dev;
int err;
err = open_candev(netdev);
if (err)
return err;
err = kvaser_usb_setup_rx_urbs(dev);
if (err)
goto error;
err = dev->ops->dev_set_opt_mode(priv);
if (err)
goto error;
err = dev->ops->dev_start_chip(priv);
if (err) {
netdev_warn(netdev, "Cannot start device, error %d\n", err);
goto error;
}
priv->can.state = CAN_STATE_ERROR_ACTIVE;
return 0;
error:
close_candev(netdev);
return err;
}
static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv)
{
int i, max_tx_urbs;
max_tx_urbs = priv->dev->max_tx_urbs;
priv->active_tx_contexts = 0;
for (i = 0; i < max_tx_urbs; i++)
priv->tx_contexts[i].echo_index = max_tx_urbs;
}
/* This method might sleep. Do not call it in the atomic context
* of URB completions.
*/
static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
{
usb_kill_anchored_urbs(&priv->tx_submitted);
kvaser_usb_reset_tx_urb_contexts(priv);
}
static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
{
int i;
usb_kill_anchored_urbs(&dev->rx_submitted);
for (i = 0; i < KVASER_USB_MAX_RX_URBS; i++)
usb_free_coherent(dev->udev, KVASER_USB_RX_BUFFER_SIZE,
dev->rxbuf[i], dev->rxbuf_dma[i]);
for (i = 0; i < dev->nchannels; i++) {
struct kvaser_usb_net_priv *priv = dev->nets[i];
if (priv)
kvaser_usb_unlink_tx_urbs(priv);
}
}
static int kvaser_usb_close(struct net_device *netdev)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
struct kvaser_usb *dev = priv->dev;
int err;
netif_stop_queue(netdev);
err = dev->ops->dev_flush_queue(priv);
if (err)
netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
if (dev->ops->dev_reset_chip) {
err = dev->ops->dev_reset_chip(dev, priv->channel);
if (err)
netdev_warn(netdev, "Cannot reset card, error %d\n",
err);
}
err = dev->ops->dev_stop_chip(priv);
if (err)
netdev_warn(netdev, "Cannot stop device, error %d\n", err);
/* reset tx contexts */
kvaser_usb_unlink_tx_urbs(priv);
priv->can.state = CAN_STATE_STOPPED;
close_candev(priv->netdev);
return 0;
}
static void kvaser_usb_write_bulk_callback(struct urb *urb)
{
struct kvaser_usb_tx_urb_context *context = urb->context;
struct kvaser_usb_net_priv *priv;
struct net_device *netdev;
if (WARN_ON(!context))
return;
priv = context->priv;
netdev = priv->netdev;
kfree(urb->transfer_buffer);
if (!netif_device_present(netdev))
return;
if (urb->status)
netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
}
static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
struct kvaser_usb *dev = priv->dev;
struct net_device_stats *stats = &netdev->stats;
struct kvaser_usb_tx_urb_context *context = NULL;
struct urb *urb;
void *buf;
int cmd_len = 0;
int err, ret = NETDEV_TX_OK;
unsigned int i;
unsigned long flags;
if (can_dropped_invalid_skb(netdev, skb))
return NETDEV_TX_OK;
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
stats->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
for (i = 0; i < dev->max_tx_urbs; i++) {
if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) {
context = &priv->tx_contexts[i];
context->echo_index = i;
can_put_echo_skb(skb, netdev, context->echo_index);
++priv->active_tx_contexts;
if (priv->active_tx_contexts >= (int)dev->max_tx_urbs)
netif_stop_queue(netdev);
break;
}
}
spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
/* This should never happen; it implies a flow control bug */
if (!context) {
netdev_warn(netdev, "cannot find free context\n");
ret = NETDEV_TX_BUSY;
goto freeurb;
}
buf = dev->ops->dev_frame_to_cmd(priv, skb, &context->dlc, &cmd_len,
context->echo_index);
if (!buf) {
stats->tx_dropped++;
dev_kfree_skb(skb);
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
can_free_echo_skb(netdev, context->echo_index);
context->echo_index = dev->max_tx_urbs;
--priv->active_tx_contexts;
netif_wake_queue(netdev);
spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
goto freeurb;
}
context->priv = priv;
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev,
dev->bulk_out->bEndpointAddress),
buf, cmd_len, kvaser_usb_write_bulk_callback,
context);
usb_anchor_urb(urb, &priv->tx_submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (unlikely(err)) {
spin_lock_irqsave(&priv->tx_contexts_lock, flags);
can_free_echo_skb(netdev, context->echo_index);
context->echo_index = dev->max_tx_urbs;
--priv->active_tx_contexts;
netif_wake_queue(netdev);
spin_unlock_irqrestore(&priv->tx_contexts_lock, flags);
usb_unanchor_urb(urb);
kfree(buf);
stats->tx_dropped++;
if (err == -ENODEV)
netif_device_detach(netdev);
else
netdev_warn(netdev, "Failed tx_urb %d\n", err);
goto freeurb;
}
ret = NETDEV_TX_OK;
freeurb:
usb_free_urb(urb);
return ret;
}
static const struct net_device_ops kvaser_usb_netdev_ops = {
.ndo_open = kvaser_usb_open,
.ndo_stop = kvaser_usb_close,
.ndo_start_xmit = kvaser_usb_start_xmit,
.ndo_change_mtu = can_change_mtu,
};
static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
{
int i;
for (i = 0; i < dev->nchannels; i++) {
if (!dev->nets[i])
continue;
unregister_candev(dev->nets[i]->netdev);
}
kvaser_usb_unlink_all_urbs(dev);
for (i = 0; i < dev->nchannels; i++) {
if (!dev->nets[i])
continue;
free_candev(dev->nets[i]->netdev);
}
}
static int kvaser_usb_init_one(struct kvaser_usb *dev,
const struct usb_device_id *id, int channel)
{
struct net_device *netdev;
struct kvaser_usb_net_priv *priv;
int err;
if (dev->ops->dev_reset_chip) {
err = dev->ops->dev_reset_chip(dev, channel);
if (err)
return err;
}
netdev = alloc_candev(sizeof(*priv) +
dev->max_tx_urbs * sizeof(*priv->tx_contexts),
dev->max_tx_urbs);
if (!netdev) {
dev_err(&dev->intf->dev, "Cannot alloc candev\n");
return -ENOMEM;
}
priv = netdev_priv(netdev);
init_usb_anchor(&priv->tx_submitted);
init_completion(&priv->start_comp);
init_completion(&priv->stop_comp);
priv->can.ctrlmode_supported = 0;
priv->dev = dev;
priv->netdev = netdev;
priv->channel = channel;
spin_lock_init(&priv->tx_contexts_lock);
kvaser_usb_reset_tx_urb_contexts(priv);
priv->can.state = CAN_STATE_STOPPED;
priv->can.clock.freq = dev->cfg->clock.freq;
priv->can.bittiming_const = dev->cfg->bittiming_const;
priv->can.do_set_bittiming = dev->ops->dev_set_bittiming;
priv->can.do_set_mode = dev->ops->dev_set_mode;
if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
(priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
priv->can.do_set_data_bittiming =
dev->ops->dev_set_data_bittiming;
}
netdev->flags |= IFF_ECHO;
netdev->netdev_ops = &kvaser_usb_netdev_ops;
SET_NETDEV_DEV(netdev, &dev->intf->dev);
netdev->dev_id = channel;
dev->nets[channel] = priv;
err = register_candev(netdev);
if (err) {
dev_err(&dev->intf->dev, "Failed to register CAN device\n");
free_candev(netdev);
dev->nets[channel] = NULL;
return err;
}
netdev_dbg(netdev, "device registered\n");
return 0;
}
static int kvaser_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct kvaser_usb *dev;
int err;
int i;
dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
if (kvaser_is_leaf(id)) {
dev->card_data.leaf.family = KVASER_LEAF;
dev->ops = &kvaser_usb_leaf_dev_ops;
} else if (kvaser_is_usbcan(id)) {
dev->card_data.leaf.family = KVASER_USBCAN;
dev->ops = &kvaser_usb_leaf_dev_ops;
} else if (kvaser_is_hydra(id)) {
dev->ops = &kvaser_usb_hydra_dev_ops;
} else {
dev_err(&intf->dev,
"Product ID (%d) is not a supported Kvaser USB device\n",
id->idProduct);
return -ENODEV;
}
dev->intf = intf;
err = dev->ops->dev_setup_endpoints(dev);
if (err) {
dev_err(&intf->dev, "Cannot get usb endpoint(s)");
return err;
}
dev->udev = interface_to_usbdev(intf);
init_usb_anchor(&dev->rx_submitted);
usb_set_intfdata(intf, dev);
dev->card_data.ctrlmode_supported = 0;
dev->card_data.capabilities = 0;
err = dev->ops->dev_init_card(dev);
if (err) {
dev_err(&intf->dev,
"Failed to initialize card, error %d\n", err);
return err;
}
err = dev->ops->dev_get_software_info(dev);
if (err) {
dev_err(&intf->dev,
"Cannot get software info, error %d\n", err);
return err;
}
if (dev->ops->dev_get_software_details) {
err = dev->ops->dev_get_software_details(dev);
if (err) {
dev_err(&intf->dev,
"Cannot get software details, error %d\n", err);
return err;
}
}
if (WARN_ON(!dev->cfg))
return -ENODEV;
dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
((dev->fw_version >> 24) & 0xff),
((dev->fw_version >> 16) & 0xff),
(dev->fw_version & 0xffff));
dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
err = dev->ops->dev_get_card_info(dev);
if (err) {
dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
return err;
}
if (dev->ops->dev_get_capabilities) {
err = dev->ops->dev_get_capabilities(dev);
if (err) {
dev_err(&intf->dev,
"Cannot get capabilities, error %d\n", err);
kvaser_usb_remove_interfaces(dev);
return err;
}
}
for (i = 0; i < dev->nchannels; i++) {
err = kvaser_usb_init_one(dev, id, i);
if (err) {
kvaser_usb_remove_interfaces(dev);
return err;
}
}
return 0;
}
static void kvaser_usb_disconnect(struct usb_interface *intf)
{
struct kvaser_usb *dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
if (!dev)
return;
kvaser_usb_remove_interfaces(dev);
}
static struct usb_driver kvaser_usb_driver = {
.name = "kvaser_usb",
.probe = kvaser_usb_probe,
.disconnect = kvaser_usb_disconnect,
.id_table = kvaser_usb_table,
};
module_usb_driver(kvaser_usb_driver);
MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
MODULE_AUTHOR("Kvaser AB <support@kvaser.com>");
MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -423,6 +423,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
new_state = CAN_STATE_ERROR_WARNING;
break;
}
/* else: fall through */
case CAN_STATE_ERROR_WARNING:
if (n & PCAN_USB_ERROR_BUS_HEAVY) {

View File

@@ -353,6 +353,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
default:
netdev_warn(netdev, "tx urb submitting failed err=%d\n",
err);
/* fall through */
case -ENOENT:
/* cable unplugged */
stats->tx_dropped++;

View File

@@ -141,8 +141,10 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, u8 id, ...)
switch (id) {
case PCAN_USBPRO_TXMSG8:
i += 4;
/* fall through */
case PCAN_USBPRO_TXMSG4:
i += 4;
/* fall through */
case PCAN_USBPRO_TXMSG0:
*pc++ = va_arg(ap, int);
*pc++ = va_arg(ap, int);

1613
drivers/net/can/usb/ucan.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
*
* Copyright (C) 2012 - 2014 Xilinx, Inc.
* Copyright (C) 2009 PetaLogix. All rights reserved.
* Copyright (C) 2017 Sandvik Mining and Construction Oy
* Copyright (C) 2017 - 2018 Sandvik Mining and Construction Oy
*
* Description:
* This driver is developed for Axi CAN IP and for Zynq CANPS Controller.
@@ -51,16 +51,34 @@ enum xcan_reg {
XCAN_ISR_OFFSET = 0x1C, /* Interrupt status */
XCAN_IER_OFFSET = 0x20, /* Interrupt enable */
XCAN_ICR_OFFSET = 0x24, /* Interrupt clear */
XCAN_TXFIFO_ID_OFFSET = 0x30,/* TX FIFO ID */
XCAN_TXFIFO_DLC_OFFSET = 0x34, /* TX FIFO DLC */
XCAN_TXFIFO_DW1_OFFSET = 0x38, /* TX FIFO Data Word 1 */
XCAN_TXFIFO_DW2_OFFSET = 0x3C, /* TX FIFO Data Word 2 */
XCAN_RXFIFO_ID_OFFSET = 0x50, /* RX FIFO ID */
XCAN_RXFIFO_DLC_OFFSET = 0x54, /* RX FIFO DLC */
XCAN_RXFIFO_DW1_OFFSET = 0x58, /* RX FIFO Data Word 1 */
XCAN_RXFIFO_DW2_OFFSET = 0x5C, /* RX FIFO Data Word 2 */
/* not on CAN FD cores */
XCAN_TXFIFO_OFFSET = 0x30, /* TX FIFO base */
XCAN_RXFIFO_OFFSET = 0x50, /* RX FIFO base */
XCAN_AFR_OFFSET = 0x60, /* Acceptance Filter */
/* only on CAN FD cores */
XCAN_TRR_OFFSET = 0x0090, /* TX Buffer Ready Request */
XCAN_AFR_EXT_OFFSET = 0x00E0, /* Acceptance Filter */
XCAN_FSR_OFFSET = 0x00E8, /* RX FIFO Status */
XCAN_TXMSG_BASE_OFFSET = 0x0100, /* TX Message Space */
XCAN_RXMSG_BASE_OFFSET = 0x1100, /* RX Message Space */
};
#define XCAN_FRAME_ID_OFFSET(frame_base) ((frame_base) + 0x00)
#define XCAN_FRAME_DLC_OFFSET(frame_base) ((frame_base) + 0x04)
#define XCAN_FRAME_DW1_OFFSET(frame_base) ((frame_base) + 0x08)
#define XCAN_FRAME_DW2_OFFSET(frame_base) ((frame_base) + 0x0C)
#define XCAN_CANFD_FRAME_SIZE 0x48
#define XCAN_TXMSG_FRAME_OFFSET(n) (XCAN_TXMSG_BASE_OFFSET + \
XCAN_CANFD_FRAME_SIZE * (n))
#define XCAN_RXMSG_FRAME_OFFSET(n) (XCAN_RXMSG_BASE_OFFSET + \
XCAN_CANFD_FRAME_SIZE * (n))
/* the single TX mailbox used by this driver on CAN FD HW */
#define XCAN_TX_MAILBOX_IDX 0
/* CAN register bit masks - XCAN_<REG>_<BIT>_MASK */
#define XCAN_SRR_CEN_MASK 0x00000002 /* CAN enable */
#define XCAN_SRR_RESET_MASK 0x00000001 /* Soft Reset the CAN core */
@@ -70,6 +88,9 @@ enum xcan_reg {
#define XCAN_BTR_SJW_MASK 0x00000180 /* Synchronous jump width */
#define XCAN_BTR_TS2_MASK 0x00000070 /* Time segment 2 */
#define XCAN_BTR_TS1_MASK 0x0000000F /* Time segment 1 */
#define XCAN_BTR_SJW_MASK_CANFD 0x000F0000 /* Synchronous jump width */
#define XCAN_BTR_TS2_MASK_CANFD 0x00000F00 /* Time segment 2 */
#define XCAN_BTR_TS1_MASK_CANFD 0x0000003F /* Time segment 1 */
#define XCAN_ECR_REC_MASK 0x0000FF00 /* Receive error counter */
#define XCAN_ECR_TEC_MASK 0x000000FF /* Transmit error counter */
#define XCAN_ESR_ACKER_MASK 0x00000010 /* ACK error */
@@ -83,6 +104,7 @@ enum xcan_reg {
#define XCAN_SR_NORMAL_MASK 0x00000008 /* Normal mode */
#define XCAN_SR_LBACK_MASK 0x00000002 /* Loop back mode */
#define XCAN_SR_CONFIG_MASK 0x00000001 /* Configuration mode */
#define XCAN_IXR_RXMNF_MASK 0x00020000 /* RX match not finished */
#define XCAN_IXR_TXFEMP_MASK 0x00004000 /* TX FIFO Empty */
#define XCAN_IXR_WKUP_MASK 0x00000800 /* Wake up interrupt */
#define XCAN_IXR_SLP_MASK 0x00000400 /* Sleep interrupt */
@@ -100,15 +122,15 @@ enum xcan_reg {
#define XCAN_IDR_ID2_MASK 0x0007FFFE /* Extended message ident */
#define XCAN_IDR_RTR_MASK 0x00000001 /* Remote TX request */
#define XCAN_DLCR_DLC_MASK 0xF0000000 /* Data length code */
#define XCAN_INTR_ALL (XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |\
XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | \
XCAN_IXR_RXNEMP_MASK | XCAN_IXR_ERROR_MASK | \
XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ARBLST_MASK)
#define XCAN_FSR_FL_MASK 0x00003F00 /* RX Fill Level */
#define XCAN_FSR_IRI_MASK 0x00000080 /* RX Increment Read Index */
#define XCAN_FSR_RI_MASK 0x0000001F /* RX Read Index */
/* CAN register bit shift - XCAN_<REG>_<BIT>_SHIFT */
#define XCAN_BTR_SJW_SHIFT 7 /* Synchronous jump width */
#define XCAN_BTR_TS2_SHIFT 4 /* Time segment 2 */
#define XCAN_BTR_SJW_SHIFT_CANFD 16 /* Synchronous jump width */
#define XCAN_BTR_TS2_SHIFT_CANFD 8 /* Time segment 2 */
#define XCAN_IDR_ID1_SHIFT 21 /* Standard Messg Identifier */
#define XCAN_IDR_ID2_SHIFT 1 /* Extended Message Identifier */
#define XCAN_DLCR_DLC_SHIFT 28 /* Data length code */
@@ -118,6 +140,27 @@ enum xcan_reg {
#define XCAN_FRAME_MAX_DATA_LEN 8
#define XCAN_TIMEOUT (1 * HZ)
/* TX-FIFO-empty interrupt available */
#define XCAN_FLAG_TXFEMP 0x0001
/* RX Match Not Finished interrupt available */
#define XCAN_FLAG_RXMNF 0x0002
/* Extended acceptance filters with control at 0xE0 */
#define XCAN_FLAG_EXT_FILTERS 0x0004
/* TX mailboxes instead of TX FIFO */
#define XCAN_FLAG_TX_MAILBOXES 0x0008
/* RX FIFO with each buffer in separate registers at 0x1100
* instead of the regular FIFO at 0x50
*/
#define XCAN_FLAG_RX_FIFO_MULTI 0x0010
struct xcan_devtype_data {
unsigned int flags;
const struct can_bittiming_const *bittiming_const;
const char *bus_clk_name;
unsigned int btr_ts2_shift;
unsigned int btr_sjw_shift;
};
/**
* struct xcan_priv - This definition define CAN driver instance
* @can: CAN private data structure.
@@ -133,6 +176,7 @@ enum xcan_reg {
* @irq_flags: For request_irq()
* @bus_clk: Pointer to struct clk
* @can_clk: Pointer to struct clk
* @devtype: Device type specific constants
*/
struct xcan_priv {
struct can_priv can;
@@ -149,6 +193,7 @@ struct xcan_priv {
unsigned long irq_flags;
struct clk *bus_clk;
struct clk *can_clk;
struct xcan_devtype_data devtype;
};
/* CAN Bittiming constants as per Xilinx CAN specs */
@@ -164,9 +209,16 @@ static const struct can_bittiming_const xcan_bittiming_const = {
.brp_inc = 1,
};
#define XCAN_CAP_WATERMARK 0x0001
struct xcan_devtype_data {
unsigned int caps;
static const struct can_bittiming_const xcan_bittiming_const_canfd = {
.name = DRIVER_NAME,
.tseg1_min = 1,
.tseg1_max = 64,
.tseg2_min = 1,
.tseg2_max = 16,
.sjw_max = 16,
.brp_min = 1,
.brp_max = 256,
.brp_inc = 1,
};
/**
@@ -223,6 +275,23 @@ static u32 xcan_read_reg_be(const struct xcan_priv *priv, enum xcan_reg reg)
return ioread32be(priv->reg_base + reg);
}
/**
* xcan_rx_int_mask - Get the mask for the receive interrupt
* @priv: Driver private data structure
*
* Return: The receive interrupt mask used by the driver on this HW
*/
static u32 xcan_rx_int_mask(const struct xcan_priv *priv)
{
/* RXNEMP is better suited for our use case as it cannot be cleared
* while the FIFO is non-empty, but CAN FD HW does not have it
*/
if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI)
return XCAN_IXR_RXOK_MASK;
else
return XCAN_IXR_RXNEMP_MASK;
}
/**
* set_reset_mode - Resets the CAN device mode
* @ndev: Pointer to net_device structure
@@ -287,10 +356,10 @@ static int xcan_set_bittiming(struct net_device *ndev)
btr1 = (bt->prop_seg + bt->phase_seg1 - 1);
/* Setting Time Segment 2 in BTR Register */
btr1 |= (bt->phase_seg2 - 1) << XCAN_BTR_TS2_SHIFT;
btr1 |= (bt->phase_seg2 - 1) << priv->devtype.btr_ts2_shift;
/* Setting Synchronous jump width in BTR Register */
btr1 |= (bt->sjw - 1) << XCAN_BTR_SJW_SHIFT;
btr1 |= (bt->sjw - 1) << priv->devtype.btr_sjw_shift;
priv->write_reg(priv, XCAN_BRPR_OFFSET, btr0);
priv->write_reg(priv, XCAN_BTR_OFFSET, btr1);
@@ -318,6 +387,7 @@ static int xcan_chip_start(struct net_device *ndev)
u32 reg_msr, reg_sr_mask;
int err;
unsigned long timeout;
u32 ier;
/* Check if it is in reset mode */
err = set_reset_mode(ndev);
@@ -329,7 +399,15 @@ static int xcan_chip_start(struct net_device *ndev)
return err;
/* Enable interrupts */
priv->write_reg(priv, XCAN_IER_OFFSET, XCAN_INTR_ALL);
ier = XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |
XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK |
XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
XCAN_IXR_ARBLST_MASK | xcan_rx_int_mask(priv);
if (priv->devtype.flags & XCAN_FLAG_RXMNF)
ier |= XCAN_IXR_RXMNF_MASK;
priv->write_reg(priv, XCAN_IER_OFFSET, ier);
/* Check whether it is loopback mode or normal mode */
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
@@ -340,6 +418,12 @@ static int xcan_chip_start(struct net_device *ndev)
reg_sr_mask = XCAN_SR_NORMAL_MASK;
}
/* enable the first extended filter, if any, as cores with extended
* filtering default to non-receipt if all filters are disabled
*/
if (priv->devtype.flags & XCAN_FLAG_EXT_FILTERS)
priv->write_reg(priv, XCAN_AFR_EXT_OFFSET, 0x00000001);
priv->write_reg(priv, XCAN_MSR_OFFSET, reg_msr);
priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_CEN_MASK);
@@ -390,34 +474,15 @@ static int xcan_do_set_mode(struct net_device *ndev, enum can_mode mode)
}
/**
* xcan_start_xmit - Starts the transmission
* @skb: sk_buff pointer that contains data to be Txed
* @ndev: Pointer to net_device structure
*
* This function is invoked from upper layers to initiate transmission. This
* function uses the next available free txbuff and populates their fields to
* start the transmission.
*
* Return: 0 on success and failure value on error
* xcan_write_frame - Write a frame to HW
* @skb: sk_buff pointer that contains data to be Txed
* @frame_offset: Register offset to write the frame to
*/
static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
static void xcan_write_frame(struct xcan_priv *priv, struct sk_buff *skb,
int frame_offset)
{
struct xcan_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
struct can_frame *cf = (struct can_frame *)skb->data;
u32 id, dlc, data[2] = {0, 0};
unsigned long flags;
if (can_dropped_invalid_skb(ndev, skb))
return NETDEV_TX_OK;
/* Check if the TX buffer is full */
if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) &
XCAN_SR_TXFLL_MASK)) {
netif_stop_queue(ndev);
netdev_err(ndev, "BUG!, TX FIFO full when queue awake!\n");
return NETDEV_TX_BUSY;
}
struct can_frame *cf = (struct can_frame *)skb->data;
/* Watch carefully on the bit sequence */
if (cf->can_id & CAN_EFF_FLAG) {
@@ -453,24 +518,44 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (cf->can_dlc > 4)
data[1] = be32_to_cpup((__be32 *)(cf->data + 4));
priv->write_reg(priv, XCAN_FRAME_ID_OFFSET(frame_offset), id);
/* If the CAN frame is RTR frame this write triggers transmission
* (not on CAN FD)
*/
priv->write_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_offset), dlc);
if (!(cf->can_id & CAN_RTR_FLAG)) {
priv->write_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_offset),
data[0]);
/* If the CAN frame is Standard/Extended frame this
* write triggers transmission (not on CAN FD)
*/
priv->write_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_offset),
data[1]);
}
}
/**
* xcan_start_xmit_fifo - Starts the transmission (FIFO mode)
*
* Return: 0 on success, -ENOSPC if FIFO is full.
*/
static int xcan_start_xmit_fifo(struct sk_buff *skb, struct net_device *ndev)
{
struct xcan_priv *priv = netdev_priv(ndev);
unsigned long flags;
/* Check if the TX buffer is full */
if (unlikely(priv->read_reg(priv, XCAN_SR_OFFSET) &
XCAN_SR_TXFLL_MASK))
return -ENOSPC;
can_put_echo_skb(skb, ndev, priv->tx_head % priv->tx_max);
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_head++;
/* Write the Frame to Xilinx CAN TX FIFO */
priv->write_reg(priv, XCAN_TXFIFO_ID_OFFSET, id);
/* If the CAN frame is RTR frame this write triggers tranmission */
priv->write_reg(priv, XCAN_TXFIFO_DLC_OFFSET, dlc);
if (!(cf->can_id & CAN_RTR_FLAG)) {
priv->write_reg(priv, XCAN_TXFIFO_DW1_OFFSET, data[0]);
/* If the CAN frame is Standard/Extended frame this
* write triggers tranmission
*/
priv->write_reg(priv, XCAN_TXFIFO_DW2_OFFSET, data[1]);
stats->tx_bytes += cf->can_dlc;
}
xcan_write_frame(priv, skb, XCAN_TXFIFO_OFFSET);
/* Clear TX-FIFO-empty interrupt for xcan_tx_interrupt() */
if (priv->tx_max > 1)
@@ -482,6 +567,70 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&priv->tx_lock, flags);
return 0;
}
/**
* xcan_start_xmit_mailbox - Starts the transmission (mailbox mode)
*
* Return: 0 on success, -ENOSPC if there is no space
*/
static int xcan_start_xmit_mailbox(struct sk_buff *skb, struct net_device *ndev)
{
struct xcan_priv *priv = netdev_priv(ndev);
unsigned long flags;
if (unlikely(priv->read_reg(priv, XCAN_TRR_OFFSET) &
BIT(XCAN_TX_MAILBOX_IDX)))
return -ENOSPC;
can_put_echo_skb(skb, ndev, 0);
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_head++;
xcan_write_frame(priv, skb,
XCAN_TXMSG_FRAME_OFFSET(XCAN_TX_MAILBOX_IDX));
/* Mark buffer as ready for transmit */
priv->write_reg(priv, XCAN_TRR_OFFSET, BIT(XCAN_TX_MAILBOX_IDX));
netif_stop_queue(ndev);
spin_unlock_irqrestore(&priv->tx_lock, flags);
return 0;
}
/**
* xcan_start_xmit - Starts the transmission
* @skb: sk_buff pointer that contains data to be Txed
* @ndev: Pointer to net_device structure
*
* This function is invoked from upper layers to initiate transmission.
*
* Return: NETDEV_TX_OK on success and NETDEV_TX_BUSY when the tx queue is full
*/
static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct xcan_priv *priv = netdev_priv(ndev);
int ret;
if (can_dropped_invalid_skb(ndev, skb))
return NETDEV_TX_OK;
if (priv->devtype.flags & XCAN_FLAG_TX_MAILBOXES)
ret = xcan_start_xmit_mailbox(skb, ndev);
else
ret = xcan_start_xmit_fifo(skb, ndev);
if (ret < 0) {
netdev_err(ndev, "BUG!, TX full when queue awake!\n");
netif_stop_queue(ndev);
return NETDEV_TX_BUSY;
}
return NETDEV_TX_OK;
}
@@ -489,13 +638,14 @@ static int xcan_start_xmit(struct sk_buff *skb, struct net_device *ndev)
* xcan_rx - Is called from CAN isr to complete the received
* frame processing
* @ndev: Pointer to net_device structure
* @frame_base: Register offset to the frame to be read
*
* This function is invoked from the CAN isr(poll) to process the Rx frames. It
* does minimal processing and invokes "netif_receive_skb" to complete further
* processing.
* Return: 1 on success and 0 on failure.
*/
static int xcan_rx(struct net_device *ndev)
static int xcan_rx(struct net_device *ndev, int frame_base)
{
struct xcan_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats;
@@ -510,9 +660,9 @@ static int xcan_rx(struct net_device *ndev)
}
/* Read a frame from Xilinx zynq CANPS */
id_xcan = priv->read_reg(priv, XCAN_RXFIFO_ID_OFFSET);
dlc = priv->read_reg(priv, XCAN_RXFIFO_DLC_OFFSET) >>
XCAN_DLCR_DLC_SHIFT;
id_xcan = priv->read_reg(priv, XCAN_FRAME_ID_OFFSET(frame_base));
dlc = priv->read_reg(priv, XCAN_FRAME_DLC_OFFSET(frame_base)) >>
XCAN_DLCR_DLC_SHIFT;
/* Change Xilinx CAN data length format to socketCAN data format */
cf->can_dlc = get_can_dlc(dlc);
@@ -535,8 +685,8 @@ static int xcan_rx(struct net_device *ndev)
}
/* DW1/DW2 must always be read to remove message from RXFIFO */
data[0] = priv->read_reg(priv, XCAN_RXFIFO_DW1_OFFSET);
data[1] = priv->read_reg(priv, XCAN_RXFIFO_DW2_OFFSET);
data[0] = priv->read_reg(priv, XCAN_FRAME_DW1_OFFSET(frame_base));
data[1] = priv->read_reg(priv, XCAN_FRAME_DW2_OFFSET(frame_base));
if (!(cf->can_id & CAN_RTR_FLAG)) {
/* Change Xilinx CAN data format to socketCAN data format */
@@ -594,39 +744,19 @@ static void xcan_set_error_state(struct net_device *ndev,
u32 ecr = priv->read_reg(priv, XCAN_ECR_OFFSET);
u32 txerr = ecr & XCAN_ECR_TEC_MASK;
u32 rxerr = (ecr & XCAN_ECR_REC_MASK) >> XCAN_ESR_REC_SHIFT;
enum can_state tx_state = txerr >= rxerr ? new_state : 0;
enum can_state rx_state = txerr <= rxerr ? new_state : 0;
priv->can.state = new_state;
/* non-ERROR states are handled elsewhere */
if (WARN_ON(new_state > CAN_STATE_ERROR_PASSIVE))
return;
can_change_state(ndev, cf, tx_state, rx_state);
if (cf) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[6] = txerr;
cf->data[7] = rxerr;
}
switch (new_state) {
case CAN_STATE_ERROR_PASSIVE:
priv->can.can_stats.error_passive++;
if (cf)
cf->data[1] = (rxerr > 127) ?
CAN_ERR_CRTL_RX_PASSIVE :
CAN_ERR_CRTL_TX_PASSIVE;
break;
case CAN_STATE_ERROR_WARNING:
priv->can.can_stats.error_warning++;
if (cf)
cf->data[1] |= (txerr > rxerr) ?
CAN_ERR_CRTL_TX_WARNING :
CAN_ERR_CRTL_RX_WARNING;
break;
case CAN_STATE_ERROR_ACTIVE:
if (cf)
cf->data[1] |= CAN_ERR_CRTL_ACTIVE;
break;
default:
/* non-ERROR states are handled elsewhere */
WARN_ON(1);
break;
}
}
/**
@@ -703,7 +833,8 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
} else {
enum can_state new_state = xcan_current_error_state(ndev);
xcan_set_error_state(ndev, new_state, skb ? cf : NULL);
if (new_state != priv->can.state)
xcan_set_error_state(ndev, new_state, skb ? cf : NULL);
}
/* Check for Arbitration lost interrupt */
@@ -725,6 +856,17 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
}
}
/* Check for RX Match Not Finished interrupt */
if (isr & XCAN_IXR_RXMNF_MASK) {
stats->rx_dropped++;
stats->rx_errors++;
netdev_err(ndev, "RX match not finished, frame discarded\n");
if (skb) {
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] |= CAN_ERR_CRTL_UNSPEC;
}
}
/* Check for error interrupt */
if (isr & XCAN_IXR_ERROR_MASK) {
if (skb)
@@ -808,6 +950,44 @@ static void xcan_state_interrupt(struct net_device *ndev, u32 isr)
priv->can.state = CAN_STATE_ERROR_ACTIVE;
}
/**
* xcan_rx_fifo_get_next_frame - Get register offset of next RX frame
*
* Return: Register offset of the next frame in RX FIFO.
*/
static int xcan_rx_fifo_get_next_frame(struct xcan_priv *priv)
{
int offset;
if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI) {
u32 fsr;
/* clear RXOK before the is-empty check so that any newly
* received frame will reassert it without a race
*/
priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXOK_MASK);
fsr = priv->read_reg(priv, XCAN_FSR_OFFSET);
/* check if RX FIFO is empty */
if (!(fsr & XCAN_FSR_FL_MASK))
return -ENOENT;
offset = XCAN_RXMSG_FRAME_OFFSET(fsr & XCAN_FSR_RI_MASK);
} else {
/* check if RX FIFO is empty */
if (!(priv->read_reg(priv, XCAN_ISR_OFFSET) &
XCAN_IXR_RXNEMP_MASK))
return -ENOENT;
/* frames are read from a static offset */
offset = XCAN_RXFIFO_OFFSET;
}
return offset;
}
/**
* xcan_rx_poll - Poll routine for rx packets (NAPI)
* @napi: napi structure pointer
@@ -822,14 +1002,24 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota)
{
struct net_device *ndev = napi->dev;
struct xcan_priv *priv = netdev_priv(ndev);
u32 isr, ier;
u32 ier;
int work_done = 0;
int frame_offset;
isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
while ((isr & XCAN_IXR_RXNEMP_MASK) && (work_done < quota)) {
work_done += xcan_rx(ndev);
priv->write_reg(priv, XCAN_ICR_OFFSET, XCAN_IXR_RXNEMP_MASK);
isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
while ((frame_offset = xcan_rx_fifo_get_next_frame(priv)) >= 0 &&
(work_done < quota)) {
work_done += xcan_rx(ndev, frame_offset);
if (priv->devtype.flags & XCAN_FLAG_RX_FIFO_MULTI)
/* increment read index */
priv->write_reg(priv, XCAN_FSR_OFFSET,
XCAN_FSR_IRI_MASK);
else
/* clear rx-not-empty (will actually clear only if
* empty)
*/
priv->write_reg(priv, XCAN_ICR_OFFSET,
XCAN_IXR_RXNEMP_MASK);
}
if (work_done) {
@@ -840,7 +1030,7 @@ static int xcan_rx_poll(struct napi_struct *napi, int quota)
if (work_done < quota) {
napi_complete_done(napi, work_done);
ier = priv->read_reg(priv, XCAN_IER_OFFSET);
ier |= XCAN_IXR_RXNEMP_MASK;
ier |= xcan_rx_int_mask(priv);
priv->write_reg(priv, XCAN_IER_OFFSET, ier);
}
return work_done;
@@ -908,8 +1098,8 @@ static void xcan_tx_interrupt(struct net_device *ndev, u32 isr)
}
while (frames_sent--) {
can_get_echo_skb(ndev, priv->tx_tail %
priv->tx_max);
stats->tx_bytes += can_get_echo_skb(ndev, priv->tx_tail %
priv->tx_max);
priv->tx_tail++;
stats->tx_packets++;
}
@@ -939,6 +1129,7 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id)
struct xcan_priv *priv = netdev_priv(ndev);
u32 isr, ier;
u32 isr_errors;
u32 rx_int_mask = xcan_rx_int_mask(priv);
/* Get the interrupt status from Xilinx CAN */
isr = priv->read_reg(priv, XCAN_ISR_OFFSET);
@@ -958,16 +1149,17 @@ static irqreturn_t xcan_interrupt(int irq, void *dev_id)
/* Check for the type of error interrupt and Processing it */
isr_errors = isr & (XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK);
XCAN_IXR_BSOFF_MASK | XCAN_IXR_ARBLST_MASK |
XCAN_IXR_RXMNF_MASK);
if (isr_errors) {
priv->write_reg(priv, XCAN_ICR_OFFSET, isr_errors);
xcan_err_interrupt(ndev, isr);
}
/* Check for the type of receive interrupt and Processing it */
if (isr & XCAN_IXR_RXNEMP_MASK) {
if (isr & rx_int_mask) {
ier = priv->read_reg(priv, XCAN_IER_OFFSET);
ier &= ~XCAN_IXR_RXNEMP_MASK;
ier &= ~rx_int_mask;
priv->write_reg(priv, XCAN_IER_OFFSET, ier);
napi_schedule(&priv->napi);
}
@@ -1214,13 +1406,35 @@ static const struct dev_pm_ops xcan_dev_pm_ops = {
};
static const struct xcan_devtype_data xcan_zynq_data = {
.caps = XCAN_CAP_WATERMARK,
.bittiming_const = &xcan_bittiming_const,
.btr_ts2_shift = XCAN_BTR_TS2_SHIFT,
.btr_sjw_shift = XCAN_BTR_SJW_SHIFT,
.bus_clk_name = "pclk",
};
static const struct xcan_devtype_data xcan_axi_data = {
.bittiming_const = &xcan_bittiming_const,
.btr_ts2_shift = XCAN_BTR_TS2_SHIFT,
.btr_sjw_shift = XCAN_BTR_SJW_SHIFT,
.bus_clk_name = "s_axi_aclk",
};
static const struct xcan_devtype_data xcan_canfd_data = {
.flags = XCAN_FLAG_EXT_FILTERS |
XCAN_FLAG_RXMNF |
XCAN_FLAG_TX_MAILBOXES |
XCAN_FLAG_RX_FIFO_MULTI,
.bittiming_const = &xcan_bittiming_const,
.btr_ts2_shift = XCAN_BTR_TS2_SHIFT_CANFD,
.btr_sjw_shift = XCAN_BTR_SJW_SHIFT_CANFD,
.bus_clk_name = "s_axi_aclk",
};
/* Match table for OF platform binding */
static const struct of_device_id xcan_of_match[] = {
{ .compatible = "xlnx,zynq-can-1.0", .data = &xcan_zynq_data },
{ .compatible = "xlnx,axi-can-1.00.a", },
{ .compatible = "xlnx,axi-can-1.00.a", .data = &xcan_axi_data },
{ .compatible = "xlnx,canfd-1.0", .data = &xcan_canfd_data },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, xcan_of_match);
@@ -1240,9 +1454,12 @@ static int xcan_probe(struct platform_device *pdev)
struct net_device *ndev;
struct xcan_priv *priv;
const struct of_device_id *of_id;
int caps = 0;
const struct xcan_devtype_data *devtype = &xcan_axi_data;
void __iomem *addr;
int ret, rx_max, tx_max, tx_fifo_depth;
int ret;
int rx_max, tx_max;
int hw_tx_max, hw_rx_max;
const char *hw_tx_max_property;
/* Get the virtual base address for the device */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1252,25 +1469,33 @@ static int xcan_probe(struct platform_device *pdev)
goto err;
}
ret = of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
&tx_fifo_depth);
if (ret < 0)
goto err;
ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth", &rx_max);
if (ret < 0)
goto err;
of_id = of_match_device(xcan_of_match, &pdev->dev);
if (of_id) {
const struct xcan_devtype_data *devtype_data = of_id->data;
if (of_id && of_id->data)
devtype = of_id->data;
if (devtype_data)
caps = devtype_data->caps;
hw_tx_max_property = devtype->flags & XCAN_FLAG_TX_MAILBOXES ?
"tx-mailbox-count" : "tx-fifo-depth";
ret = of_property_read_u32(pdev->dev.of_node, hw_tx_max_property,
&hw_tx_max);
if (ret < 0) {
dev_err(&pdev->dev, "missing %s property\n",
hw_tx_max_property);
goto err;
}
/* There is no way to directly figure out how many frames have been
* sent when the TXOK interrupt is processed. If watermark programming
ret = of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
&hw_rx_max);
if (ret < 0) {
dev_err(&pdev->dev,
"missing rx-fifo-depth property (mailbox mode is not supported)\n");
goto err;
}
/* With TX FIFO:
*
* There is no way to directly figure out how many frames have been
* sent when the TXOK interrupt is processed. If TXFEMP
* is supported, we can have 2 frames in the FIFO and use TXFEMP
* to determine if 1 or 2 frames have been sent.
* Theoretically we should be able to use TXFWMEMP to determine up
@@ -1279,12 +1504,20 @@ static int xcan_probe(struct platform_device *pdev)
* than 2 frames in FIFO) is set anyway with no TXOK (a frame was
* sent), which is not a sensible state - possibly TXFWMEMP is not
* completely synchronized with the rest of the bits?
*
* With TX mailboxes:
*
* HW sends frames in CAN ID priority order. To preserve FIFO ordering
* we submit frames one at a time.
*/
if (caps & XCAN_CAP_WATERMARK)
tx_max = min(tx_fifo_depth, 2);
if (!(devtype->flags & XCAN_FLAG_TX_MAILBOXES) &&
(devtype->flags & XCAN_FLAG_TXFEMP))
tx_max = min(hw_tx_max, 2);
else
tx_max = 1;
rx_max = hw_rx_max;
/* Create a CAN device instance */
ndev = alloc_candev(sizeof(struct xcan_priv), tx_max);
if (!ndev)
@@ -1292,13 +1525,14 @@ static int xcan_probe(struct platform_device *pdev)
priv = netdev_priv(ndev);
priv->dev = &pdev->dev;
priv->can.bittiming_const = &xcan_bittiming_const;
priv->can.bittiming_const = devtype->bittiming_const;
priv->can.do_set_mode = xcan_do_set_mode;
priv->can.do_get_berr_counter = xcan_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_BERR_REPORTING;
priv->reg_base = addr;
priv->tx_max = tx_max;
priv->devtype = *devtype;
spin_lock_init(&priv->tx_lock);
/* Get IRQ for the device */
@@ -1316,22 +1550,12 @@ static int xcan_probe(struct platform_device *pdev)
ret = PTR_ERR(priv->can_clk);
goto err_free;
}
/* Check for type of CAN device */
if (of_device_is_compatible(pdev->dev.of_node,
"xlnx,zynq-can-1.0")) {
priv->bus_clk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(priv->bus_clk)) {
dev_err(&pdev->dev, "bus clock not found\n");
ret = PTR_ERR(priv->bus_clk);
goto err_free;
}
} else {
priv->bus_clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
if (IS_ERR(priv->bus_clk)) {
dev_err(&pdev->dev, "bus clock not found\n");
ret = PTR_ERR(priv->bus_clk);
goto err_free;
}
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) {
dev_err(&pdev->dev, "bus clock not found\n");
ret = PTR_ERR(priv->bus_clk);
goto err_free;
}
priv->write_reg = xcan_write_reg_le;
@@ -1364,9 +1588,9 @@ static int xcan_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx fifo depth: actual %d, using %d\n",
priv->reg_base, ndev->irq, priv->can.clock.freq,
tx_fifo_depth, priv->tx_max);
netdev_dbg(ndev, "reg_base=0x%p irq=%d clock=%d, tx buffers: actual %d, using %d\n",
priv->reg_base, ndev->irq, priv->can.clock.freq,
hw_tx_max, priv->tx_max);
return 0;