All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: Vivian Wang <wangruikang@iscas.ac.cn>
Cc: Andrew Lunn <andrew+netdev@lunn.ch>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>, Yixun Lan <dlan@gentoo.org>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Paolo Abeni <pabeni@redhat.com>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>, Vivian Wang <uwu@dram.page>,
	Vadim Fedorenko <vadim.fedorenko@linux.dev>,
	Junhui Liu <junhui.liu@pigmoral.tech>,
	Simon Horman <horms@kernel.org>,
	Maxime Chevallier <maxime.chevallier@bootlin.com>,
	netdev@vger.kernel.org, devicetree@vger.kernel.org,
	linux-riscv@lists.infradead.org, spacemit@lists.linux.dev,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v6 2/5] net: spacemit: Add K1 Ethernet MAC
Date: Thu, 21 Aug 2025 16:14:20 -0700	[thread overview]
Message-ID: <20250821161420.7c9804f7@kernel.org> (raw)
In-Reply-To: <20250820-net-k1-emac-v6-2-c1e28f2b8be5@iscas.ac.cn>

On Wed, 20 Aug 2025 14:47:51 +0800 Vivian Wang wrote:
> +static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
> +{
> +	struct emac_desc_ring *tx_ring = &priv->tx_ring;
> +	struct emac_desc tx_desc, *tx_desc_addr;
> +	struct device *dev = &priv->pdev->dev;
> +	struct emac_tx_desc_buffer *tx_buf;
> +	u32 head, old_head, frag_num, f;
> +	bool buf_idx;
> +
> +	frag_num = skb_shinfo(skb)->nr_frags;
> +	head = tx_ring->head;
> +	old_head = head;
> +
> +	for (f = 0; f < frag_num + 1; f++) {
> +		buf_idx = f % 2;
> +
> +		/*
> +		 * If using buffer 1, initialize a new desc. Otherwise, use
> +		 * buffer 2 of previous fragment's desc.
> +		 */
> +		if (!buf_idx) {
> +			tx_buf = &tx_ring->tx_desc_buf[head];
> +			tx_desc_addr =
> +				&((struct emac_desc *)tx_ring->desc_addr)[head];
> +			memset(&tx_desc, 0, sizeof(tx_desc));
> +
> +			/*
> +			 * Give ownership for all but first desc initially. For
> +			 * first desc, give at the end so DMA cannot start
> +			 * reading uninitialized descs.
> +			 */
> +			if (head != old_head)
> +				tx_desc.desc0 |= TX_DESC_0_OWN;
> +
> +			if (++head == tx_ring->total_cnt) {
> +				/* Just used last desc in ring */
> +				tx_desc.desc1 |= TX_DESC_1_END_RING;
> +				head = 0;
> +			}
> +		}
> +
> +		if (emac_tx_map_frag(dev, &tx_desc, tx_buf, skb, f)) {
> +			netdev_err(priv->ndev, "Map TX frag %d failed", f);
> +			goto dma_map_err;
> +		}
> +
> +		if (f == 0)
> +			tx_desc.desc1 |= TX_DESC_1_FIRST_SEGMENT;
> +
> +		if (f == frag_num) {
> +			tx_desc.desc1 |= TX_DESC_1_LAST_SEGMENT;
> +			tx_buf->skb = skb;
> +			if (emac_tx_should_interrupt(priv, frag_num + 1))
> +				tx_desc.desc1 |=
> +					TX_DESC_1_INTERRUPT_ON_COMPLETION;
> +		}
> +
> +		*tx_desc_addr = tx_desc;
> +	}
> +
> +	/* All descriptors are ready, give ownership for first desc */
> +	tx_desc_addr = &((struct emac_desc *)tx_ring->desc_addr)[old_head];
> +	dma_wmb();
> +	WRITE_ONCE(tx_desc_addr->desc0, tx_desc_addr->desc0 | TX_DESC_0_OWN);
> +
> +	emac_dma_start_transmit(priv);
> +
> +	tx_ring->head = head;
> +
> +	return;
> +
> +dma_map_err:
> +	dev_kfree_skb_any(skb);

You free the skb here.. 

> +	priv->ndev->stats.tx_dropped++;
> +}
> +
> +static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
> +{
> +	struct emac_priv *priv = netdev_priv(ndev);
> +	int nfrags = skb_shinfo(skb)->nr_frags;
> +	struct device *dev = &priv->pdev->dev;
> +
> +	if (unlikely(emac_tx_avail(priv) < nfrags + 1)) {
> +		if (!netif_queue_stopped(ndev)) {
> +			netif_stop_queue(ndev);
> +			dev_err_ratelimited(dev, "TX ring full, stop TX queue\n");
> +		}
> +		return NETDEV_TX_BUSY;
> +	}
> +
> +	emac_tx_mem_map(priv, skb);
> +
> +	ndev->stats.tx_packets++;
> +	ndev->stats.tx_bytes += skb->len;

.. and then you use skb here.

> +	/* Make sure there is space in the ring for the next TX. */
> +	if (unlikely(emac_tx_avail(priv) <= MAX_SKB_FRAGS + 2))
> +		netif_stop_queue(ndev);
> +
> +	return NETDEV_TX_OK;
> +}

> +static void emac_get_ethtool_stats(struct net_device *dev,
> +				   struct ethtool_stats *stats, u64 *data)
> +{
> +	struct emac_priv *priv = netdev_priv(dev);
> +	u64 *rx_stats = (u64 *)&priv->rx_stats;
> +	int i;
> +
> +	scoped_guard(spinlock_irqsave, &priv->stats_lock) {

Why is this spin lock taken in irqsave mode?
Please convert the code not to use scoped_guard()
There's not a single flow control (return) in any of them.
It's just hiding the information that you're unnecessarily masking irqs.
See
https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#using-device-managed-and-cleanup-h-constructs

> +		emac_stats_update(priv);
> +
> +		for (i = 0; i < ARRAY_SIZE(emac_ethtool_rx_stats); i++)
> +			data[i] = rx_stats[emac_ethtool_rx_stats[i].offset];
> +	}

> +static void emac_tx_timeout_task(struct work_struct *work)
> +{
> +	struct net_device *ndev;
> +	struct emac_priv *priv;
> +
> +	priv = container_of(work, struct emac_priv, tx_timeout_task);
> +	ndev = priv->ndev;

I don't see this work ever being canceled.
What prevents ndev from being freed before it gets to run?

> +/* Called when net interface is brought up. */
> +static int emac_open(struct net_device *ndev)
> +{
> +	struct emac_priv *priv = netdev_priv(ndev);
> +	struct device *dev = &priv->pdev->dev;
> +	int ret;
> +
> +	ret = emac_alloc_tx_resources(priv);
> +	if (ret) {
> +		dev_err(dev, "Error when setting up the Tx resources\n");
> +		goto emac_alloc_tx_resource_fail;
> +	}
> +
> +	ret = emac_alloc_rx_resources(priv);
> +	if (ret) {
> +		dev_err(dev, "Error when setting up the Rx resources\n");
> +		goto emac_alloc_rx_resource_fail;
> +	}
> +
> +	ret = emac_up(priv);
> +	if (ret) {
> +		dev_err(dev, "Error when bringing interface up\n");
> +		goto emac_up_fail;
> +	}
> +	return 0;
> +
> +emac_up_fail:

please name the jump labels after the destination not the source.
Please fix everywhere in the driver.
This is covered in the kernel coding style docs.

> +	emac_free_rx_resources(priv);
> +emac_alloc_rx_resource_fail:
> +	emac_free_tx_resources(priv);
> +emac_alloc_tx_resource_fail:
> +	return ret;
> +}


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

WARNING: multiple messages have this Message-ID (diff)
From: Jakub Kicinski <kuba@kernel.org>
To: Vivian Wang <wangruikang@iscas.ac.cn>
Cc: Andrew Lunn <andrew+netdev@lunn.ch>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>, Yixun Lan <dlan@gentoo.org>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Paolo Abeni <pabeni@redhat.com>,
	Philipp Zabel <p.zabel@pengutronix.de>,
	Paul Walmsley <paul.walmsley@sifive.com>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Albert Ou <aou@eecs.berkeley.edu>,
	Alexandre Ghiti <alex@ghiti.fr>, Vivian Wang <uwu@dram.page>,
	Vadim Fedorenko <vadim.fedorenko@linux.dev>,
	Junhui Liu <junhui.liu@pigmoral.tech>,
	Simon Horman <horms@kernel.org>,
	Maxime Chevallier <maxime.chevallier@bootlin.com>,
	netdev@vger.kernel.org, devicetree@vger.kernel.org,
	linux-riscv@lists.infradead.org, spacemit@lists.linux.dev,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH net-next v6 2/5] net: spacemit: Add K1 Ethernet MAC
Date: Thu, 21 Aug 2025 16:14:20 -0700	[thread overview]
Message-ID: <20250821161420.7c9804f7@kernel.org> (raw)
In-Reply-To: <20250820-net-k1-emac-v6-2-c1e28f2b8be5@iscas.ac.cn>

On Wed, 20 Aug 2025 14:47:51 +0800 Vivian Wang wrote:
> +static void emac_tx_mem_map(struct emac_priv *priv, struct sk_buff *skb)
> +{
> +	struct emac_desc_ring *tx_ring = &priv->tx_ring;
> +	struct emac_desc tx_desc, *tx_desc_addr;
> +	struct device *dev = &priv->pdev->dev;
> +	struct emac_tx_desc_buffer *tx_buf;
> +	u32 head, old_head, frag_num, f;
> +	bool buf_idx;
> +
> +	frag_num = skb_shinfo(skb)->nr_frags;
> +	head = tx_ring->head;
> +	old_head = head;
> +
> +	for (f = 0; f < frag_num + 1; f++) {
> +		buf_idx = f % 2;
> +
> +		/*
> +		 * If using buffer 1, initialize a new desc. Otherwise, use
> +		 * buffer 2 of previous fragment's desc.
> +		 */
> +		if (!buf_idx) {
> +			tx_buf = &tx_ring->tx_desc_buf[head];
> +			tx_desc_addr =
> +				&((struct emac_desc *)tx_ring->desc_addr)[head];
> +			memset(&tx_desc, 0, sizeof(tx_desc));
> +
> +			/*
> +			 * Give ownership for all but first desc initially. For
> +			 * first desc, give at the end so DMA cannot start
> +			 * reading uninitialized descs.
> +			 */
> +			if (head != old_head)
> +				tx_desc.desc0 |= TX_DESC_0_OWN;
> +
> +			if (++head == tx_ring->total_cnt) {
> +				/* Just used last desc in ring */
> +				tx_desc.desc1 |= TX_DESC_1_END_RING;
> +				head = 0;
> +			}
> +		}
> +
> +		if (emac_tx_map_frag(dev, &tx_desc, tx_buf, skb, f)) {
> +			netdev_err(priv->ndev, "Map TX frag %d failed", f);
> +			goto dma_map_err;
> +		}
> +
> +		if (f == 0)
> +			tx_desc.desc1 |= TX_DESC_1_FIRST_SEGMENT;
> +
> +		if (f == frag_num) {
> +			tx_desc.desc1 |= TX_DESC_1_LAST_SEGMENT;
> +			tx_buf->skb = skb;
> +			if (emac_tx_should_interrupt(priv, frag_num + 1))
> +				tx_desc.desc1 |=
> +					TX_DESC_1_INTERRUPT_ON_COMPLETION;
> +		}
> +
> +		*tx_desc_addr = tx_desc;
> +	}
> +
> +	/* All descriptors are ready, give ownership for first desc */
> +	tx_desc_addr = &((struct emac_desc *)tx_ring->desc_addr)[old_head];
> +	dma_wmb();
> +	WRITE_ONCE(tx_desc_addr->desc0, tx_desc_addr->desc0 | TX_DESC_0_OWN);
> +
> +	emac_dma_start_transmit(priv);
> +
> +	tx_ring->head = head;
> +
> +	return;
> +
> +dma_map_err:
> +	dev_kfree_skb_any(skb);

You free the skb here.. 

> +	priv->ndev->stats.tx_dropped++;
> +}
> +
> +static netdev_tx_t emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
> +{
> +	struct emac_priv *priv = netdev_priv(ndev);
> +	int nfrags = skb_shinfo(skb)->nr_frags;
> +	struct device *dev = &priv->pdev->dev;
> +
> +	if (unlikely(emac_tx_avail(priv) < nfrags + 1)) {
> +		if (!netif_queue_stopped(ndev)) {
> +			netif_stop_queue(ndev);
> +			dev_err_ratelimited(dev, "TX ring full, stop TX queue\n");
> +		}
> +		return NETDEV_TX_BUSY;
> +	}
> +
> +	emac_tx_mem_map(priv, skb);
> +
> +	ndev->stats.tx_packets++;
> +	ndev->stats.tx_bytes += skb->len;

.. and then you use skb here.

> +	/* Make sure there is space in the ring for the next TX. */
> +	if (unlikely(emac_tx_avail(priv) <= MAX_SKB_FRAGS + 2))
> +		netif_stop_queue(ndev);
> +
> +	return NETDEV_TX_OK;
> +}

> +static void emac_get_ethtool_stats(struct net_device *dev,
> +				   struct ethtool_stats *stats, u64 *data)
> +{
> +	struct emac_priv *priv = netdev_priv(dev);
> +	u64 *rx_stats = (u64 *)&priv->rx_stats;
> +	int i;
> +
> +	scoped_guard(spinlock_irqsave, &priv->stats_lock) {

Why is this spin lock taken in irqsave mode?
Please convert the code not to use scoped_guard()
There's not a single flow control (return) in any of them.
It's just hiding the information that you're unnecessarily masking irqs.
See
https://www.kernel.org/doc/html/next/process/maintainer-netdev.html#using-device-managed-and-cleanup-h-constructs

> +		emac_stats_update(priv);
> +
> +		for (i = 0; i < ARRAY_SIZE(emac_ethtool_rx_stats); i++)
> +			data[i] = rx_stats[emac_ethtool_rx_stats[i].offset];
> +	}

> +static void emac_tx_timeout_task(struct work_struct *work)
> +{
> +	struct net_device *ndev;
> +	struct emac_priv *priv;
> +
> +	priv = container_of(work, struct emac_priv, tx_timeout_task);
> +	ndev = priv->ndev;

I don't see this work ever being canceled.
What prevents ndev from being freed before it gets to run?

> +/* Called when net interface is brought up. */
> +static int emac_open(struct net_device *ndev)
> +{
> +	struct emac_priv *priv = netdev_priv(ndev);
> +	struct device *dev = &priv->pdev->dev;
> +	int ret;
> +
> +	ret = emac_alloc_tx_resources(priv);
> +	if (ret) {
> +		dev_err(dev, "Error when setting up the Tx resources\n");
> +		goto emac_alloc_tx_resource_fail;
> +	}
> +
> +	ret = emac_alloc_rx_resources(priv);
> +	if (ret) {
> +		dev_err(dev, "Error when setting up the Rx resources\n");
> +		goto emac_alloc_rx_resource_fail;
> +	}
> +
> +	ret = emac_up(priv);
> +	if (ret) {
> +		dev_err(dev, "Error when bringing interface up\n");
> +		goto emac_up_fail;
> +	}
> +	return 0;
> +
> +emac_up_fail:

please name the jump labels after the destination not the source.
Please fix everywhere in the driver.
This is covered in the kernel coding style docs.

> +	emac_free_rx_resources(priv);
> +emac_alloc_rx_resource_fail:
> +	emac_free_tx_resources(priv);
> +emac_alloc_tx_resource_fail:
> +	return ret;
> +}


  parent reply	other threads:[~2025-08-22  3:40 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-20  6:47 [PATCH net-next v6 0/5] Add Ethernet MAC support for SpacemiT K1 Vivian Wang
2025-08-20  6:47 ` Vivian Wang
2025-08-20  6:47 ` [PATCH net-next v6 1/5] dt-bindings: net: Add " Vivian Wang
2025-08-20  6:47   ` Vivian Wang
2025-08-20  6:47 ` [PATCH net-next v6 2/5] net: spacemit: Add K1 Ethernet MAC Vivian Wang
2025-08-20  6:47   ` Vivian Wang
2025-08-20 11:34   ` Maxime Chevallier
2025-08-20 11:34     ` Maxime Chevallier
2025-08-20 17:48     ` Vivian Wang
2025-08-20 17:48       ` Vivian Wang
2025-08-21 12:59   ` Vadim Fedorenko
2025-08-21 12:59     ` Vadim Fedorenko
2025-08-21 13:38     ` Vivian Wang
2025-08-21 13:38       ` Vivian Wang
2025-08-21 23:14   ` Jakub Kicinski [this message]
2025-08-21 23:14     ` Jakub Kicinski
2025-08-22 13:27     ` Vivian Wang
2025-08-22 13:27       ` Vivian Wang
2025-08-20  6:47 ` [PATCH net-next v6 3/5] riscv: dts: spacemit: Add Ethernet support for K1 Vivian Wang
2025-08-20  6:47   ` Vivian Wang
2025-08-25 23:32   ` Yixun Lan
2025-08-25 23:32     ` Yixun Lan
2025-08-20  6:47 ` [PATCH net-next v6 4/5] riscv: dts: spacemit: Add Ethernet support for BPI-F3 Vivian Wang
2025-08-20  6:47   ` Vivian Wang
2025-08-25 23:33   ` Yixun Lan
2025-08-25 23:33     ` Yixun Lan
2025-08-20  6:47 ` [PATCH net-next v6 5/5] riscv: dts: spacemit: Add Ethernet support for Jupiter Vivian Wang
2025-08-20  6:47   ` Vivian Wang
2025-08-25 23:33   ` Yixun Lan
2025-08-25 23:33     ` Yixun Lan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250821161420.7c9804f7@kernel.org \
    --to=kuba@kernel.org \
    --cc=alex@ghiti.fr \
    --cc=andrew+netdev@lunn.ch \
    --cc=aou@eecs.berkeley.edu \
    --cc=conor+dt@kernel.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=dlan@gentoo.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=junhui.liu@pigmoral.tech \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=maxime.chevallier@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=p.zabel@pengutronix.de \
    --cc=pabeni@redhat.com \
    --cc=palmer@dabbelt.com \
    --cc=paul.walmsley@sifive.com \
    --cc=robh@kernel.org \
    --cc=spacemit@lists.linux.dev \
    --cc=uwu@dram.page \
    --cc=vadim.fedorenko@linux.dev \
    --cc=wangruikang@iscas.ac.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.