drivers/net/can/rockchip/rockchip_canfd-tx.c

Source file repositories/reference/linux-study-clean/drivers/net/can/rockchip/rockchip_canfd-tx.c

File Facts

System
Linux kernel
Corpus path
drivers/net/can/rockchip/rockchip_canfd-tx.c
Extension
.c
Size
4516 bytes
Lines
168
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2023, 2024 Pengutronix,
//               Marc Kleine-Budde <kernel@pengutronix.de>
//

#include <net/netdev_queues.h>

#include "rockchip_canfd.h"

static bool rkcanfd_tx_tail_is_eff(const struct rkcanfd_priv *priv)
{
	const struct canfd_frame *cfd;
	const struct sk_buff *skb;
	unsigned int tx_tail;

	if (!rkcanfd_get_tx_pending(priv))
		return false;

	tx_tail = rkcanfd_get_tx_tail(priv);
	skb = priv->can.echo_skb[tx_tail];
	if (!skb) {
		netdev_err(priv->ndev,
			   "%s: echo_skb[%u]=NULL tx_head=0x%08x tx_tail=0x%08x\n",
			   __func__, tx_tail,
			   priv->tx_head, priv->tx_tail);

		return false;
	}

	cfd = (struct canfd_frame *)skb->data;

	return cfd->can_id & CAN_EFF_FLAG;
}

unsigned int rkcanfd_get_effective_tx_free(const struct rkcanfd_priv *priv)
{
	if (priv->devtype_data.quirks & RKCANFD_QUIRK_RK3568_ERRATUM_6 &&
	    rkcanfd_tx_tail_is_eff(priv))
		return 0;

	return rkcanfd_get_tx_free(priv);
}

static void rkcanfd_start_xmit_write_cmd(const struct rkcanfd_priv *priv,
					 const u32 reg_cmd)
{
	if (priv->devtype_data.quirks & RKCANFD_QUIRK_RK3568_ERRATUM_12)
		rkcanfd_write(priv, RKCANFD_REG_MODE, priv->reg_mode_default |
			      RKCANFD_REG_MODE_SPACE_RX_MODE);

	rkcanfd_write(priv, RKCANFD_REG_CMD, reg_cmd);

	if (priv->devtype_data.quirks & RKCANFD_QUIRK_RK3568_ERRATUM_12)
		rkcanfd_write(priv, RKCANFD_REG_MODE, priv->reg_mode_default);
}

void rkcanfd_xmit_retry(struct rkcanfd_priv *priv)
{
	const unsigned int tx_head = rkcanfd_get_tx_head(priv);
	const u32 reg_cmd = RKCANFD_REG_CMD_TX_REQ(tx_head);

	rkcanfd_start_xmit_write_cmd(priv, reg_cmd);
}

netdev_tx_t rkcanfd_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
	struct rkcanfd_priv *priv = netdev_priv(ndev);
	u32 reg_frameinfo, reg_id, reg_cmd;
	unsigned int tx_head, frame_len;
	const struct canfd_frame *cfd;
	int err;
	u8 i;

	if (can_dev_dropped_skb(ndev, skb))
		return NETDEV_TX_OK;

	if (!netif_subqueue_maybe_stop(priv->ndev, 0,
				       rkcanfd_get_effective_tx_free(priv),
				       RKCANFD_TX_STOP_THRESHOLD,
				       RKCANFD_TX_START_THRESHOLD)) {
		if (net_ratelimit())
			netdev_info(priv->ndev,
				    "Stopping tx-queue (tx_head=0x%08x, tx_tail=0x%08x, tx_pending=%d)\n",
				    priv->tx_head, priv->tx_tail,
				    rkcanfd_get_tx_pending(priv));

		return NETDEV_TX_BUSY;
	}

Annotation

Implementation Notes