diff mbox series

[net-next,2/7] net: hibmcge: Add debugfs supported in this module

Message ID 20241023134213.3359092-3-shaojijie@huawei.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series Support some features for the HIBMCGE driver | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 5 this patch: 5
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 4 this patch: 4
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch warning WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Jijie Shao Oct. 23, 2024, 1:42 p.m. UTC
This patch supports querying the detailed status of the port
through debugfs, including the TX/RX ring, specifications,
interrupt and port status.

This driver supports four interrupts. the abnormal interrupt has
multiple interrupt sources. To locate the exception cause in detail,
the debugfs displays the status and count of each interrupt source.

Signed-off-by: Jijie Shao <shaojijie@huawei.com>
---
 .../net/ethernet/hisilicon/hibmcge/Makefile   |   3 +-
 .../ethernet/hisilicon/hibmcge/hbg_debugfs.c  | 150 ++++++++++++++++++
 .../ethernet/hisilicon/hibmcge/hbg_debugfs.h  |  12 ++
 .../net/ethernet/hisilicon/hibmcge/hbg_main.c |  26 ++-
 4 files changed, 189 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.c
 create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.h

Comments

Andrew Lunn Oct. 23, 2024, 2 p.m. UTC | #1
> +static int hbg_dbg_dev_spec(struct seq_file *s, void *unused)
> +{
> +	struct net_device *netdev = dev_get_drvdata(s->private);
> +	struct hbg_priv *priv = netdev_priv(netdev);
> +	struct hbg_dev_specs *specs;
> +
> +	specs = &priv->dev_specs;
> +	seq_printf(s, "mac id: %u\n", specs->mac_id);
> +	seq_printf(s, "phy addr: %u\n", specs->phy_addr);
> +	seq_printf(s, "mac addr: %pM\n", specs->mac_addr.sa_data);
> +	seq_printf(s, "vlan layers: %u\n", specs->vlan_layers);
> +	seq_printf(s, "max frame len: %u\n", specs->max_frame_len);
> +	seq_printf(s, "min mtu: %u, max mtu: %u\n",
> +		   specs->min_mtu, specs->max_mtu);

I think these are all available via standard APIs. There is no need to
have them in debugfs as well.

> +	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);

Is this interesting? Are you clocking it greater than 2.5MHz?

> +static int hbg_dbg_irq_info(struct seq_file *s, void *unused)
> +{
> +	struct net_device *netdev = dev_get_drvdata(s->private);
> +	struct hbg_priv *priv = netdev_priv(netdev);
> +	struct hbg_irq_info *info;
> +	u32 i;
> +
> +	for (i = 0; i < priv->vectors.info_array_len; i++) {
> +		info = &priv->vectors.info_array[i];
> +		seq_printf(s,
> +			   "%-20s: is enabled: %s, print: %s, count: %llu\n",
> +			   info->name,
> +			   hbg_get_bool_str(hbg_hw_irq_is_enabled(priv,
> +								  info->mask)),
> +			   hbg_get_bool_str(info->need_print),
> +			   info->count);
> +	}

How does this differ from what is available already from the IRQ
subsystem?

> +static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
> +{
> +	struct net_device *netdev = dev_get_drvdata(s->private);
> +	struct hbg_priv *priv = netdev_priv(netdev);
> +
> +	seq_printf(s, "event handling state: %s\n",
> +		   hbg_get_bool_str(test_bit(HBG_NIC_STATE_EVENT_HANDLING,
> +					     &priv->state)));
> +
> +	seq_printf(s, "tx timeout cnt: %llu\n", priv->stats.tx_timeout_cnt);

Don't you have this via ethtool -S ?

> @@ -209,6 +210,10 @@ static int hbg_init(struct hbg_priv *priv)
>  	if (ret)
>  		return ret;
>  
> +	ret = hbg_debugfs_init(priv);
> +	if (ret)
> +		return ret;
> +

There is no need to test the results from debugfs calls.

> +static int __init hbg_module_init(void)
> +{
> +	int ret;
> +
> +	hbg_debugfs_register();
> +	ret = pci_register_driver(&hbg_driver);
> +	if (ret)
> +		hbg_debugfs_unregister();

This seems odd. I would expect that each device has its own debugfs,
there is nothing global.

	Andrew
Jijie Shao Oct. 24, 2024, 2:19 a.m. UTC | #2
on 2024/10/23 22:00, Andrew Lunn wrote:
>> +static int hbg_dbg_dev_spec(struct seq_file *s, void *unused)
>> +{
>> +	struct net_device *netdev = dev_get_drvdata(s->private);
>> +	struct hbg_priv *priv = netdev_priv(netdev);
>> +	struct hbg_dev_specs *specs;
>> +
>> +	specs = &priv->dev_specs;
>> +	seq_printf(s, "mac id: %u\n", specs->mac_id);
>> +	seq_printf(s, "phy addr: %u\n", specs->phy_addr);
>> +	seq_printf(s, "mac addr: %pM\n", specs->mac_addr.sa_data);
>> +	seq_printf(s, "vlan layers: %u\n", specs->vlan_layers);
>> +	seq_printf(s, "max frame len: %u\n", specs->max_frame_len);
>> +	seq_printf(s, "min mtu: %u, max mtu: %u\n",
>> +		   specs->min_mtu, specs->max_mtu);
> I think these are all available via standard APIs. There is no need to
> have them in debugfs as well.

Yes, and these specifications are displayed by running the ethtool -d command. You can delete these specifications,
We will discuss internally, there is a high probability that this debugfs file will be deleted in v2.

>
>> +	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);
> Is this interesting? Are you clocking it greater than 2.5MHz?

MDIO controller supports 1MHz, 2.5MHz, 12.5MHz, and 25MHz
Of course, we chose and tested 2.5M in actual work, but this can be modified.

>
>> +static int hbg_dbg_irq_info(struct seq_file *s, void *unused)
>> +{
>> +	struct net_device *netdev = dev_get_drvdata(s->private);
>> +	struct hbg_priv *priv = netdev_priv(netdev);
>> +	struct hbg_irq_info *info;
>> +	u32 i;
>> +
>> +	for (i = 0; i < priv->vectors.info_array_len; i++) {
>> +		info = &priv->vectors.info_array[i];
>> +		seq_printf(s,
>> +			   "%-20s: is enabled: %s, print: %s, count: %llu\n",
>> +			   info->name,
>> +			   hbg_get_bool_str(hbg_hw_irq_is_enabled(priv,
>> +								  info->mask)),
>> +			   hbg_get_bool_str(info->need_print),
>> +			   info->count);
>> +	}
> How does this differ from what is available already from the IRQ
> subsystem?

We requested three interrupts: "tx", "rx", "err"
The err interrupt is a summary interrupt. We distinguish different errors
based on the status register and mask.

With "cat /proc/interrupts | grep hibmcge",
we can't distinguish the detailed cause of the error,
so we added this file to debugfs.

the following effects are achieved:
[root@localhost sjj]# cat /sys/kernel/debug/hibmcge/0000\:83\:00.1/irq_info
RX                  : is enabled: true, print: false, count: 2
TX                  : is enabled: true, print: false, count: 0
MAC_MII_FIFO_ERR    : is enabled: false, print: true, count: 0
MAC_PCS_RX_FIFO_ERR : is enabled: false, print: true, count: 0
MAC_PCS_TX_FIFO_ERR : is enabled: false, print: true, count: 0
MAC_APP_RX_FIFO_ERR : is enabled: false, print: true, count: 0
MAC_APP_TX_FIFO_ERR : is enabled: false, print: true, count: 0
SRAM_PARITY_ERR     : is enabled: true, print: true, count: 0
TX_AHB_ERR          : is enabled: true, print: true, count: 0
RX_BUF_AVL          : is enabled: true, print: false, count: 0
REL_BUF_ERR         : is enabled: true, print: true, count: 0
TXCFG_AVL           : is enabled: true, print: false, count: 0
TX_DROP             : is enabled: true, print: false, count: 0
RX_DROP             : is enabled: true, print: false, count: 0
RX_AHB_ERR          : is enabled: true, print: true, count: 0
MAC_FIFO_ERR        : is enabled: true, print: false, count: 0
RBREQ_ERR           : is enabled: true, print: false, count: 0
WE_ERR              : is enabled: true, print: false, count: 0


The irq framework of hibmcge driver also includes tx/rx interrupts.
Therefore, these interrupts are not distinguished separately in debugfs.

>
>> +static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
>> +{
>> +	struct net_device *netdev = dev_get_drvdata(s->private);
>> +	struct hbg_priv *priv = netdev_priv(netdev);
>> +
>> +	seq_printf(s, "event handling state: %s\n",
>> +		   hbg_get_bool_str(test_bit(HBG_NIC_STATE_EVENT_HANDLING,
>> +					     &priv->state)));
>> +
>> +	seq_printf(s, "tx timeout cnt: %llu\n", priv->stats.tx_timeout_cnt);
> Don't you have this via ethtool -S ?

Although tx_timeout_cnt is a statistical item, it is not displayed in the ethtool -S.

>
>> @@ -209,6 +210,10 @@ static int hbg_init(struct hbg_priv *priv)
>>   	if (ret)
>>   		return ret;
>>   
>> +	ret = hbg_debugfs_init(priv);
>> +	if (ret)
>> +		return ret;
>> +
> There is no need to test the results from debugfs calls.

ok

>
>> +static int __init hbg_module_init(void)
>> +{
>> +	int ret;
>> +
>> +	hbg_debugfs_register();
>> +	ret = pci_register_driver(&hbg_driver);
>> +	if (ret)
>> +		hbg_debugfs_unregister();
> This seems odd. I would expect that each device has its own debugfs,
> there is nothing global.
>
> 	Andrew

Yes, that's how we designed it.
In this, We register and create the root dir of hibmcge,
And in each probe(), device create their own dir using bdf:

/sys/kernel/debug/hibmcge/0000\:83\:00.1/
/sys/kernel/debug/hibmcge/0000\:83\:00.2/

for each device:
[root@localhost sjj]# ls -n /sys/kernel/debug/hibmcge/0000\:83\:00.1/
-r--r--r--. 1 0 0 0 10月 24 09:42 dev_spec
-r--r--r--. 1 0 0 0 10月 24 09:42 irq_info
-r--r--r--. 1 0 0 0 10月 24 09:42 mac_talbe
-r--r--r--. 1 0 0 0 10月 24 09:42 nic_state
-r--r--r--. 1 0 0 0 10月 24 09:42 rx_ring
-r--r--r--. 1 0 0 0 10月 24 09:42 tx_ring


Thanks a lot!
Jijie Shao
Andrew Lunn Oct. 24, 2024, 12:05 p.m. UTC | #3
> > > +	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);
> > Is this interesting? Are you clocking it greater than 2.5MHz?
> 
> MDIO controller supports 1MHz, 2.5MHz, 12.5MHz, and 25MHz
> Of course, we chose and tested 2.5M in actual work, but this can be modified.

How? What API are you using it allow it to be modified? Why cannot you
get the value using the same API?

> We requested three interrupts: "tx", "rx", "err"
> The err interrupt is a summary interrupt. We distinguish different errors
> based on the status register and mask.
> 
> With "cat /proc/interrupts | grep hibmcge",
> we can't distinguish the detailed cause of the error,
> so we added this file to debugfs.
> 
> the following effects are achieved:
> [root@localhost sjj]# cat /sys/kernel/debug/hibmcge/0000\:83\:00.1/irq_info
> RX                  : is enabled: true, print: false, count: 2
> TX                  : is enabled: true, print: false, count: 0
> MAC_MII_FIFO_ERR    : is enabled: false, print: true, count: 0
> MAC_PCS_RX_FIFO_ERR : is enabled: false, print: true, count: 0
> MAC_PCS_TX_FIFO_ERR : is enabled: false, print: true, count: 0
> MAC_APP_RX_FIFO_ERR : is enabled: false, print: true, count: 0
> MAC_APP_TX_FIFO_ERR : is enabled: false, print: true, count: 0
> SRAM_PARITY_ERR     : is enabled: true, print: true, count: 0
> TX_AHB_ERR          : is enabled: true, print: true, count: 0
> RX_BUF_AVL          : is enabled: true, print: false, count: 0
> REL_BUF_ERR         : is enabled: true, print: true, count: 0
> TXCFG_AVL           : is enabled: true, print: false, count: 0
> TX_DROP             : is enabled: true, print: false, count: 0
> RX_DROP             : is enabled: true, print: false, count: 0
> RX_AHB_ERR          : is enabled: true, print: true, count: 0
> MAC_FIFO_ERR        : is enabled: true, print: false, count: 0
> RBREQ_ERR           : is enabled: true, print: false, count: 0
> WE_ERR              : is enabled: true, print: false, count: 0
> 
> 
> The irq framework of hibmcge driver also includes tx/rx interrupts.
> Therefore, these interrupts are not distinguished separately in debugfs.

Please make this a patch of its own, and include this in the commit
message.

Ideally you need to show there is no standard API for what you want to
put into debugfs, because if there is a standard API, you don't need
debugfs...

> 
> > 
> > > +static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
> > > +{
> > > +	struct net_device *netdev = dev_get_drvdata(s->private);
> > > +	struct hbg_priv *priv = netdev_priv(netdev);
> > > +
> > > +	seq_printf(s, "event handling state: %s\n",
> > > +		   hbg_get_bool_str(test_bit(HBG_NIC_STATE_EVENT_HANDLING,
> > > +					     &priv->state)));
> > > +
> > > +	seq_printf(s, "tx timeout cnt: %llu\n", priv->stats.tx_timeout_cnt);
> > Don't you have this via ethtool -S ?
> 
> Although tx_timeout_cnt is a statistical item, it is not displayed in the ethtool -S.

Why?

	Andrew
Jijie Shao Oct. 24, 2024, 2:06 p.m. UTC | #4
on 2024/10/24 20:05, Andrew Lunn wrote:
>>>> +	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);
>>> Is this interesting? Are you clocking it greater than 2.5MHz?
>> MDIO controller supports 1MHz, 2.5MHz, 12.5MHz, and 25MHz
>> Of course, we chose and tested 2.5M in actual work, but this can be modified.
> How? What API are you using it allow it to be modified? Why cannot you
> get the value using the same API?

This frequency cannot be modified dynamically.
There are some specification registers that store some initialization configuration parameters
written by the BMC, such as the default MAC address and hardware FIFO size and mdio frequency.

When the device is in prob, the driver reads the related configuration information and
initializes the device based on the configuration.

>
>> We requested three interrupts: "tx", "rx", "err"
>> The err interrupt is a summary interrupt. We distinguish different errors
>> based on the status register and mask.
>>
>> With "cat /proc/interrupts | grep hibmcge",
>> we can't distinguish the detailed cause of the error,
>> so we added this file to debugfs.
>>
>> the following effects are achieved:
>> [root@localhost sjj]# cat /sys/kernel/debug/hibmcge/0000\:83\:00.1/irq_info
>> RX                  : is enabled: true, print: false, count: 2
>> TX                  : is enabled: true, print: false, count: 0
>> MAC_MII_FIFO_ERR    : is enabled: false, print: true, count: 0
>> MAC_PCS_RX_FIFO_ERR : is enabled: false, print: true, count: 0
>> MAC_PCS_TX_FIFO_ERR : is enabled: false, print: true, count: 0
>> MAC_APP_RX_FIFO_ERR : is enabled: false, print: true, count: 0
>> MAC_APP_TX_FIFO_ERR : is enabled: false, print: true, count: 0
>> SRAM_PARITY_ERR     : is enabled: true, print: true, count: 0
>> TX_AHB_ERR          : is enabled: true, print: true, count: 0
>> RX_BUF_AVL          : is enabled: true, print: false, count: 0
>> REL_BUF_ERR         : is enabled: true, print: true, count: 0
>> TXCFG_AVL           : is enabled: true, print: false, count: 0
>> TX_DROP             : is enabled: true, print: false, count: 0
>> RX_DROP             : is enabled: true, print: false, count: 0
>> RX_AHB_ERR          : is enabled: true, print: true, count: 0
>> MAC_FIFO_ERR        : is enabled: true, print: false, count: 0
>> RBREQ_ERR           : is enabled: true, print: false, count: 0
>> WE_ERR              : is enabled: true, print: false, count: 0
>>
>>
>> The irq framework of hibmcge driver also includes tx/rx interrupts.
>> Therefore, these interrupts are not distinguished separately in debugfs.
> Please make this a patch of its own, and include this in the commit
> message.
>
> Ideally you need to show there is no standard API for what you want to
> put into debugfs, because if there is a standard API, you don't need
> debugfs...

Because standard API don't meet my needs, I added detailed interrupt information to debugfs.
I'll add a detailed description to the commit message of v2.

>
>>>> +static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
>>>> +{
>>>> +	struct net_device *netdev = dev_get_drvdata(s->private);
>>>> +	struct hbg_priv *priv = netdev_priv(netdev);
>>>> +
>>>> +	seq_printf(s, "event handling state: %s\n",
>>>> +		   hbg_get_bool_str(test_bit(HBG_NIC_STATE_EVENT_HANDLING,
>>>> +					     &priv->state)));
>>>> +
>>>> +	seq_printf(s, "tx timeout cnt: %llu\n", priv->stats.tx_timeout_cnt);
>>> Don't you have this via ethtool -S ?
>> Although tx_timeout_cnt is a statistical item, it is not displayed in the ethtool -S.
> Why?
>
> 	Andrew

This was decided by our internal discussion before,
and we'll revisit it, and move it to ethtool -S in the next version if it's okay with us.

Thanks,
Jijie Shao
Andrew Lunn Oct. 24, 2024, 2:21 p.m. UTC | #5
On Thu, Oct 24, 2024 at 10:06:14PM +0800, Jijie Shao wrote:
> 
> on 2024/10/24 20:05, Andrew Lunn wrote:
> > > > > +	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);
> > > > Is this interesting? Are you clocking it greater than 2.5MHz?
> > > MDIO controller supports 1MHz, 2.5MHz, 12.5MHz, and 25MHz
> > > Of course, we chose and tested 2.5M in actual work, but this can be modified.
> > How? What API are you using it allow it to be modified? Why cannot you
> > get the value using the same API?
> 
> This frequency cannot be modified dynamically.
> There are some specification registers that store some initialization configuration parameters
> written by the BMC, such as the default MAC address and hardware FIFO size and mdio frequency.
> 
> When the device is in prob, the driver reads the related configuration information and
> initializes the device based on the configuration.

Does the BMC have an API to set these values? And show these values?

	Andrew
Jijie Shao Oct. 24, 2024, 2:31 p.m. UTC | #6
on 2024/10/24 22:21, Andrew Lunn wrote:
> On Thu, Oct 24, 2024 at 10:06:14PM +0800, Jijie Shao wrote:
>> on 2024/10/24 20:05, Andrew Lunn wrote:
>>>>>> +	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);
>>>>> Is this interesting? Are you clocking it greater than 2.5MHz?
>>>> MDIO controller supports 1MHz, 2.5MHz, 12.5MHz, and 25MHz
>>>> Of course, we chose and tested 2.5M in actual work, but this can be modified.
>>> How? What API are you using it allow it to be modified? Why cannot you
>>> get the value using the same API?
>> This frequency cannot be modified dynamically.
>> There are some specification registers that store some initialization configuration parameters
>> written by the BMC, such as the default MAC address and hardware FIFO size and mdio frequency.
>>
>> When the device is in prob, the driver reads the related configuration information and
>> initializes the device based on the configuration.
> Does the BMC have an API to set these values? And show these values?
>
> 	Andrew

Currently, there are no other API except devmem.

But this is not important.
According to the discussion in patch "[PATCH net-next 4/7] net: hibmcge: Add register dump supported in this module",
this debugfs file will be deleted. I will put these informations in register dump by ethtool -d.

Thanks
diff mbox series

Patch

diff --git a/drivers/net/ethernet/hisilicon/hibmcge/Makefile b/drivers/net/ethernet/hisilicon/hibmcge/Makefile
index ae58ac38c206..1a0ec2fb8c24 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/Makefile
+++ b/drivers/net/ethernet/hisilicon/hibmcge/Makefile
@@ -5,4 +5,5 @@ 
 
 obj-$(CONFIG_HIBMCGE) += hibmcge.o
 
-hibmcge-objs = hbg_main.o hbg_hw.o hbg_mdio.o hbg_irq.o hbg_txrx.o hbg_ethtool.o
+hibmcge-objs = hbg_main.o hbg_hw.o hbg_mdio.o hbg_irq.o hbg_txrx.o hbg_ethtool.o \
+		hbg_debugfs.o
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.c
new file mode 100644
index 000000000000..e65e1d498d2b
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.c
@@ -0,0 +1,150 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2024 Hisilicon Limited.
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/seq_file.h>
+#include "hbg_common.h"
+#include "hbg_debugfs.h"
+#include "hbg_hw.h"
+#include "hbg_irq.h"
+#include "hbg_txrx.h"
+
+static struct dentry *hbg_dbgfs_root;
+
+struct hbg_dbg_info {
+	const char *name;
+	int (*read)(struct seq_file *seq, void *data);
+};
+
+#define hbg_get_bool_str(state) ((state) ? "true" : "false")
+
+static int hbg_dbg_dev_spec(struct seq_file *s, void *unused)
+{
+	struct net_device *netdev = dev_get_drvdata(s->private);
+	struct hbg_priv *priv = netdev_priv(netdev);
+	struct hbg_dev_specs *specs;
+
+	specs = &priv->dev_specs;
+	seq_printf(s, "mac id: %u\n", specs->mac_id);
+	seq_printf(s, "phy addr: %u\n", specs->phy_addr);
+	seq_printf(s, "mac addr: %pM\n", specs->mac_addr.sa_data);
+	seq_printf(s, "vlan layers: %u\n", specs->vlan_layers);
+	seq_printf(s, "max frame len: %u\n", specs->max_frame_len);
+	seq_printf(s, "min mtu: %u, max mtu: %u\n",
+		   specs->min_mtu, specs->max_mtu);
+	seq_printf(s, "mdio frequency: %u\n", specs->mdio_frequency);
+
+	return 0;
+}
+
+static void hbg_dbg_ring(struct hbg_priv *priv, struct hbg_ring *ring,
+			 struct seq_file *s)
+{
+	u32 irq_mask = ring->dir == HBG_DIR_TX ? HBG_INT_MSK_TX_B :
+						 HBG_INT_MSK_RX_B;
+
+	seq_printf(s, "ring used num: %u\n",
+		   hbg_get_queue_used_num(ring));
+	seq_printf(s, "ring max num: %u\n", ring->len);
+	seq_printf(s, "ring head: %u, tail: %u\n", ring->head, ring->tail);
+	seq_printf(s, "fifo used num: %u\n",
+		   hbg_hw_get_fifo_used_num(priv, ring->dir));
+	seq_printf(s, "fifo max num: %u\n",
+		   hbg_get_spec_fifo_max_num(priv, ring->dir));
+	seq_printf(s, "irq enabled: %s\n",
+		   hbg_get_bool_str(hbg_hw_irq_is_enabled(priv, irq_mask)));
+}
+
+static int hbg_dbg_tx_ring(struct seq_file *s, void *unused)
+{
+	struct net_device *netdev = dev_get_drvdata(s->private);
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	hbg_dbg_ring(priv, &priv->tx_ring, s);
+	return 0;
+}
+
+static int hbg_dbg_rx_ring(struct seq_file *s, void *unused)
+{
+	struct net_device *netdev = dev_get_drvdata(s->private);
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	hbg_dbg_ring(priv, &priv->rx_ring, s);
+	return 0;
+}
+
+static int hbg_dbg_irq_info(struct seq_file *s, void *unused)
+{
+	struct net_device *netdev = dev_get_drvdata(s->private);
+	struct hbg_priv *priv = netdev_priv(netdev);
+	struct hbg_irq_info *info;
+	u32 i;
+
+	for (i = 0; i < priv->vectors.info_array_len; i++) {
+		info = &priv->vectors.info_array[i];
+		seq_printf(s,
+			   "%-20s: is enabled: %s, print: %s, count: %llu\n",
+			   info->name,
+			   hbg_get_bool_str(hbg_hw_irq_is_enabled(priv,
+								  info->mask)),
+			   hbg_get_bool_str(info->need_print),
+			   info->count);
+	}
+
+	return 0;
+}
+
+static int hbg_dbg_nic_state(struct seq_file *s, void *unused)
+{
+	struct net_device *netdev = dev_get_drvdata(s->private);
+	struct hbg_priv *priv = netdev_priv(netdev);
+
+	seq_printf(s, "event handling state: %s\n",
+		   hbg_get_bool_str(test_bit(HBG_NIC_STATE_EVENT_HANDLING,
+					     &priv->state)));
+
+	seq_printf(s, "tx timeout cnt: %llu\n", priv->stats.tx_timeout_cnt);
+	return 0;
+}
+
+static const struct hbg_dbg_info hbg_dbg_infos[] = {
+	{ "dev_spec", hbg_dbg_dev_spec },
+	{ "tx_ring", hbg_dbg_tx_ring },
+	{ "rx_ring", hbg_dbg_rx_ring },
+	{ "irq_info", hbg_dbg_irq_info },
+	{ "nic_state", hbg_dbg_nic_state },
+};
+
+static void hbg_debugfs_uninit(void *data)
+{
+	debugfs_remove_recursive((struct dentry *)data);
+}
+
+int hbg_debugfs_init(struct hbg_priv *priv)
+{
+	const char *name = pci_name(priv->pdev);
+	struct device *dev = &priv->pdev->dev;
+	struct dentry *root;
+	u32 i;
+
+	root = debugfs_create_dir(name, hbg_dbgfs_root);
+
+	for (i = 0; i < ARRAY_SIZE(hbg_dbg_infos); i++)
+		debugfs_create_devm_seqfile(dev, hbg_dbg_infos[i].name,
+					    root, hbg_dbg_infos[i].read);
+
+	return devm_add_action_or_reset(dev, hbg_debugfs_uninit, root);
+}
+
+void hbg_debugfs_register(void)
+{
+	hbg_dbgfs_root = debugfs_create_dir("hibmcge", NULL);
+}
+
+void hbg_debugfs_unregister(void)
+{
+	debugfs_remove_recursive(hbg_dbgfs_root);
+	hbg_dbgfs_root = NULL;
+}
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.h
new file mode 100644
index 000000000000..678651ec710b
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.h
@@ -0,0 +1,12 @@ 
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2024 Hisilicon Limited. */
+
+#ifndef __HBG_DEBUGFS_H
+#define __HBG_DEBUGFS_H
+
+void hbg_debugfs_register(void);
+void hbg_debugfs_unregister(void);
+
+int hbg_debugfs_init(struct hbg_priv *priv);
+
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
index 33fe92104e90..30576483a938 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
@@ -11,6 +11,7 @@ 
 #include "hbg_irq.h"
 #include "hbg_mdio.h"
 #include "hbg_txrx.h"
+#include "hbg_debugfs.h"
 
 static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu);
 
@@ -209,6 +210,10 @@  static int hbg_init(struct hbg_priv *priv)
 	if (ret)
 		return ret;
 
+	ret = hbg_debugfs_init(priv);
+	if (ret)
+		return ret;
+
 	hbg_delaywork_init(priv);
 	return devm_add_action_or_reset(&priv->pdev->dev, hbg_delaywork_uninit,
 					&priv->service_task);
@@ -296,7 +301,26 @@  static struct pci_driver hbg_driver = {
 	.id_table	= hbg_pci_tbl,
 	.probe		= hbg_probe,
 };
-module_pci_driver(hbg_driver);
+
+static int __init hbg_module_init(void)
+{
+	int ret;
+
+	hbg_debugfs_register();
+	ret = pci_register_driver(&hbg_driver);
+	if (ret)
+		hbg_debugfs_unregister();
+
+	return ret;
+}
+module_init(hbg_module_init);
+
+static void __exit hbg_module_exit(void)
+{
+	pci_unregister_driver(&hbg_driver);
+	hbg_debugfs_unregister();
+}
+module_exit(hbg_module_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Huawei Tech. Co., Ltd.");