drivers/net/can/rcar/rcar_can.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/rcar/rcar_can.c
Extension
.c
Size
27122 bytes
Lines
918
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 rcar_can_netdev_ops = {
	.ndo_open = rcar_can_open,
	.ndo_stop = rcar_can_close,
	.ndo_start_xmit = rcar_can_start_xmit,
};

static const struct ethtool_ops rcar_can_ethtool_ops = {
	.get_ts_info = ethtool_op_get_ts_info,
};

static void rcar_can_rx_pkt(struct rcar_can_priv *priv)
{
	struct net_device_stats *stats = &priv->ndev->stats;
	struct can_frame *cf;
	struct sk_buff *skb;
	u32 data;
	u8 dlc;

	skb = alloc_can_skb(priv->ndev, &cf);
	if (!skb) {
		stats->rx_dropped++;
		return;
	}

	data = readl(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].id);
	if (data & RCAR_CAN_IDE)
		cf->can_id = FIELD_GET(RCAR_CAN_EID, data) | CAN_EFF_FLAG;
	else
		cf->can_id = FIELD_GET(RCAR_CAN_SID, data);

	dlc = readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].dlc);
	cf->len = can_cc_dlc2len(dlc);
	if (data & RCAR_CAN_RTR) {
		cf->can_id |= CAN_RTR_FLAG;
	} else {
		for (dlc = 0; dlc < cf->len; dlc++)
			cf->data[dlc] =
			readb(&priv->regs->mb[RCAR_CAN_RX_FIFO_MBX].data[dlc]);

		stats->rx_bytes += cf->len;
	}
	stats->rx_packets++;

	netif_receive_skb(skb);
}

static int rcar_can_rx_poll(struct napi_struct *napi, int quota)
{
	struct rcar_can_priv *priv = container_of(napi,
						  struct rcar_can_priv, napi);
	int num_pkts;

	for (num_pkts = 0; num_pkts < quota; num_pkts++) {
		u8 rfcr, isr;

		isr = readb(&priv->regs->isr);
		/* Clear interrupt bit */
		if (isr & RCAR_CAN_ISR_RXFF)
			writeb(isr & ~RCAR_CAN_ISR_RXFF, &priv->regs->isr);
		rfcr = readb(&priv->regs->rfcr);
		if (rfcr & RCAR_CAN_RFCR_RFEST)
			break;
		rcar_can_rx_pkt(priv);
		/* Write 0xff to the RFPCR register to increment
		 * the CPU-side pointer for the receive FIFO
		 * to the next mailbox location
		 */
		writeb(0xff, &priv->regs->rfpcr);
	}
	/* All packets processed */
	if (num_pkts < quota) {
		napi_complete_done(napi, num_pkts);
		priv->ier |= RCAR_CAN_IER_RXFIE;
		writeb(priv->ier, &priv->regs->ier);
	}
	return num_pkts;
}

static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
{
	switch (mode) {
	case CAN_MODE_START:
		rcar_can_start(ndev);
		netif_wake_queue(ndev);
		return 0;
	default:
		return -EOPNOTSUPP;
	}
}

Annotation

Implementation Notes