drivers/net/can/dev/rx-offload.c

Source file repositories/reference/linux-study-clean/drivers/net/can/dev/rx-offload.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/dev/rx-offload.c
Extension
.c
Size
10615 bytes
Lines
428
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct can_rx_offload_cb {
	u32 timestamp;
};

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)
{
	if (offload->inc)
		return a <= b;
	else
		return a >= b;
}

static inline unsigned int
can_rx_offload_inc(struct can_rx_offload *offload, unsigned int *val)
{
	if (offload->inc)
		return (*val)++;
	else
		return (*val)--;
}

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 net_device *dev = offload->dev;
	struct net_device_stats *stats = &dev->stats;
	struct sk_buff *skb;
	int work_done = 0;

	while ((work_done < quota) &&
	       (skb = skb_dequeue(&offload->skb_queue))) {
		struct can_frame *cf = (struct can_frame *)skb->data;

		work_done++;
		if (!(cf->can_id & CAN_ERR_FLAG)) {
			stats->rx_packets++;
			if (!(cf->can_id & CAN_RTR_FLAG))
				stats->rx_bytes += cf->len;
		}
		netif_receive_skb(skb);
	}

	if (work_done < quota) {
		napi_complete_done(napi, work_done);

		/* Check if there was another interrupt */
		if (!skb_queue_empty(&offload->skb_queue))
			napi_schedule(&offload->napi);
	}

	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))
{
	struct sk_buff *pos, *insert = NULL;

	skb_queue_reverse_walk(head, pos) {
		const struct can_rx_offload_cb *cb_pos, *cb_new;

		cb_pos = can_rx_offload_get_cb(pos);
		cb_new = can_rx_offload_get_cb(new);

		netdev_dbg(new->dev,
			   "%s: pos=0x%08x, new=0x%08x, diff=%10d, queue_len=%d\n",
			   __func__,
			   cb_pos->timestamp, cb_new->timestamp,
			   cb_new->timestamp - cb_pos->timestamp,
			   skb_queue_len(head));

		if (compare(pos, new) < 0)
			continue;
		insert = pos;
		break;
	}
	if (!insert)

Annotation

Implementation Notes