drivers/net/can/m_can/m_can.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/m_can/m_can.c
Extension
.c
Size
69222 bytes
Lines
2681
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 m_can_netdev_ops = {
	.ndo_open = m_can_open,
	.ndo_stop = m_can_close,
	.ndo_start_xmit = m_can_start_xmit,
};

static int m_can_get_coalesce(struct net_device *dev,
			      struct ethtool_coalesce *ec,
			      struct kernel_ethtool_coalesce *kec,
			      struct netlink_ext_ack *ext_ack)
{
	struct m_can_classdev *cdev = netdev_priv(dev);

	ec->rx_max_coalesced_frames_irq = cdev->rx_max_coalesced_frames_irq;
	ec->rx_coalesce_usecs_irq = cdev->rx_coalesce_usecs_irq;
	ec->tx_max_coalesced_frames = cdev->tx_max_coalesced_frames;
	ec->tx_max_coalesced_frames_irq = cdev->tx_max_coalesced_frames_irq;
	ec->tx_coalesce_usecs_irq = cdev->tx_coalesce_usecs_irq;

	return 0;
}

static int m_can_set_coalesce(struct net_device *dev,
			      struct ethtool_coalesce *ec,
			      struct kernel_ethtool_coalesce *kec,
			      struct netlink_ext_ack *ext_ack)
{
	struct m_can_classdev *cdev = netdev_priv(dev);

	if (cdev->can.state != CAN_STATE_STOPPED) {
		netdev_err(dev, "Device is in use, please shut it down first\n");
		return -EBUSY;
	}

	if (ec->rx_max_coalesced_frames_irq > cdev->mcfg[MRAM_RXF0].num) {
		netdev_err(dev, "rx-frames-irq %u greater than the RX FIFO %u\n",
			   ec->rx_max_coalesced_frames_irq,
			   cdev->mcfg[MRAM_RXF0].num);
		return -EINVAL;
	}
	if ((ec->rx_max_coalesced_frames_irq == 0) != (ec->rx_coalesce_usecs_irq == 0)) {
		netdev_err(dev, "rx-frames-irq and rx-usecs-irq can only be set together\n");
		return -EINVAL;
	}
	if (ec->tx_max_coalesced_frames_irq > cdev->mcfg[MRAM_TXE].num) {
		netdev_err(dev, "tx-frames-irq %u greater than the TX event FIFO %u\n",
			   ec->tx_max_coalesced_frames_irq,
			   cdev->mcfg[MRAM_TXE].num);
		return -EINVAL;
	}
	if (ec->tx_max_coalesced_frames_irq > cdev->mcfg[MRAM_TXB].num) {
		netdev_err(dev, "tx-frames-irq %u greater than the TX FIFO %u\n",
			   ec->tx_max_coalesced_frames_irq,
			   cdev->mcfg[MRAM_TXB].num);
		return -EINVAL;
	}
	if ((ec->tx_max_coalesced_frames_irq == 0) != (ec->tx_coalesce_usecs_irq == 0)) {
		netdev_err(dev, "tx-frames-irq and tx-usecs-irq can only be set together\n");
		return -EINVAL;
	}
	if (ec->tx_max_coalesced_frames > cdev->mcfg[MRAM_TXE].num) {
		netdev_err(dev, "tx-frames %u greater than the TX event FIFO %u\n",
			   ec->tx_max_coalesced_frames,
			   cdev->mcfg[MRAM_TXE].num);
		return -EINVAL;
	}
	if (ec->tx_max_coalesced_frames > cdev->mcfg[MRAM_TXB].num) {
		netdev_err(dev, "tx-frames %u greater than the TX FIFO %u\n",
			   ec->tx_max_coalesced_frames,
			   cdev->mcfg[MRAM_TXB].num);
		return -EINVAL;
	}
	if (ec->rx_coalesce_usecs_irq != 0 && ec->tx_coalesce_usecs_irq != 0 &&
	    ec->rx_coalesce_usecs_irq != ec->tx_coalesce_usecs_irq) {
		netdev_err(dev, "rx-usecs-irq %u needs to be equal to tx-usecs-irq %u if both are enabled\n",
			   ec->rx_coalesce_usecs_irq,
			   ec->tx_coalesce_usecs_irq);
		return -EINVAL;
	}

	cdev->rx_max_coalesced_frames_irq = ec->rx_max_coalesced_frames_irq;
	cdev->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq;
	cdev->tx_max_coalesced_frames = ec->tx_max_coalesced_frames;
	cdev->tx_max_coalesced_frames_irq = ec->tx_max_coalesced_frames_irq;
	cdev->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq;

	if (cdev->rx_coalesce_usecs_irq)
		cdev->irq_timer_wait = us_to_ktime(cdev->rx_coalesce_usecs_irq);
	else
		cdev->irq_timer_wait = us_to_ktime(cdev->tx_coalesce_usecs_irq);

Annotation

Implementation Notes