Commit 55059f2b authored by Oleksij Rempel's avatar Oleksij Rempel Committed by Marc Kleine-Budde
Browse files

can: rx-offload: introduce can_rx_offload_get_echo_skb() and...


can: rx-offload: introduce can_rx_offload_get_echo_skb() and can_rx_offload_queue_sorted() functions

Current CAN framework can't guarantee proper/chronological order
of RX and TX-ECHO messages. To make this possible, drivers should use
this functions instead of can_get_echo_skb().

Signed-off-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Cc: linux-stable <stable@vger.kernel.org>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 7da11ba5
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -211,6 +211,52 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
}
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);

int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
				struct sk_buff *skb, u32 timestamp)
{
	struct can_rx_offload_cb *cb;
	unsigned long flags;

	if (skb_queue_len(&offload->skb_queue) >
	    offload->skb_queue_len_max)
		return -ENOMEM;

	cb = can_rx_offload_get_cb(skb);
	cb->timestamp = timestamp;

	spin_lock_irqsave(&offload->skb_queue.lock, flags);
	__skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
	spin_unlock_irqrestore(&offload->skb_queue.lock, flags);

	can_rx_offload_schedule(offload);

	return 0;
}
EXPORT_SYMBOL_GPL(can_rx_offload_queue_sorted);

unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
					 unsigned int idx, u32 timestamp)
{
	struct net_device *dev = offload->dev;
	struct net_device_stats *stats = &dev->stats;
	struct sk_buff *skb;
	u8 len;
	int err;

	skb = __can_get_echo_skb(dev, idx, &len);
	if (!skb)
		return 0;

	err = can_rx_offload_queue_sorted(offload, skb, timestamp);
	if (err) {
		stats->rx_errors++;
		stats->tx_fifo_errors++;
	}

	return len;
}
EXPORT_SYMBOL_GPL(can_rx_offload_get_echo_skb);

int can_rx_offload_irq_queue_err_skb(struct can_rx_offload *offload, struct sk_buff *skb)
{
	if (skb_queue_len(&offload->skb_queue) >
+4 −0
Original line number Diff line number Diff line
@@ -41,6 +41,10 @@ int can_rx_offload_add_timestamp(struct net_device *dev, struct can_rx_offload *
int can_rx_offload_add_fifo(struct net_device *dev, struct can_rx_offload *offload, unsigned int weight);
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload, u64 reg);
int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload);
int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
				struct sk_buff *skb, u32 timestamp);
unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
					 unsigned int idx, u32 timestamp);
int can_rx_offload_irq_queue_err_skb(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);