|
@@ -135,13 +135,12 @@
|
|
|
|
|
|
/* FLEXCAN interrupt flag register (IFLAG) bits */
|
|
|
/* Errata ERR005829 step7: Reserve first valid MB */
|
|
|
-#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
|
|
|
-#define FLEXCAN_TX_MB_OFF_FIFO 9
|
|
|
+#define FLEXCAN_TX_MB_RESERVED_OFF_FIFO 8
|
|
|
#define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP 0
|
|
|
-#define FLEXCAN_TX_MB_OFF_TIMESTAMP 1
|
|
|
-#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_OFF_TIMESTAMP + 1)
|
|
|
-#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST 63
|
|
|
-#define FLEXCAN_IFLAG_MB(x) BIT(x)
|
|
|
+#define FLEXCAN_TX_MB 63
|
|
|
+#define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST (FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP + 1)
|
|
|
+#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST (FLEXCAN_TX_MB - 1)
|
|
|
+#define FLEXCAN_IFLAG_MB(x) BIT(x & 0x1f)
|
|
|
#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
|
|
|
#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
|
|
|
#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
|
|
@@ -259,9 +258,7 @@ struct flexcan_priv {
|
|
|
struct can_rx_offload offload;
|
|
|
|
|
|
struct flexcan_regs __iomem *regs;
|
|
|
- struct flexcan_mb __iomem *tx_mb;
|
|
|
struct flexcan_mb __iomem *tx_mb_reserved;
|
|
|
- u8 tx_mb_idx;
|
|
|
u32 reg_ctrl_default;
|
|
|
u32 reg_imask1_default;
|
|
|
u32 reg_imask2_default;
|
|
@@ -515,6 +512,7 @@ static int flexcan_get_berr_counter(const struct net_device *dev,
|
|
|
static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
|
{
|
|
|
const struct flexcan_priv *priv = netdev_priv(dev);
|
|
|
+ struct flexcan_regs __iomem *regs = priv->regs;
|
|
|
struct can_frame *cf = (struct can_frame *)skb->data;
|
|
|
u32 can_id;
|
|
|
u32 data;
|
|
@@ -537,17 +535,17 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
|
|
|
|
|
|
if (cf->can_dlc > 0) {
|
|
|
data = be32_to_cpup((__be32 *)&cf->data[0]);
|
|
|
- priv->write(data, &priv->tx_mb->data[0]);
|
|
|
+ priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[0]);
|
|
|
}
|
|
|
if (cf->can_dlc > 4) {
|
|
|
data = be32_to_cpup((__be32 *)&cf->data[4]);
|
|
|
- priv->write(data, &priv->tx_mb->data[1]);
|
|
|
+ priv->write(data, ®s->mb[FLEXCAN_TX_MB].data[1]);
|
|
|
}
|
|
|
|
|
|
can_put_echo_skb(skb, dev, 0);
|
|
|
|
|
|
- priv->write(can_id, &priv->tx_mb->can_id);
|
|
|
- priv->write(ctrl, &priv->tx_mb->can_ctrl);
|
|
|
+ priv->write(can_id, ®s->mb[FLEXCAN_TX_MB].can_id);
|
|
|
+ priv->write(ctrl, ®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
|
|
|
|
|
/* Errata ERR005829 step8:
|
|
|
* Write twice INACTIVE(0x8) code to first MB.
|
|
@@ -563,9 +561,13 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
|
|
|
static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
|
|
|
{
|
|
|
struct flexcan_priv *priv = netdev_priv(dev);
|
|
|
+ struct flexcan_regs __iomem *regs = priv->regs;
|
|
|
struct sk_buff *skb;
|
|
|
struct can_frame *cf;
|
|
|
bool rx_errors = false, tx_errors = false;
|
|
|
+ u32 timestamp;
|
|
|
+
|
|
|
+ timestamp = priv->read(®s->timer) << 16;
|
|
|
|
|
|
skb = alloc_can_err_skb(dev, &cf);
|
|
|
if (unlikely(!skb))
|
|
@@ -612,17 +614,21 @@ static void flexcan_irq_bus_err(struct net_device *dev, u32 reg_esr)
|
|
|
if (tx_errors)
|
|
|
dev->stats.tx_errors++;
|
|
|
|
|
|
- can_rx_offload_irq_queue_err_skb(&priv->offload, skb);
|
|
|
+ can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
|
|
}
|
|
|
|
|
|
static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
|
|
{
|
|
|
struct flexcan_priv *priv = netdev_priv(dev);
|
|
|
+ struct flexcan_regs __iomem *regs = priv->regs;
|
|
|
struct sk_buff *skb;
|
|
|
struct can_frame *cf;
|
|
|
enum can_state new_state, rx_state, tx_state;
|
|
|
int flt;
|
|
|
struct can_berr_counter bec;
|
|
|
+ u32 timestamp;
|
|
|
+
|
|
|
+ timestamp = priv->read(®s->timer) << 16;
|
|
|
|
|
|
flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
|
|
|
if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
|
|
@@ -652,7 +658,7 @@ static void flexcan_irq_state(struct net_device *dev, u32 reg_esr)
|
|
|
if (unlikely(new_state == CAN_STATE_BUS_OFF))
|
|
|
can_bus_off(dev);
|
|
|
|
|
|
- can_rx_offload_irq_queue_err_skb(&priv->offload, skb);
|
|
|
+ can_rx_offload_queue_sorted(&priv->offload, skb, timestamp);
|
|
|
}
|
|
|
|
|
|
static inline struct flexcan_priv *rx_offload_to_priv(struct can_rx_offload *offload)
|
|
@@ -720,9 +726,14 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
|
|
|
priv->write(BIT(n - 32), ®s->iflag2);
|
|
|
} else {
|
|
|
priv->write(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1);
|
|
|
- priv->read(®s->timer);
|
|
|
}
|
|
|
|
|
|
+ /* Read the Free Running Timer. It is optional but recommended
|
|
|
+ * to unlock Mailbox as soon as possible and make it available
|
|
|
+ * for reception.
|
|
|
+ */
|
|
|
+ priv->read(®s->timer);
|
|
|
+
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -732,9 +743,9 @@ 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;
|
|
|
- iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default &
|
|
|
- ~FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
|
|
+ iflag2 = priv->read(®s->iflag2) & priv->reg_imask2_default &
|
|
|
+ ~FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB);
|
|
|
+ iflag1 = priv->read(®s->iflag1) & priv->reg_imask1_default;
|
|
|
|
|
|
return (u64)iflag2 << 32 | iflag1;
|
|
|
}
|
|
@@ -746,11 +757,9 @@ 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_iflag1, reg_esr;
|
|
|
+ u32 reg_iflag2, reg_esr;
|
|
|
enum can_state last_state = priv->can.state;
|
|
|
|
|
|
- reg_iflag1 = priv->read(®s->iflag1);
|
|
|
-
|
|
|
/* reception interrupt */
|
|
|
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
|
|
u64 reg_iflag;
|
|
@@ -764,6 +773,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|
|
break;
|
|
|
}
|
|
|
} else {
|
|
|
+ u32 reg_iflag1;
|
|
|
+
|
|
|
+ reg_iflag1 = priv->read(®s->iflag1);
|
|
|
if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) {
|
|
|
handled = IRQ_HANDLED;
|
|
|
can_rx_offload_irq_offload_fifo(&priv->offload);
|
|
@@ -779,17 +791,22 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ reg_iflag2 = priv->read(®s->iflag2);
|
|
|
+
|
|
|
/* transmission complete interrupt */
|
|
|
- if (reg_iflag1 & FLEXCAN_IFLAG_MB(priv->tx_mb_idx)) {
|
|
|
+ if (reg_iflag2 & FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB)) {
|
|
|
+ u32 reg_ctrl = priv->read(®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
|
|
+
|
|
|
handled = IRQ_HANDLED;
|
|
|
- stats->tx_bytes += can_get_echo_skb(dev, 0);
|
|
|
+ stats->tx_bytes += can_rx_offload_get_echo_skb(&priv->offload,
|
|
|
+ 0, reg_ctrl << 16);
|
|
|
stats->tx_packets++;
|
|
|
can_led_event(dev, CAN_LED_EVENT_TX);
|
|
|
|
|
|
/* 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->iflag1);
|
|
|
+ ®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
|
|
+ priv->write(FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB), ®s->iflag2);
|
|
|
netif_wake_queue(dev);
|
|
|
}
|
|
|
|
|
@@ -931,15 +948,13 @@ static int flexcan_chip_start(struct net_device *dev)
|
|
|
reg_mcr &= ~FLEXCAN_MCR_MAXMB(0xff);
|
|
|
reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | FLEXCAN_MCR_SUPV |
|
|
|
FLEXCAN_MCR_WRN_EN | FLEXCAN_MCR_SRX_DIS | FLEXCAN_MCR_IRMQ |
|
|
|
- FLEXCAN_MCR_IDAM_C;
|
|
|
+ FLEXCAN_MCR_IDAM_C | FLEXCAN_MCR_MAXMB(FLEXCAN_TX_MB);
|
|
|
|
|
|
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
|
|
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
|
|
reg_mcr &= ~FLEXCAN_MCR_FEN;
|
|
|
- reg_mcr |= FLEXCAN_MCR_MAXMB(priv->offload.mb_last);
|
|
|
- } else {
|
|
|
- reg_mcr |= FLEXCAN_MCR_FEN |
|
|
|
- FLEXCAN_MCR_MAXMB(priv->tx_mb_idx);
|
|
|
- }
|
|
|
+ else
|
|
|
+ reg_mcr |= FLEXCAN_MCR_FEN;
|
|
|
+
|
|
|
netdev_dbg(dev, "%s: writing mcr=0x%08x", __func__, reg_mcr);
|
|
|
priv->write(reg_mcr, ®s->mcr);
|
|
|
|
|
@@ -982,16 +997,17 @@ static int flexcan_chip_start(struct net_device *dev)
|
|
|
priv->write(reg_ctrl2, ®s->ctrl2);
|
|
|
}
|
|
|
|
|
|
- /* clear and invalidate all mailboxes first */
|
|
|
- for (i = priv->tx_mb_idx; i < ARRAY_SIZE(regs->mb); i++) {
|
|
|
- priv->write(FLEXCAN_MB_CODE_RX_INACTIVE,
|
|
|
- ®s->mb[i].can_ctrl);
|
|
|
- }
|
|
|
-
|
|
|
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
|
|
- for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++)
|
|
|
+ for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++) {
|
|
|
priv->write(FLEXCAN_MB_CODE_RX_EMPTY,
|
|
|
®s->mb[i].can_ctrl);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* clear and invalidate unused mailboxes first */
|
|
|
+ for (i = FLEXCAN_TX_MB_RESERVED_OFF_FIFO; i <= ARRAY_SIZE(regs->mb); i++) {
|
|
|
+ priv->write(FLEXCAN_MB_CODE_RX_INACTIVE,
|
|
|
+ ®s->mb[i].can_ctrl);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Errata ERR005829: mark first TX mailbox as INACTIVE */
|
|
@@ -1000,7 +1016,7 @@ static int flexcan_chip_start(struct net_device *dev)
|
|
|
|
|
|
/* mark TX mailbox as INACTIVE */
|
|
|
priv->write(FLEXCAN_MB_CODE_TX_INACTIVE,
|
|
|
- &priv->tx_mb->can_ctrl);
|
|
|
+ ®s->mb[FLEXCAN_TX_MB].can_ctrl);
|
|
|
|
|
|
/* acceptance mask/acceptance code (accept everything) */
|
|
|
priv->write(0x0, ®s->rxgmask);
|
|
@@ -1355,17 +1371,13 @@ static int flexcan_probe(struct platform_device *pdev)
|
|
|
priv->devtype_data = devtype_data;
|
|
|
priv->reg_xceiver = reg_xceiver;
|
|
|
|
|
|
- if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
|
|
|
- priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_TIMESTAMP;
|
|
|
+ if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
|
|
priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP];
|
|
|
- } else {
|
|
|
- priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_FIFO;
|
|
|
+ else
|
|
|
priv->tx_mb_reserved = ®s->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO];
|
|
|
- }
|
|
|
- priv->tx_mb = ®s->mb[priv->tx_mb_idx];
|
|
|
|
|
|
- priv->reg_imask1_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
|
|
|
- priv->reg_imask2_default = 0;
|
|
|
+ priv->reg_imask1_default = 0;
|
|
|
+ priv->reg_imask2_default = FLEXCAN_IFLAG_MB(FLEXCAN_TX_MB);
|
|
|
|
|
|
priv->offload.mailbox_read = flexcan_mailbox_read;
|
|
|
|