mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 06:31:58 +02:00
Merge branch 'support-some-features-for-the-hibmcge-driver'
Jijie Shao says: ==================== Support some features for the HIBMCGE driver In this patch series, The HIBMCGE driver implements some functions such as dump register, unicast MAC address filtering, debugfs and reset. ==================== Link: https://patch.msgid.link/20241216040532.1566229-1-shaojijie@huawei.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
2b9da35f48
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.c
Normal file
160
drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// 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
drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.h
Normal file
12
drivers/net/ethernet/hisilicon/hibmcge/hbg_debugfs.h
Normal file
|
|
@ -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);
|
||||
|
||||
void hbg_debugfs_init(struct hbg_priv *priv);
|
||||
|
||||
#endif
|
||||
134
drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c
Normal file
134
drivers/net/ethernet/hisilicon/hibmcge/hbg_err.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// 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;
|
||||
}
|
||||
13
drivers/net/ethernet/hisilicon/hibmcge/hbg_err.h
Normal file
13
drivers/net/ethernet/hisilicon/hibmcge/hbg_err.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/* Copyright (c) 2024 Hisilicon Limited. */
|
||||
|
||||
#ifndef __HBG_ERR_H
|
||||
#define __HBG_ERR_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
void hbg_set_pci_err_handler(struct pci_driver *pdrv);
|
||||
int hbg_reset(struct hbg_priv *priv);
|
||||
int hbg_rebuild(struct hbg_priv *priv);
|
||||
|
||||
#endif
|
||||
|
|
@ -3,12 +3,193 @@
|
|||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include "hbg_common.h"
|
||||
#include "hbg_err.h"
|
||||
#include "hbg_ethtool.h"
|
||||
#include "hbg_hw.h"
|
||||
|
||||
enum hbg_reg_dump_type {
|
||||
HBG_DUMP_REG_TYPE_SPEC = 0,
|
||||
HBG_DUMP_REG_TYPE_MDIO,
|
||||
HBG_DUMP_REG_TYPE_GMAC,
|
||||
HBG_DUMP_REG_TYPE_PCU,
|
||||
};
|
||||
|
||||
struct hbg_reg_info {
|
||||
u32 type;
|
||||
u32 offset;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
#define HBG_DUMP_SPEC_I(offset) {HBG_DUMP_REG_TYPE_SPEC, offset, 0}
|
||||
#define HBG_DUMP_MDIO_I(offset) {HBG_DUMP_REG_TYPE_MDIO, offset, 0}
|
||||
#define HBG_DUMP_GMAC_I(offset) {HBG_DUMP_REG_TYPE_GMAC, offset, 0}
|
||||
#define HBG_DUMP_PCU_I(offset) {HBG_DUMP_REG_TYPE_PCU, offset, 0}
|
||||
|
||||
static const struct hbg_reg_info hbg_dump_reg_infos[] = {
|
||||
/* dev specs */
|
||||
HBG_DUMP_SPEC_I(HBG_REG_SPEC_VALID_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_EVENT_REQ_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_MAC_ID_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_PHY_ID_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_MAC_ADDR_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_MAC_ADDR_HIGH_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_UC_MAC_NUM_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_MDIO_FREQ_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_MAX_MTU_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_MIN_MTU_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_TX_FIFO_NUM_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_RX_FIFO_NUM_ADDR),
|
||||
HBG_DUMP_SPEC_I(HBG_REG_VLAN_LAYERS_ADDR),
|
||||
|
||||
/* mdio */
|
||||
HBG_DUMP_MDIO_I(HBG_REG_MDIO_COMMAND_ADDR),
|
||||
HBG_DUMP_MDIO_I(HBG_REG_MDIO_ADDR_ADDR),
|
||||
HBG_DUMP_MDIO_I(HBG_REG_MDIO_WDATA_ADDR),
|
||||
HBG_DUMP_MDIO_I(HBG_REG_MDIO_RDATA_ADDR),
|
||||
HBG_DUMP_MDIO_I(HBG_REG_MDIO_STA_ADDR),
|
||||
|
||||
/* gmac */
|
||||
HBG_DUMP_GMAC_I(HBG_REG_DUPLEX_TYPE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_FD_FC_TYPE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_FC_TX_TIMER_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_FD_FC_ADDR_LOW_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_FD_FC_ADDR_HIGH_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_MAX_FRAME_SIZE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_PORT_MODE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_PORT_ENABLE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_PAUSE_ENABLE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_AN_NEG_STATE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_TRANSMIT_CTRL_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_REC_FILT_CTRL_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_LINE_LOOP_BACK_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_CF_CRC_STRIP_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_MODE_CHANGE_EN_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_LOOP_REG_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_RECV_CTRL_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_VLAN_CODE_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_0_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_0_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_1_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_1_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_2_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_2_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_3_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_3_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_4_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_4_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_LOW_5_ADDR),
|
||||
HBG_DUMP_GMAC_I(HBG_REG_STATION_ADDR_HIGH_5_ADDR),
|
||||
|
||||
/* pcu */
|
||||
HBG_DUMP_PCU_I(HBG_REG_TX_FIFO_THRSLD_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_RX_FIFO_THRSLD_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CFG_FIFO_THRSLD_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_MSK_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_STAT_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_INTRPT_CLR_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_TX_BUS_ERR_ADDR_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_RX_BUS_ERR_ADDR_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_MAX_FRAME_LEN_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_DEBUG_ST_MCH_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_FIFO_CURR_STATUS_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_FIFO_HIST_STATUS_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_CFF_DATA_NUM_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_TX_PAUSE_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_RX_CFF_ADDR_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_RX_BUF_SIZE_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_BUS_CTRL_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_RX_CTRL_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_RX_PKT_MODE_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_DBG_ST0_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_DBG_ST1_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_DBG_ST2_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_BUS_RST_EN_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_MSK_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_STAT_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_IND_TXINT_CLR_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_MSK_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_STAT_ADDR),
|
||||
HBG_DUMP_PCU_I(HBG_REG_CF_IND_RXINT_CLR_ADDR),
|
||||
};
|
||||
|
||||
static const u32 hbg_dump_type_base_array[] = {
|
||||
[HBG_DUMP_REG_TYPE_SPEC] = 0,
|
||||
[HBG_DUMP_REG_TYPE_MDIO] = HBG_REG_MDIO_BASE,
|
||||
[HBG_DUMP_REG_TYPE_GMAC] = HBG_REG_SGMII_BASE,
|
||||
[HBG_DUMP_REG_TYPE_PCU] = HBG_REG_SGMII_BASE,
|
||||
};
|
||||
|
||||
static int hbg_ethtool_get_regs_len(struct net_device *netdev)
|
||||
{
|
||||
return ARRAY_SIZE(hbg_dump_reg_infos) * sizeof(struct hbg_reg_info);
|
||||
}
|
||||
|
||||
static void hbg_ethtool_get_regs(struct net_device *netdev,
|
||||
struct ethtool_regs *regs, void *data)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
struct hbg_reg_info *info;
|
||||
u32 i, offset = 0;
|
||||
|
||||
regs->version = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(hbg_dump_reg_infos); i++) {
|
||||
info = data + offset;
|
||||
|
||||
*info = hbg_dump_reg_infos[i];
|
||||
info->val = hbg_reg_read(priv, info->offset);
|
||||
info->offset -= hbg_dump_type_base_array[info->type];
|
||||
|
||||
offset += sizeof(*info);
|
||||
}
|
||||
}
|
||||
|
||||
static void hbg_ethtool_get_pauseparam(struct net_device *net_dev,
|
||||
struct ethtool_pauseparam *param)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(net_dev);
|
||||
|
||||
param->autoneg = priv->mac.pause_autoneg;
|
||||
hbg_hw_get_pause_enable(priv, ¶m->tx_pause, ¶m->rx_pause);
|
||||
}
|
||||
|
||||
static int hbg_ethtool_set_pauseparam(struct net_device *net_dev,
|
||||
struct ethtool_pauseparam *param)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(net_dev);
|
||||
|
||||
priv->mac.pause_autoneg = param->autoneg;
|
||||
phy_set_asym_pause(priv->mac.phydev, param->rx_pause, param->tx_pause);
|
||||
|
||||
if (!param->autoneg)
|
||||
hbg_hw_set_pause_enable(priv, param->tx_pause, param->rx_pause);
|
||||
|
||||
priv->user_def.pause_param = *param;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hbg_ethtool_reset(struct net_device *netdev, u32 *flags)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (*flags != ETH_RESET_DEDICATED)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
*flags = 0;
|
||||
return hbg_reset(priv);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops hbg_ethtool_ops = {
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_link_ksettings = phy_ethtool_get_link_ksettings,
|
||||
.set_link_ksettings = phy_ethtool_set_link_ksettings,
|
||||
.get_regs_len = hbg_ethtool_get_regs_len,
|
||||
.get_regs = hbg_ethtool_get_regs,
|
||||
.get_pauseparam = hbg_ethtool_get_pauseparam,
|
||||
.set_pauseparam = hbg_ethtool_set_pauseparam,
|
||||
.reset = hbg_ethtool_reset,
|
||||
.nway_reset = phy_ethtool_nway_reset,
|
||||
};
|
||||
|
||||
void hbg_ethtool_set_ops(struct net_device *netdev)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/minmax.h>
|
||||
#include "hbg_common.h"
|
||||
|
|
@ -67,6 +68,8 @@ static int hbg_hw_dev_specs_init(struct hbg_priv *priv)
|
|||
specs->vlan_layers = hbg_reg_read(priv, HBG_REG_VLAN_LAYERS_ADDR);
|
||||
specs->rx_fifo_num = hbg_reg_read(priv, HBG_REG_RX_FIFO_NUM_ADDR);
|
||||
specs->tx_fifo_num = hbg_reg_read(priv, HBG_REG_TX_FIFO_NUM_ADDR);
|
||||
specs->uc_mac_num = hbg_reg_read(priv, HBG_REG_UC_MAC_NUM_ADDR);
|
||||
|
||||
mac_addr = hbg_reg_read64(priv, HBG_REG_MAC_ADDR_ADDR);
|
||||
u64_to_ether_addr(mac_addr, (u8 *)specs->mac_addr.sa_data);
|
||||
|
||||
|
|
@ -135,9 +138,13 @@ void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable)
|
|||
hbg_reg_write(priv, HBG_REG_CF_INTRPT_MSK_ADDR, value);
|
||||
}
|
||||
|
||||
void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr)
|
||||
void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr, u32 index)
|
||||
{
|
||||
hbg_reg_write64(priv, HBG_REG_STATION_ADDR_LOW_2_ADDR, mac_addr);
|
||||
u32 addr;
|
||||
|
||||
/* mac addr is u64, so the addr offset is 0x8 */
|
||||
addr = HBG_REG_STATION_ADDR_LOW_2_ADDR + (index * 0x8);
|
||||
hbg_reg_write64(priv, addr, mac_addr);
|
||||
}
|
||||
|
||||
static void hbg_hw_set_pcu_max_frame_len(struct hbg_priv *priv,
|
||||
|
|
@ -161,8 +168,13 @@ static void hbg_hw_set_mac_max_frame_len(struct hbg_priv *priv,
|
|||
|
||||
void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu)
|
||||
{
|
||||
hbg_hw_set_pcu_max_frame_len(priv, mtu);
|
||||
hbg_hw_set_mac_max_frame_len(priv, mtu);
|
||||
u32 frame_len;
|
||||
|
||||
frame_len = mtu + VLAN_HLEN * priv->dev_specs.vlan_layers +
|
||||
ETH_HLEN + ETH_FCS_LEN;
|
||||
|
||||
hbg_hw_set_pcu_max_frame_len(priv, frame_len);
|
||||
hbg_hw_set_mac_max_frame_len(priv, frame_len);
|
||||
}
|
||||
|
||||
void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable)
|
||||
|
|
@ -207,6 +219,34 @@ void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex)
|
|||
HBG_REG_DUPLEX_B, duplex);
|
||||
}
|
||||
|
||||
/* only support uc filter */
|
||||
void hbg_hw_set_mac_filter_enable(struct hbg_priv *priv, u32 enable)
|
||||
{
|
||||
hbg_reg_write_field(priv, HBG_REG_REC_FILT_CTRL_ADDR,
|
||||
HBG_REG_REC_FILT_CTRL_UC_MATCH_EN_B, enable);
|
||||
}
|
||||
|
||||
void hbg_hw_set_pause_enable(struct hbg_priv *priv, u32 tx_en, u32 rx_en)
|
||||
{
|
||||
hbg_reg_write_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
|
||||
HBG_REG_PAUSE_ENABLE_TX_B, tx_en);
|
||||
hbg_reg_write_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
|
||||
HBG_REG_PAUSE_ENABLE_RX_B, rx_en);
|
||||
}
|
||||
|
||||
void hbg_hw_get_pause_enable(struct hbg_priv *priv, u32 *tx_en, u32 *rx_en)
|
||||
{
|
||||
*tx_en = hbg_reg_read_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
|
||||
HBG_REG_PAUSE_ENABLE_TX_B);
|
||||
*rx_en = hbg_reg_read_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
|
||||
HBG_REG_PAUSE_ENABLE_RX_B);
|
||||
}
|
||||
|
||||
void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr)
|
||||
{
|
||||
hbg_reg_write64(priv, HBG_REG_FD_FC_ADDR_LOW_ADDR, mac_addr);
|
||||
}
|
||||
|
||||
static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv)
|
||||
{
|
||||
u32 ctrl = 0;
|
||||
|
|
|
|||
|
|
@ -51,9 +51,13 @@ bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask);
|
|||
void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable);
|
||||
void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu);
|
||||
void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable);
|
||||
void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr);
|
||||
void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr, u32 index);
|
||||
u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir);
|
||||
void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc);
|
||||
void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr);
|
||||
void hbg_hw_set_mac_filter_enable(struct hbg_priv *priv, u32 enable);
|
||||
void hbg_hw_set_pause_enable(struct hbg_priv *priv, u32 tx_en, u32 rx_en);
|
||||
void hbg_hw_get_pause_enable(struct hbg_priv *priv, u32 *tx_en, u32 *rx_en);
|
||||
void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/pci.h>
|
||||
#include "hbg_common.h"
|
||||
#include "hbg_err.h"
|
||||
#include "hbg_ethtool.h"
|
||||
#include "hbg_hw.h"
|
||||
#include "hbg_irq.h"
|
||||
#include "hbg_mdio.h"
|
||||
#include "hbg_txrx.h"
|
||||
|
||||
static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu);
|
||||
#include "hbg_debugfs.h"
|
||||
|
||||
static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled)
|
||||
{
|
||||
|
|
@ -55,11 +55,7 @@ static int hbg_hw_txrx_clear(struct hbg_priv *priv)
|
|||
return ret;
|
||||
|
||||
/* After reset, regs need to be reconfigured */
|
||||
hbg_hw_init(priv);
|
||||
hbg_hw_set_uc_addr(priv, ether_addr_to_u64(priv->netdev->dev_addr));
|
||||
hbg_change_mtu(priv, priv->netdev->mtu);
|
||||
|
||||
return 0;
|
||||
return hbg_rebuild(priv);
|
||||
}
|
||||
|
||||
static int hbg_net_stop(struct net_device *netdev)
|
||||
|
|
@ -74,31 +70,127 @@ static int hbg_net_stop(struct net_device *netdev)
|
|||
return hbg_hw_txrx_clear(priv);
|
||||
}
|
||||
|
||||
static void hbg_update_promisc_mode(struct net_device *netdev, bool overflow)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
|
||||
/* Only when not table_overflow, and netdev->flags not set IFF_PROMISC,
|
||||
* The MAC filter will be enabled.
|
||||
* Otherwise the filter will be disabled.
|
||||
*/
|
||||
priv->filter.enabled = !(overflow || (netdev->flags & IFF_PROMISC));
|
||||
hbg_hw_set_mac_filter_enable(priv, priv->filter.enabled);
|
||||
}
|
||||
|
||||
static void hbg_set_mac_to_mac_table(struct hbg_priv *priv,
|
||||
u32 index, const u8 *addr)
|
||||
{
|
||||
if (addr) {
|
||||
ether_addr_copy(priv->filter.mac_table[index].addr, addr);
|
||||
hbg_hw_set_uc_addr(priv, ether_addr_to_u64(addr), index);
|
||||
} else {
|
||||
eth_zero_addr(priv->filter.mac_table[index].addr);
|
||||
hbg_hw_set_uc_addr(priv, 0, index);
|
||||
}
|
||||
}
|
||||
|
||||
static int hbg_get_index_from_mac_table(struct hbg_priv *priv,
|
||||
const u8 *addr, u32 *index)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < priv->filter.table_max_len; i++)
|
||||
if (ether_addr_equal(priv->filter.mac_table[i].addr, addr)) {
|
||||
*index = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int hbg_add_mac_to_filter(struct hbg_priv *priv, const u8 *addr)
|
||||
{
|
||||
u32 index;
|
||||
|
||||
/* already exists */
|
||||
if (!hbg_get_index_from_mac_table(priv, addr, &index))
|
||||
return 0;
|
||||
|
||||
for (index = 0; index < priv->filter.table_max_len; index++)
|
||||
if (is_zero_ether_addr(priv->filter.mac_table[index].addr)) {
|
||||
hbg_set_mac_to_mac_table(priv, index, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static void hbg_del_mac_from_filter(struct hbg_priv *priv, const u8 *addr)
|
||||
{
|
||||
u32 index;
|
||||
|
||||
/* not exists */
|
||||
if (hbg_get_index_from_mac_table(priv, addr, &index))
|
||||
return;
|
||||
|
||||
hbg_set_mac_to_mac_table(priv, index, NULL);
|
||||
}
|
||||
|
||||
static int hbg_uc_sync(struct net_device *netdev, const unsigned char *addr)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
|
||||
return hbg_add_mac_to_filter(priv, addr);
|
||||
}
|
||||
|
||||
static int hbg_uc_unsync(struct net_device *netdev, const unsigned char *addr)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (ether_addr_equal(netdev->dev_addr, (u8 *)addr))
|
||||
return 0;
|
||||
|
||||
hbg_del_mac_from_filter(priv, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hbg_net_set_rx_mode(struct net_device *netdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __dev_uc_sync(netdev, hbg_uc_sync, hbg_uc_unsync);
|
||||
|
||||
/* If ret != 0, overflow has occurred */
|
||||
hbg_update_promisc_mode(netdev, !!ret);
|
||||
}
|
||||
|
||||
static int hbg_net_set_mac_address(struct net_device *netdev, void *addr)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
u8 *mac_addr;
|
||||
bool exists;
|
||||
u32 index;
|
||||
|
||||
mac_addr = ((struct sockaddr *)addr)->sa_data;
|
||||
|
||||
if (!is_valid_ether_addr(mac_addr))
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
hbg_hw_set_uc_addr(priv, ether_addr_to_u64(mac_addr));
|
||||
/* The index of host mac is always 0.
|
||||
* If new mac address already exists,
|
||||
* delete the existing mac address and
|
||||
* add it to the position with index 0.
|
||||
*/
|
||||
exists = !hbg_get_index_from_mac_table(priv, mac_addr, &index);
|
||||
hbg_set_mac_to_mac_table(priv, 0, mac_addr);
|
||||
if (exists)
|
||||
hbg_set_mac_to_mac_table(priv, index, NULL);
|
||||
|
||||
hbg_hw_set_rx_pause_mac_addr(priv, ether_addr_to_u64(mac_addr));
|
||||
dev_addr_set(netdev, mac_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu)
|
||||
{
|
||||
u32 frame_len;
|
||||
|
||||
frame_len = new_mtu + VLAN_HLEN * priv->dev_specs.vlan_layers +
|
||||
ETH_HLEN + ETH_FCS_LEN;
|
||||
hbg_hw_set_mtu(priv, frame_len);
|
||||
}
|
||||
|
||||
static int hbg_net_change_mtu(struct net_device *netdev, int new_mtu)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
|
|
@ -106,7 +198,7 @@ static int hbg_net_change_mtu(struct net_device *netdev, int new_mtu)
|
|||
if (netif_running(netdev))
|
||||
return -EBUSY;
|
||||
|
||||
hbg_change_mtu(priv, new_mtu);
|
||||
hbg_hw_set_mtu(priv, new_mtu);
|
||||
WRITE_ONCE(netdev->mtu, new_mtu);
|
||||
|
||||
dev_dbg(&priv->pdev->dev,
|
||||
|
|
@ -142,8 +234,39 @@ static const struct net_device_ops hbg_netdev_ops = {
|
|||
.ndo_set_mac_address = hbg_net_set_mac_address,
|
||||
.ndo_change_mtu = hbg_net_change_mtu,
|
||||
.ndo_tx_timeout = hbg_net_tx_timeout,
|
||||
.ndo_set_rx_mode = hbg_net_set_rx_mode,
|
||||
};
|
||||
|
||||
static int hbg_mac_filter_init(struct hbg_priv *priv)
|
||||
{
|
||||
struct hbg_dev_specs *dev_specs = &priv->dev_specs;
|
||||
struct hbg_mac_filter *filter = &priv->filter;
|
||||
struct hbg_mac_table_entry *tmp_table;
|
||||
|
||||
tmp_table = devm_kcalloc(&priv->pdev->dev, dev_specs->uc_mac_num,
|
||||
sizeof(*tmp_table), GFP_KERNEL);
|
||||
if (!tmp_table)
|
||||
return -ENOMEM;
|
||||
|
||||
filter->mac_table = tmp_table;
|
||||
filter->table_max_len = dev_specs->uc_mac_num;
|
||||
filter->enabled = true;
|
||||
|
||||
hbg_hw_set_mac_filter_enable(priv, filter->enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hbg_init_user_def(struct hbg_priv *priv)
|
||||
{
|
||||
struct ethtool_pauseparam *pause_param = &priv->user_def.pause_param;
|
||||
|
||||
priv->mac.pause_autoneg = HBG_STATUS_ENABLE;
|
||||
|
||||
pause_param->autoneg = priv->mac.pause_autoneg;
|
||||
hbg_hw_get_pause_enable(priv, &pause_param->tx_pause,
|
||||
&pause_param->rx_pause);
|
||||
}
|
||||
|
||||
static int hbg_init(struct hbg_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -160,7 +283,17 @@ static int hbg_init(struct hbg_priv *priv)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return hbg_mdio_init(priv);
|
||||
ret = hbg_mdio_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hbg_mac_filter_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hbg_debugfs_init(priv);
|
||||
hbg_init_user_def(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hbg_pci_init(struct pci_dev *pdev)
|
||||
|
|
@ -216,13 +349,15 @@ static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
netdev->priv_flags |= IFF_UNICAST_FLT;
|
||||
|
||||
netdev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
|
||||
netdev->max_mtu = priv->dev_specs.max_mtu;
|
||||
netdev->min_mtu = priv->dev_specs.min_mtu;
|
||||
netdev->netdev_ops = &hbg_netdev_ops;
|
||||
netdev->watchdog_timeo = 5 * HZ;
|
||||
|
||||
hbg_change_mtu(priv, ETH_DATA_LEN);
|
||||
hbg_hw_set_mtu(priv, ETH_DATA_LEN);
|
||||
hbg_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr);
|
||||
hbg_ethtool_set_ops(netdev);
|
||||
|
||||
|
|
@ -245,7 +380,27 @@ 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();
|
||||
hbg_set_pci_err_handler(&hbg_driver);
|
||||
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.");
|
||||
|
|
|
|||
|
|
@ -114,6 +114,19 @@ static void hbg_mdio_init_hw(struct hbg_priv *priv)
|
|||
hbg_mdio_set_command(mac, cmd);
|
||||
}
|
||||
|
||||
static void hbg_flowctrl_cfg(struct hbg_priv *priv)
|
||||
{
|
||||
struct phy_device *phydev = priv->mac.phydev;
|
||||
bool rx_pause;
|
||||
bool tx_pause;
|
||||
|
||||
if (!priv->mac.pause_autoneg)
|
||||
return;
|
||||
|
||||
phy_get_pause(phydev, &tx_pause, &rx_pause);
|
||||
hbg_hw_set_pause_enable(priv, tx_pause, rx_pause);
|
||||
}
|
||||
|
||||
static void hbg_phy_adjust_link(struct net_device *netdev)
|
||||
{
|
||||
struct hbg_priv *priv = netdev_priv(netdev);
|
||||
|
|
@ -140,6 +153,7 @@ static void hbg_phy_adjust_link(struct net_device *netdev)
|
|||
priv->mac.duplex = phydev->duplex;
|
||||
priv->mac.autoneg = phydev->autoneg;
|
||||
hbg_hw_adjust_link(priv, speed, phydev->duplex);
|
||||
hbg_flowctrl_cfg(priv);
|
||||
}
|
||||
|
||||
priv->mac.link_status = phydev->link;
|
||||
|
|
@ -168,6 +182,7 @@ static int hbg_phy_connect(struct hbg_priv *priv)
|
|||
return ret;
|
||||
|
||||
phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
|
||||
phy_support_asym_pause(phydev);
|
||||
phy_attached_info(phydev);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#define HBG_REG_MAC_ID_ADDR 0x0008
|
||||
#define HBG_REG_PHY_ID_ADDR 0x000C
|
||||
#define HBG_REG_MAC_ADDR_ADDR 0x0010
|
||||
#define HBG_REG_MAC_ADDR_HIGH_ADDR 0x0014
|
||||
#define HBG_REG_UC_MAC_NUM_ADDR 0x0018
|
||||
#define HBG_REG_MDIO_FREQ_ADDR 0x0024
|
||||
#define HBG_REG_MAX_MTU_ADDR 0x0028
|
||||
#define HBG_REG_MIN_MTU_ADDR 0x002C
|
||||
|
|
@ -28,6 +30,7 @@
|
|||
#define HBG_REG_MDIO_COMMAND_OP_M GENMASK(11, 10)
|
||||
#define HBG_REG_MDIO_COMMAND_PRTAD_M GENMASK(9, 5)
|
||||
#define HBG_REG_MDIO_COMMAND_DEVAD_M GENMASK(4, 0)
|
||||
#define HBG_REG_MDIO_ADDR_ADDR (HBG_REG_MDIO_BASE + 0x0004)
|
||||
#define HBG_REG_MDIO_WDATA_ADDR (HBG_REG_MDIO_BASE + 0x0008)
|
||||
#define HBG_REG_MDIO_WDATA_M GENMASK(15, 0)
|
||||
#define HBG_REG_MDIO_RDATA_ADDR (HBG_REG_MDIO_BASE + 0x000C)
|
||||
|
|
@ -36,6 +39,10 @@
|
|||
/* GMAC */
|
||||
#define HBG_REG_SGMII_BASE 0x10000
|
||||
#define HBG_REG_DUPLEX_TYPE_ADDR (HBG_REG_SGMII_BASE + 0x0008)
|
||||
#define HBG_REG_FD_FC_TYPE_ADDR (HBG_REG_SGMII_BASE + 0x000C)
|
||||
#define HBG_REG_FC_TX_TIMER_ADDR (HBG_REG_SGMII_BASE + 0x001C)
|
||||
#define HBG_REG_FD_FC_ADDR_LOW_ADDR (HBG_REG_SGMII_BASE + 0x0020)
|
||||
#define HBG_REG_FD_FC_ADDR_HIGH_ADDR (HBG_REG_SGMII_BASE + 0x0024)
|
||||
#define HBG_REG_DUPLEX_B BIT(0)
|
||||
#define HBG_REG_MAX_FRAME_SIZE_ADDR (HBG_REG_SGMII_BASE + 0x003C)
|
||||
#define HBG_REG_PORT_MODE_ADDR (HBG_REG_SGMII_BASE + 0x0040)
|
||||
|
|
@ -43,20 +50,42 @@
|
|||
#define HBG_REG_PORT_ENABLE_ADDR (HBG_REG_SGMII_BASE + 0x0044)
|
||||
#define HBG_REG_PORT_ENABLE_RX_B BIT(1)
|
||||
#define HBG_REG_PORT_ENABLE_TX_B BIT(2)
|
||||
#define HBG_REG_PAUSE_ENABLE_ADDR (HBG_REG_SGMII_BASE + 0x0048)
|
||||
#define HBG_REG_PAUSE_ENABLE_RX_B BIT(0)
|
||||
#define HBG_REG_PAUSE_ENABLE_TX_B BIT(1)
|
||||
#define HBG_REG_AN_NEG_STATE_ADDR (HBG_REG_SGMII_BASE + 0x0058)
|
||||
#define HBG_REG_TRANSMIT_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x0060)
|
||||
#define HBG_REG_TRANSMIT_CTRL_PAD_EN_B BIT(7)
|
||||
#define HBG_REG_TRANSMIT_CTRL_CRC_ADD_B BIT(6)
|
||||
#define HBG_REG_TRANSMIT_CTRL_AN_EN_B BIT(5)
|
||||
#define HBG_REG_REC_FILT_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x0064)
|
||||
#define HBG_REG_REC_FILT_CTRL_UC_MATCH_EN_B BIT(0)
|
||||
#define HBG_REG_LINE_LOOP_BACK_ADDR (HBG_REG_SGMII_BASE + 0x01A8)
|
||||
#define HBG_REG_CF_CRC_STRIP_ADDR (HBG_REG_SGMII_BASE + 0x01B0)
|
||||
#define HBG_REG_CF_CRC_STRIP_B BIT(0)
|
||||
#define HBG_REG_MODE_CHANGE_EN_ADDR (HBG_REG_SGMII_BASE + 0x01B4)
|
||||
#define HBG_REG_MODE_CHANGE_EN_B BIT(0)
|
||||
#define HBG_REG_LOOP_REG_ADDR (HBG_REG_SGMII_BASE + 0x01DC)
|
||||
#define HBG_REG_RECV_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x01E0)
|
||||
#define HBG_REG_RECV_CTRL_STRIP_PAD_EN_B BIT(3)
|
||||
#define HBG_REG_VLAN_CODE_ADDR (HBG_REG_SGMII_BASE + 0x01E8)
|
||||
#define HBG_REG_STATION_ADDR_LOW_0_ADDR (HBG_REG_SGMII_BASE + 0x0200)
|
||||
#define HBG_REG_STATION_ADDR_HIGH_0_ADDR (HBG_REG_SGMII_BASE + 0x0204)
|
||||
#define HBG_REG_STATION_ADDR_LOW_1_ADDR (HBG_REG_SGMII_BASE + 0x0208)
|
||||
#define HBG_REG_STATION_ADDR_HIGH_1_ADDR (HBG_REG_SGMII_BASE + 0x020C)
|
||||
#define HBG_REG_STATION_ADDR_LOW_2_ADDR (HBG_REG_SGMII_BASE + 0x0210)
|
||||
#define HBG_REG_STATION_ADDR_HIGH_2_ADDR (HBG_REG_SGMII_BASE + 0x0214)
|
||||
#define HBG_REG_STATION_ADDR_LOW_3_ADDR (HBG_REG_SGMII_BASE + 0x0218)
|
||||
#define HBG_REG_STATION_ADDR_HIGH_3_ADDR (HBG_REG_SGMII_BASE + 0x021C)
|
||||
#define HBG_REG_STATION_ADDR_LOW_4_ADDR (HBG_REG_SGMII_BASE + 0x0220)
|
||||
#define HBG_REG_STATION_ADDR_HIGH_4_ADDR (HBG_REG_SGMII_BASE + 0x0224)
|
||||
#define HBG_REG_STATION_ADDR_LOW_5_ADDR (HBG_REG_SGMII_BASE + 0x0228)
|
||||
#define HBG_REG_STATION_ADDR_HIGH_5_ADDR (HBG_REG_SGMII_BASE + 0x022C)
|
||||
|
||||
/* PCU */
|
||||
#define HBG_REG_TX_FIFO_THRSLD_ADDR (HBG_REG_SGMII_BASE + 0x0420)
|
||||
#define HBG_REG_RX_FIFO_THRSLD_ADDR (HBG_REG_SGMII_BASE + 0x0424)
|
||||
#define HBG_REG_CFG_FIFO_THRSLD_ADDR (HBG_REG_SGMII_BASE + 0x0428)
|
||||
#define HBG_REG_CF_INTRPT_MSK_ADDR (HBG_REG_SGMII_BASE + 0x042C)
|
||||
#define HBG_INT_MSK_WE_ERR_B BIT(31)
|
||||
#define HBG_INT_MSK_RBREQ_ERR_B BIT(30)
|
||||
|
|
@ -78,11 +107,17 @@
|
|||
#define HBG_INT_MSK_RX_B BIT(0) /* just used in driver */
|
||||
#define HBG_REG_CF_INTRPT_STAT_ADDR (HBG_REG_SGMII_BASE + 0x0434)
|
||||
#define HBG_REG_CF_INTRPT_CLR_ADDR (HBG_REG_SGMII_BASE + 0x0438)
|
||||
#define HBG_REG_TX_BUS_ERR_ADDR_ADDR (HBG_REG_SGMII_BASE + 0x043C)
|
||||
#define HBG_REG_RX_BUS_ERR_ADDR_ADDR (HBG_REG_SGMII_BASE + 0x0440)
|
||||
#define HBG_REG_MAX_FRAME_LEN_ADDR (HBG_REG_SGMII_BASE + 0x0444)
|
||||
#define HBG_REG_MAX_FRAME_LEN_M GENMASK(15, 0)
|
||||
#define HBG_REG_DEBUG_ST_MCH_ADDR (HBG_REG_SGMII_BASE + 0x0450)
|
||||
#define HBG_REG_FIFO_CURR_STATUS_ADDR (HBG_REG_SGMII_BASE + 0x0454)
|
||||
#define HBG_REG_FIFO_HIST_STATUS_ADDR (HBG_REG_SGMII_BASE + 0x0458)
|
||||
#define HBG_REG_CF_CFF_DATA_NUM_ADDR (HBG_REG_SGMII_BASE + 0x045C)
|
||||
#define HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M GENMASK(8, 0)
|
||||
#define HBG_REG_CF_CFF_DATA_NUM_ADDR_RX_M GENMASK(24, 16)
|
||||
#define HBG_REG_CF_TX_PAUSE_ADDR (HBG_REG_SGMII_BASE + 0x0470)
|
||||
#define HBG_REG_TX_CFF_ADDR_0_ADDR (HBG_REG_SGMII_BASE + 0x0488)
|
||||
#define HBG_REG_TX_CFF_ADDR_1_ADDR (HBG_REG_SGMII_BASE + 0x048C)
|
||||
#define HBG_REG_TX_CFF_ADDR_2_ADDR (HBG_REG_SGMII_BASE + 0x0490)
|
||||
|
|
@ -101,6 +136,10 @@
|
|||
#define HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE2_M GENMASK(3, 0)
|
||||
#define HBG_REG_RX_PKT_MODE_ADDR (HBG_REG_SGMII_BASE + 0x04F4)
|
||||
#define HBG_REG_RX_PKT_MODE_PARSE_MODE_M GENMASK(22, 21)
|
||||
#define HBG_REG_DBG_ST0_ADDR (HBG_REG_SGMII_BASE + 0x05E4)
|
||||
#define HBG_REG_DBG_ST1_ADDR (HBG_REG_SGMII_BASE + 0x05E8)
|
||||
#define HBG_REG_DBG_ST2_ADDR (HBG_REG_SGMII_BASE + 0x05EC)
|
||||
#define HBG_REG_BUS_RST_EN_ADDR (HBG_REG_SGMII_BASE + 0x0688)
|
||||
#define HBG_REG_CF_IND_TXINT_MSK_ADDR (HBG_REG_SGMII_BASE + 0x0694)
|
||||
#define HBG_REG_IND_INTR_MASK_B BIT(0)
|
||||
#define HBG_REG_CF_IND_TXINT_STAT_ADDR (HBG_REG_SGMII_BASE + 0x0698)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user