drivers/net/can/rcar/rcar_canfd.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/can/rcar/rcar_canfd.c
Extension
.c
Size
68998 bytes
Lines
2390
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_canfd_netdev_ops = {
	.ndo_open = rcar_canfd_open,
	.ndo_stop = rcar_canfd_close,
	.ndo_start_xmit = rcar_canfd_start_xmit,
};

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

static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
				    u32 fcan_freq, struct phy *transceiver)
{
	const struct rcar_canfd_hw_info *info = gpriv->info;
	struct platform_device *pdev = gpriv->pdev;
	struct device *dev = &pdev->dev;
	struct rcar_canfd_channel *priv;
	struct net_device *ndev;
	int err = -ENODEV;

	ndev = alloc_candev(sizeof(*priv), RCANFD_FIFO_DEPTH);
	if (!ndev)
		return -ENOMEM;

	priv = netdev_priv(ndev);

	ndev->netdev_ops = &rcar_canfd_netdev_ops;
	ndev->ethtool_ops = &rcar_canfd_ethtool_ops;
	ndev->flags |= IFF_ECHO;
	priv->ndev = ndev;
	priv->base = gpriv->base;
	priv->transceiver = transceiver;
	priv->channel = ch;
	priv->gpriv = gpriv;
	if (transceiver)
		priv->can.bitrate_max = transceiver->attrs.max_link_rate;
	priv->can.clock.freq = fcan_freq;
	dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq);

	if (info->multi_channel_irqs) {
		char *irq_name;
		char name[10];
		int err_irq;
		int tx_irq;

		scnprintf(name, sizeof(name), "ch%u_err", ch);
		err_irq = platform_get_irq_byname(pdev, name);
		if (err_irq < 0) {
			err = err_irq;
			goto fail;
		}

		scnprintf(name, sizeof(name), "ch%u_trx", ch);
		tx_irq = platform_get_irq_byname(pdev, name);
		if (tx_irq < 0) {
			err = tx_irq;
			goto fail;
		}

		irq_name = devm_kasprintf(dev, GFP_KERNEL, "canfd.ch%d_err",
					  ch);
		if (!irq_name) {
			err = -ENOMEM;
			goto fail;
		}
		err = devm_request_irq(dev, err_irq,
				       rcar_canfd_channel_err_interrupt, 0,
				       irq_name, priv);
		if (err) {
			dev_err(dev, "devm_request_irq CH Err %d failed: %pe\n",
				err_irq, ERR_PTR(err));
			goto fail;
		}
		irq_name = devm_kasprintf(dev, GFP_KERNEL, "canfd.ch%d_trx",
					  ch);
		if (!irq_name) {
			err = -ENOMEM;
			goto fail;
		}
		err = devm_request_irq(dev, tx_irq,
				       rcar_canfd_channel_tx_interrupt, 0,
				       irq_name, priv);
		if (err) {
			dev_err(dev, "devm_request_irq Tx %d failed: %pe\n",
				tx_irq, ERR_PTR(err));
			goto fail;
		}
	}

	if (gpriv->fdmode) {

Annotation

Implementation Notes