diff options
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h | 48 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c | 54 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c | 270 | ||||
-rw-r--r-- | drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.h | 39 |
8 files changed, 455 insertions, 3 deletions
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h index f60c2cc828fb..cceb674bd1c8 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h @@ -13,14 +13,61 @@ #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 + +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 { @@ -73,6 +120,7 @@ struct hbg_priv { unsigned long state; struct hbg_mac mac; struct hbg_vector vectors; + struct hbg_ring tx_ring; }; #endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c index 5258c5376987..05c71887b25a 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c @@ -73,6 +73,7 @@ static int hbg_hw_dev_specs_init(struct hbg_priv *priv) 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; return 0; } @@ -171,6 +172,23 @@ void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable) 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); + + 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_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex) { hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR, diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h index 0ce500e907b3..508e41cce41e 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h @@ -52,5 +52,7 @@ 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); #endif diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c index 66e047fb2d79..fed5502e51c8 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_irq.c @@ -13,6 +13,12 @@ static void hbg_irq_handle_err(struct hbg_priv *priv, "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); +} + #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) \ @@ -20,7 +26,7 @@ static void hbg_irq_handle_err(struct hbg_priv *priv, static struct hbg_irq_info hbg_irqs[] = { HBG_TXRX_IRQ_I(RX, NULL), - HBG_TXRX_IRQ_I(TX, NULL), + 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), diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c index 3f6f3b381c50..9bea5e21066f 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c @@ -9,6 +9,9 @@ #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) { @@ -24,6 +27,11 @@ static void hbg_all_irq_enable(struct hbg_priv *priv, bool 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); @@ -33,6 +41,26 @@ static int hbg_net_open(struct net_device *netdev) 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); @@ -41,8 +69,8 @@ static int hbg_net_stop(struct net_device *netdev) netif_stop_queue(netdev); hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE); hbg_all_irq_enable(priv, false); - - return 0; + hbg_txrx_uninit(priv); + return hbg_hw_txrx_clear(priv); } static int hbg_net_set_mac_address(struct net_device *netdev, void *addr) @@ -86,12 +114,33 @@ static int hbg_net_change_mtu(struct net_device *netdev, int 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) @@ -170,6 +219,7 @@ static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 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); diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h index fbc17ca5564f..0b7926a2a4fa 100644 --- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h @@ -80,6 +80,12 @@ #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_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_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) @@ -108,4 +114,17 @@ enum hbg_port_mode { 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) + #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..6f828d7e77b3 --- /dev/null +++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_txrx.c @@ -0,0 +1,270 @@ +// 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_next_prt(p, ring) (((p) + 1) % (ring)->len) + +#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 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 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; + + netif_napi_add_tx(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); +} + +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; +} + +void hbg_txrx_uninit(struct hbg_priv *priv) +{ + hbg_ring_uninit(&priv->tx_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 |