diff options
Diffstat (limited to 'drivers/net/ethernet/hisilicon')
41 files changed, 1908 insertions, 254 deletions
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index 3312e1d93c3b..65302c41bfb1 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -7,7 +7,6 @@ config NET_VENDOR_HISILICON bool "Hisilicon devices" default y depends on OF || ACPI - depends on ARM || ARM64 || COMPILE_TEST help If you have a network (Ethernet) card belonging to this class, say Y. @@ -18,6 +17,8 @@ config NET_VENDOR_HISILICON if NET_VENDOR_HISILICON +if ARM || ARM64 || COMPILE_TEST + config HIX5HD2_GMAC tristate "Hisilicon HIX5HD2 Family Network Device Support" select PHYLIB @@ -141,4 +142,19 @@ config HNS3_ENET endif #HNS3 +endif # ARM || ARM64 || COMPILE_TEST + +config HIBMCGE + tristate "Hisilicon BMC Gigabit Ethernet Device Support" + depends on PCI && PCI_MSI + select PHYLIB + select MOTORCOMM_PHY + select REALTEK_PHY + help + If you wish to compile a kernel for a BMC with HIBMC-xx_gmac + then you should answer Y to this. This makes this driver suitable for use + on certain boards such as the HIBMC-210. + + If you are unsure, say N. + endif # NET_VENDOR_HISILICON diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile index 7f76d412047a..0e2cadfea8ff 100644 --- a/drivers/net/ethernet/hisilicon/Makefile +++ b/drivers/net/ethernet/hisilicon/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_HNS_MDIO) += hns_mdio.o obj-$(CONFIG_HNS) += hns/ obj-$(CONFIG_HNS3) += hns3/ obj-$(CONFIG_HISI_FEMAC) += hisi_femac.o +obj-$(CONFIG_HIBMCGE) += hibmcge/ diff --git a/drivers/net/ethernet/hisilicon/hibmcge/Makefile b/drivers/net/ethernet/hisilicon/hibmcge/Makefile new file mode 100644 index 000000000000..ae58ac38c206 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Makefile for the HISILICON BMC GE network device drivers. +# + +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 diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h new file mode 100644 index 000000000000..96daf058d387 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_COMMON_H +#define __HBG_COMMON_H + +#include <linux/netdevice.h> +#include <linux/pci.h> +#include "hbg_reg.h" + +#define HBG_STATUS_DISABLE 0x0 +#define HBG_STATUS_ENABLE 0x1 +#define HBG_RX_SKIP1 0x00 +#define HBG_RX_SKIP2 0x01 +#define HBG_VECTOR_NUM 4 +#define HBG_PCU_CACHE_LINE_SIZE 32 +#define HBG_TX_TIMEOUT_BUF_LEN 1024 +#define HBG_RX_DESCR 0x01 + +#define HBG_PACKET_HEAD_SIZE ((HBG_RX_SKIP1 + HBG_RX_SKIP2 + \ + HBG_RX_DESCR) * HBG_PCU_CACHE_LINE_SIZE) + +enum hbg_dir { + HBG_DIR_TX = 1 << 0, + HBG_DIR_RX = 1 << 1, + HBG_DIR_TX_RX = HBG_DIR_TX | HBG_DIR_RX, +}; + +enum hbg_tx_state { + HBG_TX_STATE_COMPLETE = 0, /* clear state, must fix to 0 */ + HBG_TX_STATE_START, +}; + +enum hbg_nic_state { + HBG_NIC_STATE_EVENT_HANDLING = 0, +}; + +struct hbg_buffer { + u32 state; + dma_addr_t state_dma; + + struct sk_buff *skb; + dma_addr_t skb_dma; + u32 skb_len; + + enum hbg_dir dir; + struct hbg_ring *ring; + struct hbg_priv *priv; +}; + +struct hbg_ring { + struct hbg_buffer *queue; + dma_addr_t queue_dma; + + union { + u32 head; + u32 ntc; + }; + union { + u32 tail; + u32 ntu; + }; + u32 len; + + enum hbg_dir dir; + struct hbg_priv *priv; + struct napi_struct napi; + char *tout_log_buf; /* tx timeout log buffer */ +}; + +enum hbg_hw_event_type { + HBG_HW_EVENT_NONE = 0, + HBG_HW_EVENT_INIT, /* driver is loading */ + HBG_HW_EVENT_RESET, +}; + +struct hbg_dev_specs { + u32 mac_id; + struct sockaddr mac_addr; + u32 phy_addr; + u32 mdio_frequency; + u32 rx_fifo_num; + u32 tx_fifo_num; + u32 vlan_layers; + u32 max_mtu; + u32 min_mtu; + + u32 max_frame_len; + u32 rx_buf_size; +}; + +struct hbg_irq_info { + const char *name; + u32 mask; + bool re_enable; + bool need_print; + u64 count; + + void (*irq_handle)(struct hbg_priv *priv, struct hbg_irq_info *info); +}; + +struct hbg_vector { + char name[HBG_VECTOR_NUM][32]; + struct hbg_irq_info *info_array; + u32 info_array_len; +}; + +struct hbg_mac { + struct mii_bus *mdio_bus; + struct phy_device *phydev; + u8 phy_addr; + + u32 speed; + u32 duplex; + u32 autoneg; + u32 link_status; +}; + +struct hbg_priv { + struct net_device *netdev; + struct pci_dev *pdev; + u8 __iomem *io_base; + struct hbg_dev_specs dev_specs; + unsigned long state; + struct hbg_mac mac; + struct hbg_vector vectors; + struct hbg_ring tx_ring; + struct hbg_ring rx_ring; +}; + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c new file mode 100644 index 000000000000..c3370114aef3 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include <linux/ethtool.h> +#include <linux/phy.h> +#include "hbg_ethtool.h" + +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, +}; + +void hbg_ethtool_set_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &hbg_ethtool_ops; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.h new file mode 100644 index 000000000000..628707ec2686 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_ETHTOOL_H +#define __HBG_ETHTOOL_H + +#include <linux/netdevice.h> + +void hbg_ethtool_set_ops(struct net_device *netdev); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c new file mode 100644 index 000000000000..05295c2ad439 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/iopoll.h> +#include <linux/minmax.h> +#include "hbg_common.h" +#include "hbg_hw.h" +#include "hbg_reg.h" + +#define HBG_HW_EVENT_WAIT_TIMEOUT_US (2 * 1000 * 1000) +#define HBG_HW_EVENT_WAIT_INTERVAL_US (10 * 1000) +/* little endian or big endian. + * ctrl means packet description, data means skb packet data + */ +#define HBG_ENDIAN_CTRL_LE_DATA_BE 0x0 +#define HBG_PCU_FRAME_LEN_PLUS 4 + +static bool hbg_hw_spec_is_valid(struct hbg_priv *priv) +{ + return hbg_reg_read(priv, HBG_REG_SPEC_VALID_ADDR) && + !hbg_reg_read(priv, HBG_REG_EVENT_REQ_ADDR); +} + +int hbg_hw_event_notify(struct hbg_priv *priv, + enum hbg_hw_event_type event_type) +{ + bool is_valid; + int ret; + + if (test_and_set_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state)) + return -EBUSY; + + /* notify */ + hbg_reg_write(priv, HBG_REG_EVENT_REQ_ADDR, event_type); + + ret = read_poll_timeout(hbg_hw_spec_is_valid, is_valid, is_valid, + HBG_HW_EVENT_WAIT_INTERVAL_US, + HBG_HW_EVENT_WAIT_TIMEOUT_US, + HBG_HW_EVENT_WAIT_INTERVAL_US, priv); + + clear_bit(HBG_NIC_STATE_EVENT_HANDLING, &priv->state); + + if (ret) + dev_err(&priv->pdev->dev, + "event %d wait timeout\n", event_type); + + return ret; +} + +static int hbg_hw_dev_specs_init(struct hbg_priv *priv) +{ + struct hbg_dev_specs *specs = &priv->dev_specs; + u64 mac_addr; + + if (!hbg_hw_spec_is_valid(priv)) { + dev_err(&priv->pdev->dev, "dev_specs not init\n"); + return -EINVAL; + } + + specs->mac_id = hbg_reg_read(priv, HBG_REG_MAC_ID_ADDR); + specs->phy_addr = hbg_reg_read(priv, HBG_REG_PHY_ID_ADDR); + specs->mdio_frequency = hbg_reg_read(priv, HBG_REG_MDIO_FREQ_ADDR); + specs->max_mtu = hbg_reg_read(priv, HBG_REG_MAX_MTU_ADDR); + specs->min_mtu = hbg_reg_read(priv, HBG_REG_MIN_MTU_ADDR); + 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); + mac_addr = hbg_reg_read64(priv, HBG_REG_MAC_ADDR_ADDR); + u64_to_ether_addr(mac_addr, (u8 *)specs->mac_addr.sa_data); + + if (!is_valid_ether_addr((u8 *)specs->mac_addr.sa_data)) + return -EADDRNOTAVAIL; + + specs->max_frame_len = HBG_PCU_CACHE_LINE_SIZE + specs->max_mtu; + specs->rx_buf_size = HBG_PACKET_HEAD_SIZE + specs->max_frame_len; + return 0; +} + +u32 hbg_hw_get_irq_status(struct hbg_priv *priv) +{ + u32 status; + + status = hbg_reg_read(priv, HBG_REG_CF_INTRPT_STAT_ADDR); + + hbg_field_modify(status, HBG_INT_MSK_TX_B, + hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_STAT_ADDR)); + hbg_field_modify(status, HBG_INT_MSK_RX_B, + hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_STAT_ADDR)); + + return status; +} + +void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask) +{ + if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) + return hbg_reg_write(priv, HBG_REG_CF_IND_TXINT_CLR_ADDR, 0x1); + + if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) + return hbg_reg_write(priv, HBG_REG_CF_IND_RXINT_CLR_ADDR, 0x1); + + return hbg_reg_write(priv, HBG_REG_CF_INTRPT_CLR_ADDR, mask); +} + +bool hbg_hw_irq_is_enabled(struct hbg_priv *priv, u32 mask) +{ + if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) + return hbg_reg_read(priv, HBG_REG_CF_IND_TXINT_MSK_ADDR); + + if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) + return hbg_reg_read(priv, HBG_REG_CF_IND_RXINT_MSK_ADDR); + + return hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR) & mask; +} + +void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable) +{ + u32 value; + + if (FIELD_GET(HBG_INT_MSK_TX_B, mask)) + return hbg_reg_write(priv, + HBG_REG_CF_IND_TXINT_MSK_ADDR, enable); + + if (FIELD_GET(HBG_INT_MSK_RX_B, mask)) + return hbg_reg_write(priv, + HBG_REG_CF_IND_RXINT_MSK_ADDR, enable); + + value = hbg_reg_read(priv, HBG_REG_CF_INTRPT_MSK_ADDR); + if (enable) + value |= mask; + else + value &= ~mask; + + hbg_reg_write(priv, HBG_REG_CF_INTRPT_MSK_ADDR, value); +} + +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) +{ + max_frame_len = max_t(u32, max_frame_len, ETH_DATA_LEN); + + /* lower two bits of value must be set to 0 */ + 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_field(priv, HBG_REG_PORT_ENABLE_ADDR, + HBG_REG_PORT_ENABLE_TX_B, enable); + hbg_reg_write_field(priv, HBG_REG_PORT_ENABLE_ADDR, + HBG_REG_PORT_ENABLE_RX_B, enable); +} + +u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir) +{ + if (dir & HBG_DIR_TX) + return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR, + HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M); + + if (dir & HBG_DIR_RX) + return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR, + HBG_REG_CF_CFF_DATA_NUM_ADDR_RX_M); + + return 0; +} + +void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc) +{ + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_0_ADDR, tx_desc->word0); + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_1_ADDR, tx_desc->word1); + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_2_ADDR, tx_desc->word2); + hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_3_ADDR, tx_desc->word3); +} + +void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr) +{ + hbg_reg_write(priv, HBG_REG_RX_CFF_ADDR_ADDR, buffer_dma_addr); +} + +void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex) +{ + hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR, + HBG_REG_PORT_MODE_M, speed); + hbg_reg_write_field(priv, HBG_REG_DUPLEX_TYPE_ADDR, + HBG_REG_DUPLEX_B, duplex); +} + +static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv) +{ + u32 ctrl = 0; + + ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_AN_EN_B, HBG_STATUS_ENABLE); + ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_CRC_ADD_B, HBG_STATUS_ENABLE); + ctrl |= FIELD_PREP(HBG_REG_TRANSMIT_CTRL_PAD_EN_B, HBG_STATUS_ENABLE); + + hbg_reg_write(priv, HBG_REG_TRANSMIT_CTRL_ADDR, ctrl); +} + +static void hbg_hw_init_rx_ctrl(struct hbg_priv *priv) +{ + u32 ctrl = 0; + + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_GET_ADDR_MODE_B, + HBG_STATUS_ENABLE); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_TIME_INF_EN_B, HBG_STATUS_DISABLE); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE_M, HBG_RX_SKIP1); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE2_M, + HBG_RX_SKIP2); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_RX_ALIGN_NUM_M, NET_IP_ALIGN); + ctrl |= FIELD_PREP(HBG_REG_RX_CTRL_PORT_NUM, priv->dev_specs.mac_id); + + hbg_reg_write(priv, HBG_REG_RX_CTRL_ADDR, ctrl); +} + +static void hbg_hw_init_rx_control(struct hbg_priv *priv) +{ + hbg_hw_init_rx_ctrl(priv); + + /* parse from L2 layer */ + hbg_reg_write_field(priv, HBG_REG_RX_PKT_MODE_ADDR, + HBG_REG_RX_PKT_MODE_PARSE_MODE_M, 0x1); + + hbg_reg_write_field(priv, HBG_REG_RECV_CTRL_ADDR, + HBG_REG_RECV_CTRL_STRIP_PAD_EN_B, + HBG_STATUS_ENABLE); + hbg_reg_write_field(priv, HBG_REG_RX_BUF_SIZE_ADDR, + HBG_REG_RX_BUF_SIZE_M, priv->dev_specs.rx_buf_size); + hbg_reg_write_field(priv, HBG_REG_CF_CRC_STRIP_ADDR, + HBG_REG_CF_CRC_STRIP_B, HBG_STATUS_DISABLE); +} + +int hbg_hw_init(struct hbg_priv *priv) +{ + int ret; + + ret = hbg_hw_dev_specs_init(priv); + if (ret) + return ret; + + hbg_reg_write_field(priv, HBG_REG_BUS_CTRL_ADDR, + HBG_REG_BUS_CTRL_ENDIAN_M, + HBG_ENDIAN_CTRL_LE_DATA_BE); + hbg_reg_write_field(priv, HBG_REG_MODE_CHANGE_EN_ADDR, + HBG_REG_MODE_CHANGE_EN_B, HBG_STATUS_ENABLE); + + hbg_hw_init_rx_control(priv); + hbg_hw_init_transmit_ctrl(priv); + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h new file mode 100644 index 000000000000..14fb39241c93 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_HW_H +#define __HBG_HW_H + +#include <linux/bitfield.h> +#include <linux/io-64-nonatomic-lo-hi.h> + +static inline u32 hbg_reg_read(struct hbg_priv *priv, u32 addr) +{ + return readl(priv->io_base + addr); +} + +static inline void hbg_reg_write(struct hbg_priv *priv, u32 addr, u32 value) +{ + writel(value, priv->io_base + addr); +} + +static inline u64 hbg_reg_read64(struct hbg_priv *priv, u32 addr) +{ + return lo_hi_readq(priv->io_base + addr); +} + +static inline void hbg_reg_write64(struct hbg_priv *priv, u32 addr, u64 value) +{ + lo_hi_writeq(value, priv->io_base + addr); +} + +#define hbg_reg_read_field(priv, addr, mask) \ + FIELD_GET(mask, hbg_reg_read(priv, addr)) + +#define hbg_field_modify(reg_value, mask, value) ({ \ + (reg_value) &= ~(mask); \ + (reg_value) |= FIELD_PREP(mask, value); }) + +#define hbg_reg_write_field(priv, addr, mask, val) ({ \ + typeof(priv) _priv = (priv); \ + typeof(addr) _addr = (addr); \ + u32 _value = hbg_reg_read(_priv, _addr); \ + hbg_field_modify(_value, mask, val); \ + hbg_reg_write(_priv, _addr, _value); }) + +int hbg_hw_event_notify(struct hbg_priv *priv, + enum hbg_hw_event_type event_type); +int hbg_hw_init(struct hbg_priv *priv); +void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex); +u32 hbg_hw_get_irq_status(struct hbg_priv *priv); +void hbg_hw_irq_clear(struct hbg_priv *priv, u32 mask); +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); +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); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c new file mode 100644 index 000000000000..25dd25f096fe --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include <linux/interrupt.h> +#include "hbg_irq.h" +#include "hbg_hw.h" + +static void hbg_irq_handle_err(struct hbg_priv *priv, + struct hbg_irq_info *irq_info) +{ + if (irq_info->need_print) + dev_err(&priv->pdev->dev, + "receive error interrupt: %s\n", irq_info->name); +} + +static void hbg_irq_handle_tx(struct hbg_priv *priv, + struct hbg_irq_info *irq_info) +{ + napi_schedule(&priv->tx_ring.napi); +} + +static void hbg_irq_handle_rx(struct hbg_priv *priv, + struct hbg_irq_info *irq_info) +{ + napi_schedule(&priv->rx_ring.napi); +} + +#define HBG_TXRX_IRQ_I(name, handle) \ + {#name, HBG_INT_MSK_##name##_B, false, false, 0, handle} +#define HBG_ERR_IRQ_I(name, need_print) \ + {#name, HBG_INT_MSK_##name##_B, true, need_print, 0, hbg_irq_handle_err} + +static struct hbg_irq_info hbg_irqs[] = { + HBG_TXRX_IRQ_I(RX, hbg_irq_handle_rx), + HBG_TXRX_IRQ_I(TX, hbg_irq_handle_tx), + HBG_ERR_IRQ_I(MAC_MII_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_PCS_RX_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_PCS_TX_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_APP_RX_FIFO_ERR, true), + HBG_ERR_IRQ_I(MAC_APP_TX_FIFO_ERR, true), + HBG_ERR_IRQ_I(SRAM_PARITY_ERR, true), + HBG_ERR_IRQ_I(TX_AHB_ERR, true), + HBG_ERR_IRQ_I(RX_BUF_AVL, false), + HBG_ERR_IRQ_I(REL_BUF_ERR, true), + HBG_ERR_IRQ_I(TXCFG_AVL, false), + HBG_ERR_IRQ_I(TX_DROP, false), + HBG_ERR_IRQ_I(RX_DROP, false), + HBG_ERR_IRQ_I(RX_AHB_ERR, true), + HBG_ERR_IRQ_I(MAC_FIFO_ERR, false), + HBG_ERR_IRQ_I(RBREQ_ERR, false), + HBG_ERR_IRQ_I(WE_ERR, false), +}; + +static irqreturn_t hbg_irq_handle(int irq_num, void *p) +{ + struct hbg_irq_info *info; + struct hbg_priv *priv = p; + u32 status; + u32 i; + + status = hbg_hw_get_irq_status(priv); + for (i = 0; i < priv->vectors.info_array_len; i++) { + info = &priv->vectors.info_array[i]; + if (status & info->mask) { + if (!hbg_hw_irq_is_enabled(priv, info->mask)) + continue; + + hbg_hw_irq_enable(priv, info->mask, false); + hbg_hw_irq_clear(priv, info->mask); + + info->count++; + if (info->irq_handle) + info->irq_handle(priv, info); + + if (info->re_enable) + hbg_hw_irq_enable(priv, info->mask, true); + } + } + + return IRQ_HANDLED; +} + +static const char *irq_names_map[HBG_VECTOR_NUM] = { "tx", "rx", + "err", "mdio" }; + +int hbg_irq_init(struct hbg_priv *priv) +{ + struct hbg_vector *vectors = &priv->vectors; + struct device *dev = &priv->pdev->dev; + int ret, id; + u32 i; + + /* used pcim_enable_device(), so the vectors become device managed */ + ret = pci_alloc_irq_vectors(priv->pdev, HBG_VECTOR_NUM, HBG_VECTOR_NUM, + PCI_IRQ_MSI | PCI_IRQ_MSIX); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to allocate vectors\n"); + + if (ret != HBG_VECTOR_NUM) + return dev_err_probe(dev, -EINVAL, + "requested %u MSI, but allocated %d MSI\n", + HBG_VECTOR_NUM, ret); + + /* mdio irq not requested, so the number of requested interrupts + * is HBG_VECTOR_NUM - 1. + */ + for (i = 0; i < HBG_VECTOR_NUM - 1; i++) { + id = pci_irq_vector(priv->pdev, i); + if (id < 0) + return dev_err_probe(dev, id, "failed to get irq id\n"); + + snprintf(vectors->name[i], sizeof(vectors->name[i]), "%s-%s-%s", + dev_driver_string(dev), pci_name(priv->pdev), + irq_names_map[i]); + + ret = devm_request_irq(dev, id, hbg_irq_handle, 0, + vectors->name[i], priv); + if (ret) + return dev_err_probe(dev, ret, + "failed to request irq: %s\n", + irq_names_map[i]); + } + + vectors->info_array = hbg_irqs; + vectors->info_array_len = ARRAY_SIZE(hbg_irqs); + return 0; +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.h new file mode 100644 index 000000000000..5c5323cfc751 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_IRQ_H +#define __HBG_IRQ_H + +#include "hbg_common.h" + +int hbg_irq_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 new file mode 100644 index 000000000000..75505fb5cc4a --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0+ +// 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" +#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); + +static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled) +{ + struct hbg_irq_info *info; + u32 i; + + for (i = 0; i < priv->vectors.info_array_len; i++) { + info = &priv->vectors.info_array[i]; + hbg_hw_irq_enable(priv, info->mask, enabled); + } +} + +static int hbg_net_open(struct net_device *netdev) +{ + struct hbg_priv *priv = netdev_priv(netdev); + int ret; + + ret = hbg_txrx_init(priv); + if (ret) + return ret; + + hbg_all_irq_enable(priv, true); + hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE); + netif_start_queue(netdev); + hbg_phy_start(priv); + + return 0; +} + +/* This function only can be called after hbg_txrx_uninit() */ +static int hbg_hw_txrx_clear(struct hbg_priv *priv) +{ + int ret; + + /* After ring buffers have been released, + * do a reset to release hw fifo rx ring buffer + */ + ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET); + if (ret) + 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; +} + +static int hbg_net_stop(struct net_device *netdev) +{ + struct hbg_priv *priv = netdev_priv(netdev); + + hbg_phy_stop(priv); + netif_stop_queue(netdev); + hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE); + hbg_all_irq_enable(priv, false); + hbg_txrx_uninit(priv); + return hbg_hw_txrx_clear(priv); +} + +static int hbg_net_set_mac_address(struct net_device *netdev, void *addr) +{ + struct hbg_priv *priv = netdev_priv(netdev); + u8 *mac_addr; + + 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)); + 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); + + if (netif_running(netdev)) + return -EBUSY; + + hbg_change_mtu(priv, new_mtu); + WRITE_ONCE(netdev->mtu, new_mtu); + + dev_dbg(&priv->pdev->dev, + "change mtu from %u to %u\n", netdev->mtu, new_mtu); + + return 0; +} + +static void hbg_net_tx_timeout(struct net_device *netdev, unsigned int txqueue) +{ + struct hbg_priv *priv = netdev_priv(netdev); + struct hbg_ring *ring = &priv->tx_ring; + char *buf = ring->tout_log_buf; + u32 pos = 0; + + pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos, + "ring used num: %u, fifo used num: %u\n", + hbg_get_queue_used_num(ring), + hbg_hw_get_fifo_used_num(priv, HBG_DIR_TX)); + pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos, + "ntc: %u, ntu: %u, irq enabled: %u\n", + ring->ntc, ring->ntu, + hbg_hw_irq_is_enabled(priv, HBG_INT_MSK_TX_B)); + + netdev_info(netdev, "%s", buf); +} + +static const struct net_device_ops hbg_netdev_ops = { + .ndo_open = hbg_net_open, + .ndo_stop = hbg_net_stop, + .ndo_start_xmit = hbg_net_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = hbg_net_set_mac_address, + .ndo_change_mtu = hbg_net_change_mtu, + .ndo_tx_timeout = hbg_net_tx_timeout, +}; + +static int hbg_init(struct hbg_priv *priv) +{ + int ret; + + ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_INIT); + if (ret) + return ret; + + ret = hbg_hw_init(priv); + if (ret) + return ret; + + ret = hbg_irq_init(priv); + if (ret) + return ret; + + return hbg_mdio_init(priv); +} + +static int hbg_pci_init(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct hbg_priv *priv = netdev_priv(netdev); + struct device *dev = &pdev->dev; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return dev_err_probe(dev, ret, "failed to enable PCI device\n"); + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) + return dev_err_probe(dev, ret, "failed to set PCI DMA mask\n"); + + ret = pcim_iomap_regions(pdev, BIT(0), dev_driver_string(dev)); + if (ret) + return dev_err_probe(dev, ret, "failed to map PCI bar space\n"); + + priv->io_base = pcim_iomap_table(pdev)[0]; + if (!priv->io_base) + return dev_err_probe(dev, -ENOMEM, "failed to get io base\n"); + + pci_set_master(pdev); + return 0; +} + +static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct net_device *netdev; + struct hbg_priv *priv; + int ret; + + netdev = devm_alloc_etherdev(dev, sizeof(struct hbg_priv)); + if (!netdev) + return -ENOMEM; + + pci_set_drvdata(pdev, netdev); + SET_NETDEV_DEV(netdev, dev); + + priv = netdev_priv(netdev); + priv->netdev = netdev; + priv->pdev = pdev; + + ret = hbg_pci_init(pdev); + if (ret) + return ret; + + ret = hbg_init(priv); + if (ret) + return ret; + + 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_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr); + hbg_ethtool_set_ops(netdev); + + ret = devm_register_netdev(dev, netdev); + if (ret) + return dev_err_probe(dev, ret, "failed to register netdev\n"); + + netif_carrier_off(netdev); + return 0; +} + +static const struct pci_device_id hbg_pci_tbl[] = { + {PCI_VDEVICE(HUAWEI, 0x3730), 0}, + { } +}; +MODULE_DEVICE_TABLE(pci, hbg_pci_tbl); + +static struct pci_driver hbg_driver = { + .name = "hibmcge", + .id_table = hbg_pci_tbl, + .probe = hbg_probe, +}; +module_pci_driver(hbg_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huawei Tech. Co., Ltd."); +MODULE_DESCRIPTION("hibmcge driver"); +MODULE_VERSION("1.0"); diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c new file mode 100644 index 000000000000..a3479fba8501 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include <linux/phy.h> +#include "hbg_common.h" +#include "hbg_hw.h" +#include "hbg_mdio.h" +#include "hbg_reg.h" + +#define HBG_MAC_GET_PRIV(mac) ((struct hbg_priv *)(mac)->mdio_bus->priv) +#define HBG_MII_BUS_GET_MAC(bus) (&((struct hbg_priv *)(bus)->priv)->mac) + +#define HBG_MDIO_C22_MODE 0x1 +#define HBG_MDIO_C22_REG_WRITE 0x1 +#define HBG_MDIO_C22_REG_READ 0x2 + +#define HBG_MDIO_OP_TIMEOUT_US (1 * 1000 * 1000) +#define HBG_MDIO_OP_INTERVAL_US (5 * 1000) + +static void hbg_mdio_set_command(struct hbg_mac *mac, u32 cmd) +{ + hbg_reg_write(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR, cmd); +} + +static void hbg_mdio_get_command(struct hbg_mac *mac, u32 *cmd) +{ + *cmd = hbg_reg_read(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_ADDR); +} + +static void hbg_mdio_set_wdata_reg(struct hbg_mac *mac, u16 wdata_value) +{ + hbg_reg_write_field(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_WDATA_ADDR, + HBG_REG_MDIO_WDATA_M, wdata_value); +} + +static u32 hbg_mdio_get_rdata_reg(struct hbg_mac *mac) +{ + return hbg_reg_read_field(HBG_MAC_GET_PRIV(mac), + HBG_REG_MDIO_RDATA_ADDR, + HBG_REG_MDIO_WDATA_M); +} + +static int hbg_mdio_wait_ready(struct hbg_mac *mac) +{ + struct hbg_priv *priv = HBG_MAC_GET_PRIV(mac); + u32 cmd = 0; + int ret; + + ret = readl_poll_timeout(priv->io_base + HBG_REG_MDIO_COMMAND_ADDR, cmd, + !FIELD_GET(HBG_REG_MDIO_COMMAND_START_B, cmd), + HBG_MDIO_OP_INTERVAL_US, + HBG_MDIO_OP_TIMEOUT_US); + + return ret ? -ETIMEDOUT : 0; +} + +static int hbg_mdio_cmd_send(struct hbg_mac *mac, u32 prt_addr, u32 dev_addr, + u32 type, u32 op_code) +{ + u32 cmd = 0; + + hbg_mdio_get_command(mac, &cmd); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_ST_M, type); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_OP_M, op_code); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_PRTAD_M, prt_addr); + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_DEVAD_M, dev_addr); + + /* if auto scan enabled, this value need fix to 0 */ + hbg_field_modify(cmd, HBG_REG_MDIO_COMMAND_START_B, 0x1); + + hbg_mdio_set_command(mac, cmd); + + /* wait operation complete and check the result */ + return hbg_mdio_wait_ready(mac); +} + +static int hbg_mdio_read22(struct mii_bus *bus, int phy_addr, int regnum) +{ + struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); + int ret; + + ret = hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, + HBG_MDIO_C22_REG_READ); + if (ret) + return ret; + + return hbg_mdio_get_rdata_reg(mac); +} + +static int hbg_mdio_write22(struct mii_bus *bus, int phy_addr, int regnum, + u16 val) +{ + struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus); + + hbg_mdio_set_wdata_reg(mac, val); + return hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE, + HBG_MDIO_C22_REG_WRITE); +} + +static void hbg_mdio_init_hw(struct hbg_priv *priv) +{ + u32 freq = priv->dev_specs.mdio_frequency; + struct hbg_mac *mac = &priv->mac; + u32 cmd = 0; + + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_ST_M, HBG_MDIO_C22_MODE); + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_AUTO_SCAN_B, HBG_STATUS_DISABLE); + + /* freq use two bits, which are stored in clk_sel and clk_sel_exp */ + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_B, freq & 0x1); + cmd |= FIELD_PREP(HBG_REG_MDIO_COMMAND_CLK_SEL_EXP_B, + (freq >> 1) & 0x1); + + hbg_mdio_set_command(mac, cmd); +} + +static void hbg_phy_adjust_link(struct net_device *netdev) +{ + struct hbg_priv *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; + u32 speed; + + if (phydev->link != priv->mac.link_status) { + if (phydev->link) { + switch (phydev->speed) { + case SPEED_10: + speed = HBG_PORT_MODE_SGMII_10M; + break; + case SPEED_100: + speed = HBG_PORT_MODE_SGMII_100M; + break; + case SPEED_1000: + speed = HBG_PORT_MODE_SGMII_1000M; + break; + default: + return; + } + + priv->mac.speed = speed; + priv->mac.duplex = phydev->duplex; + priv->mac.autoneg = phydev->autoneg; + hbg_hw_adjust_link(priv, speed, phydev->duplex); + } + + priv->mac.link_status = phydev->link; + phy_print_status(phydev); + } +} + +static void hbg_phy_disconnect(void *data) +{ + phy_disconnect((struct phy_device *)data); +} + +static int hbg_phy_connect(struct hbg_priv *priv) +{ + struct phy_device *phydev = priv->mac.phydev; + struct device *dev = &priv->pdev->dev; + int ret; + + ret = phy_connect_direct(priv->netdev, phydev, hbg_phy_adjust_link, + PHY_INTERFACE_MODE_SGMII); + if (ret) + return dev_err_probe(dev, ret, "failed to connect phy\n"); + + ret = devm_add_action_or_reset(dev, hbg_phy_disconnect, phydev); + if (ret) + return ret; + + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_attached_info(phydev); + + return 0; +} + +void hbg_phy_start(struct hbg_priv *priv) +{ + phy_start(priv->mac.phydev); +} + +void hbg_phy_stop(struct hbg_priv *priv) +{ + phy_stop(priv->mac.phydev); +} + +int hbg_mdio_init(struct hbg_priv *priv) +{ + struct device *dev = &priv->pdev->dev; + struct hbg_mac *mac = &priv->mac; + struct phy_device *phydev; + struct mii_bus *mdio_bus; + int ret; + + mac->phy_addr = priv->dev_specs.phy_addr; + mdio_bus = devm_mdiobus_alloc(dev); + if (!mdio_bus) + return dev_err_probe(dev, -ENOMEM, + "failed to alloc MDIO bus\n"); + + mdio_bus->parent = dev; + mdio_bus->priv = priv; + mdio_bus->phy_mask = ~(1 << mac->phy_addr); + mdio_bus->name = "hibmcge mii bus"; + mac->mdio_bus = mdio_bus; + + mdio_bus->read = hbg_mdio_read22; + mdio_bus->write = hbg_mdio_write22; + snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii", dev_name(dev)); + + ret = devm_mdiobus_register(dev, mdio_bus); + if (ret) + return dev_err_probe(dev, ret, "failed to register MDIO bus\n"); + + phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr); + if (!phydev) + return dev_err_probe(dev, -ENODEV, + "failed to get phy device\n"); + + mac->phydev = phydev; + hbg_mdio_init_hw(priv); + return hbg_phy_connect(priv); +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h new file mode 100644 index 000000000000..febd02a309c7 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_MDIO_H +#define __HBG_MDIO_H + +#include "hbg_common.h" + +int hbg_mdio_init(struct hbg_priv *priv); +void hbg_phy_start(struct hbg_priv *priv); +void hbg_phy_stop(struct hbg_priv *priv); +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h new file mode 100644 index 000000000000..57d81c6d7633 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_REG_H +#define __HBG_REG_H + +/* DEV SPEC */ +#define HBG_REG_SPEC_VALID_ADDR 0x0000 +#define HBG_REG_EVENT_REQ_ADDR 0x0004 +#define HBG_REG_MAC_ID_ADDR 0x0008 +#define HBG_REG_PHY_ID_ADDR 0x000C +#define HBG_REG_MAC_ADDR_ADDR 0x0010 +#define HBG_REG_MDIO_FREQ_ADDR 0x0024 +#define HBG_REG_MAX_MTU_ADDR 0x0028 +#define HBG_REG_MIN_MTU_ADDR 0x002C +#define HBG_REG_TX_FIFO_NUM_ADDR 0x0030 +#define HBG_REG_RX_FIFO_NUM_ADDR 0x0034 +#define HBG_REG_VLAN_LAYERS_ADDR 0x0038 + +/* MDIO */ +#define HBG_REG_MDIO_BASE 0x8000 +#define HBG_REG_MDIO_COMMAND_ADDR (HBG_REG_MDIO_BASE + 0x0000) +#define HBG_REG_MDIO_COMMAND_CLK_SEL_EXP_B BIT(17) +#define HBG_REG_MDIO_COMMAND_AUTO_SCAN_B BIT(16) +#define HBG_REG_MDIO_COMMAND_CLK_SEL_B BIT(15) +#define HBG_REG_MDIO_COMMAND_START_B BIT(14) +#define HBG_REG_MDIO_COMMAND_ST_M GENMASK(13, 12) +#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_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) +#define HBG_REG_MDIO_STA_ADDR (HBG_REG_MDIO_BASE + 0x0010) + +/* GMAC */ +#define HBG_REG_SGMII_BASE 0x10000 +#define HBG_REG_DUPLEX_TYPE_ADDR (HBG_REG_SGMII_BASE + 0x0008) +#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) +#define HBG_REG_PORT_MODE_M GENMASK(3, 0) +#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_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_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_RECV_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x01E0) +#define HBG_REG_RECV_CTRL_STRIP_PAD_EN_B BIT(3) +#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_INT_MSK_WE_ERR_B BIT(31) +#define HBG_INT_MSK_RBREQ_ERR_B BIT(30) +#define HBG_INT_MSK_MAC_FIFO_ERR_B BIT(29) +#define HBG_INT_MSK_RX_AHB_ERR_B BIT(28) +#define HBG_INT_MSK_RX_DROP_B BIT(26) +#define HBG_INT_MSK_TX_DROP_B BIT(25) +#define HBG_INT_MSK_TXCFG_AVL_B BIT(24) +#define HBG_INT_MSK_REL_BUF_ERR_B BIT(23) +#define HBG_INT_MSK_RX_BUF_AVL_B BIT(22) +#define HBG_INT_MSK_TX_AHB_ERR_B BIT(21) +#define HBG_INT_MSK_SRAM_PARITY_ERR_B BIT(20) +#define HBG_INT_MSK_MAC_APP_TX_FIFO_ERR_B BIT(19) +#define HBG_INT_MSK_MAC_APP_RX_FIFO_ERR_B BIT(18) +#define HBG_INT_MSK_MAC_PCS_TX_FIFO_ERR_B BIT(17) +#define HBG_INT_MSK_MAC_PCS_RX_FIFO_ERR_B BIT(16) +#define HBG_INT_MSK_MAC_MII_FIFO_ERR_B BIT(15) +#define HBG_INT_MSK_TX_B BIT(1) /* just used in driver */ +#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_MAX_FRAME_LEN_ADDR (HBG_REG_SGMII_BASE + 0x0444) +#define HBG_REG_MAX_FRAME_LEN_M GENMASK(15, 0) +#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_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) +#define HBG_REG_TX_CFF_ADDR_3_ADDR (HBG_REG_SGMII_BASE + 0x0494) +#define HBG_REG_RX_CFF_ADDR_ADDR (HBG_REG_SGMII_BASE + 0x04A0) +#define HBG_REG_RX_BUF_SIZE_ADDR (HBG_REG_SGMII_BASE + 0x04E4) +#define HBG_REG_RX_BUF_SIZE_M GENMASK(15, 0) +#define HBG_REG_BUS_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x04E8) +#define HBG_REG_BUS_CTRL_ENDIAN_M GENMASK(2, 1) +#define HBG_REG_RX_CTRL_ADDR (HBG_REG_SGMII_BASE + 0x04F0) +#define HBG_REG_RX_CTRL_RXBUF_1ST_SKIP_SIZE_M GENMASK(31, 28) +#define HBG_REG_RX_CTRL_TIME_INF_EN_B BIT(23) +#define HBG_REG_RX_CTRL_RX_ALIGN_NUM_M GENMASK(18, 17) +#define HBG_REG_RX_CTRL_PORT_NUM GENMASK(16, 13) +#define HBG_REG_RX_CTRL_RX_GET_ADDR_MODE_B BIT(12) +#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_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) +#define HBG_REG_CF_IND_TXINT_CLR_ADDR (HBG_REG_SGMII_BASE + 0x069C) +#define HBG_REG_CF_IND_RXINT_MSK_ADDR (HBG_REG_SGMII_BASE + 0x06a0) +#define HBG_REG_CF_IND_RXINT_STAT_ADDR (HBG_REG_SGMII_BASE + 0x06a4) +#define HBG_REG_CF_IND_RXINT_CLR_ADDR (HBG_REG_SGMII_BASE + 0x06a8) + +enum hbg_port_mode { + /* 0x0 ~ 0x5 are reserved */ + HBG_PORT_MODE_SGMII_10M = 0x6, + HBG_PORT_MODE_SGMII_100M = 0x7, + HBG_PORT_MODE_SGMII_1000M = 0x8, +}; + +struct hbg_tx_desc { + u32 word0; + u32 word1; + u32 word2; /* pkt_addr */ + u32 word3; /* clear_addr */ +}; + +#define HBG_TX_DESC_W0_IP_OFF_M GENMASK(30, 26) +#define HBG_TX_DESC_W0_l3_CS_B BIT(2) +#define HBG_TX_DESC_W0_WB_B BIT(1) +#define HBG_TX_DESC_W0_l4_CS_B BIT(0) +#define HBG_TX_DESC_W1_SEND_LEN_M GENMASK(19, 4) + +struct hbg_rx_desc { + u32 word0; + u32 word1; /* tag */ + u32 word2; + u32 word3; + u32 word4; + u32 word5; +}; + +#define HBG_RX_DESC_W2_PKT_LEN_M GENMASK(31, 16) + +#endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c new file mode 100644 index 000000000000..f4f256a0dfea --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2024 Hisilicon Limited. + +#include <net/netdev_queues.h> +#include "hbg_common.h" +#include "hbg_irq.h" +#include "hbg_reg.h" +#include "hbg_txrx.h" + +#define netdev_get_tx_ring(netdev) \ + (&(((struct hbg_priv *)netdev_priv(netdev))->tx_ring)) + +#define buffer_to_dma_dir(buffer) (((buffer)->dir == HBG_DIR_RX) ? \ + DMA_FROM_DEVICE : DMA_TO_DEVICE) + +#define hbg_queue_used_num(head, tail, ring) ({ \ + typeof(ring) _ring = (ring); \ + ((tail) + _ring->len - (head)) % _ring->len; }) +#define hbg_queue_left_num(head, tail, ring) ({ \ + typeof(ring) _r = (ring); \ + _r->len - hbg_queue_used_num((head), (tail), _r) - 1; }) +#define hbg_queue_is_empty(head, tail, ring) \ + (hbg_queue_used_num((head), (tail), (ring)) == 0) +#define hbg_queue_is_full(head, tail, ring) \ + (hbg_queue_left_num((head), (tail), (ring)) == 0) +#define hbg_queue_next_prt(p, ring) (((p) + 1) % (ring)->len) +#define hbg_queue_move_next(p, ring) ({ \ + typeof(ring) _ring = (ring); \ + _ring->p = hbg_queue_next_prt(_ring->p, _ring); }) + +#define HBG_TX_STOP_THRS 2 +#define HBG_TX_START_THRS (2 * HBG_TX_STOP_THRS) + +static int hbg_dma_map(struct hbg_buffer *buffer) +{ + struct hbg_priv *priv = buffer->priv; + + buffer->skb_dma = dma_map_single(&priv->pdev->dev, + buffer->skb->data, buffer->skb_len, + buffer_to_dma_dir(buffer)); + if (unlikely(dma_mapping_error(&priv->pdev->dev, buffer->skb_dma))) + return -ENOMEM; + + return 0; +} + +static void hbg_dma_unmap(struct hbg_buffer *buffer) +{ + struct hbg_priv *priv = buffer->priv; + + if (unlikely(!buffer->skb_dma)) + return; + + dma_unmap_single(&priv->pdev->dev, buffer->skb_dma, buffer->skb_len, + buffer_to_dma_dir(buffer)); + buffer->skb_dma = 0; +} + +static void hbg_init_tx_desc(struct hbg_buffer *buffer, + struct hbg_tx_desc *tx_desc) +{ + u32 ip_offset = buffer->skb->network_header - buffer->skb->mac_header; + u32 word0 = 0; + + word0 |= FIELD_PREP(HBG_TX_DESC_W0_WB_B, HBG_STATUS_ENABLE); + word0 |= FIELD_PREP(HBG_TX_DESC_W0_IP_OFF_M, ip_offset); + if (likely(buffer->skb->ip_summed == CHECKSUM_PARTIAL)) { + word0 |= FIELD_PREP(HBG_TX_DESC_W0_l3_CS_B, HBG_STATUS_ENABLE); + word0 |= FIELD_PREP(HBG_TX_DESC_W0_l4_CS_B, HBG_STATUS_ENABLE); + } + + tx_desc->word0 = word0; + tx_desc->word1 = FIELD_PREP(HBG_TX_DESC_W1_SEND_LEN_M, + buffer->skb->len); + tx_desc->word2 = buffer->skb_dma; + tx_desc->word3 = buffer->state_dma; +} + +netdev_tx_t hbg_net_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct hbg_ring *ring = netdev_get_tx_ring(netdev); + struct hbg_priv *priv = netdev_priv(netdev); + /* This smp_load_acquire() pairs with smp_store_release() in + * hbg_napi_tx_recycle() called in tx interrupt handle process. + */ + u32 ntc = smp_load_acquire(&ring->ntc); + struct hbg_buffer *buffer; + struct hbg_tx_desc tx_desc; + u32 ntu = ring->ntu; + + if (unlikely(!skb->len || + skb->len > hbg_spec_max_frame_len(priv, HBG_DIR_TX))) { + dev_kfree_skb_any(skb); + netdev->stats.tx_errors++; + return NETDEV_TX_OK; + } + + if (!netif_subqueue_maybe_stop(netdev, 0, + hbg_queue_left_num(ntc, ntu, ring), + HBG_TX_STOP_THRS, HBG_TX_START_THRS)) + return NETDEV_TX_BUSY; + + buffer = &ring->queue[ntu]; + buffer->skb = skb; + buffer->skb_len = skb->len; + if (unlikely(hbg_dma_map(buffer))) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + buffer->state = HBG_TX_STATE_START; + hbg_init_tx_desc(buffer, &tx_desc); + hbg_hw_set_tx_desc(priv, &tx_desc); + + /* This smp_store_release() pairs with smp_load_acquire() in + * hbg_napi_tx_recycle() called in tx interrupt handle process. + */ + smp_store_release(&ring->ntu, hbg_queue_next_prt(ntu, ring)); + dev_sw_netstats_tx_add(netdev, 1, skb->len); + return NETDEV_TX_OK; +} + +static void hbg_buffer_free_skb(struct hbg_buffer *buffer) +{ + if (unlikely(!buffer->skb)) + return; + + dev_kfree_skb_any(buffer->skb); + buffer->skb = NULL; +} + +static int hbg_buffer_alloc_skb(struct hbg_buffer *buffer) +{ + u32 len = hbg_spec_max_frame_len(buffer->priv, buffer->dir); + struct hbg_priv *priv = buffer->priv; + + buffer->skb = netdev_alloc_skb(priv->netdev, len); + if (unlikely(!buffer->skb)) + return -ENOMEM; + + buffer->skb_len = len; + memset(buffer->skb->data, 0, HBG_PACKET_HEAD_SIZE); + return 0; +} + +static void hbg_buffer_free(struct hbg_buffer *buffer) +{ + hbg_dma_unmap(buffer); + hbg_buffer_free_skb(buffer); +} + +static int hbg_napi_tx_recycle(struct napi_struct *napi, int budget) +{ + struct hbg_ring *ring = container_of(napi, struct hbg_ring, napi); + /* This smp_load_acquire() pairs with smp_store_release() in + * hbg_net_start_xmit() called in xmit process. + */ + u32 ntu = smp_load_acquire(&ring->ntu); + struct hbg_priv *priv = ring->priv; + struct hbg_buffer *buffer; + u32 ntc = ring->ntc; + int packet_done = 0; + + /* We need do cleanup even if budget is 0. + * Per NAPI documentation budget is for Rx. + * So We hardcode the amount of work Tx NAPI does to 128. + */ + budget = 128; + while (packet_done < budget) { + if (unlikely(hbg_queue_is_empty(ntc, ntu, ring))) + break; + + /* make sure HW write desc complete */ + dma_rmb(); + + buffer = &ring->queue[ntc]; + if (buffer->state != HBG_TX_STATE_COMPLETE) + break; + + hbg_buffer_free(buffer); + ntc = hbg_queue_next_prt(ntc, ring); + packet_done++; + } + + /* This smp_store_release() pairs with smp_load_acquire() in + * hbg_net_start_xmit() called in xmit process. + */ + smp_store_release(&ring->ntc, ntc); + netif_wake_queue(priv->netdev); + + if (likely(packet_done < budget && + napi_complete_done(napi, packet_done))) + hbg_hw_irq_enable(priv, HBG_INT_MSK_TX_B, true); + + return packet_done; +} + +static int hbg_rx_fill_one_buffer(struct hbg_priv *priv) +{ + struct hbg_ring *ring = &priv->rx_ring; + struct hbg_buffer *buffer; + int ret; + + if (hbg_queue_is_full(ring->ntc, ring->ntu, ring)) + return 0; + + buffer = &ring->queue[ring->ntu]; + ret = hbg_buffer_alloc_skb(buffer); + if (unlikely(ret)) + return ret; + + ret = hbg_dma_map(buffer); + if (unlikely(ret)) { + hbg_buffer_free_skb(buffer); + return ret; + } + + hbg_hw_fill_buffer(priv, buffer->skb_dma); + hbg_queue_move_next(ntu, ring); + return 0; +} + +static bool hbg_sync_data_from_hw(struct hbg_priv *priv, + struct hbg_buffer *buffer) +{ + struct hbg_rx_desc *rx_desc; + + /* make sure HW write desc complete */ + dma_rmb(); + + dma_sync_single_for_cpu(&priv->pdev->dev, buffer->skb_dma, + buffer->skb_len, DMA_FROM_DEVICE); + + rx_desc = (struct hbg_rx_desc *)buffer->skb->data; + return FIELD_GET(HBG_RX_DESC_W2_PKT_LEN_M, rx_desc->word2) != 0; +} + +static int hbg_napi_rx_poll(struct napi_struct *napi, int budget) +{ + struct hbg_ring *ring = container_of(napi, struct hbg_ring, napi); + struct hbg_priv *priv = ring->priv; + struct hbg_rx_desc *rx_desc; + struct hbg_buffer *buffer; + u32 packet_done = 0; + u32 pkt_len; + + while (packet_done < budget) { + if (unlikely(hbg_queue_is_empty(ring->ntc, ring->ntu, ring))) + break; + + buffer = &ring->queue[ring->ntc]; + if (unlikely(!buffer->skb)) + goto next_buffer; + + if (unlikely(!hbg_sync_data_from_hw(priv, buffer))) + break; + rx_desc = (struct hbg_rx_desc *)buffer->skb->data; + pkt_len = FIELD_GET(HBG_RX_DESC_W2_PKT_LEN_M, rx_desc->word2); + + hbg_dma_unmap(buffer); + + skb_reserve(buffer->skb, HBG_PACKET_HEAD_SIZE + NET_IP_ALIGN); + skb_put(buffer->skb, pkt_len); + buffer->skb->protocol = eth_type_trans(buffer->skb, + priv->netdev); + + dev_sw_netstats_rx_add(priv->netdev, pkt_len); + napi_gro_receive(napi, buffer->skb); + buffer->skb = NULL; + +next_buffer: + hbg_rx_fill_one_buffer(priv); + hbg_queue_move_next(ntc, ring); + packet_done++; + } + + if (likely(packet_done < budget && + napi_complete_done(napi, packet_done))) + hbg_hw_irq_enable(priv, HBG_INT_MSK_RX_B, true); + + return packet_done; +} + +static void hbg_ring_uninit(struct hbg_ring *ring) +{ + struct hbg_buffer *buffer; + u32 i; + + if (!ring->queue) + return; + + napi_disable(&ring->napi); + netif_napi_del(&ring->napi); + + for (i = 0; i < ring->len; i++) { + buffer = &ring->queue[i]; + hbg_buffer_free(buffer); + buffer->ring = NULL; + buffer->priv = NULL; + } + + dma_free_coherent(&ring->priv->pdev->dev, + ring->len * sizeof(*ring->queue), + ring->queue, ring->queue_dma); + ring->queue = NULL; + ring->queue_dma = 0; + ring->len = 0; + ring->priv = NULL; +} + +static int hbg_ring_init(struct hbg_priv *priv, struct hbg_ring *ring, + int (*napi_poll)(struct napi_struct *, int), + enum hbg_dir dir) +{ + struct hbg_buffer *buffer; + u32 i, len; + + len = hbg_get_spec_fifo_max_num(priv, dir) + 1; + ring->queue = dma_alloc_coherent(&priv->pdev->dev, + len * sizeof(*ring->queue), + &ring->queue_dma, GFP_KERNEL); + if (!ring->queue) + return -ENOMEM; + + for (i = 0; i < len; i++) { + buffer = &ring->queue[i]; + buffer->skb_len = 0; + buffer->dir = dir; + buffer->ring = ring; + buffer->priv = priv; + buffer->state_dma = ring->queue_dma + (i * sizeof(*buffer)); + } + + ring->dir = dir; + ring->priv = priv; + ring->ntc = 0; + ring->ntu = 0; + ring->len = len; + + if (dir == HBG_DIR_TX) + netif_napi_add_tx(priv->netdev, &ring->napi, napi_poll); + else + netif_napi_add(priv->netdev, &ring->napi, napi_poll); + + napi_enable(&ring->napi); + return 0; +} + +static int hbg_tx_ring_init(struct hbg_priv *priv) +{ + struct hbg_ring *tx_ring = &priv->tx_ring; + + if (!tx_ring->tout_log_buf) + tx_ring->tout_log_buf = devm_kmalloc(&priv->pdev->dev, + HBG_TX_TIMEOUT_BUF_LEN, + GFP_KERNEL); + + if (!tx_ring->tout_log_buf) + return -ENOMEM; + + return hbg_ring_init(priv, tx_ring, hbg_napi_tx_recycle, HBG_DIR_TX); +} + +static int hbg_rx_ring_init(struct hbg_priv *priv) +{ + int ret; + u32 i; + + ret = hbg_ring_init(priv, &priv->rx_ring, hbg_napi_rx_poll, HBG_DIR_RX); + if (ret) + return ret; + + for (i = 0; i < priv->rx_ring.len - 1; i++) { + ret = hbg_rx_fill_one_buffer(priv); + if (ret) { + hbg_ring_uninit(&priv->rx_ring); + return ret; + } + } + + return 0; +} + +int hbg_txrx_init(struct hbg_priv *priv) +{ + int ret; + + ret = hbg_tx_ring_init(priv); + if (ret) { + dev_err(&priv->pdev->dev, + "failed to init tx ring, ret = %d\n", ret); + return ret; + } + + ret = hbg_rx_ring_init(priv); + if (ret) { + dev_err(&priv->pdev->dev, + "failed to init rx ring, ret = %d\n", ret); + hbg_ring_uninit(&priv->tx_ring); + } + + return ret; +} + +void hbg_txrx_uninit(struct hbg_priv *priv) +{ + hbg_ring_uninit(&priv->tx_ring); + hbg_ring_uninit(&priv->rx_ring); +} diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h new file mode 100644 index 000000000000..2883a5899ae2 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2024 Hisilicon Limited. */ + +#ifndef __HBG_TXRX_H +#define __HBG_TXRX_H + +#include <linux/etherdevice.h> +#include "hbg_hw.h" + +static inline u32 hbg_spec_max_frame_len(struct hbg_priv *priv, + enum hbg_dir dir) +{ + return (dir == HBG_DIR_TX) ? priv->dev_specs.max_frame_len : + priv->dev_specs.rx_buf_size; +} + +static inline u32 hbg_get_spec_fifo_max_num(struct hbg_priv *priv, + enum hbg_dir dir) +{ + return (dir == HBG_DIR_TX) ? priv->dev_specs.tx_fifo_num : + priv->dev_specs.rx_fifo_num; +} + +static inline bool hbg_fifo_is_full(struct hbg_priv *priv, enum hbg_dir dir) +{ + return hbg_hw_get_fifo_used_num(priv, dir) >= + hbg_get_spec_fifo_max_num(priv, dir); +} + +static inline u32 hbg_get_queue_used_num(struct hbg_ring *ring) +{ + return (ring->ntu + ring->len - ring->ntc) % ring->len; +} + +netdev_tx_t hbg_net_start_xmit(struct sk_buff *skb, struct net_device *netdev); +int hbg_txrx_init(struct hbg_priv *priv); +void hbg_txrx_uninit(struct hbg_priv *priv); + +#endif diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index beb815e5289b..a376d4bdf281 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -1047,7 +1047,7 @@ MODULE_DEVICE_TABLE(of, hip04_mac_match); static struct platform_driver hip04_mac_driver = { .probe = hip04_mac_probe, - .remove_new = hip04_remove, + .remove = hip04_remove, .driver = { .name = DRV_NAME, .of_match_table = hip04_mac_match, diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index 2406263c9dd3..d244a40df430 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -959,7 +959,7 @@ static struct platform_driver hisi_femac_driver = { .of_match_table = hisi_femac_match, }, .probe = hisi_femac_drv_probe, - .remove_new = hisi_femac_drv_remove, + .remove = hisi_femac_drv_remove, #ifdef CONFIG_PM .suspend = hisi_femac_drv_suspend, .resume = hisi_femac_drv_resume, diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index 1a972b093a42..e3e7f2270560 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1312,7 +1312,7 @@ static struct platform_driver hix5hd2_dev_driver = { .of_match_table = hix5hd2_of_match, }, .probe = hix5hd2_dev_probe, - .remove_new = hix5hd2_dev_remove, + .remove = hix5hd2_dev_remove, }; module_platform_driver(hix5hd2_dev_driver); diff --git a/drivers/net/ethernet/hisilicon/hns/hnae.h b/drivers/net/ethernet/hisilicon/hns/hnae.h index d72657444ef3..2ae34d01fd36 100644 --- a/drivers/net/ethernet/hisilicon/hns/hnae.h +++ b/drivers/net/ethernet/hisilicon/hns/hnae.h @@ -512,7 +512,7 @@ struct hnae_ae_ops { struct net_device_stats *net_stats); void (*get_stats)(struct hnae_handle *handle, u64 *data); void (*get_strings)(struct hnae_handle *handle, - u32 stringset, u8 *data); + u32 stringset, u8 **data); int (*get_sset_count)(struct hnae_handle *handle, int stringset); void (*update_led_status)(struct hnae_handle *handle); int (*set_led_id)(struct hnae_handle *handle, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index bc3e406f0139..8ce910f8d0cc 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -730,15 +730,14 @@ static void hns_ae_get_stats(struct hnae_handle *handle, u64 *data) hns_dsaf_get_stats(vf_cb->dsaf_dev, p, vf_cb->port_index); } -static void hns_ae_get_strings(struct hnae_handle *handle, - u32 stringset, u8 *data) +static void hns_ae_get_strings(struct hnae_handle *handle, u32 stringset, + u8 **data) { int port; int idx; struct hns_mac_cb *mac_cb; struct hns_ppe_cb *ppe_cb; struct dsaf_device *dsaf_dev = hns_ae_get_dsaf_dev(handle->dev); - u8 *p = data; struct hnae_vf_cb *vf_cb; assert(handle); @@ -748,19 +747,14 @@ static void hns_ae_get_strings(struct hnae_handle *handle, mac_cb = hns_get_mac_cb(handle); ppe_cb = hns_get_ppe_cb(handle); - for (idx = 0; idx < handle->q_num; idx++) { - hns_rcb_get_strings(stringset, p, idx); - p += ETH_GSTRING_LEN * hns_rcb_get_ring_sset_count(stringset); - } - - hns_ppe_get_strings(ppe_cb, stringset, p); - p += ETH_GSTRING_LEN * hns_ppe_get_sset_count(stringset); + for (idx = 0; idx < handle->q_num; idx++) + hns_rcb_get_strings(stringset, data, idx); - hns_mac_get_strings(mac_cb, stringset, p); - p += ETH_GSTRING_LEN * hns_mac_get_sset_count(mac_cb, stringset); + hns_ppe_get_strings(ppe_cb, stringset, data); + hns_mac_get_strings(mac_cb, stringset, data); if (mac_cb->mac_type == HNAE_PORT_SERVICE) - hns_dsaf_get_strings(stringset, p, port, dsaf_dev); + hns_dsaf_get_strings(stringset, data, port, dsaf_dev); } static int hns_ae_get_sset_count(struct hnae_handle *handle, int stringset) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index bdb7afaabdd0..400933ca1a29 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -669,16 +669,15 @@ static void hns_gmac_get_stats(void *mac_drv, u64 *data) } } -static void hns_gmac_get_strings(u32 stringset, u8 *data) +static void hns_gmac_get_strings(u32 stringset, u8 **data) { - u8 *buff = data; u32 i; if (stringset != ETH_SS_STATS) return; for (i = 0; i < ARRAY_SIZE(g_gmac_stats_string); i++) - ethtool_puts(&buff, g_gmac_stats_string[i].desc); + ethtool_puts(data, g_gmac_stats_string[i].desc); } static int hns_gmac_get_sset_count(int stringset) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 58baac7103b3..bc6b269be299 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -1090,28 +1090,24 @@ int hns_mac_init(struct dsaf_device *dsaf_dev) u32 port_id; int max_port_num = hns_mac_get_max_port_num(dsaf_dev); struct hns_mac_cb *mac_cb; - struct fwnode_handle *child; - device_for_each_child_node(dsaf_dev->dev, child) { + device_for_each_child_node_scoped(dsaf_dev->dev, child) { ret = fwnode_property_read_u32(child, "reg", &port_id); if (ret) { - fwnode_handle_put(child); dev_err(dsaf_dev->dev, "get reg fail, ret=%d!\n", ret); return ret; } if (port_id >= max_port_num) { - fwnode_handle_put(child); dev_err(dsaf_dev->dev, "reg(%u) out of range!\n", port_id); return -EINVAL; } mac_cb = devm_kzalloc(dsaf_dev->dev, sizeof(*mac_cb), GFP_KERNEL); - if (!mac_cb) { - fwnode_handle_put(child); + if (!mac_cb) return -ENOMEM; - } + mac_cb->fw_port = child; mac_cb->mac_id = (u8)port_id; dsaf_dev->mac_cb[port_id] = mac_cb; @@ -1194,8 +1190,7 @@ void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data) mac_ctrl_drv->get_ethtool_stats(mac_ctrl_drv, data); } -void hns_mac_get_strings(struct hns_mac_cb *mac_cb, - int stringset, u8 *data) +void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 **data) { struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h index edf0bcf76ac9..630f01cf7a71 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.h @@ -378,7 +378,7 @@ struct mac_driver { void (*get_regs)(void *mac_drv, void *data); int (*get_regs_count)(void); /* get strings name for ethtool statistic */ - void (*get_strings)(u32 stringset, u8 *data); + void (*get_strings)(u32 stringset, u8 **data); /* get the number of strings*/ int (*get_sset_count)(int stringset); @@ -445,7 +445,7 @@ int hns_mac_config_mac_loopback(struct hns_mac_cb *mac_cb, enum hnae_loop loop, int en); void hns_mac_update_stats(struct hns_mac_cb *mac_cb); void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data); -void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 *data); +void hns_mac_get_strings(struct hns_mac_cb *mac_cb, int stringset, u8 **data); int hns_mac_get_sset_count(struct hns_mac_cb *mac_cb, int stringset); void hns_mac_get_regs(struct hns_mac_cb *mac_cb, void *data); int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index 1b67da1f6fa8..851490346261 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -2590,55 +2590,34 @@ void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data) p[i] = 0xdddddddd; } -static char *hns_dsaf_get_node_stats_strings(char *data, int node, - struct dsaf_device *dsaf_dev) +static void hns_dsaf_get_node_stats_strings(u8 **data, int node, + struct dsaf_device *dsaf_dev) { - char *buff = data; - int i; bool is_ver1 = AE_IS_VER1(dsaf_dev->dsaf_ver); + int i; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_pad_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_manage_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pkt_id", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_rx_pause_frame", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_release_buf_num", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_sbm_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_crc_false_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_bp_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_lookup_rslt_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_local_rslt_fail_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_vlan_drop_pkts", node); - buff += ETH_GSTRING_LEN; - snprintf(buff, ETH_GSTRING_LEN, "innod%d_stp_drop_pkts", node); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "innod%d_pad_drop_pkts", node); + ethtool_sprintf(data, "innod%d_manage_pkts", node); + ethtool_sprintf(data, "innod%d_rx_pkts", node); + ethtool_sprintf(data, "innod%d_rx_pkt_id", node); + ethtool_sprintf(data, "innod%d_rx_pause_frame", node); + ethtool_sprintf(data, "innod%d_release_buf_num", node); + ethtool_sprintf(data, "innod%d_sbm_drop_pkts", node); + ethtool_sprintf(data, "innod%d_crc_false_pkts", node); + ethtool_sprintf(data, "innod%d_bp_drop_pkts", node); + ethtool_sprintf(data, "innod%d_lookup_rslt_drop_pkts", node); + ethtool_sprintf(data, "innod%d_local_rslt_fail_pkts", node); + ethtool_sprintf(data, "innod%d_vlan_drop_pkts", node); + ethtool_sprintf(data, "innod%d_stp_drop_pkts", node); if (node < DSAF_SERVICE_NW_NUM && !is_ver1) { for (i = 0; i < DSAF_PRIO_NR; i++) { - snprintf(buff + 0 * ETH_GSTRING_LEN * DSAF_PRIO_NR, - ETH_GSTRING_LEN, "inod%d_pfc_prio%d_pkts", - node, i); - snprintf(buff + 1 * ETH_GSTRING_LEN * DSAF_PRIO_NR, - ETH_GSTRING_LEN, "onod%d_pfc_prio%d_pkts", - node, i); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "inod%d_pfc_prio%d_pkts", node, + i); + ethtool_sprintf(data, "onod%d_pfc_prio%d_pkts", node, + i); } - buff += 1 * DSAF_PRIO_NR * ETH_GSTRING_LEN; } - snprintf(buff, ETH_GSTRING_LEN, "onnod%d_tx_pkts", node); - buff += ETH_GSTRING_LEN; - - return buff; + ethtool_sprintf(data, "onnod%d_tx_pkts", node); } static u64 *hns_dsaf_get_node_stats(struct dsaf_device *ddev, u64 *data, @@ -2720,21 +2699,20 @@ int hns_dsaf_get_sset_count(struct dsaf_device *dsaf_dev, int stringset) *@port:port index *@dsaf_dev: dsaf device */ -void hns_dsaf_get_strings(int stringset, u8 *data, int port, +void hns_dsaf_get_strings(int stringset, u8 **data, int port, struct dsaf_device *dsaf_dev) { - char *buff = (char *)data; int node = port; if (stringset != ETH_SS_STATS) return; /* for ge/xge node info */ - buff = hns_dsaf_get_node_stats_strings(buff, node, dsaf_dev); + hns_dsaf_get_node_stats_strings(data, node, dsaf_dev); /* for ppe node info */ node = port + DSAF_PPE_INODE_BASE; - (void)hns_dsaf_get_node_stats_strings(buff, node, dsaf_dev); + hns_dsaf_get_node_stats_strings(data, node, dsaf_dev); } /** @@ -3031,7 +3009,7 @@ MODULE_DEVICE_TABLE(of, g_dsaf_match); static struct platform_driver g_dsaf_driver = { .probe = hns_dsaf_probe, - .remove_new = hns_dsaf_remove, + .remove = hns_dsaf_remove, .driver = { .name = DSAF_DRV_NAME, .of_match_table = g_dsaf_match, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index 5526a10caac5..0eb03dff1a8b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -442,7 +442,7 @@ void hns_dsaf_update_stats(struct dsaf_device *dsaf_dev, u32 inode_num); int hns_dsaf_get_sset_count(struct dsaf_device *dsaf_dev, int stringset); void hns_dsaf_get_stats(struct dsaf_device *ddev, u64 *data, int port); -void hns_dsaf_get_strings(int stringset, u8 *data, int port, +void hns_dsaf_get_strings(int stringset, u8 **data, int port, struct dsaf_device *dsaf_dev); void hns_dsaf_get_regs(struct dsaf_device *ddev, u32 port, void *data); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c index a08d1f0a5a16..5013beb4d282 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c @@ -457,24 +457,23 @@ int hns_ppe_get_regs_count(void) * @stringset: string set type * @data: output string */ -void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data) +void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 **data) { int index = ppe_cb->index; - u8 *buff = data; - - ethtool_sprintf(&buff, "ppe%d_rx_sw_pkt", index); - ethtool_sprintf(&buff, "ppe%d_rx_pkt_ok", index); - ethtool_sprintf(&buff, "ppe%d_rx_drop_pkt_no_bd", index); - ethtool_sprintf(&buff, "ppe%d_rx_alloc_buf_fail", index); - ethtool_sprintf(&buff, "ppe%d_rx_alloc_buf_wait", index); - ethtool_sprintf(&buff, "ppe%d_rx_pkt_drop_no_buf", index); - ethtool_sprintf(&buff, "ppe%d_rx_pkt_err_fifo_full", index); - - ethtool_sprintf(&buff, "ppe%d_tx_bd", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt_ok", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt_err_fifo_empty", index); - ethtool_sprintf(&buff, "ppe%d_tx_pkt_err_csum_fail", index); + + ethtool_sprintf(data, "ppe%d_rx_sw_pkt", index); + ethtool_sprintf(data, "ppe%d_rx_pkt_ok", index); + ethtool_sprintf(data, "ppe%d_rx_drop_pkt_no_bd", index); + ethtool_sprintf(data, "ppe%d_rx_alloc_buf_fail", index); + ethtool_sprintf(data, "ppe%d_rx_alloc_buf_wait", index); + ethtool_sprintf(data, "ppe%d_rx_pkt_drop_no_buf", index); + ethtool_sprintf(data, "ppe%d_rx_pkt_err_fifo_full", index); + + ethtool_sprintf(data, "ppe%d_tx_bd", index); + ethtool_sprintf(data, "ppe%d_tx_pkt", index); + ethtool_sprintf(data, "ppe%d_tx_pkt_ok", index); + ethtool_sprintf(data, "ppe%d_tx_pkt_err_fifo_empty", index); + ethtool_sprintf(data, "ppe%d_tx_pkt_err_csum_fail", index); } void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h index 7e00231c1acf..602c8e971fe4 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.h @@ -109,7 +109,7 @@ int hns_ppe_get_sset_count(int stringset); int hns_ppe_get_regs_count(void); void hns_ppe_get_regs(struct hns_ppe_cb *ppe_cb, void *data); -void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 *data); +void hns_ppe_get_strings(struct hns_ppe_cb *ppe_cb, int stringset, u8 **data); void hns_ppe_get_stats(struct hns_ppe_cb *ppe_cb, u64 *data); void hns_ppe_set_tso_enable(struct hns_ppe_cb *ppe_cb, u32 value); void hns_ppe_set_rss_key(struct hns_ppe_cb *ppe_cb, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index 93344563a259..46af467aa596 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -923,44 +923,42 @@ int hns_rcb_get_ring_regs_count(void) *@data:strings name value *@index:queue index */ -void hns_rcb_get_strings(int stringset, u8 *data, int index) +void hns_rcb_get_strings(int stringset, u8 **data, int index) { - u8 *buff = data; - if (stringset != ETH_SS_STATS) return; - ethtool_sprintf(&buff, "tx_ring%d_rcb_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_ppe_tx_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_ppe_drop_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_fbd_num", index); - - ethtool_sprintf(&buff, "tx_ring%d_pkt_num", index); - ethtool_sprintf(&buff, "tx_ring%d_bytes", index); - ethtool_sprintf(&buff, "tx_ring%d_err_cnt", index); - ethtool_sprintf(&buff, "tx_ring%d_io_err", index); - ethtool_sprintf(&buff, "tx_ring%d_sw_err", index); - ethtool_sprintf(&buff, "tx_ring%d_seg_pkt", index); - ethtool_sprintf(&buff, "tx_ring%d_restart_queue", index); - ethtool_sprintf(&buff, "tx_ring%d_tx_busy", index); - - ethtool_sprintf(&buff, "rx_ring%d_rcb_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_ppe_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_ppe_drop_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_fbd_num", index); - - ethtool_sprintf(&buff, "rx_ring%d_pkt_num", index); - ethtool_sprintf(&buff, "rx_ring%d_bytes", index); - ethtool_sprintf(&buff, "rx_ring%d_err_cnt", index); - ethtool_sprintf(&buff, "rx_ring%d_io_err", index); - ethtool_sprintf(&buff, "rx_ring%d_sw_err", index); - ethtool_sprintf(&buff, "rx_ring%d_seg_pkt", index); - ethtool_sprintf(&buff, "rx_ring%d_reuse_pg", index); - ethtool_sprintf(&buff, "rx_ring%d_len_err", index); - ethtool_sprintf(&buff, "rx_ring%d_non_vld_desc_err", index); - ethtool_sprintf(&buff, "rx_ring%d_bd_num_err", index); - ethtool_sprintf(&buff, "rx_ring%d_l2_err", index); - ethtool_sprintf(&buff, "rx_ring%d_l3l4csum_err", index); + ethtool_sprintf(data, "tx_ring%d_rcb_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_ppe_tx_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_ppe_drop_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_fbd_num", index); + + ethtool_sprintf(data, "tx_ring%d_pkt_num", index); + ethtool_sprintf(data, "tx_ring%d_bytes", index); + ethtool_sprintf(data, "tx_ring%d_err_cnt", index); + ethtool_sprintf(data, "tx_ring%d_io_err", index); + ethtool_sprintf(data, "tx_ring%d_sw_err", index); + ethtool_sprintf(data, "tx_ring%d_seg_pkt", index); + ethtool_sprintf(data, "tx_ring%d_restart_queue", index); + ethtool_sprintf(data, "tx_ring%d_tx_busy", index); + + ethtool_sprintf(data, "rx_ring%d_rcb_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_ppe_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_ppe_drop_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_fbd_num", index); + + ethtool_sprintf(data, "rx_ring%d_pkt_num", index); + ethtool_sprintf(data, "rx_ring%d_bytes", index); + ethtool_sprintf(data, "rx_ring%d_err_cnt", index); + ethtool_sprintf(data, "rx_ring%d_io_err", index); + ethtool_sprintf(data, "rx_ring%d_sw_err", index); + ethtool_sprintf(data, "rx_ring%d_seg_pkt", index); + ethtool_sprintf(data, "rx_ring%d_reuse_pg", index); + ethtool_sprintf(data, "rx_ring%d_len_err", index); + ethtool_sprintf(data, "rx_ring%d_non_vld_desc_err", index); + ethtool_sprintf(data, "rx_ring%d_bd_num_err", index); + ethtool_sprintf(data, "rx_ring%d_l2_err", index); + ethtool_sprintf(data, "rx_ring%d_l3l4csum_err", index); } void hns_rcb_get_common_regs(struct rcb_common_cb *rcb_com, void *data) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h index c1e9b6997853..0f4cc184ef39 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.h @@ -157,7 +157,7 @@ int hns_rcb_get_ring_regs_count(void); void hns_rcb_get_ring_regs(struct hnae_queue *queue, void *data); -void hns_rcb_get_strings(int stringset, u8 *data, int index); +void hns_rcb_get_strings(int stringset, u8 **data, int index); void hns_rcb_set_rx_ring_bs(struct hnae_queue *q, u32 buf_size); void hns_rcb_set_tx_ring_bs(struct hnae_queue *q, u32 buf_size); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c index c58833eb4830..dbc44c2c26c2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c @@ -743,16 +743,15 @@ static void hns_xgmac_get_stats(void *mac_drv, u64 *data) *@stringset: type of values in data *@data:data for value of string name */ -static void hns_xgmac_get_strings(u32 stringset, u8 *data) +static void hns_xgmac_get_strings(u32 stringset, u8 **data) { - u8 *buff = data; u32 i; if (stringset != ETH_SS_STATS) return; for (i = 0; i < ARRAY_SIZE(g_xgmac_stats_string); i++) - ethtool_puts(&buff, g_xgmac_stats_string[i].desc); + ethtool_puts(data, g_xgmac_stats_string[i].desc); } /** diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index fd32e15cadcb..42bb341fd80b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -2439,7 +2439,7 @@ static struct platform_driver hns_nic_dev_driver = { .acpi_match_table = ACPI_PTR(hns_enet_acpi_match), }, .probe = hns_nic_dev_probe, - .remove_new = hns_nic_dev_remove, + .remove = hns_nic_dev_remove, }; module_platform_driver(hns_nic_dev_driver); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index a5bb306b2cf1..6c458f037262 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -903,7 +903,6 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { struct hns_nic_priv *priv = netdev_priv(netdev); struct hnae_handle *h = priv->ae_handle; - u8 *buff = data; if (!h->dev->ops->get_strings) { netdev_err(netdev, "h->dev->ops->get_strings is null!\n"); @@ -912,43 +911,43 @@ static void hns_get_strings(struct net_device *netdev, u32 stringset, u8 *data) if (stringset == ETH_SS_TEST) { if (priv->ae_handle->phy_if != PHY_INTERFACE_MODE_XGMII) - ethtool_puts(&buff, + ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_MAC]); - ethtool_puts(&buff, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]); + ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_SERDES]); if ((netdev->phydev) && (!netdev->phydev->is_c45)) - ethtool_puts(&buff, + ethtool_puts(&data, hns_nic_test_strs[MAC_INTERNALLOOP_PHY]); } else { - ethtool_puts(&buff, "rx_packets"); - ethtool_puts(&buff, "tx_packets"); - ethtool_puts(&buff, "rx_bytes"); - ethtool_puts(&buff, "tx_bytes"); - ethtool_puts(&buff, "rx_errors"); - ethtool_puts(&buff, "tx_errors"); - ethtool_puts(&buff, "rx_dropped"); - ethtool_puts(&buff, "tx_dropped"); - ethtool_puts(&buff, "multicast"); - ethtool_puts(&buff, "collisions"); - ethtool_puts(&buff, "rx_over_errors"); - ethtool_puts(&buff, "rx_crc_errors"); - ethtool_puts(&buff, "rx_frame_errors"); - ethtool_puts(&buff, "rx_fifo_errors"); - ethtool_puts(&buff, "rx_missed_errors"); - ethtool_puts(&buff, "tx_aborted_errors"); - ethtool_puts(&buff, "tx_carrier_errors"); - ethtool_puts(&buff, "tx_fifo_errors"); - ethtool_puts(&buff, "tx_heartbeat_errors"); - ethtool_puts(&buff, "rx_length_errors"); - ethtool_puts(&buff, "tx_window_errors"); - ethtool_puts(&buff, "rx_compressed"); - ethtool_puts(&buff, "tx_compressed"); - ethtool_puts(&buff, "netdev_rx_dropped"); - ethtool_puts(&buff, "netdev_tx_dropped"); - - ethtool_puts(&buff, "netdev_tx_timeout"); - - h->dev->ops->get_strings(h, stringset, buff); + ethtool_puts(&data, "rx_packets"); + ethtool_puts(&data, "tx_packets"); + ethtool_puts(&data, "rx_bytes"); + ethtool_puts(&data, "tx_bytes"); + ethtool_puts(&data, "rx_errors"); + ethtool_puts(&data, "tx_errors"); + ethtool_puts(&data, "rx_dropped"); + ethtool_puts(&data, "tx_dropped"); + ethtool_puts(&data, "multicast"); + ethtool_puts(&data, "collisions"); + ethtool_puts(&data, "rx_over_errors"); + ethtool_puts(&data, "rx_crc_errors"); + ethtool_puts(&data, "rx_frame_errors"); + ethtool_puts(&data, "rx_fifo_errors"); + ethtool_puts(&data, "rx_missed_errors"); + ethtool_puts(&data, "tx_aborted_errors"); + ethtool_puts(&data, "tx_carrier_errors"); + ethtool_puts(&data, "tx_fifo_errors"); + ethtool_puts(&data, "tx_heartbeat_errors"); + ethtool_puts(&data, "rx_length_errors"); + ethtool_puts(&data, "tx_window_errors"); + ethtool_puts(&data, "rx_compressed"); + ethtool_puts(&data, "tx_compressed"); + ethtool_puts(&data, "netdev_rx_dropped"); + ethtool_puts(&data, "netdev_tx_dropped"); + + ethtool_puts(&data, "netdev_tx_timeout"); + + h->dev->ops->get_strings(h, stringset, &data); } } @@ -970,7 +969,7 @@ static int hns_get_sset_count(struct net_device *netdev, int stringset) return -EOPNOTSUPP; } if (stringset == ETH_SS_TEST) { - u32 cnt = (sizeof(hns_nic_test_strs) / ETH_GSTRING_LEN); + u32 cnt = ARRAY_SIZE(hns_nic_test_strs); if (priv->ae_handle->phy_if == PHY_INTERFACE_MODE_XGMII) cnt--; diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 27dbe367f3d3..710a8f9f2248 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -677,7 +677,7 @@ struct hnae3_ae_ops { void (*get_mac_stats)(struct hnae3_handle *handle, struct hns3_mac_stats *mac_stats); void (*get_strings)(struct hnae3_handle *handle, - u32 stringset, u8 *data); + u32 stringset, u8 **data); int (*get_sset_count)(struct hnae3_handle *handle, int stringset); void (*get_regs)(struct hnae3_handle *handle, u32 *version, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c index 2b31188ff555..f9a3d6fc4416 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.c @@ -36,27 +36,22 @@ int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle) } EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_sset_count); -u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data) +void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; - u8 *buff = data; u16 i; for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_comm_tqp *tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "txq%u_pktnum_rcd", tqp->index); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "txq%u_pktnum_rcd", tqp->index); } for (i = 0; i < kinfo->num_tqps; i++) { struct hclge_comm_tqp *tqp = container_of(kinfo->tqp[i], struct hclge_comm_tqp, q); - snprintf(buff, ETH_GSTRING_LEN, "rxq%u_pktnum_rcd", tqp->index); - buff += ETH_GSTRING_LEN; + ethtool_sprintf(data, "rxq%u_pktnum_rcd", tqp->index); } - - return buff; } EXPORT_SYMBOL_GPL(hclge_comm_tqps_get_strings); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h index a46350162ee8..b9ff424c0bc2 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_common/hclge_comm_tqp_stats.h @@ -32,7 +32,7 @@ struct hclge_comm_tqp { u64 *hclge_comm_tqps_get_stats(struct hnae3_handle *handle, u64 *data); int hclge_comm_tqps_get_sset_count(struct hnae3_handle *handle); -u8 *hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 *data); +void hclge_comm_tqps_get_strings(struct hnae3_handle *handle, u8 **data); void hclge_comm_reset_tqp_stats(struct hnae3_handle *handle); int hclge_comm_tqps_update_stats(struct hnae3_handle *handle, struct hclge_comm_hw *hw); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 4cbc4d069a1f..43377a7b2426 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4448,7 +4448,7 @@ static void hns3_update_rx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) dim_update_sample(tqp_vector->event_cnt, rx_group->total_packets, rx_group->total_bytes, &sample); - net_dim(&rx_group->dim, sample); + net_dim(&rx_group->dim, &sample); } static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) @@ -4461,7 +4461,7 @@ static void hns3_update_tx_int_coalesce(struct hns3_enet_tqp_vector *tqp_vector) dim_update_sample(tqp_vector->event_cnt, tx_group->total_packets, tx_group->total_bytes, &sample); - net_dim(&tx_group->dim, sample); + net_dim(&tx_group->dim, &sample); } static int hns3_nic_common_poll(struct napi_struct *napi, int budget) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index b1e988347347..b771a2daba43 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -509,54 +509,37 @@ static int hns3_get_sset_count(struct net_device *netdev, int stringset) } } -static void *hns3_update_strings(u8 *data, const struct hns3_stats *stats, - u32 stat_count, u32 num_tqps, const char *prefix) +static void hns3_update_strings(u8 **data, const struct hns3_stats *stats, + u32 stat_count, u32 num_tqps, + const char *prefix) { -#define MAX_PREFIX_SIZE (6 + 4) - u32 size_left; u32 i, j; - u32 n1; - for (i = 0; i < num_tqps; i++) { - for (j = 0; j < stat_count; j++) { - data[ETH_GSTRING_LEN - 1] = '\0'; - - /* first, prepend the prefix string */ - n1 = scnprintf(data, MAX_PREFIX_SIZE, "%s%u_", - prefix, i); - size_left = (ETH_GSTRING_LEN - 1) - n1; - - /* now, concatenate the stats string to it */ - strncat(data, stats[j].stats_string, size_left); - data += ETH_GSTRING_LEN; - } - } - - return data; + for (i = 0; i < num_tqps; i++) + for (j = 0; j < stat_count; j++) + ethtool_sprintf(data, "%s%u_%s", prefix, i, + stats[j].stats_string); } -static u8 *hns3_get_strings_tqps(struct hnae3_handle *handle, u8 *data) +static void hns3_get_strings_tqps(struct hnae3_handle *handle, u8 **data) { struct hnae3_knic_private_info *kinfo = &handle->kinfo; const char tx_prefix[] = "txq"; const char rx_prefix[] = "rxq"; /* get strings for Tx */ - data = hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT, - kinfo->num_tqps, tx_prefix); + hns3_update_strings(data, hns3_txq_stats, HNS3_TXQ_STATS_COUNT, + kinfo->num_tqps, tx_prefix); /* get strings for Rx */ - data = hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT, - kinfo->num_tqps, rx_prefix); - - return data; + hns3_update_strings(data, hns3_rxq_stats, HNS3_RXQ_STATS_COUNT, + kinfo->num_tqps, rx_prefix); } static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) { struct hnae3_handle *h = hns3_get_handle(netdev); const struct hnae3_ae_ops *ops = h->ae_algo->ops; - char *buff = (char *)data; int i; if (!ops->get_strings) @@ -564,18 +547,15 @@ static void hns3_get_strings(struct net_device *netdev, u32 stringset, u8 *data) switch (stringset) { case ETH_SS_STATS: - buff = hns3_get_strings_tqps(h, buff); - ops->get_strings(h, stringset, (u8 *)buff); + hns3_get_strings_tqps(h, &data); + ops->get_strings(h, stringset, &data); break; case ETH_SS_TEST: - ops->get_strings(h, stringset, data); + ops->get_strings(h, stringset, &data); break; case ETH_SS_PRIV_FLAGS: - for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) { - snprintf(buff, ETH_GSTRING_LEN, "%s", - hns3_priv_flags[i].name); - buff += ETH_GSTRING_LEN; - } + for (i = 0; i < HNS3_PRIV_FLAGS_LEN; i++) + ethtool_puts(&data, hns3_priv_flags[i].name); break; default: break; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index bd86efd92a5a..05942fa78b11 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -594,25 +594,21 @@ static u64 *hclge_comm_get_stats(struct hclge_dev *hdev, return buf; } -static u8 *hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset, - const struct hclge_comm_stats_str strs[], - int size, u8 *data) +static void hclge_comm_get_strings(struct hclge_dev *hdev, u32 stringset, + const struct hclge_comm_stats_str strs[], + int size, u8 **data) { - char *buff = (char *)data; u32 i; if (stringset != ETH_SS_STATS) - return buff; + return; for (i = 0; i < size; i++) { if (strs[i].stats_num > hdev->ae_dev->dev_specs.mac_stats_num) continue; - snprintf(buff, ETH_GSTRING_LEN, "%s", strs[i].desc); - buff = buff + ETH_GSTRING_LEN; + ethtool_puts(data, strs[i].desc); } - - return (u8 *)buff; } static void hclge_update_stats_for_all(struct hclge_dev *hdev) @@ -717,44 +713,38 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) } static void hclge_get_strings(struct hnae3_handle *handle, u32 stringset, - u8 *data) + u8 **data) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; - u8 *p = (char *)data; + const char *str; int size; if (stringset == ETH_SS_STATS) { size = ARRAY_SIZE(g_mac_stats_string); - p = hclge_comm_get_strings(hdev, stringset, g_mac_stats_string, - size, p); - p = hclge_comm_tqps_get_strings(handle, p); + hclge_comm_get_strings(hdev, stringset, g_mac_stats_string, + size, data); + hclge_comm_tqps_get_strings(handle, data); } else if (stringset == ETH_SS_TEST) { if (handle->flags & HNAE3_SUPPORT_EXTERNAL_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_EXTERNAL]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_APP_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_APP], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_APP]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_SERIAL_SERDES]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) { - memcpy(p, - hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_PARALLEL_SERDES]; + ethtool_puts(data, str); } if (handle->flags & HNAE3_SUPPORT_PHY_LOOPBACK) { - memcpy(p, hns3_nic_test_strs[HNAE3_LOOP_PHY], - ETH_GSTRING_LEN); - p += ETH_GSTRING_LEN; + str = hns3_nic_test_strs[HNAE3_LOOP_PHY]; + ethtool_puts(data, str); } } } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 094a7c7b5592..2f6ffb88e700 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -130,12 +130,10 @@ static int hclgevf_get_sset_count(struct hnae3_handle *handle, int strset) } static void hclgevf_get_strings(struct hnae3_handle *handle, u32 strset, - u8 *data) + u8 **data) { - u8 *p = (char *)data; - if (strset == ETH_SS_STATS) - p = hclge_comm_tqps_get_strings(handle, p); + hclge_comm_tqps_get_strings(handle, data); } static void hclgevf_get_stats(struct hnae3_handle *handle, u64 *data) diff --git a/drivers/net/ethernet/hisilicon/hns_mdio.c b/drivers/net/ethernet/hisilicon/hns_mdio.c index 8a047145f0c5..a1aa6c1f966e 100644 --- a/drivers/net/ethernet/hisilicon/hns_mdio.c +++ b/drivers/net/ethernet/hisilicon/hns_mdio.c @@ -636,7 +636,7 @@ MODULE_DEVICE_TABLE(acpi, hns_mdio_acpi_match); static struct platform_driver hns_mdio_driver = { .probe = hns_mdio_probe, - .remove_new = hns_mdio_remove, + .remove = hns_mdio_remove, .driver = { .name = MDIO_DRV_NAME, .of_match_table = hns_mdio_match, |