18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for Marvell PPv2 network controller for Armada 375 SoC.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Marcin Wojtas <mw@semihalf.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/acpi.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
168c2ecf20Sopenharmony_ci#include <linux/inetdevice.h>
178c2ecf20Sopenharmony_ci#include <linux/mbus.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
208c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
218c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
228c2ecf20Sopenharmony_ci#include <linux/of.h>
238c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
248c2ecf20Sopenharmony_ci#include <linux/of_mdio.h>
258c2ecf20Sopenharmony_ci#include <linux/of_net.h>
268c2ecf20Sopenharmony_ci#include <linux/of_address.h>
278c2ecf20Sopenharmony_ci#include <linux/of_device.h>
288c2ecf20Sopenharmony_ci#include <linux/phy.h>
298c2ecf20Sopenharmony_ci#include <linux/phylink.h>
308c2ecf20Sopenharmony_ci#include <linux/phy/phy.h>
318c2ecf20Sopenharmony_ci#include <linux/ptp_classify.h>
328c2ecf20Sopenharmony_ci#include <linux/clk.h>
338c2ecf20Sopenharmony_ci#include <linux/hrtimer.h>
348c2ecf20Sopenharmony_ci#include <linux/ktime.h>
358c2ecf20Sopenharmony_ci#include <linux/regmap.h>
368c2ecf20Sopenharmony_ci#include <uapi/linux/ppp_defs.h>
378c2ecf20Sopenharmony_ci#include <net/ip.h>
388c2ecf20Sopenharmony_ci#include <net/ipv6.h>
398c2ecf20Sopenharmony_ci#include <net/tso.h>
408c2ecf20Sopenharmony_ci#include <linux/bpf_trace.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include "mvpp2.h"
438c2ecf20Sopenharmony_ci#include "mvpp2_prs.h"
448c2ecf20Sopenharmony_ci#include "mvpp2_cls.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cienum mvpp2_bm_pool_log_num {
478c2ecf20Sopenharmony_ci	MVPP2_BM_SHORT,
488c2ecf20Sopenharmony_ci	MVPP2_BM_LONG,
498c2ecf20Sopenharmony_ci	MVPP2_BM_JUMBO,
508c2ecf20Sopenharmony_ci	MVPP2_BM_POOLS_NUM
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic struct {
548c2ecf20Sopenharmony_ci	int pkt_size;
558c2ecf20Sopenharmony_ci	int buf_num;
568c2ecf20Sopenharmony_ci} mvpp2_pools[MVPP2_BM_POOLS_NUM];
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* The prototype is added here to be used in start_dev when using ACPI. This
598c2ecf20Sopenharmony_ci * will be removed once phylink is used for all modes (dt+ACPI).
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_cistatic void mvpp2_acpi_start(struct mvpp2_port *port);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Queue modes */
648c2ecf20Sopenharmony_ci#define MVPP2_QDIST_SINGLE_MODE	0
658c2ecf20Sopenharmony_ci#define MVPP2_QDIST_MULTI_MODE	1
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int queue_mode = MVPP2_QDIST_MULTI_MODE;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cimodule_param(queue_mode, int, 0444);
708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(queue_mode, "Set queue_mode (single=0, multi=1)");
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* Utility/helper methods */
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_civoid mvpp2_write(struct mvpp2 *priv, u32 offset, u32 data)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	writel(data, priv->swth_base[0] + offset);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ciu32 mvpp2_read(struct mvpp2 *priv, u32 offset)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	return readl(priv->swth_base[0] + offset);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic u32 mvpp2_read_relaxed(struct mvpp2 *priv, u32 offset)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	return readl_relaxed(priv->swth_base[0] + offset);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic inline u32 mvpp2_cpu_to_thread(struct mvpp2 *priv, int cpu)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	return cpu % priv->nthreads;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic struct page_pool *
958c2ecf20Sopenharmony_cimvpp2_create_page_pool(struct device *dev, int num, int len,
968c2ecf20Sopenharmony_ci		       enum dma_data_direction dma_dir)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct page_pool_params pp_params = {
998c2ecf20Sopenharmony_ci		/* internal DMA mapping in page_pool */
1008c2ecf20Sopenharmony_ci		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
1018c2ecf20Sopenharmony_ci		.pool_size = num,
1028c2ecf20Sopenharmony_ci		.nid = NUMA_NO_NODE,
1038c2ecf20Sopenharmony_ci		.dev = dev,
1048c2ecf20Sopenharmony_ci		.dma_dir = dma_dir,
1058c2ecf20Sopenharmony_ci		.offset = MVPP2_SKB_HEADROOM,
1068c2ecf20Sopenharmony_ci		.max_len = len,
1078c2ecf20Sopenharmony_ci	};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return page_pool_create(&pp_params);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/* These accessors should be used to access:
1138c2ecf20Sopenharmony_ci *
1148c2ecf20Sopenharmony_ci * - per-thread registers, where each thread has its own copy of the
1158c2ecf20Sopenharmony_ci *   register.
1168c2ecf20Sopenharmony_ci *
1178c2ecf20Sopenharmony_ci *   MVPP2_BM_VIRT_ALLOC_REG
1188c2ecf20Sopenharmony_ci *   MVPP2_BM_ADDR_HIGH_ALLOC
1198c2ecf20Sopenharmony_ci *   MVPP22_BM_ADDR_HIGH_RLS_REG
1208c2ecf20Sopenharmony_ci *   MVPP2_BM_VIRT_RLS_REG
1218c2ecf20Sopenharmony_ci *   MVPP2_ISR_RX_TX_CAUSE_REG
1228c2ecf20Sopenharmony_ci *   MVPP2_ISR_RX_TX_MASK_REG
1238c2ecf20Sopenharmony_ci *   MVPP2_TXQ_NUM_REG
1248c2ecf20Sopenharmony_ci *   MVPP2_AGGR_TXQ_UPDATE_REG
1258c2ecf20Sopenharmony_ci *   MVPP2_TXQ_RSVD_REQ_REG
1268c2ecf20Sopenharmony_ci *   MVPP2_TXQ_RSVD_RSLT_REG
1278c2ecf20Sopenharmony_ci *   MVPP2_TXQ_SENT_REG
1288c2ecf20Sopenharmony_ci *   MVPP2_RXQ_NUM_REG
1298c2ecf20Sopenharmony_ci *
1308c2ecf20Sopenharmony_ci * - global registers that must be accessed through a specific thread
1318c2ecf20Sopenharmony_ci *   window, because they are related to an access to a per-thread
1328c2ecf20Sopenharmony_ci *   register
1338c2ecf20Sopenharmony_ci *
1348c2ecf20Sopenharmony_ci *   MVPP2_BM_PHY_ALLOC_REG    (related to MVPP2_BM_VIRT_ALLOC_REG)
1358c2ecf20Sopenharmony_ci *   MVPP2_BM_PHY_RLS_REG      (related to MVPP2_BM_VIRT_RLS_REG)
1368c2ecf20Sopenharmony_ci *   MVPP2_RXQ_THRESH_REG      (related to MVPP2_RXQ_NUM_REG)
1378c2ecf20Sopenharmony_ci *   MVPP2_RXQ_DESC_ADDR_REG   (related to MVPP2_RXQ_NUM_REG)
1388c2ecf20Sopenharmony_ci *   MVPP2_RXQ_DESC_SIZE_REG   (related to MVPP2_RXQ_NUM_REG)
1398c2ecf20Sopenharmony_ci *   MVPP2_RXQ_INDEX_REG       (related to MVPP2_RXQ_NUM_REG)
1408c2ecf20Sopenharmony_ci *   MVPP2_TXQ_PENDING_REG     (related to MVPP2_TXQ_NUM_REG)
1418c2ecf20Sopenharmony_ci *   MVPP2_TXQ_DESC_ADDR_REG   (related to MVPP2_TXQ_NUM_REG)
1428c2ecf20Sopenharmony_ci *   MVPP2_TXQ_DESC_SIZE_REG   (related to MVPP2_TXQ_NUM_REG)
1438c2ecf20Sopenharmony_ci *   MVPP2_TXQ_INDEX_REG       (related to MVPP2_TXQ_NUM_REG)
1448c2ecf20Sopenharmony_ci *   MVPP2_TXQ_PENDING_REG     (related to MVPP2_TXQ_NUM_REG)
1458c2ecf20Sopenharmony_ci *   MVPP2_TXQ_PREF_BUF_REG    (related to MVPP2_TXQ_NUM_REG)
1468c2ecf20Sopenharmony_ci *   MVPP2_TXQ_PREF_BUF_REG    (related to MVPP2_TXQ_NUM_REG)
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_cistatic void mvpp2_thread_write(struct mvpp2 *priv, unsigned int thread,
1498c2ecf20Sopenharmony_ci			       u32 offset, u32 data)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	writel(data, priv->swth_base[thread] + offset);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic u32 mvpp2_thread_read(struct mvpp2 *priv, unsigned int thread,
1558c2ecf20Sopenharmony_ci			     u32 offset)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	return readl(priv->swth_base[thread] + offset);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic void mvpp2_thread_write_relaxed(struct mvpp2 *priv, unsigned int thread,
1618c2ecf20Sopenharmony_ci				       u32 offset, u32 data)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	writel_relaxed(data, priv->swth_base[thread] + offset);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic u32 mvpp2_thread_read_relaxed(struct mvpp2 *priv, unsigned int thread,
1678c2ecf20Sopenharmony_ci				     u32 offset)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return readl_relaxed(priv->swth_base[thread] + offset);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic dma_addr_t mvpp2_txdesc_dma_addr_get(struct mvpp2_port *port,
1738c2ecf20Sopenharmony_ci					    struct mvpp2_tx_desc *tx_desc)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
1768c2ecf20Sopenharmony_ci		return le32_to_cpu(tx_desc->pp21.buf_dma_addr);
1778c2ecf20Sopenharmony_ci	else
1788c2ecf20Sopenharmony_ci		return le64_to_cpu(tx_desc->pp22.buf_dma_addr_ptp) &
1798c2ecf20Sopenharmony_ci		       MVPP2_DESC_DMA_MASK;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port,
1838c2ecf20Sopenharmony_ci				      struct mvpp2_tx_desc *tx_desc,
1848c2ecf20Sopenharmony_ci				      dma_addr_t dma_addr)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	dma_addr_t addr, offset;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	addr = dma_addr & ~MVPP2_TX_DESC_ALIGN;
1898c2ecf20Sopenharmony_ci	offset = dma_addr & MVPP2_TX_DESC_ALIGN;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21) {
1928c2ecf20Sopenharmony_ci		tx_desc->pp21.buf_dma_addr = cpu_to_le32(addr);
1938c2ecf20Sopenharmony_ci		tx_desc->pp21.packet_offset = offset;
1948c2ecf20Sopenharmony_ci	} else {
1958c2ecf20Sopenharmony_ci		__le64 val = cpu_to_le64(addr);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		tx_desc->pp22.buf_dma_addr_ptp &= ~cpu_to_le64(MVPP2_DESC_DMA_MASK);
1988c2ecf20Sopenharmony_ci		tx_desc->pp22.buf_dma_addr_ptp |= val;
1998c2ecf20Sopenharmony_ci		tx_desc->pp22.packet_offset = offset;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic size_t mvpp2_txdesc_size_get(struct mvpp2_port *port,
2048c2ecf20Sopenharmony_ci				    struct mvpp2_tx_desc *tx_desc)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2078c2ecf20Sopenharmony_ci		return le16_to_cpu(tx_desc->pp21.data_size);
2088c2ecf20Sopenharmony_ci	else
2098c2ecf20Sopenharmony_ci		return le16_to_cpu(tx_desc->pp22.data_size);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void mvpp2_txdesc_size_set(struct mvpp2_port *port,
2138c2ecf20Sopenharmony_ci				  struct mvpp2_tx_desc *tx_desc,
2148c2ecf20Sopenharmony_ci				  size_t size)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2178c2ecf20Sopenharmony_ci		tx_desc->pp21.data_size = cpu_to_le16(size);
2188c2ecf20Sopenharmony_ci	else
2198c2ecf20Sopenharmony_ci		tx_desc->pp22.data_size = cpu_to_le16(size);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic void mvpp2_txdesc_txq_set(struct mvpp2_port *port,
2238c2ecf20Sopenharmony_ci				 struct mvpp2_tx_desc *tx_desc,
2248c2ecf20Sopenharmony_ci				 unsigned int txq)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2278c2ecf20Sopenharmony_ci		tx_desc->pp21.phys_txq = txq;
2288c2ecf20Sopenharmony_ci	else
2298c2ecf20Sopenharmony_ci		tx_desc->pp22.phys_txq = txq;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic void mvpp2_txdesc_cmd_set(struct mvpp2_port *port,
2338c2ecf20Sopenharmony_ci				 struct mvpp2_tx_desc *tx_desc,
2348c2ecf20Sopenharmony_ci				 unsigned int command)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2378c2ecf20Sopenharmony_ci		tx_desc->pp21.command = cpu_to_le32(command);
2388c2ecf20Sopenharmony_ci	else
2398c2ecf20Sopenharmony_ci		tx_desc->pp22.command = cpu_to_le32(command);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic unsigned int mvpp2_txdesc_offset_get(struct mvpp2_port *port,
2438c2ecf20Sopenharmony_ci					    struct mvpp2_tx_desc *tx_desc)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2468c2ecf20Sopenharmony_ci		return tx_desc->pp21.packet_offset;
2478c2ecf20Sopenharmony_ci	else
2488c2ecf20Sopenharmony_ci		return tx_desc->pp22.packet_offset;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic dma_addr_t mvpp2_rxdesc_dma_addr_get(struct mvpp2_port *port,
2528c2ecf20Sopenharmony_ci					    struct mvpp2_rx_desc *rx_desc)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2558c2ecf20Sopenharmony_ci		return le32_to_cpu(rx_desc->pp21.buf_dma_addr);
2568c2ecf20Sopenharmony_ci	else
2578c2ecf20Sopenharmony_ci		return le64_to_cpu(rx_desc->pp22.buf_dma_addr_key_hash) &
2588c2ecf20Sopenharmony_ci		       MVPP2_DESC_DMA_MASK;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic unsigned long mvpp2_rxdesc_cookie_get(struct mvpp2_port *port,
2628c2ecf20Sopenharmony_ci					     struct mvpp2_rx_desc *rx_desc)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2658c2ecf20Sopenharmony_ci		return le32_to_cpu(rx_desc->pp21.buf_cookie);
2668c2ecf20Sopenharmony_ci	else
2678c2ecf20Sopenharmony_ci		return le64_to_cpu(rx_desc->pp22.buf_cookie_misc) &
2688c2ecf20Sopenharmony_ci		       MVPP2_DESC_DMA_MASK;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port,
2728c2ecf20Sopenharmony_ci				    struct mvpp2_rx_desc *rx_desc)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2758c2ecf20Sopenharmony_ci		return le16_to_cpu(rx_desc->pp21.data_size);
2768c2ecf20Sopenharmony_ci	else
2778c2ecf20Sopenharmony_ci		return le16_to_cpu(rx_desc->pp22.data_size);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic u32 mvpp2_rxdesc_status_get(struct mvpp2_port *port,
2818c2ecf20Sopenharmony_ci				   struct mvpp2_rx_desc *rx_desc)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
2848c2ecf20Sopenharmony_ci		return le32_to_cpu(rx_desc->pp21.status);
2858c2ecf20Sopenharmony_ci	else
2868c2ecf20Sopenharmony_ci		return le32_to_cpu(rx_desc->pp22.status);
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	txq_pcpu->txq_get_index++;
2928c2ecf20Sopenharmony_ci	if (txq_pcpu->txq_get_index == txq_pcpu->size)
2938c2ecf20Sopenharmony_ci		txq_pcpu->txq_get_index = 0;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic void mvpp2_txq_inc_put(struct mvpp2_port *port,
2978c2ecf20Sopenharmony_ci			      struct mvpp2_txq_pcpu *txq_pcpu,
2988c2ecf20Sopenharmony_ci			      void *data,
2998c2ecf20Sopenharmony_ci			      struct mvpp2_tx_desc *tx_desc,
3008c2ecf20Sopenharmony_ci			      enum mvpp2_tx_buf_type buf_type)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu_buf *tx_buf =
3038c2ecf20Sopenharmony_ci		txq_pcpu->buffs + txq_pcpu->txq_put_index;
3048c2ecf20Sopenharmony_ci	tx_buf->type = buf_type;
3058c2ecf20Sopenharmony_ci	if (buf_type == MVPP2_TYPE_SKB)
3068c2ecf20Sopenharmony_ci		tx_buf->skb = data;
3078c2ecf20Sopenharmony_ci	else
3088c2ecf20Sopenharmony_ci		tx_buf->xdpf = data;
3098c2ecf20Sopenharmony_ci	tx_buf->size = mvpp2_txdesc_size_get(port, tx_desc);
3108c2ecf20Sopenharmony_ci	tx_buf->dma = mvpp2_txdesc_dma_addr_get(port, tx_desc) +
3118c2ecf20Sopenharmony_ci		mvpp2_txdesc_offset_get(port, tx_desc);
3128c2ecf20Sopenharmony_ci	txq_pcpu->txq_put_index++;
3138c2ecf20Sopenharmony_ci	if (txq_pcpu->txq_put_index == txq_pcpu->size)
3148c2ecf20Sopenharmony_ci		txq_pcpu->txq_put_index = 0;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci/* Get number of maximum RXQ */
3188c2ecf20Sopenharmony_cistatic int mvpp2_get_nrxqs(struct mvpp2 *priv)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	unsigned int nrxqs;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22 && queue_mode == MVPP2_QDIST_SINGLE_MODE)
3238c2ecf20Sopenharmony_ci		return 1;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* According to the PPv2.2 datasheet and our experiments on
3268c2ecf20Sopenharmony_ci	 * PPv2.1, RX queues have an allocation granularity of 4 (when
3278c2ecf20Sopenharmony_ci	 * more than a single one on PPv2.2).
3288c2ecf20Sopenharmony_ci	 * Round up to nearest multiple of 4.
3298c2ecf20Sopenharmony_ci	 */
3308c2ecf20Sopenharmony_ci	nrxqs = (num_possible_cpus() + 3) & ~0x3;
3318c2ecf20Sopenharmony_ci	if (nrxqs > MVPP2_PORT_MAX_RXQ)
3328c2ecf20Sopenharmony_ci		nrxqs = MVPP2_PORT_MAX_RXQ;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return nrxqs;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/* Get number of physical egress port */
3388c2ecf20Sopenharmony_cistatic inline int mvpp2_egress_port(struct mvpp2_port *port)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	return MVPP2_MAX_TCONT + port->id;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/* Get number of physical TXQ */
3448c2ecf20Sopenharmony_cistatic inline int mvpp2_txq_phys(int port, int txq)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	return (MVPP2_MAX_TCONT + port) * MVPP2_MAX_TXQ + txq;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/* Returns a struct page if page_pool is set, otherwise a buffer */
3508c2ecf20Sopenharmony_cistatic void *mvpp2_frag_alloc(const struct mvpp2_bm_pool *pool,
3518c2ecf20Sopenharmony_ci			      struct page_pool *page_pool)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	if (page_pool)
3548c2ecf20Sopenharmony_ci		return page_pool_dev_alloc_pages(page_pool);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (likely(pool->frag_size <= PAGE_SIZE))
3578c2ecf20Sopenharmony_ci		return netdev_alloc_frag(pool->frag_size);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return kmalloc(pool->frag_size, GFP_ATOMIC);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic void mvpp2_frag_free(const struct mvpp2_bm_pool *pool,
3638c2ecf20Sopenharmony_ci			    struct page_pool *page_pool, void *data)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	if (page_pool)
3668c2ecf20Sopenharmony_ci		page_pool_put_full_page(page_pool, virt_to_head_page(data), false);
3678c2ecf20Sopenharmony_ci	else if (likely(pool->frag_size <= PAGE_SIZE))
3688c2ecf20Sopenharmony_ci		skb_free_frag(data);
3698c2ecf20Sopenharmony_ci	else
3708c2ecf20Sopenharmony_ci		kfree(data);
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci/* Buffer Manager configuration routines */
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/* Create pool */
3768c2ecf20Sopenharmony_cistatic int mvpp2_bm_pool_create(struct device *dev, struct mvpp2 *priv,
3778c2ecf20Sopenharmony_ci				struct mvpp2_bm_pool *bm_pool, int size)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	u32 val;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* Number of buffer pointers must be a multiple of 16, as per
3828c2ecf20Sopenharmony_ci	 * hardware constraints
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(size, 16))
3858c2ecf20Sopenharmony_ci		return -EINVAL;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* PPv2.1 needs 8 bytes per buffer pointer, PPv2.2 needs 16
3888c2ecf20Sopenharmony_ci	 * bytes per buffer pointer
3898c2ecf20Sopenharmony_ci	 */
3908c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
3918c2ecf20Sopenharmony_ci		bm_pool->size_bytes = 2 * sizeof(u32) * size;
3928c2ecf20Sopenharmony_ci	else
3938c2ecf20Sopenharmony_ci		bm_pool->size_bytes = 2 * sizeof(u64) * size;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	bm_pool->virt_addr = dma_alloc_coherent(dev, bm_pool->size_bytes,
3968c2ecf20Sopenharmony_ci						&bm_pool->dma_addr,
3978c2ecf20Sopenharmony_ci						GFP_KERNEL);
3988c2ecf20Sopenharmony_ci	if (!bm_pool->virt_addr)
3998c2ecf20Sopenharmony_ci		return -ENOMEM;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (!IS_ALIGNED((unsigned long)bm_pool->virt_addr,
4028c2ecf20Sopenharmony_ci			MVPP2_BM_POOL_PTR_ALIGN)) {
4038c2ecf20Sopenharmony_ci		dma_free_coherent(dev, bm_pool->size_bytes,
4048c2ecf20Sopenharmony_ci				  bm_pool->virt_addr, bm_pool->dma_addr);
4058c2ecf20Sopenharmony_ci		dev_err(dev, "BM pool %d is not %d bytes aligned\n",
4068c2ecf20Sopenharmony_ci			bm_pool->id, MVPP2_BM_POOL_PTR_ALIGN);
4078c2ecf20Sopenharmony_ci		return -ENOMEM;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_BM_POOL_BASE_REG(bm_pool->id),
4118c2ecf20Sopenharmony_ci		    lower_32_bits(bm_pool->dma_addr));
4128c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_BM_POOL_SIZE_REG(bm_pool->id), size);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id));
4158c2ecf20Sopenharmony_ci	val |= MVPP2_BM_START_MASK;
4168c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id), val);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	bm_pool->size = size;
4198c2ecf20Sopenharmony_ci	bm_pool->pkt_size = 0;
4208c2ecf20Sopenharmony_ci	bm_pool->buf_num = 0;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci/* Set pool buffer size */
4268c2ecf20Sopenharmony_cistatic void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv,
4278c2ecf20Sopenharmony_ci				      struct mvpp2_bm_pool *bm_pool,
4288c2ecf20Sopenharmony_ci				      int buf_size)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	u32 val;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	bm_pool->buf_size = buf_size;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	val = ALIGN(buf_size, 1 << MVPP2_POOL_BUF_SIZE_OFFSET);
4358c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_POOL_BUF_SIZE_REG(bm_pool->id), val);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void mvpp2_bm_bufs_get_addrs(struct device *dev, struct mvpp2 *priv,
4398c2ecf20Sopenharmony_ci				    struct mvpp2_bm_pool *bm_pool,
4408c2ecf20Sopenharmony_ci				    dma_addr_t *dma_addr,
4418c2ecf20Sopenharmony_ci				    phys_addr_t *phys_addr)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(priv, get_cpu());
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	*dma_addr = mvpp2_thread_read(priv, thread,
4468c2ecf20Sopenharmony_ci				      MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
4478c2ecf20Sopenharmony_ci	*phys_addr = mvpp2_thread_read(priv, thread, MVPP2_BM_VIRT_ALLOC_REG);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22) {
4508c2ecf20Sopenharmony_ci		u32 val;
4518c2ecf20Sopenharmony_ci		u32 dma_addr_highbits, phys_addr_highbits;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		val = mvpp2_thread_read(priv, thread, MVPP22_BM_ADDR_HIGH_ALLOC);
4548c2ecf20Sopenharmony_ci		dma_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_PHYS_MASK);
4558c2ecf20Sopenharmony_ci		phys_addr_highbits = (val & MVPP22_BM_ADDR_HIGH_VIRT_MASK) >>
4568c2ecf20Sopenharmony_ci			MVPP22_BM_ADDR_HIGH_VIRT_SHIFT;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		if (sizeof(dma_addr_t) == 8)
4598c2ecf20Sopenharmony_ci			*dma_addr |= (u64)dma_addr_highbits << 32;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		if (sizeof(phys_addr_t) == 8)
4628c2ecf20Sopenharmony_ci			*phys_addr |= (u64)phys_addr_highbits << 32;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	put_cpu();
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci/* Free all buffers from the pool */
4698c2ecf20Sopenharmony_cistatic void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv,
4708c2ecf20Sopenharmony_ci			       struct mvpp2_bm_pool *bm_pool, int buf_num)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct page_pool *pp = NULL;
4738c2ecf20Sopenharmony_ci	int i;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (buf_num > bm_pool->buf_num) {
4768c2ecf20Sopenharmony_ci		WARN(1, "Pool does not have so many bufs pool(%d) bufs(%d)\n",
4778c2ecf20Sopenharmony_ci		     bm_pool->id, buf_num);
4788c2ecf20Sopenharmony_ci		buf_num = bm_pool->buf_num;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	if (priv->percpu_pools)
4828c2ecf20Sopenharmony_ci		pp = priv->page_pool[bm_pool->id];
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	for (i = 0; i < buf_num; i++) {
4858c2ecf20Sopenharmony_ci		dma_addr_t buf_dma_addr;
4868c2ecf20Sopenharmony_ci		phys_addr_t buf_phys_addr;
4878c2ecf20Sopenharmony_ci		void *data;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		mvpp2_bm_bufs_get_addrs(dev, priv, bm_pool,
4908c2ecf20Sopenharmony_ci					&buf_dma_addr, &buf_phys_addr);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		if (!pp)
4938c2ecf20Sopenharmony_ci			dma_unmap_single(dev, buf_dma_addr,
4948c2ecf20Sopenharmony_ci					 bm_pool->buf_size, DMA_FROM_DEVICE);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci		data = (void *)phys_to_virt(buf_phys_addr);
4978c2ecf20Sopenharmony_ci		if (!data)
4988c2ecf20Sopenharmony_ci			break;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci		mvpp2_frag_free(bm_pool, pp, data);
5018c2ecf20Sopenharmony_ci	}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/* Update BM driver with number of buffers removed from pool */
5048c2ecf20Sopenharmony_ci	bm_pool->buf_num -= i;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci/* Check number of buffers in BM pool */
5088c2ecf20Sopenharmony_cistatic int mvpp2_check_hw_buf_num(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
5098c2ecf20Sopenharmony_ci{
5108c2ecf20Sopenharmony_ci	int buf_num = 0;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	buf_num += mvpp2_read(priv, MVPP2_BM_POOL_PTRS_NUM_REG(bm_pool->id)) &
5138c2ecf20Sopenharmony_ci				    MVPP22_BM_POOL_PTRS_NUM_MASK;
5148c2ecf20Sopenharmony_ci	buf_num += mvpp2_read(priv, MVPP2_BM_BPPI_PTRS_NUM_REG(bm_pool->id)) &
5158c2ecf20Sopenharmony_ci				    MVPP2_BM_BPPI_PTR_NUM_MASK;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* HW has one buffer ready which is not reflected in the counters */
5188c2ecf20Sopenharmony_ci	if (buf_num)
5198c2ecf20Sopenharmony_ci		buf_num += 1;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return buf_num;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci/* Cleanup pool */
5258c2ecf20Sopenharmony_cistatic int mvpp2_bm_pool_destroy(struct device *dev, struct mvpp2 *priv,
5268c2ecf20Sopenharmony_ci				 struct mvpp2_bm_pool *bm_pool)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	int buf_num;
5298c2ecf20Sopenharmony_ci	u32 val;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	buf_num = mvpp2_check_hw_buf_num(priv, bm_pool);
5328c2ecf20Sopenharmony_ci	mvpp2_bm_bufs_free(dev, priv, bm_pool, buf_num);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* Check buffer counters after free */
5358c2ecf20Sopenharmony_ci	buf_num = mvpp2_check_hw_buf_num(priv, bm_pool);
5368c2ecf20Sopenharmony_ci	if (buf_num) {
5378c2ecf20Sopenharmony_ci		WARN(1, "cannot free all buffers in pool %d, buf_num left %d\n",
5388c2ecf20Sopenharmony_ci		     bm_pool->id, bm_pool->buf_num);
5398c2ecf20Sopenharmony_ci		return 0;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id));
5438c2ecf20Sopenharmony_ci	val |= MVPP2_BM_STOP_MASK;
5448c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id), val);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (priv->percpu_pools) {
5478c2ecf20Sopenharmony_ci		page_pool_destroy(priv->page_pool[bm_pool->id]);
5488c2ecf20Sopenharmony_ci		priv->page_pool[bm_pool->id] = NULL;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	dma_free_coherent(dev, bm_pool->size_bytes,
5528c2ecf20Sopenharmony_ci			  bm_pool->virt_addr,
5538c2ecf20Sopenharmony_ci			  bm_pool->dma_addr);
5548c2ecf20Sopenharmony_ci	return 0;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_cistatic int mvpp2_bm_pools_init(struct device *dev, struct mvpp2 *priv)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	int i, err, size, poolnum = MVPP2_BM_POOLS_NUM;
5608c2ecf20Sopenharmony_ci	struct mvpp2_bm_pool *bm_pool;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	if (priv->percpu_pools)
5638c2ecf20Sopenharmony_ci		poolnum = mvpp2_get_nrxqs(priv) * 2;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	/* Create all pools with maximum size */
5668c2ecf20Sopenharmony_ci	size = MVPP2_BM_POOL_SIZE_MAX;
5678c2ecf20Sopenharmony_ci	for (i = 0; i < poolnum; i++) {
5688c2ecf20Sopenharmony_ci		bm_pool = &priv->bm_pools[i];
5698c2ecf20Sopenharmony_ci		bm_pool->id = i;
5708c2ecf20Sopenharmony_ci		err = mvpp2_bm_pool_create(dev, priv, bm_pool, size);
5718c2ecf20Sopenharmony_ci		if (err)
5728c2ecf20Sopenharmony_ci			goto err_unroll_pools;
5738c2ecf20Sopenharmony_ci		mvpp2_bm_pool_bufsize_set(priv, bm_pool, 0);
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci	return 0;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cierr_unroll_pools:
5788c2ecf20Sopenharmony_ci	dev_err(dev, "failed to create BM pool %d, size %d\n", i, size);
5798c2ecf20Sopenharmony_ci	for (i = i - 1; i >= 0; i--)
5808c2ecf20Sopenharmony_ci		mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]);
5818c2ecf20Sopenharmony_ci	return err;
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci/* Cleanup pool before actual initialization in the OS */
5858c2ecf20Sopenharmony_cistatic void mvpp2_bm_pool_cleanup(struct mvpp2 *priv, int pool_id)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(priv, get_cpu());
5888c2ecf20Sopenharmony_ci	u32 val;
5898c2ecf20Sopenharmony_ci	int i;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	/* Drain the BM from all possible residues left by firmware */
5928c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_BM_POOL_SIZE_MAX; i++)
5938c2ecf20Sopenharmony_ci		mvpp2_thread_read(priv, thread, MVPP2_BM_PHY_ALLOC_REG(pool_id));
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	put_cpu();
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	/* Stop the BM pool */
5988c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(pool_id));
5998c2ecf20Sopenharmony_ci	val |= MVPP2_BM_STOP_MASK;
6008c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_BM_POOL_CTRL_REG(pool_id), val);
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic int mvpp2_bm_init(struct device *dev, struct mvpp2 *priv)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	enum dma_data_direction dma_dir = DMA_FROM_DEVICE;
6068c2ecf20Sopenharmony_ci	int i, err, poolnum = MVPP2_BM_POOLS_NUM;
6078c2ecf20Sopenharmony_ci	struct mvpp2_port *port;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	if (priv->percpu_pools)
6108c2ecf20Sopenharmony_ci		poolnum = mvpp2_get_nrxqs(priv) * 2;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* Clean up the pool state in case it contains stale state */
6138c2ecf20Sopenharmony_ci	for (i = 0; i < poolnum; i++)
6148c2ecf20Sopenharmony_ci		mvpp2_bm_pool_cleanup(priv, i);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (priv->percpu_pools) {
6178c2ecf20Sopenharmony_ci		for (i = 0; i < priv->port_count; i++) {
6188c2ecf20Sopenharmony_ci			port = priv->port_list[i];
6198c2ecf20Sopenharmony_ci			if (port->xdp_prog) {
6208c2ecf20Sopenharmony_ci				dma_dir = DMA_BIDIRECTIONAL;
6218c2ecf20Sopenharmony_ci				break;
6228c2ecf20Sopenharmony_ci			}
6238c2ecf20Sopenharmony_ci		}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		for (i = 0; i < poolnum; i++) {
6268c2ecf20Sopenharmony_ci			/* the pool in use */
6278c2ecf20Sopenharmony_ci			int pn = i / (poolnum / 2);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci			priv->page_pool[i] =
6308c2ecf20Sopenharmony_ci				mvpp2_create_page_pool(dev,
6318c2ecf20Sopenharmony_ci						       mvpp2_pools[pn].buf_num,
6328c2ecf20Sopenharmony_ci						       mvpp2_pools[pn].pkt_size,
6338c2ecf20Sopenharmony_ci						       dma_dir);
6348c2ecf20Sopenharmony_ci			if (IS_ERR(priv->page_pool[i])) {
6358c2ecf20Sopenharmony_ci				int j;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci				for (j = 0; j < i; j++) {
6388c2ecf20Sopenharmony_ci					page_pool_destroy(priv->page_pool[j]);
6398c2ecf20Sopenharmony_ci					priv->page_pool[j] = NULL;
6408c2ecf20Sopenharmony_ci				}
6418c2ecf20Sopenharmony_ci				return PTR_ERR(priv->page_pool[i]);
6428c2ecf20Sopenharmony_ci			}
6438c2ecf20Sopenharmony_ci		}
6448c2ecf20Sopenharmony_ci	}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	dev_info(dev, "using %d %s buffers\n", poolnum,
6478c2ecf20Sopenharmony_ci		 priv->percpu_pools ? "per-cpu" : "shared");
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	for (i = 0; i < poolnum; i++) {
6508c2ecf20Sopenharmony_ci		/* Mask BM all interrupts */
6518c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_BM_INTR_MASK_REG(i), 0);
6528c2ecf20Sopenharmony_ci		/* Clear BM cause register */
6538c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_BM_INTR_CAUSE_REG(i), 0);
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* Allocate and initialize BM pools */
6578c2ecf20Sopenharmony_ci	priv->bm_pools = devm_kcalloc(dev, poolnum,
6588c2ecf20Sopenharmony_ci				      sizeof(*priv->bm_pools), GFP_KERNEL);
6598c2ecf20Sopenharmony_ci	if (!priv->bm_pools)
6608c2ecf20Sopenharmony_ci		return -ENOMEM;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	err = mvpp2_bm_pools_init(dev, priv);
6638c2ecf20Sopenharmony_ci	if (err < 0)
6648c2ecf20Sopenharmony_ci		return err;
6658c2ecf20Sopenharmony_ci	return 0;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic void mvpp2_setup_bm_pool(void)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	/* Short pool */
6718c2ecf20Sopenharmony_ci	mvpp2_pools[MVPP2_BM_SHORT].buf_num  = MVPP2_BM_SHORT_BUF_NUM;
6728c2ecf20Sopenharmony_ci	mvpp2_pools[MVPP2_BM_SHORT].pkt_size = MVPP2_BM_SHORT_PKT_SIZE;
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	/* Long pool */
6758c2ecf20Sopenharmony_ci	mvpp2_pools[MVPP2_BM_LONG].buf_num  = MVPP2_BM_LONG_BUF_NUM;
6768c2ecf20Sopenharmony_ci	mvpp2_pools[MVPP2_BM_LONG].pkt_size = MVPP2_BM_LONG_PKT_SIZE;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	/* Jumbo pool */
6798c2ecf20Sopenharmony_ci	mvpp2_pools[MVPP2_BM_JUMBO].buf_num  = MVPP2_BM_JUMBO_BUF_NUM;
6808c2ecf20Sopenharmony_ci	mvpp2_pools[MVPP2_BM_JUMBO].pkt_size = MVPP2_BM_JUMBO_PKT_SIZE;
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci/* Attach long pool to rxq */
6848c2ecf20Sopenharmony_cistatic void mvpp2_rxq_long_pool_set(struct mvpp2_port *port,
6858c2ecf20Sopenharmony_ci				    int lrxq, int long_pool)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	u32 val, mask;
6888c2ecf20Sopenharmony_ci	int prxq;
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	/* Get queue physical ID */
6918c2ecf20Sopenharmony_ci	prxq = port->rxqs[lrxq]->id;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
6948c2ecf20Sopenharmony_ci		mask = MVPP21_RXQ_POOL_LONG_MASK;
6958c2ecf20Sopenharmony_ci	else
6968c2ecf20Sopenharmony_ci		mask = MVPP22_RXQ_POOL_LONG_MASK;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
6998c2ecf20Sopenharmony_ci	val &= ~mask;
7008c2ecf20Sopenharmony_ci	val |= (long_pool << MVPP2_RXQ_POOL_LONG_OFFS) & mask;
7018c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/* Attach short pool to rxq */
7058c2ecf20Sopenharmony_cistatic void mvpp2_rxq_short_pool_set(struct mvpp2_port *port,
7068c2ecf20Sopenharmony_ci				     int lrxq, int short_pool)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	u32 val, mask;
7098c2ecf20Sopenharmony_ci	int prxq;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	/* Get queue physical ID */
7128c2ecf20Sopenharmony_ci	prxq = port->rxqs[lrxq]->id;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
7158c2ecf20Sopenharmony_ci		mask = MVPP21_RXQ_POOL_SHORT_MASK;
7168c2ecf20Sopenharmony_ci	else
7178c2ecf20Sopenharmony_ci		mask = MVPP22_RXQ_POOL_SHORT_MASK;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
7208c2ecf20Sopenharmony_ci	val &= ~mask;
7218c2ecf20Sopenharmony_ci	val |= (short_pool << MVPP2_RXQ_POOL_SHORT_OFFS) & mask;
7228c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_cistatic void *mvpp2_buf_alloc(struct mvpp2_port *port,
7268c2ecf20Sopenharmony_ci			     struct mvpp2_bm_pool *bm_pool,
7278c2ecf20Sopenharmony_ci			     struct page_pool *page_pool,
7288c2ecf20Sopenharmony_ci			     dma_addr_t *buf_dma_addr,
7298c2ecf20Sopenharmony_ci			     phys_addr_t *buf_phys_addr,
7308c2ecf20Sopenharmony_ci			     gfp_t gfp_mask)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
7338c2ecf20Sopenharmony_ci	struct page *page;
7348c2ecf20Sopenharmony_ci	void *data;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	data = mvpp2_frag_alloc(bm_pool, page_pool);
7378c2ecf20Sopenharmony_ci	if (!data)
7388c2ecf20Sopenharmony_ci		return NULL;
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	if (page_pool) {
7418c2ecf20Sopenharmony_ci		page = (struct page *)data;
7428c2ecf20Sopenharmony_ci		dma_addr = page_pool_get_dma_addr(page);
7438c2ecf20Sopenharmony_ci		data = page_to_virt(page);
7448c2ecf20Sopenharmony_ci	} else {
7458c2ecf20Sopenharmony_ci		dma_addr = dma_map_single(port->dev->dev.parent, data,
7468c2ecf20Sopenharmony_ci					  MVPP2_RX_BUF_SIZE(bm_pool->pkt_size),
7478c2ecf20Sopenharmony_ci					  DMA_FROM_DEVICE);
7488c2ecf20Sopenharmony_ci		if (unlikely(dma_mapping_error(port->dev->dev.parent, dma_addr))) {
7498c2ecf20Sopenharmony_ci			mvpp2_frag_free(bm_pool, NULL, data);
7508c2ecf20Sopenharmony_ci			return NULL;
7518c2ecf20Sopenharmony_ci		}
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci	*buf_dma_addr = dma_addr;
7548c2ecf20Sopenharmony_ci	*buf_phys_addr = virt_to_phys(data);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	return data;
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci/* Release buffer to BM */
7608c2ecf20Sopenharmony_cistatic inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
7618c2ecf20Sopenharmony_ci				     dma_addr_t buf_dma_addr,
7628c2ecf20Sopenharmony_ci				     phys_addr_t buf_phys_addr)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
7658c2ecf20Sopenharmony_ci	unsigned long flags = 0;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if (test_bit(thread, &port->priv->lock_map))
7688c2ecf20Sopenharmony_ci		spin_lock_irqsave(&port->bm_lock[thread], flags);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP22) {
7718c2ecf20Sopenharmony_ci		u32 val = 0;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		if (sizeof(dma_addr_t) == 8)
7748c2ecf20Sopenharmony_ci			val |= upper_32_bits(buf_dma_addr) &
7758c2ecf20Sopenharmony_ci				MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci		if (sizeof(phys_addr_t) == 8)
7788c2ecf20Sopenharmony_ci			val |= (upper_32_bits(buf_phys_addr)
7798c2ecf20Sopenharmony_ci				<< MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) &
7808c2ecf20Sopenharmony_ci				MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		mvpp2_thread_write_relaxed(port->priv, thread,
7838c2ecf20Sopenharmony_ci					   MVPP22_BM_ADDR_HIGH_RLS_REG, val);
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	/* MVPP2_BM_VIRT_RLS_REG is not interpreted by HW, and simply
7878c2ecf20Sopenharmony_ci	 * returned in the "cookie" field of the RX
7888c2ecf20Sopenharmony_ci	 * descriptor. Instead of storing the virtual address, we
7898c2ecf20Sopenharmony_ci	 * store the physical address
7908c2ecf20Sopenharmony_ci	 */
7918c2ecf20Sopenharmony_ci	mvpp2_thread_write_relaxed(port->priv, thread,
7928c2ecf20Sopenharmony_ci				   MVPP2_BM_VIRT_RLS_REG, buf_phys_addr);
7938c2ecf20Sopenharmony_ci	mvpp2_thread_write_relaxed(port->priv, thread,
7948c2ecf20Sopenharmony_ci				   MVPP2_BM_PHY_RLS_REG(pool), buf_dma_addr);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	if (test_bit(thread, &port->priv->lock_map))
7978c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&port->bm_lock[thread], flags);
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	put_cpu();
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci/* Allocate buffers for the pool */
8038c2ecf20Sopenharmony_cistatic int mvpp2_bm_bufs_add(struct mvpp2_port *port,
8048c2ecf20Sopenharmony_ci			     struct mvpp2_bm_pool *bm_pool, int buf_num)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	int i, buf_size, total_size;
8078c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
8088c2ecf20Sopenharmony_ci	phys_addr_t phys_addr;
8098c2ecf20Sopenharmony_ci	struct page_pool *pp = NULL;
8108c2ecf20Sopenharmony_ci	void *buf;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (port->priv->percpu_pools &&
8138c2ecf20Sopenharmony_ci	    bm_pool->pkt_size > MVPP2_BM_LONG_PKT_SIZE) {
8148c2ecf20Sopenharmony_ci		netdev_err(port->dev,
8158c2ecf20Sopenharmony_ci			   "attempted to use jumbo frames with per-cpu pools");
8168c2ecf20Sopenharmony_ci		return 0;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	buf_size = MVPP2_RX_BUF_SIZE(bm_pool->pkt_size);
8208c2ecf20Sopenharmony_ci	total_size = MVPP2_RX_TOTAL_SIZE(buf_size);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (buf_num < 0 ||
8238c2ecf20Sopenharmony_ci	    (buf_num + bm_pool->buf_num > bm_pool->size)) {
8248c2ecf20Sopenharmony_ci		netdev_err(port->dev,
8258c2ecf20Sopenharmony_ci			   "cannot allocate %d buffers for pool %d\n",
8268c2ecf20Sopenharmony_ci			   buf_num, bm_pool->id);
8278c2ecf20Sopenharmony_ci		return 0;
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (port->priv->percpu_pools)
8318c2ecf20Sopenharmony_ci		pp = port->priv->page_pool[bm_pool->id];
8328c2ecf20Sopenharmony_ci	for (i = 0; i < buf_num; i++) {
8338c2ecf20Sopenharmony_ci		buf = mvpp2_buf_alloc(port, bm_pool, pp, &dma_addr,
8348c2ecf20Sopenharmony_ci				      &phys_addr, GFP_KERNEL);
8358c2ecf20Sopenharmony_ci		if (!buf)
8368c2ecf20Sopenharmony_ci			break;
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci		mvpp2_bm_pool_put(port, bm_pool->id, dma_addr,
8398c2ecf20Sopenharmony_ci				  phys_addr);
8408c2ecf20Sopenharmony_ci	}
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/* Update BM driver with number of buffers added to pool */
8438c2ecf20Sopenharmony_ci	bm_pool->buf_num += i;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	netdev_dbg(port->dev,
8468c2ecf20Sopenharmony_ci		   "pool %d: pkt_size=%4d, buf_size=%4d, total_size=%4d\n",
8478c2ecf20Sopenharmony_ci		   bm_pool->id, bm_pool->pkt_size, buf_size, total_size);
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	netdev_dbg(port->dev,
8508c2ecf20Sopenharmony_ci		   "pool %d: %d of %d buffers added\n",
8518c2ecf20Sopenharmony_ci		   bm_pool->id, i, buf_num);
8528c2ecf20Sopenharmony_ci	return i;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/* Notify the driver that BM pool is being used as specific type and return the
8568c2ecf20Sopenharmony_ci * pool pointer on success
8578c2ecf20Sopenharmony_ci */
8588c2ecf20Sopenharmony_cistatic struct mvpp2_bm_pool *
8598c2ecf20Sopenharmony_cimvpp2_bm_pool_use(struct mvpp2_port *port, unsigned pool, int pkt_size)
8608c2ecf20Sopenharmony_ci{
8618c2ecf20Sopenharmony_ci	struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool];
8628c2ecf20Sopenharmony_ci	int num;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	if ((port->priv->percpu_pools && pool > mvpp2_get_nrxqs(port->priv) * 2) ||
8658c2ecf20Sopenharmony_ci	    (!port->priv->percpu_pools && pool >= MVPP2_BM_POOLS_NUM)) {
8668c2ecf20Sopenharmony_ci		netdev_err(port->dev, "Invalid pool %d\n", pool);
8678c2ecf20Sopenharmony_ci		return NULL;
8688c2ecf20Sopenharmony_ci	}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	/* Allocate buffers in case BM pool is used as long pool, but packet
8718c2ecf20Sopenharmony_ci	 * size doesn't match MTU or BM pool hasn't being used yet
8728c2ecf20Sopenharmony_ci	 */
8738c2ecf20Sopenharmony_ci	if (new_pool->pkt_size == 0) {
8748c2ecf20Sopenharmony_ci		int pkts_num;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci		/* Set default buffer number or free all the buffers in case
8778c2ecf20Sopenharmony_ci		 * the pool is not empty
8788c2ecf20Sopenharmony_ci		 */
8798c2ecf20Sopenharmony_ci		pkts_num = new_pool->buf_num;
8808c2ecf20Sopenharmony_ci		if (pkts_num == 0) {
8818c2ecf20Sopenharmony_ci			if (port->priv->percpu_pools) {
8828c2ecf20Sopenharmony_ci				if (pool < port->nrxqs)
8838c2ecf20Sopenharmony_ci					pkts_num = mvpp2_pools[MVPP2_BM_SHORT].buf_num;
8848c2ecf20Sopenharmony_ci				else
8858c2ecf20Sopenharmony_ci					pkts_num = mvpp2_pools[MVPP2_BM_LONG].buf_num;
8868c2ecf20Sopenharmony_ci			} else {
8878c2ecf20Sopenharmony_ci				pkts_num = mvpp2_pools[pool].buf_num;
8888c2ecf20Sopenharmony_ci			}
8898c2ecf20Sopenharmony_ci		} else {
8908c2ecf20Sopenharmony_ci			mvpp2_bm_bufs_free(port->dev->dev.parent,
8918c2ecf20Sopenharmony_ci					   port->priv, new_pool, pkts_num);
8928c2ecf20Sopenharmony_ci		}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		new_pool->pkt_size = pkt_size;
8958c2ecf20Sopenharmony_ci		new_pool->frag_size =
8968c2ecf20Sopenharmony_ci			SKB_DATA_ALIGN(MVPP2_RX_BUF_SIZE(pkt_size)) +
8978c2ecf20Sopenharmony_ci			MVPP2_SKB_SHINFO_SIZE;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci		/* Allocate buffers for this pool */
9008c2ecf20Sopenharmony_ci		num = mvpp2_bm_bufs_add(port, new_pool, pkts_num);
9018c2ecf20Sopenharmony_ci		if (num != pkts_num) {
9028c2ecf20Sopenharmony_ci			WARN(1, "pool %d: %d of %d allocated\n",
9038c2ecf20Sopenharmony_ci			     new_pool->id, num, pkts_num);
9048c2ecf20Sopenharmony_ci			return NULL;
9058c2ecf20Sopenharmony_ci		}
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
9098c2ecf20Sopenharmony_ci				  MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	return new_pool;
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic struct mvpp2_bm_pool *
9158c2ecf20Sopenharmony_cimvpp2_bm_pool_use_percpu(struct mvpp2_port *port, int type,
9168c2ecf20Sopenharmony_ci			 unsigned int pool, int pkt_size)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct mvpp2_bm_pool *new_pool = &port->priv->bm_pools[pool];
9198c2ecf20Sopenharmony_ci	int num;
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	if (pool > port->nrxqs * 2) {
9228c2ecf20Sopenharmony_ci		netdev_err(port->dev, "Invalid pool %d\n", pool);
9238c2ecf20Sopenharmony_ci		return NULL;
9248c2ecf20Sopenharmony_ci	}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	/* Allocate buffers in case BM pool is used as long pool, but packet
9278c2ecf20Sopenharmony_ci	 * size doesn't match MTU or BM pool hasn't being used yet
9288c2ecf20Sopenharmony_ci	 */
9298c2ecf20Sopenharmony_ci	if (new_pool->pkt_size == 0) {
9308c2ecf20Sopenharmony_ci		int pkts_num;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci		/* Set default buffer number or free all the buffers in case
9338c2ecf20Sopenharmony_ci		 * the pool is not empty
9348c2ecf20Sopenharmony_ci		 */
9358c2ecf20Sopenharmony_ci		pkts_num = new_pool->buf_num;
9368c2ecf20Sopenharmony_ci		if (pkts_num == 0)
9378c2ecf20Sopenharmony_ci			pkts_num = mvpp2_pools[type].buf_num;
9388c2ecf20Sopenharmony_ci		else
9398c2ecf20Sopenharmony_ci			mvpp2_bm_bufs_free(port->dev->dev.parent,
9408c2ecf20Sopenharmony_ci					   port->priv, new_pool, pkts_num);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci		new_pool->pkt_size = pkt_size;
9438c2ecf20Sopenharmony_ci		new_pool->frag_size =
9448c2ecf20Sopenharmony_ci			SKB_DATA_ALIGN(MVPP2_RX_BUF_SIZE(pkt_size)) +
9458c2ecf20Sopenharmony_ci			MVPP2_SKB_SHINFO_SIZE;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci		/* Allocate buffers for this pool */
9488c2ecf20Sopenharmony_ci		num = mvpp2_bm_bufs_add(port, new_pool, pkts_num);
9498c2ecf20Sopenharmony_ci		if (num != pkts_num) {
9508c2ecf20Sopenharmony_ci			WARN(1, "pool %d: %d of %d allocated\n",
9518c2ecf20Sopenharmony_ci			     new_pool->id, num, pkts_num);
9528c2ecf20Sopenharmony_ci			return NULL;
9538c2ecf20Sopenharmony_ci		}
9548c2ecf20Sopenharmony_ci	}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci	mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
9578c2ecf20Sopenharmony_ci				  MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	return new_pool;
9608c2ecf20Sopenharmony_ci}
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci/* Initialize pools for swf, shared buffers variant */
9638c2ecf20Sopenharmony_cistatic int mvpp2_swf_bm_pool_init_shared(struct mvpp2_port *port)
9648c2ecf20Sopenharmony_ci{
9658c2ecf20Sopenharmony_ci	enum mvpp2_bm_pool_log_num long_log_pool, short_log_pool;
9668c2ecf20Sopenharmony_ci	int rxq;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	/* If port pkt_size is higher than 1518B:
9698c2ecf20Sopenharmony_ci	 * HW Long pool - SW Jumbo pool, HW Short pool - SW Long pool
9708c2ecf20Sopenharmony_ci	 * else: HW Long pool - SW Long pool, HW Short pool - SW Short pool
9718c2ecf20Sopenharmony_ci	 */
9728c2ecf20Sopenharmony_ci	if (port->pkt_size > MVPP2_BM_LONG_PKT_SIZE) {
9738c2ecf20Sopenharmony_ci		long_log_pool = MVPP2_BM_JUMBO;
9748c2ecf20Sopenharmony_ci		short_log_pool = MVPP2_BM_LONG;
9758c2ecf20Sopenharmony_ci	} else {
9768c2ecf20Sopenharmony_ci		long_log_pool = MVPP2_BM_LONG;
9778c2ecf20Sopenharmony_ci		short_log_pool = MVPP2_BM_SHORT;
9788c2ecf20Sopenharmony_ci	}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	if (!port->pool_long) {
9818c2ecf20Sopenharmony_ci		port->pool_long =
9828c2ecf20Sopenharmony_ci			mvpp2_bm_pool_use(port, long_log_pool,
9838c2ecf20Sopenharmony_ci					  mvpp2_pools[long_log_pool].pkt_size);
9848c2ecf20Sopenharmony_ci		if (!port->pool_long)
9858c2ecf20Sopenharmony_ci			return -ENOMEM;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci		port->pool_long->port_map |= BIT(port->id);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci		for (rxq = 0; rxq < port->nrxqs; rxq++)
9908c2ecf20Sopenharmony_ci			mvpp2_rxq_long_pool_set(port, rxq, port->pool_long->id);
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (!port->pool_short) {
9948c2ecf20Sopenharmony_ci		port->pool_short =
9958c2ecf20Sopenharmony_ci			mvpp2_bm_pool_use(port, short_log_pool,
9968c2ecf20Sopenharmony_ci					  mvpp2_pools[short_log_pool].pkt_size);
9978c2ecf20Sopenharmony_ci		if (!port->pool_short)
9988c2ecf20Sopenharmony_ci			return -ENOMEM;
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci		port->pool_short->port_map |= BIT(port->id);
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci		for (rxq = 0; rxq < port->nrxqs; rxq++)
10038c2ecf20Sopenharmony_ci			mvpp2_rxq_short_pool_set(port, rxq,
10048c2ecf20Sopenharmony_ci						 port->pool_short->id);
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	return 0;
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci/* Initialize pools for swf, percpu buffers variant */
10118c2ecf20Sopenharmony_cistatic int mvpp2_swf_bm_pool_init_percpu(struct mvpp2_port *port)
10128c2ecf20Sopenharmony_ci{
10138c2ecf20Sopenharmony_ci	struct mvpp2_bm_pool *bm_pool;
10148c2ecf20Sopenharmony_ci	int i;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	for (i = 0; i < port->nrxqs; i++) {
10178c2ecf20Sopenharmony_ci		bm_pool = mvpp2_bm_pool_use_percpu(port, MVPP2_BM_SHORT, i,
10188c2ecf20Sopenharmony_ci						   mvpp2_pools[MVPP2_BM_SHORT].pkt_size);
10198c2ecf20Sopenharmony_ci		if (!bm_pool)
10208c2ecf20Sopenharmony_ci			return -ENOMEM;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci		bm_pool->port_map |= BIT(port->id);
10238c2ecf20Sopenharmony_ci		mvpp2_rxq_short_pool_set(port, i, bm_pool->id);
10248c2ecf20Sopenharmony_ci	}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	for (i = 0; i < port->nrxqs; i++) {
10278c2ecf20Sopenharmony_ci		bm_pool = mvpp2_bm_pool_use_percpu(port, MVPP2_BM_LONG, i + port->nrxqs,
10288c2ecf20Sopenharmony_ci						   mvpp2_pools[MVPP2_BM_LONG].pkt_size);
10298c2ecf20Sopenharmony_ci		if (!bm_pool)
10308c2ecf20Sopenharmony_ci			return -ENOMEM;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci		bm_pool->port_map |= BIT(port->id);
10338c2ecf20Sopenharmony_ci		mvpp2_rxq_long_pool_set(port, i, bm_pool->id);
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	port->pool_long = NULL;
10378c2ecf20Sopenharmony_ci	port->pool_short = NULL;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	return 0;
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_cistatic int mvpp2_swf_bm_pool_init(struct mvpp2_port *port)
10438c2ecf20Sopenharmony_ci{
10448c2ecf20Sopenharmony_ci	if (port->priv->percpu_pools)
10458c2ecf20Sopenharmony_ci		return mvpp2_swf_bm_pool_init_percpu(port);
10468c2ecf20Sopenharmony_ci	else
10478c2ecf20Sopenharmony_ci		return mvpp2_swf_bm_pool_init_shared(port);
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_cistatic void mvpp2_set_hw_csum(struct mvpp2_port *port,
10518c2ecf20Sopenharmony_ci			      enum mvpp2_bm_pool_log_num new_long_pool)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	const netdev_features_t csums = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	/* Update L4 checksum when jumbo enable/disable on port.
10568c2ecf20Sopenharmony_ci	 * Only port 0 supports hardware checksum offload due to
10578c2ecf20Sopenharmony_ci	 * the Tx FIFO size limitation.
10588c2ecf20Sopenharmony_ci	 * Also, don't set NETIF_F_HW_CSUM because L3_offset in TX descriptor
10598c2ecf20Sopenharmony_ci	 * has 7 bits, so the maximum L3 offset is 128.
10608c2ecf20Sopenharmony_ci	 */
10618c2ecf20Sopenharmony_ci	if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) {
10628c2ecf20Sopenharmony_ci		port->dev->features &= ~csums;
10638c2ecf20Sopenharmony_ci		port->dev->hw_features &= ~csums;
10648c2ecf20Sopenharmony_ci	} else {
10658c2ecf20Sopenharmony_ci		port->dev->features |= csums;
10668c2ecf20Sopenharmony_ci		port->dev->hw_features |= csums;
10678c2ecf20Sopenharmony_ci	}
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
10718c2ecf20Sopenharmony_ci{
10728c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
10738c2ecf20Sopenharmony_ci	enum mvpp2_bm_pool_log_num new_long_pool;
10748c2ecf20Sopenharmony_ci	int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	if (port->priv->percpu_pools)
10778c2ecf20Sopenharmony_ci		goto out_set;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	/* If port MTU is higher than 1518B:
10808c2ecf20Sopenharmony_ci	 * HW Long pool - SW Jumbo pool, HW Short pool - SW Long pool
10818c2ecf20Sopenharmony_ci	 * else: HW Long pool - SW Long pool, HW Short pool - SW Short pool
10828c2ecf20Sopenharmony_ci	 */
10838c2ecf20Sopenharmony_ci	if (pkt_size > MVPP2_BM_LONG_PKT_SIZE)
10848c2ecf20Sopenharmony_ci		new_long_pool = MVPP2_BM_JUMBO;
10858c2ecf20Sopenharmony_ci	else
10868c2ecf20Sopenharmony_ci		new_long_pool = MVPP2_BM_LONG;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (new_long_pool != port->pool_long->id) {
10898c2ecf20Sopenharmony_ci		/* Remove port from old short & long pool */
10908c2ecf20Sopenharmony_ci		port->pool_long = mvpp2_bm_pool_use(port, port->pool_long->id,
10918c2ecf20Sopenharmony_ci						    port->pool_long->pkt_size);
10928c2ecf20Sopenharmony_ci		port->pool_long->port_map &= ~BIT(port->id);
10938c2ecf20Sopenharmony_ci		port->pool_long = NULL;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci		port->pool_short = mvpp2_bm_pool_use(port, port->pool_short->id,
10968c2ecf20Sopenharmony_ci						     port->pool_short->pkt_size);
10978c2ecf20Sopenharmony_ci		port->pool_short->port_map &= ~BIT(port->id);
10988c2ecf20Sopenharmony_ci		port->pool_short = NULL;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci		port->pkt_size =  pkt_size;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci		/* Add port to new short & long pool */
11038c2ecf20Sopenharmony_ci		mvpp2_swf_bm_pool_init(port);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci		mvpp2_set_hw_csum(port, new_long_pool);
11068c2ecf20Sopenharmony_ci	}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ciout_set:
11098c2ecf20Sopenharmony_ci	dev->mtu = mtu;
11108c2ecf20Sopenharmony_ci	dev->wanted_features = dev->features;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	netdev_update_features(dev);
11138c2ecf20Sopenharmony_ci	return 0;
11148c2ecf20Sopenharmony_ci}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_cistatic inline void mvpp2_interrupts_enable(struct mvpp2_port *port)
11178c2ecf20Sopenharmony_ci{
11188c2ecf20Sopenharmony_ci	int i, sw_thread_mask = 0;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++)
11218c2ecf20Sopenharmony_ci		sw_thread_mask |= port->qvecs[i].sw_thread_mask;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
11248c2ecf20Sopenharmony_ci		    MVPP2_ISR_ENABLE_INTERRUPT(sw_thread_mask));
11258c2ecf20Sopenharmony_ci}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_cistatic inline void mvpp2_interrupts_disable(struct mvpp2_port *port)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	int i, sw_thread_mask = 0;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++)
11328c2ecf20Sopenharmony_ci		sw_thread_mask |= port->qvecs[i].sw_thread_mask;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
11358c2ecf20Sopenharmony_ci		    MVPP2_ISR_DISABLE_INTERRUPT(sw_thread_mask));
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic inline void mvpp2_qvec_interrupt_enable(struct mvpp2_queue_vector *qvec)
11398c2ecf20Sopenharmony_ci{
11408c2ecf20Sopenharmony_ci	struct mvpp2_port *port = qvec->port;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
11438c2ecf20Sopenharmony_ci		    MVPP2_ISR_ENABLE_INTERRUPT(qvec->sw_thread_mask));
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_cistatic inline void mvpp2_qvec_interrupt_disable(struct mvpp2_queue_vector *qvec)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	struct mvpp2_port *port = qvec->port;
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_ISR_ENABLE_REG(port->id),
11518c2ecf20Sopenharmony_ci		    MVPP2_ISR_DISABLE_INTERRUPT(qvec->sw_thread_mask));
11528c2ecf20Sopenharmony_ci}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci/* Mask the current thread's Rx/Tx interrupts
11558c2ecf20Sopenharmony_ci * Called by on_each_cpu(), guaranteed to run with migration disabled,
11568c2ecf20Sopenharmony_ci * using smp_processor_id() is OK.
11578c2ecf20Sopenharmony_ci */
11588c2ecf20Sopenharmony_cistatic void mvpp2_interrupts_mask(void *arg)
11598c2ecf20Sopenharmony_ci{
11608c2ecf20Sopenharmony_ci	struct mvpp2_port *port = arg;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	/* If the thread isn't used, don't do anything */
11638c2ecf20Sopenharmony_ci	if (smp_processor_id() > port->priv->nthreads)
11648c2ecf20Sopenharmony_ci		return;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv,
11678c2ecf20Sopenharmony_ci			   mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
11688c2ecf20Sopenharmony_ci			   MVPP2_ISR_RX_TX_MASK_REG(port->id), 0);
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci/* Unmask the current thread's Rx/Tx interrupts.
11728c2ecf20Sopenharmony_ci * Called by on_each_cpu(), guaranteed to run with migration disabled,
11738c2ecf20Sopenharmony_ci * using smp_processor_id() is OK.
11748c2ecf20Sopenharmony_ci */
11758c2ecf20Sopenharmony_cistatic void mvpp2_interrupts_unmask(void *arg)
11768c2ecf20Sopenharmony_ci{
11778c2ecf20Sopenharmony_ci	struct mvpp2_port *port = arg;
11788c2ecf20Sopenharmony_ci	u32 val;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	/* If the thread isn't used, don't do anything */
11818c2ecf20Sopenharmony_ci	if (smp_processor_id() >= port->priv->nthreads)
11828c2ecf20Sopenharmony_ci		return;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	val = MVPP2_CAUSE_MISC_SUM_MASK |
11858c2ecf20Sopenharmony_ci		MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version);
11868c2ecf20Sopenharmony_ci	if (port->has_tx_irqs)
11878c2ecf20Sopenharmony_ci		val |= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv,
11908c2ecf20Sopenharmony_ci			   mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
11918c2ecf20Sopenharmony_ci			   MVPP2_ISR_RX_TX_MASK_REG(port->id), val);
11928c2ecf20Sopenharmony_ci}
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_cistatic void
11958c2ecf20Sopenharmony_cimvpp2_shared_interrupt_mask_unmask(struct mvpp2_port *port, bool mask)
11968c2ecf20Sopenharmony_ci{
11978c2ecf20Sopenharmony_ci	u32 val;
11988c2ecf20Sopenharmony_ci	int i;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (port->priv->hw_version != MVPP22)
12018c2ecf20Sopenharmony_ci		return;
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci	if (mask)
12048c2ecf20Sopenharmony_ci		val = 0;
12058c2ecf20Sopenharmony_ci	else
12068c2ecf20Sopenharmony_ci		val = MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(MVPP22);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++) {
12098c2ecf20Sopenharmony_ci		struct mvpp2_queue_vector *v = port->qvecs + i;
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci		if (v->type != MVPP2_QUEUE_VECTOR_SHARED)
12128c2ecf20Sopenharmony_ci			continue;
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci		mvpp2_thread_write(port->priv, v->sw_thread_id,
12158c2ecf20Sopenharmony_ci				   MVPP2_ISR_RX_TX_MASK_REG(port->id), val);
12168c2ecf20Sopenharmony_ci	}
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci/* Only GOP port 0 has an XLG MAC */
12208c2ecf20Sopenharmony_cistatic bool mvpp2_port_supports_xlg(struct mvpp2_port *port)
12218c2ecf20Sopenharmony_ci{
12228c2ecf20Sopenharmony_ci	return port->gop_id == 0;
12238c2ecf20Sopenharmony_ci}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_cistatic bool mvpp2_port_supports_rgmii(struct mvpp2_port *port)
12268c2ecf20Sopenharmony_ci{
12278c2ecf20Sopenharmony_ci	return !(port->priv->hw_version == MVPP22 && port->gop_id == 0);
12288c2ecf20Sopenharmony_ci}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci/* Port configuration routines */
12318c2ecf20Sopenharmony_cistatic bool mvpp2_is_xlg(phy_interface_t interface)
12328c2ecf20Sopenharmony_ci{
12338c2ecf20Sopenharmony_ci	return interface == PHY_INTERFACE_MODE_10GBASER ||
12348c2ecf20Sopenharmony_ci	       interface == PHY_INTERFACE_MODE_XAUI;
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic void mvpp2_modify(void __iomem *ptr, u32 mask, u32 set)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	u32 old, val;
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	old = val = readl(ptr);
12428c2ecf20Sopenharmony_ci	val &= ~mask;
12438c2ecf20Sopenharmony_ci	val |= set;
12448c2ecf20Sopenharmony_ci	if (old != val)
12458c2ecf20Sopenharmony_ci		writel(val, ptr);
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_cistatic void mvpp22_gop_init_rgmii(struct mvpp2_port *port)
12498c2ecf20Sopenharmony_ci{
12508c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
12518c2ecf20Sopenharmony_ci	u32 val;
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val);
12548c2ecf20Sopenharmony_ci	val |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT;
12558c2ecf20Sopenharmony_ci	regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val);
12588c2ecf20Sopenharmony_ci	if (port->gop_id == 2)
12598c2ecf20Sopenharmony_ci		val |= GENCONF_CTRL0_PORT0_RGMII;
12608c2ecf20Sopenharmony_ci	else if (port->gop_id == 3)
12618c2ecf20Sopenharmony_ci		val |= GENCONF_CTRL0_PORT1_RGMII_MII;
12628c2ecf20Sopenharmony_ci	regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val);
12638c2ecf20Sopenharmony_ci}
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_cistatic void mvpp22_gop_init_sgmii(struct mvpp2_port *port)
12668c2ecf20Sopenharmony_ci{
12678c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
12688c2ecf20Sopenharmony_ci	u32 val;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val);
12718c2ecf20Sopenharmony_ci	val |= GENCONF_PORT_CTRL0_BUS_WIDTH_SELECT |
12728c2ecf20Sopenharmony_ci	       GENCONF_PORT_CTRL0_RX_DATA_SAMPLE;
12738c2ecf20Sopenharmony_ci	regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	if (port->gop_id > 1) {
12768c2ecf20Sopenharmony_ci		regmap_read(priv->sysctrl_base, GENCONF_CTRL0, &val);
12778c2ecf20Sopenharmony_ci		if (port->gop_id == 2)
12788c2ecf20Sopenharmony_ci			val &= ~GENCONF_CTRL0_PORT0_RGMII;
12798c2ecf20Sopenharmony_ci		else if (port->gop_id == 3)
12808c2ecf20Sopenharmony_ci			val &= ~GENCONF_CTRL0_PORT1_RGMII_MII;
12818c2ecf20Sopenharmony_ci		regmap_write(priv->sysctrl_base, GENCONF_CTRL0, val);
12828c2ecf20Sopenharmony_ci	}
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cistatic void mvpp22_gop_init_10gkr(struct mvpp2_port *port)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
12888c2ecf20Sopenharmony_ci	void __iomem *mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id);
12898c2ecf20Sopenharmony_ci	void __iomem *xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id);
12908c2ecf20Sopenharmony_ci	u32 val;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	val = readl(xpcs + MVPP22_XPCS_CFG0);
12938c2ecf20Sopenharmony_ci	val &= ~(MVPP22_XPCS_CFG0_PCS_MODE(0x3) |
12948c2ecf20Sopenharmony_ci		 MVPP22_XPCS_CFG0_ACTIVE_LANE(0x3));
12958c2ecf20Sopenharmony_ci	val |= MVPP22_XPCS_CFG0_ACTIVE_LANE(2);
12968c2ecf20Sopenharmony_ci	writel(val, xpcs + MVPP22_XPCS_CFG0);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	val = readl(mpcs + MVPP22_MPCS_CTRL);
12998c2ecf20Sopenharmony_ci	val &= ~MVPP22_MPCS_CTRL_FWD_ERR_CONN;
13008c2ecf20Sopenharmony_ci	writel(val, mpcs + MVPP22_MPCS_CTRL);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	val = readl(mpcs + MVPP22_MPCS_CLK_RESET);
13038c2ecf20Sopenharmony_ci	val &= ~MVPP22_MPCS_CLK_RESET_DIV_RATIO(0x7);
13048c2ecf20Sopenharmony_ci	val |= MVPP22_MPCS_CLK_RESET_DIV_RATIO(1);
13058c2ecf20Sopenharmony_ci	writel(val, mpcs + MVPP22_MPCS_CLK_RESET);
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_cistatic int mvpp22_gop_init(struct mvpp2_port *port)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
13118c2ecf20Sopenharmony_ci	u32 val;
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (!priv->sysctrl_base)
13148c2ecf20Sopenharmony_ci		return 0;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	switch (port->phy_interface) {
13178c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
13188c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
13198c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
13208c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
13218c2ecf20Sopenharmony_ci		if (!mvpp2_port_supports_rgmii(port))
13228c2ecf20Sopenharmony_ci			goto invalid_conf;
13238c2ecf20Sopenharmony_ci		mvpp22_gop_init_rgmii(port);
13248c2ecf20Sopenharmony_ci		break;
13258c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_SGMII:
13268c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_1000BASEX:
13278c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_2500BASEX:
13288c2ecf20Sopenharmony_ci		mvpp22_gop_init_sgmii(port);
13298c2ecf20Sopenharmony_ci		break;
13308c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
13318c2ecf20Sopenharmony_ci		if (!mvpp2_port_supports_xlg(port))
13328c2ecf20Sopenharmony_ci			goto invalid_conf;
13338c2ecf20Sopenharmony_ci		mvpp22_gop_init_10gkr(port);
13348c2ecf20Sopenharmony_ci		break;
13358c2ecf20Sopenharmony_ci	default:
13368c2ecf20Sopenharmony_ci		goto unsupported_conf;
13378c2ecf20Sopenharmony_ci	}
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL1, &val);
13408c2ecf20Sopenharmony_ci	val |= GENCONF_PORT_CTRL1_RESET(port->gop_id) |
13418c2ecf20Sopenharmony_ci	       GENCONF_PORT_CTRL1_EN(port->gop_id);
13428c2ecf20Sopenharmony_ci	regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL1, val);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	regmap_read(priv->sysctrl_base, GENCONF_PORT_CTRL0, &val);
13458c2ecf20Sopenharmony_ci	val |= GENCONF_PORT_CTRL0_CLK_DIV_PHASE_CLR;
13468c2ecf20Sopenharmony_ci	regmap_write(priv->sysctrl_base, GENCONF_PORT_CTRL0, val);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	regmap_read(priv->sysctrl_base, GENCONF_SOFT_RESET1, &val);
13498c2ecf20Sopenharmony_ci	val |= GENCONF_SOFT_RESET1_GOP;
13508c2ecf20Sopenharmony_ci	regmap_write(priv->sysctrl_base, GENCONF_SOFT_RESET1, val);
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ciunsupported_conf:
13538c2ecf20Sopenharmony_ci	return 0;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ciinvalid_conf:
13568c2ecf20Sopenharmony_ci	netdev_err(port->dev, "Invalid port configuration\n");
13578c2ecf20Sopenharmony_ci	return -EINVAL;
13588c2ecf20Sopenharmony_ci}
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_cistatic void mvpp22_gop_unmask_irq(struct mvpp2_port *port)
13618c2ecf20Sopenharmony_ci{
13628c2ecf20Sopenharmony_ci	u32 val;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_rgmii(port->phy_interface) ||
13658c2ecf20Sopenharmony_ci	    phy_interface_mode_is_8023z(port->phy_interface) ||
13668c2ecf20Sopenharmony_ci	    port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
13678c2ecf20Sopenharmony_ci		/* Enable the GMAC link status irq for this port */
13688c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_GMAC_INT_SUM_MASK);
13698c2ecf20Sopenharmony_ci		val |= MVPP22_GMAC_INT_SUM_MASK_LINK_STAT;
13708c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_GMAC_INT_SUM_MASK);
13718c2ecf20Sopenharmony_ci	}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port)) {
13748c2ecf20Sopenharmony_ci		/* Enable the XLG/GIG irqs for this port */
13758c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_EXT_INT_MASK);
13768c2ecf20Sopenharmony_ci		if (mvpp2_is_xlg(port->phy_interface))
13778c2ecf20Sopenharmony_ci			val |= MVPP22_XLG_EXT_INT_MASK_XLG;
13788c2ecf20Sopenharmony_ci		else
13798c2ecf20Sopenharmony_ci			val |= MVPP22_XLG_EXT_INT_MASK_GIG;
13808c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_EXT_INT_MASK);
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic void mvpp22_gop_mask_irq(struct mvpp2_port *port)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	u32 val;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port)) {
13898c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_EXT_INT_MASK);
13908c2ecf20Sopenharmony_ci		val &= ~(MVPP22_XLG_EXT_INT_MASK_XLG |
13918c2ecf20Sopenharmony_ci			 MVPP22_XLG_EXT_INT_MASK_GIG);
13928c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_EXT_INT_MASK);
13938c2ecf20Sopenharmony_ci	}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_rgmii(port->phy_interface) ||
13968c2ecf20Sopenharmony_ci	    phy_interface_mode_is_8023z(port->phy_interface) ||
13978c2ecf20Sopenharmony_ci	    port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
13988c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_GMAC_INT_SUM_MASK);
13998c2ecf20Sopenharmony_ci		val &= ~MVPP22_GMAC_INT_SUM_MASK_LINK_STAT;
14008c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_GMAC_INT_SUM_MASK);
14018c2ecf20Sopenharmony_ci	}
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic void mvpp22_gop_setup_irq(struct mvpp2_port *port)
14058c2ecf20Sopenharmony_ci{
14068c2ecf20Sopenharmony_ci	u32 val;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci	mvpp2_modify(port->base + MVPP22_GMAC_INT_SUM_MASK,
14098c2ecf20Sopenharmony_ci		     MVPP22_GMAC_INT_SUM_MASK_PTP,
14108c2ecf20Sopenharmony_ci		     MVPP22_GMAC_INT_SUM_MASK_PTP);
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	if (port->phylink ||
14138c2ecf20Sopenharmony_ci	    phy_interface_mode_is_rgmii(port->phy_interface) ||
14148c2ecf20Sopenharmony_ci	    phy_interface_mode_is_8023z(port->phy_interface) ||
14158c2ecf20Sopenharmony_ci	    port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
14168c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_GMAC_INT_MASK);
14178c2ecf20Sopenharmony_ci		val |= MVPP22_GMAC_INT_MASK_LINK_STAT;
14188c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_GMAC_INT_MASK);
14198c2ecf20Sopenharmony_ci	}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port)) {
14228c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_INT_MASK);
14238c2ecf20Sopenharmony_ci		val |= MVPP22_XLG_INT_MASK_LINK;
14248c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_INT_MASK);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci		mvpp2_modify(port->base + MVPP22_XLG_EXT_INT_MASK,
14278c2ecf20Sopenharmony_ci			     MVPP22_XLG_EXT_INT_MASK_PTP,
14288c2ecf20Sopenharmony_ci			     MVPP22_XLG_EXT_INT_MASK_PTP);
14298c2ecf20Sopenharmony_ci	}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	mvpp22_gop_unmask_irq(port);
14328c2ecf20Sopenharmony_ci}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci/* Sets the PHY mode of the COMPHY (which configures the serdes lanes).
14358c2ecf20Sopenharmony_ci *
14368c2ecf20Sopenharmony_ci * The PHY mode used by the PPv2 driver comes from the network subsystem, while
14378c2ecf20Sopenharmony_ci * the one given to the COMPHY comes from the generic PHY subsystem. Hence they
14388c2ecf20Sopenharmony_ci * differ.
14398c2ecf20Sopenharmony_ci *
14408c2ecf20Sopenharmony_ci * The COMPHY configures the serdes lanes regardless of the actual use of the
14418c2ecf20Sopenharmony_ci * lanes by the physical layer. This is why configurations like
14428c2ecf20Sopenharmony_ci * "PPv2 (2500BaseX) - COMPHY (2500SGMII)" are valid.
14438c2ecf20Sopenharmony_ci */
14448c2ecf20Sopenharmony_cistatic int mvpp22_comphy_init(struct mvpp2_port *port)
14458c2ecf20Sopenharmony_ci{
14468c2ecf20Sopenharmony_ci	int ret;
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	if (!port->comphy)
14498c2ecf20Sopenharmony_ci		return 0;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	ret = phy_set_mode_ext(port->comphy, PHY_MODE_ETHERNET,
14528c2ecf20Sopenharmony_ci			       port->phy_interface);
14538c2ecf20Sopenharmony_ci	if (ret)
14548c2ecf20Sopenharmony_ci		return ret;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	return phy_power_on(port->comphy);
14578c2ecf20Sopenharmony_ci}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_cistatic void mvpp2_port_enable(struct mvpp2_port *port)
14608c2ecf20Sopenharmony_ci{
14618c2ecf20Sopenharmony_ci	u32 val;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port) &&
14648c2ecf20Sopenharmony_ci	    mvpp2_is_xlg(port->phy_interface)) {
14658c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_CTRL0_REG);
14668c2ecf20Sopenharmony_ci		val |= MVPP22_XLG_CTRL0_PORT_EN;
14678c2ecf20Sopenharmony_ci		val &= ~MVPP22_XLG_CTRL0_MIB_CNT_DIS;
14688c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_CTRL0_REG);
14698c2ecf20Sopenharmony_ci	} else {
14708c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
14718c2ecf20Sopenharmony_ci		val |= MVPP2_GMAC_PORT_EN_MASK;
14728c2ecf20Sopenharmony_ci		val |= MVPP2_GMAC_MIB_CNTR_EN_MASK;
14738c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
14748c2ecf20Sopenharmony_ci	}
14758c2ecf20Sopenharmony_ci}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_cistatic void mvpp2_port_disable(struct mvpp2_port *port)
14788c2ecf20Sopenharmony_ci{
14798c2ecf20Sopenharmony_ci	u32 val;
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port) &&
14828c2ecf20Sopenharmony_ci	    mvpp2_is_xlg(port->phy_interface)) {
14838c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_CTRL0_REG);
14848c2ecf20Sopenharmony_ci		val &= ~MVPP22_XLG_CTRL0_PORT_EN;
14858c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_CTRL0_REG);
14868c2ecf20Sopenharmony_ci	}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
14898c2ecf20Sopenharmony_ci	val &= ~(MVPP2_GMAC_PORT_EN_MASK);
14908c2ecf20Sopenharmony_ci	writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
14918c2ecf20Sopenharmony_ci}
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci/* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */
14948c2ecf20Sopenharmony_cistatic void mvpp2_port_periodic_xon_disable(struct mvpp2_port *port)
14958c2ecf20Sopenharmony_ci{
14968c2ecf20Sopenharmony_ci	u32 val;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP2_GMAC_CTRL_1_REG) &
14998c2ecf20Sopenharmony_ci		    ~MVPP2_GMAC_PERIODIC_XON_EN_MASK;
15008c2ecf20Sopenharmony_ci	writel(val, port->base + MVPP2_GMAC_CTRL_1_REG);
15018c2ecf20Sopenharmony_ci}
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci/* Configure loopback port */
15048c2ecf20Sopenharmony_cistatic void mvpp2_port_loopback_set(struct mvpp2_port *port,
15058c2ecf20Sopenharmony_ci				    const struct phylink_link_state *state)
15068c2ecf20Sopenharmony_ci{
15078c2ecf20Sopenharmony_ci	u32 val;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP2_GMAC_CTRL_1_REG);
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	if (state->speed == 1000)
15128c2ecf20Sopenharmony_ci		val |= MVPP2_GMAC_GMII_LB_EN_MASK;
15138c2ecf20Sopenharmony_ci	else
15148c2ecf20Sopenharmony_ci		val &= ~MVPP2_GMAC_GMII_LB_EN_MASK;
15158c2ecf20Sopenharmony_ci
15168c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_8023z(state->interface) ||
15178c2ecf20Sopenharmony_ci	    state->interface == PHY_INTERFACE_MODE_SGMII)
15188c2ecf20Sopenharmony_ci		val |= MVPP2_GMAC_PCS_LB_EN_MASK;
15198c2ecf20Sopenharmony_ci	else
15208c2ecf20Sopenharmony_ci		val &= ~MVPP2_GMAC_PCS_LB_EN_MASK;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci	writel(val, port->base + MVPP2_GMAC_CTRL_1_REG);
15238c2ecf20Sopenharmony_ci}
15248c2ecf20Sopenharmony_ci
15258c2ecf20Sopenharmony_cienum {
15268c2ecf20Sopenharmony_ci	ETHTOOL_XDP_REDIRECT,
15278c2ecf20Sopenharmony_ci	ETHTOOL_XDP_PASS,
15288c2ecf20Sopenharmony_ci	ETHTOOL_XDP_DROP,
15298c2ecf20Sopenharmony_ci	ETHTOOL_XDP_TX,
15308c2ecf20Sopenharmony_ci	ETHTOOL_XDP_TX_ERR,
15318c2ecf20Sopenharmony_ci	ETHTOOL_XDP_XMIT,
15328c2ecf20Sopenharmony_ci	ETHTOOL_XDP_XMIT_ERR,
15338c2ecf20Sopenharmony_ci};
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_cistruct mvpp2_ethtool_counter {
15368c2ecf20Sopenharmony_ci	unsigned int offset;
15378c2ecf20Sopenharmony_ci	const char string[ETH_GSTRING_LEN];
15388c2ecf20Sopenharmony_ci	bool reg_is_64b;
15398c2ecf20Sopenharmony_ci};
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic u64 mvpp2_read_count(struct mvpp2_port *port,
15428c2ecf20Sopenharmony_ci			    const struct mvpp2_ethtool_counter *counter)
15438c2ecf20Sopenharmony_ci{
15448c2ecf20Sopenharmony_ci	u64 val;
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	val = readl(port->stats_base + counter->offset);
15478c2ecf20Sopenharmony_ci	if (counter->reg_is_64b)
15488c2ecf20Sopenharmony_ci		val += (u64)readl(port->stats_base + counter->offset + 4) << 32;
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	return val;
15518c2ecf20Sopenharmony_ci}
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci/* Some counters are accessed indirectly by first writing an index to
15548c2ecf20Sopenharmony_ci * MVPP2_CTRS_IDX. The index can represent various resources depending on the
15558c2ecf20Sopenharmony_ci * register we access, it can be a hit counter for some classification tables,
15568c2ecf20Sopenharmony_ci * a counter specific to a rxq, a txq or a buffer pool.
15578c2ecf20Sopenharmony_ci */
15588c2ecf20Sopenharmony_cistatic u32 mvpp2_read_index(struct mvpp2 *priv, u32 index, u32 reg)
15598c2ecf20Sopenharmony_ci{
15608c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_CTRS_IDX, index);
15618c2ecf20Sopenharmony_ci	return mvpp2_read(priv, reg);
15628c2ecf20Sopenharmony_ci}
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci/* Due to the fact that software statistics and hardware statistics are, by
15658c2ecf20Sopenharmony_ci * design, incremented at different moments in the chain of packet processing,
15668c2ecf20Sopenharmony_ci * it is very likely that incoming packets could have been dropped after being
15678c2ecf20Sopenharmony_ci * counted by hardware but before reaching software statistics (most probably
15688c2ecf20Sopenharmony_ci * multicast packets), and in the oppposite way, during transmission, FCS bytes
15698c2ecf20Sopenharmony_ci * are added in between as well as TSO skb will be split and header bytes added.
15708c2ecf20Sopenharmony_ci * Hence, statistics gathered from userspace with ifconfig (software) and
15718c2ecf20Sopenharmony_ci * ethtool (hardware) cannot be compared.
15728c2ecf20Sopenharmony_ci */
15738c2ecf20Sopenharmony_cistatic const struct mvpp2_ethtool_counter mvpp2_ethtool_mib_regs[] = {
15748c2ecf20Sopenharmony_ci	{ MVPP2_MIB_GOOD_OCTETS_RCVD, "good_octets_received", true },
15758c2ecf20Sopenharmony_ci	{ MVPP2_MIB_BAD_OCTETS_RCVD, "bad_octets_received" },
15768c2ecf20Sopenharmony_ci	{ MVPP2_MIB_CRC_ERRORS_SENT, "crc_errors_sent" },
15778c2ecf20Sopenharmony_ci	{ MVPP2_MIB_UNICAST_FRAMES_RCVD, "unicast_frames_received" },
15788c2ecf20Sopenharmony_ci	{ MVPP2_MIB_BROADCAST_FRAMES_RCVD, "broadcast_frames_received" },
15798c2ecf20Sopenharmony_ci	{ MVPP2_MIB_MULTICAST_FRAMES_RCVD, "multicast_frames_received" },
15808c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAMES_64_OCTETS, "frames_64_octets" },
15818c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAMES_65_TO_127_OCTETS, "frames_65_to_127_octet" },
15828c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAMES_128_TO_255_OCTETS, "frames_128_to_255_octet" },
15838c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAMES_256_TO_511_OCTETS, "frames_256_to_511_octet" },
15848c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAMES_512_TO_1023_OCTETS, "frames_512_to_1023_octet" },
15858c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAMES_1024_TO_MAX_OCTETS, "frames_1024_to_max_octet" },
15868c2ecf20Sopenharmony_ci	{ MVPP2_MIB_GOOD_OCTETS_SENT, "good_octets_sent", true },
15878c2ecf20Sopenharmony_ci	{ MVPP2_MIB_UNICAST_FRAMES_SENT, "unicast_frames_sent" },
15888c2ecf20Sopenharmony_ci	{ MVPP2_MIB_MULTICAST_FRAMES_SENT, "multicast_frames_sent" },
15898c2ecf20Sopenharmony_ci	{ MVPP2_MIB_BROADCAST_FRAMES_SENT, "broadcast_frames_sent" },
15908c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FC_SENT, "fc_sent" },
15918c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FC_RCVD, "fc_received" },
15928c2ecf20Sopenharmony_ci	{ MVPP2_MIB_RX_FIFO_OVERRUN, "rx_fifo_overrun" },
15938c2ecf20Sopenharmony_ci	{ MVPP2_MIB_UNDERSIZE_RCVD, "undersize_received" },
15948c2ecf20Sopenharmony_ci	{ MVPP2_MIB_FRAGMENTS_RCVD, "fragments_received" },
15958c2ecf20Sopenharmony_ci	{ MVPP2_MIB_OVERSIZE_RCVD, "oversize_received" },
15968c2ecf20Sopenharmony_ci	{ MVPP2_MIB_JABBER_RCVD, "jabber_received" },
15978c2ecf20Sopenharmony_ci	{ MVPP2_MIB_MAC_RCV_ERROR, "mac_receive_error" },
15988c2ecf20Sopenharmony_ci	{ MVPP2_MIB_BAD_CRC_EVENT, "bad_crc_event" },
15998c2ecf20Sopenharmony_ci	{ MVPP2_MIB_COLLISION, "collision" },
16008c2ecf20Sopenharmony_ci	{ MVPP2_MIB_LATE_COLLISION, "late_collision" },
16018c2ecf20Sopenharmony_ci};
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_cistatic const struct mvpp2_ethtool_counter mvpp2_ethtool_port_regs[] = {
16048c2ecf20Sopenharmony_ci	{ MVPP2_OVERRUN_ETH_DROP, "rx_fifo_or_parser_overrun_drops" },
16058c2ecf20Sopenharmony_ci	{ MVPP2_CLS_ETH_DROP, "rx_classifier_drops" },
16068c2ecf20Sopenharmony_ci};
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_cistatic const struct mvpp2_ethtool_counter mvpp2_ethtool_txq_regs[] = {
16098c2ecf20Sopenharmony_ci	{ MVPP2_TX_DESC_ENQ_CTR, "txq_%d_desc_enqueue" },
16108c2ecf20Sopenharmony_ci	{ MVPP2_TX_DESC_ENQ_TO_DDR_CTR, "txq_%d_desc_enqueue_to_ddr" },
16118c2ecf20Sopenharmony_ci	{ MVPP2_TX_BUFF_ENQ_TO_DDR_CTR, "txq_%d_buff_euqueue_to_ddr" },
16128c2ecf20Sopenharmony_ci	{ MVPP2_TX_DESC_ENQ_HW_FWD_CTR, "txq_%d_desc_hardware_forwarded" },
16138c2ecf20Sopenharmony_ci	{ MVPP2_TX_PKTS_DEQ_CTR, "txq_%d_packets_dequeued" },
16148c2ecf20Sopenharmony_ci	{ MVPP2_TX_PKTS_FULL_QUEUE_DROP_CTR, "txq_%d_queue_full_drops" },
16158c2ecf20Sopenharmony_ci	{ MVPP2_TX_PKTS_EARLY_DROP_CTR, "txq_%d_packets_early_drops" },
16168c2ecf20Sopenharmony_ci	{ MVPP2_TX_PKTS_BM_DROP_CTR, "txq_%d_packets_bm_drops" },
16178c2ecf20Sopenharmony_ci	{ MVPP2_TX_PKTS_BM_MC_DROP_CTR, "txq_%d_packets_rep_bm_drops" },
16188c2ecf20Sopenharmony_ci};
16198c2ecf20Sopenharmony_ci
16208c2ecf20Sopenharmony_cistatic const struct mvpp2_ethtool_counter mvpp2_ethtool_rxq_regs[] = {
16218c2ecf20Sopenharmony_ci	{ MVPP2_RX_DESC_ENQ_CTR, "rxq_%d_desc_enqueue" },
16228c2ecf20Sopenharmony_ci	{ MVPP2_RX_PKTS_FULL_QUEUE_DROP_CTR, "rxq_%d_queue_full_drops" },
16238c2ecf20Sopenharmony_ci	{ MVPP2_RX_PKTS_EARLY_DROP_CTR, "rxq_%d_packets_early_drops" },
16248c2ecf20Sopenharmony_ci	{ MVPP2_RX_PKTS_BM_DROP_CTR, "rxq_%d_packets_bm_drops" },
16258c2ecf20Sopenharmony_ci};
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_cistatic const struct mvpp2_ethtool_counter mvpp2_ethtool_xdp[] = {
16288c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_REDIRECT, "rx_xdp_redirect", },
16298c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_PASS, "rx_xdp_pass", },
16308c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_DROP, "rx_xdp_drop", },
16318c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_TX, "rx_xdp_tx", },
16328c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_TX_ERR, "rx_xdp_tx_errors", },
16338c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_XMIT, "tx_xdp_xmit", },
16348c2ecf20Sopenharmony_ci	{ ETHTOOL_XDP_XMIT_ERR, "tx_xdp_xmit_errors", },
16358c2ecf20Sopenharmony_ci};
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci#define MVPP2_N_ETHTOOL_STATS(ntxqs, nrxqs)	(ARRAY_SIZE(mvpp2_ethtool_mib_regs) + \
16388c2ecf20Sopenharmony_ci						 ARRAY_SIZE(mvpp2_ethtool_port_regs) + \
16398c2ecf20Sopenharmony_ci						 (ARRAY_SIZE(mvpp2_ethtool_txq_regs) * (ntxqs)) + \
16408c2ecf20Sopenharmony_ci						 (ARRAY_SIZE(mvpp2_ethtool_rxq_regs) * (nrxqs)) + \
16418c2ecf20Sopenharmony_ci						 ARRAY_SIZE(mvpp2_ethtool_xdp))
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_cistatic void mvpp2_ethtool_get_strings(struct net_device *netdev, u32 sset,
16448c2ecf20Sopenharmony_ci				      u8 *data)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(netdev);
16478c2ecf20Sopenharmony_ci	int i, q;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	if (sset != ETH_SS_STATS)
16508c2ecf20Sopenharmony_ci		return;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++) {
16538c2ecf20Sopenharmony_ci		strscpy(data, mvpp2_ethtool_mib_regs[i].string,
16548c2ecf20Sopenharmony_ci			ETH_GSTRING_LEN);
16558c2ecf20Sopenharmony_ci		data += ETH_GSTRING_LEN;
16568c2ecf20Sopenharmony_ci	}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++) {
16598c2ecf20Sopenharmony_ci		strscpy(data, mvpp2_ethtool_port_regs[i].string,
16608c2ecf20Sopenharmony_ci			ETH_GSTRING_LEN);
16618c2ecf20Sopenharmony_ci		data += ETH_GSTRING_LEN;
16628c2ecf20Sopenharmony_ci	}
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	for (q = 0; q < port->ntxqs; q++) {
16658c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++) {
16668c2ecf20Sopenharmony_ci			snprintf(data, ETH_GSTRING_LEN,
16678c2ecf20Sopenharmony_ci				 mvpp2_ethtool_txq_regs[i].string, q);
16688c2ecf20Sopenharmony_ci			data += ETH_GSTRING_LEN;
16698c2ecf20Sopenharmony_ci		}
16708c2ecf20Sopenharmony_ci	}
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	for (q = 0; q < port->nrxqs; q++) {
16738c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++) {
16748c2ecf20Sopenharmony_ci			snprintf(data, ETH_GSTRING_LEN,
16758c2ecf20Sopenharmony_ci				 mvpp2_ethtool_rxq_regs[i].string,
16768c2ecf20Sopenharmony_ci				 q);
16778c2ecf20Sopenharmony_ci			data += ETH_GSTRING_LEN;
16788c2ecf20Sopenharmony_ci		}
16798c2ecf20Sopenharmony_ci	}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_xdp); i++) {
16828c2ecf20Sopenharmony_ci		strscpy(data, mvpp2_ethtool_xdp[i].string,
16838c2ecf20Sopenharmony_ci			ETH_GSTRING_LEN);
16848c2ecf20Sopenharmony_ci		data += ETH_GSTRING_LEN;
16858c2ecf20Sopenharmony_ci	}
16868c2ecf20Sopenharmony_ci}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_cistatic void
16898c2ecf20Sopenharmony_cimvpp2_get_xdp_stats(struct mvpp2_port *port, struct mvpp2_pcpu_stats *xdp_stats)
16908c2ecf20Sopenharmony_ci{
16918c2ecf20Sopenharmony_ci	unsigned int start;
16928c2ecf20Sopenharmony_ci	unsigned int cpu;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	/* Gather XDP Statistics */
16958c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
16968c2ecf20Sopenharmony_ci		struct mvpp2_pcpu_stats *cpu_stats;
16978c2ecf20Sopenharmony_ci		u64	xdp_redirect;
16988c2ecf20Sopenharmony_ci		u64	xdp_pass;
16998c2ecf20Sopenharmony_ci		u64	xdp_drop;
17008c2ecf20Sopenharmony_ci		u64	xdp_xmit;
17018c2ecf20Sopenharmony_ci		u64	xdp_xmit_err;
17028c2ecf20Sopenharmony_ci		u64	xdp_tx;
17038c2ecf20Sopenharmony_ci		u64	xdp_tx_err;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci		cpu_stats = per_cpu_ptr(port->stats, cpu);
17068c2ecf20Sopenharmony_ci		do {
17078c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
17088c2ecf20Sopenharmony_ci			xdp_redirect = cpu_stats->xdp_redirect;
17098c2ecf20Sopenharmony_ci			xdp_pass   = cpu_stats->xdp_pass;
17108c2ecf20Sopenharmony_ci			xdp_drop = cpu_stats->xdp_drop;
17118c2ecf20Sopenharmony_ci			xdp_xmit   = cpu_stats->xdp_xmit;
17128c2ecf20Sopenharmony_ci			xdp_xmit_err   = cpu_stats->xdp_xmit_err;
17138c2ecf20Sopenharmony_ci			xdp_tx   = cpu_stats->xdp_tx;
17148c2ecf20Sopenharmony_ci			xdp_tx_err   = cpu_stats->xdp_tx_err;
17158c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci		xdp_stats->xdp_redirect += xdp_redirect;
17188c2ecf20Sopenharmony_ci		xdp_stats->xdp_pass   += xdp_pass;
17198c2ecf20Sopenharmony_ci		xdp_stats->xdp_drop += xdp_drop;
17208c2ecf20Sopenharmony_ci		xdp_stats->xdp_xmit   += xdp_xmit;
17218c2ecf20Sopenharmony_ci		xdp_stats->xdp_xmit_err   += xdp_xmit_err;
17228c2ecf20Sopenharmony_ci		xdp_stats->xdp_tx   += xdp_tx;
17238c2ecf20Sopenharmony_ci		xdp_stats->xdp_tx_err   += xdp_tx_err;
17248c2ecf20Sopenharmony_ci	}
17258c2ecf20Sopenharmony_ci}
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_cistatic void mvpp2_read_stats(struct mvpp2_port *port)
17288c2ecf20Sopenharmony_ci{
17298c2ecf20Sopenharmony_ci	struct mvpp2_pcpu_stats xdp_stats = {};
17308c2ecf20Sopenharmony_ci	const struct mvpp2_ethtool_counter *s;
17318c2ecf20Sopenharmony_ci	u64 *pstats;
17328c2ecf20Sopenharmony_ci	int i, q;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	pstats = port->ethtool_stats;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_mib_regs); i++)
17378c2ecf20Sopenharmony_ci		*pstats++ += mvpp2_read_count(port, &mvpp2_ethtool_mib_regs[i]);
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_port_regs); i++)
17408c2ecf20Sopenharmony_ci		*pstats++ += mvpp2_read(port->priv,
17418c2ecf20Sopenharmony_ci					mvpp2_ethtool_port_regs[i].offset +
17428c2ecf20Sopenharmony_ci					4 * port->id);
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	for (q = 0; q < port->ntxqs; q++)
17458c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_txq_regs); i++)
17468c2ecf20Sopenharmony_ci			*pstats++ += mvpp2_read_index(port->priv,
17478c2ecf20Sopenharmony_ci						      MVPP22_CTRS_TX_CTR(port->id, q),
17488c2ecf20Sopenharmony_ci						      mvpp2_ethtool_txq_regs[i].offset);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	/* Rxqs are numbered from 0 from the user standpoint, but not from the
17518c2ecf20Sopenharmony_ci	 * driver's. We need to add the  port->first_rxq offset.
17528c2ecf20Sopenharmony_ci	 */
17538c2ecf20Sopenharmony_ci	for (q = 0; q < port->nrxqs; q++)
17548c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(mvpp2_ethtool_rxq_regs); i++)
17558c2ecf20Sopenharmony_ci			*pstats++ += mvpp2_read_index(port->priv,
17568c2ecf20Sopenharmony_ci						      port->first_rxq + q,
17578c2ecf20Sopenharmony_ci						      mvpp2_ethtool_rxq_regs[i].offset);
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	/* Gather XDP Statistics */
17608c2ecf20Sopenharmony_ci	mvpp2_get_xdp_stats(port, &xdp_stats);
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	for (i = 0, s = mvpp2_ethtool_xdp;
17638c2ecf20Sopenharmony_ci		 s < mvpp2_ethtool_xdp + ARRAY_SIZE(mvpp2_ethtool_xdp);
17648c2ecf20Sopenharmony_ci	     s++, i++) {
17658c2ecf20Sopenharmony_ci		switch (s->offset) {
17668c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_REDIRECT:
17678c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_redirect;
17688c2ecf20Sopenharmony_ci			break;
17698c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_PASS:
17708c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_pass;
17718c2ecf20Sopenharmony_ci			break;
17728c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_DROP:
17738c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_drop;
17748c2ecf20Sopenharmony_ci			break;
17758c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_TX:
17768c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_tx;
17778c2ecf20Sopenharmony_ci			break;
17788c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_TX_ERR:
17798c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_tx_err;
17808c2ecf20Sopenharmony_ci			break;
17818c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_XMIT:
17828c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_xmit;
17838c2ecf20Sopenharmony_ci			break;
17848c2ecf20Sopenharmony_ci		case ETHTOOL_XDP_XMIT_ERR:
17858c2ecf20Sopenharmony_ci			*pstats++ = xdp_stats.xdp_xmit_err;
17868c2ecf20Sopenharmony_ci			break;
17878c2ecf20Sopenharmony_ci		}
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci}
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_cistatic void mvpp2_gather_hw_statistics(struct work_struct *work)
17928c2ecf20Sopenharmony_ci{
17938c2ecf20Sopenharmony_ci	struct delayed_work *del_work = to_delayed_work(work);
17948c2ecf20Sopenharmony_ci	struct mvpp2_port *port = container_of(del_work, struct mvpp2_port,
17958c2ecf20Sopenharmony_ci					       stats_work);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	mutex_lock(&port->gather_stats_lock);
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	mvpp2_read_stats(port);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	/* No need to read again the counters right after this function if it
18028c2ecf20Sopenharmony_ci	 * was called asynchronously by the user (ie. use of ethtool).
18038c2ecf20Sopenharmony_ci	 */
18048c2ecf20Sopenharmony_ci	cancel_delayed_work(&port->stats_work);
18058c2ecf20Sopenharmony_ci	queue_delayed_work(port->priv->stats_queue, &port->stats_work,
18068c2ecf20Sopenharmony_ci			   MVPP2_MIB_COUNTERS_STATS_DELAY);
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	mutex_unlock(&port->gather_stats_lock);
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_cistatic void mvpp2_ethtool_get_stats(struct net_device *dev,
18128c2ecf20Sopenharmony_ci				    struct ethtool_stats *stats, u64 *data)
18138c2ecf20Sopenharmony_ci{
18148c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci	/* Update statistics for the given port, then take the lock to avoid
18178c2ecf20Sopenharmony_ci	 * concurrent accesses on the ethtool_stats structure during its copy.
18188c2ecf20Sopenharmony_ci	 */
18198c2ecf20Sopenharmony_ci	mvpp2_gather_hw_statistics(&port->stats_work.work);
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_ci	mutex_lock(&port->gather_stats_lock);
18228c2ecf20Sopenharmony_ci	memcpy(data, port->ethtool_stats,
18238c2ecf20Sopenharmony_ci	       sizeof(u64) * MVPP2_N_ETHTOOL_STATS(port->ntxqs, port->nrxqs));
18248c2ecf20Sopenharmony_ci	mutex_unlock(&port->gather_stats_lock);
18258c2ecf20Sopenharmony_ci}
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_sset_count(struct net_device *dev, int sset)
18288c2ecf20Sopenharmony_ci{
18298c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_ci	if (sset == ETH_SS_STATS)
18328c2ecf20Sopenharmony_ci		return MVPP2_N_ETHTOOL_STATS(port->ntxqs, port->nrxqs);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
18358c2ecf20Sopenharmony_ci}
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_cistatic void mvpp2_mac_reset_assert(struct mvpp2_port *port)
18388c2ecf20Sopenharmony_ci{
18398c2ecf20Sopenharmony_ci	u32 val;
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP2_GMAC_CTRL_2_REG) |
18428c2ecf20Sopenharmony_ci	      MVPP2_GMAC_PORT_RESET_MASK;
18438c2ecf20Sopenharmony_ci	writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
18448c2ecf20Sopenharmony_ci
18458c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP22 && port->gop_id == 0) {
18468c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_CTRL0_REG) &
18478c2ecf20Sopenharmony_ci		      ~MVPP22_XLG_CTRL0_MAC_RESET_DIS;
18488c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_CTRL0_REG);
18498c2ecf20Sopenharmony_ci	}
18508c2ecf20Sopenharmony_ci}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_cistatic void mvpp22_pcs_reset_assert(struct mvpp2_port *port)
18538c2ecf20Sopenharmony_ci{
18548c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
18558c2ecf20Sopenharmony_ci	void __iomem *mpcs, *xpcs;
18568c2ecf20Sopenharmony_ci	u32 val;
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	if (port->priv->hw_version != MVPP22 || port->gop_id != 0)
18598c2ecf20Sopenharmony_ci		return;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id);
18628c2ecf20Sopenharmony_ci	xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id);
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	val = readl(mpcs + MVPP22_MPCS_CLK_RESET);
18658c2ecf20Sopenharmony_ci	val &= ~(MAC_CLK_RESET_MAC | MAC_CLK_RESET_SD_RX | MAC_CLK_RESET_SD_TX);
18668c2ecf20Sopenharmony_ci	val |= MVPP22_MPCS_CLK_RESET_DIV_SET;
18678c2ecf20Sopenharmony_ci	writel(val, mpcs + MVPP22_MPCS_CLK_RESET);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	val = readl(xpcs + MVPP22_XPCS_CFG0);
18708c2ecf20Sopenharmony_ci	writel(val & ~MVPP22_XPCS_CFG0_RESET_DIS, xpcs + MVPP22_XPCS_CFG0);
18718c2ecf20Sopenharmony_ci}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_cistatic void mvpp22_pcs_reset_deassert(struct mvpp2_port *port)
18748c2ecf20Sopenharmony_ci{
18758c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
18768c2ecf20Sopenharmony_ci	void __iomem *mpcs, *xpcs;
18778c2ecf20Sopenharmony_ci	u32 val;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	if (port->priv->hw_version != MVPP22 || port->gop_id != 0)
18808c2ecf20Sopenharmony_ci		return;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id);
18838c2ecf20Sopenharmony_ci	xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id);
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	switch (port->phy_interface) {
18868c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
18878c2ecf20Sopenharmony_ci		val = readl(mpcs + MVPP22_MPCS_CLK_RESET);
18888c2ecf20Sopenharmony_ci		val |= MAC_CLK_RESET_MAC | MAC_CLK_RESET_SD_RX |
18898c2ecf20Sopenharmony_ci		       MAC_CLK_RESET_SD_TX;
18908c2ecf20Sopenharmony_ci		val &= ~MVPP22_MPCS_CLK_RESET_DIV_SET;
18918c2ecf20Sopenharmony_ci		writel(val, mpcs + MVPP22_MPCS_CLK_RESET);
18928c2ecf20Sopenharmony_ci		break;
18938c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_XAUI:
18948c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RXAUI:
18958c2ecf20Sopenharmony_ci		val = readl(xpcs + MVPP22_XPCS_CFG0);
18968c2ecf20Sopenharmony_ci		writel(val | MVPP22_XPCS_CFG0_RESET_DIS, xpcs + MVPP22_XPCS_CFG0);
18978c2ecf20Sopenharmony_ci		break;
18988c2ecf20Sopenharmony_ci	default:
18998c2ecf20Sopenharmony_ci		break;
19008c2ecf20Sopenharmony_ci	}
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci/* Change maximum receive size of the port */
19048c2ecf20Sopenharmony_cistatic inline void mvpp2_gmac_max_rx_size_set(struct mvpp2_port *port)
19058c2ecf20Sopenharmony_ci{
19068c2ecf20Sopenharmony_ci	u32 val;
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
19098c2ecf20Sopenharmony_ci	val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK;
19108c2ecf20Sopenharmony_ci	val |= (((port->pkt_size - MVPP2_MH_SIZE) / 2) <<
19118c2ecf20Sopenharmony_ci		    MVPP2_GMAC_MAX_RX_SIZE_OFFS);
19128c2ecf20Sopenharmony_ci	writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
19138c2ecf20Sopenharmony_ci}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci/* Change maximum receive size of the port */
19168c2ecf20Sopenharmony_cistatic inline void mvpp2_xlg_max_rx_size_set(struct mvpp2_port *port)
19178c2ecf20Sopenharmony_ci{
19188c2ecf20Sopenharmony_ci	u32 val;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	val =  readl(port->base + MVPP22_XLG_CTRL1_REG);
19218c2ecf20Sopenharmony_ci	val &= ~MVPP22_XLG_CTRL1_FRAMESIZELIMIT_MASK;
19228c2ecf20Sopenharmony_ci	val |= ((port->pkt_size - MVPP2_MH_SIZE) / 2) <<
19238c2ecf20Sopenharmony_ci	       MVPP22_XLG_CTRL1_FRAMESIZELIMIT_OFFS;
19248c2ecf20Sopenharmony_ci	writel(val, port->base + MVPP22_XLG_CTRL1_REG);
19258c2ecf20Sopenharmony_ci}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci/* Set defaults to the MVPP2 port */
19288c2ecf20Sopenharmony_cistatic void mvpp2_defaults_set(struct mvpp2_port *port)
19298c2ecf20Sopenharmony_ci{
19308c2ecf20Sopenharmony_ci	int tx_port_num, val, queue, lrxq;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21) {
19338c2ecf20Sopenharmony_ci		/* Update TX FIFO MIN Threshold */
19348c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
19358c2ecf20Sopenharmony_ci		val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
19368c2ecf20Sopenharmony_ci		/* Min. TX threshold must be less than minimal packet length */
19378c2ecf20Sopenharmony_ci		val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2);
19388c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
19398c2ecf20Sopenharmony_ci	}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_ci	/* Disable Legacy WRR, Disable EJP, Release from reset */
19428c2ecf20Sopenharmony_ci	tx_port_num = mvpp2_egress_port(port);
19438c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG,
19448c2ecf20Sopenharmony_ci		    tx_port_num);
19458c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci	/* Set TXQ scheduling to Round-Robin */
19488c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_FIXED_PRIO_REG, 0);
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	/* Close bandwidth for all queues */
19518c2ecf20Sopenharmony_ci	for (queue = 0; queue < MVPP2_MAX_TXQ; queue++)
19528c2ecf20Sopenharmony_ci		mvpp2_write(port->priv,
19538c2ecf20Sopenharmony_ci			    MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(queue), 0);
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	/* Set refill period to 1 usec, refill tokens
19568c2ecf20Sopenharmony_ci	 * and bucket size to maximum
19578c2ecf20Sopenharmony_ci	 */
19588c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_PERIOD_REG,
19598c2ecf20Sopenharmony_ci		    port->priv->tclk / USEC_PER_SEC);
19608c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_REFILL_REG);
19618c2ecf20Sopenharmony_ci	val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK;
19628c2ecf20Sopenharmony_ci	val |= MVPP2_TXP_REFILL_PERIOD_MASK(1);
19638c2ecf20Sopenharmony_ci	val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK;
19648c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_REFILL_REG, val);
19658c2ecf20Sopenharmony_ci	val = MVPP2_TXP_TOKEN_SIZE_MAX;
19668c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci	/* Set MaximumLowLatencyPacketSize value to 256 */
19698c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RX_CTRL_REG(port->id),
19708c2ecf20Sopenharmony_ci		    MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK |
19718c2ecf20Sopenharmony_ci		    MVPP2_RX_LOW_LATENCY_PKT_SIZE(256));
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_ci	/* Enable Rx cache snoop */
19748c2ecf20Sopenharmony_ci	for (lrxq = 0; lrxq < port->nrxqs; lrxq++) {
19758c2ecf20Sopenharmony_ci		queue = port->rxqs[lrxq]->id;
19768c2ecf20Sopenharmony_ci		val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
19778c2ecf20Sopenharmony_ci		val |= MVPP2_SNOOP_PKT_SIZE_MASK |
19788c2ecf20Sopenharmony_ci			   MVPP2_SNOOP_BUF_HDR_MASK;
19798c2ecf20Sopenharmony_ci		mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
19808c2ecf20Sopenharmony_ci	}
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	/* At default, mask all interrupts to all present cpus */
19838c2ecf20Sopenharmony_ci	mvpp2_interrupts_disable(port);
19848c2ecf20Sopenharmony_ci}
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci/* Enable/disable receiving packets */
19878c2ecf20Sopenharmony_cistatic void mvpp2_ingress_enable(struct mvpp2_port *port)
19888c2ecf20Sopenharmony_ci{
19898c2ecf20Sopenharmony_ci	u32 val;
19908c2ecf20Sopenharmony_ci	int lrxq, queue;
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	for (lrxq = 0; lrxq < port->nrxqs; lrxq++) {
19938c2ecf20Sopenharmony_ci		queue = port->rxqs[lrxq]->id;
19948c2ecf20Sopenharmony_ci		val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
19958c2ecf20Sopenharmony_ci		val &= ~MVPP2_RXQ_DISABLE_MASK;
19968c2ecf20Sopenharmony_ci		mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
19978c2ecf20Sopenharmony_ci	}
19988c2ecf20Sopenharmony_ci}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_cistatic void mvpp2_ingress_disable(struct mvpp2_port *port)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	u32 val;
20038c2ecf20Sopenharmony_ci	int lrxq, queue;
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	for (lrxq = 0; lrxq < port->nrxqs; lrxq++) {
20068c2ecf20Sopenharmony_ci		queue = port->rxqs[lrxq]->id;
20078c2ecf20Sopenharmony_ci		val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
20088c2ecf20Sopenharmony_ci		val |= MVPP2_RXQ_DISABLE_MASK;
20098c2ecf20Sopenharmony_ci		mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
20108c2ecf20Sopenharmony_ci	}
20118c2ecf20Sopenharmony_ci}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci/* Enable transmit via physical egress queue
20148c2ecf20Sopenharmony_ci * - HW starts take descriptors from DRAM
20158c2ecf20Sopenharmony_ci */
20168c2ecf20Sopenharmony_cistatic void mvpp2_egress_enable(struct mvpp2_port *port)
20178c2ecf20Sopenharmony_ci{
20188c2ecf20Sopenharmony_ci	u32 qmap;
20198c2ecf20Sopenharmony_ci	int queue;
20208c2ecf20Sopenharmony_ci	int tx_port_num = mvpp2_egress_port(port);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	/* Enable all initialized TXs. */
20238c2ecf20Sopenharmony_ci	qmap = 0;
20248c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
20258c2ecf20Sopenharmony_ci		struct mvpp2_tx_queue *txq = port->txqs[queue];
20268c2ecf20Sopenharmony_ci
20278c2ecf20Sopenharmony_ci		if (txq->descs)
20288c2ecf20Sopenharmony_ci			qmap |= (1 << queue);
20298c2ecf20Sopenharmony_ci	}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
20328c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap);
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci/* Disable transmit via physical egress queue
20368c2ecf20Sopenharmony_ci * - HW doesn't take descriptors from DRAM
20378c2ecf20Sopenharmony_ci */
20388c2ecf20Sopenharmony_cistatic void mvpp2_egress_disable(struct mvpp2_port *port)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	u32 reg_data;
20418c2ecf20Sopenharmony_ci	int delay;
20428c2ecf20Sopenharmony_ci	int tx_port_num = mvpp2_egress_port(port);
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	/* Issue stop command for active channels only */
20458c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
20468c2ecf20Sopenharmony_ci	reg_data = (mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG)) &
20478c2ecf20Sopenharmony_ci		    MVPP2_TXP_SCHED_ENQ_MASK;
20488c2ecf20Sopenharmony_ci	if (reg_data != 0)
20498c2ecf20Sopenharmony_ci		mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG,
20508c2ecf20Sopenharmony_ci			    (reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET));
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_ci	/* Wait for all Tx activity to terminate. */
20538c2ecf20Sopenharmony_ci	delay = 0;
20548c2ecf20Sopenharmony_ci	do {
20558c2ecf20Sopenharmony_ci		if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
20568c2ecf20Sopenharmony_ci			netdev_warn(port->dev,
20578c2ecf20Sopenharmony_ci				    "Tx stop timed out, status=0x%08x\n",
20588c2ecf20Sopenharmony_ci				    reg_data);
20598c2ecf20Sopenharmony_ci			break;
20608c2ecf20Sopenharmony_ci		}
20618c2ecf20Sopenharmony_ci		mdelay(1);
20628c2ecf20Sopenharmony_ci		delay++;
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci		/* Check port TX Command register that all
20658c2ecf20Sopenharmony_ci		 * Tx queues are stopped
20668c2ecf20Sopenharmony_ci		 */
20678c2ecf20Sopenharmony_ci		reg_data = mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG);
20688c2ecf20Sopenharmony_ci	} while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK);
20698c2ecf20Sopenharmony_ci}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci/* Rx descriptors helper methods */
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci/* Get number of Rx descriptors occupied by received packets */
20748c2ecf20Sopenharmony_cistatic inline int
20758c2ecf20Sopenharmony_cimvpp2_rxq_received(struct mvpp2_port *port, int rxq_id)
20768c2ecf20Sopenharmony_ci{
20778c2ecf20Sopenharmony_ci	u32 val = mvpp2_read(port->priv, MVPP2_RXQ_STATUS_REG(rxq_id));
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	return val & MVPP2_RXQ_OCCUPIED_MASK;
20808c2ecf20Sopenharmony_ci}
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci/* Update Rx queue status with the number of occupied and available
20838c2ecf20Sopenharmony_ci * Rx descriptor slots.
20848c2ecf20Sopenharmony_ci */
20858c2ecf20Sopenharmony_cistatic inline void
20868c2ecf20Sopenharmony_cimvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id,
20878c2ecf20Sopenharmony_ci			int used_count, int free_count)
20888c2ecf20Sopenharmony_ci{
20898c2ecf20Sopenharmony_ci	/* Decrement the number of used descriptors and increment count
20908c2ecf20Sopenharmony_ci	 * increment the number of free descriptors.
20918c2ecf20Sopenharmony_ci	 */
20928c2ecf20Sopenharmony_ci	u32 val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val);
20958c2ecf20Sopenharmony_ci}
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci/* Get pointer to next RX descriptor to be processed by SW */
20988c2ecf20Sopenharmony_cistatic inline struct mvpp2_rx_desc *
20998c2ecf20Sopenharmony_cimvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq)
21008c2ecf20Sopenharmony_ci{
21018c2ecf20Sopenharmony_ci	int rx_desc = rxq->next_desc_to_proc;
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	rxq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(rxq, rx_desc);
21048c2ecf20Sopenharmony_ci	prefetch(rxq->descs + rxq->next_desc_to_proc);
21058c2ecf20Sopenharmony_ci	return rxq->descs + rx_desc;
21068c2ecf20Sopenharmony_ci}
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci/* Set rx queue offset */
21098c2ecf20Sopenharmony_cistatic void mvpp2_rxq_offset_set(struct mvpp2_port *port,
21108c2ecf20Sopenharmony_ci				 int prxq, int offset)
21118c2ecf20Sopenharmony_ci{
21128c2ecf20Sopenharmony_ci	u32 val;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	/* Convert offset from bytes to units of 32 bytes */
21158c2ecf20Sopenharmony_ci	offset = offset >> 5;
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
21188c2ecf20Sopenharmony_ci	val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK;
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	/* Offset is in */
21218c2ecf20Sopenharmony_ci	val |= ((offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) &
21228c2ecf20Sopenharmony_ci		    MVPP2_RXQ_PACKET_OFFSET_MASK);
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
21258c2ecf20Sopenharmony_ci}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci/* Tx descriptors helper methods */
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci/* Get pointer to next Tx descriptor to be processed (send) by HW */
21308c2ecf20Sopenharmony_cistatic struct mvpp2_tx_desc *
21318c2ecf20Sopenharmony_cimvpp2_txq_next_desc_get(struct mvpp2_tx_queue *txq)
21328c2ecf20Sopenharmony_ci{
21338c2ecf20Sopenharmony_ci	int tx_desc = txq->next_desc_to_proc;
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_ci	txq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(txq, tx_desc);
21368c2ecf20Sopenharmony_ci	return txq->descs + tx_desc;
21378c2ecf20Sopenharmony_ci}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci/* Update HW with number of aggregated Tx descriptors to be sent
21408c2ecf20Sopenharmony_ci *
21418c2ecf20Sopenharmony_ci * Called only from mvpp2_tx(), so migration is disabled, using
21428c2ecf20Sopenharmony_ci * smp_processor_id() is OK.
21438c2ecf20Sopenharmony_ci */
21448c2ecf20Sopenharmony_cistatic void mvpp2_aggr_txq_pend_desc_add(struct mvpp2_port *port, int pending)
21458c2ecf20Sopenharmony_ci{
21468c2ecf20Sopenharmony_ci	/* aggregated access - relevant TXQ number is written in TX desc */
21478c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv,
21488c2ecf20Sopenharmony_ci			   mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
21498c2ecf20Sopenharmony_ci			   MVPP2_AGGR_TXQ_UPDATE_REG, pending);
21508c2ecf20Sopenharmony_ci}
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci/* Check if there are enough free descriptors in aggregated txq.
21538c2ecf20Sopenharmony_ci * If not, update the number of occupied descriptors and repeat the check.
21548c2ecf20Sopenharmony_ci *
21558c2ecf20Sopenharmony_ci * Called only from mvpp2_tx(), so migration is disabled, using
21568c2ecf20Sopenharmony_ci * smp_processor_id() is OK.
21578c2ecf20Sopenharmony_ci */
21588c2ecf20Sopenharmony_cistatic int mvpp2_aggr_desc_num_check(struct mvpp2_port *port,
21598c2ecf20Sopenharmony_ci				     struct mvpp2_tx_queue *aggr_txq, int num)
21608c2ecf20Sopenharmony_ci{
21618c2ecf20Sopenharmony_ci	if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE) {
21628c2ecf20Sopenharmony_ci		/* Update number of occupied aggregated Tx descriptors */
21638c2ecf20Sopenharmony_ci		unsigned int thread =
21648c2ecf20Sopenharmony_ci			mvpp2_cpu_to_thread(port->priv, smp_processor_id());
21658c2ecf20Sopenharmony_ci		u32 val = mvpp2_read_relaxed(port->priv,
21668c2ecf20Sopenharmony_ci					     MVPP2_AGGR_TXQ_STATUS_REG(thread));
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci		aggr_txq->count = val & MVPP2_AGGR_TXQ_PENDING_MASK;
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci		if ((aggr_txq->count + num) > MVPP2_AGGR_TXQ_SIZE)
21718c2ecf20Sopenharmony_ci			return -ENOMEM;
21728c2ecf20Sopenharmony_ci	}
21738c2ecf20Sopenharmony_ci	return 0;
21748c2ecf20Sopenharmony_ci}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci/* Reserved Tx descriptors allocation request
21778c2ecf20Sopenharmony_ci *
21788c2ecf20Sopenharmony_ci * Called only from mvpp2_txq_reserved_desc_num_proc(), itself called
21798c2ecf20Sopenharmony_ci * only by mvpp2_tx(), so migration is disabled, using
21808c2ecf20Sopenharmony_ci * smp_processor_id() is OK.
21818c2ecf20Sopenharmony_ci */
21828c2ecf20Sopenharmony_cistatic int mvpp2_txq_alloc_reserved_desc(struct mvpp2_port *port,
21838c2ecf20Sopenharmony_ci					 struct mvpp2_tx_queue *txq, int num)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
21868c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
21878c2ecf20Sopenharmony_ci	u32 val;
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	val = (txq->id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | num;
21908c2ecf20Sopenharmony_ci	mvpp2_thread_write_relaxed(priv, thread, MVPP2_TXQ_RSVD_REQ_REG, val);
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci	val = mvpp2_thread_read_relaxed(priv, thread, MVPP2_TXQ_RSVD_RSLT_REG);
21938c2ecf20Sopenharmony_ci
21948c2ecf20Sopenharmony_ci	return val & MVPP2_TXQ_RSVD_RSLT_MASK;
21958c2ecf20Sopenharmony_ci}
21968c2ecf20Sopenharmony_ci
21978c2ecf20Sopenharmony_ci/* Check if there are enough reserved descriptors for transmission.
21988c2ecf20Sopenharmony_ci * If not, request chunk of reserved descriptors and check again.
21998c2ecf20Sopenharmony_ci */
22008c2ecf20Sopenharmony_cistatic int mvpp2_txq_reserved_desc_num_proc(struct mvpp2_port *port,
22018c2ecf20Sopenharmony_ci					    struct mvpp2_tx_queue *txq,
22028c2ecf20Sopenharmony_ci					    struct mvpp2_txq_pcpu *txq_pcpu,
22038c2ecf20Sopenharmony_ci					    int num)
22048c2ecf20Sopenharmony_ci{
22058c2ecf20Sopenharmony_ci	int req, desc_count;
22068c2ecf20Sopenharmony_ci	unsigned int thread;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci	if (txq_pcpu->reserved_num >= num)
22098c2ecf20Sopenharmony_ci		return 0;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	/* Not enough descriptors reserved! Update the reserved descriptor
22128c2ecf20Sopenharmony_ci	 * count and check again.
22138c2ecf20Sopenharmony_ci	 */
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci	desc_count = 0;
22168c2ecf20Sopenharmony_ci	/* Compute total of used descriptors */
22178c2ecf20Sopenharmony_ci	for (thread = 0; thread < port->priv->nthreads; thread++) {
22188c2ecf20Sopenharmony_ci		struct mvpp2_txq_pcpu *txq_pcpu_aux;
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci		txq_pcpu_aux = per_cpu_ptr(txq->pcpu, thread);
22218c2ecf20Sopenharmony_ci		desc_count += txq_pcpu_aux->count;
22228c2ecf20Sopenharmony_ci		desc_count += txq_pcpu_aux->reserved_num;
22238c2ecf20Sopenharmony_ci	}
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	req = max(MVPP2_CPU_DESC_CHUNK, num - txq_pcpu->reserved_num);
22268c2ecf20Sopenharmony_ci	desc_count += req;
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	if (desc_count >
22298c2ecf20Sopenharmony_ci	   (txq->size - (MVPP2_MAX_THREADS * MVPP2_CPU_DESC_CHUNK)))
22308c2ecf20Sopenharmony_ci		return -ENOMEM;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci	txq_pcpu->reserved_num += mvpp2_txq_alloc_reserved_desc(port, txq, req);
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	/* OK, the descriptor could have been updated: check again. */
22358c2ecf20Sopenharmony_ci	if (txq_pcpu->reserved_num < num)
22368c2ecf20Sopenharmony_ci		return -ENOMEM;
22378c2ecf20Sopenharmony_ci	return 0;
22388c2ecf20Sopenharmony_ci}
22398c2ecf20Sopenharmony_ci
22408c2ecf20Sopenharmony_ci/* Release the last allocated Tx descriptor. Useful to handle DMA
22418c2ecf20Sopenharmony_ci * mapping failures in the Tx path.
22428c2ecf20Sopenharmony_ci */
22438c2ecf20Sopenharmony_cistatic void mvpp2_txq_desc_put(struct mvpp2_tx_queue *txq)
22448c2ecf20Sopenharmony_ci{
22458c2ecf20Sopenharmony_ci	if (txq->next_desc_to_proc == 0)
22468c2ecf20Sopenharmony_ci		txq->next_desc_to_proc = txq->last_desc - 1;
22478c2ecf20Sopenharmony_ci	else
22488c2ecf20Sopenharmony_ci		txq->next_desc_to_proc--;
22498c2ecf20Sopenharmony_ci}
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci/* Set Tx descriptors fields relevant for CSUM calculation */
22528c2ecf20Sopenharmony_cistatic u32 mvpp2_txq_desc_csum(int l3_offs, __be16 l3_proto,
22538c2ecf20Sopenharmony_ci			       int ip_hdr_len, int l4_proto)
22548c2ecf20Sopenharmony_ci{
22558c2ecf20Sopenharmony_ci	u32 command;
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	/* fields: L3_offset, IP_hdrlen, L3_type, G_IPv4_chk,
22588c2ecf20Sopenharmony_ci	 * G_L4_chk, L4_type required only for checksum calculation
22598c2ecf20Sopenharmony_ci	 */
22608c2ecf20Sopenharmony_ci	command = (l3_offs << MVPP2_TXD_L3_OFF_SHIFT);
22618c2ecf20Sopenharmony_ci	command |= (ip_hdr_len << MVPP2_TXD_IP_HLEN_SHIFT);
22628c2ecf20Sopenharmony_ci	command |= MVPP2_TXD_IP_CSUM_DISABLE;
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci	if (l3_proto == htons(ETH_P_IP)) {
22658c2ecf20Sopenharmony_ci		command &= ~MVPP2_TXD_IP_CSUM_DISABLE;	/* enable IPv4 csum */
22668c2ecf20Sopenharmony_ci		command &= ~MVPP2_TXD_L3_IP6;		/* enable IPv4 */
22678c2ecf20Sopenharmony_ci	} else {
22688c2ecf20Sopenharmony_ci		command |= MVPP2_TXD_L3_IP6;		/* enable IPv6 */
22698c2ecf20Sopenharmony_ci	}
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	if (l4_proto == IPPROTO_TCP) {
22728c2ecf20Sopenharmony_ci		command &= ~MVPP2_TXD_L4_UDP;		/* enable TCP */
22738c2ecf20Sopenharmony_ci		command &= ~MVPP2_TXD_L4_CSUM_FRAG;	/* generate L4 csum */
22748c2ecf20Sopenharmony_ci	} else if (l4_proto == IPPROTO_UDP) {
22758c2ecf20Sopenharmony_ci		command |= MVPP2_TXD_L4_UDP;		/* enable UDP */
22768c2ecf20Sopenharmony_ci		command &= ~MVPP2_TXD_L4_CSUM_FRAG;	/* generate L4 csum */
22778c2ecf20Sopenharmony_ci	} else {
22788c2ecf20Sopenharmony_ci		command |= MVPP2_TXD_L4_CSUM_NOT;
22798c2ecf20Sopenharmony_ci	}
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_ci	return command;
22828c2ecf20Sopenharmony_ci}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci/* Get number of sent descriptors and decrement counter.
22858c2ecf20Sopenharmony_ci * The number of sent descriptors is returned.
22868c2ecf20Sopenharmony_ci * Per-thread access
22878c2ecf20Sopenharmony_ci *
22888c2ecf20Sopenharmony_ci * Called only from mvpp2_txq_done(), called from mvpp2_tx()
22898c2ecf20Sopenharmony_ci * (migration disabled) and from the TX completion tasklet (migration
22908c2ecf20Sopenharmony_ci * disabled) so using smp_processor_id() is OK.
22918c2ecf20Sopenharmony_ci */
22928c2ecf20Sopenharmony_cistatic inline int mvpp2_txq_sent_desc_proc(struct mvpp2_port *port,
22938c2ecf20Sopenharmony_ci					   struct mvpp2_tx_queue *txq)
22948c2ecf20Sopenharmony_ci{
22958c2ecf20Sopenharmony_ci	u32 val;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	/* Reading status reg resets transmitted descriptor counter */
22988c2ecf20Sopenharmony_ci	val = mvpp2_thread_read_relaxed(port->priv,
22998c2ecf20Sopenharmony_ci					mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
23008c2ecf20Sopenharmony_ci					MVPP2_TXQ_SENT_REG(txq->id));
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	return (val & MVPP2_TRANSMITTED_COUNT_MASK) >>
23038c2ecf20Sopenharmony_ci		MVPP2_TRANSMITTED_COUNT_OFFSET;
23048c2ecf20Sopenharmony_ci}
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci/* Called through on_each_cpu(), so runs on all CPUs, with migration
23078c2ecf20Sopenharmony_ci * disabled, therefore using smp_processor_id() is OK.
23088c2ecf20Sopenharmony_ci */
23098c2ecf20Sopenharmony_cistatic void mvpp2_txq_sent_counter_clear(void *arg)
23108c2ecf20Sopenharmony_ci{
23118c2ecf20Sopenharmony_ci	struct mvpp2_port *port = arg;
23128c2ecf20Sopenharmony_ci	int queue;
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	/* If the thread isn't used, don't do anything */
23158c2ecf20Sopenharmony_ci	if (smp_processor_id() >= port->priv->nthreads)
23168c2ecf20Sopenharmony_ci		return;
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
23198c2ecf20Sopenharmony_ci		int id = port->txqs[queue]->id;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci		mvpp2_thread_read(port->priv,
23228c2ecf20Sopenharmony_ci				  mvpp2_cpu_to_thread(port->priv, smp_processor_id()),
23238c2ecf20Sopenharmony_ci				  MVPP2_TXQ_SENT_REG(id));
23248c2ecf20Sopenharmony_ci	}
23258c2ecf20Sopenharmony_ci}
23268c2ecf20Sopenharmony_ci
23278c2ecf20Sopenharmony_ci/* Set max sizes for Tx queues */
23288c2ecf20Sopenharmony_cistatic void mvpp2_txp_max_tx_size_set(struct mvpp2_port *port)
23298c2ecf20Sopenharmony_ci{
23308c2ecf20Sopenharmony_ci	u32	val, size, mtu;
23318c2ecf20Sopenharmony_ci	int	txq, tx_port_num;
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ci	mtu = port->pkt_size * 8;
23348c2ecf20Sopenharmony_ci	if (mtu > MVPP2_TXP_MTU_MAX)
23358c2ecf20Sopenharmony_ci		mtu = MVPP2_TXP_MTU_MAX;
23368c2ecf20Sopenharmony_ci
23378c2ecf20Sopenharmony_ci	/* WA for wrong Token bucket update: Set MTU value = 3*real MTU value */
23388c2ecf20Sopenharmony_ci	mtu = 3 * mtu;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	/* Indirect access to registers */
23418c2ecf20Sopenharmony_ci	tx_port_num = mvpp2_egress_port(port);
23428c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	/* Set MTU */
23458c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_MTU_REG);
23468c2ecf20Sopenharmony_ci	val &= ~MVPP2_TXP_MTU_MAX;
23478c2ecf20Sopenharmony_ci	val |= mtu;
23488c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_MTU_REG, val);
23498c2ecf20Sopenharmony_ci
23508c2ecf20Sopenharmony_ci	/* TXP token size and all TXQs token size must be larger that MTU */
23518c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG);
23528c2ecf20Sopenharmony_ci	size = val & MVPP2_TXP_TOKEN_SIZE_MAX;
23538c2ecf20Sopenharmony_ci	if (size < mtu) {
23548c2ecf20Sopenharmony_ci		size = mtu;
23558c2ecf20Sopenharmony_ci		val &= ~MVPP2_TXP_TOKEN_SIZE_MAX;
23568c2ecf20Sopenharmony_ci		val |= size;
23578c2ecf20Sopenharmony_ci		mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
23588c2ecf20Sopenharmony_ci	}
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	for (txq = 0; txq < port->ntxqs; txq++) {
23618c2ecf20Sopenharmony_ci		val = mvpp2_read(port->priv,
23628c2ecf20Sopenharmony_ci				 MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq));
23638c2ecf20Sopenharmony_ci		size = val & MVPP2_TXQ_TOKEN_SIZE_MAX;
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci		if (size < mtu) {
23668c2ecf20Sopenharmony_ci			size = mtu;
23678c2ecf20Sopenharmony_ci			val &= ~MVPP2_TXQ_TOKEN_SIZE_MAX;
23688c2ecf20Sopenharmony_ci			val |= size;
23698c2ecf20Sopenharmony_ci			mvpp2_write(port->priv,
23708c2ecf20Sopenharmony_ci				    MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq),
23718c2ecf20Sopenharmony_ci				    val);
23728c2ecf20Sopenharmony_ci		}
23738c2ecf20Sopenharmony_ci	}
23748c2ecf20Sopenharmony_ci}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci/* Set the number of packets that will be received before Rx interrupt
23778c2ecf20Sopenharmony_ci * will be generated by HW.
23788c2ecf20Sopenharmony_ci */
23798c2ecf20Sopenharmony_cistatic void mvpp2_rx_pkts_coal_set(struct mvpp2_port *port,
23808c2ecf20Sopenharmony_ci				   struct mvpp2_rx_queue *rxq)
23818c2ecf20Sopenharmony_ci{
23828c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	if (rxq->pkts_coal > MVPP2_OCCUPIED_THRESH_MASK)
23858c2ecf20Sopenharmony_ci		rxq->pkts_coal = MVPP2_OCCUPIED_THRESH_MASK;
23868c2ecf20Sopenharmony_ci
23878c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id);
23888c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_THRESH_REG,
23898c2ecf20Sopenharmony_ci			   rxq->pkts_coal);
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci	put_cpu();
23928c2ecf20Sopenharmony_ci}
23938c2ecf20Sopenharmony_ci
23948c2ecf20Sopenharmony_ci/* For some reason in the LSP this is done on each CPU. Why ? */
23958c2ecf20Sopenharmony_cistatic void mvpp2_tx_pkts_coal_set(struct mvpp2_port *port,
23968c2ecf20Sopenharmony_ci				   struct mvpp2_tx_queue *txq)
23978c2ecf20Sopenharmony_ci{
23988c2ecf20Sopenharmony_ci	unsigned int thread;
23998c2ecf20Sopenharmony_ci	u32 val;
24008c2ecf20Sopenharmony_ci
24018c2ecf20Sopenharmony_ci	if (txq->done_pkts_coal > MVPP2_TXQ_THRESH_MASK)
24028c2ecf20Sopenharmony_ci		txq->done_pkts_coal = MVPP2_TXQ_THRESH_MASK;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	val = (txq->done_pkts_coal << MVPP2_TXQ_THRESH_OFFSET);
24058c2ecf20Sopenharmony_ci	/* PKT-coalescing registers are per-queue + per-thread */
24068c2ecf20Sopenharmony_ci	for (thread = 0; thread < MVPP2_MAX_THREADS; thread++) {
24078c2ecf20Sopenharmony_ci		mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
24088c2ecf20Sopenharmony_ci		mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_THRESH_REG, val);
24098c2ecf20Sopenharmony_ci	}
24108c2ecf20Sopenharmony_ci}
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_cistatic u32 mvpp2_usec_to_cycles(u32 usec, unsigned long clk_hz)
24138c2ecf20Sopenharmony_ci{
24148c2ecf20Sopenharmony_ci	u64 tmp = (u64)clk_hz * usec;
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	do_div(tmp, USEC_PER_SEC);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	return tmp > U32_MAX ? U32_MAX : tmp;
24198c2ecf20Sopenharmony_ci}
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_cistatic u32 mvpp2_cycles_to_usec(u32 cycles, unsigned long clk_hz)
24228c2ecf20Sopenharmony_ci{
24238c2ecf20Sopenharmony_ci	u64 tmp = (u64)cycles * USEC_PER_SEC;
24248c2ecf20Sopenharmony_ci
24258c2ecf20Sopenharmony_ci	do_div(tmp, clk_hz);
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	return tmp > U32_MAX ? U32_MAX : tmp;
24288c2ecf20Sopenharmony_ci}
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci/* Set the time delay in usec before Rx interrupt */
24318c2ecf20Sopenharmony_cistatic void mvpp2_rx_time_coal_set(struct mvpp2_port *port,
24328c2ecf20Sopenharmony_ci				   struct mvpp2_rx_queue *rxq)
24338c2ecf20Sopenharmony_ci{
24348c2ecf20Sopenharmony_ci	unsigned long freq = port->priv->tclk;
24358c2ecf20Sopenharmony_ci	u32 val = mvpp2_usec_to_cycles(rxq->time_coal, freq);
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	if (val > MVPP2_MAX_ISR_RX_THRESHOLD) {
24388c2ecf20Sopenharmony_ci		rxq->time_coal =
24398c2ecf20Sopenharmony_ci			mvpp2_cycles_to_usec(MVPP2_MAX_ISR_RX_THRESHOLD, freq);
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_ci		/* re-evaluate to get actual register value */
24428c2ecf20Sopenharmony_ci		val = mvpp2_usec_to_cycles(rxq->time_coal, freq);
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_ISR_RX_THRESHOLD_REG(rxq->id), val);
24468c2ecf20Sopenharmony_ci}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_cistatic void mvpp2_tx_time_coal_set(struct mvpp2_port *port)
24498c2ecf20Sopenharmony_ci{
24508c2ecf20Sopenharmony_ci	unsigned long freq = port->priv->tclk;
24518c2ecf20Sopenharmony_ci	u32 val = mvpp2_usec_to_cycles(port->tx_time_coal, freq);
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	if (val > MVPP2_MAX_ISR_TX_THRESHOLD) {
24548c2ecf20Sopenharmony_ci		port->tx_time_coal =
24558c2ecf20Sopenharmony_ci			mvpp2_cycles_to_usec(MVPP2_MAX_ISR_TX_THRESHOLD, freq);
24568c2ecf20Sopenharmony_ci
24578c2ecf20Sopenharmony_ci		/* re-evaluate to get actual register value */
24588c2ecf20Sopenharmony_ci		val = mvpp2_usec_to_cycles(port->tx_time_coal, freq);
24598c2ecf20Sopenharmony_ci	}
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_ISR_TX_THRESHOLD_REG(port->id), val);
24628c2ecf20Sopenharmony_ci}
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci/* Free Tx queue skbuffs */
24658c2ecf20Sopenharmony_cistatic void mvpp2_txq_bufs_free(struct mvpp2_port *port,
24668c2ecf20Sopenharmony_ci				struct mvpp2_tx_queue *txq,
24678c2ecf20Sopenharmony_ci				struct mvpp2_txq_pcpu *txq_pcpu, int num)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci	int i;
24708c2ecf20Sopenharmony_ci
24718c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
24728c2ecf20Sopenharmony_ci		struct mvpp2_txq_pcpu_buf *tx_buf =
24738c2ecf20Sopenharmony_ci			txq_pcpu->buffs + txq_pcpu->txq_get_index;
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci		if (!IS_TSO_HEADER(txq_pcpu, tx_buf->dma) &&
24768c2ecf20Sopenharmony_ci		    tx_buf->type != MVPP2_TYPE_XDP_TX)
24778c2ecf20Sopenharmony_ci			dma_unmap_single(port->dev->dev.parent, tx_buf->dma,
24788c2ecf20Sopenharmony_ci					 tx_buf->size, DMA_TO_DEVICE);
24798c2ecf20Sopenharmony_ci		if (tx_buf->type == MVPP2_TYPE_SKB && tx_buf->skb)
24808c2ecf20Sopenharmony_ci			dev_kfree_skb_any(tx_buf->skb);
24818c2ecf20Sopenharmony_ci		else if (tx_buf->type == MVPP2_TYPE_XDP_TX ||
24828c2ecf20Sopenharmony_ci			 tx_buf->type == MVPP2_TYPE_XDP_NDO)
24838c2ecf20Sopenharmony_ci			xdp_return_frame(tx_buf->xdpf);
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci		mvpp2_txq_inc_get(txq_pcpu);
24868c2ecf20Sopenharmony_ci	}
24878c2ecf20Sopenharmony_ci}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_cistatic inline struct mvpp2_rx_queue *mvpp2_get_rx_queue(struct mvpp2_port *port,
24908c2ecf20Sopenharmony_ci							u32 cause)
24918c2ecf20Sopenharmony_ci{
24928c2ecf20Sopenharmony_ci	int queue = fls(cause) - 1;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	return port->rxqs[queue];
24958c2ecf20Sopenharmony_ci}
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_cistatic inline struct mvpp2_tx_queue *mvpp2_get_tx_queue(struct mvpp2_port *port,
24988c2ecf20Sopenharmony_ci							u32 cause)
24998c2ecf20Sopenharmony_ci{
25008c2ecf20Sopenharmony_ci	int queue = fls(cause) - 1;
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_ci	return port->txqs[queue];
25038c2ecf20Sopenharmony_ci}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci/* Handle end of transmission */
25068c2ecf20Sopenharmony_cistatic void mvpp2_txq_done(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
25078c2ecf20Sopenharmony_ci			   struct mvpp2_txq_pcpu *txq_pcpu)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	struct netdev_queue *nq = netdev_get_tx_queue(port->dev, txq->log_id);
25108c2ecf20Sopenharmony_ci	int tx_done;
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	if (txq_pcpu->thread != mvpp2_cpu_to_thread(port->priv, smp_processor_id()))
25138c2ecf20Sopenharmony_ci		netdev_err(port->dev, "wrong cpu on the end of Tx processing\n");
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	tx_done = mvpp2_txq_sent_desc_proc(port, txq);
25168c2ecf20Sopenharmony_ci	if (!tx_done)
25178c2ecf20Sopenharmony_ci		return;
25188c2ecf20Sopenharmony_ci	mvpp2_txq_bufs_free(port, txq, txq_pcpu, tx_done);
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	txq_pcpu->count -= tx_done;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	if (netif_tx_queue_stopped(nq))
25238c2ecf20Sopenharmony_ci		if (txq_pcpu->count <= txq_pcpu->wake_threshold)
25248c2ecf20Sopenharmony_ci			netif_tx_wake_queue(nq);
25258c2ecf20Sopenharmony_ci}
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_cistatic unsigned int mvpp2_tx_done(struct mvpp2_port *port, u32 cause,
25288c2ecf20Sopenharmony_ci				  unsigned int thread)
25298c2ecf20Sopenharmony_ci{
25308c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *txq;
25318c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
25328c2ecf20Sopenharmony_ci	unsigned int tx_todo = 0;
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	while (cause) {
25358c2ecf20Sopenharmony_ci		txq = mvpp2_get_tx_queue(port, cause);
25368c2ecf20Sopenharmony_ci		if (!txq)
25378c2ecf20Sopenharmony_ci			break;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_ci		txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
25408c2ecf20Sopenharmony_ci
25418c2ecf20Sopenharmony_ci		if (txq_pcpu->count) {
25428c2ecf20Sopenharmony_ci			mvpp2_txq_done(port, txq, txq_pcpu);
25438c2ecf20Sopenharmony_ci			tx_todo += txq_pcpu->count;
25448c2ecf20Sopenharmony_ci		}
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci		cause &= ~(1 << txq->log_id);
25478c2ecf20Sopenharmony_ci	}
25488c2ecf20Sopenharmony_ci	return tx_todo;
25498c2ecf20Sopenharmony_ci}
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci/* Rx/Tx queue initialization/cleanup methods */
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci/* Allocate and initialize descriptors for aggr TXQ */
25548c2ecf20Sopenharmony_cistatic int mvpp2_aggr_txq_init(struct platform_device *pdev,
25558c2ecf20Sopenharmony_ci			       struct mvpp2_tx_queue *aggr_txq,
25568c2ecf20Sopenharmony_ci			       unsigned int thread, struct mvpp2 *priv)
25578c2ecf20Sopenharmony_ci{
25588c2ecf20Sopenharmony_ci	u32 txq_dma;
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	/* Allocate memory for TX descriptors */
25618c2ecf20Sopenharmony_ci	aggr_txq->descs = dma_alloc_coherent(&pdev->dev,
25628c2ecf20Sopenharmony_ci					     MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
25638c2ecf20Sopenharmony_ci					     &aggr_txq->descs_dma, GFP_KERNEL);
25648c2ecf20Sopenharmony_ci	if (!aggr_txq->descs)
25658c2ecf20Sopenharmony_ci		return -ENOMEM;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci	aggr_txq->last_desc = MVPP2_AGGR_TXQ_SIZE - 1;
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	/* Aggr TXQ no reset WA */
25708c2ecf20Sopenharmony_ci	aggr_txq->next_desc_to_proc = mvpp2_read(priv,
25718c2ecf20Sopenharmony_ci						 MVPP2_AGGR_TXQ_INDEX_REG(thread));
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	/* Set Tx descriptors queue starting address indirect
25748c2ecf20Sopenharmony_ci	 * access
25758c2ecf20Sopenharmony_ci	 */
25768c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
25778c2ecf20Sopenharmony_ci		txq_dma = aggr_txq->descs_dma;
25788c2ecf20Sopenharmony_ci	else
25798c2ecf20Sopenharmony_ci		txq_dma = aggr_txq->descs_dma >>
25808c2ecf20Sopenharmony_ci			MVPP22_AGGR_TXQ_DESC_ADDR_OFFS;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(thread), txq_dma);
25838c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(thread),
25848c2ecf20Sopenharmony_ci		    MVPP2_AGGR_TXQ_SIZE);
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	return 0;
25878c2ecf20Sopenharmony_ci}
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci/* Create a specified Rx queue */
25908c2ecf20Sopenharmony_cistatic int mvpp2_rxq_init(struct mvpp2_port *port,
25918c2ecf20Sopenharmony_ci			  struct mvpp2_rx_queue *rxq)
25928c2ecf20Sopenharmony_ci{
25938c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
25948c2ecf20Sopenharmony_ci	unsigned int thread;
25958c2ecf20Sopenharmony_ci	u32 rxq_dma;
25968c2ecf20Sopenharmony_ci	int err;
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	rxq->size = port->rx_ring_size;
25998c2ecf20Sopenharmony_ci
26008c2ecf20Sopenharmony_ci	/* Allocate memory for RX descriptors */
26018c2ecf20Sopenharmony_ci	rxq->descs = dma_alloc_coherent(port->dev->dev.parent,
26028c2ecf20Sopenharmony_ci					rxq->size * MVPP2_DESC_ALIGNED_SIZE,
26038c2ecf20Sopenharmony_ci					&rxq->descs_dma, GFP_KERNEL);
26048c2ecf20Sopenharmony_ci	if (!rxq->descs)
26058c2ecf20Sopenharmony_ci		return -ENOMEM;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	rxq->last_desc = rxq->size - 1;
26088c2ecf20Sopenharmony_ci
26098c2ecf20Sopenharmony_ci	/* Zero occupied and non-occupied counters - direct access */
26108c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0);
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	/* Set Rx descriptors queue starting address - indirect access */
26138c2ecf20Sopenharmony_ci	thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
26148c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id);
26158c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21)
26168c2ecf20Sopenharmony_ci		rxq_dma = rxq->descs_dma;
26178c2ecf20Sopenharmony_ci	else
26188c2ecf20Sopenharmony_ci		rxq_dma = rxq->descs_dma >> MVPP22_DESC_ADDR_OFFS;
26198c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma);
26208c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, rxq->size);
26218c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_INDEX_REG, 0);
26228c2ecf20Sopenharmony_ci	put_cpu();
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	/* Set Offset */
26258c2ecf20Sopenharmony_ci	mvpp2_rxq_offset_set(port, rxq->id, MVPP2_SKB_HEADROOM);
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	/* Set coalescing pkts and time */
26288c2ecf20Sopenharmony_ci	mvpp2_rx_pkts_coal_set(port, rxq);
26298c2ecf20Sopenharmony_ci	mvpp2_rx_time_coal_set(port, rxq);
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	/* Add number of descriptors ready for receiving packets */
26328c2ecf20Sopenharmony_ci	mvpp2_rxq_status_update(port, rxq->id, 0, rxq->size);
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	if (priv->percpu_pools) {
26358c2ecf20Sopenharmony_ci		err = xdp_rxq_info_reg(&rxq->xdp_rxq_short, port->dev, rxq->logic_rxq);
26368c2ecf20Sopenharmony_ci		if (err < 0)
26378c2ecf20Sopenharmony_ci			goto err_free_dma;
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_ci		err = xdp_rxq_info_reg(&rxq->xdp_rxq_long, port->dev, rxq->logic_rxq);
26408c2ecf20Sopenharmony_ci		if (err < 0)
26418c2ecf20Sopenharmony_ci			goto err_unregister_rxq_short;
26428c2ecf20Sopenharmony_ci
26438c2ecf20Sopenharmony_ci		/* Every RXQ has a pool for short and another for long packets */
26448c2ecf20Sopenharmony_ci		err = xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq_short,
26458c2ecf20Sopenharmony_ci						 MEM_TYPE_PAGE_POOL,
26468c2ecf20Sopenharmony_ci						 priv->page_pool[rxq->logic_rxq]);
26478c2ecf20Sopenharmony_ci		if (err < 0)
26488c2ecf20Sopenharmony_ci			goto err_unregister_rxq_long;
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci		err = xdp_rxq_info_reg_mem_model(&rxq->xdp_rxq_long,
26518c2ecf20Sopenharmony_ci						 MEM_TYPE_PAGE_POOL,
26528c2ecf20Sopenharmony_ci						 priv->page_pool[rxq->logic_rxq +
26538c2ecf20Sopenharmony_ci								 port->nrxqs]);
26548c2ecf20Sopenharmony_ci		if (err < 0)
26558c2ecf20Sopenharmony_ci			goto err_unregister_mem_rxq_short;
26568c2ecf20Sopenharmony_ci	}
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	return 0;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_cierr_unregister_mem_rxq_short:
26618c2ecf20Sopenharmony_ci	xdp_rxq_info_unreg_mem_model(&rxq->xdp_rxq_short);
26628c2ecf20Sopenharmony_cierr_unregister_rxq_long:
26638c2ecf20Sopenharmony_ci	xdp_rxq_info_unreg(&rxq->xdp_rxq_long);
26648c2ecf20Sopenharmony_cierr_unregister_rxq_short:
26658c2ecf20Sopenharmony_ci	xdp_rxq_info_unreg(&rxq->xdp_rxq_short);
26668c2ecf20Sopenharmony_cierr_free_dma:
26678c2ecf20Sopenharmony_ci	dma_free_coherent(port->dev->dev.parent,
26688c2ecf20Sopenharmony_ci			  rxq->size * MVPP2_DESC_ALIGNED_SIZE,
26698c2ecf20Sopenharmony_ci			  rxq->descs, rxq->descs_dma);
26708c2ecf20Sopenharmony_ci	return err;
26718c2ecf20Sopenharmony_ci}
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci/* Push packets received by the RXQ to BM pool */
26748c2ecf20Sopenharmony_cistatic void mvpp2_rxq_drop_pkts(struct mvpp2_port *port,
26758c2ecf20Sopenharmony_ci				struct mvpp2_rx_queue *rxq)
26768c2ecf20Sopenharmony_ci{
26778c2ecf20Sopenharmony_ci	int rx_received, i;
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	rx_received = mvpp2_rxq_received(port, rxq->id);
26808c2ecf20Sopenharmony_ci	if (!rx_received)
26818c2ecf20Sopenharmony_ci		return;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	for (i = 0; i < rx_received; i++) {
26848c2ecf20Sopenharmony_ci		struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq);
26858c2ecf20Sopenharmony_ci		u32 status = mvpp2_rxdesc_status_get(port, rx_desc);
26868c2ecf20Sopenharmony_ci		int pool;
26878c2ecf20Sopenharmony_ci
26888c2ecf20Sopenharmony_ci		pool = (status & MVPP2_RXD_BM_POOL_ID_MASK) >>
26898c2ecf20Sopenharmony_ci			MVPP2_RXD_BM_POOL_ID_OFFS;
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci		mvpp2_bm_pool_put(port, pool,
26928c2ecf20Sopenharmony_ci				  mvpp2_rxdesc_dma_addr_get(port, rx_desc),
26938c2ecf20Sopenharmony_ci				  mvpp2_rxdesc_cookie_get(port, rx_desc));
26948c2ecf20Sopenharmony_ci	}
26958c2ecf20Sopenharmony_ci	mvpp2_rxq_status_update(port, rxq->id, rx_received, rx_received);
26968c2ecf20Sopenharmony_ci}
26978c2ecf20Sopenharmony_ci
26988c2ecf20Sopenharmony_ci/* Cleanup Rx queue */
26998c2ecf20Sopenharmony_cistatic void mvpp2_rxq_deinit(struct mvpp2_port *port,
27008c2ecf20Sopenharmony_ci			     struct mvpp2_rx_queue *rxq)
27018c2ecf20Sopenharmony_ci{
27028c2ecf20Sopenharmony_ci	unsigned int thread;
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_ci	if (xdp_rxq_info_is_reg(&rxq->xdp_rxq_short))
27058c2ecf20Sopenharmony_ci		xdp_rxq_info_unreg(&rxq->xdp_rxq_short);
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	if (xdp_rxq_info_is_reg(&rxq->xdp_rxq_long))
27088c2ecf20Sopenharmony_ci		xdp_rxq_info_unreg(&rxq->xdp_rxq_long);
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci	mvpp2_rxq_drop_pkts(port, rxq);
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci	if (rxq->descs)
27138c2ecf20Sopenharmony_ci		dma_free_coherent(port->dev->dev.parent,
27148c2ecf20Sopenharmony_ci				  rxq->size * MVPP2_DESC_ALIGNED_SIZE,
27158c2ecf20Sopenharmony_ci				  rxq->descs,
27168c2ecf20Sopenharmony_ci				  rxq->descs_dma);
27178c2ecf20Sopenharmony_ci
27188c2ecf20Sopenharmony_ci	rxq->descs             = NULL;
27198c2ecf20Sopenharmony_ci	rxq->last_desc         = 0;
27208c2ecf20Sopenharmony_ci	rxq->next_desc_to_proc = 0;
27218c2ecf20Sopenharmony_ci	rxq->descs_dma         = 0;
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	/* Clear Rx descriptors queue starting address and size;
27248c2ecf20Sopenharmony_ci	 * free descriptor number
27258c2ecf20Sopenharmony_ci	 */
27268c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_RXQ_STATUS_REG(rxq->id), 0);
27278c2ecf20Sopenharmony_ci	thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
27288c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_NUM_REG, rxq->id);
27298c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_ADDR_REG, 0);
27308c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_RXQ_DESC_SIZE_REG, 0);
27318c2ecf20Sopenharmony_ci	put_cpu();
27328c2ecf20Sopenharmony_ci}
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci/* Create and initialize a Tx queue */
27358c2ecf20Sopenharmony_cistatic int mvpp2_txq_init(struct mvpp2_port *port,
27368c2ecf20Sopenharmony_ci			  struct mvpp2_tx_queue *txq)
27378c2ecf20Sopenharmony_ci{
27388c2ecf20Sopenharmony_ci	u32 val;
27398c2ecf20Sopenharmony_ci	unsigned int thread;
27408c2ecf20Sopenharmony_ci	int desc, desc_per_txq, tx_port_num;
27418c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
27428c2ecf20Sopenharmony_ci
27438c2ecf20Sopenharmony_ci	txq->size = port->tx_ring_size;
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	/* Allocate memory for Tx descriptors */
27468c2ecf20Sopenharmony_ci	txq->descs = dma_alloc_coherent(port->dev->dev.parent,
27478c2ecf20Sopenharmony_ci				txq->size * MVPP2_DESC_ALIGNED_SIZE,
27488c2ecf20Sopenharmony_ci				&txq->descs_dma, GFP_KERNEL);
27498c2ecf20Sopenharmony_ci	if (!txq->descs)
27508c2ecf20Sopenharmony_ci		return -ENOMEM;
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	txq->last_desc = txq->size - 1;
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci	/* Set Tx descriptors queue starting address - indirect access */
27558c2ecf20Sopenharmony_ci	thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
27568c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
27578c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG,
27588c2ecf20Sopenharmony_ci			   txq->descs_dma);
27598c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG,
27608c2ecf20Sopenharmony_ci			   txq->size & MVPP2_TXQ_DESC_SIZE_MASK);
27618c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_INDEX_REG, 0);
27628c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_RSVD_CLR_REG,
27638c2ecf20Sopenharmony_ci			   txq->id << MVPP2_TXQ_RSVD_CLR_OFFSET);
27648c2ecf20Sopenharmony_ci	val = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PENDING_REG);
27658c2ecf20Sopenharmony_ci	val &= ~MVPP2_TXQ_PENDING_MASK;
27668c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PENDING_REG, val);
27678c2ecf20Sopenharmony_ci
27688c2ecf20Sopenharmony_ci	/* Calculate base address in prefetch buffer. We reserve 16 descriptors
27698c2ecf20Sopenharmony_ci	 * for each existing TXQ.
27708c2ecf20Sopenharmony_ci	 * TCONTS for PON port must be continuous from 0 to MVPP2_MAX_TCONT
27718c2ecf20Sopenharmony_ci	 * GBE ports assumed to be continuous from 0 to MVPP2_MAX_PORTS
27728c2ecf20Sopenharmony_ci	 */
27738c2ecf20Sopenharmony_ci	desc_per_txq = 16;
27748c2ecf20Sopenharmony_ci	desc = (port->id * MVPP2_MAX_TXQ * desc_per_txq) +
27758c2ecf20Sopenharmony_ci	       (txq->log_id * desc_per_txq);
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG,
27788c2ecf20Sopenharmony_ci			   MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 |
27798c2ecf20Sopenharmony_ci			   MVPP2_PREF_BUF_THRESH(desc_per_txq / 2));
27808c2ecf20Sopenharmony_ci	put_cpu();
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	/* WRR / EJP configuration - indirect access */
27838c2ecf20Sopenharmony_ci	tx_port_num = mvpp2_egress_port(port);
27848c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_TXQ_SCHED_REFILL_REG(txq->log_id));
27878c2ecf20Sopenharmony_ci	val &= ~MVPP2_TXQ_REFILL_PERIOD_ALL_MASK;
27888c2ecf20Sopenharmony_ci	val |= MVPP2_TXQ_REFILL_PERIOD_MASK(1);
27898c2ecf20Sopenharmony_ci	val |= MVPP2_TXQ_REFILL_TOKENS_ALL_MASK;
27908c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXQ_SCHED_REFILL_REG(txq->log_id), val);
27918c2ecf20Sopenharmony_ci
27928c2ecf20Sopenharmony_ci	val = MVPP2_TXQ_TOKEN_SIZE_MAX;
27938c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(txq->log_id),
27948c2ecf20Sopenharmony_ci		    val);
27958c2ecf20Sopenharmony_ci
27968c2ecf20Sopenharmony_ci	for (thread = 0; thread < port->priv->nthreads; thread++) {
27978c2ecf20Sopenharmony_ci		txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
27988c2ecf20Sopenharmony_ci		txq_pcpu->size = txq->size;
27998c2ecf20Sopenharmony_ci		txq_pcpu->buffs = kmalloc_array(txq_pcpu->size,
28008c2ecf20Sopenharmony_ci						sizeof(*txq_pcpu->buffs),
28018c2ecf20Sopenharmony_ci						GFP_KERNEL);
28028c2ecf20Sopenharmony_ci		if (!txq_pcpu->buffs)
28038c2ecf20Sopenharmony_ci			return -ENOMEM;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci		txq_pcpu->count = 0;
28068c2ecf20Sopenharmony_ci		txq_pcpu->reserved_num = 0;
28078c2ecf20Sopenharmony_ci		txq_pcpu->txq_put_index = 0;
28088c2ecf20Sopenharmony_ci		txq_pcpu->txq_get_index = 0;
28098c2ecf20Sopenharmony_ci		txq_pcpu->tso_headers = NULL;
28108c2ecf20Sopenharmony_ci
28118c2ecf20Sopenharmony_ci		txq_pcpu->stop_threshold = txq->size - MVPP2_MAX_SKB_DESCS;
28128c2ecf20Sopenharmony_ci		txq_pcpu->wake_threshold = txq_pcpu->stop_threshold / 2;
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci		txq_pcpu->tso_headers =
28158c2ecf20Sopenharmony_ci			dma_alloc_coherent(port->dev->dev.parent,
28168c2ecf20Sopenharmony_ci					   txq_pcpu->size * TSO_HEADER_SIZE,
28178c2ecf20Sopenharmony_ci					   &txq_pcpu->tso_headers_dma,
28188c2ecf20Sopenharmony_ci					   GFP_KERNEL);
28198c2ecf20Sopenharmony_ci		if (!txq_pcpu->tso_headers)
28208c2ecf20Sopenharmony_ci			return -ENOMEM;
28218c2ecf20Sopenharmony_ci	}
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	return 0;
28248c2ecf20Sopenharmony_ci}
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_ci/* Free allocated TXQ resources */
28278c2ecf20Sopenharmony_cistatic void mvpp2_txq_deinit(struct mvpp2_port *port,
28288c2ecf20Sopenharmony_ci			     struct mvpp2_tx_queue *txq)
28298c2ecf20Sopenharmony_ci{
28308c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
28318c2ecf20Sopenharmony_ci	unsigned int thread;
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	for (thread = 0; thread < port->priv->nthreads; thread++) {
28348c2ecf20Sopenharmony_ci		txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
28358c2ecf20Sopenharmony_ci		kfree(txq_pcpu->buffs);
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci		if (txq_pcpu->tso_headers)
28388c2ecf20Sopenharmony_ci			dma_free_coherent(port->dev->dev.parent,
28398c2ecf20Sopenharmony_ci					  txq_pcpu->size * TSO_HEADER_SIZE,
28408c2ecf20Sopenharmony_ci					  txq_pcpu->tso_headers,
28418c2ecf20Sopenharmony_ci					  txq_pcpu->tso_headers_dma);
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci		txq_pcpu->tso_headers = NULL;
28448c2ecf20Sopenharmony_ci	}
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	if (txq->descs)
28478c2ecf20Sopenharmony_ci		dma_free_coherent(port->dev->dev.parent,
28488c2ecf20Sopenharmony_ci				  txq->size * MVPP2_DESC_ALIGNED_SIZE,
28498c2ecf20Sopenharmony_ci				  txq->descs, txq->descs_dma);
28508c2ecf20Sopenharmony_ci
28518c2ecf20Sopenharmony_ci	txq->descs             = NULL;
28528c2ecf20Sopenharmony_ci	txq->last_desc         = 0;
28538c2ecf20Sopenharmony_ci	txq->next_desc_to_proc = 0;
28548c2ecf20Sopenharmony_ci	txq->descs_dma         = 0;
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_ci	/* Set minimum bandwidth for disabled TXQs */
28578c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(txq->log_id), 0);
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci	/* Set Tx descriptors queue starting address and size */
28608c2ecf20Sopenharmony_ci	thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
28618c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
28628c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_ADDR_REG, 0);
28638c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_DESC_SIZE_REG, 0);
28648c2ecf20Sopenharmony_ci	put_cpu();
28658c2ecf20Sopenharmony_ci}
28668c2ecf20Sopenharmony_ci
28678c2ecf20Sopenharmony_ci/* Cleanup Tx ports */
28688c2ecf20Sopenharmony_cistatic void mvpp2_txq_clean(struct mvpp2_port *port, struct mvpp2_tx_queue *txq)
28698c2ecf20Sopenharmony_ci{
28708c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
28718c2ecf20Sopenharmony_ci	int delay, pending;
28728c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, get_cpu());
28738c2ecf20Sopenharmony_ci	u32 val;
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_NUM_REG, txq->id);
28768c2ecf20Sopenharmony_ci	val = mvpp2_thread_read(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG);
28778c2ecf20Sopenharmony_ci	val |= MVPP2_TXQ_DRAIN_EN_MASK;
28788c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val);
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	/* The napi queue has been stopped so wait for all packets
28818c2ecf20Sopenharmony_ci	 * to be transmitted.
28828c2ecf20Sopenharmony_ci	 */
28838c2ecf20Sopenharmony_ci	delay = 0;
28848c2ecf20Sopenharmony_ci	do {
28858c2ecf20Sopenharmony_ci		if (delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) {
28868c2ecf20Sopenharmony_ci			netdev_warn(port->dev,
28878c2ecf20Sopenharmony_ci				    "port %d: cleaning queue %d timed out\n",
28888c2ecf20Sopenharmony_ci				    port->id, txq->log_id);
28898c2ecf20Sopenharmony_ci			break;
28908c2ecf20Sopenharmony_ci		}
28918c2ecf20Sopenharmony_ci		mdelay(1);
28928c2ecf20Sopenharmony_ci		delay++;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci		pending = mvpp2_thread_read(port->priv, thread,
28958c2ecf20Sopenharmony_ci					    MVPP2_TXQ_PENDING_REG);
28968c2ecf20Sopenharmony_ci		pending &= MVPP2_TXQ_PENDING_MASK;
28978c2ecf20Sopenharmony_ci	} while (pending);
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci	val &= ~MVPP2_TXQ_DRAIN_EN_MASK;
29008c2ecf20Sopenharmony_ci	mvpp2_thread_write(port->priv, thread, MVPP2_TXQ_PREF_BUF_REG, val);
29018c2ecf20Sopenharmony_ci	put_cpu();
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	for (thread = 0; thread < port->priv->nthreads; thread++) {
29048c2ecf20Sopenharmony_ci		txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci		/* Release all packets */
29078c2ecf20Sopenharmony_ci		mvpp2_txq_bufs_free(port, txq, txq_pcpu, txq_pcpu->count);
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci		/* Reset queue */
29108c2ecf20Sopenharmony_ci		txq_pcpu->count = 0;
29118c2ecf20Sopenharmony_ci		txq_pcpu->txq_put_index = 0;
29128c2ecf20Sopenharmony_ci		txq_pcpu->txq_get_index = 0;
29138c2ecf20Sopenharmony_ci	}
29148c2ecf20Sopenharmony_ci}
29158c2ecf20Sopenharmony_ci
29168c2ecf20Sopenharmony_ci/* Cleanup all Tx queues */
29178c2ecf20Sopenharmony_cistatic void mvpp2_cleanup_txqs(struct mvpp2_port *port)
29188c2ecf20Sopenharmony_ci{
29198c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *txq;
29208c2ecf20Sopenharmony_ci	int queue;
29218c2ecf20Sopenharmony_ci	u32 val;
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	val = mvpp2_read(port->priv, MVPP2_TX_PORT_FLUSH_REG);
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	/* Reset Tx ports and delete Tx queues */
29268c2ecf20Sopenharmony_ci	val |= MVPP2_TX_PORT_FLUSH_MASK(port->id);
29278c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TX_PORT_FLUSH_REG, val);
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
29308c2ecf20Sopenharmony_ci		txq = port->txqs[queue];
29318c2ecf20Sopenharmony_ci		mvpp2_txq_clean(port, txq);
29328c2ecf20Sopenharmony_ci		mvpp2_txq_deinit(port, txq);
29338c2ecf20Sopenharmony_ci	}
29348c2ecf20Sopenharmony_ci
29358c2ecf20Sopenharmony_ci	on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1);
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_ci	val &= ~MVPP2_TX_PORT_FLUSH_MASK(port->id);
29388c2ecf20Sopenharmony_ci	mvpp2_write(port->priv, MVPP2_TX_PORT_FLUSH_REG, val);
29398c2ecf20Sopenharmony_ci}
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci/* Cleanup all Rx queues */
29428c2ecf20Sopenharmony_cistatic void mvpp2_cleanup_rxqs(struct mvpp2_port *port)
29438c2ecf20Sopenharmony_ci{
29448c2ecf20Sopenharmony_ci	int queue;
29458c2ecf20Sopenharmony_ci
29468c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->nrxqs; queue++)
29478c2ecf20Sopenharmony_ci		mvpp2_rxq_deinit(port, port->rxqs[queue]);
29488c2ecf20Sopenharmony_ci}
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_ci/* Init all Rx queues for port */
29518c2ecf20Sopenharmony_cistatic int mvpp2_setup_rxqs(struct mvpp2_port *port)
29528c2ecf20Sopenharmony_ci{
29538c2ecf20Sopenharmony_ci	int queue, err;
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->nrxqs; queue++) {
29568c2ecf20Sopenharmony_ci		err = mvpp2_rxq_init(port, port->rxqs[queue]);
29578c2ecf20Sopenharmony_ci		if (err)
29588c2ecf20Sopenharmony_ci			goto err_cleanup;
29598c2ecf20Sopenharmony_ci	}
29608c2ecf20Sopenharmony_ci	return 0;
29618c2ecf20Sopenharmony_ci
29628c2ecf20Sopenharmony_cierr_cleanup:
29638c2ecf20Sopenharmony_ci	mvpp2_cleanup_rxqs(port);
29648c2ecf20Sopenharmony_ci	return err;
29658c2ecf20Sopenharmony_ci}
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci/* Init all tx queues for port */
29688c2ecf20Sopenharmony_cistatic int mvpp2_setup_txqs(struct mvpp2_port *port)
29698c2ecf20Sopenharmony_ci{
29708c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *txq;
29718c2ecf20Sopenharmony_ci	int queue, err;
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
29748c2ecf20Sopenharmony_ci		txq = port->txqs[queue];
29758c2ecf20Sopenharmony_ci		err = mvpp2_txq_init(port, txq);
29768c2ecf20Sopenharmony_ci		if (err)
29778c2ecf20Sopenharmony_ci			goto err_cleanup;
29788c2ecf20Sopenharmony_ci
29798c2ecf20Sopenharmony_ci		/* Assign this queue to a CPU */
29808c2ecf20Sopenharmony_ci		if (queue < num_possible_cpus())
29818c2ecf20Sopenharmony_ci			netif_set_xps_queue(port->dev, cpumask_of(queue), queue);
29828c2ecf20Sopenharmony_ci	}
29838c2ecf20Sopenharmony_ci
29848c2ecf20Sopenharmony_ci	if (port->has_tx_irqs) {
29858c2ecf20Sopenharmony_ci		mvpp2_tx_time_coal_set(port);
29868c2ecf20Sopenharmony_ci		for (queue = 0; queue < port->ntxqs; queue++) {
29878c2ecf20Sopenharmony_ci			txq = port->txqs[queue];
29888c2ecf20Sopenharmony_ci			mvpp2_tx_pkts_coal_set(port, txq);
29898c2ecf20Sopenharmony_ci		}
29908c2ecf20Sopenharmony_ci	}
29918c2ecf20Sopenharmony_ci
29928c2ecf20Sopenharmony_ci	on_each_cpu(mvpp2_txq_sent_counter_clear, port, 1);
29938c2ecf20Sopenharmony_ci	return 0;
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_cierr_cleanup:
29968c2ecf20Sopenharmony_ci	mvpp2_cleanup_txqs(port);
29978c2ecf20Sopenharmony_ci	return err;
29988c2ecf20Sopenharmony_ci}
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci/* The callback for per-port interrupt */
30018c2ecf20Sopenharmony_cistatic irqreturn_t mvpp2_isr(int irq, void *dev_id)
30028c2ecf20Sopenharmony_ci{
30038c2ecf20Sopenharmony_ci	struct mvpp2_queue_vector *qv = dev_id;
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_ci	mvpp2_qvec_interrupt_disable(qv);
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	napi_schedule(&qv->napi);
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
30108c2ecf20Sopenharmony_ci}
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_cistatic void mvpp2_isr_handle_ptp_queue(struct mvpp2_port *port, int nq)
30138c2ecf20Sopenharmony_ci{
30148c2ecf20Sopenharmony_ci	struct skb_shared_hwtstamps shhwtstamps;
30158c2ecf20Sopenharmony_ci	struct mvpp2_hwtstamp_queue *queue;
30168c2ecf20Sopenharmony_ci	struct sk_buff *skb;
30178c2ecf20Sopenharmony_ci	void __iomem *ptp_q;
30188c2ecf20Sopenharmony_ci	unsigned int id;
30198c2ecf20Sopenharmony_ci	u32 r0, r1, r2;
30208c2ecf20Sopenharmony_ci
30218c2ecf20Sopenharmony_ci	ptp_q = port->priv->iface_base + MVPP22_PTP_BASE(port->gop_id);
30228c2ecf20Sopenharmony_ci	if (nq)
30238c2ecf20Sopenharmony_ci		ptp_q += MVPP22_PTP_TX_Q1_R0 - MVPP22_PTP_TX_Q0_R0;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	queue = &port->tx_hwtstamp_queue[nq];
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_ci	while (1) {
30288c2ecf20Sopenharmony_ci		r0 = readl_relaxed(ptp_q + MVPP22_PTP_TX_Q0_R0) & 0xffff;
30298c2ecf20Sopenharmony_ci		if (!r0)
30308c2ecf20Sopenharmony_ci			break;
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci		r1 = readl_relaxed(ptp_q + MVPP22_PTP_TX_Q0_R1) & 0xffff;
30338c2ecf20Sopenharmony_ci		r2 = readl_relaxed(ptp_q + MVPP22_PTP_TX_Q0_R2) & 0xffff;
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_ci		id = (r0 >> 1) & 31;
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci		skb = queue->skb[id];
30388c2ecf20Sopenharmony_ci		queue->skb[id] = NULL;
30398c2ecf20Sopenharmony_ci		if (skb) {
30408c2ecf20Sopenharmony_ci			u32 ts = r2 << 19 | r1 << 3 | r0 >> 13;
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci			mvpp22_tai_tstamp(port->priv->tai, ts, &shhwtstamps);
30438c2ecf20Sopenharmony_ci			skb_tstamp_tx(skb, &shhwtstamps);
30448c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
30458c2ecf20Sopenharmony_ci		}
30468c2ecf20Sopenharmony_ci	}
30478c2ecf20Sopenharmony_ci}
30488c2ecf20Sopenharmony_ci
30498c2ecf20Sopenharmony_cistatic void mvpp2_isr_handle_ptp(struct mvpp2_port *port)
30508c2ecf20Sopenharmony_ci{
30518c2ecf20Sopenharmony_ci	void __iomem *ptp;
30528c2ecf20Sopenharmony_ci	u32 val;
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci	ptp = port->priv->iface_base + MVPP22_PTP_BASE(port->gop_id);
30558c2ecf20Sopenharmony_ci	val = readl(ptp + MVPP22_PTP_INT_CAUSE);
30568c2ecf20Sopenharmony_ci	if (val & MVPP22_PTP_INT_CAUSE_QUEUE0)
30578c2ecf20Sopenharmony_ci		mvpp2_isr_handle_ptp_queue(port, 0);
30588c2ecf20Sopenharmony_ci	if (val & MVPP22_PTP_INT_CAUSE_QUEUE1)
30598c2ecf20Sopenharmony_ci		mvpp2_isr_handle_ptp_queue(port, 1);
30608c2ecf20Sopenharmony_ci}
30618c2ecf20Sopenharmony_ci
30628c2ecf20Sopenharmony_cistatic void mvpp2_isr_handle_link(struct mvpp2_port *port, bool link)
30638c2ecf20Sopenharmony_ci{
30648c2ecf20Sopenharmony_ci	struct net_device *dev = port->dev;
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci	if (port->phylink) {
30678c2ecf20Sopenharmony_ci		phylink_mac_change(port->phylink, link);
30688c2ecf20Sopenharmony_ci		return;
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci
30718c2ecf20Sopenharmony_ci	if (!netif_running(dev))
30728c2ecf20Sopenharmony_ci		return;
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	if (link) {
30758c2ecf20Sopenharmony_ci		mvpp2_interrupts_enable(port);
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_ci		mvpp2_egress_enable(port);
30788c2ecf20Sopenharmony_ci		mvpp2_ingress_enable(port);
30798c2ecf20Sopenharmony_ci		netif_carrier_on(dev);
30808c2ecf20Sopenharmony_ci		netif_tx_wake_all_queues(dev);
30818c2ecf20Sopenharmony_ci	} else {
30828c2ecf20Sopenharmony_ci		netif_tx_stop_all_queues(dev);
30838c2ecf20Sopenharmony_ci		netif_carrier_off(dev);
30848c2ecf20Sopenharmony_ci		mvpp2_ingress_disable(port);
30858c2ecf20Sopenharmony_ci		mvpp2_egress_disable(port);
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci		mvpp2_interrupts_disable(port);
30888c2ecf20Sopenharmony_ci	}
30898c2ecf20Sopenharmony_ci}
30908c2ecf20Sopenharmony_ci
30918c2ecf20Sopenharmony_cistatic void mvpp2_isr_handle_xlg(struct mvpp2_port *port)
30928c2ecf20Sopenharmony_ci{
30938c2ecf20Sopenharmony_ci	bool link;
30948c2ecf20Sopenharmony_ci	u32 val;
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP22_XLG_INT_STAT);
30978c2ecf20Sopenharmony_ci	if (val & MVPP22_XLG_INT_STAT_LINK) {
30988c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_STATUS);
30998c2ecf20Sopenharmony_ci		link = (val & MVPP22_XLG_STATUS_LINK_UP);
31008c2ecf20Sopenharmony_ci		mvpp2_isr_handle_link(port, link);
31018c2ecf20Sopenharmony_ci	}
31028c2ecf20Sopenharmony_ci}
31038c2ecf20Sopenharmony_ci
31048c2ecf20Sopenharmony_cistatic void mvpp2_isr_handle_gmac_internal(struct mvpp2_port *port)
31058c2ecf20Sopenharmony_ci{
31068c2ecf20Sopenharmony_ci	bool link;
31078c2ecf20Sopenharmony_ci	u32 val;
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_rgmii(port->phy_interface) ||
31108c2ecf20Sopenharmony_ci	    phy_interface_mode_is_8023z(port->phy_interface) ||
31118c2ecf20Sopenharmony_ci	    port->phy_interface == PHY_INTERFACE_MODE_SGMII) {
31128c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_GMAC_INT_STAT);
31138c2ecf20Sopenharmony_ci		if (val & MVPP22_GMAC_INT_STAT_LINK) {
31148c2ecf20Sopenharmony_ci			val = readl(port->base + MVPP2_GMAC_STATUS0);
31158c2ecf20Sopenharmony_ci			link = (val & MVPP2_GMAC_STATUS0_LINK_UP);
31168c2ecf20Sopenharmony_ci			mvpp2_isr_handle_link(port, link);
31178c2ecf20Sopenharmony_ci		}
31188c2ecf20Sopenharmony_ci	}
31198c2ecf20Sopenharmony_ci}
31208c2ecf20Sopenharmony_ci
31218c2ecf20Sopenharmony_ci/* Per-port interrupt for link status changes */
31228c2ecf20Sopenharmony_cistatic irqreturn_t mvpp2_port_isr(int irq, void *dev_id)
31238c2ecf20Sopenharmony_ci{
31248c2ecf20Sopenharmony_ci	struct mvpp2_port *port = (struct mvpp2_port *)dev_id;
31258c2ecf20Sopenharmony_ci	u32 val;
31268c2ecf20Sopenharmony_ci
31278c2ecf20Sopenharmony_ci	mvpp22_gop_mask_irq(port);
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port) &&
31308c2ecf20Sopenharmony_ci	    mvpp2_is_xlg(port->phy_interface)) {
31318c2ecf20Sopenharmony_ci		/* Check the external status register */
31328c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_EXT_INT_STAT);
31338c2ecf20Sopenharmony_ci		if (val & MVPP22_XLG_EXT_INT_STAT_XLG)
31348c2ecf20Sopenharmony_ci			mvpp2_isr_handle_xlg(port);
31358c2ecf20Sopenharmony_ci		if (val & MVPP22_XLG_EXT_INT_STAT_PTP)
31368c2ecf20Sopenharmony_ci			mvpp2_isr_handle_ptp(port);
31378c2ecf20Sopenharmony_ci	} else {
31388c2ecf20Sopenharmony_ci		/* If it's not the XLG, we must be using the GMAC.
31398c2ecf20Sopenharmony_ci		 * Check the summary status.
31408c2ecf20Sopenharmony_ci		 */
31418c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_GMAC_INT_SUM_STAT);
31428c2ecf20Sopenharmony_ci		if (val & MVPP22_GMAC_INT_SUM_STAT_INTERNAL)
31438c2ecf20Sopenharmony_ci			mvpp2_isr_handle_gmac_internal(port);
31448c2ecf20Sopenharmony_ci		if (val & MVPP22_GMAC_INT_SUM_STAT_PTP)
31458c2ecf20Sopenharmony_ci			mvpp2_isr_handle_ptp(port);
31468c2ecf20Sopenharmony_ci	}
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	mvpp22_gop_unmask_irq(port);
31498c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
31508c2ecf20Sopenharmony_ci}
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_cistatic enum hrtimer_restart mvpp2_hr_timer_cb(struct hrtimer *timer)
31538c2ecf20Sopenharmony_ci{
31548c2ecf20Sopenharmony_ci	struct net_device *dev;
31558c2ecf20Sopenharmony_ci	struct mvpp2_port *port;
31568c2ecf20Sopenharmony_ci	struct mvpp2_port_pcpu *port_pcpu;
31578c2ecf20Sopenharmony_ci	unsigned int tx_todo, cause;
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_ci	port_pcpu = container_of(timer, struct mvpp2_port_pcpu, tx_done_timer);
31608c2ecf20Sopenharmony_ci	dev = port_pcpu->dev;
31618c2ecf20Sopenharmony_ci
31628c2ecf20Sopenharmony_ci	if (!netif_running(dev))
31638c2ecf20Sopenharmony_ci		return HRTIMER_NORESTART;
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	port_pcpu->timer_scheduled = false;
31668c2ecf20Sopenharmony_ci	port = netdev_priv(dev);
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	/* Process all the Tx queues */
31698c2ecf20Sopenharmony_ci	cause = (1 << port->ntxqs) - 1;
31708c2ecf20Sopenharmony_ci	tx_todo = mvpp2_tx_done(port, cause,
31718c2ecf20Sopenharmony_ci				mvpp2_cpu_to_thread(port->priv, smp_processor_id()));
31728c2ecf20Sopenharmony_ci
31738c2ecf20Sopenharmony_ci	/* Set the timer in case not all the packets were processed */
31748c2ecf20Sopenharmony_ci	if (tx_todo && !port_pcpu->timer_scheduled) {
31758c2ecf20Sopenharmony_ci		port_pcpu->timer_scheduled = true;
31768c2ecf20Sopenharmony_ci		hrtimer_forward_now(&port_pcpu->tx_done_timer,
31778c2ecf20Sopenharmony_ci				    MVPP2_TXDONE_HRTIMER_PERIOD_NS);
31788c2ecf20Sopenharmony_ci
31798c2ecf20Sopenharmony_ci		return HRTIMER_RESTART;
31808c2ecf20Sopenharmony_ci	}
31818c2ecf20Sopenharmony_ci	return HRTIMER_NORESTART;
31828c2ecf20Sopenharmony_ci}
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci/* Main RX/TX processing routines */
31858c2ecf20Sopenharmony_ci
31868c2ecf20Sopenharmony_ci/* Display more error info */
31878c2ecf20Sopenharmony_cistatic void mvpp2_rx_error(struct mvpp2_port *port,
31888c2ecf20Sopenharmony_ci			   struct mvpp2_rx_desc *rx_desc)
31898c2ecf20Sopenharmony_ci{
31908c2ecf20Sopenharmony_ci	u32 status = mvpp2_rxdesc_status_get(port, rx_desc);
31918c2ecf20Sopenharmony_ci	size_t sz = mvpp2_rxdesc_size_get(port, rx_desc);
31928c2ecf20Sopenharmony_ci	char *err_str = NULL;
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci	switch (status & MVPP2_RXD_ERR_CODE_MASK) {
31958c2ecf20Sopenharmony_ci	case MVPP2_RXD_ERR_CRC:
31968c2ecf20Sopenharmony_ci		err_str = "crc";
31978c2ecf20Sopenharmony_ci		break;
31988c2ecf20Sopenharmony_ci	case MVPP2_RXD_ERR_OVERRUN:
31998c2ecf20Sopenharmony_ci		err_str = "overrun";
32008c2ecf20Sopenharmony_ci		break;
32018c2ecf20Sopenharmony_ci	case MVPP2_RXD_ERR_RESOURCE:
32028c2ecf20Sopenharmony_ci		err_str = "resource";
32038c2ecf20Sopenharmony_ci		break;
32048c2ecf20Sopenharmony_ci	}
32058c2ecf20Sopenharmony_ci	if (err_str && net_ratelimit())
32068c2ecf20Sopenharmony_ci		netdev_err(port->dev,
32078c2ecf20Sopenharmony_ci			   "bad rx status %08x (%s error), size=%zu\n",
32088c2ecf20Sopenharmony_ci			   status, err_str, sz);
32098c2ecf20Sopenharmony_ci}
32108c2ecf20Sopenharmony_ci
32118c2ecf20Sopenharmony_ci/* Handle RX checksum offload */
32128c2ecf20Sopenharmony_cistatic void mvpp2_rx_csum(struct mvpp2_port *port, u32 status,
32138c2ecf20Sopenharmony_ci			  struct sk_buff *skb)
32148c2ecf20Sopenharmony_ci{
32158c2ecf20Sopenharmony_ci	if (((status & MVPP2_RXD_L3_IP4) &&
32168c2ecf20Sopenharmony_ci	     !(status & MVPP2_RXD_IP4_HEADER_ERR)) ||
32178c2ecf20Sopenharmony_ci	    (status & MVPP2_RXD_L3_IP6))
32188c2ecf20Sopenharmony_ci		if (((status & MVPP2_RXD_L4_UDP) ||
32198c2ecf20Sopenharmony_ci		     (status & MVPP2_RXD_L4_TCP)) &&
32208c2ecf20Sopenharmony_ci		     (status & MVPP2_RXD_L4_CSUM_OK)) {
32218c2ecf20Sopenharmony_ci			skb->csum = 0;
32228c2ecf20Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
32238c2ecf20Sopenharmony_ci			return;
32248c2ecf20Sopenharmony_ci		}
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	skb->ip_summed = CHECKSUM_NONE;
32278c2ecf20Sopenharmony_ci}
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci/* Allocate a new skb and add it to BM pool */
32308c2ecf20Sopenharmony_cistatic int mvpp2_rx_refill(struct mvpp2_port *port,
32318c2ecf20Sopenharmony_ci			   struct mvpp2_bm_pool *bm_pool,
32328c2ecf20Sopenharmony_ci			   struct page_pool *page_pool, int pool)
32338c2ecf20Sopenharmony_ci{
32348c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
32358c2ecf20Sopenharmony_ci	phys_addr_t phys_addr;
32368c2ecf20Sopenharmony_ci	void *buf;
32378c2ecf20Sopenharmony_ci
32388c2ecf20Sopenharmony_ci	buf = mvpp2_buf_alloc(port, bm_pool, page_pool,
32398c2ecf20Sopenharmony_ci			      &dma_addr, &phys_addr, GFP_ATOMIC);
32408c2ecf20Sopenharmony_ci	if (!buf)
32418c2ecf20Sopenharmony_ci		return -ENOMEM;
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci	mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	return 0;
32468c2ecf20Sopenharmony_ci}
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci/* Handle tx checksum */
32498c2ecf20Sopenharmony_cistatic u32 mvpp2_skb_tx_csum(struct mvpp2_port *port, struct sk_buff *skb)
32508c2ecf20Sopenharmony_ci{
32518c2ecf20Sopenharmony_ci	if (skb->ip_summed == CHECKSUM_PARTIAL) {
32528c2ecf20Sopenharmony_ci		int ip_hdr_len = 0;
32538c2ecf20Sopenharmony_ci		u8 l4_proto;
32548c2ecf20Sopenharmony_ci		__be16 l3_proto = vlan_get_protocol(skb);
32558c2ecf20Sopenharmony_ci
32568c2ecf20Sopenharmony_ci		if (l3_proto == htons(ETH_P_IP)) {
32578c2ecf20Sopenharmony_ci			struct iphdr *ip4h = ip_hdr(skb);
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci			/* Calculate IPv4 checksum and L4 checksum */
32608c2ecf20Sopenharmony_ci			ip_hdr_len = ip4h->ihl;
32618c2ecf20Sopenharmony_ci			l4_proto = ip4h->protocol;
32628c2ecf20Sopenharmony_ci		} else if (l3_proto == htons(ETH_P_IPV6)) {
32638c2ecf20Sopenharmony_ci			struct ipv6hdr *ip6h = ipv6_hdr(skb);
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci			/* Read l4_protocol from one of IPv6 extra headers */
32668c2ecf20Sopenharmony_ci			if (skb_network_header_len(skb) > 0)
32678c2ecf20Sopenharmony_ci				ip_hdr_len = (skb_network_header_len(skb) >> 2);
32688c2ecf20Sopenharmony_ci			l4_proto = ip6h->nexthdr;
32698c2ecf20Sopenharmony_ci		} else {
32708c2ecf20Sopenharmony_ci			return MVPP2_TXD_L4_CSUM_NOT;
32718c2ecf20Sopenharmony_ci		}
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci		return mvpp2_txq_desc_csum(skb_network_offset(skb),
32748c2ecf20Sopenharmony_ci					   l3_proto, ip_hdr_len, l4_proto);
32758c2ecf20Sopenharmony_ci	}
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	return MVPP2_TXD_L4_CSUM_NOT | MVPP2_TXD_IP_CSUM_DISABLE;
32788c2ecf20Sopenharmony_ci}
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_cistatic void mvpp2_xdp_finish_tx(struct mvpp2_port *port, u16 txq_id, int nxmit, int nxmit_byte)
32818c2ecf20Sopenharmony_ci{
32828c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
32838c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *aggr_txq;
32848c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
32858c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *txq;
32868c2ecf20Sopenharmony_ci	struct netdev_queue *nq;
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci	txq = port->txqs[txq_id];
32898c2ecf20Sopenharmony_ci	txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
32908c2ecf20Sopenharmony_ci	nq = netdev_get_tx_queue(port->dev, txq_id);
32918c2ecf20Sopenharmony_ci	aggr_txq = &port->priv->aggr_txqs[thread];
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	txq_pcpu->reserved_num -= nxmit;
32948c2ecf20Sopenharmony_ci	txq_pcpu->count += nxmit;
32958c2ecf20Sopenharmony_ci	aggr_txq->count += nxmit;
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci	/* Enable transmit */
32988c2ecf20Sopenharmony_ci	wmb();
32998c2ecf20Sopenharmony_ci	mvpp2_aggr_txq_pend_desc_add(port, nxmit);
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci	if (txq_pcpu->count >= txq_pcpu->stop_threshold)
33028c2ecf20Sopenharmony_ci		netif_tx_stop_queue(nq);
33038c2ecf20Sopenharmony_ci
33048c2ecf20Sopenharmony_ci	/* Finalize TX processing */
33058c2ecf20Sopenharmony_ci	if (!port->has_tx_irqs && txq_pcpu->count >= txq->done_pkts_coal)
33068c2ecf20Sopenharmony_ci		mvpp2_txq_done(port, txq, txq_pcpu);
33078c2ecf20Sopenharmony_ci}
33088c2ecf20Sopenharmony_ci
33098c2ecf20Sopenharmony_cistatic int
33108c2ecf20Sopenharmony_cimvpp2_xdp_submit_frame(struct mvpp2_port *port, u16 txq_id,
33118c2ecf20Sopenharmony_ci		       struct xdp_frame *xdpf, bool dma_map)
33128c2ecf20Sopenharmony_ci{
33138c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
33148c2ecf20Sopenharmony_ci	u32 tx_cmd = MVPP2_TXD_L4_CSUM_NOT | MVPP2_TXD_IP_CSUM_DISABLE |
33158c2ecf20Sopenharmony_ci		     MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
33168c2ecf20Sopenharmony_ci	enum mvpp2_tx_buf_type buf_type;
33178c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
33188c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *aggr_txq;
33198c2ecf20Sopenharmony_ci	struct mvpp2_tx_desc *tx_desc;
33208c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *txq;
33218c2ecf20Sopenharmony_ci	int ret = MVPP2_XDP_TX;
33228c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
33238c2ecf20Sopenharmony_ci
33248c2ecf20Sopenharmony_ci	txq = port->txqs[txq_id];
33258c2ecf20Sopenharmony_ci	txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
33268c2ecf20Sopenharmony_ci	aggr_txq = &port->priv->aggr_txqs[thread];
33278c2ecf20Sopenharmony_ci
33288c2ecf20Sopenharmony_ci	/* Check number of available descriptors */
33298c2ecf20Sopenharmony_ci	if (mvpp2_aggr_desc_num_check(port, aggr_txq, 1) ||
33308c2ecf20Sopenharmony_ci	    mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, 1)) {
33318c2ecf20Sopenharmony_ci		ret = MVPP2_XDP_DROPPED;
33328c2ecf20Sopenharmony_ci		goto out;
33338c2ecf20Sopenharmony_ci	}
33348c2ecf20Sopenharmony_ci
33358c2ecf20Sopenharmony_ci	/* Get a descriptor for the first part of the packet */
33368c2ecf20Sopenharmony_ci	tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
33378c2ecf20Sopenharmony_ci	mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
33388c2ecf20Sopenharmony_ci	mvpp2_txdesc_size_set(port, tx_desc, xdpf->len);
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci	if (dma_map) {
33418c2ecf20Sopenharmony_ci		/* XDP_REDIRECT or AF_XDP */
33428c2ecf20Sopenharmony_ci		dma_addr = dma_map_single(port->dev->dev.parent, xdpf->data,
33438c2ecf20Sopenharmony_ci					  xdpf->len, DMA_TO_DEVICE);
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci		if (unlikely(dma_mapping_error(port->dev->dev.parent, dma_addr))) {
33468c2ecf20Sopenharmony_ci			mvpp2_txq_desc_put(txq);
33478c2ecf20Sopenharmony_ci			ret = MVPP2_XDP_DROPPED;
33488c2ecf20Sopenharmony_ci			goto out;
33498c2ecf20Sopenharmony_ci		}
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci		buf_type = MVPP2_TYPE_XDP_NDO;
33528c2ecf20Sopenharmony_ci	} else {
33538c2ecf20Sopenharmony_ci		/* XDP_TX */
33548c2ecf20Sopenharmony_ci		struct page *page = virt_to_page(xdpf->data);
33558c2ecf20Sopenharmony_ci
33568c2ecf20Sopenharmony_ci		dma_addr = page_pool_get_dma_addr(page) +
33578c2ecf20Sopenharmony_ci			   sizeof(*xdpf) + xdpf->headroom;
33588c2ecf20Sopenharmony_ci		dma_sync_single_for_device(port->dev->dev.parent, dma_addr,
33598c2ecf20Sopenharmony_ci					   xdpf->len, DMA_BIDIRECTIONAL);
33608c2ecf20Sopenharmony_ci
33618c2ecf20Sopenharmony_ci		buf_type = MVPP2_TYPE_XDP_TX;
33628c2ecf20Sopenharmony_ci	}
33638c2ecf20Sopenharmony_ci
33648c2ecf20Sopenharmony_ci	mvpp2_txdesc_dma_addr_set(port, tx_desc, dma_addr);
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_ci	mvpp2_txdesc_cmd_set(port, tx_desc, tx_cmd);
33678c2ecf20Sopenharmony_ci	mvpp2_txq_inc_put(port, txq_pcpu, xdpf, tx_desc, buf_type);
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ciout:
33708c2ecf20Sopenharmony_ci	return ret;
33718c2ecf20Sopenharmony_ci}
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_cistatic int
33748c2ecf20Sopenharmony_cimvpp2_xdp_xmit_back(struct mvpp2_port *port, struct xdp_buff *xdp)
33758c2ecf20Sopenharmony_ci{
33768c2ecf20Sopenharmony_ci	struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats);
33778c2ecf20Sopenharmony_ci	struct xdp_frame *xdpf;
33788c2ecf20Sopenharmony_ci	u16 txq_id;
33798c2ecf20Sopenharmony_ci	int ret;
33808c2ecf20Sopenharmony_ci
33818c2ecf20Sopenharmony_ci	xdpf = xdp_convert_buff_to_frame(xdp);
33828c2ecf20Sopenharmony_ci	if (unlikely(!xdpf))
33838c2ecf20Sopenharmony_ci		return MVPP2_XDP_DROPPED;
33848c2ecf20Sopenharmony_ci
33858c2ecf20Sopenharmony_ci	/* The first of the TX queues are used for XPS,
33868c2ecf20Sopenharmony_ci	 * the second half for XDP_TX
33878c2ecf20Sopenharmony_ci	 */
33888c2ecf20Sopenharmony_ci	txq_id = mvpp2_cpu_to_thread(port->priv, smp_processor_id()) + (port->ntxqs / 2);
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci	ret = mvpp2_xdp_submit_frame(port, txq_id, xdpf, false);
33918c2ecf20Sopenharmony_ci	if (ret == MVPP2_XDP_TX) {
33928c2ecf20Sopenharmony_ci		u64_stats_update_begin(&stats->syncp);
33938c2ecf20Sopenharmony_ci		stats->tx_bytes += xdpf->len;
33948c2ecf20Sopenharmony_ci		stats->tx_packets++;
33958c2ecf20Sopenharmony_ci		stats->xdp_tx++;
33968c2ecf20Sopenharmony_ci		u64_stats_update_end(&stats->syncp);
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci		mvpp2_xdp_finish_tx(port, txq_id, 1, xdpf->len);
33998c2ecf20Sopenharmony_ci	} else {
34008c2ecf20Sopenharmony_ci		u64_stats_update_begin(&stats->syncp);
34018c2ecf20Sopenharmony_ci		stats->xdp_tx_err++;
34028c2ecf20Sopenharmony_ci		u64_stats_update_end(&stats->syncp);
34038c2ecf20Sopenharmony_ci	}
34048c2ecf20Sopenharmony_ci
34058c2ecf20Sopenharmony_ci	return ret;
34068c2ecf20Sopenharmony_ci}
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_cistatic int
34098c2ecf20Sopenharmony_cimvpp2_xdp_xmit(struct net_device *dev, int num_frame,
34108c2ecf20Sopenharmony_ci	       struct xdp_frame **frames, u32 flags)
34118c2ecf20Sopenharmony_ci{
34128c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
34138c2ecf20Sopenharmony_ci	int i, nxmit_byte = 0, nxmit = num_frame;
34148c2ecf20Sopenharmony_ci	struct mvpp2_pcpu_stats *stats;
34158c2ecf20Sopenharmony_ci	u16 txq_id;
34168c2ecf20Sopenharmony_ci	u32 ret;
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	if (unlikely(test_bit(0, &port->state)))
34198c2ecf20Sopenharmony_ci		return -ENETDOWN;
34208c2ecf20Sopenharmony_ci
34218c2ecf20Sopenharmony_ci	if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
34228c2ecf20Sopenharmony_ci		return -EINVAL;
34238c2ecf20Sopenharmony_ci
34248c2ecf20Sopenharmony_ci	/* The first of the TX queues are used for XPS,
34258c2ecf20Sopenharmony_ci	 * the second half for XDP_TX
34268c2ecf20Sopenharmony_ci	 */
34278c2ecf20Sopenharmony_ci	txq_id = mvpp2_cpu_to_thread(port->priv, smp_processor_id()) + (port->ntxqs / 2);
34288c2ecf20Sopenharmony_ci
34298c2ecf20Sopenharmony_ci	for (i = 0; i < num_frame; i++) {
34308c2ecf20Sopenharmony_ci		ret = mvpp2_xdp_submit_frame(port, txq_id, frames[i], true);
34318c2ecf20Sopenharmony_ci		if (ret == MVPP2_XDP_TX) {
34328c2ecf20Sopenharmony_ci			nxmit_byte += frames[i]->len;
34338c2ecf20Sopenharmony_ci		} else {
34348c2ecf20Sopenharmony_ci			xdp_return_frame_rx_napi(frames[i]);
34358c2ecf20Sopenharmony_ci			nxmit--;
34368c2ecf20Sopenharmony_ci		}
34378c2ecf20Sopenharmony_ci	}
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci	if (likely(nxmit > 0))
34408c2ecf20Sopenharmony_ci		mvpp2_xdp_finish_tx(port, txq_id, nxmit, nxmit_byte);
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci	stats = this_cpu_ptr(port->stats);
34438c2ecf20Sopenharmony_ci	u64_stats_update_begin(&stats->syncp);
34448c2ecf20Sopenharmony_ci	stats->tx_bytes += nxmit_byte;
34458c2ecf20Sopenharmony_ci	stats->tx_packets += nxmit;
34468c2ecf20Sopenharmony_ci	stats->xdp_xmit += nxmit;
34478c2ecf20Sopenharmony_ci	stats->xdp_xmit_err += num_frame - nxmit;
34488c2ecf20Sopenharmony_ci	u64_stats_update_end(&stats->syncp);
34498c2ecf20Sopenharmony_ci
34508c2ecf20Sopenharmony_ci	return nxmit;
34518c2ecf20Sopenharmony_ci}
34528c2ecf20Sopenharmony_ci
34538c2ecf20Sopenharmony_cistatic int
34548c2ecf20Sopenharmony_cimvpp2_run_xdp(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq,
34558c2ecf20Sopenharmony_ci	      struct bpf_prog *prog, struct xdp_buff *xdp,
34568c2ecf20Sopenharmony_ci	      struct page_pool *pp, struct mvpp2_pcpu_stats *stats)
34578c2ecf20Sopenharmony_ci{
34588c2ecf20Sopenharmony_ci	unsigned int len, sync, err;
34598c2ecf20Sopenharmony_ci	struct page *page;
34608c2ecf20Sopenharmony_ci	u32 ret, act;
34618c2ecf20Sopenharmony_ci
34628c2ecf20Sopenharmony_ci	len = xdp->data_end - xdp->data_hard_start - MVPP2_SKB_HEADROOM;
34638c2ecf20Sopenharmony_ci	act = bpf_prog_run_xdp(prog, xdp);
34648c2ecf20Sopenharmony_ci
34658c2ecf20Sopenharmony_ci	/* Due xdp_adjust_tail: DMA sync for_device cover max len CPU touch */
34668c2ecf20Sopenharmony_ci	sync = xdp->data_end - xdp->data_hard_start - MVPP2_SKB_HEADROOM;
34678c2ecf20Sopenharmony_ci	sync = max(sync, len);
34688c2ecf20Sopenharmony_ci
34698c2ecf20Sopenharmony_ci	switch (act) {
34708c2ecf20Sopenharmony_ci	case XDP_PASS:
34718c2ecf20Sopenharmony_ci		stats->xdp_pass++;
34728c2ecf20Sopenharmony_ci		ret = MVPP2_XDP_PASS;
34738c2ecf20Sopenharmony_ci		break;
34748c2ecf20Sopenharmony_ci	case XDP_REDIRECT:
34758c2ecf20Sopenharmony_ci		err = xdp_do_redirect(port->dev, xdp, prog);
34768c2ecf20Sopenharmony_ci		if (unlikely(err)) {
34778c2ecf20Sopenharmony_ci			ret = MVPP2_XDP_DROPPED;
34788c2ecf20Sopenharmony_ci			page = virt_to_head_page(xdp->data);
34798c2ecf20Sopenharmony_ci			page_pool_put_page(pp, page, sync, true);
34808c2ecf20Sopenharmony_ci		} else {
34818c2ecf20Sopenharmony_ci			ret = MVPP2_XDP_REDIR;
34828c2ecf20Sopenharmony_ci			stats->xdp_redirect++;
34838c2ecf20Sopenharmony_ci		}
34848c2ecf20Sopenharmony_ci		break;
34858c2ecf20Sopenharmony_ci	case XDP_TX:
34868c2ecf20Sopenharmony_ci		ret = mvpp2_xdp_xmit_back(port, xdp);
34878c2ecf20Sopenharmony_ci		if (ret != MVPP2_XDP_TX) {
34888c2ecf20Sopenharmony_ci			page = virt_to_head_page(xdp->data);
34898c2ecf20Sopenharmony_ci			page_pool_put_page(pp, page, sync, true);
34908c2ecf20Sopenharmony_ci		}
34918c2ecf20Sopenharmony_ci		break;
34928c2ecf20Sopenharmony_ci	default:
34938c2ecf20Sopenharmony_ci		bpf_warn_invalid_xdp_action(act);
34948c2ecf20Sopenharmony_ci		fallthrough;
34958c2ecf20Sopenharmony_ci	case XDP_ABORTED:
34968c2ecf20Sopenharmony_ci		trace_xdp_exception(port->dev, prog, act);
34978c2ecf20Sopenharmony_ci		fallthrough;
34988c2ecf20Sopenharmony_ci	case XDP_DROP:
34998c2ecf20Sopenharmony_ci		page = virt_to_head_page(xdp->data);
35008c2ecf20Sopenharmony_ci		page_pool_put_page(pp, page, sync, true);
35018c2ecf20Sopenharmony_ci		ret = MVPP2_XDP_DROPPED;
35028c2ecf20Sopenharmony_ci		stats->xdp_drop++;
35038c2ecf20Sopenharmony_ci		break;
35048c2ecf20Sopenharmony_ci	}
35058c2ecf20Sopenharmony_ci
35068c2ecf20Sopenharmony_ci	return ret;
35078c2ecf20Sopenharmony_ci}
35088c2ecf20Sopenharmony_ci
35098c2ecf20Sopenharmony_cistatic void mvpp2_buff_hdr_pool_put(struct mvpp2_port *port, struct mvpp2_rx_desc *rx_desc,
35108c2ecf20Sopenharmony_ci				    int pool, u32 rx_status)
35118c2ecf20Sopenharmony_ci{
35128c2ecf20Sopenharmony_ci	phys_addr_t phys_addr, phys_addr_next;
35138c2ecf20Sopenharmony_ci	dma_addr_t dma_addr, dma_addr_next;
35148c2ecf20Sopenharmony_ci	struct mvpp2_buff_hdr *buff_hdr;
35158c2ecf20Sopenharmony_ci
35168c2ecf20Sopenharmony_ci	phys_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc);
35178c2ecf20Sopenharmony_ci	dma_addr = mvpp2_rxdesc_cookie_get(port, rx_desc);
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_ci	do {
35208c2ecf20Sopenharmony_ci		buff_hdr = (struct mvpp2_buff_hdr *)phys_to_virt(phys_addr);
35218c2ecf20Sopenharmony_ci
35228c2ecf20Sopenharmony_ci		phys_addr_next = le32_to_cpu(buff_hdr->next_phys_addr);
35238c2ecf20Sopenharmony_ci		dma_addr_next = le32_to_cpu(buff_hdr->next_dma_addr);
35248c2ecf20Sopenharmony_ci
35258c2ecf20Sopenharmony_ci		if (port->priv->hw_version >= MVPP22) {
35268c2ecf20Sopenharmony_ci			phys_addr_next |= ((u64)buff_hdr->next_phys_addr_high << 32);
35278c2ecf20Sopenharmony_ci			dma_addr_next |= ((u64)buff_hdr->next_dma_addr_high << 32);
35288c2ecf20Sopenharmony_ci		}
35298c2ecf20Sopenharmony_ci
35308c2ecf20Sopenharmony_ci		mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
35318c2ecf20Sopenharmony_ci
35328c2ecf20Sopenharmony_ci		phys_addr = phys_addr_next;
35338c2ecf20Sopenharmony_ci		dma_addr = dma_addr_next;
35348c2ecf20Sopenharmony_ci
35358c2ecf20Sopenharmony_ci	} while (!MVPP2_B_HDR_INFO_IS_LAST(le16_to_cpu(buff_hdr->info)));
35368c2ecf20Sopenharmony_ci}
35378c2ecf20Sopenharmony_ci
35388c2ecf20Sopenharmony_ci/* Main rx processing */
35398c2ecf20Sopenharmony_cistatic int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
35408c2ecf20Sopenharmony_ci		    int rx_todo, struct mvpp2_rx_queue *rxq)
35418c2ecf20Sopenharmony_ci{
35428c2ecf20Sopenharmony_ci	struct net_device *dev = port->dev;
35438c2ecf20Sopenharmony_ci	struct mvpp2_pcpu_stats ps = {};
35448c2ecf20Sopenharmony_ci	enum dma_data_direction dma_dir;
35458c2ecf20Sopenharmony_ci	struct bpf_prog *xdp_prog;
35468c2ecf20Sopenharmony_ci	struct xdp_buff xdp;
35478c2ecf20Sopenharmony_ci	int rx_received;
35488c2ecf20Sopenharmony_ci	int rx_done = 0;
35498c2ecf20Sopenharmony_ci	u32 xdp_ret = 0;
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	rcu_read_lock();
35528c2ecf20Sopenharmony_ci
35538c2ecf20Sopenharmony_ci	xdp_prog = READ_ONCE(port->xdp_prog);
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	/* Get number of received packets and clamp the to-do */
35568c2ecf20Sopenharmony_ci	rx_received = mvpp2_rxq_received(port, rxq->id);
35578c2ecf20Sopenharmony_ci	if (rx_todo > rx_received)
35588c2ecf20Sopenharmony_ci		rx_todo = rx_received;
35598c2ecf20Sopenharmony_ci
35608c2ecf20Sopenharmony_ci	while (rx_done < rx_todo) {
35618c2ecf20Sopenharmony_ci		struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq);
35628c2ecf20Sopenharmony_ci		struct mvpp2_bm_pool *bm_pool;
35638c2ecf20Sopenharmony_ci		struct page_pool *pp = NULL;
35648c2ecf20Sopenharmony_ci		struct sk_buff *skb;
35658c2ecf20Sopenharmony_ci		unsigned int frag_size;
35668c2ecf20Sopenharmony_ci		dma_addr_t dma_addr;
35678c2ecf20Sopenharmony_ci		phys_addr_t phys_addr;
35688c2ecf20Sopenharmony_ci		u32 rx_status, timestamp;
35698c2ecf20Sopenharmony_ci		int pool, rx_bytes, err, ret;
35708c2ecf20Sopenharmony_ci		void *data;
35718c2ecf20Sopenharmony_ci
35728c2ecf20Sopenharmony_ci		rx_done++;
35738c2ecf20Sopenharmony_ci		rx_status = mvpp2_rxdesc_status_get(port, rx_desc);
35748c2ecf20Sopenharmony_ci		rx_bytes = mvpp2_rxdesc_size_get(port, rx_desc);
35758c2ecf20Sopenharmony_ci		rx_bytes -= MVPP2_MH_SIZE;
35768c2ecf20Sopenharmony_ci		dma_addr = mvpp2_rxdesc_dma_addr_get(port, rx_desc);
35778c2ecf20Sopenharmony_ci		phys_addr = mvpp2_rxdesc_cookie_get(port, rx_desc);
35788c2ecf20Sopenharmony_ci		data = (void *)phys_to_virt(phys_addr);
35798c2ecf20Sopenharmony_ci
35808c2ecf20Sopenharmony_ci		pool = (rx_status & MVPP2_RXD_BM_POOL_ID_MASK) >>
35818c2ecf20Sopenharmony_ci			MVPP2_RXD_BM_POOL_ID_OFFS;
35828c2ecf20Sopenharmony_ci		bm_pool = &port->priv->bm_pools[pool];
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci		if (port->priv->percpu_pools) {
35858c2ecf20Sopenharmony_ci			pp = port->priv->page_pool[pool];
35868c2ecf20Sopenharmony_ci			dma_dir = page_pool_get_dma_dir(pp);
35878c2ecf20Sopenharmony_ci		} else {
35888c2ecf20Sopenharmony_ci			dma_dir = DMA_FROM_DEVICE;
35898c2ecf20Sopenharmony_ci		}
35908c2ecf20Sopenharmony_ci
35918c2ecf20Sopenharmony_ci		dma_sync_single_for_cpu(dev->dev.parent, dma_addr,
35928c2ecf20Sopenharmony_ci					rx_bytes + MVPP2_MH_SIZE,
35938c2ecf20Sopenharmony_ci					dma_dir);
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci		/* Buffer header not supported */
35968c2ecf20Sopenharmony_ci		if (rx_status & MVPP2_RXD_BUF_HDR)
35978c2ecf20Sopenharmony_ci			goto err_drop_frame;
35988c2ecf20Sopenharmony_ci
35998c2ecf20Sopenharmony_ci		/* In case of an error, release the requested buffer pointer
36008c2ecf20Sopenharmony_ci		 * to the Buffer Manager. This request process is controlled
36018c2ecf20Sopenharmony_ci		 * by the hardware, and the information about the buffer is
36028c2ecf20Sopenharmony_ci		 * comprised by the RX descriptor.
36038c2ecf20Sopenharmony_ci		 */
36048c2ecf20Sopenharmony_ci		if (rx_status & MVPP2_RXD_ERR_SUMMARY)
36058c2ecf20Sopenharmony_ci			goto err_drop_frame;
36068c2ecf20Sopenharmony_ci
36078c2ecf20Sopenharmony_ci		/* Prefetch header */
36088c2ecf20Sopenharmony_ci		prefetch(data);
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci		if (bm_pool->frag_size > PAGE_SIZE)
36118c2ecf20Sopenharmony_ci			frag_size = 0;
36128c2ecf20Sopenharmony_ci		else
36138c2ecf20Sopenharmony_ci			frag_size = bm_pool->frag_size;
36148c2ecf20Sopenharmony_ci
36158c2ecf20Sopenharmony_ci		if (xdp_prog) {
36168c2ecf20Sopenharmony_ci			xdp.data_hard_start = data;
36178c2ecf20Sopenharmony_ci			xdp.data = data + MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM;
36188c2ecf20Sopenharmony_ci			xdp.data_end = xdp.data + rx_bytes;
36198c2ecf20Sopenharmony_ci			xdp.frame_sz = PAGE_SIZE;
36208c2ecf20Sopenharmony_ci
36218c2ecf20Sopenharmony_ci			if (bm_pool->pkt_size == MVPP2_BM_SHORT_PKT_SIZE)
36228c2ecf20Sopenharmony_ci				xdp.rxq = &rxq->xdp_rxq_short;
36238c2ecf20Sopenharmony_ci			else
36248c2ecf20Sopenharmony_ci				xdp.rxq = &rxq->xdp_rxq_long;
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_ci			xdp_set_data_meta_invalid(&xdp);
36278c2ecf20Sopenharmony_ci
36288c2ecf20Sopenharmony_ci			ret = mvpp2_run_xdp(port, rxq, xdp_prog, &xdp, pp, &ps);
36298c2ecf20Sopenharmony_ci
36308c2ecf20Sopenharmony_ci			if (ret) {
36318c2ecf20Sopenharmony_ci				xdp_ret |= ret;
36328c2ecf20Sopenharmony_ci				err = mvpp2_rx_refill(port, bm_pool, pp, pool);
36338c2ecf20Sopenharmony_ci				if (err) {
36348c2ecf20Sopenharmony_ci					netdev_err(port->dev, "failed to refill BM pools\n");
36358c2ecf20Sopenharmony_ci					goto err_drop_frame;
36368c2ecf20Sopenharmony_ci				}
36378c2ecf20Sopenharmony_ci
36388c2ecf20Sopenharmony_ci				ps.rx_packets++;
36398c2ecf20Sopenharmony_ci				ps.rx_bytes += rx_bytes;
36408c2ecf20Sopenharmony_ci				continue;
36418c2ecf20Sopenharmony_ci			}
36428c2ecf20Sopenharmony_ci		}
36438c2ecf20Sopenharmony_ci
36448c2ecf20Sopenharmony_ci		skb = build_skb(data, frag_size);
36458c2ecf20Sopenharmony_ci		if (!skb) {
36468c2ecf20Sopenharmony_ci			netdev_warn(port->dev, "skb build failed\n");
36478c2ecf20Sopenharmony_ci			goto err_drop_frame;
36488c2ecf20Sopenharmony_ci		}
36498c2ecf20Sopenharmony_ci
36508c2ecf20Sopenharmony_ci		/* If we have RX hardware timestamping enabled, grab the
36518c2ecf20Sopenharmony_ci		 * timestamp from the queue and convert.
36528c2ecf20Sopenharmony_ci		 */
36538c2ecf20Sopenharmony_ci		if (mvpp22_rx_hwtstamping(port)) {
36548c2ecf20Sopenharmony_ci			timestamp = le32_to_cpu(rx_desc->pp22.timestamp);
36558c2ecf20Sopenharmony_ci			mvpp22_tai_tstamp(port->priv->tai, timestamp,
36568c2ecf20Sopenharmony_ci					 skb_hwtstamps(skb));
36578c2ecf20Sopenharmony_ci		}
36588c2ecf20Sopenharmony_ci
36598c2ecf20Sopenharmony_ci		err = mvpp2_rx_refill(port, bm_pool, pp, pool);
36608c2ecf20Sopenharmony_ci		if (err) {
36618c2ecf20Sopenharmony_ci			netdev_err(port->dev, "failed to refill BM pools\n");
36628c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
36638c2ecf20Sopenharmony_ci			goto err_drop_frame;
36648c2ecf20Sopenharmony_ci		}
36658c2ecf20Sopenharmony_ci
36668c2ecf20Sopenharmony_ci		if (pp)
36678c2ecf20Sopenharmony_ci			page_pool_release_page(pp, virt_to_page(data));
36688c2ecf20Sopenharmony_ci		else
36698c2ecf20Sopenharmony_ci			dma_unmap_single_attrs(dev->dev.parent, dma_addr,
36708c2ecf20Sopenharmony_ci					       bm_pool->buf_size, DMA_FROM_DEVICE,
36718c2ecf20Sopenharmony_ci					       DMA_ATTR_SKIP_CPU_SYNC);
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci		ps.rx_packets++;
36748c2ecf20Sopenharmony_ci		ps.rx_bytes += rx_bytes;
36758c2ecf20Sopenharmony_ci
36768c2ecf20Sopenharmony_ci		skb_reserve(skb, MVPP2_MH_SIZE + MVPP2_SKB_HEADROOM);
36778c2ecf20Sopenharmony_ci		skb_put(skb, rx_bytes);
36788c2ecf20Sopenharmony_ci		skb->protocol = eth_type_trans(skb, dev);
36798c2ecf20Sopenharmony_ci		mvpp2_rx_csum(port, rx_status, skb);
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_ci		napi_gro_receive(napi, skb);
36828c2ecf20Sopenharmony_ci		continue;
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_cierr_drop_frame:
36858c2ecf20Sopenharmony_ci		dev->stats.rx_errors++;
36868c2ecf20Sopenharmony_ci		mvpp2_rx_error(port, rx_desc);
36878c2ecf20Sopenharmony_ci		/* Return the buffer to the pool */
36888c2ecf20Sopenharmony_ci		if (rx_status & MVPP2_RXD_BUF_HDR)
36898c2ecf20Sopenharmony_ci			mvpp2_buff_hdr_pool_put(port, rx_desc, pool, rx_status);
36908c2ecf20Sopenharmony_ci		else
36918c2ecf20Sopenharmony_ci			mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
36928c2ecf20Sopenharmony_ci	}
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci	rcu_read_unlock();
36958c2ecf20Sopenharmony_ci
36968c2ecf20Sopenharmony_ci	if (xdp_ret & MVPP2_XDP_REDIR)
36978c2ecf20Sopenharmony_ci		xdp_do_flush_map();
36988c2ecf20Sopenharmony_ci
36998c2ecf20Sopenharmony_ci	if (ps.rx_packets) {
37008c2ecf20Sopenharmony_ci		struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats);
37018c2ecf20Sopenharmony_ci
37028c2ecf20Sopenharmony_ci		u64_stats_update_begin(&stats->syncp);
37038c2ecf20Sopenharmony_ci		stats->rx_packets += ps.rx_packets;
37048c2ecf20Sopenharmony_ci		stats->rx_bytes   += ps.rx_bytes;
37058c2ecf20Sopenharmony_ci		/* xdp */
37068c2ecf20Sopenharmony_ci		stats->xdp_redirect += ps.xdp_redirect;
37078c2ecf20Sopenharmony_ci		stats->xdp_pass += ps.xdp_pass;
37088c2ecf20Sopenharmony_ci		stats->xdp_drop += ps.xdp_drop;
37098c2ecf20Sopenharmony_ci		u64_stats_update_end(&stats->syncp);
37108c2ecf20Sopenharmony_ci	}
37118c2ecf20Sopenharmony_ci
37128c2ecf20Sopenharmony_ci	/* Update Rx queue management counters */
37138c2ecf20Sopenharmony_ci	wmb();
37148c2ecf20Sopenharmony_ci	mvpp2_rxq_status_update(port, rxq->id, rx_done, rx_done);
37158c2ecf20Sopenharmony_ci
37168c2ecf20Sopenharmony_ci	return rx_todo;
37178c2ecf20Sopenharmony_ci}
37188c2ecf20Sopenharmony_ci
37198c2ecf20Sopenharmony_cistatic inline void
37208c2ecf20Sopenharmony_citx_desc_unmap_put(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
37218c2ecf20Sopenharmony_ci		  struct mvpp2_tx_desc *desc)
37228c2ecf20Sopenharmony_ci{
37238c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
37248c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
37258c2ecf20Sopenharmony_ci
37268c2ecf20Sopenharmony_ci	dma_addr_t buf_dma_addr =
37278c2ecf20Sopenharmony_ci		mvpp2_txdesc_dma_addr_get(port, desc);
37288c2ecf20Sopenharmony_ci	size_t buf_sz =
37298c2ecf20Sopenharmony_ci		mvpp2_txdesc_size_get(port, desc);
37308c2ecf20Sopenharmony_ci	if (!IS_TSO_HEADER(txq_pcpu, buf_dma_addr))
37318c2ecf20Sopenharmony_ci		dma_unmap_single(port->dev->dev.parent, buf_dma_addr,
37328c2ecf20Sopenharmony_ci				 buf_sz, DMA_TO_DEVICE);
37338c2ecf20Sopenharmony_ci	mvpp2_txq_desc_put(txq);
37348c2ecf20Sopenharmony_ci}
37358c2ecf20Sopenharmony_ci
37368c2ecf20Sopenharmony_cistatic void mvpp2_txdesc_clear_ptp(struct mvpp2_port *port,
37378c2ecf20Sopenharmony_ci				   struct mvpp2_tx_desc *desc)
37388c2ecf20Sopenharmony_ci{
37398c2ecf20Sopenharmony_ci	/* We only need to clear the low bits */
37408c2ecf20Sopenharmony_ci	if (port->priv->hw_version != MVPP21)
37418c2ecf20Sopenharmony_ci		desc->pp22.ptp_descriptor &=
37428c2ecf20Sopenharmony_ci			cpu_to_le32(~MVPP22_PTP_DESC_MASK_LOW);
37438c2ecf20Sopenharmony_ci}
37448c2ecf20Sopenharmony_ci
37458c2ecf20Sopenharmony_cistatic bool mvpp2_tx_hw_tstamp(struct mvpp2_port *port,
37468c2ecf20Sopenharmony_ci			       struct mvpp2_tx_desc *tx_desc,
37478c2ecf20Sopenharmony_ci			       struct sk_buff *skb)
37488c2ecf20Sopenharmony_ci{
37498c2ecf20Sopenharmony_ci	struct mvpp2_hwtstamp_queue *queue;
37508c2ecf20Sopenharmony_ci	unsigned int mtype, type, i;
37518c2ecf20Sopenharmony_ci	struct ptp_header *hdr;
37528c2ecf20Sopenharmony_ci	u64 ptpdesc;
37538c2ecf20Sopenharmony_ci
37548c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21 ||
37558c2ecf20Sopenharmony_ci	    port->tx_hwtstamp_type == HWTSTAMP_TX_OFF)
37568c2ecf20Sopenharmony_ci		return false;
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci	type = ptp_classify_raw(skb);
37598c2ecf20Sopenharmony_ci	if (!type)
37608c2ecf20Sopenharmony_ci		return false;
37618c2ecf20Sopenharmony_ci
37628c2ecf20Sopenharmony_ci	hdr = ptp_parse_header(skb, type);
37638c2ecf20Sopenharmony_ci	if (!hdr)
37648c2ecf20Sopenharmony_ci		return false;
37658c2ecf20Sopenharmony_ci
37668c2ecf20Sopenharmony_ci	skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci	ptpdesc = MVPP22_PTP_MACTIMESTAMPINGEN |
37698c2ecf20Sopenharmony_ci		  MVPP22_PTP_ACTION_CAPTURE;
37708c2ecf20Sopenharmony_ci	queue = &port->tx_hwtstamp_queue[0];
37718c2ecf20Sopenharmony_ci
37728c2ecf20Sopenharmony_ci	switch (type & PTP_CLASS_VMASK) {
37738c2ecf20Sopenharmony_ci	case PTP_CLASS_V1:
37748c2ecf20Sopenharmony_ci		ptpdesc |= MVPP22_PTP_PACKETFORMAT(MVPP22_PTP_PKT_FMT_PTPV1);
37758c2ecf20Sopenharmony_ci		break;
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_ci	case PTP_CLASS_V2:
37788c2ecf20Sopenharmony_ci		ptpdesc |= MVPP22_PTP_PACKETFORMAT(MVPP22_PTP_PKT_FMT_PTPV2);
37798c2ecf20Sopenharmony_ci		mtype = hdr->tsmt & 15;
37808c2ecf20Sopenharmony_ci		/* Direct PTP Sync messages to queue 1 */
37818c2ecf20Sopenharmony_ci		if (mtype == 0) {
37828c2ecf20Sopenharmony_ci			ptpdesc |= MVPP22_PTP_TIMESTAMPQUEUESELECT;
37838c2ecf20Sopenharmony_ci			queue = &port->tx_hwtstamp_queue[1];
37848c2ecf20Sopenharmony_ci		}
37858c2ecf20Sopenharmony_ci		break;
37868c2ecf20Sopenharmony_ci	}
37878c2ecf20Sopenharmony_ci
37888c2ecf20Sopenharmony_ci	/* Take a reference on the skb and insert into our queue */
37898c2ecf20Sopenharmony_ci	i = queue->next;
37908c2ecf20Sopenharmony_ci	queue->next = (i + 1) & 31;
37918c2ecf20Sopenharmony_ci	if (queue->skb[i])
37928c2ecf20Sopenharmony_ci		dev_kfree_skb_any(queue->skb[i]);
37938c2ecf20Sopenharmony_ci	queue->skb[i] = skb_get(skb);
37948c2ecf20Sopenharmony_ci
37958c2ecf20Sopenharmony_ci	ptpdesc |= MVPP22_PTP_TIMESTAMPENTRYID(i);
37968c2ecf20Sopenharmony_ci
37978c2ecf20Sopenharmony_ci	/*
37988c2ecf20Sopenharmony_ci	 * 3:0		- PTPAction
37998c2ecf20Sopenharmony_ci	 * 6:4		- PTPPacketFormat
38008c2ecf20Sopenharmony_ci	 * 7		- PTP_CF_WraparoundCheckEn
38018c2ecf20Sopenharmony_ci	 * 9:8		- IngressTimestampSeconds[1:0]
38028c2ecf20Sopenharmony_ci	 * 10		- Reserved
38038c2ecf20Sopenharmony_ci	 * 11		- MACTimestampingEn
38048c2ecf20Sopenharmony_ci	 * 17:12	- PTP_TimestampQueueEntryID[5:0]
38058c2ecf20Sopenharmony_ci	 * 18		- PTPTimestampQueueSelect
38068c2ecf20Sopenharmony_ci	 * 19		- UDPChecksumUpdateEn
38078c2ecf20Sopenharmony_ci	 * 27:20	- TimestampOffset
38088c2ecf20Sopenharmony_ci	 *			PTP, NTPTransmit, OWAMP/TWAMP - L3 to PTP header
38098c2ecf20Sopenharmony_ci	 *			NTPTs, Y.1731 - L3 to timestamp entry
38108c2ecf20Sopenharmony_ci	 * 35:28	- UDP Checksum Offset
38118c2ecf20Sopenharmony_ci	 *
38128c2ecf20Sopenharmony_ci	 * stored in tx descriptor bits 75:64 (11:0) and 191:168 (35:12)
38138c2ecf20Sopenharmony_ci	 */
38148c2ecf20Sopenharmony_ci	tx_desc->pp22.ptp_descriptor &=
38158c2ecf20Sopenharmony_ci		cpu_to_le32(~MVPP22_PTP_DESC_MASK_LOW);
38168c2ecf20Sopenharmony_ci	tx_desc->pp22.ptp_descriptor |=
38178c2ecf20Sopenharmony_ci		cpu_to_le32(ptpdesc & MVPP22_PTP_DESC_MASK_LOW);
38188c2ecf20Sopenharmony_ci	tx_desc->pp22.buf_dma_addr_ptp &= cpu_to_le64(~0xffffff0000000000ULL);
38198c2ecf20Sopenharmony_ci	tx_desc->pp22.buf_dma_addr_ptp |= cpu_to_le64((ptpdesc >> 12) << 40);
38208c2ecf20Sopenharmony_ci
38218c2ecf20Sopenharmony_ci	return true;
38228c2ecf20Sopenharmony_ci}
38238c2ecf20Sopenharmony_ci
38248c2ecf20Sopenharmony_ci/* Handle tx fragmentation processing */
38258c2ecf20Sopenharmony_cistatic int mvpp2_tx_frag_process(struct mvpp2_port *port, struct sk_buff *skb,
38268c2ecf20Sopenharmony_ci				 struct mvpp2_tx_queue *aggr_txq,
38278c2ecf20Sopenharmony_ci				 struct mvpp2_tx_queue *txq)
38288c2ecf20Sopenharmony_ci{
38298c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
38308c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
38318c2ecf20Sopenharmony_ci	struct mvpp2_tx_desc *tx_desc;
38328c2ecf20Sopenharmony_ci	int i;
38338c2ecf20Sopenharmony_ci	dma_addr_t buf_dma_addr;
38348c2ecf20Sopenharmony_ci
38358c2ecf20Sopenharmony_ci	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
38368c2ecf20Sopenharmony_ci		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
38378c2ecf20Sopenharmony_ci		void *addr = skb_frag_address(frag);
38388c2ecf20Sopenharmony_ci
38398c2ecf20Sopenharmony_ci		tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
38408c2ecf20Sopenharmony_ci		mvpp2_txdesc_clear_ptp(port, tx_desc);
38418c2ecf20Sopenharmony_ci		mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
38428c2ecf20Sopenharmony_ci		mvpp2_txdesc_size_set(port, tx_desc, skb_frag_size(frag));
38438c2ecf20Sopenharmony_ci
38448c2ecf20Sopenharmony_ci		buf_dma_addr = dma_map_single(port->dev->dev.parent, addr,
38458c2ecf20Sopenharmony_ci					      skb_frag_size(frag),
38468c2ecf20Sopenharmony_ci					      DMA_TO_DEVICE);
38478c2ecf20Sopenharmony_ci		if (dma_mapping_error(port->dev->dev.parent, buf_dma_addr)) {
38488c2ecf20Sopenharmony_ci			mvpp2_txq_desc_put(txq);
38498c2ecf20Sopenharmony_ci			goto cleanup;
38508c2ecf20Sopenharmony_ci		}
38518c2ecf20Sopenharmony_ci
38528c2ecf20Sopenharmony_ci		mvpp2_txdesc_dma_addr_set(port, tx_desc, buf_dma_addr);
38538c2ecf20Sopenharmony_ci
38548c2ecf20Sopenharmony_ci		if (i == (skb_shinfo(skb)->nr_frags - 1)) {
38558c2ecf20Sopenharmony_ci			/* Last descriptor */
38568c2ecf20Sopenharmony_ci			mvpp2_txdesc_cmd_set(port, tx_desc,
38578c2ecf20Sopenharmony_ci					     MVPP2_TXD_L_DESC);
38588c2ecf20Sopenharmony_ci			mvpp2_txq_inc_put(port, txq_pcpu, skb, tx_desc, MVPP2_TYPE_SKB);
38598c2ecf20Sopenharmony_ci		} else {
38608c2ecf20Sopenharmony_ci			/* Descriptor in the middle: Not First, Not Last */
38618c2ecf20Sopenharmony_ci			mvpp2_txdesc_cmd_set(port, tx_desc, 0);
38628c2ecf20Sopenharmony_ci			mvpp2_txq_inc_put(port, txq_pcpu, NULL, tx_desc, MVPP2_TYPE_SKB);
38638c2ecf20Sopenharmony_ci		}
38648c2ecf20Sopenharmony_ci	}
38658c2ecf20Sopenharmony_ci
38668c2ecf20Sopenharmony_ci	return 0;
38678c2ecf20Sopenharmony_cicleanup:
38688c2ecf20Sopenharmony_ci	/* Release all descriptors that were used to map fragments of
38698c2ecf20Sopenharmony_ci	 * this packet, as well as the corresponding DMA mappings
38708c2ecf20Sopenharmony_ci	 */
38718c2ecf20Sopenharmony_ci	for (i = i - 1; i >= 0; i--) {
38728c2ecf20Sopenharmony_ci		tx_desc = txq->descs + i;
38738c2ecf20Sopenharmony_ci		tx_desc_unmap_put(port, txq, tx_desc);
38748c2ecf20Sopenharmony_ci	}
38758c2ecf20Sopenharmony_ci
38768c2ecf20Sopenharmony_ci	return -ENOMEM;
38778c2ecf20Sopenharmony_ci}
38788c2ecf20Sopenharmony_ci
38798c2ecf20Sopenharmony_cistatic inline void mvpp2_tso_put_hdr(struct sk_buff *skb,
38808c2ecf20Sopenharmony_ci				     struct net_device *dev,
38818c2ecf20Sopenharmony_ci				     struct mvpp2_tx_queue *txq,
38828c2ecf20Sopenharmony_ci				     struct mvpp2_tx_queue *aggr_txq,
38838c2ecf20Sopenharmony_ci				     struct mvpp2_txq_pcpu *txq_pcpu,
38848c2ecf20Sopenharmony_ci				     int hdr_sz)
38858c2ecf20Sopenharmony_ci{
38868c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
38878c2ecf20Sopenharmony_ci	struct mvpp2_tx_desc *tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
38888c2ecf20Sopenharmony_ci	dma_addr_t addr;
38898c2ecf20Sopenharmony_ci
38908c2ecf20Sopenharmony_ci	mvpp2_txdesc_clear_ptp(port, tx_desc);
38918c2ecf20Sopenharmony_ci	mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
38928c2ecf20Sopenharmony_ci	mvpp2_txdesc_size_set(port, tx_desc, hdr_sz);
38938c2ecf20Sopenharmony_ci
38948c2ecf20Sopenharmony_ci	addr = txq_pcpu->tso_headers_dma +
38958c2ecf20Sopenharmony_ci	       txq_pcpu->txq_put_index * TSO_HEADER_SIZE;
38968c2ecf20Sopenharmony_ci	mvpp2_txdesc_dma_addr_set(port, tx_desc, addr);
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_ci	mvpp2_txdesc_cmd_set(port, tx_desc, mvpp2_skb_tx_csum(port, skb) |
38998c2ecf20Sopenharmony_ci					    MVPP2_TXD_F_DESC |
39008c2ecf20Sopenharmony_ci					    MVPP2_TXD_PADDING_DISABLE);
39018c2ecf20Sopenharmony_ci	mvpp2_txq_inc_put(port, txq_pcpu, NULL, tx_desc, MVPP2_TYPE_SKB);
39028c2ecf20Sopenharmony_ci}
39038c2ecf20Sopenharmony_ci
39048c2ecf20Sopenharmony_cistatic inline int mvpp2_tso_put_data(struct sk_buff *skb,
39058c2ecf20Sopenharmony_ci				     struct net_device *dev, struct tso_t *tso,
39068c2ecf20Sopenharmony_ci				     struct mvpp2_tx_queue *txq,
39078c2ecf20Sopenharmony_ci				     struct mvpp2_tx_queue *aggr_txq,
39088c2ecf20Sopenharmony_ci				     struct mvpp2_txq_pcpu *txq_pcpu,
39098c2ecf20Sopenharmony_ci				     int sz, bool left, bool last)
39108c2ecf20Sopenharmony_ci{
39118c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
39128c2ecf20Sopenharmony_ci	struct mvpp2_tx_desc *tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
39138c2ecf20Sopenharmony_ci	dma_addr_t buf_dma_addr;
39148c2ecf20Sopenharmony_ci
39158c2ecf20Sopenharmony_ci	mvpp2_txdesc_clear_ptp(port, tx_desc);
39168c2ecf20Sopenharmony_ci	mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
39178c2ecf20Sopenharmony_ci	mvpp2_txdesc_size_set(port, tx_desc, sz);
39188c2ecf20Sopenharmony_ci
39198c2ecf20Sopenharmony_ci	buf_dma_addr = dma_map_single(dev->dev.parent, tso->data, sz,
39208c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
39218c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(dev->dev.parent, buf_dma_addr))) {
39228c2ecf20Sopenharmony_ci		mvpp2_txq_desc_put(txq);
39238c2ecf20Sopenharmony_ci		return -ENOMEM;
39248c2ecf20Sopenharmony_ci	}
39258c2ecf20Sopenharmony_ci
39268c2ecf20Sopenharmony_ci	mvpp2_txdesc_dma_addr_set(port, tx_desc, buf_dma_addr);
39278c2ecf20Sopenharmony_ci
39288c2ecf20Sopenharmony_ci	if (!left) {
39298c2ecf20Sopenharmony_ci		mvpp2_txdesc_cmd_set(port, tx_desc, MVPP2_TXD_L_DESC);
39308c2ecf20Sopenharmony_ci		if (last) {
39318c2ecf20Sopenharmony_ci			mvpp2_txq_inc_put(port, txq_pcpu, skb, tx_desc, MVPP2_TYPE_SKB);
39328c2ecf20Sopenharmony_ci			return 0;
39338c2ecf20Sopenharmony_ci		}
39348c2ecf20Sopenharmony_ci	} else {
39358c2ecf20Sopenharmony_ci		mvpp2_txdesc_cmd_set(port, tx_desc, 0);
39368c2ecf20Sopenharmony_ci	}
39378c2ecf20Sopenharmony_ci
39388c2ecf20Sopenharmony_ci	mvpp2_txq_inc_put(port, txq_pcpu, NULL, tx_desc, MVPP2_TYPE_SKB);
39398c2ecf20Sopenharmony_ci	return 0;
39408c2ecf20Sopenharmony_ci}
39418c2ecf20Sopenharmony_ci
39428c2ecf20Sopenharmony_cistatic int mvpp2_tx_tso(struct sk_buff *skb, struct net_device *dev,
39438c2ecf20Sopenharmony_ci			struct mvpp2_tx_queue *txq,
39448c2ecf20Sopenharmony_ci			struct mvpp2_tx_queue *aggr_txq,
39458c2ecf20Sopenharmony_ci			struct mvpp2_txq_pcpu *txq_pcpu)
39468c2ecf20Sopenharmony_ci{
39478c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
39488c2ecf20Sopenharmony_ci	int hdr_sz, i, len, descs = 0;
39498c2ecf20Sopenharmony_ci	struct tso_t tso;
39508c2ecf20Sopenharmony_ci
39518c2ecf20Sopenharmony_ci	/* Check number of available descriptors */
39528c2ecf20Sopenharmony_ci	if (mvpp2_aggr_desc_num_check(port, aggr_txq, tso_count_descs(skb)) ||
39538c2ecf20Sopenharmony_ci	    mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu,
39548c2ecf20Sopenharmony_ci					     tso_count_descs(skb)))
39558c2ecf20Sopenharmony_ci		return 0;
39568c2ecf20Sopenharmony_ci
39578c2ecf20Sopenharmony_ci	hdr_sz = tso_start(skb, &tso);
39588c2ecf20Sopenharmony_ci
39598c2ecf20Sopenharmony_ci	len = skb->len - hdr_sz;
39608c2ecf20Sopenharmony_ci	while (len > 0) {
39618c2ecf20Sopenharmony_ci		int left = min_t(int, skb_shinfo(skb)->gso_size, len);
39628c2ecf20Sopenharmony_ci		char *hdr = txq_pcpu->tso_headers +
39638c2ecf20Sopenharmony_ci			    txq_pcpu->txq_put_index * TSO_HEADER_SIZE;
39648c2ecf20Sopenharmony_ci
39658c2ecf20Sopenharmony_ci		len -= left;
39668c2ecf20Sopenharmony_ci		descs++;
39678c2ecf20Sopenharmony_ci
39688c2ecf20Sopenharmony_ci		tso_build_hdr(skb, hdr, &tso, left, len == 0);
39698c2ecf20Sopenharmony_ci		mvpp2_tso_put_hdr(skb, dev, txq, aggr_txq, txq_pcpu, hdr_sz);
39708c2ecf20Sopenharmony_ci
39718c2ecf20Sopenharmony_ci		while (left > 0) {
39728c2ecf20Sopenharmony_ci			int sz = min_t(int, tso.size, left);
39738c2ecf20Sopenharmony_ci			left -= sz;
39748c2ecf20Sopenharmony_ci			descs++;
39758c2ecf20Sopenharmony_ci
39768c2ecf20Sopenharmony_ci			if (mvpp2_tso_put_data(skb, dev, &tso, txq, aggr_txq,
39778c2ecf20Sopenharmony_ci					       txq_pcpu, sz, left, len == 0))
39788c2ecf20Sopenharmony_ci				goto release;
39798c2ecf20Sopenharmony_ci			tso_build_data(skb, &tso, sz);
39808c2ecf20Sopenharmony_ci		}
39818c2ecf20Sopenharmony_ci	}
39828c2ecf20Sopenharmony_ci
39838c2ecf20Sopenharmony_ci	return descs;
39848c2ecf20Sopenharmony_ci
39858c2ecf20Sopenharmony_cirelease:
39868c2ecf20Sopenharmony_ci	for (i = descs - 1; i >= 0; i--) {
39878c2ecf20Sopenharmony_ci		struct mvpp2_tx_desc *tx_desc = txq->descs + i;
39888c2ecf20Sopenharmony_ci		tx_desc_unmap_put(port, txq, tx_desc);
39898c2ecf20Sopenharmony_ci	}
39908c2ecf20Sopenharmony_ci	return 0;
39918c2ecf20Sopenharmony_ci}
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_ci/* Main tx processing */
39948c2ecf20Sopenharmony_cistatic netdev_tx_t mvpp2_tx(struct sk_buff *skb, struct net_device *dev)
39958c2ecf20Sopenharmony_ci{
39968c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
39978c2ecf20Sopenharmony_ci	struct mvpp2_tx_queue *txq, *aggr_txq;
39988c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
39998c2ecf20Sopenharmony_ci	struct mvpp2_tx_desc *tx_desc;
40008c2ecf20Sopenharmony_ci	dma_addr_t buf_dma_addr;
40018c2ecf20Sopenharmony_ci	unsigned long flags = 0;
40028c2ecf20Sopenharmony_ci	unsigned int thread;
40038c2ecf20Sopenharmony_ci	int frags = 0;
40048c2ecf20Sopenharmony_ci	u16 txq_id;
40058c2ecf20Sopenharmony_ci	u32 tx_cmd;
40068c2ecf20Sopenharmony_ci
40078c2ecf20Sopenharmony_ci	thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
40088c2ecf20Sopenharmony_ci
40098c2ecf20Sopenharmony_ci	txq_id = skb_get_queue_mapping(skb);
40108c2ecf20Sopenharmony_ci	txq = port->txqs[txq_id];
40118c2ecf20Sopenharmony_ci	txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
40128c2ecf20Sopenharmony_ci	aggr_txq = &port->priv->aggr_txqs[thread];
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci	if (test_bit(thread, &port->priv->lock_map))
40158c2ecf20Sopenharmony_ci		spin_lock_irqsave(&port->tx_lock[thread], flags);
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_ci	if (skb_is_gso(skb)) {
40188c2ecf20Sopenharmony_ci		frags = mvpp2_tx_tso(skb, dev, txq, aggr_txq, txq_pcpu);
40198c2ecf20Sopenharmony_ci		goto out;
40208c2ecf20Sopenharmony_ci	}
40218c2ecf20Sopenharmony_ci	frags = skb_shinfo(skb)->nr_frags + 1;
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_ci	/* Check number of available descriptors */
40248c2ecf20Sopenharmony_ci	if (mvpp2_aggr_desc_num_check(port, aggr_txq, frags) ||
40258c2ecf20Sopenharmony_ci	    mvpp2_txq_reserved_desc_num_proc(port, txq, txq_pcpu, frags)) {
40268c2ecf20Sopenharmony_ci		frags = 0;
40278c2ecf20Sopenharmony_ci		goto out;
40288c2ecf20Sopenharmony_ci	}
40298c2ecf20Sopenharmony_ci
40308c2ecf20Sopenharmony_ci	/* Get a descriptor for the first part of the packet */
40318c2ecf20Sopenharmony_ci	tx_desc = mvpp2_txq_next_desc_get(aggr_txq);
40328c2ecf20Sopenharmony_ci	if (!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) ||
40338c2ecf20Sopenharmony_ci	    !mvpp2_tx_hw_tstamp(port, tx_desc, skb))
40348c2ecf20Sopenharmony_ci		mvpp2_txdesc_clear_ptp(port, tx_desc);
40358c2ecf20Sopenharmony_ci	mvpp2_txdesc_txq_set(port, tx_desc, txq->id);
40368c2ecf20Sopenharmony_ci	mvpp2_txdesc_size_set(port, tx_desc, skb_headlen(skb));
40378c2ecf20Sopenharmony_ci
40388c2ecf20Sopenharmony_ci	buf_dma_addr = dma_map_single(dev->dev.parent, skb->data,
40398c2ecf20Sopenharmony_ci				      skb_headlen(skb), DMA_TO_DEVICE);
40408c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(dev->dev.parent, buf_dma_addr))) {
40418c2ecf20Sopenharmony_ci		mvpp2_txq_desc_put(txq);
40428c2ecf20Sopenharmony_ci		frags = 0;
40438c2ecf20Sopenharmony_ci		goto out;
40448c2ecf20Sopenharmony_ci	}
40458c2ecf20Sopenharmony_ci
40468c2ecf20Sopenharmony_ci	mvpp2_txdesc_dma_addr_set(port, tx_desc, buf_dma_addr);
40478c2ecf20Sopenharmony_ci
40488c2ecf20Sopenharmony_ci	tx_cmd = mvpp2_skb_tx_csum(port, skb);
40498c2ecf20Sopenharmony_ci
40508c2ecf20Sopenharmony_ci	if (frags == 1) {
40518c2ecf20Sopenharmony_ci		/* First and Last descriptor */
40528c2ecf20Sopenharmony_ci		tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_L_DESC;
40538c2ecf20Sopenharmony_ci		mvpp2_txdesc_cmd_set(port, tx_desc, tx_cmd);
40548c2ecf20Sopenharmony_ci		mvpp2_txq_inc_put(port, txq_pcpu, skb, tx_desc, MVPP2_TYPE_SKB);
40558c2ecf20Sopenharmony_ci	} else {
40568c2ecf20Sopenharmony_ci		/* First but not Last */
40578c2ecf20Sopenharmony_ci		tx_cmd |= MVPP2_TXD_F_DESC | MVPP2_TXD_PADDING_DISABLE;
40588c2ecf20Sopenharmony_ci		mvpp2_txdesc_cmd_set(port, tx_desc, tx_cmd);
40598c2ecf20Sopenharmony_ci		mvpp2_txq_inc_put(port, txq_pcpu, NULL, tx_desc, MVPP2_TYPE_SKB);
40608c2ecf20Sopenharmony_ci
40618c2ecf20Sopenharmony_ci		/* Continue with other skb fragments */
40628c2ecf20Sopenharmony_ci		if (mvpp2_tx_frag_process(port, skb, aggr_txq, txq)) {
40638c2ecf20Sopenharmony_ci			tx_desc_unmap_put(port, txq, tx_desc);
40648c2ecf20Sopenharmony_ci			frags = 0;
40658c2ecf20Sopenharmony_ci		}
40668c2ecf20Sopenharmony_ci	}
40678c2ecf20Sopenharmony_ci
40688c2ecf20Sopenharmony_ciout:
40698c2ecf20Sopenharmony_ci	if (frags > 0) {
40708c2ecf20Sopenharmony_ci		struct mvpp2_pcpu_stats *stats = per_cpu_ptr(port->stats, thread);
40718c2ecf20Sopenharmony_ci		struct netdev_queue *nq = netdev_get_tx_queue(dev, txq_id);
40728c2ecf20Sopenharmony_ci
40738c2ecf20Sopenharmony_ci		txq_pcpu->reserved_num -= frags;
40748c2ecf20Sopenharmony_ci		txq_pcpu->count += frags;
40758c2ecf20Sopenharmony_ci		aggr_txq->count += frags;
40768c2ecf20Sopenharmony_ci
40778c2ecf20Sopenharmony_ci		/* Enable transmit */
40788c2ecf20Sopenharmony_ci		wmb();
40798c2ecf20Sopenharmony_ci		mvpp2_aggr_txq_pend_desc_add(port, frags);
40808c2ecf20Sopenharmony_ci
40818c2ecf20Sopenharmony_ci		if (txq_pcpu->count >= txq_pcpu->stop_threshold)
40828c2ecf20Sopenharmony_ci			netif_tx_stop_queue(nq);
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_ci		u64_stats_update_begin(&stats->syncp);
40858c2ecf20Sopenharmony_ci		stats->tx_packets++;
40868c2ecf20Sopenharmony_ci		stats->tx_bytes += skb->len;
40878c2ecf20Sopenharmony_ci		u64_stats_update_end(&stats->syncp);
40888c2ecf20Sopenharmony_ci	} else {
40898c2ecf20Sopenharmony_ci		dev->stats.tx_dropped++;
40908c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
40918c2ecf20Sopenharmony_ci	}
40928c2ecf20Sopenharmony_ci
40938c2ecf20Sopenharmony_ci	/* Finalize TX processing */
40948c2ecf20Sopenharmony_ci	if (!port->has_tx_irqs && txq_pcpu->count >= txq->done_pkts_coal)
40958c2ecf20Sopenharmony_ci		mvpp2_txq_done(port, txq, txq_pcpu);
40968c2ecf20Sopenharmony_ci
40978c2ecf20Sopenharmony_ci	/* Set the timer in case not all frags were processed */
40988c2ecf20Sopenharmony_ci	if (!port->has_tx_irqs && txq_pcpu->count <= frags &&
40998c2ecf20Sopenharmony_ci	    txq_pcpu->count > 0) {
41008c2ecf20Sopenharmony_ci		struct mvpp2_port_pcpu *port_pcpu = per_cpu_ptr(port->pcpu, thread);
41018c2ecf20Sopenharmony_ci
41028c2ecf20Sopenharmony_ci		if (!port_pcpu->timer_scheduled) {
41038c2ecf20Sopenharmony_ci			port_pcpu->timer_scheduled = true;
41048c2ecf20Sopenharmony_ci			hrtimer_start(&port_pcpu->tx_done_timer,
41058c2ecf20Sopenharmony_ci				      MVPP2_TXDONE_HRTIMER_PERIOD_NS,
41068c2ecf20Sopenharmony_ci				      HRTIMER_MODE_REL_PINNED_SOFT);
41078c2ecf20Sopenharmony_ci		}
41088c2ecf20Sopenharmony_ci	}
41098c2ecf20Sopenharmony_ci
41108c2ecf20Sopenharmony_ci	if (test_bit(thread, &port->priv->lock_map))
41118c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&port->tx_lock[thread], flags);
41128c2ecf20Sopenharmony_ci
41138c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
41148c2ecf20Sopenharmony_ci}
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_cistatic inline void mvpp2_cause_error(struct net_device *dev, int cause)
41178c2ecf20Sopenharmony_ci{
41188c2ecf20Sopenharmony_ci	if (cause & MVPP2_CAUSE_FCS_ERR_MASK)
41198c2ecf20Sopenharmony_ci		netdev_err(dev, "FCS error\n");
41208c2ecf20Sopenharmony_ci	if (cause & MVPP2_CAUSE_RX_FIFO_OVERRUN_MASK)
41218c2ecf20Sopenharmony_ci		netdev_err(dev, "rx fifo overrun error\n");
41228c2ecf20Sopenharmony_ci	if (cause & MVPP2_CAUSE_TX_FIFO_UNDERRUN_MASK)
41238c2ecf20Sopenharmony_ci		netdev_err(dev, "tx fifo underrun error\n");
41248c2ecf20Sopenharmony_ci}
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_cistatic int mvpp2_poll(struct napi_struct *napi, int budget)
41278c2ecf20Sopenharmony_ci{
41288c2ecf20Sopenharmony_ci	u32 cause_rx_tx, cause_rx, cause_tx, cause_misc;
41298c2ecf20Sopenharmony_ci	int rx_done = 0;
41308c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(napi->dev);
41318c2ecf20Sopenharmony_ci	struct mvpp2_queue_vector *qv;
41328c2ecf20Sopenharmony_ci	unsigned int thread = mvpp2_cpu_to_thread(port->priv, smp_processor_id());
41338c2ecf20Sopenharmony_ci
41348c2ecf20Sopenharmony_ci	qv = container_of(napi, struct mvpp2_queue_vector, napi);
41358c2ecf20Sopenharmony_ci
41368c2ecf20Sopenharmony_ci	/* Rx/Tx cause register
41378c2ecf20Sopenharmony_ci	 *
41388c2ecf20Sopenharmony_ci	 * Bits 0-15: each bit indicates received packets on the Rx queue
41398c2ecf20Sopenharmony_ci	 * (bit 0 is for Rx queue 0).
41408c2ecf20Sopenharmony_ci	 *
41418c2ecf20Sopenharmony_ci	 * Bits 16-23: each bit indicates transmitted packets on the Tx queue
41428c2ecf20Sopenharmony_ci	 * (bit 16 is for Tx queue 0).
41438c2ecf20Sopenharmony_ci	 *
41448c2ecf20Sopenharmony_ci	 * Each CPU has its own Rx/Tx cause register
41458c2ecf20Sopenharmony_ci	 */
41468c2ecf20Sopenharmony_ci	cause_rx_tx = mvpp2_thread_read_relaxed(port->priv, qv->sw_thread_id,
41478c2ecf20Sopenharmony_ci						MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
41508c2ecf20Sopenharmony_ci	if (cause_misc) {
41518c2ecf20Sopenharmony_ci		mvpp2_cause_error(port->dev, cause_misc);
41528c2ecf20Sopenharmony_ci
41538c2ecf20Sopenharmony_ci		/* Clear the cause register */
41548c2ecf20Sopenharmony_ci		mvpp2_write(port->priv, MVPP2_ISR_MISC_CAUSE_REG, 0);
41558c2ecf20Sopenharmony_ci		mvpp2_thread_write(port->priv, thread,
41568c2ecf20Sopenharmony_ci				   MVPP2_ISR_RX_TX_CAUSE_REG(port->id),
41578c2ecf20Sopenharmony_ci				   cause_rx_tx & ~MVPP2_CAUSE_MISC_SUM_MASK);
41588c2ecf20Sopenharmony_ci	}
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci	if (port->has_tx_irqs) {
41618c2ecf20Sopenharmony_ci		cause_tx = cause_rx_tx & MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
41628c2ecf20Sopenharmony_ci		if (cause_tx) {
41638c2ecf20Sopenharmony_ci			cause_tx >>= MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_OFFSET;
41648c2ecf20Sopenharmony_ci			mvpp2_tx_done(port, cause_tx, qv->sw_thread_id);
41658c2ecf20Sopenharmony_ci		}
41668c2ecf20Sopenharmony_ci	}
41678c2ecf20Sopenharmony_ci
41688c2ecf20Sopenharmony_ci	/* Process RX packets */
41698c2ecf20Sopenharmony_ci	cause_rx = cause_rx_tx &
41708c2ecf20Sopenharmony_ci		   MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK(port->priv->hw_version);
41718c2ecf20Sopenharmony_ci	cause_rx <<= qv->first_rxq;
41728c2ecf20Sopenharmony_ci	cause_rx |= qv->pending_cause_rx;
41738c2ecf20Sopenharmony_ci	while (cause_rx && budget > 0) {
41748c2ecf20Sopenharmony_ci		int count;
41758c2ecf20Sopenharmony_ci		struct mvpp2_rx_queue *rxq;
41768c2ecf20Sopenharmony_ci
41778c2ecf20Sopenharmony_ci		rxq = mvpp2_get_rx_queue(port, cause_rx);
41788c2ecf20Sopenharmony_ci		if (!rxq)
41798c2ecf20Sopenharmony_ci			break;
41808c2ecf20Sopenharmony_ci
41818c2ecf20Sopenharmony_ci		count = mvpp2_rx(port, napi, budget, rxq);
41828c2ecf20Sopenharmony_ci		rx_done += count;
41838c2ecf20Sopenharmony_ci		budget -= count;
41848c2ecf20Sopenharmony_ci		if (budget > 0) {
41858c2ecf20Sopenharmony_ci			/* Clear the bit associated to this Rx queue
41868c2ecf20Sopenharmony_ci			 * so that next iteration will continue from
41878c2ecf20Sopenharmony_ci			 * the next Rx queue.
41888c2ecf20Sopenharmony_ci			 */
41898c2ecf20Sopenharmony_ci			cause_rx &= ~(1 << rxq->logic_rxq);
41908c2ecf20Sopenharmony_ci		}
41918c2ecf20Sopenharmony_ci	}
41928c2ecf20Sopenharmony_ci
41938c2ecf20Sopenharmony_ci	if (budget > 0) {
41948c2ecf20Sopenharmony_ci		cause_rx = 0;
41958c2ecf20Sopenharmony_ci		napi_complete_done(napi, rx_done);
41968c2ecf20Sopenharmony_ci
41978c2ecf20Sopenharmony_ci		mvpp2_qvec_interrupt_enable(qv);
41988c2ecf20Sopenharmony_ci	}
41998c2ecf20Sopenharmony_ci	qv->pending_cause_rx = cause_rx;
42008c2ecf20Sopenharmony_ci	return rx_done;
42018c2ecf20Sopenharmony_ci}
42028c2ecf20Sopenharmony_ci
42038c2ecf20Sopenharmony_cistatic void mvpp22_mode_reconfigure(struct mvpp2_port *port)
42048c2ecf20Sopenharmony_ci{
42058c2ecf20Sopenharmony_ci	u32 ctrl3;
42068c2ecf20Sopenharmony_ci
42078c2ecf20Sopenharmony_ci	/* Set the GMAC & XLG MAC in reset */
42088c2ecf20Sopenharmony_ci	mvpp2_mac_reset_assert(port);
42098c2ecf20Sopenharmony_ci
42108c2ecf20Sopenharmony_ci	/* Set the MPCS and XPCS in reset */
42118c2ecf20Sopenharmony_ci	mvpp22_pcs_reset_assert(port);
42128c2ecf20Sopenharmony_ci
42138c2ecf20Sopenharmony_ci	/* comphy reconfiguration */
42148c2ecf20Sopenharmony_ci	mvpp22_comphy_init(port);
42158c2ecf20Sopenharmony_ci
42168c2ecf20Sopenharmony_ci	/* gop reconfiguration */
42178c2ecf20Sopenharmony_ci	mvpp22_gop_init(port);
42188c2ecf20Sopenharmony_ci
42198c2ecf20Sopenharmony_ci	mvpp22_pcs_reset_deassert(port);
42208c2ecf20Sopenharmony_ci
42218c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port)) {
42228c2ecf20Sopenharmony_ci		ctrl3 = readl(port->base + MVPP22_XLG_CTRL3_REG);
42238c2ecf20Sopenharmony_ci		ctrl3 &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
42248c2ecf20Sopenharmony_ci
42258c2ecf20Sopenharmony_ci		if (mvpp2_is_xlg(port->phy_interface))
42268c2ecf20Sopenharmony_ci			ctrl3 |= MVPP22_XLG_CTRL3_MACMODESELECT_10G;
42278c2ecf20Sopenharmony_ci		else
42288c2ecf20Sopenharmony_ci			ctrl3 |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
42298c2ecf20Sopenharmony_ci
42308c2ecf20Sopenharmony_ci		writel(ctrl3, port->base + MVPP22_XLG_CTRL3_REG);
42318c2ecf20Sopenharmony_ci	}
42328c2ecf20Sopenharmony_ci
42338c2ecf20Sopenharmony_ci	if (mvpp2_port_supports_xlg(port) && mvpp2_is_xlg(port->phy_interface))
42348c2ecf20Sopenharmony_ci		mvpp2_xlg_max_rx_size_set(port);
42358c2ecf20Sopenharmony_ci	else
42368c2ecf20Sopenharmony_ci		mvpp2_gmac_max_rx_size_set(port);
42378c2ecf20Sopenharmony_ci}
42388c2ecf20Sopenharmony_ci
42398c2ecf20Sopenharmony_ci/* Set hw internals when starting port */
42408c2ecf20Sopenharmony_cistatic void mvpp2_start_dev(struct mvpp2_port *port)
42418c2ecf20Sopenharmony_ci{
42428c2ecf20Sopenharmony_ci	int i;
42438c2ecf20Sopenharmony_ci
42448c2ecf20Sopenharmony_ci	mvpp2_txp_max_tx_size_set(port);
42458c2ecf20Sopenharmony_ci
42468c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++)
42478c2ecf20Sopenharmony_ci		napi_enable(&port->qvecs[i].napi);
42488c2ecf20Sopenharmony_ci
42498c2ecf20Sopenharmony_ci	/* Enable interrupts on all threads */
42508c2ecf20Sopenharmony_ci	mvpp2_interrupts_enable(port);
42518c2ecf20Sopenharmony_ci
42528c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP22)
42538c2ecf20Sopenharmony_ci		mvpp22_mode_reconfigure(port);
42548c2ecf20Sopenharmony_ci
42558c2ecf20Sopenharmony_ci	if (port->phylink) {
42568c2ecf20Sopenharmony_ci		phylink_start(port->phylink);
42578c2ecf20Sopenharmony_ci	} else {
42588c2ecf20Sopenharmony_ci		mvpp2_acpi_start(port);
42598c2ecf20Sopenharmony_ci	}
42608c2ecf20Sopenharmony_ci
42618c2ecf20Sopenharmony_ci	netif_tx_start_all_queues(port->dev);
42628c2ecf20Sopenharmony_ci
42638c2ecf20Sopenharmony_ci	clear_bit(0, &port->state);
42648c2ecf20Sopenharmony_ci}
42658c2ecf20Sopenharmony_ci
42668c2ecf20Sopenharmony_ci/* Set hw internals when stopping port */
42678c2ecf20Sopenharmony_cistatic void mvpp2_stop_dev(struct mvpp2_port *port)
42688c2ecf20Sopenharmony_ci{
42698c2ecf20Sopenharmony_ci	int i;
42708c2ecf20Sopenharmony_ci
42718c2ecf20Sopenharmony_ci	set_bit(0, &port->state);
42728c2ecf20Sopenharmony_ci
42738c2ecf20Sopenharmony_ci	/* Disable interrupts on all threads */
42748c2ecf20Sopenharmony_ci	mvpp2_interrupts_disable(port);
42758c2ecf20Sopenharmony_ci
42768c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++)
42778c2ecf20Sopenharmony_ci		napi_disable(&port->qvecs[i].napi);
42788c2ecf20Sopenharmony_ci
42798c2ecf20Sopenharmony_ci	if (port->phylink)
42808c2ecf20Sopenharmony_ci		phylink_stop(port->phylink);
42818c2ecf20Sopenharmony_ci	phy_power_off(port->comphy);
42828c2ecf20Sopenharmony_ci}
42838c2ecf20Sopenharmony_ci
42848c2ecf20Sopenharmony_cistatic int mvpp2_check_ringparam_valid(struct net_device *dev,
42858c2ecf20Sopenharmony_ci				       struct ethtool_ringparam *ring)
42868c2ecf20Sopenharmony_ci{
42878c2ecf20Sopenharmony_ci	u16 new_rx_pending = ring->rx_pending;
42888c2ecf20Sopenharmony_ci	u16 new_tx_pending = ring->tx_pending;
42898c2ecf20Sopenharmony_ci
42908c2ecf20Sopenharmony_ci	if (ring->rx_pending == 0 || ring->tx_pending == 0)
42918c2ecf20Sopenharmony_ci		return -EINVAL;
42928c2ecf20Sopenharmony_ci
42938c2ecf20Sopenharmony_ci	if (ring->rx_pending > MVPP2_MAX_RXD_MAX)
42948c2ecf20Sopenharmony_ci		new_rx_pending = MVPP2_MAX_RXD_MAX;
42958c2ecf20Sopenharmony_ci	else if (!IS_ALIGNED(ring->rx_pending, 16))
42968c2ecf20Sopenharmony_ci		new_rx_pending = ALIGN(ring->rx_pending, 16);
42978c2ecf20Sopenharmony_ci
42988c2ecf20Sopenharmony_ci	if (ring->tx_pending > MVPP2_MAX_TXD_MAX)
42998c2ecf20Sopenharmony_ci		new_tx_pending = MVPP2_MAX_TXD_MAX;
43008c2ecf20Sopenharmony_ci	else if (!IS_ALIGNED(ring->tx_pending, 32))
43018c2ecf20Sopenharmony_ci		new_tx_pending = ALIGN(ring->tx_pending, 32);
43028c2ecf20Sopenharmony_ci
43038c2ecf20Sopenharmony_ci	/* The Tx ring size cannot be smaller than the minimum number of
43048c2ecf20Sopenharmony_ci	 * descriptors needed for TSO.
43058c2ecf20Sopenharmony_ci	 */
43068c2ecf20Sopenharmony_ci	if (new_tx_pending < MVPP2_MAX_SKB_DESCS)
43078c2ecf20Sopenharmony_ci		new_tx_pending = ALIGN(MVPP2_MAX_SKB_DESCS, 32);
43088c2ecf20Sopenharmony_ci
43098c2ecf20Sopenharmony_ci	if (ring->rx_pending != new_rx_pending) {
43108c2ecf20Sopenharmony_ci		netdev_info(dev, "illegal Rx ring size value %d, round to %d\n",
43118c2ecf20Sopenharmony_ci			    ring->rx_pending, new_rx_pending);
43128c2ecf20Sopenharmony_ci		ring->rx_pending = new_rx_pending;
43138c2ecf20Sopenharmony_ci	}
43148c2ecf20Sopenharmony_ci
43158c2ecf20Sopenharmony_ci	if (ring->tx_pending != new_tx_pending) {
43168c2ecf20Sopenharmony_ci		netdev_info(dev, "illegal Tx ring size value %d, round to %d\n",
43178c2ecf20Sopenharmony_ci			    ring->tx_pending, new_tx_pending);
43188c2ecf20Sopenharmony_ci		ring->tx_pending = new_tx_pending;
43198c2ecf20Sopenharmony_ci	}
43208c2ecf20Sopenharmony_ci
43218c2ecf20Sopenharmony_ci	return 0;
43228c2ecf20Sopenharmony_ci}
43238c2ecf20Sopenharmony_ci
43248c2ecf20Sopenharmony_cistatic void mvpp21_get_mac_address(struct mvpp2_port *port, unsigned char *addr)
43258c2ecf20Sopenharmony_ci{
43268c2ecf20Sopenharmony_ci	u32 mac_addr_l, mac_addr_m, mac_addr_h;
43278c2ecf20Sopenharmony_ci
43288c2ecf20Sopenharmony_ci	mac_addr_l = readl(port->base + MVPP2_GMAC_CTRL_1_REG);
43298c2ecf20Sopenharmony_ci	mac_addr_m = readl(port->priv->lms_base + MVPP2_SRC_ADDR_MIDDLE);
43308c2ecf20Sopenharmony_ci	mac_addr_h = readl(port->priv->lms_base + MVPP2_SRC_ADDR_HIGH);
43318c2ecf20Sopenharmony_ci	addr[0] = (mac_addr_h >> 24) & 0xFF;
43328c2ecf20Sopenharmony_ci	addr[1] = (mac_addr_h >> 16) & 0xFF;
43338c2ecf20Sopenharmony_ci	addr[2] = (mac_addr_h >> 8) & 0xFF;
43348c2ecf20Sopenharmony_ci	addr[3] = mac_addr_h & 0xFF;
43358c2ecf20Sopenharmony_ci	addr[4] = mac_addr_m & 0xFF;
43368c2ecf20Sopenharmony_ci	addr[5] = (mac_addr_l >> MVPP2_GMAC_SA_LOW_OFFS) & 0xFF;
43378c2ecf20Sopenharmony_ci}
43388c2ecf20Sopenharmony_ci
43398c2ecf20Sopenharmony_cistatic int mvpp2_irqs_init(struct mvpp2_port *port)
43408c2ecf20Sopenharmony_ci{
43418c2ecf20Sopenharmony_ci	int err, i;
43428c2ecf20Sopenharmony_ci
43438c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++) {
43448c2ecf20Sopenharmony_ci		struct mvpp2_queue_vector *qv = port->qvecs + i;
43458c2ecf20Sopenharmony_ci
43468c2ecf20Sopenharmony_ci		if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) {
43478c2ecf20Sopenharmony_ci			qv->mask = kzalloc(cpumask_size(), GFP_KERNEL);
43488c2ecf20Sopenharmony_ci			if (!qv->mask) {
43498c2ecf20Sopenharmony_ci				err = -ENOMEM;
43508c2ecf20Sopenharmony_ci				goto err;
43518c2ecf20Sopenharmony_ci			}
43528c2ecf20Sopenharmony_ci
43538c2ecf20Sopenharmony_ci			irq_set_status_flags(qv->irq, IRQ_NO_BALANCING);
43548c2ecf20Sopenharmony_ci		}
43558c2ecf20Sopenharmony_ci
43568c2ecf20Sopenharmony_ci		err = request_irq(qv->irq, mvpp2_isr, 0, port->dev->name, qv);
43578c2ecf20Sopenharmony_ci		if (err)
43588c2ecf20Sopenharmony_ci			goto err;
43598c2ecf20Sopenharmony_ci
43608c2ecf20Sopenharmony_ci		if (qv->type == MVPP2_QUEUE_VECTOR_PRIVATE) {
43618c2ecf20Sopenharmony_ci			unsigned int cpu;
43628c2ecf20Sopenharmony_ci
43638c2ecf20Sopenharmony_ci			for_each_present_cpu(cpu) {
43648c2ecf20Sopenharmony_ci				if (mvpp2_cpu_to_thread(port->priv, cpu) ==
43658c2ecf20Sopenharmony_ci				    qv->sw_thread_id)
43668c2ecf20Sopenharmony_ci					cpumask_set_cpu(cpu, qv->mask);
43678c2ecf20Sopenharmony_ci			}
43688c2ecf20Sopenharmony_ci
43698c2ecf20Sopenharmony_ci			irq_set_affinity_hint(qv->irq, qv->mask);
43708c2ecf20Sopenharmony_ci		}
43718c2ecf20Sopenharmony_ci	}
43728c2ecf20Sopenharmony_ci
43738c2ecf20Sopenharmony_ci	return 0;
43748c2ecf20Sopenharmony_cierr:
43758c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++) {
43768c2ecf20Sopenharmony_ci		struct mvpp2_queue_vector *qv = port->qvecs + i;
43778c2ecf20Sopenharmony_ci
43788c2ecf20Sopenharmony_ci		irq_set_affinity_hint(qv->irq, NULL);
43798c2ecf20Sopenharmony_ci		kfree(qv->mask);
43808c2ecf20Sopenharmony_ci		qv->mask = NULL;
43818c2ecf20Sopenharmony_ci		free_irq(qv->irq, qv);
43828c2ecf20Sopenharmony_ci	}
43838c2ecf20Sopenharmony_ci
43848c2ecf20Sopenharmony_ci	return err;
43858c2ecf20Sopenharmony_ci}
43868c2ecf20Sopenharmony_ci
43878c2ecf20Sopenharmony_cistatic void mvpp2_irqs_deinit(struct mvpp2_port *port)
43888c2ecf20Sopenharmony_ci{
43898c2ecf20Sopenharmony_ci	int i;
43908c2ecf20Sopenharmony_ci
43918c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++) {
43928c2ecf20Sopenharmony_ci		struct mvpp2_queue_vector *qv = port->qvecs + i;
43938c2ecf20Sopenharmony_ci
43948c2ecf20Sopenharmony_ci		irq_set_affinity_hint(qv->irq, NULL);
43958c2ecf20Sopenharmony_ci		kfree(qv->mask);
43968c2ecf20Sopenharmony_ci		qv->mask = NULL;
43978c2ecf20Sopenharmony_ci		irq_clear_status_flags(qv->irq, IRQ_NO_BALANCING);
43988c2ecf20Sopenharmony_ci		free_irq(qv->irq, qv);
43998c2ecf20Sopenharmony_ci	}
44008c2ecf20Sopenharmony_ci}
44018c2ecf20Sopenharmony_ci
44028c2ecf20Sopenharmony_cistatic bool mvpp22_rss_is_supported(void)
44038c2ecf20Sopenharmony_ci{
44048c2ecf20Sopenharmony_ci	return queue_mode == MVPP2_QDIST_MULTI_MODE;
44058c2ecf20Sopenharmony_ci}
44068c2ecf20Sopenharmony_ci
44078c2ecf20Sopenharmony_cistatic int mvpp2_open(struct net_device *dev)
44088c2ecf20Sopenharmony_ci{
44098c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
44108c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
44118c2ecf20Sopenharmony_ci	unsigned char mac_bcast[ETH_ALEN] = {
44128c2ecf20Sopenharmony_ci			0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
44138c2ecf20Sopenharmony_ci	bool valid = false;
44148c2ecf20Sopenharmony_ci	int err;
44158c2ecf20Sopenharmony_ci
44168c2ecf20Sopenharmony_ci	err = mvpp2_prs_mac_da_accept(port, mac_bcast, true);
44178c2ecf20Sopenharmony_ci	if (err) {
44188c2ecf20Sopenharmony_ci		netdev_err(dev, "mvpp2_prs_mac_da_accept BC failed\n");
44198c2ecf20Sopenharmony_ci		return err;
44208c2ecf20Sopenharmony_ci	}
44218c2ecf20Sopenharmony_ci	err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, true);
44228c2ecf20Sopenharmony_ci	if (err) {
44238c2ecf20Sopenharmony_ci		netdev_err(dev, "mvpp2_prs_mac_da_accept own addr failed\n");
44248c2ecf20Sopenharmony_ci		return err;
44258c2ecf20Sopenharmony_ci	}
44268c2ecf20Sopenharmony_ci	err = mvpp2_prs_tag_mode_set(port->priv, port->id, MVPP2_TAG_TYPE_MH);
44278c2ecf20Sopenharmony_ci	if (err) {
44288c2ecf20Sopenharmony_ci		netdev_err(dev, "mvpp2_prs_tag_mode_set failed\n");
44298c2ecf20Sopenharmony_ci		return err;
44308c2ecf20Sopenharmony_ci	}
44318c2ecf20Sopenharmony_ci	err = mvpp2_prs_def_flow(port);
44328c2ecf20Sopenharmony_ci	if (err) {
44338c2ecf20Sopenharmony_ci		netdev_err(dev, "mvpp2_prs_def_flow failed\n");
44348c2ecf20Sopenharmony_ci		return err;
44358c2ecf20Sopenharmony_ci	}
44368c2ecf20Sopenharmony_ci
44378c2ecf20Sopenharmony_ci	/* Allocate the Rx/Tx queues */
44388c2ecf20Sopenharmony_ci	err = mvpp2_setup_rxqs(port);
44398c2ecf20Sopenharmony_ci	if (err) {
44408c2ecf20Sopenharmony_ci		netdev_err(port->dev, "cannot allocate Rx queues\n");
44418c2ecf20Sopenharmony_ci		return err;
44428c2ecf20Sopenharmony_ci	}
44438c2ecf20Sopenharmony_ci
44448c2ecf20Sopenharmony_ci	err = mvpp2_setup_txqs(port);
44458c2ecf20Sopenharmony_ci	if (err) {
44468c2ecf20Sopenharmony_ci		netdev_err(port->dev, "cannot allocate Tx queues\n");
44478c2ecf20Sopenharmony_ci		goto err_cleanup_rxqs;
44488c2ecf20Sopenharmony_ci	}
44498c2ecf20Sopenharmony_ci
44508c2ecf20Sopenharmony_ci	err = mvpp2_irqs_init(port);
44518c2ecf20Sopenharmony_ci	if (err) {
44528c2ecf20Sopenharmony_ci		netdev_err(port->dev, "cannot init IRQs\n");
44538c2ecf20Sopenharmony_ci		goto err_cleanup_txqs;
44548c2ecf20Sopenharmony_ci	}
44558c2ecf20Sopenharmony_ci
44568c2ecf20Sopenharmony_ci	/* Phylink isn't supported yet in ACPI mode */
44578c2ecf20Sopenharmony_ci	if (port->of_node) {
44588c2ecf20Sopenharmony_ci		err = phylink_of_phy_connect(port->phylink, port->of_node, 0);
44598c2ecf20Sopenharmony_ci		if (err) {
44608c2ecf20Sopenharmony_ci			netdev_err(port->dev, "could not attach PHY (%d)\n",
44618c2ecf20Sopenharmony_ci				   err);
44628c2ecf20Sopenharmony_ci			goto err_free_irq;
44638c2ecf20Sopenharmony_ci		}
44648c2ecf20Sopenharmony_ci
44658c2ecf20Sopenharmony_ci		valid = true;
44668c2ecf20Sopenharmony_ci	}
44678c2ecf20Sopenharmony_ci
44688c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22 && port->port_irq) {
44698c2ecf20Sopenharmony_ci		err = request_irq(port->port_irq, mvpp2_port_isr, 0,
44708c2ecf20Sopenharmony_ci				  dev->name, port);
44718c2ecf20Sopenharmony_ci		if (err) {
44728c2ecf20Sopenharmony_ci			netdev_err(port->dev,
44738c2ecf20Sopenharmony_ci				   "cannot request port link/ptp IRQ %d\n",
44748c2ecf20Sopenharmony_ci				   port->port_irq);
44758c2ecf20Sopenharmony_ci			goto err_free_irq;
44768c2ecf20Sopenharmony_ci		}
44778c2ecf20Sopenharmony_ci
44788c2ecf20Sopenharmony_ci		mvpp22_gop_setup_irq(port);
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci		/* In default link is down */
44818c2ecf20Sopenharmony_ci		netif_carrier_off(port->dev);
44828c2ecf20Sopenharmony_ci
44838c2ecf20Sopenharmony_ci		valid = true;
44848c2ecf20Sopenharmony_ci	} else {
44858c2ecf20Sopenharmony_ci		port->port_irq = 0;
44868c2ecf20Sopenharmony_ci	}
44878c2ecf20Sopenharmony_ci
44888c2ecf20Sopenharmony_ci	if (!valid) {
44898c2ecf20Sopenharmony_ci		netdev_err(port->dev,
44908c2ecf20Sopenharmony_ci			   "invalid configuration: no dt or link IRQ");
44918c2ecf20Sopenharmony_ci		err = -ENOENT;
44928c2ecf20Sopenharmony_ci		goto err_free_irq;
44938c2ecf20Sopenharmony_ci	}
44948c2ecf20Sopenharmony_ci
44958c2ecf20Sopenharmony_ci	/* Unmask interrupts on all CPUs */
44968c2ecf20Sopenharmony_ci	on_each_cpu(mvpp2_interrupts_unmask, port, 1);
44978c2ecf20Sopenharmony_ci	mvpp2_shared_interrupt_mask_unmask(port, false);
44988c2ecf20Sopenharmony_ci
44998c2ecf20Sopenharmony_ci	mvpp2_start_dev(port);
45008c2ecf20Sopenharmony_ci
45018c2ecf20Sopenharmony_ci	/* Start hardware statistics gathering */
45028c2ecf20Sopenharmony_ci	queue_delayed_work(priv->stats_queue, &port->stats_work,
45038c2ecf20Sopenharmony_ci			   MVPP2_MIB_COUNTERS_STATS_DELAY);
45048c2ecf20Sopenharmony_ci
45058c2ecf20Sopenharmony_ci	return 0;
45068c2ecf20Sopenharmony_ci
45078c2ecf20Sopenharmony_cierr_free_irq:
45088c2ecf20Sopenharmony_ci	mvpp2_irqs_deinit(port);
45098c2ecf20Sopenharmony_cierr_cleanup_txqs:
45108c2ecf20Sopenharmony_ci	mvpp2_cleanup_txqs(port);
45118c2ecf20Sopenharmony_cierr_cleanup_rxqs:
45128c2ecf20Sopenharmony_ci	mvpp2_cleanup_rxqs(port);
45138c2ecf20Sopenharmony_ci	return err;
45148c2ecf20Sopenharmony_ci}
45158c2ecf20Sopenharmony_ci
45168c2ecf20Sopenharmony_cistatic int mvpp2_stop(struct net_device *dev)
45178c2ecf20Sopenharmony_ci{
45188c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
45198c2ecf20Sopenharmony_ci	struct mvpp2_port_pcpu *port_pcpu;
45208c2ecf20Sopenharmony_ci	unsigned int thread;
45218c2ecf20Sopenharmony_ci
45228c2ecf20Sopenharmony_ci	mvpp2_stop_dev(port);
45238c2ecf20Sopenharmony_ci
45248c2ecf20Sopenharmony_ci	/* Mask interrupts on all threads */
45258c2ecf20Sopenharmony_ci	on_each_cpu(mvpp2_interrupts_mask, port, 1);
45268c2ecf20Sopenharmony_ci	mvpp2_shared_interrupt_mask_unmask(port, true);
45278c2ecf20Sopenharmony_ci
45288c2ecf20Sopenharmony_ci	if (port->phylink)
45298c2ecf20Sopenharmony_ci		phylink_disconnect_phy(port->phylink);
45308c2ecf20Sopenharmony_ci	if (port->port_irq)
45318c2ecf20Sopenharmony_ci		free_irq(port->port_irq, port);
45328c2ecf20Sopenharmony_ci
45338c2ecf20Sopenharmony_ci	mvpp2_irqs_deinit(port);
45348c2ecf20Sopenharmony_ci	if (!port->has_tx_irqs) {
45358c2ecf20Sopenharmony_ci		for (thread = 0; thread < port->priv->nthreads; thread++) {
45368c2ecf20Sopenharmony_ci			port_pcpu = per_cpu_ptr(port->pcpu, thread);
45378c2ecf20Sopenharmony_ci
45388c2ecf20Sopenharmony_ci			hrtimer_cancel(&port_pcpu->tx_done_timer);
45398c2ecf20Sopenharmony_ci			port_pcpu->timer_scheduled = false;
45408c2ecf20Sopenharmony_ci		}
45418c2ecf20Sopenharmony_ci	}
45428c2ecf20Sopenharmony_ci	mvpp2_cleanup_rxqs(port);
45438c2ecf20Sopenharmony_ci	mvpp2_cleanup_txqs(port);
45448c2ecf20Sopenharmony_ci
45458c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&port->stats_work);
45468c2ecf20Sopenharmony_ci
45478c2ecf20Sopenharmony_ci	mvpp2_mac_reset_assert(port);
45488c2ecf20Sopenharmony_ci	mvpp22_pcs_reset_assert(port);
45498c2ecf20Sopenharmony_ci
45508c2ecf20Sopenharmony_ci	return 0;
45518c2ecf20Sopenharmony_ci}
45528c2ecf20Sopenharmony_ci
45538c2ecf20Sopenharmony_cistatic int mvpp2_prs_mac_da_accept_list(struct mvpp2_port *port,
45548c2ecf20Sopenharmony_ci					struct netdev_hw_addr_list *list)
45558c2ecf20Sopenharmony_ci{
45568c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
45578c2ecf20Sopenharmony_ci	int ret;
45588c2ecf20Sopenharmony_ci
45598c2ecf20Sopenharmony_ci	netdev_hw_addr_list_for_each(ha, list) {
45608c2ecf20Sopenharmony_ci		ret = mvpp2_prs_mac_da_accept(port, ha->addr, true);
45618c2ecf20Sopenharmony_ci		if (ret)
45628c2ecf20Sopenharmony_ci			return ret;
45638c2ecf20Sopenharmony_ci	}
45648c2ecf20Sopenharmony_ci
45658c2ecf20Sopenharmony_ci	return 0;
45668c2ecf20Sopenharmony_ci}
45678c2ecf20Sopenharmony_ci
45688c2ecf20Sopenharmony_cistatic void mvpp2_set_rx_promisc(struct mvpp2_port *port, bool enable)
45698c2ecf20Sopenharmony_ci{
45708c2ecf20Sopenharmony_ci	if (!enable && (port->dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
45718c2ecf20Sopenharmony_ci		mvpp2_prs_vid_enable_filtering(port);
45728c2ecf20Sopenharmony_ci	else
45738c2ecf20Sopenharmony_ci		mvpp2_prs_vid_disable_filtering(port);
45748c2ecf20Sopenharmony_ci
45758c2ecf20Sopenharmony_ci	mvpp2_prs_mac_promisc_set(port->priv, port->id,
45768c2ecf20Sopenharmony_ci				  MVPP2_PRS_L2_UNI_CAST, enable);
45778c2ecf20Sopenharmony_ci
45788c2ecf20Sopenharmony_ci	mvpp2_prs_mac_promisc_set(port->priv, port->id,
45798c2ecf20Sopenharmony_ci				  MVPP2_PRS_L2_MULTI_CAST, enable);
45808c2ecf20Sopenharmony_ci}
45818c2ecf20Sopenharmony_ci
45828c2ecf20Sopenharmony_cistatic void mvpp2_set_rx_mode(struct net_device *dev)
45838c2ecf20Sopenharmony_ci{
45848c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
45858c2ecf20Sopenharmony_ci
45868c2ecf20Sopenharmony_ci	/* Clear the whole UC and MC list */
45878c2ecf20Sopenharmony_ci	mvpp2_prs_mac_del_all(port);
45888c2ecf20Sopenharmony_ci
45898c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
45908c2ecf20Sopenharmony_ci		mvpp2_set_rx_promisc(port, true);
45918c2ecf20Sopenharmony_ci		return;
45928c2ecf20Sopenharmony_ci	}
45938c2ecf20Sopenharmony_ci
45948c2ecf20Sopenharmony_ci	mvpp2_set_rx_promisc(port, false);
45958c2ecf20Sopenharmony_ci
45968c2ecf20Sopenharmony_ci	if (netdev_uc_count(dev) > MVPP2_PRS_MAC_UC_FILT_MAX ||
45978c2ecf20Sopenharmony_ci	    mvpp2_prs_mac_da_accept_list(port, &dev->uc))
45988c2ecf20Sopenharmony_ci		mvpp2_prs_mac_promisc_set(port->priv, port->id,
45998c2ecf20Sopenharmony_ci					  MVPP2_PRS_L2_UNI_CAST, true);
46008c2ecf20Sopenharmony_ci
46018c2ecf20Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI) {
46028c2ecf20Sopenharmony_ci		mvpp2_prs_mac_promisc_set(port->priv, port->id,
46038c2ecf20Sopenharmony_ci					  MVPP2_PRS_L2_MULTI_CAST, true);
46048c2ecf20Sopenharmony_ci		return;
46058c2ecf20Sopenharmony_ci	}
46068c2ecf20Sopenharmony_ci
46078c2ecf20Sopenharmony_ci	if (netdev_mc_count(dev) > MVPP2_PRS_MAC_MC_FILT_MAX ||
46088c2ecf20Sopenharmony_ci	    mvpp2_prs_mac_da_accept_list(port, &dev->mc))
46098c2ecf20Sopenharmony_ci		mvpp2_prs_mac_promisc_set(port->priv, port->id,
46108c2ecf20Sopenharmony_ci					  MVPP2_PRS_L2_MULTI_CAST, true);
46118c2ecf20Sopenharmony_ci}
46128c2ecf20Sopenharmony_ci
46138c2ecf20Sopenharmony_cistatic int mvpp2_set_mac_address(struct net_device *dev, void *p)
46148c2ecf20Sopenharmony_ci{
46158c2ecf20Sopenharmony_ci	const struct sockaddr *addr = p;
46168c2ecf20Sopenharmony_ci	int err;
46178c2ecf20Sopenharmony_ci
46188c2ecf20Sopenharmony_ci	if (!is_valid_ether_addr(addr->sa_data))
46198c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci	err = mvpp2_prs_update_mac_da(dev, addr->sa_data);
46228c2ecf20Sopenharmony_ci	if (err) {
46238c2ecf20Sopenharmony_ci		/* Reconfigure parser accept the original MAC address */
46248c2ecf20Sopenharmony_ci		mvpp2_prs_update_mac_da(dev, dev->dev_addr);
46258c2ecf20Sopenharmony_ci		netdev_err(dev, "failed to change MAC address\n");
46268c2ecf20Sopenharmony_ci	}
46278c2ecf20Sopenharmony_ci	return err;
46288c2ecf20Sopenharmony_ci}
46298c2ecf20Sopenharmony_ci
46308c2ecf20Sopenharmony_ci/* Shut down all the ports, reconfigure the pools as percpu or shared,
46318c2ecf20Sopenharmony_ci * then bring up again all ports.
46328c2ecf20Sopenharmony_ci */
46338c2ecf20Sopenharmony_cistatic int mvpp2_bm_switch_buffers(struct mvpp2 *priv, bool percpu)
46348c2ecf20Sopenharmony_ci{
46358c2ecf20Sopenharmony_ci	int numbufs = MVPP2_BM_POOLS_NUM, i;
46368c2ecf20Sopenharmony_ci	struct mvpp2_port *port = NULL;
46378c2ecf20Sopenharmony_ci	bool status[MVPP2_MAX_PORTS];
46388c2ecf20Sopenharmony_ci
46398c2ecf20Sopenharmony_ci	for (i = 0; i < priv->port_count; i++) {
46408c2ecf20Sopenharmony_ci		port = priv->port_list[i];
46418c2ecf20Sopenharmony_ci		status[i] = netif_running(port->dev);
46428c2ecf20Sopenharmony_ci		if (status[i])
46438c2ecf20Sopenharmony_ci			mvpp2_stop(port->dev);
46448c2ecf20Sopenharmony_ci	}
46458c2ecf20Sopenharmony_ci
46468c2ecf20Sopenharmony_ci	/* nrxqs is the same for all ports */
46478c2ecf20Sopenharmony_ci	if (priv->percpu_pools)
46488c2ecf20Sopenharmony_ci		numbufs = port->nrxqs * 2;
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	for (i = 0; i < numbufs; i++)
46518c2ecf20Sopenharmony_ci		mvpp2_bm_pool_destroy(port->dev->dev.parent, priv, &priv->bm_pools[i]);
46528c2ecf20Sopenharmony_ci
46538c2ecf20Sopenharmony_ci	devm_kfree(port->dev->dev.parent, priv->bm_pools);
46548c2ecf20Sopenharmony_ci	priv->percpu_pools = percpu;
46558c2ecf20Sopenharmony_ci	mvpp2_bm_init(port->dev->dev.parent, priv);
46568c2ecf20Sopenharmony_ci
46578c2ecf20Sopenharmony_ci	for (i = 0; i < priv->port_count; i++) {
46588c2ecf20Sopenharmony_ci		port = priv->port_list[i];
46598c2ecf20Sopenharmony_ci		mvpp2_swf_bm_pool_init(port);
46608c2ecf20Sopenharmony_ci		if (status[i])
46618c2ecf20Sopenharmony_ci			mvpp2_open(port->dev);
46628c2ecf20Sopenharmony_ci	}
46638c2ecf20Sopenharmony_ci
46648c2ecf20Sopenharmony_ci	return 0;
46658c2ecf20Sopenharmony_ci}
46668c2ecf20Sopenharmony_ci
46678c2ecf20Sopenharmony_cistatic int mvpp2_change_mtu(struct net_device *dev, int mtu)
46688c2ecf20Sopenharmony_ci{
46698c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
46708c2ecf20Sopenharmony_ci	bool running = netif_running(dev);
46718c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
46728c2ecf20Sopenharmony_ci	int err;
46738c2ecf20Sopenharmony_ci
46748c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(MVPP2_RX_PKT_SIZE(mtu), 8)) {
46758c2ecf20Sopenharmony_ci		netdev_info(dev, "illegal MTU value %d, round to %d\n", mtu,
46768c2ecf20Sopenharmony_ci			    ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8));
46778c2ecf20Sopenharmony_ci		mtu = ALIGN(MVPP2_RX_PKT_SIZE(mtu), 8);
46788c2ecf20Sopenharmony_ci	}
46798c2ecf20Sopenharmony_ci
46808c2ecf20Sopenharmony_ci	if (port->xdp_prog && mtu > MVPP2_MAX_RX_BUF_SIZE) {
46818c2ecf20Sopenharmony_ci		netdev_err(dev, "Illegal MTU value %d (> %d) for XDP mode\n",
46828c2ecf20Sopenharmony_ci			   mtu, (int)MVPP2_MAX_RX_BUF_SIZE);
46838c2ecf20Sopenharmony_ci		return -EINVAL;
46848c2ecf20Sopenharmony_ci	}
46858c2ecf20Sopenharmony_ci
46868c2ecf20Sopenharmony_ci	if (MVPP2_RX_PKT_SIZE(mtu) > MVPP2_BM_LONG_PKT_SIZE) {
46878c2ecf20Sopenharmony_ci		if (priv->percpu_pools) {
46888c2ecf20Sopenharmony_ci			netdev_warn(dev, "mtu %d too high, switching to shared buffers", mtu);
46898c2ecf20Sopenharmony_ci			mvpp2_bm_switch_buffers(priv, false);
46908c2ecf20Sopenharmony_ci		}
46918c2ecf20Sopenharmony_ci	} else {
46928c2ecf20Sopenharmony_ci		bool jumbo = false;
46938c2ecf20Sopenharmony_ci		int i;
46948c2ecf20Sopenharmony_ci
46958c2ecf20Sopenharmony_ci		for (i = 0; i < priv->port_count; i++)
46968c2ecf20Sopenharmony_ci			if (priv->port_list[i] != port &&
46978c2ecf20Sopenharmony_ci			    MVPP2_RX_PKT_SIZE(priv->port_list[i]->dev->mtu) >
46988c2ecf20Sopenharmony_ci			    MVPP2_BM_LONG_PKT_SIZE) {
46998c2ecf20Sopenharmony_ci				jumbo = true;
47008c2ecf20Sopenharmony_ci				break;
47018c2ecf20Sopenharmony_ci			}
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_ci		/* No port is using jumbo frames */
47048c2ecf20Sopenharmony_ci		if (!jumbo) {
47058c2ecf20Sopenharmony_ci			dev_info(port->dev->dev.parent,
47068c2ecf20Sopenharmony_ci				 "all ports have a low MTU, switching to per-cpu buffers");
47078c2ecf20Sopenharmony_ci			mvpp2_bm_switch_buffers(priv, true);
47088c2ecf20Sopenharmony_ci		}
47098c2ecf20Sopenharmony_ci	}
47108c2ecf20Sopenharmony_ci
47118c2ecf20Sopenharmony_ci	if (running)
47128c2ecf20Sopenharmony_ci		mvpp2_stop_dev(port);
47138c2ecf20Sopenharmony_ci
47148c2ecf20Sopenharmony_ci	err = mvpp2_bm_update_mtu(dev, mtu);
47158c2ecf20Sopenharmony_ci	if (err) {
47168c2ecf20Sopenharmony_ci		netdev_err(dev, "failed to change MTU\n");
47178c2ecf20Sopenharmony_ci		/* Reconfigure BM to the original MTU */
47188c2ecf20Sopenharmony_ci		mvpp2_bm_update_mtu(dev, dev->mtu);
47198c2ecf20Sopenharmony_ci	} else {
47208c2ecf20Sopenharmony_ci		port->pkt_size =  MVPP2_RX_PKT_SIZE(mtu);
47218c2ecf20Sopenharmony_ci	}
47228c2ecf20Sopenharmony_ci
47238c2ecf20Sopenharmony_ci	if (running) {
47248c2ecf20Sopenharmony_ci		mvpp2_start_dev(port);
47258c2ecf20Sopenharmony_ci		mvpp2_egress_enable(port);
47268c2ecf20Sopenharmony_ci		mvpp2_ingress_enable(port);
47278c2ecf20Sopenharmony_ci	}
47288c2ecf20Sopenharmony_ci
47298c2ecf20Sopenharmony_ci	return err;
47308c2ecf20Sopenharmony_ci}
47318c2ecf20Sopenharmony_ci
47328c2ecf20Sopenharmony_cistatic int mvpp2_check_pagepool_dma(struct mvpp2_port *port)
47338c2ecf20Sopenharmony_ci{
47348c2ecf20Sopenharmony_ci	enum dma_data_direction dma_dir = DMA_FROM_DEVICE;
47358c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
47368c2ecf20Sopenharmony_ci	int err = -1, i;
47378c2ecf20Sopenharmony_ci
47388c2ecf20Sopenharmony_ci	if (!priv->percpu_pools)
47398c2ecf20Sopenharmony_ci		return err;
47408c2ecf20Sopenharmony_ci
47418c2ecf20Sopenharmony_ci	if (!priv->page_pool[0])
47428c2ecf20Sopenharmony_ci		return -ENOMEM;
47438c2ecf20Sopenharmony_ci
47448c2ecf20Sopenharmony_ci	for (i = 0; i < priv->port_count; i++) {
47458c2ecf20Sopenharmony_ci		port = priv->port_list[i];
47468c2ecf20Sopenharmony_ci		if (port->xdp_prog) {
47478c2ecf20Sopenharmony_ci			dma_dir = DMA_BIDIRECTIONAL;
47488c2ecf20Sopenharmony_ci			break;
47498c2ecf20Sopenharmony_ci		}
47508c2ecf20Sopenharmony_ci	}
47518c2ecf20Sopenharmony_ci
47528c2ecf20Sopenharmony_ci	/* All pools are equal in terms of DMA direction */
47538c2ecf20Sopenharmony_ci	if (priv->page_pool[0]->p.dma_dir != dma_dir)
47548c2ecf20Sopenharmony_ci		err = mvpp2_bm_switch_buffers(priv, true);
47558c2ecf20Sopenharmony_ci
47568c2ecf20Sopenharmony_ci	return err;
47578c2ecf20Sopenharmony_ci}
47588c2ecf20Sopenharmony_ci
47598c2ecf20Sopenharmony_cistatic void
47608c2ecf20Sopenharmony_cimvpp2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
47618c2ecf20Sopenharmony_ci{
47628c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
47638c2ecf20Sopenharmony_ci	unsigned int start;
47648c2ecf20Sopenharmony_ci	unsigned int cpu;
47658c2ecf20Sopenharmony_ci
47668c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
47678c2ecf20Sopenharmony_ci		struct mvpp2_pcpu_stats *cpu_stats;
47688c2ecf20Sopenharmony_ci		u64 rx_packets;
47698c2ecf20Sopenharmony_ci		u64 rx_bytes;
47708c2ecf20Sopenharmony_ci		u64 tx_packets;
47718c2ecf20Sopenharmony_ci		u64 tx_bytes;
47728c2ecf20Sopenharmony_ci
47738c2ecf20Sopenharmony_ci		cpu_stats = per_cpu_ptr(port->stats, cpu);
47748c2ecf20Sopenharmony_ci		do {
47758c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
47768c2ecf20Sopenharmony_ci			rx_packets = cpu_stats->rx_packets;
47778c2ecf20Sopenharmony_ci			rx_bytes   = cpu_stats->rx_bytes;
47788c2ecf20Sopenharmony_ci			tx_packets = cpu_stats->tx_packets;
47798c2ecf20Sopenharmony_ci			tx_bytes   = cpu_stats->tx_bytes;
47808c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
47818c2ecf20Sopenharmony_ci
47828c2ecf20Sopenharmony_ci		stats->rx_packets += rx_packets;
47838c2ecf20Sopenharmony_ci		stats->rx_bytes   += rx_bytes;
47848c2ecf20Sopenharmony_ci		stats->tx_packets += tx_packets;
47858c2ecf20Sopenharmony_ci		stats->tx_bytes   += tx_bytes;
47868c2ecf20Sopenharmony_ci	}
47878c2ecf20Sopenharmony_ci
47888c2ecf20Sopenharmony_ci	stats->rx_errors	= dev->stats.rx_errors;
47898c2ecf20Sopenharmony_ci	stats->rx_dropped	= dev->stats.rx_dropped;
47908c2ecf20Sopenharmony_ci	stats->tx_dropped	= dev->stats.tx_dropped;
47918c2ecf20Sopenharmony_ci}
47928c2ecf20Sopenharmony_ci
47938c2ecf20Sopenharmony_cistatic int mvpp2_set_ts_config(struct mvpp2_port *port, struct ifreq *ifr)
47948c2ecf20Sopenharmony_ci{
47958c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
47968c2ecf20Sopenharmony_ci	void __iomem *ptp;
47978c2ecf20Sopenharmony_ci	u32 gcr, int_mask;
47988c2ecf20Sopenharmony_ci
47998c2ecf20Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
48008c2ecf20Sopenharmony_ci		return -EFAULT;
48018c2ecf20Sopenharmony_ci
48028c2ecf20Sopenharmony_ci	if (config.flags)
48038c2ecf20Sopenharmony_ci		return -EINVAL;
48048c2ecf20Sopenharmony_ci
48058c2ecf20Sopenharmony_ci	if (config.tx_type != HWTSTAMP_TX_OFF &&
48068c2ecf20Sopenharmony_ci	    config.tx_type != HWTSTAMP_TX_ON)
48078c2ecf20Sopenharmony_ci		return -ERANGE;
48088c2ecf20Sopenharmony_ci
48098c2ecf20Sopenharmony_ci	ptp = port->priv->iface_base + MVPP22_PTP_BASE(port->gop_id);
48108c2ecf20Sopenharmony_ci
48118c2ecf20Sopenharmony_ci	int_mask = gcr = 0;
48128c2ecf20Sopenharmony_ci	if (config.tx_type != HWTSTAMP_TX_OFF) {
48138c2ecf20Sopenharmony_ci		gcr |= MVPP22_PTP_GCR_TSU_ENABLE | MVPP22_PTP_GCR_TX_RESET;
48148c2ecf20Sopenharmony_ci		int_mask |= MVPP22_PTP_INT_MASK_QUEUE1 |
48158c2ecf20Sopenharmony_ci			    MVPP22_PTP_INT_MASK_QUEUE0;
48168c2ecf20Sopenharmony_ci	}
48178c2ecf20Sopenharmony_ci
48188c2ecf20Sopenharmony_ci	/* It seems we must also release the TX reset when enabling the TSU */
48198c2ecf20Sopenharmony_ci	if (config.rx_filter != HWTSTAMP_FILTER_NONE)
48208c2ecf20Sopenharmony_ci		gcr |= MVPP22_PTP_GCR_TSU_ENABLE | MVPP22_PTP_GCR_RX_RESET |
48218c2ecf20Sopenharmony_ci		       MVPP22_PTP_GCR_TX_RESET;
48228c2ecf20Sopenharmony_ci
48238c2ecf20Sopenharmony_ci	if (gcr & MVPP22_PTP_GCR_TSU_ENABLE)
48248c2ecf20Sopenharmony_ci		mvpp22_tai_start(port->priv->tai);
48258c2ecf20Sopenharmony_ci
48268c2ecf20Sopenharmony_ci	if (config.rx_filter != HWTSTAMP_FILTER_NONE) {
48278c2ecf20Sopenharmony_ci		config.rx_filter = HWTSTAMP_FILTER_ALL;
48288c2ecf20Sopenharmony_ci		mvpp2_modify(ptp + MVPP22_PTP_GCR,
48298c2ecf20Sopenharmony_ci			     MVPP22_PTP_GCR_RX_RESET |
48308c2ecf20Sopenharmony_ci			     MVPP22_PTP_GCR_TX_RESET |
48318c2ecf20Sopenharmony_ci			     MVPP22_PTP_GCR_TSU_ENABLE, gcr);
48328c2ecf20Sopenharmony_ci		port->rx_hwtstamp = true;
48338c2ecf20Sopenharmony_ci	} else {
48348c2ecf20Sopenharmony_ci		port->rx_hwtstamp = false;
48358c2ecf20Sopenharmony_ci		mvpp2_modify(ptp + MVPP22_PTP_GCR,
48368c2ecf20Sopenharmony_ci			     MVPP22_PTP_GCR_RX_RESET |
48378c2ecf20Sopenharmony_ci			     MVPP22_PTP_GCR_TX_RESET |
48388c2ecf20Sopenharmony_ci			     MVPP22_PTP_GCR_TSU_ENABLE, gcr);
48398c2ecf20Sopenharmony_ci	}
48408c2ecf20Sopenharmony_ci
48418c2ecf20Sopenharmony_ci	mvpp2_modify(ptp + MVPP22_PTP_INT_MASK,
48428c2ecf20Sopenharmony_ci		     MVPP22_PTP_INT_MASK_QUEUE1 |
48438c2ecf20Sopenharmony_ci		     MVPP22_PTP_INT_MASK_QUEUE0, int_mask);
48448c2ecf20Sopenharmony_ci
48458c2ecf20Sopenharmony_ci	if (!(gcr & MVPP22_PTP_GCR_TSU_ENABLE))
48468c2ecf20Sopenharmony_ci		mvpp22_tai_stop(port->priv->tai);
48478c2ecf20Sopenharmony_ci
48488c2ecf20Sopenharmony_ci	port->tx_hwtstamp_type = config.tx_type;
48498c2ecf20Sopenharmony_ci
48508c2ecf20Sopenharmony_ci	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
48518c2ecf20Sopenharmony_ci		return -EFAULT;
48528c2ecf20Sopenharmony_ci
48538c2ecf20Sopenharmony_ci	return 0;
48548c2ecf20Sopenharmony_ci}
48558c2ecf20Sopenharmony_ci
48568c2ecf20Sopenharmony_cistatic int mvpp2_get_ts_config(struct mvpp2_port *port, struct ifreq *ifr)
48578c2ecf20Sopenharmony_ci{
48588c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
48598c2ecf20Sopenharmony_ci
48608c2ecf20Sopenharmony_ci	memset(&config, 0, sizeof(config));
48618c2ecf20Sopenharmony_ci
48628c2ecf20Sopenharmony_ci	config.tx_type = port->tx_hwtstamp_type;
48638c2ecf20Sopenharmony_ci	config.rx_filter = port->rx_hwtstamp ?
48648c2ecf20Sopenharmony_ci		HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
48658c2ecf20Sopenharmony_ci
48668c2ecf20Sopenharmony_ci	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
48678c2ecf20Sopenharmony_ci		return -EFAULT;
48688c2ecf20Sopenharmony_ci
48698c2ecf20Sopenharmony_ci	return 0;
48708c2ecf20Sopenharmony_ci}
48718c2ecf20Sopenharmony_ci
48728c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_ts_info(struct net_device *dev,
48738c2ecf20Sopenharmony_ci				     struct ethtool_ts_info *info)
48748c2ecf20Sopenharmony_ci{
48758c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
48768c2ecf20Sopenharmony_ci
48778c2ecf20Sopenharmony_ci	if (!port->hwtstamp)
48788c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
48798c2ecf20Sopenharmony_ci
48808c2ecf20Sopenharmony_ci	info->phc_index = mvpp22_tai_ptp_clock_index(port->priv->tai);
48818c2ecf20Sopenharmony_ci	info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
48828c2ecf20Sopenharmony_ci				SOF_TIMESTAMPING_RX_SOFTWARE |
48838c2ecf20Sopenharmony_ci				SOF_TIMESTAMPING_SOFTWARE |
48848c2ecf20Sopenharmony_ci				SOF_TIMESTAMPING_TX_HARDWARE |
48858c2ecf20Sopenharmony_ci				SOF_TIMESTAMPING_RX_HARDWARE |
48868c2ecf20Sopenharmony_ci				SOF_TIMESTAMPING_RAW_HARDWARE;
48878c2ecf20Sopenharmony_ci	info->tx_types = BIT(HWTSTAMP_TX_OFF) |
48888c2ecf20Sopenharmony_ci			 BIT(HWTSTAMP_TX_ON);
48898c2ecf20Sopenharmony_ci	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
48908c2ecf20Sopenharmony_ci			   BIT(HWTSTAMP_FILTER_ALL);
48918c2ecf20Sopenharmony_ci
48928c2ecf20Sopenharmony_ci	return 0;
48938c2ecf20Sopenharmony_ci}
48948c2ecf20Sopenharmony_ci
48958c2ecf20Sopenharmony_cistatic int mvpp2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
48968c2ecf20Sopenharmony_ci{
48978c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
48988c2ecf20Sopenharmony_ci
48998c2ecf20Sopenharmony_ci	switch (cmd) {
49008c2ecf20Sopenharmony_ci	case SIOCSHWTSTAMP:
49018c2ecf20Sopenharmony_ci		if (port->hwtstamp)
49028c2ecf20Sopenharmony_ci			return mvpp2_set_ts_config(port, ifr);
49038c2ecf20Sopenharmony_ci		break;
49048c2ecf20Sopenharmony_ci
49058c2ecf20Sopenharmony_ci	case SIOCGHWTSTAMP:
49068c2ecf20Sopenharmony_ci		if (port->hwtstamp)
49078c2ecf20Sopenharmony_ci			return mvpp2_get_ts_config(port, ifr);
49088c2ecf20Sopenharmony_ci		break;
49098c2ecf20Sopenharmony_ci	}
49108c2ecf20Sopenharmony_ci
49118c2ecf20Sopenharmony_ci	if (!port->phylink)
49128c2ecf20Sopenharmony_ci		return -ENOTSUPP;
49138c2ecf20Sopenharmony_ci
49148c2ecf20Sopenharmony_ci	return phylink_mii_ioctl(port->phylink, ifr, cmd);
49158c2ecf20Sopenharmony_ci}
49168c2ecf20Sopenharmony_ci
49178c2ecf20Sopenharmony_cistatic int mvpp2_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid)
49188c2ecf20Sopenharmony_ci{
49198c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
49208c2ecf20Sopenharmony_ci	int ret;
49218c2ecf20Sopenharmony_ci
49228c2ecf20Sopenharmony_ci	ret = mvpp2_prs_vid_entry_add(port, vid);
49238c2ecf20Sopenharmony_ci	if (ret)
49248c2ecf20Sopenharmony_ci		netdev_err(dev, "rx-vlan-filter offloading cannot accept more than %d VIDs per port\n",
49258c2ecf20Sopenharmony_ci			   MVPP2_PRS_VLAN_FILT_MAX - 1);
49268c2ecf20Sopenharmony_ci	return ret;
49278c2ecf20Sopenharmony_ci}
49288c2ecf20Sopenharmony_ci
49298c2ecf20Sopenharmony_cistatic int mvpp2_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, u16 vid)
49308c2ecf20Sopenharmony_ci{
49318c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_ci	mvpp2_prs_vid_entry_remove(port, vid);
49348c2ecf20Sopenharmony_ci	return 0;
49358c2ecf20Sopenharmony_ci}
49368c2ecf20Sopenharmony_ci
49378c2ecf20Sopenharmony_cistatic int mvpp2_set_features(struct net_device *dev,
49388c2ecf20Sopenharmony_ci			      netdev_features_t features)
49398c2ecf20Sopenharmony_ci{
49408c2ecf20Sopenharmony_ci	netdev_features_t changed = dev->features ^ features;
49418c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
49428c2ecf20Sopenharmony_ci
49438c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) {
49448c2ecf20Sopenharmony_ci		if (features & NETIF_F_HW_VLAN_CTAG_FILTER) {
49458c2ecf20Sopenharmony_ci			mvpp2_prs_vid_enable_filtering(port);
49468c2ecf20Sopenharmony_ci		} else {
49478c2ecf20Sopenharmony_ci			/* Invalidate all registered VID filters for this
49488c2ecf20Sopenharmony_ci			 * port
49498c2ecf20Sopenharmony_ci			 */
49508c2ecf20Sopenharmony_ci			mvpp2_prs_vid_remove_all(port);
49518c2ecf20Sopenharmony_ci
49528c2ecf20Sopenharmony_ci			mvpp2_prs_vid_disable_filtering(port);
49538c2ecf20Sopenharmony_ci		}
49548c2ecf20Sopenharmony_ci	}
49558c2ecf20Sopenharmony_ci
49568c2ecf20Sopenharmony_ci	if (changed & NETIF_F_RXHASH) {
49578c2ecf20Sopenharmony_ci		if (features & NETIF_F_RXHASH)
49588c2ecf20Sopenharmony_ci			mvpp22_port_rss_enable(port);
49598c2ecf20Sopenharmony_ci		else
49608c2ecf20Sopenharmony_ci			mvpp22_port_rss_disable(port);
49618c2ecf20Sopenharmony_ci	}
49628c2ecf20Sopenharmony_ci
49638c2ecf20Sopenharmony_ci	return 0;
49648c2ecf20Sopenharmony_ci}
49658c2ecf20Sopenharmony_ci
49668c2ecf20Sopenharmony_cistatic int mvpp2_xdp_setup(struct mvpp2_port *port, struct netdev_bpf *bpf)
49678c2ecf20Sopenharmony_ci{
49688c2ecf20Sopenharmony_ci	struct bpf_prog *prog = bpf->prog, *old_prog;
49698c2ecf20Sopenharmony_ci	bool running = netif_running(port->dev);
49708c2ecf20Sopenharmony_ci	bool reset = !prog != !port->xdp_prog;
49718c2ecf20Sopenharmony_ci
49728c2ecf20Sopenharmony_ci	if (port->dev->mtu > MVPP2_MAX_RX_BUF_SIZE) {
49738c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(bpf->extack, "MTU too large for XDP");
49748c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
49758c2ecf20Sopenharmony_ci	}
49768c2ecf20Sopenharmony_ci
49778c2ecf20Sopenharmony_ci	if (!port->priv->percpu_pools) {
49788c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(bpf->extack, "Per CPU Pools required for XDP");
49798c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
49808c2ecf20Sopenharmony_ci	}
49818c2ecf20Sopenharmony_ci
49828c2ecf20Sopenharmony_ci	if (port->ntxqs < num_possible_cpus() * 2) {
49838c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(bpf->extack, "XDP_TX needs two TX queues per CPU");
49848c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
49858c2ecf20Sopenharmony_ci	}
49868c2ecf20Sopenharmony_ci
49878c2ecf20Sopenharmony_ci	/* device is up and bpf is added/removed, must setup the RX queues */
49888c2ecf20Sopenharmony_ci	if (running && reset)
49898c2ecf20Sopenharmony_ci		mvpp2_stop(port->dev);
49908c2ecf20Sopenharmony_ci
49918c2ecf20Sopenharmony_ci	old_prog = xchg(&port->xdp_prog, prog);
49928c2ecf20Sopenharmony_ci	if (old_prog)
49938c2ecf20Sopenharmony_ci		bpf_prog_put(old_prog);
49948c2ecf20Sopenharmony_ci
49958c2ecf20Sopenharmony_ci	/* bpf is just replaced, RXQ and MTU are already setup */
49968c2ecf20Sopenharmony_ci	if (!reset)
49978c2ecf20Sopenharmony_ci		return 0;
49988c2ecf20Sopenharmony_ci
49998c2ecf20Sopenharmony_ci	/* device was up, restore the link */
50008c2ecf20Sopenharmony_ci	if (running)
50018c2ecf20Sopenharmony_ci		mvpp2_open(port->dev);
50028c2ecf20Sopenharmony_ci
50038c2ecf20Sopenharmony_ci	/* Check Page Pool DMA Direction */
50048c2ecf20Sopenharmony_ci	mvpp2_check_pagepool_dma(port);
50058c2ecf20Sopenharmony_ci
50068c2ecf20Sopenharmony_ci	return 0;
50078c2ecf20Sopenharmony_ci}
50088c2ecf20Sopenharmony_ci
50098c2ecf20Sopenharmony_cistatic int mvpp2_xdp(struct net_device *dev, struct netdev_bpf *xdp)
50108c2ecf20Sopenharmony_ci{
50118c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
50128c2ecf20Sopenharmony_ci
50138c2ecf20Sopenharmony_ci	switch (xdp->command) {
50148c2ecf20Sopenharmony_ci	case XDP_SETUP_PROG:
50158c2ecf20Sopenharmony_ci		return mvpp2_xdp_setup(port, xdp);
50168c2ecf20Sopenharmony_ci	default:
50178c2ecf20Sopenharmony_ci		return -EINVAL;
50188c2ecf20Sopenharmony_ci	}
50198c2ecf20Sopenharmony_ci}
50208c2ecf20Sopenharmony_ci
50218c2ecf20Sopenharmony_ci/* Ethtool methods */
50228c2ecf20Sopenharmony_ci
50238c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_nway_reset(struct net_device *dev)
50248c2ecf20Sopenharmony_ci{
50258c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
50268c2ecf20Sopenharmony_ci
50278c2ecf20Sopenharmony_ci	if (!port->phylink)
50288c2ecf20Sopenharmony_ci		return -ENOTSUPP;
50298c2ecf20Sopenharmony_ci
50308c2ecf20Sopenharmony_ci	return phylink_ethtool_nway_reset(port->phylink);
50318c2ecf20Sopenharmony_ci}
50328c2ecf20Sopenharmony_ci
50338c2ecf20Sopenharmony_ci/* Set interrupt coalescing for ethtools */
50348c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_coalesce(struct net_device *dev,
50358c2ecf20Sopenharmony_ci				      struct ethtool_coalesce *c)
50368c2ecf20Sopenharmony_ci{
50378c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
50388c2ecf20Sopenharmony_ci	int queue;
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->nrxqs; queue++) {
50418c2ecf20Sopenharmony_ci		struct mvpp2_rx_queue *rxq = port->rxqs[queue];
50428c2ecf20Sopenharmony_ci
50438c2ecf20Sopenharmony_ci		rxq->time_coal = c->rx_coalesce_usecs;
50448c2ecf20Sopenharmony_ci		rxq->pkts_coal = c->rx_max_coalesced_frames;
50458c2ecf20Sopenharmony_ci		mvpp2_rx_pkts_coal_set(port, rxq);
50468c2ecf20Sopenharmony_ci		mvpp2_rx_time_coal_set(port, rxq);
50478c2ecf20Sopenharmony_ci	}
50488c2ecf20Sopenharmony_ci
50498c2ecf20Sopenharmony_ci	if (port->has_tx_irqs) {
50508c2ecf20Sopenharmony_ci		port->tx_time_coal = c->tx_coalesce_usecs;
50518c2ecf20Sopenharmony_ci		mvpp2_tx_time_coal_set(port);
50528c2ecf20Sopenharmony_ci	}
50538c2ecf20Sopenharmony_ci
50548c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
50558c2ecf20Sopenharmony_ci		struct mvpp2_tx_queue *txq = port->txqs[queue];
50568c2ecf20Sopenharmony_ci
50578c2ecf20Sopenharmony_ci		txq->done_pkts_coal = c->tx_max_coalesced_frames;
50588c2ecf20Sopenharmony_ci
50598c2ecf20Sopenharmony_ci		if (port->has_tx_irqs)
50608c2ecf20Sopenharmony_ci			mvpp2_tx_pkts_coal_set(port, txq);
50618c2ecf20Sopenharmony_ci	}
50628c2ecf20Sopenharmony_ci
50638c2ecf20Sopenharmony_ci	return 0;
50648c2ecf20Sopenharmony_ci}
50658c2ecf20Sopenharmony_ci
50668c2ecf20Sopenharmony_ci/* get coalescing for ethtools */
50678c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_coalesce(struct net_device *dev,
50688c2ecf20Sopenharmony_ci				      struct ethtool_coalesce *c)
50698c2ecf20Sopenharmony_ci{
50708c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
50718c2ecf20Sopenharmony_ci
50728c2ecf20Sopenharmony_ci	c->rx_coalesce_usecs       = port->rxqs[0]->time_coal;
50738c2ecf20Sopenharmony_ci	c->rx_max_coalesced_frames = port->rxqs[0]->pkts_coal;
50748c2ecf20Sopenharmony_ci	c->tx_max_coalesced_frames = port->txqs[0]->done_pkts_coal;
50758c2ecf20Sopenharmony_ci	c->tx_coalesce_usecs       = port->tx_time_coal;
50768c2ecf20Sopenharmony_ci	return 0;
50778c2ecf20Sopenharmony_ci}
50788c2ecf20Sopenharmony_ci
50798c2ecf20Sopenharmony_cistatic void mvpp2_ethtool_get_drvinfo(struct net_device *dev,
50808c2ecf20Sopenharmony_ci				      struct ethtool_drvinfo *drvinfo)
50818c2ecf20Sopenharmony_ci{
50828c2ecf20Sopenharmony_ci	strlcpy(drvinfo->driver, MVPP2_DRIVER_NAME,
50838c2ecf20Sopenharmony_ci		sizeof(drvinfo->driver));
50848c2ecf20Sopenharmony_ci	strlcpy(drvinfo->version, MVPP2_DRIVER_VERSION,
50858c2ecf20Sopenharmony_ci		sizeof(drvinfo->version));
50868c2ecf20Sopenharmony_ci	strlcpy(drvinfo->bus_info, dev_name(&dev->dev),
50878c2ecf20Sopenharmony_ci		sizeof(drvinfo->bus_info));
50888c2ecf20Sopenharmony_ci}
50898c2ecf20Sopenharmony_ci
50908c2ecf20Sopenharmony_cistatic void mvpp2_ethtool_get_ringparam(struct net_device *dev,
50918c2ecf20Sopenharmony_ci					struct ethtool_ringparam *ring)
50928c2ecf20Sopenharmony_ci{
50938c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
50948c2ecf20Sopenharmony_ci
50958c2ecf20Sopenharmony_ci	ring->rx_max_pending = MVPP2_MAX_RXD_MAX;
50968c2ecf20Sopenharmony_ci	ring->tx_max_pending = MVPP2_MAX_TXD_MAX;
50978c2ecf20Sopenharmony_ci	ring->rx_pending = port->rx_ring_size;
50988c2ecf20Sopenharmony_ci	ring->tx_pending = port->tx_ring_size;
50998c2ecf20Sopenharmony_ci}
51008c2ecf20Sopenharmony_ci
51018c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_ringparam(struct net_device *dev,
51028c2ecf20Sopenharmony_ci				       struct ethtool_ringparam *ring)
51038c2ecf20Sopenharmony_ci{
51048c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
51058c2ecf20Sopenharmony_ci	u16 prev_rx_ring_size = port->rx_ring_size;
51068c2ecf20Sopenharmony_ci	u16 prev_tx_ring_size = port->tx_ring_size;
51078c2ecf20Sopenharmony_ci	int err;
51088c2ecf20Sopenharmony_ci
51098c2ecf20Sopenharmony_ci	err = mvpp2_check_ringparam_valid(dev, ring);
51108c2ecf20Sopenharmony_ci	if (err)
51118c2ecf20Sopenharmony_ci		return err;
51128c2ecf20Sopenharmony_ci
51138c2ecf20Sopenharmony_ci	if (!netif_running(dev)) {
51148c2ecf20Sopenharmony_ci		port->rx_ring_size = ring->rx_pending;
51158c2ecf20Sopenharmony_ci		port->tx_ring_size = ring->tx_pending;
51168c2ecf20Sopenharmony_ci		return 0;
51178c2ecf20Sopenharmony_ci	}
51188c2ecf20Sopenharmony_ci
51198c2ecf20Sopenharmony_ci	/* The interface is running, so we have to force a
51208c2ecf20Sopenharmony_ci	 * reallocation of the queues
51218c2ecf20Sopenharmony_ci	 */
51228c2ecf20Sopenharmony_ci	mvpp2_stop_dev(port);
51238c2ecf20Sopenharmony_ci	mvpp2_cleanup_rxqs(port);
51248c2ecf20Sopenharmony_ci	mvpp2_cleanup_txqs(port);
51258c2ecf20Sopenharmony_ci
51268c2ecf20Sopenharmony_ci	port->rx_ring_size = ring->rx_pending;
51278c2ecf20Sopenharmony_ci	port->tx_ring_size = ring->tx_pending;
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_ci	err = mvpp2_setup_rxqs(port);
51308c2ecf20Sopenharmony_ci	if (err) {
51318c2ecf20Sopenharmony_ci		/* Reallocate Rx queues with the original ring size */
51328c2ecf20Sopenharmony_ci		port->rx_ring_size = prev_rx_ring_size;
51338c2ecf20Sopenharmony_ci		ring->rx_pending = prev_rx_ring_size;
51348c2ecf20Sopenharmony_ci		err = mvpp2_setup_rxqs(port);
51358c2ecf20Sopenharmony_ci		if (err)
51368c2ecf20Sopenharmony_ci			goto err_out;
51378c2ecf20Sopenharmony_ci	}
51388c2ecf20Sopenharmony_ci	err = mvpp2_setup_txqs(port);
51398c2ecf20Sopenharmony_ci	if (err) {
51408c2ecf20Sopenharmony_ci		/* Reallocate Tx queues with the original ring size */
51418c2ecf20Sopenharmony_ci		port->tx_ring_size = prev_tx_ring_size;
51428c2ecf20Sopenharmony_ci		ring->tx_pending = prev_tx_ring_size;
51438c2ecf20Sopenharmony_ci		err = mvpp2_setup_txqs(port);
51448c2ecf20Sopenharmony_ci		if (err)
51458c2ecf20Sopenharmony_ci			goto err_clean_rxqs;
51468c2ecf20Sopenharmony_ci	}
51478c2ecf20Sopenharmony_ci
51488c2ecf20Sopenharmony_ci	mvpp2_start_dev(port);
51498c2ecf20Sopenharmony_ci	mvpp2_egress_enable(port);
51508c2ecf20Sopenharmony_ci	mvpp2_ingress_enable(port);
51518c2ecf20Sopenharmony_ci
51528c2ecf20Sopenharmony_ci	return 0;
51538c2ecf20Sopenharmony_ci
51548c2ecf20Sopenharmony_cierr_clean_rxqs:
51558c2ecf20Sopenharmony_ci	mvpp2_cleanup_rxqs(port);
51568c2ecf20Sopenharmony_cierr_out:
51578c2ecf20Sopenharmony_ci	netdev_err(dev, "failed to change ring parameters");
51588c2ecf20Sopenharmony_ci	return err;
51598c2ecf20Sopenharmony_ci}
51608c2ecf20Sopenharmony_ci
51618c2ecf20Sopenharmony_cistatic void mvpp2_ethtool_get_pause_param(struct net_device *dev,
51628c2ecf20Sopenharmony_ci					  struct ethtool_pauseparam *pause)
51638c2ecf20Sopenharmony_ci{
51648c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
51658c2ecf20Sopenharmony_ci
51668c2ecf20Sopenharmony_ci	if (!port->phylink)
51678c2ecf20Sopenharmony_ci		return;
51688c2ecf20Sopenharmony_ci
51698c2ecf20Sopenharmony_ci	phylink_ethtool_get_pauseparam(port->phylink, pause);
51708c2ecf20Sopenharmony_ci}
51718c2ecf20Sopenharmony_ci
51728c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_pause_param(struct net_device *dev,
51738c2ecf20Sopenharmony_ci					 struct ethtool_pauseparam *pause)
51748c2ecf20Sopenharmony_ci{
51758c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
51768c2ecf20Sopenharmony_ci
51778c2ecf20Sopenharmony_ci	if (!port->phylink)
51788c2ecf20Sopenharmony_ci		return -ENOTSUPP;
51798c2ecf20Sopenharmony_ci
51808c2ecf20Sopenharmony_ci	return phylink_ethtool_set_pauseparam(port->phylink, pause);
51818c2ecf20Sopenharmony_ci}
51828c2ecf20Sopenharmony_ci
51838c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_link_ksettings(struct net_device *dev,
51848c2ecf20Sopenharmony_ci					    struct ethtool_link_ksettings *cmd)
51858c2ecf20Sopenharmony_ci{
51868c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
51878c2ecf20Sopenharmony_ci
51888c2ecf20Sopenharmony_ci	if (!port->phylink)
51898c2ecf20Sopenharmony_ci		return -ENOTSUPP;
51908c2ecf20Sopenharmony_ci
51918c2ecf20Sopenharmony_ci	return phylink_ethtool_ksettings_get(port->phylink, cmd);
51928c2ecf20Sopenharmony_ci}
51938c2ecf20Sopenharmony_ci
51948c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_link_ksettings(struct net_device *dev,
51958c2ecf20Sopenharmony_ci					    const struct ethtool_link_ksettings *cmd)
51968c2ecf20Sopenharmony_ci{
51978c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
51988c2ecf20Sopenharmony_ci
51998c2ecf20Sopenharmony_ci	if (!port->phylink)
52008c2ecf20Sopenharmony_ci		return -ENOTSUPP;
52018c2ecf20Sopenharmony_ci
52028c2ecf20Sopenharmony_ci	return phylink_ethtool_ksettings_set(port->phylink, cmd);
52038c2ecf20Sopenharmony_ci}
52048c2ecf20Sopenharmony_ci
52058c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_rxnfc(struct net_device *dev,
52068c2ecf20Sopenharmony_ci				   struct ethtool_rxnfc *info, u32 *rules)
52078c2ecf20Sopenharmony_ci{
52088c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
52098c2ecf20Sopenharmony_ci	int ret = 0, i, loc = 0;
52108c2ecf20Sopenharmony_ci
52118c2ecf20Sopenharmony_ci	if (!mvpp22_rss_is_supported())
52128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
52138c2ecf20Sopenharmony_ci
52148c2ecf20Sopenharmony_ci	switch (info->cmd) {
52158c2ecf20Sopenharmony_ci	case ETHTOOL_GRXFH:
52168c2ecf20Sopenharmony_ci		ret = mvpp2_ethtool_rxfh_get(port, info);
52178c2ecf20Sopenharmony_ci		break;
52188c2ecf20Sopenharmony_ci	case ETHTOOL_GRXRINGS:
52198c2ecf20Sopenharmony_ci		info->data = port->nrxqs;
52208c2ecf20Sopenharmony_ci		break;
52218c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLCNT:
52228c2ecf20Sopenharmony_ci		info->rule_cnt = port->n_rfs_rules;
52238c2ecf20Sopenharmony_ci		break;
52248c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRULE:
52258c2ecf20Sopenharmony_ci		ret = mvpp2_ethtool_cls_rule_get(port, info);
52268c2ecf20Sopenharmony_ci		break;
52278c2ecf20Sopenharmony_ci	case ETHTOOL_GRXCLSRLALL:
52288c2ecf20Sopenharmony_ci		for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) {
52298c2ecf20Sopenharmony_ci			if (loc == info->rule_cnt) {
52308c2ecf20Sopenharmony_ci				ret = -EMSGSIZE;
52318c2ecf20Sopenharmony_ci				break;
52328c2ecf20Sopenharmony_ci			}
52338c2ecf20Sopenharmony_ci
52348c2ecf20Sopenharmony_ci			if (port->rfs_rules[i])
52358c2ecf20Sopenharmony_ci				rules[loc++] = i;
52368c2ecf20Sopenharmony_ci		}
52378c2ecf20Sopenharmony_ci		break;
52388c2ecf20Sopenharmony_ci	default:
52398c2ecf20Sopenharmony_ci		return -ENOTSUPP;
52408c2ecf20Sopenharmony_ci	}
52418c2ecf20Sopenharmony_ci
52428c2ecf20Sopenharmony_ci	return ret;
52438c2ecf20Sopenharmony_ci}
52448c2ecf20Sopenharmony_ci
52458c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_rxnfc(struct net_device *dev,
52468c2ecf20Sopenharmony_ci				   struct ethtool_rxnfc *info)
52478c2ecf20Sopenharmony_ci{
52488c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
52498c2ecf20Sopenharmony_ci	int ret = 0;
52508c2ecf20Sopenharmony_ci
52518c2ecf20Sopenharmony_ci	if (!mvpp22_rss_is_supported())
52528c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
52538c2ecf20Sopenharmony_ci
52548c2ecf20Sopenharmony_ci	switch (info->cmd) {
52558c2ecf20Sopenharmony_ci	case ETHTOOL_SRXFH:
52568c2ecf20Sopenharmony_ci		ret = mvpp2_ethtool_rxfh_set(port, info);
52578c2ecf20Sopenharmony_ci		break;
52588c2ecf20Sopenharmony_ci	case ETHTOOL_SRXCLSRLINS:
52598c2ecf20Sopenharmony_ci		ret = mvpp2_ethtool_cls_rule_ins(port, info);
52608c2ecf20Sopenharmony_ci		break;
52618c2ecf20Sopenharmony_ci	case ETHTOOL_SRXCLSRLDEL:
52628c2ecf20Sopenharmony_ci		ret = mvpp2_ethtool_cls_rule_del(port, info);
52638c2ecf20Sopenharmony_ci		break;
52648c2ecf20Sopenharmony_ci	default:
52658c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
52668c2ecf20Sopenharmony_ci	}
52678c2ecf20Sopenharmony_ci	return ret;
52688c2ecf20Sopenharmony_ci}
52698c2ecf20Sopenharmony_ci
52708c2ecf20Sopenharmony_cistatic u32 mvpp2_ethtool_get_rxfh_indir_size(struct net_device *dev)
52718c2ecf20Sopenharmony_ci{
52728c2ecf20Sopenharmony_ci	return mvpp22_rss_is_supported() ? MVPP22_RSS_TABLE_ENTRIES : 0;
52738c2ecf20Sopenharmony_ci}
52748c2ecf20Sopenharmony_ci
52758c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
52768c2ecf20Sopenharmony_ci				  u8 *hfunc)
52778c2ecf20Sopenharmony_ci{
52788c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
52798c2ecf20Sopenharmony_ci	int ret = 0;
52808c2ecf20Sopenharmony_ci
52818c2ecf20Sopenharmony_ci	if (!mvpp22_rss_is_supported())
52828c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
52838c2ecf20Sopenharmony_ci
52848c2ecf20Sopenharmony_ci	if (indir)
52858c2ecf20Sopenharmony_ci		ret = mvpp22_port_rss_ctx_indir_get(port, 0, indir);
52868c2ecf20Sopenharmony_ci
52878c2ecf20Sopenharmony_ci	if (hfunc)
52888c2ecf20Sopenharmony_ci		*hfunc = ETH_RSS_HASH_CRC32;
52898c2ecf20Sopenharmony_ci
52908c2ecf20Sopenharmony_ci	return ret;
52918c2ecf20Sopenharmony_ci}
52928c2ecf20Sopenharmony_ci
52938c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_rxfh(struct net_device *dev, const u32 *indir,
52948c2ecf20Sopenharmony_ci				  const u8 *key, const u8 hfunc)
52958c2ecf20Sopenharmony_ci{
52968c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
52978c2ecf20Sopenharmony_ci	int ret = 0;
52988c2ecf20Sopenharmony_ci
52998c2ecf20Sopenharmony_ci	if (!mvpp22_rss_is_supported())
53008c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53018c2ecf20Sopenharmony_ci
53028c2ecf20Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_CRC32)
53038c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53048c2ecf20Sopenharmony_ci
53058c2ecf20Sopenharmony_ci	if (key)
53068c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53078c2ecf20Sopenharmony_ci
53088c2ecf20Sopenharmony_ci	if (indir)
53098c2ecf20Sopenharmony_ci		ret = mvpp22_port_rss_ctx_indir_set(port, 0, indir);
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci	return ret;
53128c2ecf20Sopenharmony_ci}
53138c2ecf20Sopenharmony_ci
53148c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_get_rxfh_context(struct net_device *dev, u32 *indir,
53158c2ecf20Sopenharmony_ci					  u8 *key, u8 *hfunc, u32 rss_context)
53168c2ecf20Sopenharmony_ci{
53178c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
53188c2ecf20Sopenharmony_ci	int ret = 0;
53198c2ecf20Sopenharmony_ci
53208c2ecf20Sopenharmony_ci	if (!mvpp22_rss_is_supported())
53218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53228c2ecf20Sopenharmony_ci	if (rss_context >= MVPP22_N_RSS_TABLES)
53238c2ecf20Sopenharmony_ci		return -EINVAL;
53248c2ecf20Sopenharmony_ci
53258c2ecf20Sopenharmony_ci	if (hfunc)
53268c2ecf20Sopenharmony_ci		*hfunc = ETH_RSS_HASH_CRC32;
53278c2ecf20Sopenharmony_ci
53288c2ecf20Sopenharmony_ci	if (indir)
53298c2ecf20Sopenharmony_ci		ret = mvpp22_port_rss_ctx_indir_get(port, rss_context, indir);
53308c2ecf20Sopenharmony_ci
53318c2ecf20Sopenharmony_ci	return ret;
53328c2ecf20Sopenharmony_ci}
53338c2ecf20Sopenharmony_ci
53348c2ecf20Sopenharmony_cistatic int mvpp2_ethtool_set_rxfh_context(struct net_device *dev,
53358c2ecf20Sopenharmony_ci					  const u32 *indir, const u8 *key,
53368c2ecf20Sopenharmony_ci					  const u8 hfunc, u32 *rss_context,
53378c2ecf20Sopenharmony_ci					  bool delete)
53388c2ecf20Sopenharmony_ci{
53398c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
53408c2ecf20Sopenharmony_ci	int ret;
53418c2ecf20Sopenharmony_ci
53428c2ecf20Sopenharmony_ci	if (!mvpp22_rss_is_supported())
53438c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53448c2ecf20Sopenharmony_ci
53458c2ecf20Sopenharmony_ci	if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_CRC32)
53468c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53478c2ecf20Sopenharmony_ci
53488c2ecf20Sopenharmony_ci	if (key)
53498c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
53508c2ecf20Sopenharmony_ci
53518c2ecf20Sopenharmony_ci	if (delete)
53528c2ecf20Sopenharmony_ci		return mvpp22_port_rss_ctx_delete(port, *rss_context);
53538c2ecf20Sopenharmony_ci
53548c2ecf20Sopenharmony_ci	if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
53558c2ecf20Sopenharmony_ci		ret = mvpp22_port_rss_ctx_create(port, rss_context);
53568c2ecf20Sopenharmony_ci		if (ret)
53578c2ecf20Sopenharmony_ci			return ret;
53588c2ecf20Sopenharmony_ci	}
53598c2ecf20Sopenharmony_ci
53608c2ecf20Sopenharmony_ci	return mvpp22_port_rss_ctx_indir_set(port, *rss_context, indir);
53618c2ecf20Sopenharmony_ci}
53628c2ecf20Sopenharmony_ci/* Device ops */
53638c2ecf20Sopenharmony_ci
53648c2ecf20Sopenharmony_cistatic const struct net_device_ops mvpp2_netdev_ops = {
53658c2ecf20Sopenharmony_ci	.ndo_open		= mvpp2_open,
53668c2ecf20Sopenharmony_ci	.ndo_stop		= mvpp2_stop,
53678c2ecf20Sopenharmony_ci	.ndo_start_xmit		= mvpp2_tx,
53688c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= mvpp2_set_rx_mode,
53698c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= mvpp2_set_mac_address,
53708c2ecf20Sopenharmony_ci	.ndo_change_mtu		= mvpp2_change_mtu,
53718c2ecf20Sopenharmony_ci	.ndo_get_stats64	= mvpp2_get_stats64,
53728c2ecf20Sopenharmony_ci	.ndo_do_ioctl		= mvpp2_ioctl,
53738c2ecf20Sopenharmony_ci	.ndo_vlan_rx_add_vid	= mvpp2_vlan_rx_add_vid,
53748c2ecf20Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= mvpp2_vlan_rx_kill_vid,
53758c2ecf20Sopenharmony_ci	.ndo_set_features	= mvpp2_set_features,
53768c2ecf20Sopenharmony_ci	.ndo_bpf		= mvpp2_xdp,
53778c2ecf20Sopenharmony_ci	.ndo_xdp_xmit		= mvpp2_xdp_xmit,
53788c2ecf20Sopenharmony_ci};
53798c2ecf20Sopenharmony_ci
53808c2ecf20Sopenharmony_cistatic const struct ethtool_ops mvpp2_eth_tool_ops = {
53818c2ecf20Sopenharmony_ci	.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
53828c2ecf20Sopenharmony_ci				     ETHTOOL_COALESCE_MAX_FRAMES,
53838c2ecf20Sopenharmony_ci	.nway_reset		= mvpp2_ethtool_nway_reset,
53848c2ecf20Sopenharmony_ci	.get_link		= ethtool_op_get_link,
53858c2ecf20Sopenharmony_ci	.get_ts_info		= mvpp2_ethtool_get_ts_info,
53868c2ecf20Sopenharmony_ci	.set_coalesce		= mvpp2_ethtool_set_coalesce,
53878c2ecf20Sopenharmony_ci	.get_coalesce		= mvpp2_ethtool_get_coalesce,
53888c2ecf20Sopenharmony_ci	.get_drvinfo		= mvpp2_ethtool_get_drvinfo,
53898c2ecf20Sopenharmony_ci	.get_ringparam		= mvpp2_ethtool_get_ringparam,
53908c2ecf20Sopenharmony_ci	.set_ringparam		= mvpp2_ethtool_set_ringparam,
53918c2ecf20Sopenharmony_ci	.get_strings		= mvpp2_ethtool_get_strings,
53928c2ecf20Sopenharmony_ci	.get_ethtool_stats	= mvpp2_ethtool_get_stats,
53938c2ecf20Sopenharmony_ci	.get_sset_count		= mvpp2_ethtool_get_sset_count,
53948c2ecf20Sopenharmony_ci	.get_pauseparam		= mvpp2_ethtool_get_pause_param,
53958c2ecf20Sopenharmony_ci	.set_pauseparam		= mvpp2_ethtool_set_pause_param,
53968c2ecf20Sopenharmony_ci	.get_link_ksettings	= mvpp2_ethtool_get_link_ksettings,
53978c2ecf20Sopenharmony_ci	.set_link_ksettings	= mvpp2_ethtool_set_link_ksettings,
53988c2ecf20Sopenharmony_ci	.get_rxnfc		= mvpp2_ethtool_get_rxnfc,
53998c2ecf20Sopenharmony_ci	.set_rxnfc		= mvpp2_ethtool_set_rxnfc,
54008c2ecf20Sopenharmony_ci	.get_rxfh_indir_size	= mvpp2_ethtool_get_rxfh_indir_size,
54018c2ecf20Sopenharmony_ci	.get_rxfh		= mvpp2_ethtool_get_rxfh,
54028c2ecf20Sopenharmony_ci	.set_rxfh		= mvpp2_ethtool_set_rxfh,
54038c2ecf20Sopenharmony_ci	.get_rxfh_context	= mvpp2_ethtool_get_rxfh_context,
54048c2ecf20Sopenharmony_ci	.set_rxfh_context	= mvpp2_ethtool_set_rxfh_context,
54058c2ecf20Sopenharmony_ci};
54068c2ecf20Sopenharmony_ci
54078c2ecf20Sopenharmony_ci/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
54088c2ecf20Sopenharmony_ci * had a single IRQ defined per-port.
54098c2ecf20Sopenharmony_ci */
54108c2ecf20Sopenharmony_cistatic int mvpp2_simple_queue_vectors_init(struct mvpp2_port *port,
54118c2ecf20Sopenharmony_ci					   struct device_node *port_node)
54128c2ecf20Sopenharmony_ci{
54138c2ecf20Sopenharmony_ci	struct mvpp2_queue_vector *v = &port->qvecs[0];
54148c2ecf20Sopenharmony_ci
54158c2ecf20Sopenharmony_ci	v->first_rxq = 0;
54168c2ecf20Sopenharmony_ci	v->nrxqs = port->nrxqs;
54178c2ecf20Sopenharmony_ci	v->type = MVPP2_QUEUE_VECTOR_SHARED;
54188c2ecf20Sopenharmony_ci	v->sw_thread_id = 0;
54198c2ecf20Sopenharmony_ci	v->sw_thread_mask = *cpumask_bits(cpu_online_mask);
54208c2ecf20Sopenharmony_ci	v->port = port;
54218c2ecf20Sopenharmony_ci	v->irq = irq_of_parse_and_map(port_node, 0);
54228c2ecf20Sopenharmony_ci	if (v->irq <= 0)
54238c2ecf20Sopenharmony_ci		return -EINVAL;
54248c2ecf20Sopenharmony_ci	netif_napi_add(port->dev, &v->napi, mvpp2_poll,
54258c2ecf20Sopenharmony_ci		       NAPI_POLL_WEIGHT);
54268c2ecf20Sopenharmony_ci
54278c2ecf20Sopenharmony_ci	port->nqvecs = 1;
54288c2ecf20Sopenharmony_ci
54298c2ecf20Sopenharmony_ci	return 0;
54308c2ecf20Sopenharmony_ci}
54318c2ecf20Sopenharmony_ci
54328c2ecf20Sopenharmony_cistatic int mvpp2_multi_queue_vectors_init(struct mvpp2_port *port,
54338c2ecf20Sopenharmony_ci					  struct device_node *port_node)
54348c2ecf20Sopenharmony_ci{
54358c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
54368c2ecf20Sopenharmony_ci	struct mvpp2_queue_vector *v;
54378c2ecf20Sopenharmony_ci	int i, ret;
54388c2ecf20Sopenharmony_ci
54398c2ecf20Sopenharmony_ci	switch (queue_mode) {
54408c2ecf20Sopenharmony_ci	case MVPP2_QDIST_SINGLE_MODE:
54418c2ecf20Sopenharmony_ci		port->nqvecs = priv->nthreads + 1;
54428c2ecf20Sopenharmony_ci		break;
54438c2ecf20Sopenharmony_ci	case MVPP2_QDIST_MULTI_MODE:
54448c2ecf20Sopenharmony_ci		port->nqvecs = priv->nthreads;
54458c2ecf20Sopenharmony_ci		break;
54468c2ecf20Sopenharmony_ci	}
54478c2ecf20Sopenharmony_ci
54488c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++) {
54498c2ecf20Sopenharmony_ci		char irqname[16];
54508c2ecf20Sopenharmony_ci
54518c2ecf20Sopenharmony_ci		v = port->qvecs + i;
54528c2ecf20Sopenharmony_ci
54538c2ecf20Sopenharmony_ci		v->port = port;
54548c2ecf20Sopenharmony_ci		v->type = MVPP2_QUEUE_VECTOR_PRIVATE;
54558c2ecf20Sopenharmony_ci		v->sw_thread_id = i;
54568c2ecf20Sopenharmony_ci		v->sw_thread_mask = BIT(i);
54578c2ecf20Sopenharmony_ci
54588c2ecf20Sopenharmony_ci		if (port->flags & MVPP2_F_DT_COMPAT)
54598c2ecf20Sopenharmony_ci			snprintf(irqname, sizeof(irqname), "tx-cpu%d", i);
54608c2ecf20Sopenharmony_ci		else
54618c2ecf20Sopenharmony_ci			snprintf(irqname, sizeof(irqname), "hif%d", i);
54628c2ecf20Sopenharmony_ci
54638c2ecf20Sopenharmony_ci		if (queue_mode == MVPP2_QDIST_MULTI_MODE) {
54648c2ecf20Sopenharmony_ci			v->first_rxq = i;
54658c2ecf20Sopenharmony_ci			v->nrxqs = 1;
54668c2ecf20Sopenharmony_ci		} else if (queue_mode == MVPP2_QDIST_SINGLE_MODE &&
54678c2ecf20Sopenharmony_ci			   i == (port->nqvecs - 1)) {
54688c2ecf20Sopenharmony_ci			v->first_rxq = 0;
54698c2ecf20Sopenharmony_ci			v->nrxqs = port->nrxqs;
54708c2ecf20Sopenharmony_ci			v->type = MVPP2_QUEUE_VECTOR_SHARED;
54718c2ecf20Sopenharmony_ci
54728c2ecf20Sopenharmony_ci			if (port->flags & MVPP2_F_DT_COMPAT)
54738c2ecf20Sopenharmony_ci				strncpy(irqname, "rx-shared", sizeof(irqname));
54748c2ecf20Sopenharmony_ci		}
54758c2ecf20Sopenharmony_ci
54768c2ecf20Sopenharmony_ci		if (port_node)
54778c2ecf20Sopenharmony_ci			v->irq = of_irq_get_byname(port_node, irqname);
54788c2ecf20Sopenharmony_ci		else
54798c2ecf20Sopenharmony_ci			v->irq = fwnode_irq_get(port->fwnode, i);
54808c2ecf20Sopenharmony_ci		if (v->irq <= 0) {
54818c2ecf20Sopenharmony_ci			ret = -EINVAL;
54828c2ecf20Sopenharmony_ci			goto err;
54838c2ecf20Sopenharmony_ci		}
54848c2ecf20Sopenharmony_ci
54858c2ecf20Sopenharmony_ci		netif_napi_add(port->dev, &v->napi, mvpp2_poll,
54868c2ecf20Sopenharmony_ci			       NAPI_POLL_WEIGHT);
54878c2ecf20Sopenharmony_ci	}
54888c2ecf20Sopenharmony_ci
54898c2ecf20Sopenharmony_ci	return 0;
54908c2ecf20Sopenharmony_ci
54918c2ecf20Sopenharmony_cierr:
54928c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++)
54938c2ecf20Sopenharmony_ci		irq_dispose_mapping(port->qvecs[i].irq);
54948c2ecf20Sopenharmony_ci	return ret;
54958c2ecf20Sopenharmony_ci}
54968c2ecf20Sopenharmony_ci
54978c2ecf20Sopenharmony_cistatic int mvpp2_queue_vectors_init(struct mvpp2_port *port,
54988c2ecf20Sopenharmony_ci				    struct device_node *port_node)
54998c2ecf20Sopenharmony_ci{
55008c2ecf20Sopenharmony_ci	if (port->has_tx_irqs)
55018c2ecf20Sopenharmony_ci		return mvpp2_multi_queue_vectors_init(port, port_node);
55028c2ecf20Sopenharmony_ci	else
55038c2ecf20Sopenharmony_ci		return mvpp2_simple_queue_vectors_init(port, port_node);
55048c2ecf20Sopenharmony_ci}
55058c2ecf20Sopenharmony_ci
55068c2ecf20Sopenharmony_cistatic void mvpp2_queue_vectors_deinit(struct mvpp2_port *port)
55078c2ecf20Sopenharmony_ci{
55088c2ecf20Sopenharmony_ci	int i;
55098c2ecf20Sopenharmony_ci
55108c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++)
55118c2ecf20Sopenharmony_ci		irq_dispose_mapping(port->qvecs[i].irq);
55128c2ecf20Sopenharmony_ci}
55138c2ecf20Sopenharmony_ci
55148c2ecf20Sopenharmony_ci/* Configure Rx queue group interrupt for this port */
55158c2ecf20Sopenharmony_cistatic void mvpp2_rx_irqs_setup(struct mvpp2_port *port)
55168c2ecf20Sopenharmony_ci{
55178c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
55188c2ecf20Sopenharmony_ci	u32 val;
55198c2ecf20Sopenharmony_ci	int i;
55208c2ecf20Sopenharmony_ci
55218c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21) {
55228c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id),
55238c2ecf20Sopenharmony_ci			    port->nrxqs);
55248c2ecf20Sopenharmony_ci		return;
55258c2ecf20Sopenharmony_ci	}
55268c2ecf20Sopenharmony_ci
55278c2ecf20Sopenharmony_ci	/* Handle the more complicated PPv2.2 case */
55288c2ecf20Sopenharmony_ci	for (i = 0; i < port->nqvecs; i++) {
55298c2ecf20Sopenharmony_ci		struct mvpp2_queue_vector *qv = port->qvecs + i;
55308c2ecf20Sopenharmony_ci
55318c2ecf20Sopenharmony_ci		if (!qv->nrxqs)
55328c2ecf20Sopenharmony_ci			continue;
55338c2ecf20Sopenharmony_ci
55348c2ecf20Sopenharmony_ci		val = qv->sw_thread_id;
55358c2ecf20Sopenharmony_ci		val |= port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET;
55368c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
55378c2ecf20Sopenharmony_ci
55388c2ecf20Sopenharmony_ci		val = qv->first_rxq;
55398c2ecf20Sopenharmony_ci		val |= qv->nrxqs << MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET;
55408c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
55418c2ecf20Sopenharmony_ci	}
55428c2ecf20Sopenharmony_ci}
55438c2ecf20Sopenharmony_ci
55448c2ecf20Sopenharmony_ci/* Initialize port HW */
55458c2ecf20Sopenharmony_cistatic int mvpp2_port_init(struct mvpp2_port *port)
55468c2ecf20Sopenharmony_ci{
55478c2ecf20Sopenharmony_ci	struct device *dev = port->dev->dev.parent;
55488c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
55498c2ecf20Sopenharmony_ci	struct mvpp2_txq_pcpu *txq_pcpu;
55508c2ecf20Sopenharmony_ci	unsigned int thread;
55518c2ecf20Sopenharmony_ci	int queue, err, val;
55528c2ecf20Sopenharmony_ci
55538c2ecf20Sopenharmony_ci	/* Checks for hardware constraints */
55548c2ecf20Sopenharmony_ci	if (port->first_rxq + port->nrxqs >
55558c2ecf20Sopenharmony_ci	    MVPP2_MAX_PORTS * priv->max_port_rxqs)
55568c2ecf20Sopenharmony_ci		return -EINVAL;
55578c2ecf20Sopenharmony_ci
55588c2ecf20Sopenharmony_ci	if (port->nrxqs > priv->max_port_rxqs || port->ntxqs > MVPP2_MAX_TXQ)
55598c2ecf20Sopenharmony_ci		return -EINVAL;
55608c2ecf20Sopenharmony_ci
55618c2ecf20Sopenharmony_ci	/* Disable port */
55628c2ecf20Sopenharmony_ci	mvpp2_egress_disable(port);
55638c2ecf20Sopenharmony_ci	mvpp2_port_disable(port);
55648c2ecf20Sopenharmony_ci
55658c2ecf20Sopenharmony_ci	if (mvpp2_is_xlg(port->phy_interface)) {
55668c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_CTRL0_REG);
55678c2ecf20Sopenharmony_ci		val &= ~MVPP22_XLG_CTRL0_FORCE_LINK_PASS;
55688c2ecf20Sopenharmony_ci		val |= MVPP22_XLG_CTRL0_FORCE_LINK_DOWN;
55698c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP22_XLG_CTRL0_REG);
55708c2ecf20Sopenharmony_ci	} else {
55718c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
55728c2ecf20Sopenharmony_ci		val &= ~MVPP2_GMAC_FORCE_LINK_PASS;
55738c2ecf20Sopenharmony_ci		val |= MVPP2_GMAC_FORCE_LINK_DOWN;
55748c2ecf20Sopenharmony_ci		writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
55758c2ecf20Sopenharmony_ci	}
55768c2ecf20Sopenharmony_ci
55778c2ecf20Sopenharmony_ci	port->tx_time_coal = MVPP2_TXDONE_COAL_USEC;
55788c2ecf20Sopenharmony_ci
55798c2ecf20Sopenharmony_ci	port->txqs = devm_kcalloc(dev, port->ntxqs, sizeof(*port->txqs),
55808c2ecf20Sopenharmony_ci				  GFP_KERNEL);
55818c2ecf20Sopenharmony_ci	if (!port->txqs)
55828c2ecf20Sopenharmony_ci		return -ENOMEM;
55838c2ecf20Sopenharmony_ci
55848c2ecf20Sopenharmony_ci	/* Associate physical Tx queues to this port and initialize.
55858c2ecf20Sopenharmony_ci	 * The mapping is predefined.
55868c2ecf20Sopenharmony_ci	 */
55878c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
55888c2ecf20Sopenharmony_ci		int queue_phy_id = mvpp2_txq_phys(port->id, queue);
55898c2ecf20Sopenharmony_ci		struct mvpp2_tx_queue *txq;
55908c2ecf20Sopenharmony_ci
55918c2ecf20Sopenharmony_ci		txq = devm_kzalloc(dev, sizeof(*txq), GFP_KERNEL);
55928c2ecf20Sopenharmony_ci		if (!txq) {
55938c2ecf20Sopenharmony_ci			err = -ENOMEM;
55948c2ecf20Sopenharmony_ci			goto err_free_percpu;
55958c2ecf20Sopenharmony_ci		}
55968c2ecf20Sopenharmony_ci
55978c2ecf20Sopenharmony_ci		txq->pcpu = alloc_percpu(struct mvpp2_txq_pcpu);
55988c2ecf20Sopenharmony_ci		if (!txq->pcpu) {
55998c2ecf20Sopenharmony_ci			err = -ENOMEM;
56008c2ecf20Sopenharmony_ci			goto err_free_percpu;
56018c2ecf20Sopenharmony_ci		}
56028c2ecf20Sopenharmony_ci
56038c2ecf20Sopenharmony_ci		txq->id = queue_phy_id;
56048c2ecf20Sopenharmony_ci		txq->log_id = queue;
56058c2ecf20Sopenharmony_ci		txq->done_pkts_coal = MVPP2_TXDONE_COAL_PKTS_THRESH;
56068c2ecf20Sopenharmony_ci		for (thread = 0; thread < priv->nthreads; thread++) {
56078c2ecf20Sopenharmony_ci			txq_pcpu = per_cpu_ptr(txq->pcpu, thread);
56088c2ecf20Sopenharmony_ci			txq_pcpu->thread = thread;
56098c2ecf20Sopenharmony_ci		}
56108c2ecf20Sopenharmony_ci
56118c2ecf20Sopenharmony_ci		port->txqs[queue] = txq;
56128c2ecf20Sopenharmony_ci	}
56138c2ecf20Sopenharmony_ci
56148c2ecf20Sopenharmony_ci	port->rxqs = devm_kcalloc(dev, port->nrxqs, sizeof(*port->rxqs),
56158c2ecf20Sopenharmony_ci				  GFP_KERNEL);
56168c2ecf20Sopenharmony_ci	if (!port->rxqs) {
56178c2ecf20Sopenharmony_ci		err = -ENOMEM;
56188c2ecf20Sopenharmony_ci		goto err_free_percpu;
56198c2ecf20Sopenharmony_ci	}
56208c2ecf20Sopenharmony_ci
56218c2ecf20Sopenharmony_ci	/* Allocate and initialize Rx queue for this port */
56228c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->nrxqs; queue++) {
56238c2ecf20Sopenharmony_ci		struct mvpp2_rx_queue *rxq;
56248c2ecf20Sopenharmony_ci
56258c2ecf20Sopenharmony_ci		/* Map physical Rx queue to port's logical Rx queue */
56268c2ecf20Sopenharmony_ci		rxq = devm_kzalloc(dev, sizeof(*rxq), GFP_KERNEL);
56278c2ecf20Sopenharmony_ci		if (!rxq) {
56288c2ecf20Sopenharmony_ci			err = -ENOMEM;
56298c2ecf20Sopenharmony_ci			goto err_free_percpu;
56308c2ecf20Sopenharmony_ci		}
56318c2ecf20Sopenharmony_ci		/* Map this Rx queue to a physical queue */
56328c2ecf20Sopenharmony_ci		rxq->id = port->first_rxq + queue;
56338c2ecf20Sopenharmony_ci		rxq->port = port->id;
56348c2ecf20Sopenharmony_ci		rxq->logic_rxq = queue;
56358c2ecf20Sopenharmony_ci
56368c2ecf20Sopenharmony_ci		port->rxqs[queue] = rxq;
56378c2ecf20Sopenharmony_ci	}
56388c2ecf20Sopenharmony_ci
56398c2ecf20Sopenharmony_ci	mvpp2_rx_irqs_setup(port);
56408c2ecf20Sopenharmony_ci
56418c2ecf20Sopenharmony_ci	/* Create Rx descriptor rings */
56428c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->nrxqs; queue++) {
56438c2ecf20Sopenharmony_ci		struct mvpp2_rx_queue *rxq = port->rxqs[queue];
56448c2ecf20Sopenharmony_ci
56458c2ecf20Sopenharmony_ci		rxq->size = port->rx_ring_size;
56468c2ecf20Sopenharmony_ci		rxq->pkts_coal = MVPP2_RX_COAL_PKTS;
56478c2ecf20Sopenharmony_ci		rxq->time_coal = MVPP2_RX_COAL_USEC;
56488c2ecf20Sopenharmony_ci	}
56498c2ecf20Sopenharmony_ci
56508c2ecf20Sopenharmony_ci	mvpp2_ingress_disable(port);
56518c2ecf20Sopenharmony_ci
56528c2ecf20Sopenharmony_ci	/* Port default configuration */
56538c2ecf20Sopenharmony_ci	mvpp2_defaults_set(port);
56548c2ecf20Sopenharmony_ci
56558c2ecf20Sopenharmony_ci	/* Port's classifier configuration */
56568c2ecf20Sopenharmony_ci	mvpp2_cls_oversize_rxq_set(port);
56578c2ecf20Sopenharmony_ci	mvpp2_cls_port_config(port);
56588c2ecf20Sopenharmony_ci
56598c2ecf20Sopenharmony_ci	if (mvpp22_rss_is_supported())
56608c2ecf20Sopenharmony_ci		mvpp22_port_rss_init(port);
56618c2ecf20Sopenharmony_ci
56628c2ecf20Sopenharmony_ci	/* Provide an initial Rx packet size */
56638c2ecf20Sopenharmony_ci	port->pkt_size = MVPP2_RX_PKT_SIZE(port->dev->mtu);
56648c2ecf20Sopenharmony_ci
56658c2ecf20Sopenharmony_ci	/* Initialize pools for swf */
56668c2ecf20Sopenharmony_ci	err = mvpp2_swf_bm_pool_init(port);
56678c2ecf20Sopenharmony_ci	if (err)
56688c2ecf20Sopenharmony_ci		goto err_free_percpu;
56698c2ecf20Sopenharmony_ci
56708c2ecf20Sopenharmony_ci	/* Clear all port stats */
56718c2ecf20Sopenharmony_ci	mvpp2_read_stats(port);
56728c2ecf20Sopenharmony_ci	memset(port->ethtool_stats, 0,
56738c2ecf20Sopenharmony_ci	       MVPP2_N_ETHTOOL_STATS(port->ntxqs, port->nrxqs) * sizeof(u64));
56748c2ecf20Sopenharmony_ci
56758c2ecf20Sopenharmony_ci	return 0;
56768c2ecf20Sopenharmony_ci
56778c2ecf20Sopenharmony_cierr_free_percpu:
56788c2ecf20Sopenharmony_ci	for (queue = 0; queue < port->ntxqs; queue++) {
56798c2ecf20Sopenharmony_ci		if (!port->txqs[queue])
56808c2ecf20Sopenharmony_ci			continue;
56818c2ecf20Sopenharmony_ci		free_percpu(port->txqs[queue]->pcpu);
56828c2ecf20Sopenharmony_ci	}
56838c2ecf20Sopenharmony_ci	return err;
56848c2ecf20Sopenharmony_ci}
56858c2ecf20Sopenharmony_ci
56868c2ecf20Sopenharmony_cistatic bool mvpp22_port_has_legacy_tx_irqs(struct device_node *port_node,
56878c2ecf20Sopenharmony_ci					   unsigned long *flags)
56888c2ecf20Sopenharmony_ci{
56898c2ecf20Sopenharmony_ci	char *irqs[5] = { "rx-shared", "tx-cpu0", "tx-cpu1", "tx-cpu2",
56908c2ecf20Sopenharmony_ci			  "tx-cpu3" };
56918c2ecf20Sopenharmony_ci	int i;
56928c2ecf20Sopenharmony_ci
56938c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++)
56948c2ecf20Sopenharmony_ci		if (of_property_match_string(port_node, "interrupt-names",
56958c2ecf20Sopenharmony_ci					     irqs[i]) < 0)
56968c2ecf20Sopenharmony_ci			return false;
56978c2ecf20Sopenharmony_ci
56988c2ecf20Sopenharmony_ci	*flags |= MVPP2_F_DT_COMPAT;
56998c2ecf20Sopenharmony_ci	return true;
57008c2ecf20Sopenharmony_ci}
57018c2ecf20Sopenharmony_ci
57028c2ecf20Sopenharmony_ci/* Checks if the port dt description has the required Tx interrupts:
57038c2ecf20Sopenharmony_ci * - PPv2.1: there are no such interrupts.
57048c2ecf20Sopenharmony_ci * - PPv2.2:
57058c2ecf20Sopenharmony_ci *   - The old DTs have: "rx-shared", "tx-cpuX" with X in [0...3]
57068c2ecf20Sopenharmony_ci *   - The new ones have: "hifX" with X in [0..8]
57078c2ecf20Sopenharmony_ci *
57088c2ecf20Sopenharmony_ci * All those variants are supported to keep the backward compatibility.
57098c2ecf20Sopenharmony_ci */
57108c2ecf20Sopenharmony_cistatic bool mvpp2_port_has_irqs(struct mvpp2 *priv,
57118c2ecf20Sopenharmony_ci				struct device_node *port_node,
57128c2ecf20Sopenharmony_ci				unsigned long *flags)
57138c2ecf20Sopenharmony_ci{
57148c2ecf20Sopenharmony_ci	char name[5];
57158c2ecf20Sopenharmony_ci	int i;
57168c2ecf20Sopenharmony_ci
57178c2ecf20Sopenharmony_ci	/* ACPI */
57188c2ecf20Sopenharmony_ci	if (!port_node)
57198c2ecf20Sopenharmony_ci		return true;
57208c2ecf20Sopenharmony_ci
57218c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
57228c2ecf20Sopenharmony_ci		return false;
57238c2ecf20Sopenharmony_ci
57248c2ecf20Sopenharmony_ci	if (mvpp22_port_has_legacy_tx_irqs(port_node, flags))
57258c2ecf20Sopenharmony_ci		return true;
57268c2ecf20Sopenharmony_ci
57278c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_THREADS; i++) {
57288c2ecf20Sopenharmony_ci		snprintf(name, 5, "hif%d", i);
57298c2ecf20Sopenharmony_ci		if (of_property_match_string(port_node, "interrupt-names",
57308c2ecf20Sopenharmony_ci					     name) < 0)
57318c2ecf20Sopenharmony_ci			return false;
57328c2ecf20Sopenharmony_ci	}
57338c2ecf20Sopenharmony_ci
57348c2ecf20Sopenharmony_ci	return true;
57358c2ecf20Sopenharmony_ci}
57368c2ecf20Sopenharmony_ci
57378c2ecf20Sopenharmony_cistatic void mvpp2_port_copy_mac_addr(struct net_device *dev, struct mvpp2 *priv,
57388c2ecf20Sopenharmony_ci				     struct fwnode_handle *fwnode,
57398c2ecf20Sopenharmony_ci				     char **mac_from)
57408c2ecf20Sopenharmony_ci{
57418c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
57428c2ecf20Sopenharmony_ci	char hw_mac_addr[ETH_ALEN] = {0};
57438c2ecf20Sopenharmony_ci	char fw_mac_addr[ETH_ALEN];
57448c2ecf20Sopenharmony_ci
57458c2ecf20Sopenharmony_ci	if (fwnode_get_mac_address(fwnode, fw_mac_addr, ETH_ALEN)) {
57468c2ecf20Sopenharmony_ci		*mac_from = "firmware node";
57478c2ecf20Sopenharmony_ci		ether_addr_copy(dev->dev_addr, fw_mac_addr);
57488c2ecf20Sopenharmony_ci		return;
57498c2ecf20Sopenharmony_ci	}
57508c2ecf20Sopenharmony_ci
57518c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21) {
57528c2ecf20Sopenharmony_ci		mvpp21_get_mac_address(port, hw_mac_addr);
57538c2ecf20Sopenharmony_ci		if (is_valid_ether_addr(hw_mac_addr)) {
57548c2ecf20Sopenharmony_ci			*mac_from = "hardware";
57558c2ecf20Sopenharmony_ci			ether_addr_copy(dev->dev_addr, hw_mac_addr);
57568c2ecf20Sopenharmony_ci			return;
57578c2ecf20Sopenharmony_ci		}
57588c2ecf20Sopenharmony_ci	}
57598c2ecf20Sopenharmony_ci
57608c2ecf20Sopenharmony_ci	*mac_from = "random";
57618c2ecf20Sopenharmony_ci	eth_hw_addr_random(dev);
57628c2ecf20Sopenharmony_ci}
57638c2ecf20Sopenharmony_ci
57648c2ecf20Sopenharmony_cistatic struct mvpp2_port *mvpp2_phylink_to_port(struct phylink_config *config)
57658c2ecf20Sopenharmony_ci{
57668c2ecf20Sopenharmony_ci	return container_of(config, struct mvpp2_port, phylink_config);
57678c2ecf20Sopenharmony_ci}
57688c2ecf20Sopenharmony_ci
57698c2ecf20Sopenharmony_cistatic struct mvpp2_port *mvpp2_pcs_to_port(struct phylink_pcs *pcs)
57708c2ecf20Sopenharmony_ci{
57718c2ecf20Sopenharmony_ci	return container_of(pcs, struct mvpp2_port, phylink_pcs);
57728c2ecf20Sopenharmony_ci}
57738c2ecf20Sopenharmony_ci
57748c2ecf20Sopenharmony_cistatic void mvpp2_xlg_pcs_get_state(struct phylink_pcs *pcs,
57758c2ecf20Sopenharmony_ci				    struct phylink_link_state *state)
57768c2ecf20Sopenharmony_ci{
57778c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
57788c2ecf20Sopenharmony_ci	u32 val;
57798c2ecf20Sopenharmony_ci
57808c2ecf20Sopenharmony_ci	state->speed = SPEED_10000;
57818c2ecf20Sopenharmony_ci	state->duplex = 1;
57828c2ecf20Sopenharmony_ci	state->an_complete = 1;
57838c2ecf20Sopenharmony_ci
57848c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP22_XLG_STATUS);
57858c2ecf20Sopenharmony_ci	state->link = !!(val & MVPP22_XLG_STATUS_LINK_UP);
57868c2ecf20Sopenharmony_ci
57878c2ecf20Sopenharmony_ci	state->pause = 0;
57888c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP22_XLG_CTRL0_REG);
57898c2ecf20Sopenharmony_ci	if (val & MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN)
57908c2ecf20Sopenharmony_ci		state->pause |= MLO_PAUSE_TX;
57918c2ecf20Sopenharmony_ci	if (val & MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN)
57928c2ecf20Sopenharmony_ci		state->pause |= MLO_PAUSE_RX;
57938c2ecf20Sopenharmony_ci}
57948c2ecf20Sopenharmony_ci
57958c2ecf20Sopenharmony_cistatic int mvpp2_xlg_pcs_config(struct phylink_pcs *pcs,
57968c2ecf20Sopenharmony_ci				unsigned int mode,
57978c2ecf20Sopenharmony_ci				phy_interface_t interface,
57988c2ecf20Sopenharmony_ci				const unsigned long *advertising,
57998c2ecf20Sopenharmony_ci				bool permit_pause_to_mac)
58008c2ecf20Sopenharmony_ci{
58018c2ecf20Sopenharmony_ci	return 0;
58028c2ecf20Sopenharmony_ci}
58038c2ecf20Sopenharmony_ci
58048c2ecf20Sopenharmony_cistatic const struct phylink_pcs_ops mvpp2_phylink_xlg_pcs_ops = {
58058c2ecf20Sopenharmony_ci	.pcs_get_state = mvpp2_xlg_pcs_get_state,
58068c2ecf20Sopenharmony_ci	.pcs_config = mvpp2_xlg_pcs_config,
58078c2ecf20Sopenharmony_ci};
58088c2ecf20Sopenharmony_ci
58098c2ecf20Sopenharmony_cistatic void mvpp2_gmac_pcs_get_state(struct phylink_pcs *pcs,
58108c2ecf20Sopenharmony_ci				     struct phylink_link_state *state)
58118c2ecf20Sopenharmony_ci{
58128c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
58138c2ecf20Sopenharmony_ci	u32 val;
58148c2ecf20Sopenharmony_ci
58158c2ecf20Sopenharmony_ci	val = readl(port->base + MVPP2_GMAC_STATUS0);
58168c2ecf20Sopenharmony_ci
58178c2ecf20Sopenharmony_ci	state->an_complete = !!(val & MVPP2_GMAC_STATUS0_AN_COMPLETE);
58188c2ecf20Sopenharmony_ci	state->link = !!(val & MVPP2_GMAC_STATUS0_LINK_UP);
58198c2ecf20Sopenharmony_ci	state->duplex = !!(val & MVPP2_GMAC_STATUS0_FULL_DUPLEX);
58208c2ecf20Sopenharmony_ci
58218c2ecf20Sopenharmony_ci	switch (port->phy_interface) {
58228c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_1000BASEX:
58238c2ecf20Sopenharmony_ci		state->speed = SPEED_1000;
58248c2ecf20Sopenharmony_ci		break;
58258c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_2500BASEX:
58268c2ecf20Sopenharmony_ci		state->speed = SPEED_2500;
58278c2ecf20Sopenharmony_ci		break;
58288c2ecf20Sopenharmony_ci	default:
58298c2ecf20Sopenharmony_ci		if (val & MVPP2_GMAC_STATUS0_GMII_SPEED)
58308c2ecf20Sopenharmony_ci			state->speed = SPEED_1000;
58318c2ecf20Sopenharmony_ci		else if (val & MVPP2_GMAC_STATUS0_MII_SPEED)
58328c2ecf20Sopenharmony_ci			state->speed = SPEED_100;
58338c2ecf20Sopenharmony_ci		else
58348c2ecf20Sopenharmony_ci			state->speed = SPEED_10;
58358c2ecf20Sopenharmony_ci	}
58368c2ecf20Sopenharmony_ci
58378c2ecf20Sopenharmony_ci	state->pause = 0;
58388c2ecf20Sopenharmony_ci	if (val & MVPP2_GMAC_STATUS0_RX_PAUSE)
58398c2ecf20Sopenharmony_ci		state->pause |= MLO_PAUSE_RX;
58408c2ecf20Sopenharmony_ci	if (val & MVPP2_GMAC_STATUS0_TX_PAUSE)
58418c2ecf20Sopenharmony_ci		state->pause |= MLO_PAUSE_TX;
58428c2ecf20Sopenharmony_ci}
58438c2ecf20Sopenharmony_ci
58448c2ecf20Sopenharmony_cistatic int mvpp2_gmac_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
58458c2ecf20Sopenharmony_ci				 phy_interface_t interface,
58468c2ecf20Sopenharmony_ci				 const unsigned long *advertising,
58478c2ecf20Sopenharmony_ci				 bool permit_pause_to_mac)
58488c2ecf20Sopenharmony_ci{
58498c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
58508c2ecf20Sopenharmony_ci	u32 mask, val, an, old_an, changed;
58518c2ecf20Sopenharmony_ci
58528c2ecf20Sopenharmony_ci	mask = MVPP2_GMAC_IN_BAND_AUTONEG_BYPASS |
58538c2ecf20Sopenharmony_ci	       MVPP2_GMAC_IN_BAND_AUTONEG |
58548c2ecf20Sopenharmony_ci	       MVPP2_GMAC_AN_SPEED_EN |
58558c2ecf20Sopenharmony_ci	       MVPP2_GMAC_FLOW_CTRL_AUTONEG |
58568c2ecf20Sopenharmony_ci	       MVPP2_GMAC_AN_DUPLEX_EN;
58578c2ecf20Sopenharmony_ci
58588c2ecf20Sopenharmony_ci	if (phylink_autoneg_inband(mode)) {
58598c2ecf20Sopenharmony_ci		mask |= MVPP2_GMAC_CONFIG_MII_SPEED |
58608c2ecf20Sopenharmony_ci			MVPP2_GMAC_CONFIG_GMII_SPEED |
58618c2ecf20Sopenharmony_ci			MVPP2_GMAC_CONFIG_FULL_DUPLEX;
58628c2ecf20Sopenharmony_ci		val = MVPP2_GMAC_IN_BAND_AUTONEG;
58638c2ecf20Sopenharmony_ci
58648c2ecf20Sopenharmony_ci		if (interface == PHY_INTERFACE_MODE_SGMII) {
58658c2ecf20Sopenharmony_ci			/* SGMII mode receives the speed and duplex from PHY */
58668c2ecf20Sopenharmony_ci			val |= MVPP2_GMAC_AN_SPEED_EN |
58678c2ecf20Sopenharmony_ci			       MVPP2_GMAC_AN_DUPLEX_EN;
58688c2ecf20Sopenharmony_ci		} else {
58698c2ecf20Sopenharmony_ci			/* 802.3z mode has fixed speed and duplex */
58708c2ecf20Sopenharmony_ci			val |= MVPP2_GMAC_CONFIG_GMII_SPEED |
58718c2ecf20Sopenharmony_ci			       MVPP2_GMAC_CONFIG_FULL_DUPLEX;
58728c2ecf20Sopenharmony_ci
58738c2ecf20Sopenharmony_ci			/* The FLOW_CTRL_AUTONEG bit selects either the hardware
58748c2ecf20Sopenharmony_ci			 * automatically or the bits in MVPP22_GMAC_CTRL_4_REG
58758c2ecf20Sopenharmony_ci			 * manually controls the GMAC pause modes.
58768c2ecf20Sopenharmony_ci			 */
58778c2ecf20Sopenharmony_ci			if (permit_pause_to_mac)
58788c2ecf20Sopenharmony_ci				val |= MVPP2_GMAC_FLOW_CTRL_AUTONEG;
58798c2ecf20Sopenharmony_ci
58808c2ecf20Sopenharmony_ci			/* Configure advertisement bits */
58818c2ecf20Sopenharmony_ci			mask |= MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN;
58828c2ecf20Sopenharmony_ci			if (phylink_test(advertising, Pause))
58838c2ecf20Sopenharmony_ci				val |= MVPP2_GMAC_FC_ADV_EN;
58848c2ecf20Sopenharmony_ci			if (phylink_test(advertising, Asym_Pause))
58858c2ecf20Sopenharmony_ci				val |= MVPP2_GMAC_FC_ADV_ASM_EN;
58868c2ecf20Sopenharmony_ci		}
58878c2ecf20Sopenharmony_ci	} else {
58888c2ecf20Sopenharmony_ci		val = 0;
58898c2ecf20Sopenharmony_ci	}
58908c2ecf20Sopenharmony_ci
58918c2ecf20Sopenharmony_ci	old_an = an = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
58928c2ecf20Sopenharmony_ci	an = (an & ~mask) | val;
58938c2ecf20Sopenharmony_ci	changed = an ^ old_an;
58948c2ecf20Sopenharmony_ci	if (changed)
58958c2ecf20Sopenharmony_ci		writel(an, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
58968c2ecf20Sopenharmony_ci
58978c2ecf20Sopenharmony_ci	/* We are only interested in the advertisement bits changing */
58988c2ecf20Sopenharmony_ci	return changed & (MVPP2_GMAC_FC_ADV_EN | MVPP2_GMAC_FC_ADV_ASM_EN);
58998c2ecf20Sopenharmony_ci}
59008c2ecf20Sopenharmony_ci
59018c2ecf20Sopenharmony_cistatic void mvpp2_gmac_pcs_an_restart(struct phylink_pcs *pcs)
59028c2ecf20Sopenharmony_ci{
59038c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_pcs_to_port(pcs);
59048c2ecf20Sopenharmony_ci	u32 val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
59058c2ecf20Sopenharmony_ci
59068c2ecf20Sopenharmony_ci	writel(val | MVPP2_GMAC_IN_BAND_RESTART_AN,
59078c2ecf20Sopenharmony_ci	       port->base + MVPP2_GMAC_AUTONEG_CONFIG);
59088c2ecf20Sopenharmony_ci	writel(val & ~MVPP2_GMAC_IN_BAND_RESTART_AN,
59098c2ecf20Sopenharmony_ci	       port->base + MVPP2_GMAC_AUTONEG_CONFIG);
59108c2ecf20Sopenharmony_ci}
59118c2ecf20Sopenharmony_ci
59128c2ecf20Sopenharmony_cistatic const struct phylink_pcs_ops mvpp2_phylink_gmac_pcs_ops = {
59138c2ecf20Sopenharmony_ci	.pcs_get_state = mvpp2_gmac_pcs_get_state,
59148c2ecf20Sopenharmony_ci	.pcs_config = mvpp2_gmac_pcs_config,
59158c2ecf20Sopenharmony_ci	.pcs_an_restart = mvpp2_gmac_pcs_an_restart,
59168c2ecf20Sopenharmony_ci};
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_cistatic void mvpp2_phylink_validate(struct phylink_config *config,
59198c2ecf20Sopenharmony_ci				   unsigned long *supported,
59208c2ecf20Sopenharmony_ci				   struct phylink_link_state *state)
59218c2ecf20Sopenharmony_ci{
59228c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
59238c2ecf20Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
59248c2ecf20Sopenharmony_ci
59258c2ecf20Sopenharmony_ci	/* Invalid combinations */
59268c2ecf20Sopenharmony_ci	switch (state->interface) {
59278c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
59288c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_XAUI:
59298c2ecf20Sopenharmony_ci		if (!mvpp2_port_supports_xlg(port))
59308c2ecf20Sopenharmony_ci			goto empty_set;
59318c2ecf20Sopenharmony_ci		break;
59328c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
59338c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
59348c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
59358c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
59368c2ecf20Sopenharmony_ci		if (!mvpp2_port_supports_rgmii(port))
59378c2ecf20Sopenharmony_ci			goto empty_set;
59388c2ecf20Sopenharmony_ci		break;
59398c2ecf20Sopenharmony_ci	default:
59408c2ecf20Sopenharmony_ci		break;
59418c2ecf20Sopenharmony_ci	}
59428c2ecf20Sopenharmony_ci
59438c2ecf20Sopenharmony_ci	phylink_set(mask, Autoneg);
59448c2ecf20Sopenharmony_ci	phylink_set_port_modes(mask);
59458c2ecf20Sopenharmony_ci
59468c2ecf20Sopenharmony_ci	switch (state->interface) {
59478c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_10GBASER:
59488c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_XAUI:
59498c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_NA:
59508c2ecf20Sopenharmony_ci		if (mvpp2_port_supports_xlg(port)) {
59518c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseT_Full);
59528c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseCR_Full);
59538c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseSR_Full);
59548c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseLR_Full);
59558c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseLRM_Full);
59568c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseER_Full);
59578c2ecf20Sopenharmony_ci			phylink_set(mask, 10000baseKR_Full);
59588c2ecf20Sopenharmony_ci		}
59598c2ecf20Sopenharmony_ci		if (state->interface != PHY_INTERFACE_MODE_NA)
59608c2ecf20Sopenharmony_ci			break;
59618c2ecf20Sopenharmony_ci		fallthrough;
59628c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII:
59638c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_ID:
59648c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_RXID:
59658c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_RGMII_TXID:
59668c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_SGMII:
59678c2ecf20Sopenharmony_ci		phylink_set(mask, 10baseT_Half);
59688c2ecf20Sopenharmony_ci		phylink_set(mask, 10baseT_Full);
59698c2ecf20Sopenharmony_ci		phylink_set(mask, 100baseT_Half);
59708c2ecf20Sopenharmony_ci		phylink_set(mask, 100baseT_Full);
59718c2ecf20Sopenharmony_ci		phylink_set(mask, 1000baseT_Full);
59728c2ecf20Sopenharmony_ci		phylink_set(mask, 1000baseX_Full);
59738c2ecf20Sopenharmony_ci		if (state->interface != PHY_INTERFACE_MODE_NA)
59748c2ecf20Sopenharmony_ci			break;
59758c2ecf20Sopenharmony_ci		fallthrough;
59768c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_1000BASEX:
59778c2ecf20Sopenharmony_ci	case PHY_INTERFACE_MODE_2500BASEX:
59788c2ecf20Sopenharmony_ci		if (port->comphy ||
59798c2ecf20Sopenharmony_ci		    state->interface != PHY_INTERFACE_MODE_2500BASEX) {
59808c2ecf20Sopenharmony_ci			phylink_set(mask, 1000baseT_Full);
59818c2ecf20Sopenharmony_ci			phylink_set(mask, 1000baseX_Full);
59828c2ecf20Sopenharmony_ci		}
59838c2ecf20Sopenharmony_ci		if (port->comphy ||
59848c2ecf20Sopenharmony_ci		    state->interface == PHY_INTERFACE_MODE_2500BASEX) {
59858c2ecf20Sopenharmony_ci			phylink_set(mask, 2500baseT_Full);
59868c2ecf20Sopenharmony_ci			phylink_set(mask, 2500baseX_Full);
59878c2ecf20Sopenharmony_ci		}
59888c2ecf20Sopenharmony_ci		break;
59898c2ecf20Sopenharmony_ci	default:
59908c2ecf20Sopenharmony_ci		goto empty_set;
59918c2ecf20Sopenharmony_ci	}
59928c2ecf20Sopenharmony_ci
59938c2ecf20Sopenharmony_ci	bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS);
59948c2ecf20Sopenharmony_ci	bitmap_and(state->advertising, state->advertising, mask,
59958c2ecf20Sopenharmony_ci		   __ETHTOOL_LINK_MODE_MASK_NBITS);
59968c2ecf20Sopenharmony_ci
59978c2ecf20Sopenharmony_ci	phylink_helper_basex_speed(state);
59988c2ecf20Sopenharmony_ci	return;
59998c2ecf20Sopenharmony_ci
60008c2ecf20Sopenharmony_ciempty_set:
60018c2ecf20Sopenharmony_ci	bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
60028c2ecf20Sopenharmony_ci}
60038c2ecf20Sopenharmony_ci
60048c2ecf20Sopenharmony_cistatic void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode,
60058c2ecf20Sopenharmony_ci			     const struct phylink_link_state *state)
60068c2ecf20Sopenharmony_ci{
60078c2ecf20Sopenharmony_ci	u32 val;
60088c2ecf20Sopenharmony_ci
60098c2ecf20Sopenharmony_ci	mvpp2_modify(port->base + MVPP22_XLG_CTRL0_REG,
60108c2ecf20Sopenharmony_ci		     MVPP22_XLG_CTRL0_MAC_RESET_DIS,
60118c2ecf20Sopenharmony_ci		     MVPP22_XLG_CTRL0_MAC_RESET_DIS);
60128c2ecf20Sopenharmony_ci	mvpp2_modify(port->base + MVPP22_XLG_CTRL4_REG,
60138c2ecf20Sopenharmony_ci		     MVPP22_XLG_CTRL4_MACMODSELECT_GMAC |
60148c2ecf20Sopenharmony_ci		     MVPP22_XLG_CTRL4_EN_IDLE_CHECK |
60158c2ecf20Sopenharmony_ci		     MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC,
60168c2ecf20Sopenharmony_ci		     MVPP22_XLG_CTRL4_FWD_FC | MVPP22_XLG_CTRL4_FWD_PFC);
60178c2ecf20Sopenharmony_ci
60188c2ecf20Sopenharmony_ci	/* Wait for reset to deassert */
60198c2ecf20Sopenharmony_ci	do {
60208c2ecf20Sopenharmony_ci		val = readl(port->base + MVPP22_XLG_CTRL0_REG);
60218c2ecf20Sopenharmony_ci	} while (!(val & MVPP22_XLG_CTRL0_MAC_RESET_DIS));
60228c2ecf20Sopenharmony_ci}
60238c2ecf20Sopenharmony_ci
60248c2ecf20Sopenharmony_cistatic void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
60258c2ecf20Sopenharmony_ci			      const struct phylink_link_state *state)
60268c2ecf20Sopenharmony_ci{
60278c2ecf20Sopenharmony_ci	u32 old_ctrl0, ctrl0;
60288c2ecf20Sopenharmony_ci	u32 old_ctrl2, ctrl2;
60298c2ecf20Sopenharmony_ci	u32 old_ctrl4, ctrl4;
60308c2ecf20Sopenharmony_ci
60318c2ecf20Sopenharmony_ci	old_ctrl0 = ctrl0 = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
60328c2ecf20Sopenharmony_ci	old_ctrl2 = ctrl2 = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
60338c2ecf20Sopenharmony_ci	old_ctrl4 = ctrl4 = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
60348c2ecf20Sopenharmony_ci
60358c2ecf20Sopenharmony_ci	ctrl0 &= ~MVPP2_GMAC_PORT_TYPE_MASK;
60368c2ecf20Sopenharmony_ci	ctrl2 &= ~(MVPP2_GMAC_INBAND_AN_MASK | MVPP2_GMAC_PCS_ENABLE_MASK);
60378c2ecf20Sopenharmony_ci
60388c2ecf20Sopenharmony_ci	/* Configure port type */
60398c2ecf20Sopenharmony_ci	if (phy_interface_mode_is_8023z(state->interface)) {
60408c2ecf20Sopenharmony_ci		ctrl2 |= MVPP2_GMAC_PCS_ENABLE_MASK;
60418c2ecf20Sopenharmony_ci		ctrl4 &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
60428c2ecf20Sopenharmony_ci		ctrl4 |= MVPP22_CTRL4_SYNC_BYPASS_DIS |
60438c2ecf20Sopenharmony_ci			 MVPP22_CTRL4_DP_CLK_SEL |
60448c2ecf20Sopenharmony_ci			 MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
60458c2ecf20Sopenharmony_ci	} else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
60468c2ecf20Sopenharmony_ci		ctrl2 |= MVPP2_GMAC_PCS_ENABLE_MASK | MVPP2_GMAC_INBAND_AN_MASK;
60478c2ecf20Sopenharmony_ci		ctrl4 &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
60488c2ecf20Sopenharmony_ci		ctrl4 |= MVPP22_CTRL4_SYNC_BYPASS_DIS |
60498c2ecf20Sopenharmony_ci			 MVPP22_CTRL4_DP_CLK_SEL |
60508c2ecf20Sopenharmony_ci			 MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
60518c2ecf20Sopenharmony_ci	} else if (phy_interface_mode_is_rgmii(state->interface)) {
60528c2ecf20Sopenharmony_ci		ctrl4 &= ~MVPP22_CTRL4_DP_CLK_SEL;
60538c2ecf20Sopenharmony_ci		ctrl4 |= MVPP22_CTRL4_EXT_PIN_GMII_SEL |
60548c2ecf20Sopenharmony_ci			 MVPP22_CTRL4_SYNC_BYPASS_DIS |
60558c2ecf20Sopenharmony_ci			 MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
60568c2ecf20Sopenharmony_ci	}
60578c2ecf20Sopenharmony_ci
60588c2ecf20Sopenharmony_ci	/* Configure negotiation style */
60598c2ecf20Sopenharmony_ci	if (!phylink_autoneg_inband(mode)) {
60608c2ecf20Sopenharmony_ci		/* Phy or fixed speed - no in-band AN, nothing to do, leave the
60618c2ecf20Sopenharmony_ci		 * configured speed, duplex and flow control as-is.
60628c2ecf20Sopenharmony_ci		 */
60638c2ecf20Sopenharmony_ci	} else if (state->interface == PHY_INTERFACE_MODE_SGMII) {
60648c2ecf20Sopenharmony_ci		/* SGMII in-band mode receives the speed and duplex from
60658c2ecf20Sopenharmony_ci		 * the PHY. Flow control information is not received. */
60668c2ecf20Sopenharmony_ci	} else if (phy_interface_mode_is_8023z(state->interface)) {
60678c2ecf20Sopenharmony_ci		/* 1000BaseX and 2500BaseX ports cannot negotiate speed nor can
60688c2ecf20Sopenharmony_ci		 * they negotiate duplex: they are always operating with a fixed
60698c2ecf20Sopenharmony_ci		 * speed of 1000/2500Mbps in full duplex, so force 1000/2500
60708c2ecf20Sopenharmony_ci		 * speed and full duplex here.
60718c2ecf20Sopenharmony_ci		 */
60728c2ecf20Sopenharmony_ci		ctrl0 |= MVPP2_GMAC_PORT_TYPE_MASK;
60738c2ecf20Sopenharmony_ci	}
60748c2ecf20Sopenharmony_ci
60758c2ecf20Sopenharmony_ci	if (old_ctrl0 != ctrl0)
60768c2ecf20Sopenharmony_ci		writel(ctrl0, port->base + MVPP2_GMAC_CTRL_0_REG);
60778c2ecf20Sopenharmony_ci	if (old_ctrl2 != ctrl2)
60788c2ecf20Sopenharmony_ci		writel(ctrl2, port->base + MVPP2_GMAC_CTRL_2_REG);
60798c2ecf20Sopenharmony_ci	if (old_ctrl4 != ctrl4)
60808c2ecf20Sopenharmony_ci		writel(ctrl4, port->base + MVPP22_GMAC_CTRL_4_REG);
60818c2ecf20Sopenharmony_ci}
60828c2ecf20Sopenharmony_ci
60838c2ecf20Sopenharmony_cistatic int mvpp2__mac_prepare(struct phylink_config *config, unsigned int mode,
60848c2ecf20Sopenharmony_ci			      phy_interface_t interface)
60858c2ecf20Sopenharmony_ci{
60868c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
60878c2ecf20Sopenharmony_ci
60888c2ecf20Sopenharmony_ci	/* Check for invalid configuration */
60898c2ecf20Sopenharmony_ci	if (mvpp2_is_xlg(interface) && port->gop_id != 0) {
60908c2ecf20Sopenharmony_ci		netdev_err(port->dev, "Invalid mode on %s\n", port->dev->name);
60918c2ecf20Sopenharmony_ci		return -EINVAL;
60928c2ecf20Sopenharmony_ci	}
60938c2ecf20Sopenharmony_ci
60948c2ecf20Sopenharmony_ci	if (port->phy_interface != interface ||
60958c2ecf20Sopenharmony_ci	    phylink_autoneg_inband(mode)) {
60968c2ecf20Sopenharmony_ci		/* Force the link down when changing the interface or if in
60978c2ecf20Sopenharmony_ci		 * in-band mode to ensure we do not change the configuration
60988c2ecf20Sopenharmony_ci		 * while the hardware is indicating link is up. We force both
60998c2ecf20Sopenharmony_ci		 * XLG and GMAC down to ensure that they're both in a known
61008c2ecf20Sopenharmony_ci		 * state.
61018c2ecf20Sopenharmony_ci		 */
61028c2ecf20Sopenharmony_ci		mvpp2_modify(port->base + MVPP2_GMAC_AUTONEG_CONFIG,
61038c2ecf20Sopenharmony_ci			     MVPP2_GMAC_FORCE_LINK_PASS |
61048c2ecf20Sopenharmony_ci			     MVPP2_GMAC_FORCE_LINK_DOWN,
61058c2ecf20Sopenharmony_ci			     MVPP2_GMAC_FORCE_LINK_DOWN);
61068c2ecf20Sopenharmony_ci
61078c2ecf20Sopenharmony_ci		if (mvpp2_port_supports_xlg(port))
61088c2ecf20Sopenharmony_ci			mvpp2_modify(port->base + MVPP22_XLG_CTRL0_REG,
61098c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_PASS |
61108c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_DOWN,
61118c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_DOWN);
61128c2ecf20Sopenharmony_ci	}
61138c2ecf20Sopenharmony_ci
61148c2ecf20Sopenharmony_ci	/* Make sure the port is disabled when reconfiguring the mode */
61158c2ecf20Sopenharmony_ci	mvpp2_port_disable(port);
61168c2ecf20Sopenharmony_ci
61178c2ecf20Sopenharmony_ci	if (port->phy_interface != interface) {
61188c2ecf20Sopenharmony_ci		/* Place GMAC into reset */
61198c2ecf20Sopenharmony_ci		mvpp2_modify(port->base + MVPP2_GMAC_CTRL_2_REG,
61208c2ecf20Sopenharmony_ci			     MVPP2_GMAC_PORT_RESET_MASK,
61218c2ecf20Sopenharmony_ci			     MVPP2_GMAC_PORT_RESET_MASK);
61228c2ecf20Sopenharmony_ci
61238c2ecf20Sopenharmony_ci		if (port->priv->hw_version == MVPP22) {
61248c2ecf20Sopenharmony_ci			mvpp22_gop_mask_irq(port);
61258c2ecf20Sopenharmony_ci
61268c2ecf20Sopenharmony_ci			phy_power_off(port->comphy);
61278c2ecf20Sopenharmony_ci		}
61288c2ecf20Sopenharmony_ci	}
61298c2ecf20Sopenharmony_ci
61308c2ecf20Sopenharmony_ci	/* Select the appropriate PCS operations depending on the
61318c2ecf20Sopenharmony_ci	 * configured interface mode. We will only switch to a mode
61328c2ecf20Sopenharmony_ci	 * that the validate() checks have already passed.
61338c2ecf20Sopenharmony_ci	 */
61348c2ecf20Sopenharmony_ci	if (mvpp2_is_xlg(interface))
61358c2ecf20Sopenharmony_ci		port->phylink_pcs.ops = &mvpp2_phylink_xlg_pcs_ops;
61368c2ecf20Sopenharmony_ci	else
61378c2ecf20Sopenharmony_ci		port->phylink_pcs.ops = &mvpp2_phylink_gmac_pcs_ops;
61388c2ecf20Sopenharmony_ci
61398c2ecf20Sopenharmony_ci	return 0;
61408c2ecf20Sopenharmony_ci}
61418c2ecf20Sopenharmony_ci
61428c2ecf20Sopenharmony_cistatic int mvpp2_mac_prepare(struct phylink_config *config, unsigned int mode,
61438c2ecf20Sopenharmony_ci			     phy_interface_t interface)
61448c2ecf20Sopenharmony_ci{
61458c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
61468c2ecf20Sopenharmony_ci	int ret;
61478c2ecf20Sopenharmony_ci
61488c2ecf20Sopenharmony_ci	ret = mvpp2__mac_prepare(config, mode, interface);
61498c2ecf20Sopenharmony_ci	if (ret == 0)
61508c2ecf20Sopenharmony_ci		phylink_set_pcs(port->phylink, &port->phylink_pcs);
61518c2ecf20Sopenharmony_ci
61528c2ecf20Sopenharmony_ci	return ret;
61538c2ecf20Sopenharmony_ci}
61548c2ecf20Sopenharmony_ci
61558c2ecf20Sopenharmony_cistatic void mvpp2_mac_config(struct phylink_config *config, unsigned int mode,
61568c2ecf20Sopenharmony_ci			     const struct phylink_link_state *state)
61578c2ecf20Sopenharmony_ci{
61588c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
61598c2ecf20Sopenharmony_ci
61608c2ecf20Sopenharmony_ci	/* mac (re)configuration */
61618c2ecf20Sopenharmony_ci	if (mvpp2_is_xlg(state->interface))
61628c2ecf20Sopenharmony_ci		mvpp2_xlg_config(port, mode, state);
61638c2ecf20Sopenharmony_ci	else if (phy_interface_mode_is_rgmii(state->interface) ||
61648c2ecf20Sopenharmony_ci		 phy_interface_mode_is_8023z(state->interface) ||
61658c2ecf20Sopenharmony_ci		 state->interface == PHY_INTERFACE_MODE_SGMII)
61668c2ecf20Sopenharmony_ci		mvpp2_gmac_config(port, mode, state);
61678c2ecf20Sopenharmony_ci
61688c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP21 && port->flags & MVPP2_F_LOOPBACK)
61698c2ecf20Sopenharmony_ci		mvpp2_port_loopback_set(port, state);
61708c2ecf20Sopenharmony_ci}
61718c2ecf20Sopenharmony_ci
61728c2ecf20Sopenharmony_cistatic int mvpp2_mac_finish(struct phylink_config *config, unsigned int mode,
61738c2ecf20Sopenharmony_ci			    phy_interface_t interface)
61748c2ecf20Sopenharmony_ci{
61758c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
61768c2ecf20Sopenharmony_ci
61778c2ecf20Sopenharmony_ci	if (port->priv->hw_version == MVPP22 &&
61788c2ecf20Sopenharmony_ci	    port->phy_interface != interface) {
61798c2ecf20Sopenharmony_ci		port->phy_interface = interface;
61808c2ecf20Sopenharmony_ci
61818c2ecf20Sopenharmony_ci		/* Reconfigure the serdes lanes */
61828c2ecf20Sopenharmony_ci		mvpp22_mode_reconfigure(port);
61838c2ecf20Sopenharmony_ci
61848c2ecf20Sopenharmony_ci		/* Unmask interrupts */
61858c2ecf20Sopenharmony_ci		mvpp22_gop_unmask_irq(port);
61868c2ecf20Sopenharmony_ci	}
61878c2ecf20Sopenharmony_ci
61888c2ecf20Sopenharmony_ci	if (!mvpp2_is_xlg(interface)) {
61898c2ecf20Sopenharmony_ci		/* Release GMAC reset and wait */
61908c2ecf20Sopenharmony_ci		mvpp2_modify(port->base + MVPP2_GMAC_CTRL_2_REG,
61918c2ecf20Sopenharmony_ci			     MVPP2_GMAC_PORT_RESET_MASK, 0);
61928c2ecf20Sopenharmony_ci
61938c2ecf20Sopenharmony_ci		while (readl(port->base + MVPP2_GMAC_CTRL_2_REG) &
61948c2ecf20Sopenharmony_ci		       MVPP2_GMAC_PORT_RESET_MASK)
61958c2ecf20Sopenharmony_ci			continue;
61968c2ecf20Sopenharmony_ci	}
61978c2ecf20Sopenharmony_ci
61988c2ecf20Sopenharmony_ci	mvpp2_port_enable(port);
61998c2ecf20Sopenharmony_ci
62008c2ecf20Sopenharmony_ci	/* Allow the link to come up if in in-band mode, otherwise the
62018c2ecf20Sopenharmony_ci	 * link is forced via mac_link_down()/mac_link_up()
62028c2ecf20Sopenharmony_ci	 */
62038c2ecf20Sopenharmony_ci	if (phylink_autoneg_inband(mode)) {
62048c2ecf20Sopenharmony_ci		if (mvpp2_is_xlg(interface))
62058c2ecf20Sopenharmony_ci			mvpp2_modify(port->base + MVPP22_XLG_CTRL0_REG,
62068c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_PASS |
62078c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_DOWN, 0);
62088c2ecf20Sopenharmony_ci		else
62098c2ecf20Sopenharmony_ci			mvpp2_modify(port->base + MVPP2_GMAC_AUTONEG_CONFIG,
62108c2ecf20Sopenharmony_ci				     MVPP2_GMAC_FORCE_LINK_PASS |
62118c2ecf20Sopenharmony_ci				     MVPP2_GMAC_FORCE_LINK_DOWN, 0);
62128c2ecf20Sopenharmony_ci	}
62138c2ecf20Sopenharmony_ci
62148c2ecf20Sopenharmony_ci	return 0;
62158c2ecf20Sopenharmony_ci}
62168c2ecf20Sopenharmony_ci
62178c2ecf20Sopenharmony_cistatic void mvpp2_mac_link_up(struct phylink_config *config,
62188c2ecf20Sopenharmony_ci			      struct phy_device *phy,
62198c2ecf20Sopenharmony_ci			      unsigned int mode, phy_interface_t interface,
62208c2ecf20Sopenharmony_ci			      int speed, int duplex,
62218c2ecf20Sopenharmony_ci			      bool tx_pause, bool rx_pause)
62228c2ecf20Sopenharmony_ci{
62238c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
62248c2ecf20Sopenharmony_ci	u32 val;
62258c2ecf20Sopenharmony_ci
62268c2ecf20Sopenharmony_ci	if (mvpp2_is_xlg(interface)) {
62278c2ecf20Sopenharmony_ci		if (!phylink_autoneg_inband(mode)) {
62288c2ecf20Sopenharmony_ci			val = MVPP22_XLG_CTRL0_FORCE_LINK_PASS;
62298c2ecf20Sopenharmony_ci			if (tx_pause)
62308c2ecf20Sopenharmony_ci				val |= MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN;
62318c2ecf20Sopenharmony_ci			if (rx_pause)
62328c2ecf20Sopenharmony_ci				val |= MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN;
62338c2ecf20Sopenharmony_ci
62348c2ecf20Sopenharmony_ci			mvpp2_modify(port->base + MVPP22_XLG_CTRL0_REG,
62358c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_DOWN |
62368c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_FORCE_LINK_PASS |
62378c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_TX_FLOW_CTRL_EN |
62388c2ecf20Sopenharmony_ci				     MVPP22_XLG_CTRL0_RX_FLOW_CTRL_EN, val);
62398c2ecf20Sopenharmony_ci		}
62408c2ecf20Sopenharmony_ci	} else {
62418c2ecf20Sopenharmony_ci		if (!phylink_autoneg_inband(mode)) {
62428c2ecf20Sopenharmony_ci			val = MVPP2_GMAC_FORCE_LINK_PASS;
62438c2ecf20Sopenharmony_ci
62448c2ecf20Sopenharmony_ci			if (speed == SPEED_1000 || speed == SPEED_2500)
62458c2ecf20Sopenharmony_ci				val |= MVPP2_GMAC_CONFIG_GMII_SPEED;
62468c2ecf20Sopenharmony_ci			else if (speed == SPEED_100)
62478c2ecf20Sopenharmony_ci				val |= MVPP2_GMAC_CONFIG_MII_SPEED;
62488c2ecf20Sopenharmony_ci
62498c2ecf20Sopenharmony_ci			if (duplex == DUPLEX_FULL)
62508c2ecf20Sopenharmony_ci				val |= MVPP2_GMAC_CONFIG_FULL_DUPLEX;
62518c2ecf20Sopenharmony_ci
62528c2ecf20Sopenharmony_ci			mvpp2_modify(port->base + MVPP2_GMAC_AUTONEG_CONFIG,
62538c2ecf20Sopenharmony_ci				     MVPP2_GMAC_FORCE_LINK_DOWN |
62548c2ecf20Sopenharmony_ci				     MVPP2_GMAC_FORCE_LINK_PASS |
62558c2ecf20Sopenharmony_ci				     MVPP2_GMAC_CONFIG_MII_SPEED |
62568c2ecf20Sopenharmony_ci				     MVPP2_GMAC_CONFIG_GMII_SPEED |
62578c2ecf20Sopenharmony_ci				     MVPP2_GMAC_CONFIG_FULL_DUPLEX, val);
62588c2ecf20Sopenharmony_ci		}
62598c2ecf20Sopenharmony_ci
62608c2ecf20Sopenharmony_ci		/* We can always update the flow control enable bits;
62618c2ecf20Sopenharmony_ci		 * these will only be effective if flow control AN
62628c2ecf20Sopenharmony_ci		 * (MVPP2_GMAC_FLOW_CTRL_AUTONEG) is disabled.
62638c2ecf20Sopenharmony_ci		 */
62648c2ecf20Sopenharmony_ci		val = 0;
62658c2ecf20Sopenharmony_ci		if (tx_pause)
62668c2ecf20Sopenharmony_ci			val |= MVPP22_CTRL4_TX_FC_EN;
62678c2ecf20Sopenharmony_ci		if (rx_pause)
62688c2ecf20Sopenharmony_ci			val |= MVPP22_CTRL4_RX_FC_EN;
62698c2ecf20Sopenharmony_ci
62708c2ecf20Sopenharmony_ci		mvpp2_modify(port->base + MVPP22_GMAC_CTRL_4_REG,
62718c2ecf20Sopenharmony_ci			     MVPP22_CTRL4_RX_FC_EN | MVPP22_CTRL4_TX_FC_EN,
62728c2ecf20Sopenharmony_ci			     val);
62738c2ecf20Sopenharmony_ci	}
62748c2ecf20Sopenharmony_ci
62758c2ecf20Sopenharmony_ci	mvpp2_port_enable(port);
62768c2ecf20Sopenharmony_ci
62778c2ecf20Sopenharmony_ci	mvpp2_egress_enable(port);
62788c2ecf20Sopenharmony_ci	mvpp2_ingress_enable(port);
62798c2ecf20Sopenharmony_ci	netif_tx_wake_all_queues(port->dev);
62808c2ecf20Sopenharmony_ci}
62818c2ecf20Sopenharmony_ci
62828c2ecf20Sopenharmony_cistatic void mvpp2_mac_link_down(struct phylink_config *config,
62838c2ecf20Sopenharmony_ci				unsigned int mode, phy_interface_t interface)
62848c2ecf20Sopenharmony_ci{
62858c2ecf20Sopenharmony_ci	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
62868c2ecf20Sopenharmony_ci	u32 val;
62878c2ecf20Sopenharmony_ci
62888c2ecf20Sopenharmony_ci	if (!phylink_autoneg_inband(mode)) {
62898c2ecf20Sopenharmony_ci		if (mvpp2_is_xlg(interface)) {
62908c2ecf20Sopenharmony_ci			val = readl(port->base + MVPP22_XLG_CTRL0_REG);
62918c2ecf20Sopenharmony_ci			val &= ~MVPP22_XLG_CTRL0_FORCE_LINK_PASS;
62928c2ecf20Sopenharmony_ci			val |= MVPP22_XLG_CTRL0_FORCE_LINK_DOWN;
62938c2ecf20Sopenharmony_ci			writel(val, port->base + MVPP22_XLG_CTRL0_REG);
62948c2ecf20Sopenharmony_ci		} else {
62958c2ecf20Sopenharmony_ci			val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
62968c2ecf20Sopenharmony_ci			val &= ~MVPP2_GMAC_FORCE_LINK_PASS;
62978c2ecf20Sopenharmony_ci			val |= MVPP2_GMAC_FORCE_LINK_DOWN;
62988c2ecf20Sopenharmony_ci			writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
62998c2ecf20Sopenharmony_ci		}
63008c2ecf20Sopenharmony_ci	}
63018c2ecf20Sopenharmony_ci
63028c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(port->dev);
63038c2ecf20Sopenharmony_ci	mvpp2_egress_disable(port);
63048c2ecf20Sopenharmony_ci	mvpp2_ingress_disable(port);
63058c2ecf20Sopenharmony_ci
63068c2ecf20Sopenharmony_ci	mvpp2_port_disable(port);
63078c2ecf20Sopenharmony_ci}
63088c2ecf20Sopenharmony_ci
63098c2ecf20Sopenharmony_cistatic const struct phylink_mac_ops mvpp2_phylink_ops = {
63108c2ecf20Sopenharmony_ci	.validate = mvpp2_phylink_validate,
63118c2ecf20Sopenharmony_ci	.mac_prepare = mvpp2_mac_prepare,
63128c2ecf20Sopenharmony_ci	.mac_config = mvpp2_mac_config,
63138c2ecf20Sopenharmony_ci	.mac_finish = mvpp2_mac_finish,
63148c2ecf20Sopenharmony_ci	.mac_link_up = mvpp2_mac_link_up,
63158c2ecf20Sopenharmony_ci	.mac_link_down = mvpp2_mac_link_down,
63168c2ecf20Sopenharmony_ci};
63178c2ecf20Sopenharmony_ci
63188c2ecf20Sopenharmony_ci/* Work-around for ACPI */
63198c2ecf20Sopenharmony_cistatic void mvpp2_acpi_start(struct mvpp2_port *port)
63208c2ecf20Sopenharmony_ci{
63218c2ecf20Sopenharmony_ci	/* Phylink isn't used as of now for ACPI, so the MAC has to be
63228c2ecf20Sopenharmony_ci	 * configured manually when the interface is started. This will
63238c2ecf20Sopenharmony_ci	 * be removed as soon as the phylink ACPI support lands in.
63248c2ecf20Sopenharmony_ci	 */
63258c2ecf20Sopenharmony_ci	struct phylink_link_state state = {
63268c2ecf20Sopenharmony_ci		.interface = port->phy_interface,
63278c2ecf20Sopenharmony_ci	};
63288c2ecf20Sopenharmony_ci	mvpp2__mac_prepare(&port->phylink_config, MLO_AN_INBAND,
63298c2ecf20Sopenharmony_ci			   port->phy_interface);
63308c2ecf20Sopenharmony_ci	mvpp2_mac_config(&port->phylink_config, MLO_AN_INBAND, &state);
63318c2ecf20Sopenharmony_ci	port->phylink_pcs.ops->pcs_config(&port->phylink_pcs, MLO_AN_INBAND,
63328c2ecf20Sopenharmony_ci					  port->phy_interface,
63338c2ecf20Sopenharmony_ci					  state.advertising, false);
63348c2ecf20Sopenharmony_ci	mvpp2_mac_finish(&port->phylink_config, MLO_AN_INBAND,
63358c2ecf20Sopenharmony_ci			 port->phy_interface);
63368c2ecf20Sopenharmony_ci	mvpp2_mac_link_up(&port->phylink_config, NULL,
63378c2ecf20Sopenharmony_ci			  MLO_AN_INBAND, port->phy_interface,
63388c2ecf20Sopenharmony_ci			  SPEED_UNKNOWN, DUPLEX_UNKNOWN, false, false);
63398c2ecf20Sopenharmony_ci}
63408c2ecf20Sopenharmony_ci
63418c2ecf20Sopenharmony_ci/* Ports initialization */
63428c2ecf20Sopenharmony_cistatic int mvpp2_port_probe(struct platform_device *pdev,
63438c2ecf20Sopenharmony_ci			    struct fwnode_handle *port_fwnode,
63448c2ecf20Sopenharmony_ci			    struct mvpp2 *priv)
63458c2ecf20Sopenharmony_ci{
63468c2ecf20Sopenharmony_ci	struct phy *comphy = NULL;
63478c2ecf20Sopenharmony_ci	struct mvpp2_port *port;
63488c2ecf20Sopenharmony_ci	struct mvpp2_port_pcpu *port_pcpu;
63498c2ecf20Sopenharmony_ci	struct device_node *port_node = to_of_node(port_fwnode);
63508c2ecf20Sopenharmony_ci	netdev_features_t features;
63518c2ecf20Sopenharmony_ci	struct net_device *dev;
63528c2ecf20Sopenharmony_ci	struct phylink *phylink;
63538c2ecf20Sopenharmony_ci	char *mac_from = "";
63548c2ecf20Sopenharmony_ci	unsigned int ntxqs, nrxqs, thread;
63558c2ecf20Sopenharmony_ci	unsigned long flags = 0;
63568c2ecf20Sopenharmony_ci	bool has_tx_irqs;
63578c2ecf20Sopenharmony_ci	u32 id;
63588c2ecf20Sopenharmony_ci	int phy_mode;
63598c2ecf20Sopenharmony_ci	int err, i;
63608c2ecf20Sopenharmony_ci
63618c2ecf20Sopenharmony_ci	has_tx_irqs = mvpp2_port_has_irqs(priv, port_node, &flags);
63628c2ecf20Sopenharmony_ci	if (!has_tx_irqs && queue_mode == MVPP2_QDIST_MULTI_MODE) {
63638c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
63648c2ecf20Sopenharmony_ci			"not enough IRQs to support multi queue mode\n");
63658c2ecf20Sopenharmony_ci		return -EINVAL;
63668c2ecf20Sopenharmony_ci	}
63678c2ecf20Sopenharmony_ci
63688c2ecf20Sopenharmony_ci	ntxqs = MVPP2_MAX_TXQ;
63698c2ecf20Sopenharmony_ci	nrxqs = mvpp2_get_nrxqs(priv);
63708c2ecf20Sopenharmony_ci
63718c2ecf20Sopenharmony_ci	dev = alloc_etherdev_mqs(sizeof(*port), ntxqs, nrxqs);
63728c2ecf20Sopenharmony_ci	if (!dev)
63738c2ecf20Sopenharmony_ci		return -ENOMEM;
63748c2ecf20Sopenharmony_ci
63758c2ecf20Sopenharmony_ci	phy_mode = fwnode_get_phy_mode(port_fwnode);
63768c2ecf20Sopenharmony_ci	if (phy_mode < 0) {
63778c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "incorrect phy mode\n");
63788c2ecf20Sopenharmony_ci		err = phy_mode;
63798c2ecf20Sopenharmony_ci		goto err_free_netdev;
63808c2ecf20Sopenharmony_ci	}
63818c2ecf20Sopenharmony_ci
63828c2ecf20Sopenharmony_ci	/*
63838c2ecf20Sopenharmony_ci	 * Rewrite 10GBASE-KR to 10GBASE-R for compatibility with existing DT.
63848c2ecf20Sopenharmony_ci	 * Existing usage of 10GBASE-KR is not correct; no backplane
63858c2ecf20Sopenharmony_ci	 * negotiation is done, and this driver does not actually support
63868c2ecf20Sopenharmony_ci	 * 10GBASE-KR.
63878c2ecf20Sopenharmony_ci	 */
63888c2ecf20Sopenharmony_ci	if (phy_mode == PHY_INTERFACE_MODE_10GKR)
63898c2ecf20Sopenharmony_ci		phy_mode = PHY_INTERFACE_MODE_10GBASER;
63908c2ecf20Sopenharmony_ci
63918c2ecf20Sopenharmony_ci	if (port_node) {
63928c2ecf20Sopenharmony_ci		comphy = devm_of_phy_get(&pdev->dev, port_node, NULL);
63938c2ecf20Sopenharmony_ci		if (IS_ERR(comphy)) {
63948c2ecf20Sopenharmony_ci			if (PTR_ERR(comphy) == -EPROBE_DEFER) {
63958c2ecf20Sopenharmony_ci				err = -EPROBE_DEFER;
63968c2ecf20Sopenharmony_ci				goto err_free_netdev;
63978c2ecf20Sopenharmony_ci			}
63988c2ecf20Sopenharmony_ci			comphy = NULL;
63998c2ecf20Sopenharmony_ci		}
64008c2ecf20Sopenharmony_ci	}
64018c2ecf20Sopenharmony_ci
64028c2ecf20Sopenharmony_ci	if (fwnode_property_read_u32(port_fwnode, "port-id", &id)) {
64038c2ecf20Sopenharmony_ci		err = -EINVAL;
64048c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing port-id value\n");
64058c2ecf20Sopenharmony_ci		goto err_free_netdev;
64068c2ecf20Sopenharmony_ci	}
64078c2ecf20Sopenharmony_ci
64088c2ecf20Sopenharmony_ci	dev->tx_queue_len = MVPP2_MAX_TXD_MAX;
64098c2ecf20Sopenharmony_ci	dev->watchdog_timeo = 5 * HZ;
64108c2ecf20Sopenharmony_ci	dev->netdev_ops = &mvpp2_netdev_ops;
64118c2ecf20Sopenharmony_ci	dev->ethtool_ops = &mvpp2_eth_tool_ops;
64128c2ecf20Sopenharmony_ci
64138c2ecf20Sopenharmony_ci	port = netdev_priv(dev);
64148c2ecf20Sopenharmony_ci	port->dev = dev;
64158c2ecf20Sopenharmony_ci	port->fwnode = port_fwnode;
64168c2ecf20Sopenharmony_ci	port->has_phy = !!of_find_property(port_node, "phy", NULL);
64178c2ecf20Sopenharmony_ci	port->ntxqs = ntxqs;
64188c2ecf20Sopenharmony_ci	port->nrxqs = nrxqs;
64198c2ecf20Sopenharmony_ci	port->priv = priv;
64208c2ecf20Sopenharmony_ci	port->has_tx_irqs = has_tx_irqs;
64218c2ecf20Sopenharmony_ci	port->flags = flags;
64228c2ecf20Sopenharmony_ci
64238c2ecf20Sopenharmony_ci	err = mvpp2_queue_vectors_init(port, port_node);
64248c2ecf20Sopenharmony_ci	if (err)
64258c2ecf20Sopenharmony_ci		goto err_free_netdev;
64268c2ecf20Sopenharmony_ci
64278c2ecf20Sopenharmony_ci	if (port_node)
64288c2ecf20Sopenharmony_ci		port->port_irq = of_irq_get_byname(port_node, "link");
64298c2ecf20Sopenharmony_ci	else
64308c2ecf20Sopenharmony_ci		port->port_irq = fwnode_irq_get(port_fwnode, port->nqvecs + 1);
64318c2ecf20Sopenharmony_ci	if (port->port_irq == -EPROBE_DEFER) {
64328c2ecf20Sopenharmony_ci		err = -EPROBE_DEFER;
64338c2ecf20Sopenharmony_ci		goto err_deinit_qvecs;
64348c2ecf20Sopenharmony_ci	}
64358c2ecf20Sopenharmony_ci	if (port->port_irq <= 0)
64368c2ecf20Sopenharmony_ci		/* the link irq is optional */
64378c2ecf20Sopenharmony_ci		port->port_irq = 0;
64388c2ecf20Sopenharmony_ci
64398c2ecf20Sopenharmony_ci	if (fwnode_property_read_bool(port_fwnode, "marvell,loopback"))
64408c2ecf20Sopenharmony_ci		port->flags |= MVPP2_F_LOOPBACK;
64418c2ecf20Sopenharmony_ci
64428c2ecf20Sopenharmony_ci	port->id = id;
64438c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
64448c2ecf20Sopenharmony_ci		port->first_rxq = port->id * port->nrxqs;
64458c2ecf20Sopenharmony_ci	else
64468c2ecf20Sopenharmony_ci		port->first_rxq = port->id * priv->max_port_rxqs;
64478c2ecf20Sopenharmony_ci
64488c2ecf20Sopenharmony_ci	port->of_node = port_node;
64498c2ecf20Sopenharmony_ci	port->phy_interface = phy_mode;
64508c2ecf20Sopenharmony_ci	port->comphy = comphy;
64518c2ecf20Sopenharmony_ci
64528c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21) {
64538c2ecf20Sopenharmony_ci		port->base = devm_platform_ioremap_resource(pdev, 2 + id);
64548c2ecf20Sopenharmony_ci		if (IS_ERR(port->base)) {
64558c2ecf20Sopenharmony_ci			err = PTR_ERR(port->base);
64568c2ecf20Sopenharmony_ci			goto err_free_irq;
64578c2ecf20Sopenharmony_ci		}
64588c2ecf20Sopenharmony_ci
64598c2ecf20Sopenharmony_ci		port->stats_base = port->priv->lms_base +
64608c2ecf20Sopenharmony_ci				   MVPP21_MIB_COUNTERS_OFFSET +
64618c2ecf20Sopenharmony_ci				   port->gop_id * MVPP21_MIB_COUNTERS_PORT_SZ;
64628c2ecf20Sopenharmony_ci	} else {
64638c2ecf20Sopenharmony_ci		if (fwnode_property_read_u32(port_fwnode, "gop-port-id",
64648c2ecf20Sopenharmony_ci					     &port->gop_id)) {
64658c2ecf20Sopenharmony_ci			err = -EINVAL;
64668c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "missing gop-port-id value\n");
64678c2ecf20Sopenharmony_ci			goto err_deinit_qvecs;
64688c2ecf20Sopenharmony_ci		}
64698c2ecf20Sopenharmony_ci
64708c2ecf20Sopenharmony_ci		port->base = priv->iface_base + MVPP22_GMAC_BASE(port->gop_id);
64718c2ecf20Sopenharmony_ci		port->stats_base = port->priv->iface_base +
64728c2ecf20Sopenharmony_ci				   MVPP22_MIB_COUNTERS_OFFSET +
64738c2ecf20Sopenharmony_ci				   port->gop_id * MVPP22_MIB_COUNTERS_PORT_SZ;
64748c2ecf20Sopenharmony_ci
64758c2ecf20Sopenharmony_ci		/* We may want a property to describe whether we should use
64768c2ecf20Sopenharmony_ci		 * MAC hardware timestamping.
64778c2ecf20Sopenharmony_ci		 */
64788c2ecf20Sopenharmony_ci		if (priv->tai)
64798c2ecf20Sopenharmony_ci			port->hwtstamp = true;
64808c2ecf20Sopenharmony_ci	}
64818c2ecf20Sopenharmony_ci
64828c2ecf20Sopenharmony_ci	/* Alloc per-cpu and ethtool stats */
64838c2ecf20Sopenharmony_ci	port->stats = netdev_alloc_pcpu_stats(struct mvpp2_pcpu_stats);
64848c2ecf20Sopenharmony_ci	if (!port->stats) {
64858c2ecf20Sopenharmony_ci		err = -ENOMEM;
64868c2ecf20Sopenharmony_ci		goto err_free_irq;
64878c2ecf20Sopenharmony_ci	}
64888c2ecf20Sopenharmony_ci
64898c2ecf20Sopenharmony_ci	port->ethtool_stats = devm_kcalloc(&pdev->dev,
64908c2ecf20Sopenharmony_ci					   MVPP2_N_ETHTOOL_STATS(ntxqs, nrxqs),
64918c2ecf20Sopenharmony_ci					   sizeof(u64), GFP_KERNEL);
64928c2ecf20Sopenharmony_ci	if (!port->ethtool_stats) {
64938c2ecf20Sopenharmony_ci		err = -ENOMEM;
64948c2ecf20Sopenharmony_ci		goto err_free_stats;
64958c2ecf20Sopenharmony_ci	}
64968c2ecf20Sopenharmony_ci
64978c2ecf20Sopenharmony_ci	mutex_init(&port->gather_stats_lock);
64988c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&port->stats_work, mvpp2_gather_hw_statistics);
64998c2ecf20Sopenharmony_ci
65008c2ecf20Sopenharmony_ci	mvpp2_port_copy_mac_addr(dev, priv, port_fwnode, &mac_from);
65018c2ecf20Sopenharmony_ci
65028c2ecf20Sopenharmony_ci	port->tx_ring_size = MVPP2_MAX_TXD_DFLT;
65038c2ecf20Sopenharmony_ci	port->rx_ring_size = MVPP2_MAX_RXD_DFLT;
65048c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
65058c2ecf20Sopenharmony_ci
65068c2ecf20Sopenharmony_ci	err = mvpp2_port_init(port);
65078c2ecf20Sopenharmony_ci	if (err < 0) {
65088c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to init port %d\n", id);
65098c2ecf20Sopenharmony_ci		goto err_free_stats;
65108c2ecf20Sopenharmony_ci	}
65118c2ecf20Sopenharmony_ci
65128c2ecf20Sopenharmony_ci	mvpp2_port_periodic_xon_disable(port);
65138c2ecf20Sopenharmony_ci
65148c2ecf20Sopenharmony_ci	mvpp2_mac_reset_assert(port);
65158c2ecf20Sopenharmony_ci	mvpp22_pcs_reset_assert(port);
65168c2ecf20Sopenharmony_ci
65178c2ecf20Sopenharmony_ci	port->pcpu = alloc_percpu(struct mvpp2_port_pcpu);
65188c2ecf20Sopenharmony_ci	if (!port->pcpu) {
65198c2ecf20Sopenharmony_ci		err = -ENOMEM;
65208c2ecf20Sopenharmony_ci		goto err_free_txq_pcpu;
65218c2ecf20Sopenharmony_ci	}
65228c2ecf20Sopenharmony_ci
65238c2ecf20Sopenharmony_ci	if (!port->has_tx_irqs) {
65248c2ecf20Sopenharmony_ci		for (thread = 0; thread < priv->nthreads; thread++) {
65258c2ecf20Sopenharmony_ci			port_pcpu = per_cpu_ptr(port->pcpu, thread);
65268c2ecf20Sopenharmony_ci
65278c2ecf20Sopenharmony_ci			hrtimer_init(&port_pcpu->tx_done_timer, CLOCK_MONOTONIC,
65288c2ecf20Sopenharmony_ci				     HRTIMER_MODE_REL_PINNED_SOFT);
65298c2ecf20Sopenharmony_ci			port_pcpu->tx_done_timer.function = mvpp2_hr_timer_cb;
65308c2ecf20Sopenharmony_ci			port_pcpu->timer_scheduled = false;
65318c2ecf20Sopenharmony_ci			port_pcpu->dev = dev;
65328c2ecf20Sopenharmony_ci		}
65338c2ecf20Sopenharmony_ci	}
65348c2ecf20Sopenharmony_ci
65358c2ecf20Sopenharmony_ci	features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
65368c2ecf20Sopenharmony_ci		   NETIF_F_TSO;
65378c2ecf20Sopenharmony_ci	dev->features = features | NETIF_F_RXCSUM;
65388c2ecf20Sopenharmony_ci	dev->hw_features |= features | NETIF_F_RXCSUM | NETIF_F_GRO |
65398c2ecf20Sopenharmony_ci			    NETIF_F_HW_VLAN_CTAG_FILTER;
65408c2ecf20Sopenharmony_ci
65418c2ecf20Sopenharmony_ci	if (mvpp22_rss_is_supported()) {
65428c2ecf20Sopenharmony_ci		dev->hw_features |= NETIF_F_RXHASH;
65438c2ecf20Sopenharmony_ci		dev->features |= NETIF_F_NTUPLE;
65448c2ecf20Sopenharmony_ci	}
65458c2ecf20Sopenharmony_ci
65468c2ecf20Sopenharmony_ci	if (!port->priv->percpu_pools)
65478c2ecf20Sopenharmony_ci		mvpp2_set_hw_csum(port, port->pool_long->id);
65488c2ecf20Sopenharmony_ci
65498c2ecf20Sopenharmony_ci	dev->vlan_features |= features;
65508c2ecf20Sopenharmony_ci	dev->gso_max_segs = MVPP2_MAX_TSO_SEGS;
65518c2ecf20Sopenharmony_ci	dev->priv_flags |= IFF_UNICAST_FLT;
65528c2ecf20Sopenharmony_ci
65538c2ecf20Sopenharmony_ci	/* MTU range: 68 - 9704 */
65548c2ecf20Sopenharmony_ci	dev->min_mtu = ETH_MIN_MTU;
65558c2ecf20Sopenharmony_ci	/* 9704 == 9728 - 20 and rounding to 8 */
65568c2ecf20Sopenharmony_ci	dev->max_mtu = MVPP2_BM_JUMBO_PKT_SIZE;
65578c2ecf20Sopenharmony_ci	dev->dev.of_node = port_node;
65588c2ecf20Sopenharmony_ci
65598c2ecf20Sopenharmony_ci	/* Phylink isn't used w/ ACPI as of now */
65608c2ecf20Sopenharmony_ci	if (port_node) {
65618c2ecf20Sopenharmony_ci		port->phylink_config.dev = &dev->dev;
65628c2ecf20Sopenharmony_ci		port->phylink_config.type = PHYLINK_NETDEV;
65638c2ecf20Sopenharmony_ci
65648c2ecf20Sopenharmony_ci		phylink = phylink_create(&port->phylink_config, port_fwnode,
65658c2ecf20Sopenharmony_ci					 phy_mode, &mvpp2_phylink_ops);
65668c2ecf20Sopenharmony_ci		if (IS_ERR(phylink)) {
65678c2ecf20Sopenharmony_ci			err = PTR_ERR(phylink);
65688c2ecf20Sopenharmony_ci			goto err_free_port_pcpu;
65698c2ecf20Sopenharmony_ci		}
65708c2ecf20Sopenharmony_ci		port->phylink = phylink;
65718c2ecf20Sopenharmony_ci	} else {
65728c2ecf20Sopenharmony_ci		port->phylink = NULL;
65738c2ecf20Sopenharmony_ci	}
65748c2ecf20Sopenharmony_ci
65758c2ecf20Sopenharmony_ci	/* Cycle the comphy to power it down, saving 270mW per port -
65768c2ecf20Sopenharmony_ci	 * don't worry about an error powering it up. When the comphy
65778c2ecf20Sopenharmony_ci	 * driver does this, we can remove this code.
65788c2ecf20Sopenharmony_ci	 */
65798c2ecf20Sopenharmony_ci	if (port->comphy) {
65808c2ecf20Sopenharmony_ci		err = mvpp22_comphy_init(port);
65818c2ecf20Sopenharmony_ci		if (err == 0)
65828c2ecf20Sopenharmony_ci			phy_power_off(port->comphy);
65838c2ecf20Sopenharmony_ci	}
65848c2ecf20Sopenharmony_ci
65858c2ecf20Sopenharmony_ci	err = register_netdev(dev);
65868c2ecf20Sopenharmony_ci	if (err < 0) {
65878c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to register netdev\n");
65888c2ecf20Sopenharmony_ci		goto err_phylink;
65898c2ecf20Sopenharmony_ci	}
65908c2ecf20Sopenharmony_ci	netdev_info(dev, "Using %s mac address %pM\n", mac_from, dev->dev_addr);
65918c2ecf20Sopenharmony_ci
65928c2ecf20Sopenharmony_ci	priv->port_list[priv->port_count++] = port;
65938c2ecf20Sopenharmony_ci
65948c2ecf20Sopenharmony_ci	return 0;
65958c2ecf20Sopenharmony_ci
65968c2ecf20Sopenharmony_cierr_phylink:
65978c2ecf20Sopenharmony_ci	if (port->phylink)
65988c2ecf20Sopenharmony_ci		phylink_destroy(port->phylink);
65998c2ecf20Sopenharmony_cierr_free_port_pcpu:
66008c2ecf20Sopenharmony_ci	free_percpu(port->pcpu);
66018c2ecf20Sopenharmony_cierr_free_txq_pcpu:
66028c2ecf20Sopenharmony_ci	for (i = 0; i < port->ntxqs; i++)
66038c2ecf20Sopenharmony_ci		free_percpu(port->txqs[i]->pcpu);
66048c2ecf20Sopenharmony_cierr_free_stats:
66058c2ecf20Sopenharmony_ci	free_percpu(port->stats);
66068c2ecf20Sopenharmony_cierr_free_irq:
66078c2ecf20Sopenharmony_ci	if (port->port_irq)
66088c2ecf20Sopenharmony_ci		irq_dispose_mapping(port->port_irq);
66098c2ecf20Sopenharmony_cierr_deinit_qvecs:
66108c2ecf20Sopenharmony_ci	mvpp2_queue_vectors_deinit(port);
66118c2ecf20Sopenharmony_cierr_free_netdev:
66128c2ecf20Sopenharmony_ci	free_netdev(dev);
66138c2ecf20Sopenharmony_ci	return err;
66148c2ecf20Sopenharmony_ci}
66158c2ecf20Sopenharmony_ci
66168c2ecf20Sopenharmony_ci/* Ports removal routine */
66178c2ecf20Sopenharmony_cistatic void mvpp2_port_remove(struct mvpp2_port *port)
66188c2ecf20Sopenharmony_ci{
66198c2ecf20Sopenharmony_ci	int i;
66208c2ecf20Sopenharmony_ci
66218c2ecf20Sopenharmony_ci	unregister_netdev(port->dev);
66228c2ecf20Sopenharmony_ci	if (port->phylink)
66238c2ecf20Sopenharmony_ci		phylink_destroy(port->phylink);
66248c2ecf20Sopenharmony_ci	free_percpu(port->pcpu);
66258c2ecf20Sopenharmony_ci	free_percpu(port->stats);
66268c2ecf20Sopenharmony_ci	for (i = 0; i < port->ntxqs; i++)
66278c2ecf20Sopenharmony_ci		free_percpu(port->txqs[i]->pcpu);
66288c2ecf20Sopenharmony_ci	mvpp2_queue_vectors_deinit(port);
66298c2ecf20Sopenharmony_ci	if (port->port_irq)
66308c2ecf20Sopenharmony_ci		irq_dispose_mapping(port->port_irq);
66318c2ecf20Sopenharmony_ci	free_netdev(port->dev);
66328c2ecf20Sopenharmony_ci}
66338c2ecf20Sopenharmony_ci
66348c2ecf20Sopenharmony_ci/* Initialize decoding windows */
66358c2ecf20Sopenharmony_cistatic void mvpp2_conf_mbus_windows(const struct mbus_dram_target_info *dram,
66368c2ecf20Sopenharmony_ci				    struct mvpp2 *priv)
66378c2ecf20Sopenharmony_ci{
66388c2ecf20Sopenharmony_ci	u32 win_enable;
66398c2ecf20Sopenharmony_ci	int i;
66408c2ecf20Sopenharmony_ci
66418c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++) {
66428c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_WIN_BASE(i), 0);
66438c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_WIN_SIZE(i), 0);
66448c2ecf20Sopenharmony_ci
66458c2ecf20Sopenharmony_ci		if (i < 4)
66468c2ecf20Sopenharmony_ci			mvpp2_write(priv, MVPP2_WIN_REMAP(i), 0);
66478c2ecf20Sopenharmony_ci	}
66488c2ecf20Sopenharmony_ci
66498c2ecf20Sopenharmony_ci	win_enable = 0;
66508c2ecf20Sopenharmony_ci
66518c2ecf20Sopenharmony_ci	for (i = 0; i < dram->num_cs; i++) {
66528c2ecf20Sopenharmony_ci		const struct mbus_dram_window *cs = dram->cs + i;
66538c2ecf20Sopenharmony_ci
66548c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_WIN_BASE(i),
66558c2ecf20Sopenharmony_ci			    (cs->base & 0xffff0000) | (cs->mbus_attr << 8) |
66568c2ecf20Sopenharmony_ci			    dram->mbus_dram_target_id);
66578c2ecf20Sopenharmony_ci
66588c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_WIN_SIZE(i),
66598c2ecf20Sopenharmony_ci			    (cs->size - 1) & 0xffff0000);
66608c2ecf20Sopenharmony_ci
66618c2ecf20Sopenharmony_ci		win_enable |= (1 << i);
66628c2ecf20Sopenharmony_ci	}
66638c2ecf20Sopenharmony_ci
66648c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_BASE_ADDR_ENABLE, win_enable);
66658c2ecf20Sopenharmony_ci}
66668c2ecf20Sopenharmony_ci
66678c2ecf20Sopenharmony_ci/* Initialize Rx FIFO's */
66688c2ecf20Sopenharmony_cistatic void mvpp2_rx_fifo_init(struct mvpp2 *priv)
66698c2ecf20Sopenharmony_ci{
66708c2ecf20Sopenharmony_ci	int port;
66718c2ecf20Sopenharmony_ci
66728c2ecf20Sopenharmony_ci	for (port = 0; port < MVPP2_MAX_PORTS; port++) {
66738c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
66748c2ecf20Sopenharmony_ci			    MVPP2_RX_FIFO_PORT_DATA_SIZE_4KB);
66758c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
66768c2ecf20Sopenharmony_ci			    MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB);
66778c2ecf20Sopenharmony_ci	}
66788c2ecf20Sopenharmony_ci
66798c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG,
66808c2ecf20Sopenharmony_ci		    MVPP2_RX_FIFO_PORT_MIN_PKT);
66818c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
66828c2ecf20Sopenharmony_ci}
66838c2ecf20Sopenharmony_ci
66848c2ecf20Sopenharmony_cistatic void mvpp22_rx_fifo_init(struct mvpp2 *priv)
66858c2ecf20Sopenharmony_ci{
66868c2ecf20Sopenharmony_ci	int port;
66878c2ecf20Sopenharmony_ci
66888c2ecf20Sopenharmony_ci	/* The FIFO size parameters are set depending on the maximum speed a
66898c2ecf20Sopenharmony_ci	 * given port can handle:
66908c2ecf20Sopenharmony_ci	 * - Port 0: 10Gbps
66918c2ecf20Sopenharmony_ci	 * - Port 1: 2.5Gbps
66928c2ecf20Sopenharmony_ci	 * - Ports 2 and 3: 1Gbps
66938c2ecf20Sopenharmony_ci	 */
66948c2ecf20Sopenharmony_ci
66958c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(0),
66968c2ecf20Sopenharmony_ci		    MVPP2_RX_FIFO_PORT_DATA_SIZE_32KB);
66978c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(0),
66988c2ecf20Sopenharmony_ci		    MVPP2_RX_FIFO_PORT_ATTR_SIZE_32KB);
66998c2ecf20Sopenharmony_ci
67008c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(1),
67018c2ecf20Sopenharmony_ci		    MVPP2_RX_FIFO_PORT_DATA_SIZE_8KB);
67028c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(1),
67038c2ecf20Sopenharmony_ci		    MVPP2_RX_FIFO_PORT_ATTR_SIZE_8KB);
67048c2ecf20Sopenharmony_ci
67058c2ecf20Sopenharmony_ci	for (port = 2; port < MVPP2_MAX_PORTS; port++) {
67068c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
67078c2ecf20Sopenharmony_ci			    MVPP2_RX_FIFO_PORT_DATA_SIZE_4KB);
67088c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
67098c2ecf20Sopenharmony_ci			    MVPP2_RX_FIFO_PORT_ATTR_SIZE_4KB);
67108c2ecf20Sopenharmony_ci	}
67118c2ecf20Sopenharmony_ci
67128c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG,
67138c2ecf20Sopenharmony_ci		    MVPP2_RX_FIFO_PORT_MIN_PKT);
67148c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
67158c2ecf20Sopenharmony_ci}
67168c2ecf20Sopenharmony_ci
67178c2ecf20Sopenharmony_ci/* Initialize Tx FIFO's: the total FIFO size is 19kB on PPv2.2 and 10G
67188c2ecf20Sopenharmony_ci * interfaces must have a Tx FIFO size of 10kB. As only port 0 can do 10G,
67198c2ecf20Sopenharmony_ci * configure its Tx FIFO size to 10kB and the others ports Tx FIFO size to 3kB.
67208c2ecf20Sopenharmony_ci */
67218c2ecf20Sopenharmony_cistatic void mvpp22_tx_fifo_init(struct mvpp2 *priv)
67228c2ecf20Sopenharmony_ci{
67238c2ecf20Sopenharmony_ci	int port, size, thrs;
67248c2ecf20Sopenharmony_ci
67258c2ecf20Sopenharmony_ci	for (port = 0; port < MVPP2_MAX_PORTS; port++) {
67268c2ecf20Sopenharmony_ci		if (port == 0) {
67278c2ecf20Sopenharmony_ci			size = MVPP22_TX_FIFO_DATA_SIZE_10KB;
67288c2ecf20Sopenharmony_ci			thrs = MVPP2_TX_FIFO_THRESHOLD_10KB;
67298c2ecf20Sopenharmony_ci		} else {
67308c2ecf20Sopenharmony_ci			size = MVPP22_TX_FIFO_DATA_SIZE_3KB;
67318c2ecf20Sopenharmony_ci			thrs = MVPP2_TX_FIFO_THRESHOLD_3KB;
67328c2ecf20Sopenharmony_ci		}
67338c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port), size);
67348c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP22_TX_FIFO_THRESH_REG(port), thrs);
67358c2ecf20Sopenharmony_ci	}
67368c2ecf20Sopenharmony_ci}
67378c2ecf20Sopenharmony_ci
67388c2ecf20Sopenharmony_cistatic void mvpp2_axi_init(struct mvpp2 *priv)
67398c2ecf20Sopenharmony_ci{
67408c2ecf20Sopenharmony_ci	u32 val, rdval, wrval;
67418c2ecf20Sopenharmony_ci
67428c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_BM_ADDR_HIGH_RLS_REG, 0x0);
67438c2ecf20Sopenharmony_ci
67448c2ecf20Sopenharmony_ci	/* AXI Bridge Configuration */
67458c2ecf20Sopenharmony_ci
67468c2ecf20Sopenharmony_ci	rdval = MVPP22_AXI_CODE_CACHE_RD_CACHE
67478c2ecf20Sopenharmony_ci		<< MVPP22_AXI_ATTR_CACHE_OFFS;
67488c2ecf20Sopenharmony_ci	rdval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
67498c2ecf20Sopenharmony_ci		<< MVPP22_AXI_ATTR_DOMAIN_OFFS;
67508c2ecf20Sopenharmony_ci
67518c2ecf20Sopenharmony_ci	wrval = MVPP22_AXI_CODE_CACHE_WR_CACHE
67528c2ecf20Sopenharmony_ci		<< MVPP22_AXI_ATTR_CACHE_OFFS;
67538c2ecf20Sopenharmony_ci	wrval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
67548c2ecf20Sopenharmony_ci		<< MVPP22_AXI_ATTR_DOMAIN_OFFS;
67558c2ecf20Sopenharmony_ci
67568c2ecf20Sopenharmony_ci	/* BM */
67578c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_BM_WR_ATTR_REG, wrval);
67588c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_BM_RD_ATTR_REG, rdval);
67598c2ecf20Sopenharmony_ci
67608c2ecf20Sopenharmony_ci	/* Descriptors */
67618c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, rdval);
67628c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, wrval);
67638c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, rdval);
67648c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, wrval);
67658c2ecf20Sopenharmony_ci
67668c2ecf20Sopenharmony_ci	/* Buffer Data */
67678c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, rdval);
67688c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, wrval);
67698c2ecf20Sopenharmony_ci
67708c2ecf20Sopenharmony_ci	val = MVPP22_AXI_CODE_CACHE_NON_CACHE
67718c2ecf20Sopenharmony_ci		<< MVPP22_AXI_CODE_CACHE_OFFS;
67728c2ecf20Sopenharmony_ci	val |= MVPP22_AXI_CODE_DOMAIN_SYSTEM
67738c2ecf20Sopenharmony_ci		<< MVPP22_AXI_CODE_DOMAIN_OFFS;
67748c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_RD_NORMAL_CODE_REG, val);
67758c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_WR_NORMAL_CODE_REG, val);
67768c2ecf20Sopenharmony_ci
67778c2ecf20Sopenharmony_ci	val = MVPP22_AXI_CODE_CACHE_RD_CACHE
67788c2ecf20Sopenharmony_ci		<< MVPP22_AXI_CODE_CACHE_OFFS;
67798c2ecf20Sopenharmony_ci	val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
67808c2ecf20Sopenharmony_ci		<< MVPP22_AXI_CODE_DOMAIN_OFFS;
67818c2ecf20Sopenharmony_ci
67828c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_RD_SNOOP_CODE_REG, val);
67838c2ecf20Sopenharmony_ci
67848c2ecf20Sopenharmony_ci	val = MVPP22_AXI_CODE_CACHE_WR_CACHE
67858c2ecf20Sopenharmony_ci		<< MVPP22_AXI_CODE_CACHE_OFFS;
67868c2ecf20Sopenharmony_ci	val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
67878c2ecf20Sopenharmony_ci		<< MVPP22_AXI_CODE_DOMAIN_OFFS;
67888c2ecf20Sopenharmony_ci
67898c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP22_AXI_WR_SNOOP_CODE_REG, val);
67908c2ecf20Sopenharmony_ci}
67918c2ecf20Sopenharmony_ci
67928c2ecf20Sopenharmony_ci/* Initialize network controller common part HW */
67938c2ecf20Sopenharmony_cistatic int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
67948c2ecf20Sopenharmony_ci{
67958c2ecf20Sopenharmony_ci	const struct mbus_dram_target_info *dram_target_info;
67968c2ecf20Sopenharmony_ci	int err, i;
67978c2ecf20Sopenharmony_ci	u32 val;
67988c2ecf20Sopenharmony_ci
67998c2ecf20Sopenharmony_ci	/* MBUS windows configuration */
68008c2ecf20Sopenharmony_ci	dram_target_info = mv_mbus_dram_info();
68018c2ecf20Sopenharmony_ci	if (dram_target_info)
68028c2ecf20Sopenharmony_ci		mvpp2_conf_mbus_windows(dram_target_info, priv);
68038c2ecf20Sopenharmony_ci
68048c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22)
68058c2ecf20Sopenharmony_ci		mvpp2_axi_init(priv);
68068c2ecf20Sopenharmony_ci
68078c2ecf20Sopenharmony_ci	/* Disable HW PHY polling */
68088c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21) {
68098c2ecf20Sopenharmony_ci		val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
68108c2ecf20Sopenharmony_ci		val |= MVPP2_PHY_AN_STOP_SMI0_MASK;
68118c2ecf20Sopenharmony_ci		writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
68128c2ecf20Sopenharmony_ci	} else {
68138c2ecf20Sopenharmony_ci		val = readl(priv->iface_base + MVPP22_SMI_MISC_CFG_REG);
68148c2ecf20Sopenharmony_ci		val &= ~MVPP22_SMI_POLLING_EN;
68158c2ecf20Sopenharmony_ci		writel(val, priv->iface_base + MVPP22_SMI_MISC_CFG_REG);
68168c2ecf20Sopenharmony_ci	}
68178c2ecf20Sopenharmony_ci
68188c2ecf20Sopenharmony_ci	/* Allocate and initialize aggregated TXQs */
68198c2ecf20Sopenharmony_ci	priv->aggr_txqs = devm_kcalloc(&pdev->dev, MVPP2_MAX_THREADS,
68208c2ecf20Sopenharmony_ci				       sizeof(*priv->aggr_txqs),
68218c2ecf20Sopenharmony_ci				       GFP_KERNEL);
68228c2ecf20Sopenharmony_ci	if (!priv->aggr_txqs)
68238c2ecf20Sopenharmony_ci		return -ENOMEM;
68248c2ecf20Sopenharmony_ci
68258c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_THREADS; i++) {
68268c2ecf20Sopenharmony_ci		priv->aggr_txqs[i].id = i;
68278c2ecf20Sopenharmony_ci		priv->aggr_txqs[i].size = MVPP2_AGGR_TXQ_SIZE;
68288c2ecf20Sopenharmony_ci		err = mvpp2_aggr_txq_init(pdev, &priv->aggr_txqs[i], i, priv);
68298c2ecf20Sopenharmony_ci		if (err < 0)
68308c2ecf20Sopenharmony_ci			return err;
68318c2ecf20Sopenharmony_ci	}
68328c2ecf20Sopenharmony_ci
68338c2ecf20Sopenharmony_ci	/* Fifo Init */
68348c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21) {
68358c2ecf20Sopenharmony_ci		mvpp2_rx_fifo_init(priv);
68368c2ecf20Sopenharmony_ci	} else {
68378c2ecf20Sopenharmony_ci		mvpp22_rx_fifo_init(priv);
68388c2ecf20Sopenharmony_ci		mvpp22_tx_fifo_init(priv);
68398c2ecf20Sopenharmony_ci	}
68408c2ecf20Sopenharmony_ci
68418c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
68428c2ecf20Sopenharmony_ci		writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
68438c2ecf20Sopenharmony_ci		       priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
68448c2ecf20Sopenharmony_ci
68458c2ecf20Sopenharmony_ci	/* Allow cache snoop when transmiting packets */
68468c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_TX_SNOOP_REG, 0x1);
68478c2ecf20Sopenharmony_ci
68488c2ecf20Sopenharmony_ci	/* Buffer Manager initialization */
68498c2ecf20Sopenharmony_ci	err = mvpp2_bm_init(&pdev->dev, priv);
68508c2ecf20Sopenharmony_ci	if (err < 0)
68518c2ecf20Sopenharmony_ci		return err;
68528c2ecf20Sopenharmony_ci
68538c2ecf20Sopenharmony_ci	/* Parser default initialization */
68548c2ecf20Sopenharmony_ci	err = mvpp2_prs_default_init(pdev, priv);
68558c2ecf20Sopenharmony_ci	if (err < 0)
68568c2ecf20Sopenharmony_ci		return err;
68578c2ecf20Sopenharmony_ci
68588c2ecf20Sopenharmony_ci	/* Classifier default initialization */
68598c2ecf20Sopenharmony_ci	mvpp2_cls_init(priv);
68608c2ecf20Sopenharmony_ci
68618c2ecf20Sopenharmony_ci	return 0;
68628c2ecf20Sopenharmony_ci}
68638c2ecf20Sopenharmony_ci
68648c2ecf20Sopenharmony_cistatic int mvpp2_probe(struct platform_device *pdev)
68658c2ecf20Sopenharmony_ci{
68668c2ecf20Sopenharmony_ci	const struct acpi_device_id *acpi_id;
68678c2ecf20Sopenharmony_ci	struct fwnode_handle *fwnode = pdev->dev.fwnode;
68688c2ecf20Sopenharmony_ci	struct fwnode_handle *port_fwnode;
68698c2ecf20Sopenharmony_ci	struct mvpp2 *priv;
68708c2ecf20Sopenharmony_ci	struct resource *res;
68718c2ecf20Sopenharmony_ci	void __iomem *base;
68728c2ecf20Sopenharmony_ci	int i, shared;
68738c2ecf20Sopenharmony_ci	int err;
68748c2ecf20Sopenharmony_ci
68758c2ecf20Sopenharmony_ci	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
68768c2ecf20Sopenharmony_ci	if (!priv)
68778c2ecf20Sopenharmony_ci		return -ENOMEM;
68788c2ecf20Sopenharmony_ci
68798c2ecf20Sopenharmony_ci	if (has_acpi_companion(&pdev->dev)) {
68808c2ecf20Sopenharmony_ci		acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
68818c2ecf20Sopenharmony_ci					    &pdev->dev);
68828c2ecf20Sopenharmony_ci		if (!acpi_id)
68838c2ecf20Sopenharmony_ci			return -EINVAL;
68848c2ecf20Sopenharmony_ci		priv->hw_version = (unsigned long)acpi_id->driver_data;
68858c2ecf20Sopenharmony_ci	} else {
68868c2ecf20Sopenharmony_ci		priv->hw_version =
68878c2ecf20Sopenharmony_ci			(unsigned long)of_device_get_match_data(&pdev->dev);
68888c2ecf20Sopenharmony_ci	}
68898c2ecf20Sopenharmony_ci
68908c2ecf20Sopenharmony_ci	/* multi queue mode isn't supported on PPV2.1, fallback to single
68918c2ecf20Sopenharmony_ci	 * mode
68928c2ecf20Sopenharmony_ci	 */
68938c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
68948c2ecf20Sopenharmony_ci		queue_mode = MVPP2_QDIST_SINGLE_MODE;
68958c2ecf20Sopenharmony_ci
68968c2ecf20Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
68978c2ecf20Sopenharmony_ci	if (IS_ERR(base))
68988c2ecf20Sopenharmony_ci		return PTR_ERR(base);
68998c2ecf20Sopenharmony_ci
69008c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21) {
69018c2ecf20Sopenharmony_ci		priv->lms_base = devm_platform_ioremap_resource(pdev, 1);
69028c2ecf20Sopenharmony_ci		if (IS_ERR(priv->lms_base))
69038c2ecf20Sopenharmony_ci			return PTR_ERR(priv->lms_base);
69048c2ecf20Sopenharmony_ci	} else {
69058c2ecf20Sopenharmony_ci		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
69068c2ecf20Sopenharmony_ci		if (!res) {
69078c2ecf20Sopenharmony_ci			dev_err(&pdev->dev, "Invalid resource\n");
69088c2ecf20Sopenharmony_ci			return -EINVAL;
69098c2ecf20Sopenharmony_ci		}
69108c2ecf20Sopenharmony_ci		if (has_acpi_companion(&pdev->dev)) {
69118c2ecf20Sopenharmony_ci			/* In case the MDIO memory region is declared in
69128c2ecf20Sopenharmony_ci			 * the ACPI, it can already appear as 'in-use'
69138c2ecf20Sopenharmony_ci			 * in the OS. Because it is overlapped by second
69148c2ecf20Sopenharmony_ci			 * region of the network controller, make
69158c2ecf20Sopenharmony_ci			 * sure it is released, before requesting it again.
69168c2ecf20Sopenharmony_ci			 * The care is taken by mvpp2 driver to avoid
69178c2ecf20Sopenharmony_ci			 * concurrent access to this memory region.
69188c2ecf20Sopenharmony_ci			 */
69198c2ecf20Sopenharmony_ci			release_resource(res);
69208c2ecf20Sopenharmony_ci		}
69218c2ecf20Sopenharmony_ci		priv->iface_base = devm_ioremap_resource(&pdev->dev, res);
69228c2ecf20Sopenharmony_ci		if (IS_ERR(priv->iface_base))
69238c2ecf20Sopenharmony_ci			return PTR_ERR(priv->iface_base);
69248c2ecf20Sopenharmony_ci	}
69258c2ecf20Sopenharmony_ci
69268c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22 && dev_of_node(&pdev->dev)) {
69278c2ecf20Sopenharmony_ci		priv->sysctrl_base =
69288c2ecf20Sopenharmony_ci			syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
69298c2ecf20Sopenharmony_ci							"marvell,system-controller");
69308c2ecf20Sopenharmony_ci		if (IS_ERR(priv->sysctrl_base))
69318c2ecf20Sopenharmony_ci			/* The system controller regmap is optional for dt
69328c2ecf20Sopenharmony_ci			 * compatibility reasons. When not provided, the
69338c2ecf20Sopenharmony_ci			 * configuration of the GoP relies on the
69348c2ecf20Sopenharmony_ci			 * firmware/bootloader.
69358c2ecf20Sopenharmony_ci			 */
69368c2ecf20Sopenharmony_ci			priv->sysctrl_base = NULL;
69378c2ecf20Sopenharmony_ci	}
69388c2ecf20Sopenharmony_ci
69398c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22 &&
69408c2ecf20Sopenharmony_ci	    mvpp2_get_nrxqs(priv) * 2 <= MVPP2_BM_MAX_POOLS)
69418c2ecf20Sopenharmony_ci		priv->percpu_pools = 1;
69428c2ecf20Sopenharmony_ci
69438c2ecf20Sopenharmony_ci	mvpp2_setup_bm_pool();
69448c2ecf20Sopenharmony_ci
69458c2ecf20Sopenharmony_ci
69468c2ecf20Sopenharmony_ci	priv->nthreads = min_t(unsigned int, num_present_cpus(),
69478c2ecf20Sopenharmony_ci			       MVPP2_MAX_THREADS);
69488c2ecf20Sopenharmony_ci
69498c2ecf20Sopenharmony_ci	shared = num_present_cpus() - priv->nthreads;
69508c2ecf20Sopenharmony_ci	if (shared > 0)
69518c2ecf20Sopenharmony_ci		bitmap_set(&priv->lock_map, 0,
69528c2ecf20Sopenharmony_ci			    min_t(int, shared, MVPP2_MAX_THREADS));
69538c2ecf20Sopenharmony_ci
69548c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_THREADS; i++) {
69558c2ecf20Sopenharmony_ci		u32 addr_space_sz;
69568c2ecf20Sopenharmony_ci
69578c2ecf20Sopenharmony_ci		addr_space_sz = (priv->hw_version == MVPP21 ?
69588c2ecf20Sopenharmony_ci				 MVPP21_ADDR_SPACE_SZ : MVPP22_ADDR_SPACE_SZ);
69598c2ecf20Sopenharmony_ci		priv->swth_base[i] = base + i * addr_space_sz;
69608c2ecf20Sopenharmony_ci	}
69618c2ecf20Sopenharmony_ci
69628c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP21)
69638c2ecf20Sopenharmony_ci		priv->max_port_rxqs = 8;
69648c2ecf20Sopenharmony_ci	else
69658c2ecf20Sopenharmony_ci		priv->max_port_rxqs = 32;
69668c2ecf20Sopenharmony_ci
69678c2ecf20Sopenharmony_ci	if (dev_of_node(&pdev->dev)) {
69688c2ecf20Sopenharmony_ci		priv->pp_clk = devm_clk_get(&pdev->dev, "pp_clk");
69698c2ecf20Sopenharmony_ci		if (IS_ERR(priv->pp_clk))
69708c2ecf20Sopenharmony_ci			return PTR_ERR(priv->pp_clk);
69718c2ecf20Sopenharmony_ci		err = clk_prepare_enable(priv->pp_clk);
69728c2ecf20Sopenharmony_ci		if (err < 0)
69738c2ecf20Sopenharmony_ci			return err;
69748c2ecf20Sopenharmony_ci
69758c2ecf20Sopenharmony_ci		priv->gop_clk = devm_clk_get(&pdev->dev, "gop_clk");
69768c2ecf20Sopenharmony_ci		if (IS_ERR(priv->gop_clk)) {
69778c2ecf20Sopenharmony_ci			err = PTR_ERR(priv->gop_clk);
69788c2ecf20Sopenharmony_ci			goto err_pp_clk;
69798c2ecf20Sopenharmony_ci		}
69808c2ecf20Sopenharmony_ci		err = clk_prepare_enable(priv->gop_clk);
69818c2ecf20Sopenharmony_ci		if (err < 0)
69828c2ecf20Sopenharmony_ci			goto err_pp_clk;
69838c2ecf20Sopenharmony_ci
69848c2ecf20Sopenharmony_ci		if (priv->hw_version == MVPP22) {
69858c2ecf20Sopenharmony_ci			priv->mg_clk = devm_clk_get(&pdev->dev, "mg_clk");
69868c2ecf20Sopenharmony_ci			if (IS_ERR(priv->mg_clk)) {
69878c2ecf20Sopenharmony_ci				err = PTR_ERR(priv->mg_clk);
69888c2ecf20Sopenharmony_ci				goto err_gop_clk;
69898c2ecf20Sopenharmony_ci			}
69908c2ecf20Sopenharmony_ci
69918c2ecf20Sopenharmony_ci			err = clk_prepare_enable(priv->mg_clk);
69928c2ecf20Sopenharmony_ci			if (err < 0)
69938c2ecf20Sopenharmony_ci				goto err_gop_clk;
69948c2ecf20Sopenharmony_ci
69958c2ecf20Sopenharmony_ci			priv->mg_core_clk = devm_clk_get(&pdev->dev, "mg_core_clk");
69968c2ecf20Sopenharmony_ci			if (IS_ERR(priv->mg_core_clk)) {
69978c2ecf20Sopenharmony_ci				priv->mg_core_clk = NULL;
69988c2ecf20Sopenharmony_ci			} else {
69998c2ecf20Sopenharmony_ci				err = clk_prepare_enable(priv->mg_core_clk);
70008c2ecf20Sopenharmony_ci				if (err < 0)
70018c2ecf20Sopenharmony_ci					goto err_mg_clk;
70028c2ecf20Sopenharmony_ci			}
70038c2ecf20Sopenharmony_ci		}
70048c2ecf20Sopenharmony_ci
70058c2ecf20Sopenharmony_ci		priv->axi_clk = devm_clk_get(&pdev->dev, "axi_clk");
70068c2ecf20Sopenharmony_ci		if (IS_ERR(priv->axi_clk)) {
70078c2ecf20Sopenharmony_ci			err = PTR_ERR(priv->axi_clk);
70088c2ecf20Sopenharmony_ci			if (err == -EPROBE_DEFER)
70098c2ecf20Sopenharmony_ci				goto err_mg_core_clk;
70108c2ecf20Sopenharmony_ci			priv->axi_clk = NULL;
70118c2ecf20Sopenharmony_ci		} else {
70128c2ecf20Sopenharmony_ci			err = clk_prepare_enable(priv->axi_clk);
70138c2ecf20Sopenharmony_ci			if (err < 0)
70148c2ecf20Sopenharmony_ci				goto err_mg_core_clk;
70158c2ecf20Sopenharmony_ci		}
70168c2ecf20Sopenharmony_ci
70178c2ecf20Sopenharmony_ci		/* Get system's tclk rate */
70188c2ecf20Sopenharmony_ci		priv->tclk = clk_get_rate(priv->pp_clk);
70198c2ecf20Sopenharmony_ci	} else if (device_property_read_u32(&pdev->dev, "clock-frequency",
70208c2ecf20Sopenharmony_ci					    &priv->tclk)) {
70218c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "missing clock-frequency value\n");
70228c2ecf20Sopenharmony_ci		return -EINVAL;
70238c2ecf20Sopenharmony_ci	}
70248c2ecf20Sopenharmony_ci
70258c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22) {
70268c2ecf20Sopenharmony_ci		err = dma_set_mask(&pdev->dev, MVPP2_DESC_DMA_MASK);
70278c2ecf20Sopenharmony_ci		if (err)
70288c2ecf20Sopenharmony_ci			goto err_axi_clk;
70298c2ecf20Sopenharmony_ci		/* Sadly, the BM pools all share the same register to
70308c2ecf20Sopenharmony_ci		 * store the high 32 bits of their address. So they
70318c2ecf20Sopenharmony_ci		 * must all have the same high 32 bits, which forces
70328c2ecf20Sopenharmony_ci		 * us to restrict coherent memory to DMA_BIT_MASK(32).
70338c2ecf20Sopenharmony_ci		 */
70348c2ecf20Sopenharmony_ci		err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
70358c2ecf20Sopenharmony_ci		if (err)
70368c2ecf20Sopenharmony_ci			goto err_axi_clk;
70378c2ecf20Sopenharmony_ci	}
70388c2ecf20Sopenharmony_ci
70398c2ecf20Sopenharmony_ci	/* Initialize network controller */
70408c2ecf20Sopenharmony_ci	err = mvpp2_init(pdev, priv);
70418c2ecf20Sopenharmony_ci	if (err < 0) {
70428c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "failed to initialize controller\n");
70438c2ecf20Sopenharmony_ci		goto err_axi_clk;
70448c2ecf20Sopenharmony_ci	}
70458c2ecf20Sopenharmony_ci
70468c2ecf20Sopenharmony_ci	err = mvpp22_tai_probe(&pdev->dev, priv);
70478c2ecf20Sopenharmony_ci	if (err < 0)
70488c2ecf20Sopenharmony_ci		goto err_axi_clk;
70498c2ecf20Sopenharmony_ci
70508c2ecf20Sopenharmony_ci	/* Initialize ports */
70518c2ecf20Sopenharmony_ci	fwnode_for_each_available_child_node(fwnode, port_fwnode) {
70528c2ecf20Sopenharmony_ci		err = mvpp2_port_probe(pdev, port_fwnode, priv);
70538c2ecf20Sopenharmony_ci		if (err < 0)
70548c2ecf20Sopenharmony_ci			goto err_port_probe;
70558c2ecf20Sopenharmony_ci	}
70568c2ecf20Sopenharmony_ci
70578c2ecf20Sopenharmony_ci	if (priv->port_count == 0) {
70588c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no ports enabled\n");
70598c2ecf20Sopenharmony_ci		err = -ENODEV;
70608c2ecf20Sopenharmony_ci		goto err_axi_clk;
70618c2ecf20Sopenharmony_ci	}
70628c2ecf20Sopenharmony_ci
70638c2ecf20Sopenharmony_ci	/* Statistics must be gathered regularly because some of them (like
70648c2ecf20Sopenharmony_ci	 * packets counters) are 32-bit registers and could overflow quite
70658c2ecf20Sopenharmony_ci	 * quickly. For instance, a 10Gb link used at full bandwidth with the
70668c2ecf20Sopenharmony_ci	 * smallest packets (64B) will overflow a 32-bit counter in less than
70678c2ecf20Sopenharmony_ci	 * 30 seconds. Then, use a workqueue to fill 64-bit counters.
70688c2ecf20Sopenharmony_ci	 */
70698c2ecf20Sopenharmony_ci	snprintf(priv->queue_name, sizeof(priv->queue_name),
70708c2ecf20Sopenharmony_ci		 "stats-wq-%s%s", netdev_name(priv->port_list[0]->dev),
70718c2ecf20Sopenharmony_ci		 priv->port_count > 1 ? "+" : "");
70728c2ecf20Sopenharmony_ci	priv->stats_queue = create_singlethread_workqueue(priv->queue_name);
70738c2ecf20Sopenharmony_ci	if (!priv->stats_queue) {
70748c2ecf20Sopenharmony_ci		err = -ENOMEM;
70758c2ecf20Sopenharmony_ci		goto err_port_probe;
70768c2ecf20Sopenharmony_ci	}
70778c2ecf20Sopenharmony_ci
70788c2ecf20Sopenharmony_ci	mvpp2_dbgfs_init(priv, pdev->name);
70798c2ecf20Sopenharmony_ci
70808c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, priv);
70818c2ecf20Sopenharmony_ci	return 0;
70828c2ecf20Sopenharmony_ci
70838c2ecf20Sopenharmony_cierr_port_probe:
70848c2ecf20Sopenharmony_ci	fwnode_handle_put(port_fwnode);
70858c2ecf20Sopenharmony_ci
70868c2ecf20Sopenharmony_ci	i = 0;
70878c2ecf20Sopenharmony_ci	fwnode_for_each_available_child_node(fwnode, port_fwnode) {
70888c2ecf20Sopenharmony_ci		if (priv->port_list[i])
70898c2ecf20Sopenharmony_ci			mvpp2_port_remove(priv->port_list[i]);
70908c2ecf20Sopenharmony_ci		i++;
70918c2ecf20Sopenharmony_ci	}
70928c2ecf20Sopenharmony_cierr_axi_clk:
70938c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->axi_clk);
70948c2ecf20Sopenharmony_ci
70958c2ecf20Sopenharmony_cierr_mg_core_clk:
70968c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22)
70978c2ecf20Sopenharmony_ci		clk_disable_unprepare(priv->mg_core_clk);
70988c2ecf20Sopenharmony_cierr_mg_clk:
70998c2ecf20Sopenharmony_ci	if (priv->hw_version == MVPP22)
71008c2ecf20Sopenharmony_ci		clk_disable_unprepare(priv->mg_clk);
71018c2ecf20Sopenharmony_cierr_gop_clk:
71028c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->gop_clk);
71038c2ecf20Sopenharmony_cierr_pp_clk:
71048c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->pp_clk);
71058c2ecf20Sopenharmony_ci	return err;
71068c2ecf20Sopenharmony_ci}
71078c2ecf20Sopenharmony_ci
71088c2ecf20Sopenharmony_cistatic int mvpp2_remove(struct platform_device *pdev)
71098c2ecf20Sopenharmony_ci{
71108c2ecf20Sopenharmony_ci	struct mvpp2 *priv = platform_get_drvdata(pdev);
71118c2ecf20Sopenharmony_ci	struct fwnode_handle *fwnode = pdev->dev.fwnode;
71128c2ecf20Sopenharmony_ci	int i = 0, poolnum = MVPP2_BM_POOLS_NUM;
71138c2ecf20Sopenharmony_ci	struct fwnode_handle *port_fwnode;
71148c2ecf20Sopenharmony_ci
71158c2ecf20Sopenharmony_ci	mvpp2_dbgfs_cleanup(priv);
71168c2ecf20Sopenharmony_ci
71178c2ecf20Sopenharmony_ci	fwnode_for_each_available_child_node(fwnode, port_fwnode) {
71188c2ecf20Sopenharmony_ci		if (priv->port_list[i]) {
71198c2ecf20Sopenharmony_ci			mutex_destroy(&priv->port_list[i]->gather_stats_lock);
71208c2ecf20Sopenharmony_ci			mvpp2_port_remove(priv->port_list[i]);
71218c2ecf20Sopenharmony_ci		}
71228c2ecf20Sopenharmony_ci		i++;
71238c2ecf20Sopenharmony_ci	}
71248c2ecf20Sopenharmony_ci
71258c2ecf20Sopenharmony_ci	destroy_workqueue(priv->stats_queue);
71268c2ecf20Sopenharmony_ci
71278c2ecf20Sopenharmony_ci	if (priv->percpu_pools)
71288c2ecf20Sopenharmony_ci		poolnum = mvpp2_get_nrxqs(priv) * 2;
71298c2ecf20Sopenharmony_ci
71308c2ecf20Sopenharmony_ci	for (i = 0; i < poolnum; i++) {
71318c2ecf20Sopenharmony_ci		struct mvpp2_bm_pool *bm_pool = &priv->bm_pools[i];
71328c2ecf20Sopenharmony_ci
71338c2ecf20Sopenharmony_ci		mvpp2_bm_pool_destroy(&pdev->dev, priv, bm_pool);
71348c2ecf20Sopenharmony_ci	}
71358c2ecf20Sopenharmony_ci
71368c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_MAX_THREADS; i++) {
71378c2ecf20Sopenharmony_ci		struct mvpp2_tx_queue *aggr_txq = &priv->aggr_txqs[i];
71388c2ecf20Sopenharmony_ci
71398c2ecf20Sopenharmony_ci		dma_free_coherent(&pdev->dev,
71408c2ecf20Sopenharmony_ci				  MVPP2_AGGR_TXQ_SIZE * MVPP2_DESC_ALIGNED_SIZE,
71418c2ecf20Sopenharmony_ci				  aggr_txq->descs,
71428c2ecf20Sopenharmony_ci				  aggr_txq->descs_dma);
71438c2ecf20Sopenharmony_ci	}
71448c2ecf20Sopenharmony_ci
71458c2ecf20Sopenharmony_ci	if (is_acpi_node(port_fwnode))
71468c2ecf20Sopenharmony_ci		return 0;
71478c2ecf20Sopenharmony_ci
71488c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->axi_clk);
71498c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->mg_core_clk);
71508c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->mg_clk);
71518c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->pp_clk);
71528c2ecf20Sopenharmony_ci	clk_disable_unprepare(priv->gop_clk);
71538c2ecf20Sopenharmony_ci
71548c2ecf20Sopenharmony_ci	return 0;
71558c2ecf20Sopenharmony_ci}
71568c2ecf20Sopenharmony_ci
71578c2ecf20Sopenharmony_cistatic const struct of_device_id mvpp2_match[] = {
71588c2ecf20Sopenharmony_ci	{
71598c2ecf20Sopenharmony_ci		.compatible = "marvell,armada-375-pp2",
71608c2ecf20Sopenharmony_ci		.data = (void *)MVPP21,
71618c2ecf20Sopenharmony_ci	},
71628c2ecf20Sopenharmony_ci	{
71638c2ecf20Sopenharmony_ci		.compatible = "marvell,armada-7k-pp22",
71648c2ecf20Sopenharmony_ci		.data = (void *)MVPP22,
71658c2ecf20Sopenharmony_ci	},
71668c2ecf20Sopenharmony_ci	{ }
71678c2ecf20Sopenharmony_ci};
71688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mvpp2_match);
71698c2ecf20Sopenharmony_ci
71708c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
71718c2ecf20Sopenharmony_cistatic const struct acpi_device_id mvpp2_acpi_match[] = {
71728c2ecf20Sopenharmony_ci	{ "MRVL0110", MVPP22 },
71738c2ecf20Sopenharmony_ci	{ },
71748c2ecf20Sopenharmony_ci};
71758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, mvpp2_acpi_match);
71768c2ecf20Sopenharmony_ci#endif
71778c2ecf20Sopenharmony_ci
71788c2ecf20Sopenharmony_cistatic struct platform_driver mvpp2_driver = {
71798c2ecf20Sopenharmony_ci	.probe = mvpp2_probe,
71808c2ecf20Sopenharmony_ci	.remove = mvpp2_remove,
71818c2ecf20Sopenharmony_ci	.driver = {
71828c2ecf20Sopenharmony_ci		.name = MVPP2_DRIVER_NAME,
71838c2ecf20Sopenharmony_ci		.of_match_table = mvpp2_match,
71848c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(mvpp2_acpi_match),
71858c2ecf20Sopenharmony_ci	},
71868c2ecf20Sopenharmony_ci};
71878c2ecf20Sopenharmony_ci
71888c2ecf20Sopenharmony_cistatic int __init mvpp2_driver_init(void)
71898c2ecf20Sopenharmony_ci{
71908c2ecf20Sopenharmony_ci	return platform_driver_register(&mvpp2_driver);
71918c2ecf20Sopenharmony_ci}
71928c2ecf20Sopenharmony_cimodule_init(mvpp2_driver_init);
71938c2ecf20Sopenharmony_ci
71948c2ecf20Sopenharmony_cistatic void __exit mvpp2_driver_exit(void)
71958c2ecf20Sopenharmony_ci{
71968c2ecf20Sopenharmony_ci	platform_driver_unregister(&mvpp2_driver);
71978c2ecf20Sopenharmony_ci	mvpp2_dbgfs_exit();
71988c2ecf20Sopenharmony_ci}
71998c2ecf20Sopenharmony_cimodule_exit(mvpp2_driver_exit);
72008c2ecf20Sopenharmony_ci
72018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell PPv2 Ethernet Driver - www.marvell.com");
72028c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marcin Wojtas <mw@semihalf.com>");
72038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
7204