mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 18:11:56 +00:00
linux-can-next-for-5.5-20191111
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEmvEkXzgOfc881GuFWsYho5HknSAFAl3J1ekTHG1rbEBwZW5n dXRyb25peC5kZQAKCRBaxiGjkeSdILUKB/9mYalSK5f4n/AalnsEoGy3IWVy/xwG KvAdZAueH2uFIhu6MfqmWbs9xp94kGsI9RP1o3UDzwLxBaol8cG97oi0T1Fn5670 LSzBkR5WXEVaerw7noGwVEvi/IKkSCO7pOI3PszwITHU+P/w/EChVLyeWnzDoTaf bzSXbtXQTOCINepIic+f1COffyJA4o84uiEFwpkuTJPbiihxr43bGrwj0xb1cWC9 Zh464vGuA7s2/Xqhsmg/Z/BU5ihWIz3/wEAqKUW99dj1rUpgdaChTFEO1femXInX WkOi6r4EZGsAB0Cbbp6hTkovK9UF94asVMOW74Yz9UK9dxEakcwmR7XK =S7hM -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-5.5-20191111' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2019-10-07 this is a pull request for net-next/master consisting of 32 patches. The first patch is by Gustavo A. R. Silva and removes unused code in the generic CAN infrastructure. The next three patches target the mcp251x driver. The one by Andy Shevchenko removes the legacy platform data support from the driver. The other two are by Timo Schlüßler and reset the device only when needed, to prevent glitches on the output when GPIO support is added. I'm contributing two patches fixing checkpatch warnings in the c_can_platform and peak_canfd driver. Stephane Grosjean's patch for the peak_canfd driver adds hw timestamps support in rx skbs. The next three patches target the xilinx_can driver. One patch by me to fix checkpatch warnings, one patch by Anssi Hannula to avoid non requested bus error frames, and a patch by YueHaibing that switches the driver to devm_platform_ioremap_resource(). Pankaj Sharma contributes two patches for the m_can driver, the first one adds support for one shot mode, the other support for handling arbitration errors. Followed by four patches by YueHaibing, switching the grcan, ifi, rcar, and sun4i drivers to devm_platform_ioremap_resource() I'm contributing cleanup patches for the rx-offload helper, while Joakim Zhang's patch prepares the rx-offload helper for CAN-FD support. The rx offload users flexcan and ti_hecc are converted accordingly. The remaining twelve patches target the flexcan driver. First Joakim Zhang switches the driver to devm_platform_ioremap_resource(). The remaining eleven patch are by me and clean up the abstract the access of the iflag1 and iflag2 register both for RX and TX mailboxes. This is a preparation for the upcoming CAN-FD support. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e0580b50d9
@ -12,6 +12,7 @@
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
@ -22,7 +23,6 @@
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/can/platform/mcp251x.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
#include "generic.h"
|
||||
@ -69,8 +69,9 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = {
|
||||
.gpio_cs = ICONTROL_MCP251x_nCS4
|
||||
};
|
||||
|
||||
static struct mcp251x_platform_data mcp251x_info = {
|
||||
.oscillator_frequency = 16E6,
|
||||
static const struct property_entry mcp251x_properties[] = {
|
||||
PROPERTY_ENTRY_U32("clock-frequency", 16000000),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct spi_board_info mcp251x_board_info[] = {
|
||||
@ -79,7 +80,7 @@ static struct spi_board_info mcp251x_board_info[] = {
|
||||
.max_speed_hz = 6500000,
|
||||
.bus_num = 3,
|
||||
.chip_select = 0,
|
||||
.platform_data = &mcp251x_info,
|
||||
.properties = mcp251x_properties,
|
||||
.controller_data = &mcp251x_chip_info1,
|
||||
.irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ1)
|
||||
},
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/serial_8250.h>
|
||||
@ -27,7 +28,6 @@
|
||||
#include <linux/platform_data/i2c-pxa.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/apm-emulation.h>
|
||||
#include <linux/can/platform/mcp251x.h>
|
||||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
@ -428,14 +428,15 @@ static struct gpiod_lookup_table can_regulator_gpiod_table = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct mcp251x_platform_data zeus_mcp2515_pdata = {
|
||||
.oscillator_frequency = 16*1000*1000,
|
||||
static const struct property_entry mcp251x_properties[] = {
|
||||
PROPERTY_ENTRY_U32("clock-frequency", 16000000),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct spi_board_info zeus_spi_board_info[] = {
|
||||
[0] = {
|
||||
.modalias = "mcp2515",
|
||||
.platform_data = &zeus_mcp2515_pdata,
|
||||
.properties = mcp251x_properties,
|
||||
.irq = PXA_GPIO_TO_IRQ(ZEUS_CAN_GPIO),
|
||||
.max_speed_hz = 1*1000*1000,
|
||||
.bus_num = 3,
|
||||
|
@ -39,10 +39,11 @@
|
||||
|
||||
#include "c_can.h"
|
||||
|
||||
#define DCAN_RAM_INIT_BIT (1 << 3)
|
||||
#define DCAN_RAM_INIT_BIT BIT(3)
|
||||
|
||||
static DEFINE_SPINLOCK(raminit_lock);
|
||||
/*
|
||||
* 16-bit c_can registers can be arranged differently in the memory
|
||||
|
||||
/* 16-bit c_can registers can be arranged differently in the memory
|
||||
* architecture of different implementations. For example: 16-bit
|
||||
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
|
||||
* Handle the same by providing a common read/write interface.
|
||||
@ -54,7 +55,7 @@ static u16 c_can_plat_read_reg_aligned_to_16bit(const struct c_can_priv *priv,
|
||||
}
|
||||
|
||||
static void c_can_plat_write_reg_aligned_to_16bit(const struct c_can_priv *priv,
|
||||
enum reg index, u16 val)
|
||||
enum reg index, u16 val)
|
||||
{
|
||||
writew(val, priv->base + priv->regs[index]);
|
||||
}
|
||||
@ -66,7 +67,7 @@ static u16 c_can_plat_read_reg_aligned_to_32bit(const struct c_can_priv *priv,
|
||||
}
|
||||
|
||||
static void c_can_plat_write_reg_aligned_to_32bit(const struct c_can_priv *priv,
|
||||
enum reg index, u16 val)
|
||||
enum reg index, u16 val)
|
||||
{
|
||||
writew(val, priv->base + 2 * priv->regs[index]);
|
||||
}
|
||||
@ -144,13 +145,13 @@ static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
|
||||
u32 val;
|
||||
|
||||
val = priv->read_reg(priv, index);
|
||||
val |= ((u32) priv->read_reg(priv, index + 1)) << 16;
|
||||
val |= ((u32)priv->read_reg(priv, index + 1)) << 16;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void c_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index,
|
||||
u32 val)
|
||||
static void c_can_plat_write_reg32(const struct c_can_priv *priv,
|
||||
enum reg index, u32 val)
|
||||
{
|
||||
priv->write_reg(priv, index + 1, val >> 16);
|
||||
priv->write_reg(priv, index, val);
|
||||
@ -161,8 +162,8 @@ static u32 d_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
|
||||
return readl(priv->base + priv->regs[index]);
|
||||
}
|
||||
|
||||
static void d_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index,
|
||||
u32 val)
|
||||
static void d_can_plat_write_reg32(const struct c_can_priv *priv,
|
||||
enum reg index, u32 val)
|
||||
{
|
||||
writel(val, priv->base + priv->regs[index]);
|
||||
}
|
||||
|
@ -553,10 +553,9 @@ static void can_restart(struct net_device *dev)
|
||||
|
||||
/* send restart message upstream */
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
if (!skb) {
|
||||
err = -ENOMEM;
|
||||
if (!skb)
|
||||
goto restart;
|
||||
}
|
||||
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
|
||||
netif_rx(skb);
|
||||
|
@ -142,7 +142,7 @@
|
||||
#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
|
||||
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
|
||||
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
|
||||
#define FLEXCAN_IFLAG_MB(x) BIT((x) & 0x1f)
|
||||
#define FLEXCAN_IFLAG_MB(x) BIT_ULL(x)
|
||||
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
|
||||
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
|
||||
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
|
||||
@ -277,9 +277,9 @@ struct flexcan_priv {
|
||||
u8 mb_size;
|
||||
u8 clk_src; /* clock source of CAN Protocol Engine */
|
||||
|
||||
u64 rx_mask;
|
||||
u64 tx_mask;
|
||||
u32 reg_ctrl_default;
|
||||
u32 reg_imask1_default;
|
||||
u32 reg_imask2_default;
|
||||
|
||||
struct clk *clk_ipg;
|
||||
struct clk *clk_per;
|
||||
@ -743,8 +743,6 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
||||
u32 timestamp;
|
||||
int err;
|
||||
|
||||
timestamp = priv->read(®s->timer) << 16;
|
||||
|
||||
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
|
||||
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
|
||||
tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ?
|
||||
@ -764,6 +762,8 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
||||
if (likely(new_state == priv->can.state))
|
||||
return;
|
||||
|
||||
timestamp = priv->read(®s->timer) << 16;
|
||||
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
if (unlikely(!skb))
|
||||
return;
|
||||
@ -778,21 +778,58 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
||||
dev->stats.rx_fifo_errors++;
|
||||
}
|
||||
|
||||
static inline u64 flexcan_read64_mask(struct flexcan_priv *priv, void __iomem *addr, u64 mask)
|
||||
{
|
||||
u64 reg = 0;
|
||||
|
||||
if (upper_32_bits(mask))
|
||||
reg = (u64)priv->read(addr - 4) << 32;
|
||||
if (lower_32_bits(mask))
|
||||
reg |= priv->read(addr);
|
||||
|
||||
return reg & mask;
|
||||
}
|
||||
|
||||
static inline void flexcan_write64(struct flexcan_priv *priv, u64 val, void __iomem *addr)
|
||||
{
|
||||
if (upper_32_bits(val))
|
||||
priv->write(upper_32_bits(val), addr - 4);
|
||||
if (lower_32_bits(val))
|
||||
priv->write(lower_32_bits(val), addr);
|
||||
}
|
||||
|
||||
static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
|
||||
{
|
||||
return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->rx_mask);
|
||||
}
|
||||
|
||||
static inline u64 flexcan_read_reg_iflag_tx(struct flexcan_priv *priv)
|
||||
{
|
||||
return flexcan_read64_mask(priv, &priv->regs->iflag1, priv->tx_mask);
|
||||
}
|
||||
|
||||
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
|
||||
{
|
||||
return container_of(offload, struct flexcan_priv, offload);
|
||||
}
|
||||
|
||||
static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
struct can_frame *cf,
|
||||
u32 *timestamp, unsigned int n)
|
||||
static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
unsigned int n, u32 *timestamp,
|
||||
bool drop)
|
||||
{
|
||||
struct flexcan_priv *priv = rx_offload_to_priv(offload);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
struct flexcan_mb __iomem *mb;
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf;
|
||||
u32 reg_ctrl, reg_id, reg_iflag1;
|
||||
int i;
|
||||
|
||||
if (unlikely(drop)) {
|
||||
skb = ERR_PTR(-ENOBUFS);
|
||||
goto mark_as_read;
|
||||
}
|
||||
|
||||
mb = flexcan_get_mb(priv, n);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||
@ -806,7 +843,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
code = reg_ctrl & FLEXCAN_MB_CODE_MASK;
|
||||
if ((code != FLEXCAN_MB_CODE_RX_FULL) &&
|
||||
(code != FLEXCAN_MB_CODE_RX_OVERRUN))
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
if (code == FLEXCAN_MB_CODE_RX_OVERRUN) {
|
||||
/* This MB was overrun, we lost data */
|
||||
@ -816,11 +853,17 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
} else {
|
||||
reg_iflag1 = priv->read(®s->iflag1);
|
||||
if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE))
|
||||
return 0;
|
||||
return NULL;
|
||||
|
||||
reg_ctrl = priv->read(&mb->can_ctrl);
|
||||
}
|
||||
|
||||
skb = alloc_can_skb(offload->dev, &cf);
|
||||
if (!skb) {
|
||||
skb = ERR_PTR(-ENOMEM);
|
||||
goto mark_as_read;
|
||||
}
|
||||
|
||||
/* increase timstamp to full 32 bit */
|
||||
*timestamp = reg_ctrl << 16;
|
||||
|
||||
@ -839,16 +882,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
*(__be32 *)(cf->data + i) = data;
|
||||
}
|
||||
|
||||
/* mark as read */
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||
/* Clear IRQ */
|
||||
if (n < 32)
|
||||
priv->write(BIT(n), ®s->iflag1);
|
||||
else
|
||||
priv->write(BIT(n - 32), ®s->iflag2);
|
||||
} else {
|
||||
mark_as_read:
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
||||
flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), ®s->iflag1);
|
||||
else
|
||||
priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1);
|
||||
}
|
||||
|
||||
/* Read the Free Running Timer. It is optional but recommended
|
||||
* to unlock Mailbox as soon as possible and make it available
|
||||
@ -856,20 +894,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
||||
*/
|
||||
priv->read(®s->timer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static inline u64 flexcan_read_reg_iflag_rx(struct flexcan_priv *priv)
|
||||
{
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
u32 iflag1, iflag2;
|
||||
|
||||
iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default &
|
||||
~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
||||
iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default;
|
||||
|
||||
return (u64)iflag2 << 32 | iflag1;
|
||||
return skb;
|
||||
}
|
||||
|
||||
static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||||
@ -879,18 +904,19 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
irqreturn_t handled = IRQ_NONE;
|
||||
u32 reg_iflag2, reg_esr;
|
||||
u64 reg_iflag_tx;
|
||||
u32 reg_esr;
|
||||
enum can_state last_state = priv->can.state;
|
||||
|
||||
/* reception interrupt */
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||
u64 reg_iflag;
|
||||
u64 reg_iflag_rx;
|
||||
int ret;
|
||||
|
||||
while ((reg_iflag = flexcan_read_reg_iflag_rx(priv))) {
|
||||
while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
|
||||
handled = IRQ_HANDLED;
|
||||
ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
|
||||
reg_iflag);
|
||||
reg_iflag_rx);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
@ -913,10 +939,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||||
}
|
||||
}
|
||||
|
||||
reg_iflag2 = priv->read(®s->iflag2);
|
||||
reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
|
||||
|
||||
/* transmission complete interrupt */
|
||||
if (reg_iflag2 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
|
||||
if (reg_iflag_tx & priv->tx_mask) {
|
||||
u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
@ -928,7 +954,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||||
/* after sending a RTR frame MB is in RX mode */
|
||||
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
||||
&priv->tx_mb->can_ctrl);
|
||||
priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), ®s->iflag2);
|
||||
flexcan_write64(priv, priv->tx_mask, ®s->iflag1);
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
|
||||
@ -1040,6 +1066,7 @@ static int flexcan_chip_start(struct net_device *dev)
|
||||
struct flexcan_priv *priv = netdev_priv(dev);
|
||||
struct flexcan_regs __iomem *regs = priv->regs;
|
||||
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
|
||||
u64 reg_imask;
|
||||
int err, i;
|
||||
struct flexcan_mb __iomem *mb;
|
||||
|
||||
@ -1214,8 +1241,9 @@ static int flexcan_chip_start(struct net_device *dev)
|
||||
/* enable interrupts atomically */
|
||||
disable_irq(dev->irq);
|
||||
priv->write(priv->reg_ctrl_default, ®s->ctrl);
|
||||
priv->write(priv->reg_imask1_default, ®s->imask1);
|
||||
priv->write(priv->reg_imask2_default, ®s->imask2);
|
||||
reg_imask = priv->rx_mask | priv->tx_mask;
|
||||
priv->write(upper_32_bits(reg_imask), ®s->imask2);
|
||||
priv->write(lower_32_bits(reg_imask), ®s->imask1);
|
||||
enable_irq(dev->irq);
|
||||
|
||||
/* print chip status */
|
||||
@ -1283,26 +1311,19 @@ static int flexcan_open(struct net_device *dev)
|
||||
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
|
||||
priv->tx_mb_idx = priv->mb_count - 1;
|
||||
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
|
||||
|
||||
priv->reg_imask1_default = 0;
|
||||
priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
||||
priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
||||
|
||||
priv->offload.mailbox_read = flexcan_mailbox_read;
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
||||
u64 imask;
|
||||
|
||||
priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
|
||||
priv->offload.mb_last = priv->mb_count - 2;
|
||||
|
||||
imask = GENMASK_ULL(priv->offload.mb_last,
|
||||
priv->offload.mb_first);
|
||||
priv->reg_imask1_default |= imask;
|
||||
priv->reg_imask2_default |= imask >> 32;
|
||||
|
||||
priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
|
||||
priv->offload.mb_first);
|
||||
err = can_rx_offload_add_timestamp(dev, &priv->offload);
|
||||
} else {
|
||||
priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
|
||||
priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
|
||||
FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
|
||||
err = can_rx_offload_add_fifo(dev, &priv->offload,
|
||||
FLEXCAN_NAPI_WEIGHT);
|
||||
@ -1534,7 +1555,6 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
struct net_device *dev;
|
||||
struct flexcan_priv *priv;
|
||||
struct regulator *reg_xceiver;
|
||||
struct resource *mem;
|
||||
struct clk *clk_ipg = NULL, *clk_per = NULL;
|
||||
struct flexcan_regs __iomem *regs;
|
||||
int err, irq;
|
||||
@ -1569,12 +1589,11 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
clock_freq = clk_get_rate(clk_per);
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
regs = devm_ioremap_resource(&pdev->dev, mem);
|
||||
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
|
@ -1652,7 +1652,6 @@ exit_free_candev:
|
||||
static int grcan_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
struct resource *res;
|
||||
u32 sysid, ambafreq;
|
||||
int irq, err;
|
||||
void __iomem *base;
|
||||
@ -1672,8 +1671,7 @@ static int grcan_probe(struct platform_device *ofdev)
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(&ofdev->dev, res);
|
||||
base = devm_platform_ioremap_resource(ofdev, 0);
|
||||
if (IS_ERR(base)) {
|
||||
err = PTR_ERR(base);
|
||||
goto exit_error;
|
||||
|
@ -942,13 +942,11 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct net_device *ndev;
|
||||
struct ifi_canfd_priv *priv;
|
||||
struct resource *res;
|
||||
void __iomem *addr;
|
||||
int irq, ret;
|
||||
u32 id, rev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(dev, res);
|
||||
addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (IS_ERR(addr) || irq < 0)
|
||||
return -EINVAL;
|
||||
|
@ -123,6 +123,7 @@ enum m_can_reg {
|
||||
#define CCCR_CME_CANFD_BRS 0x2
|
||||
#define CCCR_TXP BIT(14)
|
||||
#define CCCR_TEST BIT(7)
|
||||
#define CCCR_DAR BIT(6)
|
||||
#define CCCR_MON BIT(5)
|
||||
#define CCCR_CSR BIT(4)
|
||||
#define CCCR_CSA BIT(3)
|
||||
@ -777,6 +778,43 @@ static inline bool is_lec_err(u32 psr)
|
||||
return psr && (psr != LEC_UNUSED);
|
||||
}
|
||||
|
||||
static inline bool m_can_is_protocol_err(u32 irqstatus)
|
||||
{
|
||||
return irqstatus & IR_ERR_LEC_31X;
|
||||
}
|
||||
|
||||
static int m_can_handle_protocol_error(struct net_device *dev, u32 irqstatus)
|
||||
{
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
struct m_can_classdev *cdev = netdev_priv(dev);
|
||||
struct can_frame *cf;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* propagate the error condition to the CAN stack */
|
||||
skb = alloc_can_err_skb(dev, &cf);
|
||||
|
||||
/* update tx error stats since there is protocol error */
|
||||
stats->tx_errors++;
|
||||
|
||||
/* update arbitration lost status */
|
||||
if (cdev->version >= 31 && (irqstatus & IR_PEA)) {
|
||||
netdev_dbg(dev, "Protocol error in Arbitration fail\n");
|
||||
cdev->can.can_stats.arbitration_lost++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_LOSTARB;
|
||||
cf->data[0] |= CAN_ERR_LOSTARB_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
netdev_dbg(dev, "allocation of skb failed\n");
|
||||
return 0;
|
||||
}
|
||||
netif_receive_skb(skb);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
|
||||
u32 psr)
|
||||
{
|
||||
@ -791,6 +829,11 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
|
||||
is_lec_err(psr))
|
||||
work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED);
|
||||
|
||||
/* handle protocol errors in arbitration phase */
|
||||
if ((cdev->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
|
||||
m_can_is_protocol_err(irqstatus))
|
||||
work_done += m_can_handle_protocol_error(dev, irqstatus);
|
||||
|
||||
/* other unproccessed error interrupts */
|
||||
m_can_handle_other_err(dev, irqstatus);
|
||||
|
||||
@ -1135,7 +1178,7 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
if (cdev->version == 30) {
|
||||
/* Version 3.0.x */
|
||||
|
||||
cccr &= ~(CCCR_TEST | CCCR_MON |
|
||||
cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR |
|
||||
(CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
|
||||
(CCCR_CME_MASK << CCCR_CME_SHIFT));
|
||||
|
||||
@ -1145,7 +1188,7 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
} else {
|
||||
/* Version 3.1.x or 3.2.x */
|
||||
cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE |
|
||||
CCCR_NISO);
|
||||
CCCR_NISO | CCCR_DAR);
|
||||
|
||||
/* Only 3.2.x has NISO Bit implemented */
|
||||
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
|
||||
@ -1165,6 +1208,10 @@ static void m_can_chip_config(struct net_device *dev)
|
||||
if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
|
||||
cccr |= CCCR_MON;
|
||||
|
||||
/* Disable Auto Retransmission (all versions) */
|
||||
if (cdev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
cccr |= CCCR_DAR;
|
||||
|
||||
/* Write config */
|
||||
m_can_write(cdev, M_CAN_CCCR, cccr);
|
||||
m_can_write(cdev, M_CAN_TEST, test);
|
||||
@ -1310,7 +1357,8 @@ static int m_can_dev_setup(struct m_can_classdev *m_can_dev)
|
||||
m_can_dev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
|
||||
CAN_CTRLMODE_LISTENONLY |
|
||||
CAN_CTRLMODE_BERR_REPORTING |
|
||||
CAN_CTRLMODE_FD;
|
||||
CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_ONE_SHOT;
|
||||
|
||||
/* Set properties depending on M_CAN version */
|
||||
switch (m_can_dev->version) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
|
||||
/* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
|
||||
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
|
||||
*
|
||||
* Copyright (C) 2016 PEAK System-Technik GmbH
|
||||
@ -122,7 +121,8 @@ static int pucan_set_timing_slow(struct peak_canfd_priv *priv,
|
||||
cmd = pucan_add_cmd(pucan_init_cmd(priv), PUCAN_CMD_TIMING_SLOW);
|
||||
|
||||
cmd->sjw_t = PUCAN_TSLOW_SJW_T(pbt->sjw - 1,
|
||||
priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES);
|
||||
priv->can.ctrlmode &
|
||||
CAN_CTRLMODE_3_SAMPLES);
|
||||
cmd->tseg1 = PUCAN_TSLOW_TSEG1(pbt->prop_seg + pbt->phase_seg1 - 1);
|
||||
cmd->tseg2 = PUCAN_TSLOW_TSEG2(pbt->phase_seg2 - 1);
|
||||
cmd->brp = cpu_to_le16(PUCAN_TSLOW_BRP(pbt->brp - 1));
|
||||
@ -232,6 +232,20 @@ static int pucan_setup_rx_barrier(struct peak_canfd_priv *priv)
|
||||
return pucan_write_cmd(priv);
|
||||
}
|
||||
|
||||
static int pucan_netif_rx(struct sk_buff *skb, __le32 ts_low, __le32 ts_high)
|
||||
{
|
||||
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
|
||||
u64 ts_us;
|
||||
|
||||
ts_us = (u64)le32_to_cpu(ts_high) << 32;
|
||||
ts_us |= le32_to_cpu(ts_low);
|
||||
|
||||
/* IP core timestamps are µs. */
|
||||
hwts->hwtstamp = ns_to_ktime(ts_us * NSEC_PER_USEC);
|
||||
|
||||
return netif_rx(skb);
|
||||
}
|
||||
|
||||
/* handle the reception of one CAN frame */
|
||||
static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
|
||||
struct pucan_rx_msg *msg)
|
||||
@ -299,7 +313,7 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
|
||||
stats->rx_bytes += cf->len;
|
||||
stats->rx_packets++;
|
||||
|
||||
netif_rx(skb);
|
||||
pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -325,7 +339,6 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
|
||||
|
||||
/* this STATUS is the CNF of the RX_BARRIER: Tx path can be setup */
|
||||
if (pucan_status_is_rx_barrier(msg)) {
|
||||
|
||||
if (priv->enable_tx_path) {
|
||||
int err = priv->enable_tx_path(priv);
|
||||
|
||||
@ -393,7 +406,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
|
||||
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
netif_rx(skb);
|
||||
pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* CAN driver for PEAK System micro-CAN based adapters
|
||||
/* CAN driver for PEAK System micro-CAN based adapters
|
||||
*
|
||||
* Copyright (C) 2003-2011 PEAK System-Technik GmbH
|
||||
* Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.com>
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
|
||||
/* Copyright (C) 2007, 2011 Wolfgang Grandegger <wg@grandegger.com>
|
||||
* Copyright (C) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
|
||||
*
|
||||
* Derived from the PCAN project file driver/src/pcan_pci.c:
|
||||
@ -841,7 +840,8 @@ err_disable_pci:
|
||||
|
||||
/* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while
|
||||
* the probe() function must return a negative errno in case of failure
|
||||
* (err is unchanged if negative) */
|
||||
* (err is unchanged if negative)
|
||||
*/
|
||||
return pcibios_err_to_errno(err);
|
||||
}
|
||||
|
||||
|
@ -744,7 +744,6 @@ static int rcar_can_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_can_priv *priv;
|
||||
struct net_device *ndev;
|
||||
struct resource *mem;
|
||||
void __iomem *addr;
|
||||
u32 clock_select = CLKR_CLKP1;
|
||||
int err = -ENODEV;
|
||||
@ -759,8 +758,7 @@ static int rcar_can_probe(struct platform_device *pdev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(&pdev->dev, mem);
|
||||
addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(addr)) {
|
||||
err = PTR_ERR(addr);
|
||||
goto fail;
|
||||
|
@ -1630,7 +1630,6 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)
|
||||
|
||||
static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *mem;
|
||||
void __iomem *addr;
|
||||
u32 sts, ch, fcan_freq;
|
||||
struct rcar_canfd_global *gpriv;
|
||||
@ -1704,8 +1703,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
/* CANFD clock is further divided by (1/2) within the IP */
|
||||
fcan_freq /= 2;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(&pdev->dev, mem);
|
||||
addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(addr)) {
|
||||
err = PTR_ERR(addr);
|
||||
goto fail_dev;
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2014 David Jander, Protonic Holland
|
||||
* Copyright (C) 2014-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
/* Copyright (c) 2014 Protonic Holland,
|
||||
* David Jander
|
||||
* Copyright (C) 2014-2017 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
#include <linux/can/dev.h>
|
||||
@ -11,14 +12,17 @@ struct can_rx_offload_cb {
|
||||
u32 timestamp;
|
||||
};
|
||||
|
||||
static inline struct can_rx_offload_cb *can_rx_offload_get_cb(struct sk_buff *skb)
|
||||
static inline struct can_rx_offload_cb *
|
||||
can_rx_offload_get_cb(struct sk_buff *skb)
|
||||
{
|
||||
BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
|
||||
|
||||
return (struct can_rx_offload_cb *)skb->cb;
|
||||
}
|
||||
|
||||
static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned int a, unsigned int b)
|
||||
static inline bool
|
||||
can_rx_offload_le(struct can_rx_offload *offload,
|
||||
unsigned int a, unsigned int b)
|
||||
{
|
||||
if (offload->inc)
|
||||
return a <= b;
|
||||
@ -26,7 +30,8 @@ static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned in
|
||||
return a >= b;
|
||||
}
|
||||
|
||||
static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
|
||||
static inline unsigned int
|
||||
can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
|
||||
{
|
||||
if (offload->inc)
|
||||
return (*val)++;
|
||||
@ -36,7 +41,9 @@ static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, un
|
||||
|
||||
static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
|
||||
{
|
||||
struct can_rx_offload *offload = container_of(napi, struct can_rx_offload, napi);
|
||||
struct can_rx_offload *offload = container_of(napi,
|
||||
struct can_rx_offload,
|
||||
napi);
|
||||
struct net_device *dev = offload->dev;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
struct sk_buff *skb;
|
||||
@ -65,8 +72,9 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
|
||||
return work_done;
|
||||
}
|
||||
|
||||
static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
|
||||
int (*compare)(struct sk_buff *a, struct sk_buff *b))
|
||||
static inline void
|
||||
__skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new,
|
||||
int (*compare)(struct sk_buff *a, struct sk_buff *b))
|
||||
{
|
||||
struct sk_buff *pos, *insert = NULL;
|
||||
|
||||
@ -101,7 +109,7 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
|
||||
cb_a = can_rx_offload_get_cb(a);
|
||||
cb_b = can_rx_offload_get_cb(b);
|
||||
|
||||
/* Substract two u32 and return result as int, to keep
|
||||
/* Subtract two u32 and return result as int, to keep
|
||||
* difference steady around the u32 overflow.
|
||||
*/
|
||||
return cb_b->timestamp - cb_a->timestamp;
|
||||
@ -131,75 +139,40 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
|
||||
static struct sk_buff *
|
||||
can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
|
||||
{
|
||||
struct sk_buff *skb = NULL, *skb_error = NULL;
|
||||
struct sk_buff *skb;
|
||||
struct can_rx_offload_cb *cb;
|
||||
struct can_frame *cf;
|
||||
int ret;
|
||||
bool drop = false;
|
||||
u32 timestamp;
|
||||
|
||||
if (likely(skb_queue_len(&offload->skb_queue) <
|
||||
offload->skb_queue_len_max)) {
|
||||
skb = alloc_can_skb(offload->dev, &cf);
|
||||
if (unlikely(!skb))
|
||||
skb_error = ERR_PTR(-ENOMEM); /* skb alloc failed */
|
||||
} else {
|
||||
skb_error = ERR_PTR(-ENOBUFS); /* skb_queue is full */
|
||||
}
|
||||
|
||||
/* If queue is full or skb not available, drop by reading into
|
||||
* overflow buffer.
|
||||
*/
|
||||
if (unlikely(skb_error)) {
|
||||
struct can_frame cf_overflow;
|
||||
u32 timestamp;
|
||||
|
||||
ret = offload->mailbox_read(offload, &cf_overflow,
|
||||
×tamp, n);
|
||||
|
||||
/* Mailbox was empty. */
|
||||
if (unlikely(!ret))
|
||||
return NULL;
|
||||
|
||||
/* Mailbox has been read and we're dropping it or
|
||||
* there was a problem reading the mailbox.
|
||||
*
|
||||
* Increment error counters in any case.
|
||||
*/
|
||||
offload->dev->stats.rx_dropped++;
|
||||
offload->dev->stats.rx_fifo_errors++;
|
||||
|
||||
/* There was a problem reading the mailbox, propagate
|
||||
* error value.
|
||||
*/
|
||||
if (unlikely(ret < 0))
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return skb_error;
|
||||
}
|
||||
|
||||
cb = can_rx_offload_get_cb(skb);
|
||||
ret = offload->mailbox_read(offload, cf, &cb->timestamp, n);
|
||||
/* If queue is full drop frame */
|
||||
if (unlikely(skb_queue_len(&offload->skb_queue) >
|
||||
offload->skb_queue_len_max))
|
||||
drop = true;
|
||||
|
||||
skb = offload->mailbox_read(offload, n, ×tamp, drop);
|
||||
/* Mailbox was empty. */
|
||||
if (unlikely(!ret)) {
|
||||
kfree_skb(skb);
|
||||
if (unlikely(!skb))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* There was a problem reading the mailbox, propagate error value. */
|
||||
if (unlikely(ret < 0)) {
|
||||
kfree_skb(skb);
|
||||
|
||||
/* There was a problem reading the mailbox, propagate
|
||||
* error value.
|
||||
*/
|
||||
if (unlikely(IS_ERR(skb))) {
|
||||
offload->dev->stats.rx_dropped++;
|
||||
offload->dev->stats.rx_fifo_errors++;
|
||||
|
||||
return ERR_PTR(ret);
|
||||
return skb;
|
||||
}
|
||||
|
||||
/* Mailbox was read. */
|
||||
cb = can_rx_offload_get_cb(skb);
|
||||
cb->timestamp = timestamp;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pending)
|
||||
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
|
||||
u64 pending)
|
||||
{
|
||||
struct sk_buff_head skb_queue;
|
||||
unsigned int i;
|
||||
@ -229,8 +202,8 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pen
|
||||
skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
|
||||
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
||||
|
||||
if ((queue_len = skb_queue_len(&offload->skb_queue)) >
|
||||
(offload->skb_queue_len_max / 8))
|
||||
queue_len = skb_queue_len(&offload->skb_queue);
|
||||
if (queue_len > offload->skb_queue_len_max / 8)
|
||||
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
|
||||
__func__, queue_len);
|
||||
|
||||
@ -328,7 +301,9 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
|
||||
|
||||
static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
|
||||
static int can_rx_offload_init_queue(struct net_device *dev,
|
||||
struct can_rx_offload *offload,
|
||||
unsigned int weight)
|
||||
{
|
||||
offload->dev = dev;
|
||||
|
||||
@ -337,7 +312,6 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo
|
||||
offload->skb_queue_len_max *= 4;
|
||||
skb_queue_head_init(&offload->skb_queue);
|
||||
|
||||
can_rx_offload_reset(offload);
|
||||
netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
|
||||
|
||||
dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n",
|
||||
@ -346,7 +320,8 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo
|
||||
return 0;
|
||||
}
|
||||
|
||||
int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *offload)
|
||||
int can_rx_offload_add_timestamp(struct net_device *dev,
|
||||
struct can_rx_offload *offload)
|
||||
{
|
||||
unsigned int weight;
|
||||
|
||||
@ -366,7 +341,8 @@ int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_add_timestamp);
|
||||
|
||||
int can_rx_offload_add_fifo(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight)
|
||||
int can_rx_offload_add_fifo(struct net_device *dev,
|
||||
struct can_rx_offload *offload, unsigned int weight)
|
||||
{
|
||||
if (!offload->mailbox_read)
|
||||
return -EINVAL;
|
||||
@ -377,7 +353,6 @@ EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo);
|
||||
|
||||
void can_rx_offload_enable(struct can_rx_offload *offload)
|
||||
{
|
||||
can_rx_offload_reset(offload);
|
||||
napi_enable(&offload->napi);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_enable);
|
||||
@ -388,8 +363,3 @@ void can_rx_offload_del(struct can_rx_offload *offload)
|
||||
skb_queue_purge(&offload->skb_queue);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_del);
|
||||
|
||||
void can_rx_offload_reset(struct can_rx_offload *offload)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_reset);
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <linux/can/core.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/can/led.h>
|
||||
#include <linux/can/platform/mcp251x.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
@ -321,6 +320,18 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, u8 val)
|
||||
mcp251x_spi_trans(spi, 3);
|
||||
}
|
||||
|
||||
static void mcp251x_write_2regs(struct spi_device *spi, u8 reg, u8 v1, u8 v2)
|
||||
{
|
||||
struct mcp251x_priv *priv = spi_get_drvdata(spi);
|
||||
|
||||
priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
|
||||
priv->spi_tx_buf[1] = reg;
|
||||
priv->spi_tx_buf[2] = v1;
|
||||
priv->spi_tx_buf[3] = v2;
|
||||
|
||||
mcp251x_spi_trans(spi, 4);
|
||||
}
|
||||
|
||||
static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
|
||||
u8 mask, u8 val)
|
||||
{
|
||||
@ -457,6 +468,39 @@ static void mcp251x_hw_sleep(struct spi_device *spi)
|
||||
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
|
||||
}
|
||||
|
||||
/* May only be called when device is sleeping! */
|
||||
static int mcp251x_hw_wake(struct spi_device *spi)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
/* Force wakeup interrupt to wake device, but don't execute IST */
|
||||
disable_irq(spi->irq);
|
||||
mcp251x_write_2regs(spi, CANINTE, CANINTE_WAKIE, CANINTF_WAKIF);
|
||||
|
||||
/* Wait for oscillator startup timer after wake up */
|
||||
mdelay(MCP251X_OST_DELAY_MS);
|
||||
|
||||
/* Put device into config mode */
|
||||
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_CONF);
|
||||
|
||||
/* Wait for the device to enter config mode */
|
||||
timeout = jiffies + HZ;
|
||||
while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK) !=
|
||||
CANCTRL_REQOP_CONF) {
|
||||
schedule();
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(&spi->dev, "MCP251x didn't enter in config mode\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable and clear pending interrupts */
|
||||
mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00);
|
||||
enable_irq(spi->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *net)
|
||||
{
|
||||
@ -646,8 +690,7 @@ static int mcp251x_stop(struct net_device *net)
|
||||
mutex_lock(&priv->mcp_lock);
|
||||
|
||||
/* Disable and clear pending interrupts */
|
||||
mcp251x_write_reg(spi, CANINTE, 0x00);
|
||||
mcp251x_write_reg(spi, CANINTF, 0x00);
|
||||
mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00);
|
||||
|
||||
mcp251x_write_reg(spi, TXBCTRL(0), 0);
|
||||
mcp251x_clean(net);
|
||||
@ -715,8 +758,12 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
|
||||
|
||||
mutex_lock(&priv->mcp_lock);
|
||||
if (priv->after_suspend) {
|
||||
mcp251x_hw_reset(spi);
|
||||
mcp251x_setup(net, spi);
|
||||
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
|
||||
mcp251x_hw_reset(spi);
|
||||
mcp251x_setup(net, spi);
|
||||
} else {
|
||||
mcp251x_hw_wake(spi);
|
||||
}
|
||||
priv->force_quit = 0;
|
||||
if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
|
||||
mcp251x_set_normal_mode(spi);
|
||||
@ -913,7 +960,7 @@ static int mcp251x_open(struct net_device *net)
|
||||
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
|
||||
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
|
||||
|
||||
ret = mcp251x_hw_reset(spi);
|
||||
ret = mcp251x_hw_wake(spi);
|
||||
if (ret)
|
||||
goto out_free_wq;
|
||||
ret = mcp251x_setup(net, spi);
|
||||
@ -986,19 +1033,19 @@ MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
|
||||
static int mcp251x_can_probe(struct spi_device *spi)
|
||||
{
|
||||
const void *match = device_get_match_data(&spi->dev);
|
||||
struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
|
||||
struct net_device *net;
|
||||
struct mcp251x_priv *priv;
|
||||
struct clk *clk;
|
||||
int freq, ret;
|
||||
u32 freq;
|
||||
int ret;
|
||||
|
||||
clk = devm_clk_get_optional(&spi->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
freq = clk_get_rate(clk);
|
||||
if (freq == 0 && pdata)
|
||||
freq = pdata->oscillator_frequency;
|
||||
if (freq == 0)
|
||||
device_property_read_u32(&spi->dev, "clock-frequency", &freq);
|
||||
|
||||
/* Sanity check */
|
||||
if (freq < 1000000 || freq > 25000000)
|
||||
@ -1155,13 +1202,13 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
|
||||
|
||||
if (priv->after_suspend & AFTER_SUSPEND_POWER)
|
||||
mcp251x_power_enable(priv->power, 1);
|
||||
|
||||
if (priv->after_suspend & AFTER_SUSPEND_UP) {
|
||||
if (priv->after_suspend & AFTER_SUSPEND_UP)
|
||||
mcp251x_power_enable(priv->transceiver, 1);
|
||||
|
||||
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
|
||||
queue_work(priv->wq, &priv->restart_work);
|
||||
} else {
|
||||
else
|
||||
priv->after_suspend = 0;
|
||||
}
|
||||
|
||||
priv->force_quit = 0;
|
||||
enable_irq(spi->irq);
|
||||
|
@ -771,7 +771,6 @@ static int sun4ican_remove(struct platform_device *pdev)
|
||||
static int sun4ican_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct resource *mem;
|
||||
struct clk *clk;
|
||||
void __iomem *addr;
|
||||
int err, irq;
|
||||
@ -791,8 +790,7 @@ static int sun4ican_probe(struct platform_device *pdev)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(&pdev->dev, mem);
|
||||
addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(addr)) {
|
||||
err = -EBUSY;
|
||||
goto exit;
|
||||
|
@ -535,15 +535,28 @@ struct ti_hecc_priv *rx_offload_to_priv(struct can_rx_offload *offload)
|
||||
return container_of(offload, struct ti_hecc_priv, offload);
|
||||
}
|
||||
|
||||
static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload,
|
||||
struct can_frame *cf,
|
||||
u32 *timestamp, unsigned int mbxno)
|
||||
static struct sk_buff *ti_hecc_mailbox_read(struct can_rx_offload *offload,
|
||||
unsigned int mbxno, u32 *timestamp,
|
||||
bool drop)
|
||||
{
|
||||
struct ti_hecc_priv *priv = rx_offload_to_priv(offload);
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf;
|
||||
u32 data, mbx_mask;
|
||||
int ret = 1;
|
||||
|
||||
mbx_mask = BIT(mbxno);
|
||||
|
||||
if (unlikely(drop)) {
|
||||
skb = ERR_PTR(-ENOBUFS);
|
||||
goto mark_as_read;
|
||||
}
|
||||
|
||||
skb = alloc_can_skb(offload->dev, &cf);
|
||||
if (unlikely(!skb)) {
|
||||
skb = ERR_PTR(-ENOMEM);
|
||||
goto mark_as_read;
|
||||
}
|
||||
|
||||
data = hecc_read_mbx(priv, mbxno, HECC_CANMID);
|
||||
if (data & HECC_CANMID_IDE)
|
||||
cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
|
||||
@ -578,11 +591,12 @@ static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload,
|
||||
*/
|
||||
if (unlikely(mbxno == HECC_RX_LAST_MBOX &&
|
||||
hecc_read(priv, HECC_CANRML) & mbx_mask))
|
||||
ret = -ENOBUFS;
|
||||
skb = ERR_PTR(-ENOBUFS);
|
||||
|
||||
mark_as_read:
|
||||
hecc_write(priv, HECC_CANRMP, mbx_mask);
|
||||
|
||||
return ret;
|
||||
return skb;
|
||||
}
|
||||
|
||||
static int ti_hecc_error(struct net_device *ndev, int int_status,
|
||||
|
@ -194,7 +194,7 @@ struct xcan_devtype_data {
|
||||
*/
|
||||
struct xcan_priv {
|
||||
struct can_priv can;
|
||||
spinlock_t tx_lock;
|
||||
spinlock_t tx_lock; /* Lock for synchronizing TX interrupt handling */
|
||||
unsigned int tx_head;
|
||||
unsigned int tx_tail;
|
||||
unsigned int tx_max;
|
||||
@ -400,7 +400,7 @@ static int xcan_set_bittiming(struct net_device *ndev)
|
||||
XCAN_SR_CONFIG_MASK;
|
||||
if (!is_config_mode) {
|
||||
netdev_alert(ndev,
|
||||
"BUG! Cannot set bittiming - CAN is not in config mode\n");
|
||||
"BUG! Cannot set bittiming - CAN is not in config mode\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@ -470,7 +470,13 @@ static int xcan_chip_start(struct net_device *ndev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Enable interrupts */
|
||||
/* Enable interrupts
|
||||
*
|
||||
* We enable the ERROR interrupt even with
|
||||
* CAN_CTRLMODE_BERR_REPORTING disabled as there is no
|
||||
* dedicated interrupt for a state change to
|
||||
* ERROR_WARNING/ERROR_PASSIVE.
|
||||
*/
|
||||
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 |
|
||||
@ -482,11 +488,10 @@ static int xcan_chip_start(struct net_device *ndev)
|
||||
priv->write_reg(priv, XCAN_IER_OFFSET, ier);
|
||||
|
||||
/* Check whether it is loopback mode or normal mode */
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
|
||||
reg_msr = XCAN_MSR_LBACK_MASK;
|
||||
} else {
|
||||
else
|
||||
reg_msr = 0x0;
|
||||
}
|
||||
|
||||
/* enable the first extended filter, if any, as cores with extended
|
||||
* filtering default to non-receipt if all filters are disabled
|
||||
@ -981,12 +986,9 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
|
||||
{
|
||||
struct xcan_priv *priv = netdev_priv(ndev);
|
||||
struct net_device_stats *stats = &ndev->stats;
|
||||
struct can_frame *cf;
|
||||
struct sk_buff *skb;
|
||||
struct can_frame cf = { };
|
||||
u32 err_status;
|
||||
|
||||
skb = alloc_can_err_skb(ndev, &cf);
|
||||
|
||||
err_status = priv->read_reg(priv, XCAN_ESR_OFFSET);
|
||||
priv->write_reg(priv, XCAN_ESR_OFFSET, err_status);
|
||||
|
||||
@ -996,32 +998,27 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
|
||||
/* Leave device in Config Mode in bus-off state */
|
||||
priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
|
||||
can_bus_off(ndev);
|
||||
if (skb)
|
||||
cf->can_id |= CAN_ERR_BUSOFF;
|
||||
cf.can_id |= CAN_ERR_BUSOFF;
|
||||
} else {
|
||||
enum can_state new_state = xcan_current_error_state(ndev);
|
||||
|
||||
if (new_state != priv->can.state)
|
||||
xcan_set_error_state(ndev, new_state, skb ? cf : NULL);
|
||||
xcan_set_error_state(ndev, new_state, &cf);
|
||||
}
|
||||
|
||||
/* Check for Arbitration lost interrupt */
|
||||
if (isr & XCAN_IXR_ARBLST_MASK) {
|
||||
priv->can.can_stats.arbitration_lost++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_LOSTARB;
|
||||
cf->data[0] = CAN_ERR_LOSTARB_UNSPEC;
|
||||
}
|
||||
cf.can_id |= CAN_ERR_LOSTARB;
|
||||
cf.data[0] = CAN_ERR_LOSTARB_UNSPEC;
|
||||
}
|
||||
|
||||
/* Check for RX FIFO Overflow interrupt */
|
||||
if (isr & XCAN_IXR_RXOFLW_MASK) {
|
||||
stats->rx_over_errors++;
|
||||
stats->rx_errors++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
}
|
||||
cf.can_id |= CAN_ERR_CRTL;
|
||||
cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Check for RX Match Not Finished interrupt */
|
||||
@ -1029,68 +1026,77 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
|
||||
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;
|
||||
}
|
||||
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)
|
||||
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
bool berr_reporting = false;
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
|
||||
berr_reporting = true;
|
||||
cf.can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
|
||||
}
|
||||
|
||||
/* Check for Ack error interrupt */
|
||||
if (err_status & XCAN_ESR_ACKER_MASK) {
|
||||
stats->tx_errors++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_ACK;
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
if (berr_reporting) {
|
||||
cf.can_id |= CAN_ERR_ACK;
|
||||
cf.data[3] = CAN_ERR_PROT_LOC_ACK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for Bit error interrupt */
|
||||
if (err_status & XCAN_ESR_BERR_MASK) {
|
||||
stats->tx_errors++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT;
|
||||
cf->data[2] = CAN_ERR_PROT_BIT;
|
||||
if (berr_reporting) {
|
||||
cf.can_id |= CAN_ERR_PROT;
|
||||
cf.data[2] = CAN_ERR_PROT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for Stuff error interrupt */
|
||||
if (err_status & XCAN_ESR_STER_MASK) {
|
||||
stats->rx_errors++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT;
|
||||
cf->data[2] = CAN_ERR_PROT_STUFF;
|
||||
if (berr_reporting) {
|
||||
cf.can_id |= CAN_ERR_PROT;
|
||||
cf.data[2] = CAN_ERR_PROT_STUFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for Form error interrupt */
|
||||
if (err_status & XCAN_ESR_FMER_MASK) {
|
||||
stats->rx_errors++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT;
|
||||
cf->data[2] = CAN_ERR_PROT_FORM;
|
||||
if (berr_reporting) {
|
||||
cf.can_id |= CAN_ERR_PROT;
|
||||
cf.data[2] = CAN_ERR_PROT_FORM;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for CRC error interrupt */
|
||||
if (err_status & XCAN_ESR_CRCER_MASK) {
|
||||
stats->rx_errors++;
|
||||
if (skb) {
|
||||
cf->can_id |= CAN_ERR_PROT;
|
||||
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
if (berr_reporting) {
|
||||
cf.can_id |= CAN_ERR_PROT;
|
||||
cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
|
||||
}
|
||||
}
|
||||
priv->can.can_stats.bus_error++;
|
||||
}
|
||||
|
||||
if (skb) {
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += cf->can_dlc;
|
||||
netif_rx(skb);
|
||||
if (cf.can_id) {
|
||||
struct can_frame *skb_cf;
|
||||
struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf);
|
||||
|
||||
if (skb) {
|
||||
skb_cf->can_id |= cf.can_id;
|
||||
memcpy(skb_cf->data, cf.data, CAN_ERR_DLC);
|
||||
stats->rx_packets++;
|
||||
stats->rx_bytes += CAN_ERR_DLC;
|
||||
netif_rx(skb);
|
||||
}
|
||||
}
|
||||
|
||||
netdev_dbg(ndev, "%s: error status register:0x%x\n",
|
||||
@ -1651,7 +1657,6 @@ MODULE_DEVICE_TABLE(of, xcan_of_match);
|
||||
*/
|
||||
static int xcan_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res; /* IO mem resources */
|
||||
struct net_device *ndev;
|
||||
struct xcan_priv *priv;
|
||||
const struct of_device_id *of_id;
|
||||
@ -1663,8 +1668,7 @@ static int xcan_probe(struct platform_device *pdev)
|
||||
const char *hw_tx_max_property;
|
||||
|
||||
/* Get the virtual base address for the device */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
addr = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(addr)) {
|
||||
ret = PTR_ERR(addr);
|
||||
goto err;
|
||||
|
@ -1,22 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _CAN_PLATFORM_MCP251X_H
|
||||
#define _CAN_PLATFORM_MCP251X_H
|
||||
|
||||
/*
|
||||
*
|
||||
* CAN bus driver for Microchip 251x CAN Controller with SPI Interface
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
/*
|
||||
* struct mcp251x_platform_data - MCP251X SPI CAN controller platform data
|
||||
* @oscillator_frequency: - oscillator frequency in Hz
|
||||
*/
|
||||
|
||||
struct mcp251x_platform_data {
|
||||
unsigned long oscillator_frequency;
|
||||
};
|
||||
|
||||
#endif /* !_CAN_PLATFORM_MCP251X_H */
|
@ -15,9 +15,9 @@
|
||||
struct can_rx_offload {
|
||||
struct net_device *dev;
|
||||
|
||||
unsigned int (*mailbox_read)(struct can_rx_offload *offload,
|
||||
struct can_frame *cf,
|
||||
u32 *timestamp, unsigned int mb);
|
||||
struct sk_buff *(*mailbox_read)(struct can_rx_offload *offload,
|
||||
unsigned int mb, u32 *timestamp,
|
||||
bool drop);
|
||||
|
||||
struct sk_buff_head skb_queue;
|
||||
u32 skb_queue_len_max;
|
||||
@ -44,7 +44,6 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
unsigned int idx, u32 timestamp);
|
||||
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
||||
struct sk_buff *skb);
|
||||
void can_rx_offload_reset(struct can_rx_offload *offload);
|
||||
void can_rx_offload_del(struct can_rx_offload *offload);
|
||||
void can_rx_offload_enable(struct can_rx_offload *offload);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user