diff mbox series

[RFC,net-next,05/10] net: hibmcge: Implement some .ndo functions

Message ID 20240731094245.1967834-6-shaojijie@huawei.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series Add support of HIBMCGE Ethernet 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: 7 this patch: 7
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 7 this patch: 7
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: 7 this patch: 7
netdev/checkpatch warning WARNING: line length of 83 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns
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 July 31, 2024, 9:42 a.m. UTC
Implement the .ndo_open .ndo_stop .ndo_set_mac_address
and .ndo_change_mtu functions.
And .ndo_validate_addr calls the eth_validate_addr function directly

Signed-off-by: Jijie Shao <shaojijie@huawei.com>
---
 .../ethernet/hisilicon/hibmcge/hbg_common.h   |   4 +
 .../net/ethernet/hisilicon/hibmcge/hbg_hw.c   |  40 +++++++
 .../net/ethernet/hisilicon/hibmcge/hbg_hw.h   |   3 +
 .../net/ethernet/hisilicon/hibmcge/hbg_main.c | 105 ++++++++++++++++++
 .../net/ethernet/hisilicon/hibmcge/hbg_reg.h  |   8 ++
 5 files changed, 160 insertions(+)

Comments

Andrew Lunn Aug. 1, 2024, 12:51 a.m. UTC | #1
> +static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
> +{
> +	struct hbg_priv *priv = netdev_priv(dev);
> +	u8 *mac_addr;
> +
> +	mac_addr = ((struct sockaddr *)addr)->sa_data;
> +	if (ether_addr_equal(dev->dev_addr, mac_addr))
> +		return 0;
> +
> +	if (!is_valid_ether_addr(mac_addr))
> +		return -EADDRNOTAVAIL;

How does the core pass you an invalid MAC address?

> +static int hbg_net_change_mtu(struct net_device *dev, int new_mtu)
> +{
> +	struct hbg_priv *priv = netdev_priv(dev);
> +	bool is_opened = hbg_nic_is_open(priv);
> +	u32 frame_len;
> +
> +	if (new_mtu == dev->mtu)
> +		return 0;
> +
> +	if (new_mtu < priv->dev_specs.min_mtu || new_mtu > priv->dev_specs.max_mtu)
> +		return -EINVAL;

You just need to set dev->min_mtu and dev->max_mtu, and the core will
do this validation for you.

> +	dev_info(&priv->pdev->dev,
> +		 "change mtu from %u to %u\n", dev->mtu, new_mtu);

dev_dbg() Don't spam the log for normal operations.

	Andrew
Jijie Shao Aug. 1, 2024, 9:13 a.m. UTC | #2
on 2024/8/1 8:51, Andrew Lunn wrote:
>> +static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
>> +{
>> +	struct hbg_priv *priv = netdev_priv(dev);
>> +	u8 *mac_addr;
>> +
>> +	mac_addr = ((struct sockaddr *)addr)->sa_data;
>> +	if (ether_addr_equal(dev->dev_addr, mac_addr))
>> +		return 0;
>> +
>> +	if (!is_valid_ether_addr(mac_addr))
>> +		return -EADDRNOTAVAIL;
> How does the core pass you an invalid MAC address?

According to my test,
in the 6.4 rc4 kernel version, invalid mac address is allowed to be configured.
An error is reported only when ifconfig ethx up.

>
>> +static int hbg_net_change_mtu(struct net_device *dev, int new_mtu)
>> +{
>> +	struct hbg_priv *priv = netdev_priv(dev);
>> +	bool is_opened = hbg_nic_is_open(priv);
>> +	u32 frame_len;
>> +
>> +	if (new_mtu == dev->mtu)
>> +		return 0;
>> +
>> +	if (new_mtu < priv->dev_specs.min_mtu || new_mtu > priv->dev_specs.max_mtu)
>> +		return -EINVAL;
> You just need to set dev->min_mtu and dev->max_mtu, and the core will
> do this validation for you.

Thanks, I'll test it,and if it works I'll remove the judgement

>
>> +	dev_info(&priv->pdev->dev,
>> +		 "change mtu from %u to %u\n", dev->mtu, new_mtu);
> dev_dbg() Don't spam the log for normal operations.

okay, Thanks!
Andrew Lunn Aug. 1, 2024, 12:18 p.m. UTC | #3
On Thu, Aug 01, 2024 at 05:13:33PM +0800, Jijie Shao wrote:
> 
> on 2024/8/1 8:51, Andrew Lunn wrote:
> > > +static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
> > > +{
> > > +	struct hbg_priv *priv = netdev_priv(dev);
> > > +	u8 *mac_addr;
> > > +
> > > +	mac_addr = ((struct sockaddr *)addr)->sa_data;
> > > +	if (ether_addr_equal(dev->dev_addr, mac_addr))
> > > +		return 0;
> > > +
> > > +	if (!is_valid_ether_addr(mac_addr))
> > > +		return -EADDRNOTAVAIL;
> > How does the core pass you an invalid MAC address?
> 
> According to my test,
> in the 6.4 rc4 kernel version, invalid mac address is allowed to be configured.
> An error is reported only when ifconfig ethx up.

Ah, interesting.

I see a test in __dev_open(), which is what you are saying here. But i
would also expect a test in rtnetlink, or maybe dev_set_mac_address().
We don't want every driver having to repeat this test in their
.ndo_set_mac_address, when it could be done once in the core.

	Andrew
Jijie Shao Aug. 1, 2024, 12:33 p.m. UTC | #4
on 2024/8/1 20:18, Andrew Lunn wrote:
> On Thu, Aug 01, 2024 at 05:13:33PM +0800, Jijie Shao wrote:
>> on 2024/8/1 8:51, Andrew Lunn wrote:
>>>> +static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
>>>> +{
>>>> +	struct hbg_priv *priv = netdev_priv(dev);
>>>> +	u8 *mac_addr;
>>>> +
>>>> +	mac_addr = ((struct sockaddr *)addr)->sa_data;
>>>> +	if (ether_addr_equal(dev->dev_addr, mac_addr))
>>>> +		return 0;
>>>> +
>>>> +	if (!is_valid_ether_addr(mac_addr))
>>>> +		return -EADDRNOTAVAIL;
>>> How does the core pass you an invalid MAC address?
>> According to my test,
>> in the 6.4 rc4 kernel version, invalid mac address is allowed to be configured.
>> An error is reported only when ifconfig ethx up.
> Ah, interesting.
>
> I see a test in __dev_open(), which is what you are saying here. But i
> would also expect a test in rtnetlink, or maybe dev_set_mac_address().
> We don't want every driver having to repeat this test in their
> .ndo_set_mac_address, when it could be done once in the core.
>
> 	Andrew

Hi:
I did the following test on my device:

insmod hibmcge.ko
hibmcge: no symbol version for module_layout
hibmcge: loading out-of-tree module taints kernel.
hibmcge: module verification failed: signature and/or required key missing - tainting kernel
hibmcge 0000:83:00.1: enabling device (0140 -> 0142)
Generic PHY mii-0000:83:00.1:02: attached PHY driver (mii_bus:phy_addr=mii-0000:83:00.1:02, irq=POLL)
hibmcge 0000:83:00.1 enp131s0f1: renamed from eth0
IPv6: ADDRCONF(NETDEV_CHANGE): enp131s0f1: link becomes ready
hibmcge 0000:83:00.1: link up!

ifconfig enp131s0f1 hw ether FF:FF:FF:FF:FF:FF

ip a
6: enp131s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
     link/ether ff:ff:ff:ff:ff:ff brd ff:ff:ff:ff:ff:ff permaddr 08:02:00:00:08:08
     
ifconfig enp131s0f1 up
ifconfig enp131s0f1 down up
SIOCSIFFLAGS: Cannot assign requested address
hibmcge 0000:83:00.1: link down!

uname -a
Linux localhost.localdomain 6.4.0+ #1 SMP Fri Mar 15 14:44:20 CST 2024 aarch64 aarch64 aarch64 GNU/Linux



So I'm not sure what's wrong. I also implemented ndo_validate_addr by eth_validate_addr.

Thanks

Jijie Shao
Andrew Lunn Aug. 1, 2024, 12:36 p.m. UTC | #5
On Thu, Aug 01, 2024 at 08:33:38PM +0800, Jijie Shao wrote:
> 
> on 2024/8/1 20:18, Andrew Lunn wrote:
> > On Thu, Aug 01, 2024 at 05:13:33PM +0800, Jijie Shao wrote:
> > > on 2024/8/1 8:51, Andrew Lunn wrote:
> > > > > +static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
> > > > > +{
> > > > > +	struct hbg_priv *priv = netdev_priv(dev);
> > > > > +	u8 *mac_addr;
> > > > > +
> > > > > +	mac_addr = ((struct sockaddr *)addr)->sa_data;
> > > > > +	if (ether_addr_equal(dev->dev_addr, mac_addr))
> > > > > +		return 0;
> > > > > +
> > > > > +	if (!is_valid_ether_addr(mac_addr))
> > > > > +		return -EADDRNOTAVAIL;
> > > > How does the core pass you an invalid MAC address?
> > > According to my test,
> > > in the 6.4 rc4 kernel version, invalid mac address is allowed to be configured.
> > > An error is reported only when ifconfig ethx up.
> > Ah, interesting.
> > 
> > I see a test in __dev_open(), which is what you are saying here. But i
> > would also expect a test in rtnetlink, or maybe dev_set_mac_address().
> > We don't want every driver having to repeat this test in their
> > .ndo_set_mac_address, when it could be done once in the core.
> > 
> > 	Andrew
> 
> Hi:
> I did the following test on my device:
> 
> insmod hibmcge.ko
> hibmcge: no symbol version for module_layout
> hibmcge: loading out-of-tree module taints kernel.
> hibmcge: module verification failed: signature and/or required key missing - tainting kernel
> hibmcge 0000:83:00.1: enabling device (0140 -> 0142)
> Generic PHY mii-0000:83:00.1:02: attached PHY driver (mii_bus:phy_addr=mii-0000:83:00.1:02, irq=POLL)
> hibmcge 0000:83:00.1 enp131s0f1: renamed from eth0
> IPv6: ADDRCONF(NETDEV_CHANGE): enp131s0f1: link becomes ready
> hibmcge 0000:83:00.1: link up!
> 
> ifconfig enp131s0f1 hw ether FF:FF:FF:FF:FF:FF
> 
> ip a
> 6: enp131s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
>     link/ether ff:ff:ff:ff:ff:ff brd ff:ff:ff:ff:ff:ff permaddr 08:02:00:00:08:08
> ifconfig enp131s0f1 up
> ifconfig enp131s0f1 down up
> SIOCSIFFLAGS: Cannot assign requested address
> hibmcge 0000:83:00.1: link down!
> 
> uname -a
> Linux localhost.localdomain 6.4.0+ #1 SMP Fri Mar 15 14:44:20 CST 2024 aarch64 aarch64 aarch64 GNU/Linux
> 
> 
> 
> So I'm not sure what's wrong. I also implemented ndo_validate_addr by eth_validate_addr.

I agree. I don't see a test. Please could you include a patch to
dev_set_mac_address() to validate the address there before calling
into the driver. It might also be worth a search to see if anybody
else has tried this before, and failed. There might be a good reason
you cannot validate it.

	Andrew
Jijie Shao Aug. 1, 2024, 1:08 p.m. UTC | #6
on 2024/8/1 20:36, Andrew Lunn wrote:
> On Thu, Aug 01, 2024 at 08:33:38PM +0800, Jijie Shao wrote:
>> on 2024/8/1 20:18, Andrew Lunn wrote:
>>> On Thu, Aug 01, 2024 at 05:13:33PM +0800, Jijie Shao wrote:
>>>> on 2024/8/1 8:51, Andrew Lunn wrote:
>>>>>> +static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
>>>>>> +{
>>>>>> +	struct hbg_priv *priv = netdev_priv(dev);
>>>>>> +	u8 *mac_addr;
>>>>>> +
>>>>>> +	mac_addr = ((struct sockaddr *)addr)->sa_data;
>>>>>> +	if (ether_addr_equal(dev->dev_addr, mac_addr))
>>>>>> +		return 0;
>>>>>> +
>>>>>> +	if (!is_valid_ether_addr(mac_addr))
>>>>>> +		return -EADDRNOTAVAIL;
>>>>> How does the core pass you an invalid MAC address?
>>>> According to my test,
>>>> in the 6.4 rc4 kernel version, invalid mac address is allowed to be configured.
>>>> An error is reported only when ifconfig ethx up.
>>> Ah, interesting.
>>>
>>> I see a test in __dev_open(), which is what you are saying here. But i
>>> would also expect a test in rtnetlink, or maybe dev_set_mac_address().
>>> We don't want every driver having to repeat this test in their
>>> .ndo_set_mac_address, when it could be done once in the core.
>>>
>>> 	Andrew
>> Hi:
>> I did the following test on my device:
>>
>> insmod hibmcge.ko
>> hibmcge: no symbol version for module_layout
>> hibmcge: loading out-of-tree module taints kernel.
>> hibmcge: module verification failed: signature and/or required key missing - tainting kernel
>> hibmcge 0000:83:00.1: enabling device (0140 -> 0142)
>> Generic PHY mii-0000:83:00.1:02: attached PHY driver (mii_bus:phy_addr=mii-0000:83:00.1:02, irq=POLL)
>> hibmcge 0000:83:00.1 enp131s0f1: renamed from eth0
>> IPv6: ADDRCONF(NETDEV_CHANGE): enp131s0f1: link becomes ready
>> hibmcge 0000:83:00.1: link up!
>>
>> ifconfig enp131s0f1 hw ether FF:FF:FF:FF:FF:FF
>>
>> ip a
>> 6: enp131s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
>>      link/ether ff:ff:ff:ff:ff:ff brd ff:ff:ff:ff:ff:ff permaddr 08:02:00:00:08:08
>> ifconfig enp131s0f1 up
>> ifconfig enp131s0f1 down up
>> SIOCSIFFLAGS: Cannot assign requested address
>> hibmcge 0000:83:00.1: link down!
>>
>> uname -a
>> Linux localhost.localdomain 6.4.0+ #1 SMP Fri Mar 15 14:44:20 CST 2024 aarch64 aarch64 aarch64 GNU/Linux
>>
>>
>>
>> So I'm not sure what's wrong. I also implemented ndo_validate_addr by eth_validate_addr.
> I agree. I don't see a test. Please could you include a patch to
> dev_set_mac_address() to validate the address there before calling
> into the driver. It might also be worth a search to see if anybody
> else has tried this before, and failed. There might be a good reason
> you cannot validate it.
>
> 	Andrew

sure, I will include that in V2

Thanks,

Jijie Shao
diff mbox series

Patch

diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
index 6a3e647cd27c..22d5ce310a3f 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
@@ -30,8 +30,12 @@  enum hbg_dir {
 enum hbg_nic_state {
 	HBG_NIC_STATE_INITED = 0,
 	HBG_NIC_STATE_EVENT_HANDLING,
+	HBG_NIC_STATE_OPEN,
 };
 
+#define hbg_nic_is_open(priv) test_bit(HBG_NIC_STATE_OPEN, &(priv)->state)
+#define hbg_nic_is_inited(priv) test_bit(HBG_NIC_STATE_INITED, &(priv)->state)
+
 enum hbg_hw_event_type {
 	HBG_HW_EVENT_NONE = 0,
 	HBG_HW_EVENT_INIT, /* driver is loading */
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
index d9bed7cc7790..f06c74d59c02 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
@@ -71,6 +71,46 @@  int hbg_hw_dev_specs_init(struct hbg_priv *priv)
 	return 0;
 }
 
+void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr)
+{
+	hbg_reg_write64(priv, HBG_REG_STATION_ADDR_LOW_2_ADDR, mac_addr);
+}
+
+static void hbg_hw_set_pcu_max_frame_len(struct hbg_priv *priv,
+					 u16 max_frame_len)
+{
+#define HBG_PCU_FRAME_LEN_PLUS 4
+
+	max_frame_len = max_t(u32, max_frame_len, HBG_DEFAULT_MTU_SIZE);
+
+	/* lower two bits of value must be set to 0. Otherwise, the value is ignored */
+	max_frame_len = round_up(max_frame_len, HBG_PCU_FRAME_LEN_PLUS);
+
+	hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_LEN_ADDR,
+			    HBG_REG_MAX_FRAME_LEN_M, max_frame_len);
+}
+
+static void hbg_hw_set_mac_max_frame_len(struct hbg_priv *priv,
+					 u16 max_frame_size)
+{
+	hbg_reg_write_field(priv, HBG_REG_MAX_FRAME_SIZE_ADDR,
+			    HBG_REG_MAX_FRAME_LEN_M, max_frame_size);
+}
+
+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);
+}
+
+void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable)
+{
+	hbg_reg_write_bit(priv, HBG_REG_PORT_ENABLE_ADDR,
+			  HBG_REG_PORT_ENABLE_TX_B, enable);
+	hbg_reg_write_bit(priv, HBG_REG_PORT_ENABLE_ADDR,
+			  HBG_REG_PORT_ENABLE_RX_B, enable);
+}
+
 void hbg_hw_get_err_intr_status(struct hbg_priv *priv, struct hbg_intr_status *status)
 {
 	status->bits = hbg_reg_read(priv, HBG_REG_CF_INTRPT_STAT_ADDR);
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
index e2a08dc5d883..556f479bc094 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
@@ -57,6 +57,8 @@  static inline void hbg_reg_write64(struct hbg_priv *priv, u32 reg_addr,
 
 int hbg_hw_event_notify(struct hbg_priv *priv, enum hbg_hw_event_type event_type);
 int hbg_hw_dev_specs_init(struct hbg_priv *priv);
+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_get_err_intr_status(struct hbg_priv *priv, struct hbg_intr_status *status);
 void hbg_hw_get_err_intr_mask(struct hbg_priv *priv, struct hbg_intr_mask *msk);
 void hbg_hw_set_err_intr_mask(struct hbg_priv *priv, const struct hbg_intr_mask *msk);
@@ -67,6 +69,7 @@  void hbg_hw_set_txrx_intr_clear(struct hbg_priv *priv, enum hbg_dir dir);
 void hbg_hw_get_txrx_intr_status(struct hbg_priv *priv, struct hbg_intr_status *status);
 int hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex);
 int hbg_hw_sgmii_autoneg(struct hbg_priv *priv);
+void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu);
 int hbg_hw_init(struct hbg_priv *pri);
 
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
index 059ea155572f..0184ea5d563e 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
@@ -2,6 +2,7 @@ 
 // Copyright (c) 2024 Hisilicon Limited.
 
 #include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include "hbg_common.h"
@@ -10,6 +11,105 @@ 
 #include "hbg_main.h"
 #include "hbg_mdio.h"
 
+static void hbg_enable_intr(struct hbg_priv *priv, bool enabled)
+{
+	u32 i;
+
+	for (i = 0; i < priv->vectors.info_array_len; i++)
+		hbg_irq_enable(priv, priv->vectors.info_array[i].mask,
+			       enabled);
+
+	for (i = 0; i < priv->vectors.irq_count; i++) {
+		if (enabled)
+			enable_irq(priv->vectors.irqs[i].id);
+		else
+			disable_irq(priv->vectors.irqs[i].id);
+	}
+}
+
+static int hbg_net_open(struct net_device *dev)
+{
+	struct hbg_priv *priv = netdev_priv(dev);
+
+	if (test_and_set_bit(HBG_NIC_STATE_OPEN, &priv->state))
+		return 0;
+
+	netif_carrier_off(dev);
+	hbg_enable_intr(priv, true);
+	hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
+	netif_start_queue(dev);
+	hbg_phy_start(priv);
+	return 0;
+}
+
+static int hbg_net_stop(struct net_device *dev)
+{
+	struct hbg_priv *priv = netdev_priv(dev);
+
+	if (!hbg_nic_is_open(priv))
+		return 0;
+
+	clear_bit(HBG_NIC_STATE_OPEN, &priv->state);
+	netif_carrier_off(dev);
+	netif_stop_queue(dev);
+	hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
+	hbg_enable_intr(priv, false);
+	hbg_phy_stop(priv);
+	return 0;
+}
+
+static int hbg_net_set_mac_address(struct net_device *dev, void *addr)
+{
+	struct hbg_priv *priv = netdev_priv(dev);
+	u8 *mac_addr;
+
+	mac_addr = ((struct sockaddr *)addr)->sa_data;
+	if (ether_addr_equal(dev->dev_addr, mac_addr))
+		return 0;
+
+	if (!is_valid_ether_addr(mac_addr))
+		return -EADDRNOTAVAIL;
+
+	hbg_hw_set_uc_addr(priv, ether_addr_to_u64(mac_addr));
+	dev_addr_set(dev, mac_addr);
+	return 0;
+}
+
+static int hbg_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct hbg_priv *priv = netdev_priv(dev);
+	bool is_opened = hbg_nic_is_open(priv);
+	u32 frame_len;
+
+	if (new_mtu == dev->mtu)
+		return 0;
+
+	if (new_mtu < priv->dev_specs.min_mtu || new_mtu > priv->dev_specs.max_mtu)
+		return -EINVAL;
+
+	hbg_net_stop(dev);
+
+	frame_len = new_mtu + VLAN_HLEN * priv->dev_specs.vlan_layers +
+		    ETH_HLEN + ETH_FCS_LEN;
+	hbg_hw_set_mtu(priv, frame_len);
+
+	dev_info(&priv->pdev->dev,
+		 "change mtu from %u to %u\n", dev->mtu, new_mtu);
+	WRITE_ONCE(dev->mtu, new_mtu);
+
+	if (is_opened)
+		hbg_net_open(dev);
+	return 0;
+}
+
+static const struct net_device_ops hbg_netdev_ops = {
+	.ndo_open		= hbg_net_open,
+	.ndo_stop		= hbg_net_stop,
+	.ndo_validate_addr	= eth_validate_addr,
+	.ndo_set_mac_address	= hbg_net_set_mac_address,
+	.ndo_change_mtu		= hbg_net_change_mtu,
+};
+
 static const u32 hbg_mode_ability[] = {
 	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
 	ETHTOOL_LINK_MODE_100baseT_Full_BIT,
@@ -95,6 +195,7 @@  static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	priv = netdev_priv(netdev);
 	priv->netdev = netdev;
 	priv->pdev = pdev;
+	netdev->netdev_ops = &hbg_netdev_ops;
 
 	ret = hbg_pci_init(pdev);
 	if (ret)
@@ -104,6 +205,10 @@  static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	if (ret)
 		return ret;
 
+	netdev->max_mtu = priv->dev_specs.max_mtu;
+	netdev->min_mtu = priv->dev_specs.min_mtu;
+	hbg_net_change_mtu(netdev, HBG_DEFAULT_MTU_SIZE);
+	hbg_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr);
 	ret = devm_register_netdev(&pdev->dev, netdev);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret,
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
index b422fa990270..86f1157a2af2 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
@@ -29,7 +29,9 @@ 
 /* GMAC */
 #define HBG_REG_SGMII_BASE			0x10000
 #define HBG_REG_DUPLEX_TYPE_ADDR		(HBG_REG_SGMII_BASE + 0x0008)
+#define HBG_REG_MAX_FRAME_SIZE_ADDR		(HBG_REG_SGMII_BASE + 0x003C)
 #define HBG_REG_PORT_MODE_ADDR			(HBG_REG_SGMII_BASE + 0x0040)
+#define HBG_REG_PORT_ENABLE_ADDR		(HBG_REG_SGMII_BASE + 0x0044)
 #define HBG_REG_AN_NEG_STATE_ADDR		(HBG_REG_SGMII_BASE + 0x0058)
 #define HBG_REG_TX_LOCAL_PAGE_ADDR		(HBG_REG_SGMII_BASE + 0x005C)
 #define HBG_REG_TRANSMIT_CONTROL_ADDR		(HBG_REG_SGMII_BASE + 0x0060)
@@ -38,11 +40,14 @@ 
 #define HBG_REG_16_BIT_CNTR_ADDR		(HBG_REG_SGMII_BASE + 0x01CC)
 #define HBG_REG_LD_LINK_COUNTER_ADDR		(HBG_REG_SGMII_BASE + 0x01D0)
 #define HBG_REG_RECV_CONTROL_ADDR		(HBG_REG_SGMII_BASE + 0x01E0)
+#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)
 
 /* PCU */
 #define HBG_REG_CF_INTRPT_MSK_ADDR		(HBG_REG_SGMII_BASE + 0x042C)
 #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_MAX_FRAME_LEN_ADDR		(HBG_REG_SGMII_BASE + 0x0444)
 #define HBG_REG_RX_BUF_SIZE_ADDR		(HBG_REG_SGMII_BASE + 0x04E4)
 #define HBG_REG_BUS_CTRL_ADDR			(HBG_REG_SGMII_BASE + 0x04E8)
 #define HBG_REG_RX_CTRL_ADDR			(HBG_REG_SGMII_BASE + 0x04F0)
@@ -57,12 +62,15 @@ 
 /* mask */
 #define HBG_REG_PORT_MODE_M			GENMASK(3, 0)
 #define HBG_REG_MODE_CHANGE_EN_B		BIT(0)
+#define HBG_REG_MAX_FRAME_LEN_M			GENMASK(15, 0)
 #define HBG_REG_RX_BUF_SIZE_M			GENMASK(15, 0)
 #define HBG_REG_BUS_CTRL_ENDIAN_M		GENMASK(2, 1)
 #define HBG_REG_DUPLEX_B			BIT(0)
 #define HBG_REG_CF_CRC_STRIP_B			BIT(1)
 #define HBG_REG_MDIO_WDATA_M			GENMASK(15, 0)
 #define HBG_REG_IND_INTR_MASK_B			BIT(0)
+#define HBG_REG_PORT_ENABLE_RX_B		BIT(1)
+#define HBG_REG_PORT_ENABLE_TX_B		BIT(2)
 
 enum hbg_port_mode {
 	/* 0x0 ~ 0x5 are reserved */