Subject: Re: [PATCH net-next v10 4/7] net: tn40xx: add basic Tx handling

From: Jakub Kicinski <[email-masked]>
Date: Thu, 13 Jun 2024 17:48:08 -0700

On Tue, 11 Jun 2024 13:52:14 +0900 FUJITA Tomonori wrote:
> +	/* 1. load MAC (obsolete) */
> +	/* 2. disable Rx (and Tx) */
> +	tn40_write_reg(priv, TN40_REG_GMAC_RXF_A, 0);
> +	mdelay(100);

Why mdelay()? 100ms of CPU spinning in a loop is not great.
I only see calls to tn40_sw_reset() from open and close, both
of which can sleep so you should be able to use msleep().

You can test with CONFIG_DEBUG_ATOMIC_SLEEP enabled to confirm.

> +	/* 3. Disable port */
> +	tn40_write_reg(priv, TN40_REG_DIS_PORT, 1);
> +	/* 4. Disable queue */
> +	tn40_write_reg(priv, TN40_REG_DIS_QU, 1);
> +	/* 5. Wait until hw is disabled */
> +	for (i = 0; i < 50; i++) {
> +		if (tn40_read_reg(priv, TN40_REG_RST_PORT) & 1)
> +			break;
> +		mdelay(10);

read_poll_timeout() ?

> +	}
> +	if (i == 50)
> +		netdev_err(priv->ndev, "SW reset timeout. continuing anyway\n");

> +	if (unlikely(vid >= 4096)) {

can the core actually call with an invalid vid? I don't thinks so..

> +	struct tn40_priv *priv = netdev_priv(ndev);
> +
> +	u32 rxf_val = TN40_GMAC_RX_FILTER_AM | TN40_GMAC_RX_FILTER_AB |
> +		TN40_GMAC_RX_FILTER_OSEN | TN40_GMAC_RX_FILTER_TXFC;
> +	int i;
> +

nit: no empty lines between variable declarations

> +		u8 hash;
> +		struct netdev_hw_addr *mclist;
> +		u32 reg, val;

nit: declaration lines longest to shortest within a block

> +static void tn40_get_stats(struct net_device *ndev,
> +			   struct rtnl_link_stats64 *stats)
> +{
> +	struct tn40_priv *priv = netdev_priv(ndev);
> +
> +	netdev_stats_to_stats64(stats, &priv->net_stats);

You should hold the stats in driver priv, probably:

from struct net_device:

	struct net_device_stats	stats; /* not used by modern drivers */

> +static int tn40_priv_init(struct tn40_priv *priv)
> +{
> +	int ret;
> +
> +	tn40_set_link_speed(priv, 0);
> +
> +	ret = tn40_hw_reset(priv);
> +	if (ret)
> +		return ret;

But probe already called reset, is there a reason to reset multiple
times? Would be good to add some reason why in a comment (if you know)

> +	/* Set GPIO[9:0] to output 0 */
> +	tn40_write_reg(priv, 0x51E0, 0x30010006);	/* GPIO_OE_ WR CMD */
> +	tn40_write_reg(priv, 0x51F0, 0x0);	/* GPIO_OE_ DATA */
> +	tn40_write_reg(priv, TN40_REG_MDIO_CMD_STAT, 0x3ec8);
> +
> +	// we use tx descriptors to load a firmware.

nit: stick to a single style of comments? ;)

> +	ret = tn40_create_tx_ring(priv);
> +	if (ret)
> +		return ret;
> +	ret = tn40_fw_load(priv);
> +	tn40_destroy_tx_ring(priv);