Unverified Commit 6eb132ae authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!15076 [olk 6.6] backport some feature patches for hibmcge driver

Merge Pull Request from: @chen-hao418 
 
maillist inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IBM1QO
CVE: NA

1. net: hibmcge: Add nway_reset supported in this module
2. net: hibmcge: Add reset supported in this module
3. net: hibmcge: Add pauseparam supported in this module
4. net: hibmcge: Add register dump supported in this module
5. net: hibmcge: Add unicast frame filter supported in this module
6. net: hibmcge: Add irq_info file to debugfs
7. net: hibmcge: Add debugfs supported in this module
8. lib/string_choices: Add str_true_false()/str_false_true() helper 
 
Link:https://gitee.com/openeuler/kernel/pulls/15076

 

Signed-off-by: default avatarZhang Peng <zhangpeng362@huawei.com>
parents 1167f85d 11aaa393
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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 hbg_err.o
+29 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#ifndef __HBG_COMMON_H
#define __HBG_COMMON_H

#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include "hbg_reg.h"
@@ -33,6 +34,14 @@ enum hbg_tx_state {

enum hbg_nic_state {
	HBG_NIC_STATE_EVENT_HANDLING = 0,
	HBG_NIC_STATE_RESETTING,
	HBG_NIC_STATE_RESET_FAIL,
};

enum hbg_reset_type {
	HBG_RESET_TYPE_NONE = 0,
	HBG_RESET_TYPE_FLR,
	HBG_RESET_TYPE_FUNCTION,
};

struct hbg_buffer {
@@ -84,6 +93,7 @@ struct hbg_dev_specs {
	u32 vlan_layers;
	u32 max_mtu;
	u32 min_mtu;
	u32 uc_mac_num;

	u32 max_frame_len;
	u32 rx_buf_size;
@@ -114,6 +124,22 @@ struct hbg_mac {
	u32 duplex;
	u32 autoneg;
	u32 link_status;
	u32 pause_autoneg;
};

struct hbg_mac_table_entry {
	u8 addr[ETH_ALEN];
};

struct hbg_mac_filter {
	struct hbg_mac_table_entry *mac_table;
	u32 table_max_len;
	bool enabled;
};

/* saved for restore after rest */
struct hbg_user_def {
	struct ethtool_pauseparam pause_param;
};

struct hbg_priv {
@@ -126,6 +152,9 @@ struct hbg_priv {
	struct hbg_vector vectors;
	struct hbg_ring tx_ring;
	struct hbg_ring rx_ring;
	struct hbg_mac_filter filter;
	enum hbg_reset_type reset_type;
	struct hbg_user_def user_def;
};

#endif
+160 −0
Original line number Diff line number Diff line
// 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 <linux/string_choices.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 state_str_true_false(p, s) str_true_false(test_bit(s, &(p)->state))

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",
		   str_true_false(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: enabled: %-5s, logged: %-5s, count: %llu\n",
			   info->name,
			   str_true_false(hbg_hw_irq_is_enabled(priv,
								info->mask)),
			   str_true_false(info->need_print),
			   info->count);
	}

	return 0;
}

static int hbg_dbg_mac_table(struct seq_file *s, void *unused)
{
	struct net_device *netdev = dev_get_drvdata(s->private);
	struct hbg_priv *priv = netdev_priv(netdev);
	struct hbg_mac_filter *filter;
	u32 i;

	filter = &priv->filter;
	seq_printf(s, "mac addr max count: %u\n", filter->table_max_len);
	seq_printf(s, "filter enabled: %s\n", str_true_false(filter->enabled));

	for (i = 0; i < filter->table_max_len; i++) {
		if (is_zero_ether_addr(filter->mac_table[i].addr))
			continue;

		seq_printf(s, "[%u] %pM\n", i, filter->mac_table[i].addr);
	}

	return 0;
}

static const char * const reset_type_str[] = {"None", "FLR", "Function"};

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",
		   state_str_true_false(priv, HBG_NIC_STATE_EVENT_HANDLING));
	seq_printf(s, "resetting state: %s\n",
		   state_str_true_false(priv, HBG_NIC_STATE_RESETTING));
	seq_printf(s, "reset fail state: %s\n",
		   state_str_true_false(priv, HBG_NIC_STATE_RESET_FAIL));
	seq_printf(s, "last reset type: %s\n",
		   reset_type_str[priv->reset_type]);

	return 0;
}

static const struct hbg_dbg_info hbg_dbg_infos[] = {
	{ "tx_ring", hbg_dbg_tx_ring },
	{ "rx_ring", hbg_dbg_rx_ring },
	{ "irq_info", hbg_dbg_irq_info },
	{ "mac_table", hbg_dbg_mac_table },
	{ "nic_state", hbg_dbg_nic_state },
};

static void hbg_debugfs_uninit(void *data)
{
	debugfs_remove_recursive((struct dentry *)data);
}

void 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);

	/* Ignore the failure because debugfs is not a key feature. */
	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;
}
+12 −0
Original line number Diff line number Diff line
/* 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);

void hbg_debugfs_init(struct hbg_priv *priv);

#endif
+134 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0+
// Copyright (c) 2024 Hisilicon Limited.

#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/rtnetlink.h>
#include "hbg_common.h"
#include "hbg_err.h"
#include "hbg_hw.h"

static void hbg_restore_mac_table(struct hbg_priv *priv)
{
	struct hbg_mac_filter *filter = &priv->filter;
	u64 addr;
	u32 i;

	for (i = 0; i < filter->table_max_len; i++)
		if (!is_zero_ether_addr(filter->mac_table[i].addr)) {
			addr = ether_addr_to_u64(filter->mac_table[i].addr);
			hbg_hw_set_uc_addr(priv, addr, i);
		}

	hbg_hw_set_mac_filter_enable(priv, priv->filter.enabled);
}

static void hbg_restore_user_def_settings(struct hbg_priv *priv)
{
	struct ethtool_pauseparam *pause_param = &priv->user_def.pause_param;

	hbg_restore_mac_table(priv);
	hbg_hw_set_mtu(priv, priv->netdev->mtu);
	hbg_hw_set_pause_enable(priv, pause_param->tx_pause,
				pause_param->rx_pause);
}

int hbg_rebuild(struct hbg_priv *priv)
{
	int ret;

	ret = hbg_hw_init(priv);
	if (ret)
		return ret;

	hbg_restore_user_def_settings(priv);
	return 0;
}

static int hbg_reset_prepare(struct hbg_priv *priv, enum hbg_reset_type type)
{
	int ret;

	ASSERT_RTNL();

	if (netif_running(priv->netdev)) {
		dev_warn(&priv->pdev->dev,
			 "failed to reset because port is up\n");
		return -EBUSY;
	}

	priv->reset_type = type;
	set_bit(HBG_NIC_STATE_RESETTING, &priv->state);
	clear_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state);
	ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET);
	if (ret) {
		set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state);
		clear_bit(HBG_NIC_STATE_RESETTING, &priv->state);
	}

	return ret;
}

static int hbg_reset_done(struct hbg_priv *priv, enum hbg_reset_type type)
{
	int ret;

	if (!test_bit(HBG_NIC_STATE_RESETTING, &priv->state) ||
	    type != priv->reset_type)
		return 0;

	ASSERT_RTNL();

	clear_bit(HBG_NIC_STATE_RESETTING, &priv->state);
	ret = hbg_rebuild(priv);
	if (ret) {
		set_bit(HBG_NIC_STATE_RESET_FAIL, &priv->state);
		dev_err(&priv->pdev->dev, "failed to rebuild after reset\n");
		return ret;
	}

	dev_info(&priv->pdev->dev, "reset done\n");
	return ret;
}

/* must be protected by rtnl lock */
int hbg_reset(struct hbg_priv *priv)
{
	int ret;

	ASSERT_RTNL();
	ret = hbg_reset_prepare(priv, HBG_RESET_TYPE_FUNCTION);
	if (ret)
		return ret;

	return hbg_reset_done(priv, HBG_RESET_TYPE_FUNCTION);
}

static void hbg_pci_err_reset_prepare(struct pci_dev *pdev)
{
	struct net_device *netdev = pci_get_drvdata(pdev);
	struct hbg_priv *priv = netdev_priv(netdev);

	rtnl_lock();
	hbg_reset_prepare(priv, HBG_RESET_TYPE_FLR);
}

static void hbg_pci_err_reset_done(struct pci_dev *pdev)
{
	struct net_device *netdev = pci_get_drvdata(pdev);
	struct hbg_priv *priv = netdev_priv(netdev);

	hbg_reset_done(priv, HBG_RESET_TYPE_FLR);
	rtnl_unlock();
}

static const struct pci_error_handlers hbg_pci_err_handler = {
	.reset_prepare = hbg_pci_err_reset_prepare,
	.reset_done = hbg_pci_err_reset_done,
};

void hbg_set_pci_err_handler(struct pci_driver *pdrv)
{
	pdrv->err_handler = &hbg_pci_err_handler;
}
Loading