Commit de29aff9 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-5.18-20220313' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 97aeb877 aa66ae9b
...@@ -6,6 +6,8 @@ mcp251xfd-objs := ...@@ -6,6 +6,8 @@ mcp251xfd-objs :=
mcp251xfd-objs += mcp251xfd-chip-fifo.o mcp251xfd-objs += mcp251xfd-chip-fifo.o
mcp251xfd-objs += mcp251xfd-core.o mcp251xfd-objs += mcp251xfd-core.o
mcp251xfd-objs += mcp251xfd-crc16.o mcp251xfd-objs += mcp251xfd-crc16.o
mcp251xfd-objs += mcp251xfd-ethtool.o
mcp251xfd-objs += mcp251xfd-ram.o
mcp251xfd-objs += mcp251xfd-regmap.o mcp251xfd-objs += mcp251xfd-regmap.o
mcp251xfd-objs += mcp251xfd-ring.o mcp251xfd-objs += mcp251xfd-ring.o
mcp251xfd-objs += mcp251xfd-rx.o mcp251xfd-objs += mcp251xfd-rx.o
......
...@@ -1598,6 +1598,7 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -1598,6 +1598,7 @@ static int mcp251xfd_open(struct net_device *ndev)
goto out_transceiver_disable; goto out_transceiver_disable;
mcp251xfd_timestamp_init(priv); mcp251xfd_timestamp_init(priv);
clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
can_rx_offload_enable(&priv->offload); can_rx_offload_enable(&priv->offload);
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq, err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
...@@ -1618,6 +1619,7 @@ static int mcp251xfd_open(struct net_device *ndev) ...@@ -1618,6 +1619,7 @@ static int mcp251xfd_open(struct net_device *ndev)
free_irq(spi->irq, priv); free_irq(spi->irq, priv);
out_can_rx_offload_disable: out_can_rx_offload_disable:
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
mcp251xfd_timestamp_stop(priv); mcp251xfd_timestamp_stop(priv);
out_transceiver_disable: out_transceiver_disable:
mcp251xfd_transceiver_disable(priv); mcp251xfd_transceiver_disable(priv);
...@@ -1637,6 +1639,8 @@ static int mcp251xfd_stop(struct net_device *ndev) ...@@ -1637,6 +1639,8 @@ static int mcp251xfd_stop(struct net_device *ndev)
struct mcp251xfd_priv *priv = netdev_priv(ndev); struct mcp251xfd_priv *priv = netdev_priv(ndev);
netif_stop_queue(ndev); netif_stop_queue(ndev);
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
hrtimer_cancel(&priv->rx_irq_timer);
mcp251xfd_chip_interrupts_disable(priv); mcp251xfd_chip_interrupts_disable(priv);
free_irq(ndev->irq, priv); free_irq(ndev->irq, priv);
can_rx_offload_disable(&priv->offload); can_rx_offload_disable(&priv->offload);
...@@ -1871,6 +1875,8 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv) ...@@ -1871,6 +1875,8 @@ static int mcp251xfd_register(struct mcp251xfd_priv *priv)
if (err) if (err)
goto out_chip_sleep; goto out_chip_sleep;
mcp251xfd_ethtool_init(priv);
err = register_candev(ndev); err = register_candev(ndev);
if (err) if (err)
goto out_chip_sleep; goto out_chip_sleep;
...@@ -2034,6 +2040,7 @@ static int mcp251xfd_probe(struct spi_device *spi) ...@@ -2034,6 +2040,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO | CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
CAN_CTRLMODE_CC_LEN8_DLC; CAN_CTRLMODE_CC_LEN8_DLC;
set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
priv->ndev = ndev; priv->ndev = ndev;
priv->spi = spi; priv->spi = spi;
priv->rx_int = rx_int; priv->rx_int = rx_int;
......
// 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;
}
// 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;
}
}
/* 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 @@ ...@@ -15,6 +15,7 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "mcp251xfd.h" #include "mcp251xfd.h"
#include "mcp251xfd-ram.h"
static inline u8 static inline u8
mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv, mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
...@@ -70,6 +71,17 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base) ...@@ -70,6 +71,17 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
/* TEF- and TX-FIFO have same number of objects */ /* TEF- and TX-FIFO have same number of objects */
*base = mcp251xfd_get_tef_obj_addr(priv->tx->obj_num); *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 */ /* FIFO increment TEF tail pointer */
addr = MCP251XFD_REG_TEFCON; addr = MCP251XFD_REG_TEFCON;
val = MCP251XFD_REG_TEFCON_UINC; val = MCP251XFD_REG_TEFCON_UINC;
...@@ -93,6 +105,18 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base) ...@@ -93,6 +105,18 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
* message. * message.
*/ */
xfer->cs_change = 0; 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 static void
...@@ -181,8 +205,18 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) ...@@ -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); *base = mcp251xfd_get_rx_obj_addr(rx_ring, rx_ring->obj_num);
*fifo_nr += 1; *fifo_nr += 1;
/* FIFO increment RX tail pointer */ /* FIFO IRQ enable */
addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr); 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; val = MCP251XFD_REG_FIFOCON_UINC;
len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf, len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf,
addr, val, val); addr, val, val);
...@@ -204,6 +238,39 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr) ...@@ -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. * the chip select at the end of the message.
*/ */
xfer->cs_change = 0; 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) ...@@ -238,19 +305,58 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
*/ */
priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr); priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr);
netdev_dbg(priv->ndev, if (priv->tx_obj_num_coalesce_irq) {
"FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes\n", netdev_dbg(priv->ndev,
mcp251xfd_get_tef_obj_addr(0), "FIFO setup: TEF: 0x%03x: %2d*%zu bytes = %4zu bytes (coalesce)\n",
priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj), mcp251xfd_get_tef_obj_addr(0),
priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj)); priv->tx_obj_num_coalesce_irq,
sizeof(struct mcp251xfd_hw_tef_obj),
priv->tx_obj_num_coalesce_irq *
sizeof(struct mcp251xfd_hw_tef_obj));
mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
netdev_dbg(priv->ndev, netdev_dbg(priv->ndev,
"FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n", " 0x%03x: %2d*%zu bytes = %4zu bytes\n",
rx_ring->nr, rx_ring->fifo_nr, mcp251xfd_get_tef_obj_addr(priv->tx_obj_num_coalesce_irq),
mcp251xfd_get_rx_obj_addr(rx_ring, 0), priv->tx->obj_num - priv->tx_obj_num_coalesce_irq,
rx_ring->obj_num, rx_ring->obj_size, sizeof(struct mcp251xfd_hw_tef_obj),
rx_ring->obj_num * rx_ring->obj_size); (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) {
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, netdev_dbg(priv->ndev,
...@@ -261,7 +367,7 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv) ...@@ -261,7 +367,7 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
priv->tx->obj_num * priv->tx->obj_size); priv->tx->obj_num * priv->tx->obj_size);
netdev_dbg(priv->ndev, netdev_dbg(priv->ndev,
"FIFO setup: free: %4u bytes\n", "FIFO setup: free: %4d bytes\n",
MCP251XFD_RAM_SIZE - (base - MCP251XFD_RAM_START)); MCP251XFD_RAM_SIZE - (base - MCP251XFD_RAM_START));
ram_used = base - MCP251XFD_RAM_START; ram_used = base - MCP251XFD_RAM_START;
...@@ -285,40 +391,103 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv) ...@@ -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) 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; struct mcp251xfd_rx_ring *rx_ring;
int tef_obj_size, tx_obj_size, rx_obj_size; u8 tx_obj_size, rx_obj_size;
int tx_obj_num; u8 rem, i;
int ram_free, i;
/* 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;
}
tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj); if (fd_mode) {
if (mcp251xfd_is_fd_mode(priv)) {
tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD;
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd); tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd); rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
set_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags);
} else { } else {
tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN;
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can); tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can);
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_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; tx_ring->obj_size = tx_obj_size;
ram_free = MCP251XFD_RAM_SIZE - tx_obj_num * rem = priv->rx_obj_num;
(tef_obj_size + tx_obj_size); 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; if (i == 0 && priv->rx_obj_num_coalesce_irq)
rx_obj_num = min(1 << (fls(rx_obj_num) - 1), rx_obj_num = min_t(u8, priv->rx_obj_num_coalesce_irq * 2,
MCP251XFD_RX_OBJ_NUM_MAX); 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, rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num,
GFP_KERNEL); GFP_KERNEL);
...@@ -326,13 +495,18 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) ...@@ -326,13 +495,18 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
mcp251xfd_ring_free(priv); mcp251xfd_ring_free(priv);
return -ENOMEM; return -ENOMEM;
} }
rx_ring->obj_num = rx_obj_num; rx_ring->obj_num = rx_obj_num;
rx_ring->obj_size = rx_obj_size; rx_ring->obj_size = rx_obj_size;
priv->rx[i] = rx_ring; priv->rx[i] = rx_ring;
ram_free -= rx_ring->obj_num * rx_ring->obj_size;
} }
priv->rx_ring_num = i; 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; return 0;
} }
...@@ -254,7 +254,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv) ...@@ -254,7 +254,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
int err, n; int err, n;
mcp251xfd_for_each_rx_ring(priv, ring, 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; continue;
err = mcp251xfd_handle_rxif_ring(priv, ring); err = mcp251xfd_handle_rxif_ring(priv, ring);
...@@ -262,5 +266,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv) ...@@ -262,5 +266,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
return err; 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; return 0;
} }
...@@ -256,5 +256,11 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv) ...@@ -256,5 +256,11 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
netif_wake_queue(priv->ndev); 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; return 0;
} }
...@@ -367,23 +367,6 @@ ...@@ -367,23 +367,6 @@
#define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4) #define MCP251XFD_REG_DEVID_ID_MASK GENMASK(7, 4)
#define MCP251XFD_REG_DEVID_REV_MASK GENMASK(3, 0) #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 */ /* SPI commands */
#define MCP251XFD_SPI_INSTRUCTION_RESET 0x0000 #define MCP251XFD_SPI_INSTRUCTION_RESET 0x0000
#define MCP251XFD_SPI_INSTRUCTION_WRITE 0x2000 #define MCP251XFD_SPI_INSTRUCTION_WRITE 0x2000
...@@ -404,6 +387,9 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC < ...@@ -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_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
#define MCP251XFD_POLL_SLEEP_US (10) #define MCP251XFD_POLL_SLEEP_US (10)
#define MCP251XFD_POLL_TIMEOUT_US (USEC_PER_MSEC) #define MCP251XFD_POLL_TIMEOUT_US (USEC_PER_MSEC)
/* Misc */
#define MCP251XFD_NAPI_WEIGHT 32
#define MCP251XFD_SOFTRESET_RETRIES_MAX 3 #define MCP251XFD_SOFTRESET_RETRIES_MAX 3
#define MCP251XFD_READ_CRC_RETRIES_MAX 3 #define MCP251XFD_READ_CRC_RETRIES_MAX 3
#define MCP251XFD_ECC_CNT_MAX 2 #define MCP251XFD_ECC_CNT_MAX 2
...@@ -412,12 +398,26 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC < ...@@ -412,12 +398,26 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
/* FIFO and Ring */ /* FIFO and Ring */
#define MCP251XFD_FIFO_TEF_NUM 1U #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_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 == 1U);
static_assert(MCP251XFD_FIFO_TEF_NUM == MCP251XFD_FIFO_TX_NUM); 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 */ /* Silence TX MAB overflow warnings */
#define MCP251XFD_QUIRK_MAB_NO_WARN BIT(0) #define MCP251XFD_QUIRK_MAB_NO_WARN BIT(0)
...@@ -519,7 +519,12 @@ struct mcp251xfd_tef_ring { ...@@ -519,7 +519,12 @@ struct mcp251xfd_tef_ring {
/* u8 obj_num equals tx_ring->obj_num */ /* u8 obj_num equals tx_ring->obj_num */
/* u8 obj_size equals sizeof(struct mcp251xfd_hw_tef_obj) */ /* 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_buf;
union mcp251xfd_write_reg_buf uinc_irq_disable_buf;
struct spi_transfer uinc_xfer[MCP251XFD_TX_OBJ_NUM_MAX]; struct spi_transfer uinc_xfer[MCP251XFD_TX_OBJ_NUM_MAX];
}; };
...@@ -547,8 +552,13 @@ struct mcp251xfd_rx_ring { ...@@ -547,8 +552,13 @@ struct mcp251xfd_rx_ring {
u8 obj_num; u8 obj_num;
u8 obj_size; 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; 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[]; struct mcp251xfd_hw_rx_obj_canfd obj[];
}; };
...@@ -584,6 +594,13 @@ struct mcp251xfd_devtype_data { ...@@ -584,6 +594,13 @@ struct mcp251xfd_devtype_data {
u32 quirks; u32 quirks;
}; };
enum mcp251xfd_flags {
MCP251XFD_FLAGS_DOWN,
MCP251XFD_FLAGS_FD_MODE,
__MCP251XFD_FLAGS_SIZE__
};
struct mcp251xfd_priv { struct mcp251xfd_priv {
struct can_priv can; struct can_priv can;
struct can_rx_offload offload; struct can_rx_offload offload;
...@@ -606,10 +623,20 @@ struct mcp251xfd_priv { ...@@ -606,10 +623,20 @@ struct mcp251xfd_priv {
u32 spi_max_speed_hz_slow; u32 spi_max_speed_hz_slow;
struct mcp251xfd_tef_ring tef[MCP251XFD_FIFO_TEF_NUM]; 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]; struct mcp251xfd_tx_ring tx[MCP251XFD_FIFO_TX_NUM];
DECLARE_BITMAP(flags, __MCP251XFD_FLAGS_SIZE__);
u8 rx_ring_num; 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_ecc ecc;
struct mcp251xfd_regs_status regs_status; struct mcp251xfd_regs_status regs_status;
...@@ -891,7 +918,9 @@ int mcp251xfd_chip_fifo_init(const struct mcp251xfd_priv *priv); ...@@ -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, u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size,
const void *data, size_t data_size); const void *data, size_t data_size);
u16 mcp251xfd_crc16_compute(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); 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); int mcp251xfd_ring_init(struct mcp251xfd_priv *priv);
void mcp251xfd_ring_free(struct mcp251xfd_priv *priv); void mcp251xfd_ring_free(struct mcp251xfd_priv *priv);
int mcp251xfd_ring_alloc(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) ...@@ -57,7 +57,7 @@ static netdev_tx_t vxcan_xmit(struct sk_buff *oskb, struct net_device *dev)
if (skb) { if (skb) {
consume_skb(oskb); consume_skb(oskb);
} else { } else {
kfree(oskb); kfree_skb(oskb);
goto out_unlock; goto out_unlock;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment