linux-can-next-for-5.18-20220313
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEBsvAIBsPu6mG7thcrX5LkNig010FAmItr80THG1rbEBwZW5n dXRyb25peC5kZQAKCRCtfkuQ2KDTXQpCCACrBZRT0hqiKueoXPDTWkQPWtYHJPgE Ho1/sA89eqtTmlYHRFRX8KA4LQjCnxlvTRQdqzIZHnokvm+ymvODDrUZcjVpUfbQ W16oejtOqs7y87Uk2u16MAhkXf0KZzeO4exdkNGpgR+WrQ/4b7ZTXSf9esZYaope E1AZ/puNxpHynZQgBzdyZ1c/PUiIDSArnFKQ1RIARQhW7O+svgxvypLjBZ6L3IUM O0kXhk5M8m3yb+0ogVi8erzlne4rkjQM5DtM9egfBqRh1mqNK54XbA4SbZdxLytW cTb/RP+Mx4/slJCrsIEj5FmFMCe5YOWlq18uN/TENwKRVzsxGOpzku8V =fhK4 -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-5.18-20220313' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next linux-can-next-for-5.18-20220313 Marc Kleine-Budde says: ==================== pull-request: can-next 2022-03-13 this is a pull request of 13 patches for net-next/master. The 1st patch is by me and fixes the freeing of a skb in the vxcan driver (initially added in this net-next window). The remaining 12 patches are also by me and target the mcp251xfd driver. The first patch fixes a printf modifier (initially added in this net-next window). The remaining patches add ethtool based ring and RX/TX IRQ coalescing support to the driver. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
de29aff976
@ -6,6 +6,8 @@ mcp251xfd-objs :=
|
||||
mcp251xfd-objs += mcp251xfd-chip-fifo.o
|
||||
mcp251xfd-objs += mcp251xfd-core.o
|
||||
mcp251xfd-objs += mcp251xfd-crc16.o
|
||||
mcp251xfd-objs += mcp251xfd-ethtool.o
|
||||
mcp251xfd-objs += mcp251xfd-ram.o
|
||||
mcp251xfd-objs += mcp251xfd-regmap.o
|
||||
mcp251xfd-objs += mcp251xfd-ring.o
|
||||
mcp251xfd-objs += mcp251xfd-rx.o
|
||||
|
@ -1598,6 +1598,7 @@ static int mcp251xfd_open(struct net_device *ndev)
|
||||
goto out_transceiver_disable;
|
||||
|
||||
mcp251xfd_timestamp_init(priv);
|
||||
clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
|
||||
can_rx_offload_enable(&priv->offload);
|
||||
|
||||
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
|
||||
@ -1618,6 +1619,7 @@ static int mcp251xfd_open(struct net_device *ndev)
|
||||
free_irq(spi->irq, priv);
|
||||
out_can_rx_offload_disable:
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
|
||||
mcp251xfd_timestamp_stop(priv);
|
||||
out_transceiver_disable:
|
||||
mcp251xfd_transceiver_disable(priv);
|
||||
@ -1637,6 +1639,8 @@ static int mcp251xfd_stop(struct net_device *ndev)
|
||||
struct mcp251xfd_priv *priv = netdev_priv(ndev);
|
||||
|
||||
netif_stop_queue(ndev);
|
||||
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
|
||||
hrtimer_cancel(&priv->rx_irq_timer);
|
||||
mcp251xfd_chip_interrupts_disable(priv);
|
||||
free_irq(ndev->irq, priv);
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
@ -1871,6 +1875,8 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv)
|
||||
if (err)
|
||||
goto out_chip_sleep;
|
||||
|
||||
mcp251xfd_ethtool_init(priv);
|
||||
|
||||
err = register_candev(ndev);
|
||||
if (err)
|
||||
goto out_chip_sleep;
|
||||
@ -2034,6 +2040,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
|
||||
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING |
|
||||
CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
|
||||
CAN_CTRLMODE_CC_LEN8_DLC;
|
||||
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
|
||||
priv->ndev = ndev;
|
||||
priv->spi = spi;
|
||||
priv->rx_int = rx_int;
|
||||
|
143
drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c
Normal file
143
drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c
Normal file
@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
//
|
||||
// Copyright (c) 2021, 2022 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-ram.h"
|
||||
|
||||
static void
|
||||
mcp251xfd_ring_get_ringparam(struct net_device *ndev,
|
||||
struct ethtool_ringparam *ring,
|
||||
struct kernel_ethtool_ringparam *kernel_ring,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct mcp251xfd_priv *priv = netdev_priv(ndev);
|
||||
const bool fd_mode = mcp251xfd_is_fd_mode(priv);
|
||||
struct can_ram_layout layout;
|
||||
|
||||
can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode);
|
||||
ring->rx_max_pending = layout.max_rx;
|
||||
ring->tx_max_pending = layout.max_tx;
|
||||
|
||||
ring->rx_pending = priv->rx_obj_num;
|
||||
ring->tx_pending = priv->tx->obj_num;
|
||||
}
|
||||
|
||||
static int
|
||||
mcp251xfd_ring_set_ringparam(struct net_device *ndev,
|
||||
struct ethtool_ringparam *ring,
|
||||
struct kernel_ethtool_ringparam *kernel_ring,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mcp251xfd_priv *priv = netdev_priv(ndev);
|
||||
const bool fd_mode = mcp251xfd_is_fd_mode(priv);
|
||||
struct can_ram_layout layout;
|
||||
|
||||
can_ram_get_layout(&layout, &mcp251xfd_ram_config, ring, NULL, fd_mode);
|
||||
if ((layout.cur_rx != priv->rx_obj_num ||
|
||||
layout.cur_tx != priv->tx->obj_num) &&
|
||||
netif_running(ndev))
|
||||
return -EBUSY;
|
||||
|
||||
priv->rx_obj_num = layout.cur_rx;
|
||||
priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
|
||||
priv->tx->obj_num = layout.cur_tx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp251xfd_ring_get_coalesce(struct net_device *ndev,
|
||||
struct ethtool_coalesce *ec,
|
||||
struct kernel_ethtool_coalesce *kec,
|
||||
struct netlink_ext_ack *ext_ack)
|
||||
{
|
||||
struct mcp251xfd_priv *priv = netdev_priv(ndev);
|
||||
u32 rx_max_frames, tx_max_frames;
|
||||
|
||||
/* The ethtool doc says:
|
||||
* To disable coalescing, set usecs = 0 and max_frames = 1.
|
||||
*/
|
||||
if (priv->rx_obj_num_coalesce_irq == 0)
|
||||
rx_max_frames = 1;
|
||||
else
|
||||
rx_max_frames = priv->rx_obj_num_coalesce_irq;
|
||||
|
||||
ec->rx_max_coalesced_frames_irq = rx_max_frames;
|
||||
ec->rx_coalesce_usecs_irq = priv->rx_coalesce_usecs_irq;
|
||||
|
||||
if (priv->tx_obj_num_coalesce_irq == 0)
|
||||
tx_max_frames = 1;
|
||||
else
|
||||
tx_max_frames = priv->tx_obj_num_coalesce_irq;
|
||||
|
||||
ec->tx_max_coalesced_frames_irq = tx_max_frames;
|
||||
ec->tx_coalesce_usecs_irq = priv->tx_coalesce_usecs_irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp251xfd_ring_set_coalesce(struct net_device *ndev,
|
||||
struct ethtool_coalesce *ec,
|
||||
struct kernel_ethtool_coalesce *kec,
|
||||
struct netlink_ext_ack *ext_ack)
|
||||
{
|
||||
struct mcp251xfd_priv *priv = netdev_priv(ndev);
|
||||
const bool fd_mode = mcp251xfd_is_fd_mode(priv);
|
||||
const struct ethtool_ringparam ring = {
|
||||
.rx_pending = priv->rx_obj_num,
|
||||
.tx_pending = priv->tx->obj_num,
|
||||
};
|
||||
struct can_ram_layout layout;
|
||||
|
||||
can_ram_get_layout(&layout, &mcp251xfd_ram_config, &ring, ec, fd_mode);
|
||||
|
||||
if ((layout.rx_coalesce != priv->rx_obj_num_coalesce_irq ||
|
||||
ec->rx_coalesce_usecs_irq != priv->rx_coalesce_usecs_irq ||
|
||||
layout.tx_coalesce != priv->tx_obj_num_coalesce_irq ||
|
||||
ec->tx_coalesce_usecs_irq != priv->tx_coalesce_usecs_irq) &&
|
||||
netif_running(ndev))
|
||||
return -EBUSY;
|
||||
|
||||
priv->rx_obj_num = layout.cur_rx;
|
||||
priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
|
||||
priv->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq;
|
||||
|
||||
priv->tx->obj_num = layout.cur_tx;
|
||||
priv->tx_obj_num_coalesce_irq = layout.tx_coalesce;
|
||||
priv->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops mcp251xfd_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ |
|
||||
ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ |
|
||||
ETHTOOL_COALESCE_TX_USECS_IRQ |
|
||||
ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
|
||||
.get_ringparam = mcp251xfd_ring_get_ringparam,
|
||||
.set_ringparam = mcp251xfd_ring_set_ringparam,
|
||||
.get_coalesce = mcp251xfd_ring_get_coalesce,
|
||||
.set_coalesce = mcp251xfd_ring_set_coalesce,
|
||||
};
|
||||
|
||||
void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv)
|
||||
{
|
||||
struct can_ram_layout layout;
|
||||
|
||||
priv->ndev->ethtool_ops = &mcp251xfd_ethtool_ops;
|
||||
|
||||
can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, false);
|
||||
priv->rx_obj_num = layout.default_rx;
|
||||
priv->tx->obj_num = layout.default_tx;
|
||||
|
||||
priv->rx_obj_num_coalesce_irq = 0;
|
||||
priv->tx_obj_num_coalesce_irq = 0;
|
||||
priv->rx_coalesce_usecs_irq = 0;
|
||||
priv->tx_coalesce_usecs_irq = 0;
|
||||
}
|
153
drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.c
Normal file
153
drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.c
Normal file
@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
//
|
||||
// Copyright (c) 2021, 2022 Pengutronix,
|
||||
// Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
//
|
||||
|
||||
#include "mcp251xfd-ram.h"
|
||||
|
||||
static inline u8 can_ram_clamp(const struct can_ram_config *config,
|
||||
const struct can_ram_obj_config *obj,
|
||||
u8 val)
|
||||
{
|
||||
u8 max;
|
||||
|
||||
max = min_t(u8, obj->max, obj->fifo_num * config->fifo_depth);
|
||||
return clamp(val, obj->min, max);
|
||||
}
|
||||
|
||||
static u8
|
||||
can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
|
||||
const struct can_ram_obj_config *obj,
|
||||
const u8 coalesce, u8 val)
|
||||
{
|
||||
u8 fifo_num = obj->fifo_num;
|
||||
u8 ret = 0, i;
|
||||
|
||||
val = can_ram_clamp(config, obj, val);
|
||||
|
||||
if (coalesce) {
|
||||
/* Use 1st FIFO for coalescing, if requested.
|
||||
*
|
||||
* Either use complete FIFO (and FIFO Full IRQ) for
|
||||
* coalescing or only half of FIFO (FIFO Half Full
|
||||
* IRQ) and use remaining half for normal objects.
|
||||
*/
|
||||
ret = min_t(u8, coalesce * 2, config->fifo_depth);
|
||||
val -= ret;
|
||||
fifo_num--;
|
||||
}
|
||||
|
||||
for (i = 0; i < fifo_num && val; i++) {
|
||||
u8 n;
|
||||
|
||||
n = min_t(u8, rounddown_pow_of_two(val),
|
||||
config->fifo_depth);
|
||||
|
||||
/* skip small FIFOs */
|
||||
if (n < obj->fifo_depth_min)
|
||||
return ret;
|
||||
|
||||
ret += n;
|
||||
val -= n;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void can_ram_get_layout(struct can_ram_layout *layout,
|
||||
const struct can_ram_config *config,
|
||||
const struct ethtool_ringparam *ring,
|
||||
const struct ethtool_coalesce *ec,
|
||||
const bool fd_mode)
|
||||
{
|
||||
u8 num_rx, num_tx;
|
||||
u16 ram_free;
|
||||
|
||||
/* default CAN */
|
||||
|
||||
num_tx = config->tx.def[fd_mode];
|
||||
num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
|
||||
|
||||
ram_free = config->size;
|
||||
ram_free -= config->tx.size[fd_mode] * num_tx;
|
||||
|
||||
num_rx = ram_free / config->rx.size[fd_mode];
|
||||
|
||||
layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
|
||||
layout->default_tx = num_tx;
|
||||
|
||||
/* MAX CAN */
|
||||
|
||||
ram_free = config->size;
|
||||
ram_free -= config->tx.size[fd_mode] * config->tx.min;
|
||||
num_rx = ram_free / config->rx.size[fd_mode];
|
||||
|
||||
ram_free = config->size;
|
||||
ram_free -= config->rx.size[fd_mode] * config->rx.min;
|
||||
num_tx = ram_free / config->tx.size[fd_mode];
|
||||
|
||||
layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
|
||||
layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
|
||||
|
||||
/* cur CAN */
|
||||
|
||||
if (ring) {
|
||||
u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
|
||||
|
||||
num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
|
||||
|
||||
/* The ethtool doc says:
|
||||
* To disable coalescing, set usecs = 0 and max_frames = 1.
|
||||
*/
|
||||
if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
|
||||
ec->rx_max_coalesced_frames_irq == 1)) {
|
||||
u8 max;
|
||||
|
||||
/* use only max half of available objects for coalescing */
|
||||
max = min_t(u8, num_rx / 2, config->fifo_depth);
|
||||
num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,
|
||||
(u32)config->rx.fifo_depth_coalesce_min,
|
||||
(u32)max);
|
||||
num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
|
||||
|
||||
num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
|
||||
num_rx_coalesce, num_rx);
|
||||
}
|
||||
|
||||
ram_free = config->size - config->rx.size[fd_mode] * num_rx;
|
||||
num_tx = ram_free / config->tx.size[fd_mode];
|
||||
num_tx = min_t(u8, ring->tx_pending, num_tx);
|
||||
num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
|
||||
|
||||
/* The ethtool doc says:
|
||||
* To disable coalescing, set usecs = 0 and max_frames = 1.
|
||||
*/
|
||||
if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
|
||||
ec->tx_max_coalesced_frames_irq == 1)) {
|
||||
u8 max;
|
||||
|
||||
/* use only max half of available objects for coalescing */
|
||||
max = min_t(u8, num_tx / 2, config->fifo_depth);
|
||||
num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,
|
||||
(u32)config->tx.fifo_depth_coalesce_min,
|
||||
(u32)max);
|
||||
num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
|
||||
|
||||
num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
|
||||
num_tx_coalesce, num_tx);
|
||||
}
|
||||
|
||||
layout->cur_rx = num_rx;
|
||||
layout->cur_tx = num_tx;
|
||||
layout->rx_coalesce = num_rx_coalesce;
|
||||
layout->tx_coalesce = num_tx_coalesce;
|
||||
} else {
|
||||
layout->cur_rx = layout->default_rx;
|
||||
layout->cur_tx = layout->default_tx;
|
||||
layout->rx_coalesce = 0;
|
||||
layout->tx_coalesce = 0;
|
||||
}
|
||||
}
|
62
drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.h
Normal file
62
drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* mcp251xfd - Microchip MCP251xFD Family CAN controller driver
|
||||
*
|
||||
* Copyright (c) 2021, 2022 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#ifndef _MCP251XFD_RAM_H
|
||||
#define _MCP251XFD_RAM_H
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#define CAN_RAM_NUM_MAX (-1)
|
||||
|
||||
enum can_ram_mode {
|
||||
CAN_RAM_MODE_CAN,
|
||||
CAN_RAM_MODE_CANFD,
|
||||
__CAN_RAM_MODE_MAX
|
||||
};
|
||||
|
||||
struct can_ram_obj_config {
|
||||
u8 size[__CAN_RAM_MODE_MAX];
|
||||
|
||||
u8 def[__CAN_RAM_MODE_MAX];
|
||||
u8 min;
|
||||
u8 max;
|
||||
|
||||
u8 fifo_num;
|
||||
u8 fifo_depth_min;
|
||||
u8 fifo_depth_coalesce_min;
|
||||
};
|
||||
|
||||
struct can_ram_config {
|
||||
const struct can_ram_obj_config rx;
|
||||
const struct can_ram_obj_config tx;
|
||||
|
||||
u16 size;
|
||||
u8 fifo_depth;
|
||||
};
|
||||
|
||||
struct can_ram_layout {
|
||||
u8 default_rx;
|
||||
u8 default_tx;
|
||||
|
||||
u8 max_rx;
|
||||
u8 max_tx;
|
||||
|
||||
u8 cur_rx;
|
||||
u8 cur_tx;
|
||||
|
||||
u8 rx_coalesce;
|
||||
u8 tx_coalesce;
|
||||
};
|
||||
|
||||
void can_ram_get_layout(struct can_ram_layout *layout,
|
||||
const struct can_ram_config *config,
|
||||
const struct ethtool_ringparam *ring,
|
||||
const struct ethtool_coalesce *ec,
|
||||
const bool fd_mode);
|
||||
|
||||
#endif
|
@ -15,6 +15,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "mcp251xfd.h"
|
||||
#include "mcp251xfd-ram.h"
|
||||
|
||||
static inline u8
|
||||
mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
|
||||
@ -70,6 +71,17 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
|
||||
/* TEF- and TX-FIFO have same number of objects */
|
||||
*base = mcp251xfd_get_tef_obj_addr(priv->tx->obj_num);
|
||||
|
||||
/* FIFO IRQ enable */
|
||||
addr = MCP251XFD_REG_TEFCON;
|
||||
val = MCP251XFD_REG_TEFCON_TEFOVIE | MCP251XFD_REG_TEFCON_TEFNEIE;
|
||||
|
||||
len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->irq_enable_buf,
|
||||
addr, val, val);
|
||||
tef_ring->irq_enable_xfer.tx_buf = &tef_ring->irq_enable_buf;
|
||||
tef_ring->irq_enable_xfer.len = len;
|
||||
spi_message_init_with_transfers(&tef_ring->irq_enable_msg,
|
||||
&tef_ring->irq_enable_xfer, 1);
|
||||
|
||||
/* FIFO increment TEF tail pointer */
|
||||
addr = MCP251XFD_REG_TEFCON;
|
||||
val = MCP251XFD_REG_TEFCON_UINC;
|
||||
@ -93,6 +105,18 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
|
||||
* message.
|
||||
*/
|
||||
xfer->cs_change = 0;
|
||||
|
||||
if (priv->tx_coalesce_usecs_irq || priv->tx_obj_num_coalesce_irq) {
|
||||
val = MCP251XFD_REG_TEFCON_UINC |
|
||||
MCP251XFD_REG_TEFCON_TEFOVIE |
|
||||
MCP251XFD_REG_TEFCON_TEFHIE;
|
||||
|
||||
len = mcp251xfd_cmd_prepare_write_reg(priv,
|
||||
&tef_ring->uinc_irq_disable_buf,
|
||||
addr, val, val);
|
||||
xfer->tx_buf = &tef_ring->uinc_irq_disable_buf;
|
||||
xfer->len = len;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -181,8 +205,18 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
|
||||
*base = mcp251xfd_get_rx_obj_addr(rx_ring, rx_ring->obj_num);
|
||||
*fifo_nr += 1;
|
||||
|
||||
/* FIFO increment RX tail pointer */
|
||||
/* FIFO IRQ enable */
|
||||
addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr);
|
||||
val = MCP251XFD_REG_FIFOCON_RXOVIE |
|
||||
MCP251XFD_REG_FIFOCON_TFNRFNIE;
|
||||
len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->irq_enable_buf,
|
||||
addr, val, val);
|
||||
rx_ring->irq_enable_xfer.tx_buf = &rx_ring->irq_enable_buf;
|
||||
rx_ring->irq_enable_xfer.len = len;
|
||||
spi_message_init_with_transfers(&rx_ring->irq_enable_msg,
|
||||
&rx_ring->irq_enable_xfer, 1);
|
||||
|
||||
/* FIFO increment RX tail pointer */
|
||||
val = MCP251XFD_REG_FIFOCON_UINC;
|
||||
len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf,
|
||||
addr, val, val);
|
||||
@ -204,6 +238,39 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
|
||||
* the chip select at the end of the message.
|
||||
*/
|
||||
xfer->cs_change = 0;
|
||||
|
||||
/* Use 1st RX-FIFO for IRQ coalescing. If enabled
|
||||
* (rx_coalesce_usecs_irq or rx_max_coalesce_frames_irq
|
||||
* is activated), use the last transfer to disable:
|
||||
*
|
||||
* - TFNRFNIE (Receive FIFO Not Empty Interrupt)
|
||||
*
|
||||
* and enable:
|
||||
*
|
||||
* - TFHRFHIE (Receive FIFO Half Full Interrupt)
|
||||
* - or -
|
||||
* - TFERFFIE (Receive FIFO Full Interrupt)
|
||||
*
|
||||
* depending on rx_max_coalesce_frames_irq.
|
||||
*
|
||||
* The RXOVIE (Overflow Interrupt) is always enabled.
|
||||
*/
|
||||
if (rx_ring->nr == 0 && (priv->rx_coalesce_usecs_irq ||
|
||||
priv->rx_obj_num_coalesce_irq)) {
|
||||
val = MCP251XFD_REG_FIFOCON_UINC |
|
||||
MCP251XFD_REG_FIFOCON_RXOVIE;
|
||||
|
||||
if (priv->rx_obj_num_coalesce_irq == rx_ring->obj_num)
|
||||
val |= MCP251XFD_REG_FIFOCON_TFERFFIE;
|
||||
else if (priv->rx_obj_num_coalesce_irq)
|
||||
val |= MCP251XFD_REG_FIFOCON_TFHRFHIE;
|
||||
|
||||
len = mcp251xfd_cmd_prepare_write_reg(priv,
|
||||
&rx_ring->uinc_irq_disable_buf,
|
||||
addr, val, val);
|
||||
xfer->tx_buf = &rx_ring->uinc_irq_disable_buf;
|
||||
xfer->len = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,19 +305,58 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
|
||||
*/
|
||||
priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr);
|
||||
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes\n",
|
||||
mcp251xfd_get_tef_obj_addr(0),
|
||||
priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj),
|
||||
priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj));
|
||||
if (priv->tx_obj_num_coalesce_irq) {
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes (coalesce)\n",
|
||||
mcp251xfd_get_tef_obj_addr(0),
|
||||
priv->tx_obj_num_coalesce_irq,
|
||||
sizeof(struct mcp251xfd_hw_tef_obj),
|
||||
priv->tx_obj_num_coalesce_irq *
|
||||
sizeof(struct mcp251xfd_hw_tef_obj));
|
||||
|
||||
netdev_dbg(priv->ndev,
|
||||
" 0x%03x: %2d*%zu bytes = %4zu bytes\n",
|
||||
mcp251xfd_get_tef_obj_addr(priv->tx_obj_num_coalesce_irq),
|
||||
priv->tx->obj_num - priv->tx_obj_num_coalesce_irq,
|
||||
sizeof(struct mcp251xfd_hw_tef_obj),
|
||||
(priv->tx->obj_num - priv->tx_obj_num_coalesce_irq) *
|
||||
sizeof(struct mcp251xfd_hw_tef_obj));
|
||||
} else {
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes\n",
|
||||
mcp251xfd_get_tef_obj_addr(0),
|
||||
priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj),
|
||||
priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj));
|
||||
}
|
||||
|
||||
mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n",
|
||||
rx_ring->nr, rx_ring->fifo_nr,
|
||||
mcp251xfd_get_rx_obj_addr(rx_ring, 0),
|
||||
rx_ring->obj_num, rx_ring->obj_size,
|
||||
rx_ring->obj_num * rx_ring->obj_size);
|
||||
if (rx_ring->nr == 0 && priv->rx_obj_num_coalesce_irq) {
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes (coalesce)\n",
|
||||
rx_ring->nr, rx_ring->fifo_nr,
|
||||
mcp251xfd_get_rx_obj_addr(rx_ring, 0),
|
||||
priv->rx_obj_num_coalesce_irq, rx_ring->obj_size,
|
||||
priv->rx_obj_num_coalesce_irq * rx_ring->obj_size);
|
||||
|
||||
if (priv->rx_obj_num_coalesce_irq == MCP251XFD_FIFO_DEPTH)
|
||||
continue;
|
||||
|
||||
netdev_dbg(priv->ndev,
|
||||
" 0x%03x: %2u*%u bytes = %4u bytes\n",
|
||||
mcp251xfd_get_rx_obj_addr(rx_ring,
|
||||
priv->rx_obj_num_coalesce_irq),
|
||||
rx_ring->obj_num - priv->rx_obj_num_coalesce_irq,
|
||||
rx_ring->obj_size,
|
||||
(rx_ring->obj_num - priv->rx_obj_num_coalesce_irq) *
|
||||
rx_ring->obj_size);
|
||||
} else {
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n",
|
||||
rx_ring->nr, rx_ring->fifo_nr,
|
||||
mcp251xfd_get_rx_obj_addr(rx_ring, 0),
|
||||
rx_ring->obj_num, rx_ring->obj_size,
|
||||
rx_ring->obj_num * rx_ring->obj_size);
|
||||
}
|
||||
}
|
||||
|
||||
netdev_dbg(priv->ndev,
|
||||
@ -261,7 +367,7 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
|
||||
priv->tx->obj_num * priv->tx->obj_size);
|
||||
|
||||
netdev_dbg(priv->ndev,
|
||||
"FIFO setup: free: %4u bytes\n",
|
||||
"FIFO setup: free: %4d bytes\n",
|
||||
MCP251XFD_RAM_SIZE - (base - MCP251XFD_RAM_START));
|
||||
|
||||
ram_used = base - MCP251XFD_RAM_START;
|
||||
@ -285,40 +391,103 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static enum hrtimer_restart mcp251xfd_rx_irq_timer(struct hrtimer *t)
|
||||
{
|
||||
struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv,
|
||||
rx_irq_timer);
|
||||
struct mcp251xfd_rx_ring *ring = priv->rx[0];
|
||||
|
||||
if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags))
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
spi_async(priv->spi, &ring->irq_enable_msg);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart mcp251xfd_tx_irq_timer(struct hrtimer *t)
|
||||
{
|
||||
struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv,
|
||||
tx_irq_timer);
|
||||
struct mcp251xfd_tef_ring *ring = priv->tef;
|
||||
|
||||
if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags))
|
||||
return HRTIMER_NORESTART;
|
||||
|
||||
spi_async(priv->spi, &ring->irq_enable_msg);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
const struct can_ram_config mcp251xfd_ram_config = {
|
||||
.rx = {
|
||||
.size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_rx_obj_can),
|
||||
.size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_rx_obj_canfd),
|
||||
.min = MCP251XFD_RX_OBJ_NUM_MIN,
|
||||
.max = MCP251XFD_RX_OBJ_NUM_MAX,
|
||||
.def[CAN_RAM_MODE_CAN] = CAN_RAM_NUM_MAX,
|
||||
.def[CAN_RAM_MODE_CANFD] = CAN_RAM_NUM_MAX,
|
||||
.fifo_num = MCP251XFD_FIFO_RX_NUM,
|
||||
.fifo_depth_min = MCP251XFD_RX_FIFO_DEPTH_MIN,
|
||||
.fifo_depth_coalesce_min = MCP251XFD_RX_FIFO_DEPTH_COALESCE_MIN,
|
||||
},
|
||||
.tx = {
|
||||
.size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_tef_obj) +
|
||||
sizeof(struct mcp251xfd_hw_tx_obj_can),
|
||||
.size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_tef_obj) +
|
||||
sizeof(struct mcp251xfd_hw_tx_obj_canfd),
|
||||
.min = MCP251XFD_TX_OBJ_NUM_MIN,
|
||||
.max = MCP251XFD_TX_OBJ_NUM_MAX,
|
||||
.def[CAN_RAM_MODE_CAN] = MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT,
|
||||
.def[CAN_RAM_MODE_CANFD] = MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT,
|
||||
.fifo_num = MCP251XFD_FIFO_TX_NUM,
|
||||
.fifo_depth_min = MCP251XFD_TX_FIFO_DEPTH_MIN,
|
||||
.fifo_depth_coalesce_min = MCP251XFD_TX_FIFO_DEPTH_COALESCE_MIN,
|
||||
},
|
||||
.size = MCP251XFD_RAM_SIZE,
|
||||
.fifo_depth = MCP251XFD_FIFO_DEPTH,
|
||||
};
|
||||
|
||||
int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
|
||||
{
|
||||
struct mcp251xfd_tx_ring *tx_ring;
|
||||
const bool fd_mode = mcp251xfd_is_fd_mode(priv);
|
||||
struct mcp251xfd_tx_ring *tx_ring = priv->tx;
|
||||
struct mcp251xfd_rx_ring *rx_ring;
|
||||
int tef_obj_size, tx_obj_size, rx_obj_size;
|
||||
int tx_obj_num;
|
||||
int ram_free, i;
|
||||
u8 tx_obj_size, rx_obj_size;
|
||||
u8 rem, i;
|
||||
|
||||
tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj);
|
||||
if (mcp251xfd_is_fd_mode(priv)) {
|
||||
tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD;
|
||||
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
|
||||
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
|
||||
} else {
|
||||
tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN;
|
||||
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can);
|
||||
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can);
|
||||
/* switching from CAN-2.0 to CAN-FD mode or vice versa */
|
||||
if (fd_mode != test_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags)) {
|
||||
struct can_ram_layout layout;
|
||||
|
||||
can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode);
|
||||
priv->rx_obj_num = layout.default_rx;
|
||||
tx_ring->obj_num = layout.default_tx;
|
||||
}
|
||||
|
||||
if (fd_mode) {
|
||||
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
|
||||
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
|
||||
set_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags);
|
||||
} else {
|
||||
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can);
|
||||
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can);
|
||||
clear_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags);
|
||||
}
|
||||
|
||||
tx_ring = priv->tx;
|
||||
tx_ring->obj_num = tx_obj_num;
|
||||
tx_ring->obj_size = tx_obj_size;
|
||||
|
||||
ram_free = MCP251XFD_RAM_SIZE - tx_obj_num *
|
||||
(tef_obj_size + tx_obj_size);
|
||||
rem = priv->rx_obj_num;
|
||||
for (i = 0; i < ARRAY_SIZE(priv->rx) && rem; i++) {
|
||||
u8 rx_obj_num;
|
||||
|
||||
for (i = 0;
|
||||
i < ARRAY_SIZE(priv->rx) && ram_free >= rx_obj_size;
|
||||
i++) {
|
||||
int rx_obj_num;
|
||||
|
||||
rx_obj_num = ram_free / rx_obj_size;
|
||||
rx_obj_num = min(1 << (fls(rx_obj_num) - 1),
|
||||
MCP251XFD_RX_OBJ_NUM_MAX);
|
||||
if (i == 0 && priv->rx_obj_num_coalesce_irq)
|
||||
rx_obj_num = min_t(u8, priv->rx_obj_num_coalesce_irq * 2,
|
||||
MCP251XFD_FIFO_DEPTH);
|
||||
else
|
||||
rx_obj_num = min_t(u8, rounddown_pow_of_two(rem),
|
||||
MCP251XFD_FIFO_DEPTH);
|
||||
rem -= rx_obj_num;
|
||||
|
||||
rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num,
|
||||
GFP_KERNEL);
|
||||
@ -326,13 +495,18 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
|
||||
mcp251xfd_ring_free(priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rx_ring->obj_num = rx_obj_num;
|
||||
rx_ring->obj_size = rx_obj_size;
|
||||
priv->rx[i] = rx_ring;
|
||||
|
||||
ram_free -= rx_ring->obj_num * rx_ring->obj_size;
|
||||
}
|
||||
priv->rx_ring_num = i;
|
||||
|
||||
hrtimer_init(&priv->rx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
priv->rx_irq_timer.function = mcp251xfd_rx_irq_timer;
|
||||
|
||||
hrtimer_init(&priv->tx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
priv->tx_irq_timer.function = mcp251xfd_tx_irq_timer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -254,7 +254,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
|
||||
int err, n;
|
||||
|
||||
mcp251xfd_for_each_rx_ring(priv, ring, n) {
|
||||
if (!(priv->regs_status.rxif & BIT(ring->fifo_nr)))
|
||||
/* - if RX IRQ coalescing is active always handle ring 0
|
||||
* - only handle rings if RX IRQ is active
|
||||
*/
|
||||
if ((ring->nr > 0 || !priv->rx_obj_num_coalesce_irq) &&
|
||||
!(priv->regs_status.rxif & BIT(ring->fifo_nr)))
|
||||
continue;
|
||||
|
||||
err = mcp251xfd_handle_rxif_ring(priv, ring);
|
||||
@ -262,5 +266,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (priv->rx_coalesce_usecs_irq)
|
||||
hrtimer_start(&priv->rx_irq_timer,
|
||||
ns_to_ktime(priv->rx_coalesce_usecs_irq *
|
||||
NSEC_PER_USEC),
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -256,5 +256,11 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
|
||||
netif_wake_queue(priv->ndev);
|
||||
}
|
||||
|
||||
if (priv->tx_coalesce_usecs_irq)
|
||||
hrtimer_start(&priv->tx_irq_timer,
|
||||
ns_to_ktime(priv->tx_coalesce_usecs_irq *
|
||||
NSEC_PER_USEC),
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -367,23 +367,6 @@
|
||||
#define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4)
|
||||
#define MCP251XFD_REG_DEVID_REV_MASK GENMASK(3, 0)
|
||||
|
||||
/* number of TX FIFO objects, depending on CAN mode
|
||||
*
|
||||
* FIFO setup: tef: 8*12 bytes = 96 bytes, tx: 8*16 bytes = 128 bytes
|
||||
* FIFO setup: tef: 4*12 bytes = 48 bytes, tx: 4*72 bytes = 288 bytes
|
||||
*/
|
||||
#define MCP251XFD_RX_OBJ_NUM_MAX 32
|
||||
#define MCP251XFD_TX_OBJ_NUM_CAN 8
|
||||
#define MCP251XFD_TX_OBJ_NUM_CANFD 4
|
||||
|
||||
#if MCP251XFD_TX_OBJ_NUM_CAN > MCP251XFD_TX_OBJ_NUM_CANFD
|
||||
#define MCP251XFD_TX_OBJ_NUM_MAX MCP251XFD_TX_OBJ_NUM_CAN
|
||||
#else
|
||||
#define MCP251XFD_TX_OBJ_NUM_MAX MCP251XFD_TX_OBJ_NUM_CANFD
|
||||
#endif
|
||||
|
||||
#define MCP251XFD_NAPI_WEIGHT 32
|
||||
|
||||
/* SPI commands */
|
||||
#define MCP251XFD_SPI_INSTRUCTION_RESET 0x0000
|
||||
#define MCP251XFD_SPI_INSTRUCTION_WRITE 0x2000
|
||||
@ -404,6 +387,9 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
|
||||
#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
|
||||
#define MCP251XFD_POLL_SLEEP_US (10)
|
||||
#define MCP251XFD_POLL_TIMEOUT_US (USEC_PER_MSEC)
|
||||
|
||||
/* Misc */
|
||||
#define MCP251XFD_NAPI_WEIGHT 32
|
||||
#define MCP251XFD_SOFTRESET_RETRIES_MAX 3
|
||||
#define MCP251XFD_READ_CRC_RETRIES_MAX 3
|
||||
#define MCP251XFD_ECC_CNT_MAX 2
|
||||
@ -412,12 +398,26 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
|
||||
|
||||
/* FIFO and Ring */
|
||||
#define MCP251XFD_FIFO_TEF_NUM 1U
|
||||
#define MCP251XFD_FIFO_RX_NUM_MAX 1U
|
||||
#define MCP251XFD_FIFO_RX_NUM 3U
|
||||
#define MCP251XFD_FIFO_TX_NUM 1U
|
||||
|
||||
#define MCP251XFD_FIFO_DEPTH 32U
|
||||
|
||||
#define MCP251XFD_RX_OBJ_NUM_MIN 16U
|
||||
#define MCP251XFD_RX_OBJ_NUM_MAX (MCP251XFD_FIFO_RX_NUM * MCP251XFD_FIFO_DEPTH)
|
||||
#define MCP251XFD_RX_FIFO_DEPTH_MIN 4U
|
||||
#define MCP251XFD_RX_FIFO_DEPTH_COALESCE_MIN 8U
|
||||
|
||||
#define MCP251XFD_TX_OBJ_NUM_MIN 2U
|
||||
#define MCP251XFD_TX_OBJ_NUM_MAX 16U
|
||||
#define MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT 8U
|
||||
#define MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT 4U
|
||||
#define MCP251XFD_TX_FIFO_DEPTH_MIN 2U
|
||||
#define MCP251XFD_TX_FIFO_DEPTH_COALESCE_MIN 2U
|
||||
|
||||
static_assert(MCP251XFD_FIFO_TEF_NUM == 1U);
|
||||
static_assert(MCP251XFD_FIFO_TEF_NUM == MCP251XFD_FIFO_TX_NUM);
|
||||
static_assert(MCP251XFD_FIFO_RX_NUM_MAX <= 4U);
|
||||
static_assert(MCP251XFD_FIFO_RX_NUM <= 4U);
|
||||
|
||||
/* Silence TX MAB overflow warnings */
|
||||
#define MCP251XFD_QUIRK_MAB_NO_WARN BIT(0)
|
||||
@ -519,7 +519,12 @@ struct mcp251xfd_tef_ring {
|
||||
/* u8 obj_num equals tx_ring->obj_num */
|
||||
/* u8 obj_size equals sizeof(struct mcp251xfd_hw_tef_obj) */
|
||||
|
||||
union mcp251xfd_write_reg_buf irq_enable_buf;
|
||||
struct spi_transfer irq_enable_xfer;
|
||||
struct spi_message irq_enable_msg;
|
||||
|
||||
union mcp251xfd_write_reg_buf uinc_buf;
|
||||
union mcp251xfd_write_reg_buf uinc_irq_disable_buf;
|
||||
struct spi_transfer uinc_xfer[MCP251XFD_TX_OBJ_NUM_MAX];
|
||||
};
|
||||
|
||||
@ -547,8 +552,13 @@ struct mcp251xfd_rx_ring {
|
||||
u8 obj_num;
|
||||
u8 obj_size;
|
||||
|
||||
union mcp251xfd_write_reg_buf irq_enable_buf;
|
||||
struct spi_transfer irq_enable_xfer;
|
||||
struct spi_message irq_enable_msg;
|
||||
|
||||
union mcp251xfd_write_reg_buf uinc_buf;
|
||||
struct spi_transfer uinc_xfer[MCP251XFD_RX_OBJ_NUM_MAX];
|
||||
union mcp251xfd_write_reg_buf uinc_irq_disable_buf;
|
||||
struct spi_transfer uinc_xfer[MCP251XFD_FIFO_DEPTH];
|
||||
struct mcp251xfd_hw_rx_obj_canfd obj[];
|
||||
};
|
||||
|
||||
@ -584,6 +594,13 @@ struct mcp251xfd_devtype_data {
|
||||
u32 quirks;
|
||||
};
|
||||
|
||||
enum mcp251xfd_flags {
|
||||
MCP251XFD_FLAGS_DOWN,
|
||||
MCP251XFD_FLAGS_FD_MODE,
|
||||
|
||||
__MCP251XFD_FLAGS_SIZE__
|
||||
};
|
||||
|
||||
struct mcp251xfd_priv {
|
||||
struct can_priv can;
|
||||
struct can_rx_offload offload;
|
||||
@ -606,10 +623,20 @@ struct mcp251xfd_priv {
|
||||
u32 spi_max_speed_hz_slow;
|
||||
|
||||
struct mcp251xfd_tef_ring tef[MCP251XFD_FIFO_TEF_NUM];
|
||||
struct mcp251xfd_rx_ring *rx[MCP251XFD_FIFO_RX_NUM_MAX];
|
||||
struct mcp251xfd_rx_ring *rx[MCP251XFD_FIFO_RX_NUM];
|
||||
struct mcp251xfd_tx_ring tx[MCP251XFD_FIFO_TX_NUM];
|
||||
|
||||
DECLARE_BITMAP(flags, __MCP251XFD_FLAGS_SIZE__);
|
||||
|
||||
u8 rx_ring_num;
|
||||
u8 rx_obj_num;
|
||||
u8 rx_obj_num_coalesce_irq;
|
||||
u8 tx_obj_num_coalesce_irq;
|
||||
|
||||
u32 rx_coalesce_usecs_irq;
|
||||
u32 tx_coalesce_usecs_irq;
|
||||
struct hrtimer rx_irq_timer;
|
||||
struct hrtimer tx_irq_timer;
|
||||
|
||||
struct mcp251xfd_ecc ecc;
|
||||
struct mcp251xfd_regs_status regs_status;
|
||||
@ -891,7 +918,9 @@ int mcp251xfd_chip_fifo_init(const struct mcp251xfd_priv *priv);
|
||||
u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
|
||||
const void *data, size_t data_size);
|
||||
u16 mcp251xfd_crc16_compute(const void *data, size_t data_size);
|
||||
void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv);
|
||||
extern const struct can_ram_config mcp251xfd_ram_config;
|
||||
int mcp251xfd_ring_init(struct mcp251xfd_priv *priv);
|
||||
void mcp251xfd_ring_free(struct mcp251xfd_priv *priv);
|
||||
int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv);
|
||||
|
@ -57,7 +57,7 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
|
||||
if (skb) {
|
||||
consume_skb(oskb);
|
||||
} else {
|
||||
kfree(oskb);
|
||||
kfree_skb(oskb);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user