drivers/net/can/virtio_can.c

Source file repositories/reference/linux-study-clean/drivers/net/can/virtio_can.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/virtio_can.c
Extension
.c
Size
25867 bytes
Lines
1023
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct net_device_ops virtio_can_netdev_ops = {
	.ndo_open = virtio_can_open,
	.ndo_stop = virtio_can_close,
	.ndo_start_xmit = virtio_can_start_xmit,
};

static int register_virtio_can_dev(struct net_device *dev)
{
	dev->flags |= IFF_ECHO;	/* we support local echo */
	dev->netdev_ops = &virtio_can_netdev_ops;

	return register_candev(dev);
}

static int virtio_can_read_tx_queue(struct virtqueue *vq)
{
	struct virtio_can_priv *can_priv = vq->vdev->priv;
	struct net_device *dev = can_priv->dev;
	struct virtio_can_tx *can_tx_msg;
	struct net_device_stats *stats;
	unsigned int len;
	u8 result;

	stats = &dev->stats;

	scoped_guard(spinlock_irqsave, &can_priv->tx_lock)
		can_tx_msg = virtqueue_get_buf(vq, &len);

	if (!can_tx_msg)
		return 0;

	if (unlikely(len < sizeof(struct virtio_can_tx_in))) {
		netdev_err(dev, "TX ACK: Device sent no result code\n");
		result = VIRTIO_CAN_RESULT_NOT_OK; /* Keep things going */
	} else {
		result = can_tx_msg->tx_in.result;
	}

	if (can_priv->can.state < CAN_STATE_BUS_OFF) {
		if (result != VIRTIO_CAN_RESULT_OK) {
			struct can_frame *skb_cf;
			struct sk_buff *skb = alloc_can_err_skb(dev, &skb_cf);

			if (skb) {
				skb_cf->can_id |= CAN_ERR_CRTL;
				skb_cf->data[1] |= CAN_ERR_CRTL_UNSPEC;
				netif_rx(skb);
			}
			netdev_warn(dev, "TX ACK: Result = %u\n", result);
			can_free_echo_skb(dev, can_tx_msg->putidx, NULL);
			stats->tx_dropped++;
		} else {
			stats->tx_bytes += can_get_echo_skb(dev, can_tx_msg->putidx,
				NULL);
			stats->tx_packets++;
		}
	} else {
		netdev_dbg(dev, "TX ACK: Controller inactive, drop echo\n");
		can_free_echo_skb(dev, can_tx_msg->putidx, NULL);
		stats->tx_dropped++;
	}

	virtio_can_free_tx_idx(can_priv, can_tx_msg->putidx);

	/* Flow control */
	if (netif_queue_stopped(dev)) {
		netdev_dbg(dev, "TX ACK: Wake up stopped queue\n");
		netif_wake_queue(dev);
	}

	kfree(can_tx_msg);

	return 1; /* Queue was not empty so there may be more data */
}

static int virtio_can_tx_poll(struct napi_struct *napi, int quota)
{
	struct net_device *dev = napi->dev;
	struct virtio_can_priv *priv = netdev_priv(dev);
	struct virtqueue *vq = priv->vqs[VIRTIO_CAN_QUEUE_TX];
	int work_done = 0;

	while (work_done < quota && virtio_can_read_tx_queue(vq) != 0)
		work_done++;

	if (work_done < quota)
		virtqueue_napi_complete(napi, vq, work_done);

	return work_done;
}

Annotation

Implementation Notes