diff options
Diffstat (limited to 'drivers/net/can/flexcan.c')
| -rw-r--r-- | drivers/net/can/flexcan.c | 108 | 
1 files changed, 60 insertions, 48 deletions
| diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 8e972ef08637..75ce11395ee8 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -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; | 
