提交 e0580b50 编写于 作者: D David S. Miller

Merge tag 'linux-can-next-for-5.5-20191111' of...

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: NDavid S. Miller <davem@davemloft.net>
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -22,7 +23,6 @@ ...@@ -22,7 +23,6 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/can/platform/mcp251x.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include "generic.h" #include "generic.h"
...@@ -69,8 +69,9 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = { ...@@ -69,8 +69,9 @@ static struct pxa2xx_spi_chip mcp251x_chip_info4 = {
.gpio_cs = ICONTROL_MCP251x_nCS4 .gpio_cs = ICONTROL_MCP251x_nCS4
}; };
static struct mcp251x_platform_data mcp251x_info = { static const struct property_entry mcp251x_properties[] = {
.oscillator_frequency = 16E6, PROPERTY_ENTRY_U32("clock-frequency", 16000000),
{}
}; };
static struct spi_board_info mcp251x_board_info[] = { static struct spi_board_info mcp251x_board_info[] = {
...@@ -79,7 +80,7 @@ static struct spi_board_info mcp251x_board_info[] = { ...@@ -79,7 +80,7 @@ static struct spi_board_info mcp251x_board_info[] = {
.max_speed_hz = 6500000, .max_speed_hz = 6500000,
.bus_num = 3, .bus_num = 3,
.chip_select = 0, .chip_select = 0,
.platform_data = &mcp251x_info, .properties = mcp251x_properties,
.controller_data = &mcp251x_chip_info1, .controller_data = &mcp251x_chip_info1,
.irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ1) .irq = PXA_GPIO_TO_IRQ(ICONTROL_MCP251x_nIRQ1)
}, },
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/property.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/machine.h> #include <linux/gpio/machine.h>
#include <linux/serial_8250.h> #include <linux/serial_8250.h>
...@@ -27,7 +28,6 @@ ...@@ -27,7 +28,6 @@
#include <linux/platform_data/i2c-pxa.h> #include <linux/platform_data/i2c-pxa.h>
#include <linux/platform_data/pca953x.h> #include <linux/platform_data/pca953x.h>
#include <linux/apm-emulation.h> #include <linux/apm-emulation.h>
#include <linux/can/platform/mcp251x.h>
#include <linux/regulator/fixed.h> #include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
...@@ -428,14 +428,15 @@ static struct gpiod_lookup_table can_regulator_gpiod_table = { ...@@ -428,14 +428,15 @@ static struct gpiod_lookup_table can_regulator_gpiod_table = {
}, },
}; };
static struct mcp251x_platform_data zeus_mcp2515_pdata = { static const struct property_entry mcp251x_properties[] = {
.oscillator_frequency = 16*1000*1000, PROPERTY_ENTRY_U32("clock-frequency", 16000000),
{}
}; };
static struct spi_board_info zeus_spi_board_info[] = { static struct spi_board_info zeus_spi_board_info[] = {
[0] = { [0] = {
.modalias = "mcp2515", .modalias = "mcp2515",
.platform_data = &zeus_mcp2515_pdata, .properties = mcp251x_properties,
.irq = PXA_GPIO_TO_IRQ(ZEUS_CAN_GPIO), .irq = PXA_GPIO_TO_IRQ(ZEUS_CAN_GPIO),
.max_speed_hz = 1*1000*1000, .max_speed_hz = 1*1000*1000,
.bus_num = 3, .bus_num = 3,
......
...@@ -39,10 +39,11 @@ ...@@ -39,10 +39,11 @@
#include "c_can.h" #include "c_can.h"
#define DCAN_RAM_INIT_BIT (1 << 3) #define DCAN_RAM_INIT_BIT BIT(3)
static DEFINE_SPINLOCK(raminit_lock); 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 * architecture of different implementations. For example: 16-bit
* registers can be aligned to a 16-bit boundary or 32-bit boundary etc. * registers can be aligned to a 16-bit boundary or 32-bit boundary etc.
* Handle the same by providing a common read/write interface. * 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, ...@@ -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, 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]); 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, ...@@ -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, 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]); 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) ...@@ -144,13 +145,13 @@ static u32 c_can_plat_read_reg32(const struct c_can_priv *priv, enum reg index)
u32 val; u32 val;
val = priv->read_reg(priv, index); 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; return val;
} }
static void c_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index, static void c_can_plat_write_reg32(const struct c_can_priv *priv,
u32 val) enum reg index, u32 val)
{ {
priv->write_reg(priv, index + 1, val >> 16); priv->write_reg(priv, index + 1, val >> 16);
priv->write_reg(priv, index, val); 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) ...@@ -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]); return readl(priv->base + priv->regs[index]);
} }
static void d_can_plat_write_reg32(const struct c_can_priv *priv, enum reg index, static void d_can_plat_write_reg32(const struct c_can_priv *priv,
u32 val) enum reg index, u32 val)
{ {
writel(val, priv->base + priv->regs[index]); writel(val, priv->base + priv->regs[index]);
} }
......
...@@ -553,10 +553,9 @@ static void can_restart(struct net_device *dev) ...@@ -553,10 +553,9 @@ static void can_restart(struct net_device *dev)
/* send restart message upstream */ /* send restart message upstream */
skb = alloc_can_err_skb(dev, &cf); skb = alloc_can_err_skb(dev, &cf);
if (!skb) { if (!skb)
err = -ENOMEM;
goto restart; goto restart;
}
cf->can_id |= CAN_ERR_RESTARTED; cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb); netif_rx(skb);
......
...@@ -142,7 +142,7 @@ ...@@ -142,7 +142,7 @@
#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8 #define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1) #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_OVERFLOW BIT(7)
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) #define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5) #define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
...@@ -277,9 +277,9 @@ struct flexcan_priv { ...@@ -277,9 +277,9 @@ struct flexcan_priv {
u8 mb_size; u8 mb_size;
u8 clk_src; /* clock source of CAN Protocol Engine */ u8 clk_src; /* clock source of CAN Protocol Engine */
u64 rx_mask;
u64 tx_mask;
u32 reg_ctrl_default; u32 reg_ctrl_default;
u32 reg_imask1_default;
u32 reg_imask2_default;
struct clk *clk_ipg; struct clk *clk_ipg;
struct clk *clk_per; struct clk *clk_per;
...@@ -743,8 +743,6 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) ...@@ -743,8 +743,6 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
u32 timestamp; u32 timestamp;
int err; int err;
timestamp = priv->read(&regs->timer) << 16;
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK; flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) { if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
tx_state = unlikely(reg_esr & FLEXCAN_ESR_TX_WRN) ? 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) ...@@ -764,6 +762,8 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
if (likely(new_state == priv->can.state)) if (likely(new_state == priv->can.state))
return; return;
timestamp = priv->read(&regs->timer) << 16;
skb = alloc_can_err_skb(dev, &cf); skb = alloc_can_err_skb(dev, &cf);
if (unlikely(!skb)) if (unlikely(!skb))
return; return;
...@@ -778,21 +778,58 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr) ...@@ -778,21 +778,58 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
dev->stats.rx_fifo_errors++; 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) static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
{ {
return container_of(offload, struct flexcan_priv, offload); return container_of(offload, struct flexcan_priv, offload);
} }
static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, static struct sk_buff *flexcan_mailbox_read(struct can_rx_offload *offload,
struct can_frame *cf, unsigned int n, u32 *timestamp,
u32 *timestamp, unsigned int n) bool drop)
{ {
struct flexcan_priv *priv = rx_offload_to_priv(offload); struct flexcan_priv *priv = rx_offload_to_priv(offload);
struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_regs __iomem *regs = priv->regs;
struct flexcan_mb __iomem *mb; struct flexcan_mb __iomem *mb;
struct sk_buff *skb;
struct can_frame *cf;
u32 reg_ctrl, reg_id, reg_iflag1; u32 reg_ctrl, reg_id, reg_iflag1;
int i; int i;
if (unlikely(drop)) {
skb = ERR_PTR(-ENOBUFS);
goto mark_as_read;
}
mb = flexcan_get_mb(priv, n); mb = flexcan_get_mb(priv, n);
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { 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, ...@@ -806,7 +843,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
code = reg_ctrl & FLEXCAN_MB_CODE_MASK; code = reg_ctrl & FLEXCAN_MB_CODE_MASK;
if ((code != FLEXCAN_MB_CODE_RX_FULL) && if ((code != FLEXCAN_MB_CODE_RX_FULL) &&
(code != FLEXCAN_MB_CODE_RX_OVERRUN)) (code != FLEXCAN_MB_CODE_RX_OVERRUN))
return 0; return NULL;
if (code == FLEXCAN_MB_CODE_RX_OVERRUN) { if (code == FLEXCAN_MB_CODE_RX_OVERRUN) {
/* This MB was overrun, we lost data */ /* This MB was overrun, we lost data */
...@@ -816,11 +853,17 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, ...@@ -816,11 +853,17 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
} else { } else {
reg_iflag1 = priv->read(&regs->iflag1); reg_iflag1 = priv->read(&regs->iflag1);
if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE)) if (!(reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE))
return 0; return NULL;
reg_ctrl = priv->read(&mb->can_ctrl); 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 */ /* increase timstamp to full 32 bit */
*timestamp = reg_ctrl << 16; *timestamp = reg_ctrl << 16;
...@@ -839,16 +882,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload, ...@@ -839,16 +882,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
*(__be32 *)(cf->data + i) = data; *(__be32 *)(cf->data + i) = data;
} }
/* mark as read */ mark_as_read:
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
/* Clear IRQ */ flexcan_write64(priv, FLEXCAN_IFLAG_MB(n), &regs->iflag1);
if (n < 32) else
priv->write(BIT(n), &regs->iflag1);
else
priv->write(BIT(n - 32), &regs->iflag2);
} else {
priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1); priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, &regs->iflag1);
}
/* Read the Free Running Timer. It is optional but recommended /* Read the Free Running Timer. It is optional but recommended
* to unlock Mailbox as soon as possible and make it available * 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, ...@@ -856,20 +894,7 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
*/ */
priv->read(&regs->timer); priv->read(&regs->timer);
return 1; return skb;
}
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(&regs->iflag2) & priv->reg_imask2_default &
~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
iflag1 = priv->read(&regs->iflag1) & priv->reg_imask1_default;
return (u64)iflag2 << 32 | iflag1;
} }
static irqreturn_t flexcan_irq(int irq, void *dev_id) static irqreturn_t flexcan_irq(int irq, void *dev_id)
...@@ -879,18 +904,19 @@ 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_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_regs __iomem *regs = priv->regs;
irqreturn_t handled = IRQ_NONE; 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; enum can_state last_state = priv->can.state;
/* reception interrupt */ /* reception interrupt */
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
u64 reg_iflag; u64 reg_iflag_rx;
int ret; int ret;
while ((reg_iflag = flexcan_read_reg_iflag_rx(priv))) { while ((reg_iflag_rx = flexcan_read_reg_iflag_rx(priv))) {
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
ret = can_rx_offload_irq_offload_timestamp(&priv->offload, ret = can_rx_offload_irq_offload_timestamp(&priv->offload,
reg_iflag); reg_iflag_rx);
if (!ret) if (!ret)
break; break;
} }
...@@ -913,10 +939,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) ...@@ -913,10 +939,10 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
} }
} }
reg_iflag2 = priv->read(&regs->iflag2); reg_iflag_tx = flexcan_read_reg_iflag_tx(priv);
/* transmission complete interrupt */ /* 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); u32 reg_ctrl = priv->read(&priv->tx_mb->can_ctrl);
handled = IRQ_HANDLED; handled = IRQ_HANDLED;
...@@ -928,7 +954,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id) ...@@ -928,7 +954,7 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
/* after sending a RTR frame MB is in RX mode */ /* after sending a RTR frame MB is in RX mode */
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE, priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
&priv->tx_mb->can_ctrl); &priv->tx_mb->can_ctrl);
priv->write(FLEXCAN_IFLAG_MB(priv->tx_mb_idx), &regs->iflag2); flexcan_write64(priv, priv->tx_mask, &regs->iflag1);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
...@@ -1040,6 +1066,7 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -1040,6 +1066,7 @@ static int flexcan_chip_start(struct net_device *dev)
struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_priv *priv = netdev_priv(dev);
struct flexcan_regs __iomem *regs = priv->regs; struct flexcan_regs __iomem *regs = priv->regs;
u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr; u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
u64 reg_imask;
int err, i; int err, i;
struct flexcan_mb __iomem *mb; struct flexcan_mb __iomem *mb;
...@@ -1214,8 +1241,9 @@ static int flexcan_chip_start(struct net_device *dev) ...@@ -1214,8 +1241,9 @@ static int flexcan_chip_start(struct net_device *dev)
/* enable interrupts atomically */ /* enable interrupts atomically */
disable_irq(dev->irq); disable_irq(dev->irq);
priv->write(priv->reg_ctrl_default, &regs->ctrl); priv->write(priv->reg_ctrl_default, &regs->ctrl);
priv->write(priv->reg_imask1_default, &regs->imask1); reg_imask = priv->rx_mask | priv->tx_mask;
priv->write(priv->reg_imask2_default, &regs->imask2); priv->write(upper_32_bits(reg_imask), &regs->imask2);
priv->write(lower_32_bits(reg_imask), &regs->imask1);
enable_irq(dev->irq); enable_irq(dev->irq);
/* print chip status */ /* print chip status */
...@@ -1283,26 +1311,19 @@ static int flexcan_open(struct net_device *dev) ...@@ -1283,26 +1311,19 @@ static int flexcan_open(struct net_device *dev)
flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO); flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
priv->tx_mb_idx = priv->mb_count - 1; priv->tx_mb_idx = priv->mb_count - 1;
priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx); priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
priv->tx_mask = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
priv->reg_imask1_default = 0;
priv->reg_imask2_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
priv->offload.mailbox_read = flexcan_mailbox_read; priv->offload.mailbox_read = flexcan_mailbox_read;
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) { 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_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
priv->offload.mb_last = priv->mb_count - 2; priv->offload.mb_last = priv->mb_count - 2;
imask = GENMASK_ULL(priv->offload.mb_last, priv->rx_mask = GENMASK_ULL(priv->offload.mb_last,
priv->offload.mb_first); priv->offload.mb_first);
priv->reg_imask1_default |= imask;
priv->reg_imask2_default |= imask >> 32;
err = can_rx_offload_add_timestamp(dev, &priv->offload); err = can_rx_offload_add_timestamp(dev, &priv->offload);
} else { } else {
priv->reg_imask1_default |= FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | priv->rx_mask = FLEXCAN_IFLAG_RX_FIFO_OVERFLOW |
FLEXCAN_IFLAG_RX_FIFO_AVAILABLE; FLEXCAN_IFLAG_RX_FIFO_AVAILABLE;
err = can_rx_offload_add_fifo(dev, &priv->offload, err = can_rx_offload_add_fifo(dev, &priv->offload,
FLEXCAN_NAPI_WEIGHT); FLEXCAN_NAPI_WEIGHT);
...@@ -1534,7 +1555,6 @@ static int flexcan_probe(struct platform_device *pdev) ...@@ -1534,7 +1555,6 @@ static int flexcan_probe(struct platform_device *pdev)
struct net_device *dev; struct net_device *dev;
struct flexcan_priv *priv; struct flexcan_priv *priv;
struct regulator *reg_xceiver; struct regulator *reg_xceiver;
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL; struct clk *clk_ipg = NULL, *clk_per = NULL;
struct flexcan_regs __iomem *regs; struct flexcan_regs __iomem *regs;
int err, irq; int err, irq;
...@@ -1569,12 +1589,11 @@ static int flexcan_probe(struct platform_device *pdev) ...@@ -1569,12 +1589,11 @@ static int flexcan_probe(struct platform_device *pdev)
clock_freq = clk_get_rate(clk_per); clock_freq = clk_get_rate(clk_per);
} }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq <= 0) if (irq <= 0)
return -ENODEV; return -ENODEV;
regs = devm_ioremap_resource(&pdev->dev, mem); regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs)) if (IS_ERR(regs))
return PTR_ERR(regs); return PTR_ERR(regs);
......
...@@ -1652,7 +1652,6 @@ static int grcan_setup_netdev(struct platform_device *ofdev, ...@@ -1652,7 +1652,6 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
static int grcan_probe(struct platform_device *ofdev) static int grcan_probe(struct platform_device *ofdev)
{ {
struct device_node *np = ofdev->dev.of_node; struct device_node *np = ofdev->dev.of_node;
struct resource *res;
u32 sysid, ambafreq; u32 sysid, ambafreq;
int irq, err; int irq, err;
void __iomem *base; void __iomem *base;
...@@ -1672,8 +1671,7 @@ static int grcan_probe(struct platform_device *ofdev) ...@@ -1672,8 +1671,7 @@ static int grcan_probe(struct platform_device *ofdev)
goto exit_error; goto exit_error;
} }
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); base = devm_platform_ioremap_resource(ofdev, 0);
base = devm_ioremap_resource(&ofdev->dev, res);
if (IS_ERR(base)) { if (IS_ERR(base)) {
err = PTR_ERR(base); err = PTR_ERR(base);
goto exit_error; goto exit_error;
......
...@@ -942,13 +942,11 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) ...@@ -942,13 +942,11 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct net_device *ndev; struct net_device *ndev;
struct ifi_canfd_priv *priv; struct ifi_canfd_priv *priv;
struct resource *res;
void __iomem *addr; void __iomem *addr;
int irq, ret; int irq, ret;
u32 id, rev; u32 id, rev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_platform_ioremap_resource(pdev, 0);
addr = devm_ioremap_resource(dev, res);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (IS_ERR(addr) || irq < 0) if (IS_ERR(addr) || irq < 0)
return -EINVAL; return -EINVAL;
......
...@@ -123,6 +123,7 @@ enum m_can_reg { ...@@ -123,6 +123,7 @@ enum m_can_reg {
#define CCCR_CME_CANFD_BRS 0x2 #define CCCR_CME_CANFD_BRS 0x2
#define CCCR_TXP BIT(14) #define CCCR_TXP BIT(14)
#define CCCR_TEST BIT(7) #define CCCR_TEST BIT(7)
#define CCCR_DAR BIT(6)
#define CCCR_MON BIT(5) #define CCCR_MON BIT(5)
#define CCCR_CSR BIT(4) #define CCCR_CSR BIT(4)
#define CCCR_CSA BIT(3) #define CCCR_CSA BIT(3)
...@@ -777,6 +778,43 @@ static inline bool is_lec_err(u32 psr) ...@@ -777,6 +778,43 @@ static inline bool is_lec_err(u32 psr)
return psr && (psr != LEC_UNUSED); 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, static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
u32 psr) u32 psr)
{ {
...@@ -791,6 +829,11 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus, ...@@ -791,6 +829,11 @@ static int m_can_handle_bus_errors(struct net_device *dev, u32 irqstatus,
is_lec_err(psr)) is_lec_err(psr))
work_done += m_can_handle_lec_err(dev, psr & LEC_UNUSED); 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 */ /* other unproccessed error interrupts */
m_can_handle_other_err(dev, irqstatus); m_can_handle_other_err(dev, irqstatus);
...@@ -1135,7 +1178,7 @@ static void m_can_chip_config(struct net_device *dev) ...@@ -1135,7 +1178,7 @@ static void m_can_chip_config(struct net_device *dev)
if (cdev->version == 30) { if (cdev->version == 30) {
/* Version 3.0.x */ /* Version 3.0.x */
cccr &= ~(CCCR_TEST | CCCR_MON | cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_DAR |
(CCCR_CMR_MASK << CCCR_CMR_SHIFT) | (CCCR_CMR_MASK << CCCR_CMR_SHIFT) |
(CCCR_CME_MASK << CCCR_CME_SHIFT)); (CCCR_CME_MASK << CCCR_CME_SHIFT));
...@@ -1145,7 +1188,7 @@ static void m_can_chip_config(struct net_device *dev) ...@@ -1145,7 +1188,7 @@ static void m_can_chip_config(struct net_device *dev)
} else { } else {
/* Version 3.1.x or 3.2.x */ /* Version 3.1.x or 3.2.x */
cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE | cccr &= ~(CCCR_TEST | CCCR_MON | CCCR_BRSE | CCCR_FDOE |
CCCR_NISO); CCCR_NISO | CCCR_DAR);
/* Only 3.2.x has NISO Bit implemented */ /* Only 3.2.x has NISO Bit implemented */
if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) if (cdev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO)
...@@ -1165,6 +1208,10 @@ static void m_can_chip_config(struct net_device *dev) ...@@ -1165,6 +1208,10 @@ static void m_can_chip_config(struct net_device *dev)
if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) if (cdev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
cccr |= CCCR_MON; cccr |= CCCR_MON;
/* Disable Auto Retransmission (all versions) */
if (cdev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
cccr |= CCCR_DAR;
/* Write config */ /* Write config */
m_can_write(cdev, M_CAN_CCCR, cccr); m_can_write(cdev, M_CAN_CCCR, cccr);
m_can_write(cdev, M_CAN_TEST, test); 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) ...@@ -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 | m_can_dev->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_BERR_REPORTING | CAN_CTRLMODE_BERR_REPORTING |
CAN_CTRLMODE_FD; CAN_CTRLMODE_FD |
CAN_CTRLMODE_ONE_SHOT;
/* Set properties depending on M_CAN version */ /* Set properties depending on M_CAN version */
switch (m_can_dev->version) { switch (m_can_dev->version) {
......
// SPDX-License-Identifier: GPL-2.0-only // 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) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
* *
* Copyright (C) 2016 PEAK System-Technik GmbH * Copyright (C) 2016 PEAK System-Technik GmbH
...@@ -122,7 +121,8 @@ static int pucan_set_timing_slow(struct peak_canfd_priv *priv, ...@@ -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 = pucan_add_cmd(pucan_init_cmd(priv), PUCAN_CMD_TIMING_SLOW);
cmd->sjw_t = PUCAN_TSLOW_SJW_T(pbt->sjw - 1, 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->tseg1 = PUCAN_TSLOW_TSEG1(pbt->prop_seg + pbt->phase_seg1 - 1);
cmd->tseg2 = PUCAN_TSLOW_TSEG2(pbt->phase_seg2 - 1); cmd->tseg2 = PUCAN_TSLOW_TSEG2(pbt->phase_seg2 - 1);
cmd->brp = cpu_to_le16(PUCAN_TSLOW_BRP(pbt->brp - 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) ...@@ -232,6 +232,20 @@ static int pucan_setup_rx_barrier(struct peak_canfd_priv *priv)
return pucan_write_cmd(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 */ /* handle the reception of one CAN frame */
static int pucan_handle_can_rx(struct peak_canfd_priv *priv, static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
struct pucan_rx_msg *msg) struct pucan_rx_msg *msg)
...@@ -299,7 +313,7 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv, ...@@ -299,7 +313,7 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
stats->rx_bytes += cf->len; stats->rx_bytes += cf->len;
stats->rx_packets++; stats->rx_packets++;
netif_rx(skb); pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
return 0; return 0;
} }
...@@ -325,7 +339,6 @@ static int pucan_handle_status(struct peak_canfd_priv *priv, ...@@ -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 */ /* this STATUS is the CNF of the RX_BARRIER: Tx path can be setup */
if (pucan_status_is_rx_barrier(msg)) { if (pucan_status_is_rx_barrier(msg)) {
if (priv->enable_tx_path) { if (priv->enable_tx_path) {
int err = priv->enable_tx_path(priv); int err = priv->enable_tx_path(priv);
...@@ -393,7 +406,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv, ...@@ -393,7 +406,7 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
stats->rx_packets++; stats->rx_packets++;
stats->rx_bytes += cf->can_dlc; stats->rx_bytes += cf->can_dlc;
netif_rx(skb); pucan_netif_rx(skb, msg->ts_low, msg->ts_high);
return 0; return 0;
} }
......
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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) 2003-2011 PEAK System-Technik GmbH
* Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.com> * Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.com>
......
// SPDX-License-Identifier: GPL-2.0-only // 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) 2012 Stephane Grosjean <s.grosjean@peak-system.com>
* *
* Derived from the PCAN project file driver/src/pcan_pci.c: * Derived from the PCAN project file driver/src/pcan_pci.c:
...@@ -841,7 +840,8 @@ static int peak_pciefd_probe(struct pci_dev *pdev, ...@@ -841,7 +840,8 @@ static int peak_pciefd_probe(struct pci_dev *pdev,
/* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while /* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while
* the probe() function must return a negative errno in case of failure * 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); return pcibios_err_to_errno(err);
} }
......
...@@ -744,7 +744,6 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -744,7 +744,6 @@ static int rcar_can_probe(struct platform_device *pdev)
{ {
struct rcar_can_priv *priv; struct rcar_can_priv *priv;
struct net_device *ndev; struct net_device *ndev;
struct resource *mem;
void __iomem *addr; void __iomem *addr;
u32 clock_select = CLKR_CLKP1; u32 clock_select = CLKR_CLKP1;
int err = -ENODEV; int err = -ENODEV;
...@@ -759,8 +758,7 @@ static int rcar_can_probe(struct platform_device *pdev) ...@@ -759,8 +758,7 @@ static int rcar_can_probe(struct platform_device *pdev)
goto fail; goto fail;
} }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_platform_ioremap_resource(pdev, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) { if (IS_ERR(addr)) {
err = PTR_ERR(addr); err = PTR_ERR(addr);
goto fail; goto fail;
......
...@@ -1630,7 +1630,6 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch) ...@@ -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) static int rcar_canfd_probe(struct platform_device *pdev)
{ {
struct resource *mem;
void __iomem *addr; void __iomem *addr;
u32 sts, ch, fcan_freq; u32 sts, ch, fcan_freq;
struct rcar_canfd_global *gpriv; struct rcar_canfd_global *gpriv;
...@@ -1704,8 +1703,7 @@ static int rcar_canfd_probe(struct platform_device *pdev) ...@@ -1704,8 +1703,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
/* CANFD clock is further divided by (1/2) within the IP */ /* CANFD clock is further divided by (1/2) within the IP */
fcan_freq /= 2; fcan_freq /= 2;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_platform_ioremap_resource(pdev, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) { if (IS_ERR(addr)) {
err = PTR_ERR(addr); err = PTR_ERR(addr);
goto fail_dev; goto fail_dev;
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /* Copyright (c) 2014 Protonic Holland,
* Copyright (c) 2014 David Jander, Protonic Holland * David Jander
* Copyright (C) 2014-2017 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> * Copyright (C) 2014-2017 Pengutronix,
* Marc Kleine-Budde <kernel@pengutronix.de>
*/ */
#include <linux/can/dev.h> #include <linux/can/dev.h>
...@@ -11,14 +12,17 @@ struct can_rx_offload_cb { ...@@ -11,14 +12,17 @@ struct can_rx_offload_cb {
u32 timestamp; 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)); BUILD_BUG_ON(sizeof(struct can_rx_offload_cb) > sizeof(skb->cb));
return (struct can_rx_offload_cb *)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) if (offload->inc)
return a <= b; return a <= b;
...@@ -26,7 +30,8 @@ static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned in ...@@ -26,7 +30,8 @@ static inline bool can_rx_offload_le(struct can_rx_offload *offload, unsigned in
return a >= b; 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) if (offload->inc)
return (*val)++; return (*val)++;
...@@ -36,7 +41,9 @@ static inline unsigned int can_rx_offload_inc(struct can_rx_offload *offload, un ...@@ -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) 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 *dev = offload->dev;
struct net_device_stats *stats = &dev->stats; struct net_device_stats *stats = &dev->stats;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -65,8 +72,9 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota) ...@@ -65,8 +72,9 @@ static int can_rx_offload_napi_poll(struct napi_struct *napi, int quota)
return work_done; return work_done;
} }
static inline void __skb_queue_add_sort(struct sk_buff_head *head, struct sk_buff *new, static inline void
int (*compare)(struct sk_buff *a, struct sk_buff *b)) __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; struct sk_buff *pos, *insert = NULL;
...@@ -101,7 +109,7 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b) ...@@ -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_a = can_rx_offload_get_cb(a);
cb_b = can_rx_offload_get_cb(b); 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. * difference steady around the u32 overflow.
*/ */
return cb_b->timestamp - cb_a->timestamp; 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) ...@@ -131,75 +139,40 @@ static int can_rx_offload_compare(struct sk_buff *a, struct sk_buff *b)
static struct sk_buff * static struct sk_buff *
can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n) 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_rx_offload_cb *cb;
struct can_frame *cf; bool drop = false;
int ret; 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,
&timestamp, 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); /* If queue is full drop frame */
ret = offload->mailbox_read(offload, cf, &cb->timestamp, n); if (unlikely(skb_queue_len(&offload->skb_queue) >
offload->skb_queue_len_max))
drop = true;
skb = offload->mailbox_read(offload, n, &timestamp, drop);
/* Mailbox was empty. */ /* Mailbox was empty. */
if (unlikely(!ret)) { if (unlikely(!skb))
kfree_skb(skb);
return NULL; 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_dropped++;
offload->dev->stats.rx_fifo_errors++; offload->dev->stats.rx_fifo_errors++;
return ERR_PTR(ret); return skb;
} }
/* Mailbox was read. */ /* Mailbox was read. */
cb = can_rx_offload_get_cb(skb);
cb->timestamp = timestamp;
return skb; 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; struct sk_buff_head skb_queue;
unsigned int i; unsigned int i;
...@@ -229,8 +202,8 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 pen ...@@ -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); skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
spin_unlock_irqrestore(&offload->skb_queue.lock, flags); spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
if ((queue_len = skb_queue_len(&offload->skb_queue)) > queue_len = skb_queue_len(&offload->skb_queue);
(offload->skb_queue_len_max / 8)) if (queue_len > offload->skb_queue_len_max / 8)
netdev_dbg(offload->dev, "%s: queue_len=%d\n", netdev_dbg(offload->dev, "%s: queue_len=%d\n",
__func__, queue_len); __func__, queue_len);
...@@ -328,7 +301,9 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload, ...@@ -328,7 +301,9 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
} }
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail); 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; offload->dev = dev;
...@@ -337,7 +312,6 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo ...@@ -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; offload->skb_queue_len_max *= 4;
skb_queue_head_init(&offload->skb_queue); skb_queue_head_init(&offload->skb_queue);
can_rx_offload_reset(offload);
netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight); netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
dev_dbg(dev->dev.parent, "%s: skb_queue_len_max=%d\n", 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 ...@@ -346,7 +320,8 @@ static int can_rx_offload_init_queue(struct net_device *dev, struct can_rx_offlo
return 0; 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; unsigned int weight;
...@@ -366,7 +341,8 @@ int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload * ...@@ -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); 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) if (!offload->mailbox_read)
return -EINVAL; return -EINVAL;
...@@ -377,7 +353,6 @@ EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo); ...@@ -377,7 +353,6 @@ EXPORT_SYMBOL_GPL(can_rx_offload_add_fifo);
void can_rx_offload_enable(struct can_rx_offload *offload) void can_rx_offload_enable(struct can_rx_offload *offload)
{ {
can_rx_offload_reset(offload);
napi_enable(&offload->napi); napi_enable(&offload->napi);
} }
EXPORT_SYMBOL_GPL(can_rx_offload_enable); EXPORT_SYMBOL_GPL(can_rx_offload_enable);
...@@ -388,8 +363,3 @@ void can_rx_offload_del(struct can_rx_offload *offload) ...@@ -388,8 +363,3 @@ void can_rx_offload_del(struct can_rx_offload *offload)
skb_queue_purge(&offload->skb_queue); skb_queue_purge(&offload->skb_queue);
} }
EXPORT_SYMBOL_GPL(can_rx_offload_del); 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 @@ ...@@ -22,7 +22,6 @@
#include <linux/can/core.h> #include <linux/can/core.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/can/led.h> #include <linux/can/led.h>
#include <linux/can/platform/mcp251x.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -321,6 +320,18 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, u8 val) ...@@ -321,6 +320,18 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, u8 val)
mcp251x_spi_trans(spi, 3); 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, static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
u8 mask, u8 val) u8 mask, u8 val)
{ {
...@@ -457,6 +468,39 @@ static void mcp251x_hw_sleep(struct spi_device *spi) ...@@ -457,6 +468,39 @@ static void mcp251x_hw_sleep(struct spi_device *spi)
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP); 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, static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
struct net_device *net) struct net_device *net)
{ {
...@@ -646,8 +690,7 @@ static int mcp251x_stop(struct net_device *net) ...@@ -646,8 +690,7 @@ static int mcp251x_stop(struct net_device *net)
mutex_lock(&priv->mcp_lock); mutex_lock(&priv->mcp_lock);
/* Disable and clear pending interrupts */ /* Disable and clear pending interrupts */
mcp251x_write_reg(spi, CANINTE, 0x00); mcp251x_write_2regs(spi, CANINTE, 0x00, 0x00);
mcp251x_write_reg(spi, CANINTF, 0x00);
mcp251x_write_reg(spi, TXBCTRL(0), 0); mcp251x_write_reg(spi, TXBCTRL(0), 0);
mcp251x_clean(net); mcp251x_clean(net);
...@@ -715,8 +758,12 @@ static void mcp251x_restart_work_handler(struct work_struct *ws) ...@@ -715,8 +758,12 @@ static void mcp251x_restart_work_handler(struct work_struct *ws)
mutex_lock(&priv->mcp_lock); mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) { if (priv->after_suspend) {
mcp251x_hw_reset(spi); if (priv->after_suspend & AFTER_SUSPEND_POWER) {
mcp251x_setup(net, spi); mcp251x_hw_reset(spi);
mcp251x_setup(net, spi);
} else {
mcp251x_hw_wake(spi);
}
priv->force_quit = 0; priv->force_quit = 0;
if (priv->after_suspend & AFTER_SUSPEND_RESTART) { if (priv->after_suspend & AFTER_SUSPEND_RESTART) {
mcp251x_set_normal_mode(spi); mcp251x_set_normal_mode(spi);
...@@ -913,7 +960,7 @@ static int mcp251x_open(struct net_device *net) ...@@ -913,7 +960,7 @@ static int mcp251x_open(struct net_device *net)
INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
ret = mcp251x_hw_reset(spi); ret = mcp251x_hw_wake(spi);
if (ret) if (ret)
goto out_free_wq; goto out_free_wq;
ret = mcp251x_setup(net, spi); ret = mcp251x_setup(net, spi);
...@@ -986,19 +1033,19 @@ MODULE_DEVICE_TABLE(spi, mcp251x_id_table); ...@@ -986,19 +1033,19 @@ MODULE_DEVICE_TABLE(spi, mcp251x_id_table);
static int mcp251x_can_probe(struct spi_device *spi) static int mcp251x_can_probe(struct spi_device *spi)
{ {
const void *match = device_get_match_data(&spi->dev); const void *match = device_get_match_data(&spi->dev);
struct mcp251x_platform_data *pdata = dev_get_platdata(&spi->dev);
struct net_device *net; struct net_device *net;
struct mcp251x_priv *priv; struct mcp251x_priv *priv;
struct clk *clk; struct clk *clk;
int freq, ret; u32 freq;
int ret;
clk = devm_clk_get_optional(&spi->dev, NULL); clk = devm_clk_get_optional(&spi->dev, NULL);
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
freq = clk_get_rate(clk); freq = clk_get_rate(clk);
if (freq == 0 && pdata) if (freq == 0)
freq = pdata->oscillator_frequency; device_property_read_u32(&spi->dev, "clock-frequency", &freq);
/* Sanity check */ /* Sanity check */
if (freq < 1000000 || freq > 25000000) if (freq < 1000000 || freq > 25000000)
...@@ -1155,13 +1202,13 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev) ...@@ -1155,13 +1202,13 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev)
if (priv->after_suspend & AFTER_SUSPEND_POWER) if (priv->after_suspend & AFTER_SUSPEND_POWER)
mcp251x_power_enable(priv->power, 1); 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); mcp251x_power_enable(priv->transceiver, 1);
if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP))
queue_work(priv->wq, &priv->restart_work); queue_work(priv->wq, &priv->restart_work);
} else { else
priv->after_suspend = 0; priv->after_suspend = 0;
}
priv->force_quit = 0; priv->force_quit = 0;
enable_irq(spi->irq); enable_irq(spi->irq);
......
...@@ -771,7 +771,6 @@ static int sun4ican_remove(struct platform_device *pdev) ...@@ -771,7 +771,6 @@ static int sun4ican_remove(struct platform_device *pdev)
static int sun4ican_probe(struct platform_device *pdev) static int sun4ican_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct resource *mem;
struct clk *clk; struct clk *clk;
void __iomem *addr; void __iomem *addr;
int err, irq; int err, irq;
...@@ -791,8 +790,7 @@ static int sun4ican_probe(struct platform_device *pdev) ...@@ -791,8 +790,7 @@ static int sun4ican_probe(struct platform_device *pdev)
goto exit; goto exit;
} }
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_platform_ioremap_resource(pdev, 0);
addr = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(addr)) { if (IS_ERR(addr)) {
err = -EBUSY; err = -EBUSY;
goto exit; goto exit;
......
...@@ -535,15 +535,28 @@ struct ti_hecc_priv *rx_offload_to_priv(struct can_rx_offload *offload) ...@@ -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); return container_of(offload, struct ti_hecc_priv, offload);
} }
static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload, static struct sk_buff *ti_hecc_mailbox_read(struct can_rx_offload *offload,
struct can_frame *cf, unsigned int mbxno, u32 *timestamp,
u32 *timestamp, unsigned int mbxno) bool drop)
{ {
struct ti_hecc_priv *priv = rx_offload_to_priv(offload); struct ti_hecc_priv *priv = rx_offload_to_priv(offload);
struct sk_buff *skb;
struct can_frame *cf;
u32 data, mbx_mask; u32 data, mbx_mask;
int ret = 1;
mbx_mask = BIT(mbxno); 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); data = hecc_read_mbx(priv, mbxno, HECC_CANMID);
if (data & HECC_CANMID_IDE) if (data & HECC_CANMID_IDE)
cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG; 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, ...@@ -578,11 +591,12 @@ static unsigned int ti_hecc_mailbox_read(struct can_rx_offload *offload,
*/ */
if (unlikely(mbxno == HECC_RX_LAST_MBOX && if (unlikely(mbxno == HECC_RX_LAST_MBOX &&
hecc_read(priv, HECC_CANRML) & mbx_mask)) hecc_read(priv, HECC_CANRML) & mbx_mask))
ret = -ENOBUFS; skb = ERR_PTR(-ENOBUFS);
mark_as_read:
hecc_write(priv, HECC_CANRMP, mbx_mask); hecc_write(priv, HECC_CANRMP, mbx_mask);
return ret; return skb;
} }
static int ti_hecc_error(struct net_device *ndev, int int_status, static int ti_hecc_error(struct net_device *ndev, int int_status,
......
...@@ -194,7 +194,7 @@ struct xcan_devtype_data { ...@@ -194,7 +194,7 @@ struct xcan_devtype_data {
*/ */
struct xcan_priv { struct xcan_priv {
struct can_priv can; 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_head;
unsigned int tx_tail; unsigned int tx_tail;
unsigned int tx_max; unsigned int tx_max;
...@@ -400,7 +400,7 @@ static int xcan_set_bittiming(struct net_device *ndev) ...@@ -400,7 +400,7 @@ static int xcan_set_bittiming(struct net_device *ndev)
XCAN_SR_CONFIG_MASK; XCAN_SR_CONFIG_MASK;
if (!is_config_mode) { if (!is_config_mode) {
netdev_alert(ndev, 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; return -EPERM;
} }
...@@ -470,7 +470,13 @@ static int xcan_chip_start(struct net_device *ndev) ...@@ -470,7 +470,13 @@ static int xcan_chip_start(struct net_device *ndev)
if (err < 0) if (err < 0)
return err; 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 | ier = XCAN_IXR_TXOK_MASK | XCAN_IXR_BSOFF_MASK |
XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK | XCAN_IXR_WKUP_MASK | XCAN_IXR_SLP_MASK |
XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK | XCAN_IXR_ERROR_MASK | XCAN_IXR_RXOFLW_MASK |
...@@ -482,11 +488,10 @@ static int xcan_chip_start(struct net_device *ndev) ...@@ -482,11 +488,10 @@ static int xcan_chip_start(struct net_device *ndev)
priv->write_reg(priv, XCAN_IER_OFFSET, ier); priv->write_reg(priv, XCAN_IER_OFFSET, ier);
/* Check whether it is loopback mode or normal mode */ /* 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; reg_msr = XCAN_MSR_LBACK_MASK;
} else { else
reg_msr = 0x0; reg_msr = 0x0;
}
/* enable the first extended filter, if any, as cores with extended /* enable the first extended filter, if any, as cores with extended
* filtering default to non-receipt if all filters are disabled * 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) ...@@ -981,12 +986,9 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
{ {
struct xcan_priv *priv = netdev_priv(ndev); struct xcan_priv *priv = netdev_priv(ndev);
struct net_device_stats *stats = &ndev->stats; struct net_device_stats *stats = &ndev->stats;
struct can_frame *cf; struct can_frame cf = { };
struct sk_buff *skb;
u32 err_status; u32 err_status;
skb = alloc_can_err_skb(ndev, &cf);
err_status = priv->read_reg(priv, XCAN_ESR_OFFSET); err_status = priv->read_reg(priv, XCAN_ESR_OFFSET);
priv->write_reg(priv, XCAN_ESR_OFFSET, err_status); priv->write_reg(priv, XCAN_ESR_OFFSET, err_status);
...@@ -996,32 +998,27 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) ...@@ -996,32 +998,27 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
/* Leave device in Config Mode in bus-off state */ /* Leave device in Config Mode in bus-off state */
priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK); priv->write_reg(priv, XCAN_SRR_OFFSET, XCAN_SRR_RESET_MASK);
can_bus_off(ndev); can_bus_off(ndev);
if (skb) cf.can_id |= CAN_ERR_BUSOFF;
cf->can_id |= CAN_ERR_BUSOFF;
} else { } else {
enum can_state new_state = xcan_current_error_state(ndev); enum can_state new_state = xcan_current_error_state(ndev);
if (new_state != priv->can.state) 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 */ /* Check for Arbitration lost interrupt */
if (isr & XCAN_IXR_ARBLST_MASK) { if (isr & XCAN_IXR_ARBLST_MASK) {
priv->can.can_stats.arbitration_lost++; priv->can.can_stats.arbitration_lost++;
if (skb) { cf.can_id |= CAN_ERR_LOSTARB;
cf->can_id |= CAN_ERR_LOSTARB; cf.data[0] = CAN_ERR_LOSTARB_UNSPEC;
cf->data[0] = CAN_ERR_LOSTARB_UNSPEC;
}
} }
/* Check for RX FIFO Overflow interrupt */ /* Check for RX FIFO Overflow interrupt */
if (isr & XCAN_IXR_RXOFLW_MASK) { if (isr & XCAN_IXR_RXOFLW_MASK) {
stats->rx_over_errors++; stats->rx_over_errors++;
stats->rx_errors++; stats->rx_errors++;
if (skb) { cf.can_id |= CAN_ERR_CRTL;
cf->can_id |= CAN_ERR_CRTL; cf.data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
}
} }
/* Check for RX Match Not Finished interrupt */ /* Check for RX Match Not Finished interrupt */
...@@ -1029,68 +1026,77 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr) ...@@ -1029,68 +1026,77 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
stats->rx_dropped++; stats->rx_dropped++;
stats->rx_errors++; stats->rx_errors++;
netdev_err(ndev, "RX match not finished, frame discarded\n"); netdev_err(ndev, "RX match not finished, frame discarded\n");
if (skb) { cf.can_id |= CAN_ERR_CRTL;
cf->can_id |= CAN_ERR_CRTL; cf.data[1] |= CAN_ERR_CRTL_UNSPEC;
cf->data[1] |= CAN_ERR_CRTL_UNSPEC;
}
} }
/* Check for error interrupt */ /* Check for error interrupt */
if (isr & XCAN_IXR_ERROR_MASK) { if (isr & XCAN_IXR_ERROR_MASK) {
if (skb) bool berr_reporting = false;
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
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 */ /* Check for Ack error interrupt */
if (err_status & XCAN_ESR_ACKER_MASK) { if (err_status & XCAN_ESR_ACKER_MASK) {
stats->tx_errors++; stats->tx_errors++;
if (skb) { if (berr_reporting) {
cf->can_id |= CAN_ERR_ACK; cf.can_id |= CAN_ERR_ACK;
cf->data[3] = CAN_ERR_PROT_LOC_ACK; cf.data[3] = CAN_ERR_PROT_LOC_ACK;
} }
} }
/* Check for Bit error interrupt */ /* Check for Bit error interrupt */
if (err_status & XCAN_ESR_BERR_MASK) { if (err_status & XCAN_ESR_BERR_MASK) {
stats->tx_errors++; stats->tx_errors++;
if (skb) { if (berr_reporting) {
cf->can_id |= CAN_ERR_PROT; cf.can_id |= CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_BIT; cf.data[2] = CAN_ERR_PROT_BIT;
} }
} }
/* Check for Stuff error interrupt */ /* Check for Stuff error interrupt */
if (err_status & XCAN_ESR_STER_MASK) { if (err_status & XCAN_ESR_STER_MASK) {
stats->rx_errors++; stats->rx_errors++;
if (skb) { if (berr_reporting) {
cf->can_id |= CAN_ERR_PROT; cf.can_id |= CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_STUFF; cf.data[2] = CAN_ERR_PROT_STUFF;
} }
} }
/* Check for Form error interrupt */ /* Check for Form error interrupt */
if (err_status & XCAN_ESR_FMER_MASK) { if (err_status & XCAN_ESR_FMER_MASK) {
stats->rx_errors++; stats->rx_errors++;
if (skb) { if (berr_reporting) {
cf->can_id |= CAN_ERR_PROT; cf.can_id |= CAN_ERR_PROT;
cf->data[2] = CAN_ERR_PROT_FORM; cf.data[2] = CAN_ERR_PROT_FORM;
} }
} }
/* Check for CRC error interrupt */ /* Check for CRC error interrupt */
if (err_status & XCAN_ESR_CRCER_MASK) { if (err_status & XCAN_ESR_CRCER_MASK) {
stats->rx_errors++; stats->rx_errors++;
if (skb) { if (berr_reporting) {
cf->can_id |= CAN_ERR_PROT; cf.can_id |= CAN_ERR_PROT;
cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ; cf.data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
} }
} }
priv->can.can_stats.bus_error++; priv->can.can_stats.bus_error++;
} }
if (skb) { if (cf.can_id) {
stats->rx_packets++; struct can_frame *skb_cf;
stats->rx_bytes += cf->can_dlc; struct sk_buff *skb = alloc_can_err_skb(ndev, &skb_cf);
netif_rx(skb);
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", netdev_dbg(ndev, "%s: error status register:0x%x\n",
...@@ -1651,7 +1657,6 @@ MODULE_DEVICE_TABLE(of, xcan_of_match); ...@@ -1651,7 +1657,6 @@ MODULE_DEVICE_TABLE(of, xcan_of_match);
*/ */
static int xcan_probe(struct platform_device *pdev) static int xcan_probe(struct platform_device *pdev)
{ {
struct resource *res; /* IO mem resources */
struct net_device *ndev; struct net_device *ndev;
struct xcan_priv *priv; struct xcan_priv *priv;
const struct of_device_id *of_id; const struct of_device_id *of_id;
...@@ -1663,8 +1668,7 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1663,8 +1668,7 @@ static int xcan_probe(struct platform_device *pdev)
const char *hw_tx_max_property; const char *hw_tx_max_property;
/* Get the virtual base address for the device */ /* Get the virtual base address for the device */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_platform_ioremap_resource(pdev, 0);
addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(addr)) { if (IS_ERR(addr)) {
ret = PTR_ERR(addr); ret = PTR_ERR(addr);
goto err; goto err;
......
/* 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 @@ ...@@ -15,9 +15,9 @@
struct can_rx_offload { struct can_rx_offload {
struct net_device *dev; struct net_device *dev;
unsigned int (*mailbox_read)(struct can_rx_offload *offload, struct sk_buff *(*mailbox_read)(struct can_rx_offload *offload,
struct can_frame *cf, unsigned int mb, u32 *timestamp,
u32 *timestamp, unsigned int mb); bool drop);
struct sk_buff_head skb_queue; struct sk_buff_head skb_queue;
u32 skb_queue_len_max; u32 skb_queue_len_max;
...@@ -44,7 +44,6 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload, ...@@ -44,7 +44,6 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
unsigned int idx, u32 timestamp); unsigned int idx, u32 timestamp);
int can_rx_offload_queue_tail(struct can_rx_offload *offload, int can_rx_offload_queue_tail(struct can_rx_offload *offload,
struct sk_buff *skb); 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_del(struct can_rx_offload *offload);
void can_rx_offload_enable(struct can_rx_offload *offload); void can_rx_offload_enable(struct can_rx_offload *offload);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册