18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/* Copyright 2017-2019 NXP */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "enetc.h"
58c2ecf20Sopenharmony_ci#include <linux/tcp.h>
68c2ecf20Sopenharmony_ci#include <linux/udp.h>
78c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
88c2ecf20Sopenharmony_ci#include <net/pkt_sched.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* ENETC overhead: optional extension BD + 1 BD gap */
118c2ecf20Sopenharmony_ci#define ENETC_TXBDS_NEEDED(val)	((val) + 2)
128c2ecf20Sopenharmony_ci/* max # of chained Tx BDs is 15, including head and extension BD */
138c2ecf20Sopenharmony_ci#define ENETC_MAX_SKB_FRAGS	13
148c2ecf20Sopenharmony_ci#define ENETC_TXBDS_MAX_NEEDED	ENETC_TXBDS_NEEDED(ENETC_MAX_SKB_FRAGS + 1)
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
178c2ecf20Sopenharmony_ci			      int active_offloads);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cinetdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
228c2ecf20Sopenharmony_ci	struct enetc_bdr *tx_ring;
238c2ecf20Sopenharmony_ci	int count;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	tx_ring = priv->tx_ring[skb->queue_mapping];
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	if (unlikely(skb_shinfo(skb)->nr_frags > ENETC_MAX_SKB_FRAGS))
288c2ecf20Sopenharmony_ci		if (unlikely(skb_linearize(skb)))
298c2ecf20Sopenharmony_ci			goto drop_packet_err;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	count = skb_shinfo(skb)->nr_frags + 1; /* fragments + head */
328c2ecf20Sopenharmony_ci	if (enetc_bd_unused(tx_ring) < ENETC_TXBDS_NEEDED(count)) {
338c2ecf20Sopenharmony_ci		netif_stop_subqueue(ndev, tx_ring->index);
348c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
358c2ecf20Sopenharmony_ci	}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	enetc_lock_mdio();
388c2ecf20Sopenharmony_ci	count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads);
398c2ecf20Sopenharmony_ci	enetc_unlock_mdio();
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (unlikely(!count))
428c2ecf20Sopenharmony_ci		goto drop_packet_err;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (enetc_bd_unused(tx_ring) < ENETC_TXBDS_MAX_NEEDED)
458c2ecf20Sopenharmony_ci		netif_stop_subqueue(ndev, tx_ring->index);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cidrop_packet_err:
508c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
518c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic bool enetc_tx_csum(struct sk_buff *skb, union enetc_tx_bd *txbd)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	int l3_start, l3_hsize;
578c2ecf20Sopenharmony_ci	u16 l3_flags, l4_flags;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL)
608c2ecf20Sopenharmony_ci		return false;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	switch (skb->csum_offset) {
638c2ecf20Sopenharmony_ci	case offsetof(struct tcphdr, check):
648c2ecf20Sopenharmony_ci		l4_flags = ENETC_TXBD_L4_TCP;
658c2ecf20Sopenharmony_ci		break;
668c2ecf20Sopenharmony_ci	case offsetof(struct udphdr, check):
678c2ecf20Sopenharmony_ci		l4_flags = ENETC_TXBD_L4_UDP;
688c2ecf20Sopenharmony_ci		break;
698c2ecf20Sopenharmony_ci	default:
708c2ecf20Sopenharmony_ci		skb_checksum_help(skb);
718c2ecf20Sopenharmony_ci		return false;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	l3_start = skb_network_offset(skb);
758c2ecf20Sopenharmony_ci	l3_hsize = skb_network_header_len(skb);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	l3_flags = 0;
788c2ecf20Sopenharmony_ci	if (skb->protocol == htons(ETH_P_IPV6))
798c2ecf20Sopenharmony_ci		l3_flags = ENETC_TXBD_L3_IPV6;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* write BD fields */
828c2ecf20Sopenharmony_ci	txbd->l3_csoff = enetc_txbd_l3_csoff(l3_start, l3_hsize, l3_flags);
838c2ecf20Sopenharmony_ci	txbd->l4_csoff = l4_flags;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return true;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic void enetc_unmap_tx_buff(struct enetc_bdr *tx_ring,
898c2ecf20Sopenharmony_ci				struct enetc_tx_swbd *tx_swbd)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	if (tx_swbd->is_dma_page)
928c2ecf20Sopenharmony_ci		dma_unmap_page(tx_ring->dev, tx_swbd->dma,
938c2ecf20Sopenharmony_ci			       tx_swbd->len, DMA_TO_DEVICE);
948c2ecf20Sopenharmony_ci	else
958c2ecf20Sopenharmony_ci		dma_unmap_single(tx_ring->dev, tx_swbd->dma,
968c2ecf20Sopenharmony_ci				 tx_swbd->len, DMA_TO_DEVICE);
978c2ecf20Sopenharmony_ci	tx_swbd->dma = 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic void enetc_free_tx_skb(struct enetc_bdr *tx_ring,
1018c2ecf20Sopenharmony_ci			      struct enetc_tx_swbd *tx_swbd)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	if (tx_swbd->dma)
1048c2ecf20Sopenharmony_ci		enetc_unmap_tx_buff(tx_ring, tx_swbd);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (tx_swbd->skb) {
1078c2ecf20Sopenharmony_ci		dev_kfree_skb_any(tx_swbd->skb);
1088c2ecf20Sopenharmony_ci		tx_swbd->skb = NULL;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
1138c2ecf20Sopenharmony_ci			      int active_offloads)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct enetc_tx_swbd *tx_swbd;
1168c2ecf20Sopenharmony_ci	skb_frag_t *frag;
1178c2ecf20Sopenharmony_ci	int len = skb_headlen(skb);
1188c2ecf20Sopenharmony_ci	union enetc_tx_bd temp_bd;
1198c2ecf20Sopenharmony_ci	union enetc_tx_bd *txbd;
1208c2ecf20Sopenharmony_ci	bool do_vlan, do_tstamp;
1218c2ecf20Sopenharmony_ci	int i, count = 0;
1228c2ecf20Sopenharmony_ci	unsigned int f;
1238c2ecf20Sopenharmony_ci	dma_addr_t dma;
1248c2ecf20Sopenharmony_ci	u8 flags = 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	i = tx_ring->next_to_use;
1278c2ecf20Sopenharmony_ci	txbd = ENETC_TXBD(*tx_ring, i);
1288c2ecf20Sopenharmony_ci	prefetchw(txbd);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	dma = dma_map_single(tx_ring->dev, skb->data, len, DMA_TO_DEVICE);
1318c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(tx_ring->dev, dma)))
1328c2ecf20Sopenharmony_ci		goto dma_err;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	temp_bd.addr = cpu_to_le64(dma);
1358c2ecf20Sopenharmony_ci	temp_bd.buf_len = cpu_to_le16(len);
1368c2ecf20Sopenharmony_ci	temp_bd.lstatus = 0;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	tx_swbd = &tx_ring->tx_swbd[i];
1398c2ecf20Sopenharmony_ci	tx_swbd->dma = dma;
1408c2ecf20Sopenharmony_ci	tx_swbd->len = len;
1418c2ecf20Sopenharmony_ci	tx_swbd->is_dma_page = 0;
1428c2ecf20Sopenharmony_ci	count++;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	do_vlan = skb_vlan_tag_present(skb);
1458c2ecf20Sopenharmony_ci	do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) &&
1468c2ecf20Sopenharmony_ci		    (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP);
1478c2ecf20Sopenharmony_ci	tx_swbd->do_tstamp = do_tstamp;
1488c2ecf20Sopenharmony_ci	tx_swbd->check_wb = tx_swbd->do_tstamp;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (do_vlan || do_tstamp)
1518c2ecf20Sopenharmony_ci		flags |= ENETC_TXBD_FLAGS_EX;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (enetc_tx_csum(skb, &temp_bd))
1548c2ecf20Sopenharmony_ci		flags |= ENETC_TXBD_FLAGS_CSUM | ENETC_TXBD_FLAGS_L4CS;
1558c2ecf20Sopenharmony_ci	else if (tx_ring->tsd_enable)
1568c2ecf20Sopenharmony_ci		flags |= ENETC_TXBD_FLAGS_TSE | ENETC_TXBD_FLAGS_TXSTART;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* first BD needs frm_len and offload flags set */
1598c2ecf20Sopenharmony_ci	temp_bd.frm_len = cpu_to_le16(skb->len);
1608c2ecf20Sopenharmony_ci	temp_bd.flags = flags;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (flags & ENETC_TXBD_FLAGS_TSE) {
1638c2ecf20Sopenharmony_ci		u32 temp;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		temp = (skb->skb_mstamp_ns >> 5 & ENETC_TXBD_TXSTART_MASK)
1668c2ecf20Sopenharmony_ci			| (flags << ENETC_TXBD_FLAGS_OFFSET);
1678c2ecf20Sopenharmony_ci		temp_bd.txstart = cpu_to_le32(temp);
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (flags & ENETC_TXBD_FLAGS_EX) {
1718c2ecf20Sopenharmony_ci		u8 e_flags = 0;
1728c2ecf20Sopenharmony_ci		*txbd = temp_bd;
1738c2ecf20Sopenharmony_ci		enetc_clear_tx_bd(&temp_bd);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		/* add extension BD for VLAN and/or timestamping */
1768c2ecf20Sopenharmony_ci		flags = 0;
1778c2ecf20Sopenharmony_ci		tx_swbd++;
1788c2ecf20Sopenharmony_ci		txbd++;
1798c2ecf20Sopenharmony_ci		i++;
1808c2ecf20Sopenharmony_ci		if (unlikely(i == tx_ring->bd_count)) {
1818c2ecf20Sopenharmony_ci			i = 0;
1828c2ecf20Sopenharmony_ci			tx_swbd = tx_ring->tx_swbd;
1838c2ecf20Sopenharmony_ci			txbd = ENETC_TXBD(*tx_ring, 0);
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci		prefetchw(txbd);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		if (do_vlan) {
1888c2ecf20Sopenharmony_ci			temp_bd.ext.vid = cpu_to_le16(skb_vlan_tag_get(skb));
1898c2ecf20Sopenharmony_ci			temp_bd.ext.tpid = 0; /* < C-TAG */
1908c2ecf20Sopenharmony_ci			e_flags |= ENETC_TXBD_E_FLAGS_VLAN_INS;
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci		if (do_tstamp) {
1948c2ecf20Sopenharmony_ci			skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
1958c2ecf20Sopenharmony_ci			e_flags |= ENETC_TXBD_E_FLAGS_TWO_STEP_PTP;
1968c2ecf20Sopenharmony_ci		}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		temp_bd.ext.e_flags = e_flags;
1998c2ecf20Sopenharmony_ci		count++;
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	frag = &skb_shinfo(skb)->frags[0];
2038c2ecf20Sopenharmony_ci	for (f = 0; f < skb_shinfo(skb)->nr_frags; f++, frag++) {
2048c2ecf20Sopenharmony_ci		len = skb_frag_size(frag);
2058c2ecf20Sopenharmony_ci		dma = skb_frag_dma_map(tx_ring->dev, frag, 0, len,
2068c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
2078c2ecf20Sopenharmony_ci		if (dma_mapping_error(tx_ring->dev, dma))
2088c2ecf20Sopenharmony_ci			goto dma_err;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci		*txbd = temp_bd;
2118c2ecf20Sopenharmony_ci		enetc_clear_tx_bd(&temp_bd);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		flags = 0;
2148c2ecf20Sopenharmony_ci		tx_swbd++;
2158c2ecf20Sopenharmony_ci		txbd++;
2168c2ecf20Sopenharmony_ci		i++;
2178c2ecf20Sopenharmony_ci		if (unlikely(i == tx_ring->bd_count)) {
2188c2ecf20Sopenharmony_ci			i = 0;
2198c2ecf20Sopenharmony_ci			tx_swbd = tx_ring->tx_swbd;
2208c2ecf20Sopenharmony_ci			txbd = ENETC_TXBD(*tx_ring, 0);
2218c2ecf20Sopenharmony_ci		}
2228c2ecf20Sopenharmony_ci		prefetchw(txbd);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		temp_bd.addr = cpu_to_le64(dma);
2258c2ecf20Sopenharmony_ci		temp_bd.buf_len = cpu_to_le16(len);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		tx_swbd->dma = dma;
2288c2ecf20Sopenharmony_ci		tx_swbd->len = len;
2298c2ecf20Sopenharmony_ci		tx_swbd->is_dma_page = 1;
2308c2ecf20Sopenharmony_ci		count++;
2318c2ecf20Sopenharmony_ci	}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* last BD needs 'F' bit set */
2348c2ecf20Sopenharmony_ci	flags |= ENETC_TXBD_FLAGS_F;
2358c2ecf20Sopenharmony_ci	temp_bd.flags = flags;
2368c2ecf20Sopenharmony_ci	*txbd = temp_bd;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	tx_ring->tx_swbd[i].skb = skb;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	enetc_bdr_idx_inc(tx_ring, &i);
2418c2ecf20Sopenharmony_ci	tx_ring->next_to_use = i;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	skb_tx_timestamp(skb);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* let H/W know BD ring has been updated */
2468c2ecf20Sopenharmony_ci	enetc_wr_reg_hot(tx_ring->tpir, i); /* includes wmb() */
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return count;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cidma_err:
2518c2ecf20Sopenharmony_ci	dev_err(tx_ring->dev, "DMA map error");
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	do {
2548c2ecf20Sopenharmony_ci		tx_swbd = &tx_ring->tx_swbd[i];
2558c2ecf20Sopenharmony_ci		enetc_free_tx_skb(tx_ring, tx_swbd);
2568c2ecf20Sopenharmony_ci		if (i == 0)
2578c2ecf20Sopenharmony_ci			i = tx_ring->bd_count;
2588c2ecf20Sopenharmony_ci		i--;
2598c2ecf20Sopenharmony_ci	} while (count--);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic irqreturn_t enetc_msix(int irq, void *data)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct enetc_int_vector	*v = data;
2678c2ecf20Sopenharmony_ci	int i;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	enetc_lock_mdio();
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* disable interrupts */
2728c2ecf20Sopenharmony_ci	enetc_wr_reg_hot(v->rbier, 0);
2738c2ecf20Sopenharmony_ci	enetc_wr_reg_hot(v->ricr1, v->rx_ictt);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS)
2768c2ecf20Sopenharmony_ci		enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i), 0);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	enetc_unlock_mdio();
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	napi_schedule(&v->napi);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget);
2868c2ecf20Sopenharmony_cistatic int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
2878c2ecf20Sopenharmony_ci			       struct napi_struct *napi, int work_limit);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic void enetc_rx_dim_work(struct work_struct *w)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct dim *dim = container_of(w, struct dim, work);
2928c2ecf20Sopenharmony_ci	struct dim_cq_moder moder =
2938c2ecf20Sopenharmony_ci		net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
2948c2ecf20Sopenharmony_ci	struct enetc_int_vector	*v =
2958c2ecf20Sopenharmony_ci		container_of(dim, struct enetc_int_vector, rx_dim);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	v->rx_ictt = enetc_usecs_to_cycles(moder.usec);
2988c2ecf20Sopenharmony_ci	dim->state = DIM_START_MEASURE;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic void enetc_rx_net_dim(struct enetc_int_vector *v)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	struct dim_sample dim_sample = {};
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	v->comp_cnt++;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (!v->rx_napi_work)
3088c2ecf20Sopenharmony_ci		return;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	dim_update_sample(v->comp_cnt,
3118c2ecf20Sopenharmony_ci			  v->rx_ring.stats.packets,
3128c2ecf20Sopenharmony_ci			  v->rx_ring.stats.bytes,
3138c2ecf20Sopenharmony_ci			  &dim_sample);
3148c2ecf20Sopenharmony_ci	net_dim(&v->rx_dim, dim_sample);
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic int enetc_poll(struct napi_struct *napi, int budget)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct enetc_int_vector
3208c2ecf20Sopenharmony_ci		*v = container_of(napi, struct enetc_int_vector, napi);
3218c2ecf20Sopenharmony_ci	bool complete = true;
3228c2ecf20Sopenharmony_ci	int work_done;
3238c2ecf20Sopenharmony_ci	int i;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	enetc_lock_mdio();
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	for (i = 0; i < v->count_tx_rings; i++)
3288c2ecf20Sopenharmony_ci		if (!enetc_clean_tx_ring(&v->tx_ring[i], budget))
3298c2ecf20Sopenharmony_ci			complete = false;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	work_done = enetc_clean_rx_ring(&v->rx_ring, napi, budget);
3328c2ecf20Sopenharmony_ci	if (work_done == budget)
3338c2ecf20Sopenharmony_ci		complete = false;
3348c2ecf20Sopenharmony_ci	if (work_done)
3358c2ecf20Sopenharmony_ci		v->rx_napi_work = true;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (!complete) {
3388c2ecf20Sopenharmony_ci		enetc_unlock_mdio();
3398c2ecf20Sopenharmony_ci		return budget;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	napi_complete_done(napi, work_done);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	if (likely(v->rx_dim_en))
3458c2ecf20Sopenharmony_ci		enetc_rx_net_dim(v);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	v->rx_napi_work = false;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	/* enable interrupts */
3508c2ecf20Sopenharmony_ci	enetc_wr_reg_hot(v->rbier, ENETC_RBIER_RXTIE);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	for_each_set_bit(i, &v->tx_rings_map, ENETC_MAX_NUM_TXQS)
3538c2ecf20Sopenharmony_ci		enetc_wr_reg_hot(v->tbier_base + ENETC_BDR_OFF(i),
3548c2ecf20Sopenharmony_ci				 ENETC_TBIER_TXTIE);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	enetc_unlock_mdio();
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	return work_done;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	int pi = enetc_rd_reg_hot(tx_ring->tcir) & ENETC_TBCIR_IDX_MASK;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return pi >= ci ? pi - ci : tx_ring->bd_count - ci + pi;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic void enetc_get_tx_tstamp(struct enetc_hw *hw, union enetc_tx_bd *txbd,
3698c2ecf20Sopenharmony_ci				u64 *tstamp)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	u32 lo, hi, tstamp_lo;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	lo = enetc_rd_hot(hw, ENETC_SICTR0);
3748c2ecf20Sopenharmony_ci	hi = enetc_rd_hot(hw, ENETC_SICTR1);
3758c2ecf20Sopenharmony_ci	tstamp_lo = le32_to_cpu(txbd->wb.tstamp);
3768c2ecf20Sopenharmony_ci	if (lo <= tstamp_lo)
3778c2ecf20Sopenharmony_ci		hi -= 1;
3788c2ecf20Sopenharmony_ci	*tstamp = (u64)hi << 32 | tstamp_lo;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct skb_shared_hwtstamps shhwtstamps;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) {
3868c2ecf20Sopenharmony_ci		memset(&shhwtstamps, 0, sizeof(shhwtstamps));
3878c2ecf20Sopenharmony_ci		shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
3888c2ecf20Sopenharmony_ci		skb_txtime_consumed(skb);
3898c2ecf20Sopenharmony_ci		skb_tstamp_tx(skb, &shhwtstamps);
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
3948c2ecf20Sopenharmony_ci{
3958c2ecf20Sopenharmony_ci	struct net_device *ndev = tx_ring->ndev;
3968c2ecf20Sopenharmony_ci	int tx_frm_cnt = 0, tx_byte_cnt = 0;
3978c2ecf20Sopenharmony_ci	struct enetc_tx_swbd *tx_swbd;
3988c2ecf20Sopenharmony_ci	int i, bds_to_clean;
3998c2ecf20Sopenharmony_ci	bool do_tstamp;
4008c2ecf20Sopenharmony_ci	u64 tstamp = 0;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	i = tx_ring->next_to_clean;
4038c2ecf20Sopenharmony_ci	tx_swbd = &tx_ring->tx_swbd[i];
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	bds_to_clean = enetc_bd_ready_count(tx_ring, i);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	do_tstamp = false;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	while (bds_to_clean && tx_frm_cnt < ENETC_DEFAULT_TX_WORK) {
4108c2ecf20Sopenharmony_ci		bool is_eof = !!tx_swbd->skb;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci		if (unlikely(tx_swbd->check_wb)) {
4138c2ecf20Sopenharmony_ci			struct enetc_ndev_priv *priv = netdev_priv(ndev);
4148c2ecf20Sopenharmony_ci			union enetc_tx_bd *txbd;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci			txbd = ENETC_TXBD(*tx_ring, i);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci			if (txbd->flags & ENETC_TXBD_FLAGS_W &&
4198c2ecf20Sopenharmony_ci			    tx_swbd->do_tstamp) {
4208c2ecf20Sopenharmony_ci				enetc_get_tx_tstamp(&priv->si->hw, txbd,
4218c2ecf20Sopenharmony_ci						    &tstamp);
4228c2ecf20Sopenharmony_ci				do_tstamp = true;
4238c2ecf20Sopenharmony_ci			}
4248c2ecf20Sopenharmony_ci		}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		if (likely(tx_swbd->dma))
4278c2ecf20Sopenharmony_ci			enetc_unmap_tx_buff(tx_ring, tx_swbd);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci		if (is_eof) {
4308c2ecf20Sopenharmony_ci			if (unlikely(do_tstamp)) {
4318c2ecf20Sopenharmony_ci				enetc_tstamp_tx(tx_swbd->skb, tstamp);
4328c2ecf20Sopenharmony_ci				do_tstamp = false;
4338c2ecf20Sopenharmony_ci			}
4348c2ecf20Sopenharmony_ci			napi_consume_skb(tx_swbd->skb, napi_budget);
4358c2ecf20Sopenharmony_ci			tx_swbd->skb = NULL;
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		tx_byte_cnt += tx_swbd->len;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci		bds_to_clean--;
4418c2ecf20Sopenharmony_ci		tx_swbd++;
4428c2ecf20Sopenharmony_ci		i++;
4438c2ecf20Sopenharmony_ci		if (unlikely(i == tx_ring->bd_count)) {
4448c2ecf20Sopenharmony_ci			i = 0;
4458c2ecf20Sopenharmony_ci			tx_swbd = tx_ring->tx_swbd;
4468c2ecf20Sopenharmony_ci		}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		/* BD iteration loop end */
4498c2ecf20Sopenharmony_ci		if (is_eof) {
4508c2ecf20Sopenharmony_ci			tx_frm_cnt++;
4518c2ecf20Sopenharmony_ci			/* re-arm interrupt source */
4528c2ecf20Sopenharmony_ci			enetc_wr_reg_hot(tx_ring->idr, BIT(tx_ring->index) |
4538c2ecf20Sopenharmony_ci					 BIT(16 + tx_ring->index));
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		if (unlikely(!bds_to_clean))
4578c2ecf20Sopenharmony_ci			bds_to_clean = enetc_bd_ready_count(tx_ring, i);
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	tx_ring->next_to_clean = i;
4618c2ecf20Sopenharmony_ci	tx_ring->stats.packets += tx_frm_cnt;
4628c2ecf20Sopenharmony_ci	tx_ring->stats.bytes += tx_byte_cnt;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (unlikely(tx_frm_cnt && netif_carrier_ok(ndev) &&
4658c2ecf20Sopenharmony_ci		     __netif_subqueue_stopped(ndev, tx_ring->index) &&
4668c2ecf20Sopenharmony_ci		     (enetc_bd_unused(tx_ring) >= ENETC_TXBDS_MAX_NEEDED))) {
4678c2ecf20Sopenharmony_ci		netif_wake_subqueue(ndev, tx_ring->index);
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return tx_frm_cnt != ENETC_DEFAULT_TX_WORK;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic bool enetc_new_page(struct enetc_bdr *rx_ring,
4748c2ecf20Sopenharmony_ci			   struct enetc_rx_swbd *rx_swbd)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct page *page;
4778c2ecf20Sopenharmony_ci	dma_addr_t addr;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	page = dev_alloc_page();
4808c2ecf20Sopenharmony_ci	if (unlikely(!page))
4818c2ecf20Sopenharmony_ci		return false;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	addr = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
4848c2ecf20Sopenharmony_ci	if (unlikely(dma_mapping_error(rx_ring->dev, addr))) {
4858c2ecf20Sopenharmony_ci		__free_page(page);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		return false;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	rx_swbd->dma = addr;
4918c2ecf20Sopenharmony_ci	rx_swbd->page = page;
4928c2ecf20Sopenharmony_ci	rx_swbd->page_offset = ENETC_RXB_PAD;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	return true;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct enetc_rx_swbd *rx_swbd;
5008c2ecf20Sopenharmony_ci	union enetc_rx_bd *rxbd;
5018c2ecf20Sopenharmony_ci	int i, j;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	i = rx_ring->next_to_use;
5048c2ecf20Sopenharmony_ci	rx_swbd = &rx_ring->rx_swbd[i];
5058c2ecf20Sopenharmony_ci	rxbd = enetc_rxbd(rx_ring, i);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	for (j = 0; j < buff_cnt; j++) {
5088c2ecf20Sopenharmony_ci		/* try reuse page */
5098c2ecf20Sopenharmony_ci		if (unlikely(!rx_swbd->page)) {
5108c2ecf20Sopenharmony_ci			if (unlikely(!enetc_new_page(rx_ring, rx_swbd))) {
5118c2ecf20Sopenharmony_ci				rx_ring->stats.rx_alloc_errs++;
5128c2ecf20Sopenharmony_ci				break;
5138c2ecf20Sopenharmony_ci			}
5148c2ecf20Sopenharmony_ci		}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		/* update RxBD */
5178c2ecf20Sopenharmony_ci		rxbd->w.addr = cpu_to_le64(rx_swbd->dma +
5188c2ecf20Sopenharmony_ci					   rx_swbd->page_offset);
5198c2ecf20Sopenharmony_ci		/* clear 'R" as well */
5208c2ecf20Sopenharmony_ci		rxbd->r.lstatus = 0;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci		rxbd = enetc_rxbd_next(rx_ring, rxbd, i);
5238c2ecf20Sopenharmony_ci		rx_swbd++;
5248c2ecf20Sopenharmony_ci		i++;
5258c2ecf20Sopenharmony_ci		if (unlikely(i == rx_ring->bd_count)) {
5268c2ecf20Sopenharmony_ci			i = 0;
5278c2ecf20Sopenharmony_ci			rx_swbd = rx_ring->rx_swbd;
5288c2ecf20Sopenharmony_ci		}
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (likely(j)) {
5328c2ecf20Sopenharmony_ci		rx_ring->next_to_alloc = i; /* keep track from page reuse */
5338c2ecf20Sopenharmony_ci		rx_ring->next_to_use = i;
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return j;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
5408c2ecf20Sopenharmony_cistatic void enetc_get_rx_tstamp(struct net_device *ndev,
5418c2ecf20Sopenharmony_ci				union enetc_rx_bd *rxbd,
5428c2ecf20Sopenharmony_ci				struct sk_buff *skb)
5438c2ecf20Sopenharmony_ci{
5448c2ecf20Sopenharmony_ci	struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
5458c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
5468c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
5478c2ecf20Sopenharmony_ci	u32 lo, hi, tstamp_lo;
5488c2ecf20Sopenharmony_ci	u64 tstamp;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) {
5518c2ecf20Sopenharmony_ci		lo = enetc_rd_reg_hot(hw->reg + ENETC_SICTR0);
5528c2ecf20Sopenharmony_ci		hi = enetc_rd_reg_hot(hw->reg + ENETC_SICTR1);
5538c2ecf20Sopenharmony_ci		rxbd = enetc_rxbd_ext(rxbd);
5548c2ecf20Sopenharmony_ci		tstamp_lo = le32_to_cpu(rxbd->ext.tstamp);
5558c2ecf20Sopenharmony_ci		if (lo <= tstamp_lo)
5568c2ecf20Sopenharmony_ci			hi -= 1;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci		tstamp = (u64)hi << 32 | tstamp_lo;
5598c2ecf20Sopenharmony_ci		memset(shhwtstamps, 0, sizeof(*shhwtstamps));
5608c2ecf20Sopenharmony_ci		shhwtstamps->hwtstamp = ns_to_ktime(tstamp);
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci#endif
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic void enetc_get_offloads(struct enetc_bdr *rx_ring,
5668c2ecf20Sopenharmony_ci			       union enetc_rx_bd *rxbd, struct sk_buff *skb)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	/* TODO: hashing */
5718c2ecf20Sopenharmony_ci	if (rx_ring->ndev->features & NETIF_F_RXCSUM) {
5728c2ecf20Sopenharmony_ci		u16 inet_csum = le16_to_cpu(rxbd->r.inet_csum);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		skb->csum = csum_unfold((__force __sum16)~htons(inet_csum));
5758c2ecf20Sopenharmony_ci		skb->ip_summed = CHECKSUM_COMPLETE;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN) {
5798c2ecf20Sopenharmony_ci		__be16 tpid = 0;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		switch (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TPID) {
5828c2ecf20Sopenharmony_ci		case 0:
5838c2ecf20Sopenharmony_ci			tpid = htons(ETH_P_8021Q);
5848c2ecf20Sopenharmony_ci			break;
5858c2ecf20Sopenharmony_ci		case 1:
5868c2ecf20Sopenharmony_ci			tpid = htons(ETH_P_8021AD);
5878c2ecf20Sopenharmony_ci			break;
5888c2ecf20Sopenharmony_ci		case 2:
5898c2ecf20Sopenharmony_ci			tpid = htons(enetc_port_rd(&priv->si->hw,
5908c2ecf20Sopenharmony_ci						   ENETC_PCVLANR1));
5918c2ecf20Sopenharmony_ci			break;
5928c2ecf20Sopenharmony_ci		case 3:
5938c2ecf20Sopenharmony_ci			tpid = htons(enetc_port_rd(&priv->si->hw,
5948c2ecf20Sopenharmony_ci						   ENETC_PCVLANR2));
5958c2ecf20Sopenharmony_ci			break;
5968c2ecf20Sopenharmony_ci		default:
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, tpid, le16_to_cpu(rxbd->r.vlan_opt));
6018c2ecf20Sopenharmony_ci	}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
6048c2ecf20Sopenharmony_ci	if (priv->active_offloads & ENETC_F_RX_TSTAMP)
6058c2ecf20Sopenharmony_ci		enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb);
6068c2ecf20Sopenharmony_ci#endif
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic void enetc_process_skb(struct enetc_bdr *rx_ring,
6108c2ecf20Sopenharmony_ci			      struct sk_buff *skb)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	skb_record_rx_queue(skb, rx_ring->index);
6138c2ecf20Sopenharmony_ci	skb->protocol = eth_type_trans(skb, rx_ring->ndev);
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic bool enetc_page_reusable(struct page *page)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	return (!page_is_pfmemalloc(page) && page_ref_count(page) == 1);
6198c2ecf20Sopenharmony_ci}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_cistatic void enetc_reuse_page(struct enetc_bdr *rx_ring,
6228c2ecf20Sopenharmony_ci			     struct enetc_rx_swbd *old)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	struct enetc_rx_swbd *new;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	new = &rx_ring->rx_swbd[rx_ring->next_to_alloc];
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	/* next buf that may reuse a page */
6298c2ecf20Sopenharmony_ci	enetc_bdr_idx_inc(rx_ring, &rx_ring->next_to_alloc);
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	/* copy page reference */
6328c2ecf20Sopenharmony_ci	*new = *old;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic struct enetc_rx_swbd *enetc_get_rx_buff(struct enetc_bdr *rx_ring,
6368c2ecf20Sopenharmony_ci					       int i, u16 size)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct enetc_rx_swbd *rx_swbd = &rx_ring->rx_swbd[i];
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	dma_sync_single_range_for_cpu(rx_ring->dev, rx_swbd->dma,
6418c2ecf20Sopenharmony_ci				      rx_swbd->page_offset,
6428c2ecf20Sopenharmony_ci				      size, DMA_FROM_DEVICE);
6438c2ecf20Sopenharmony_ci	return rx_swbd;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic void enetc_put_rx_buff(struct enetc_bdr *rx_ring,
6478c2ecf20Sopenharmony_ci			      struct enetc_rx_swbd *rx_swbd)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	if (likely(enetc_page_reusable(rx_swbd->page))) {
6508c2ecf20Sopenharmony_ci		rx_swbd->page_offset ^= ENETC_RXB_TRUESIZE;
6518c2ecf20Sopenharmony_ci		page_ref_inc(rx_swbd->page);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		enetc_reuse_page(rx_ring, rx_swbd);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci		/* sync for use by the device */
6568c2ecf20Sopenharmony_ci		dma_sync_single_range_for_device(rx_ring->dev, rx_swbd->dma,
6578c2ecf20Sopenharmony_ci						 rx_swbd->page_offset,
6588c2ecf20Sopenharmony_ci						 ENETC_RXB_DMA_SIZE,
6598c2ecf20Sopenharmony_ci						 DMA_FROM_DEVICE);
6608c2ecf20Sopenharmony_ci	} else {
6618c2ecf20Sopenharmony_ci		dma_unmap_page(rx_ring->dev, rx_swbd->dma,
6628c2ecf20Sopenharmony_ci			       PAGE_SIZE, DMA_FROM_DEVICE);
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	rx_swbd->page = NULL;
6668c2ecf20Sopenharmony_ci}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic struct sk_buff *enetc_map_rx_buff_to_skb(struct enetc_bdr *rx_ring,
6698c2ecf20Sopenharmony_ci						int i, u16 size)
6708c2ecf20Sopenharmony_ci{
6718c2ecf20Sopenharmony_ci	struct enetc_rx_swbd *rx_swbd = enetc_get_rx_buff(rx_ring, i, size);
6728c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6738c2ecf20Sopenharmony_ci	void *ba;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	ba = page_address(rx_swbd->page) + rx_swbd->page_offset;
6768c2ecf20Sopenharmony_ci	skb = build_skb(ba - ENETC_RXB_PAD, ENETC_RXB_TRUESIZE);
6778c2ecf20Sopenharmony_ci	if (unlikely(!skb)) {
6788c2ecf20Sopenharmony_ci		rx_ring->stats.rx_alloc_errs++;
6798c2ecf20Sopenharmony_ci		return NULL;
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	skb_reserve(skb, ENETC_RXB_PAD);
6838c2ecf20Sopenharmony_ci	__skb_put(skb, size);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	enetc_put_rx_buff(rx_ring, rx_swbd);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	return skb;
6888c2ecf20Sopenharmony_ci}
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_cistatic void enetc_add_rx_buff_to_skb(struct enetc_bdr *rx_ring, int i,
6918c2ecf20Sopenharmony_ci				     u16 size, struct sk_buff *skb)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	struct enetc_rx_swbd *rx_swbd = enetc_get_rx_buff(rx_ring, i, size);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_swbd->page,
6968c2ecf20Sopenharmony_ci			rx_swbd->page_offset, size, ENETC_RXB_TRUESIZE);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	enetc_put_rx_buff(rx_ring, rx_swbd);
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci#define ENETC_RXBD_BUNDLE 16 /* # of BDs to update at once */
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
7048c2ecf20Sopenharmony_ci			       struct napi_struct *napi, int work_limit)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	int rx_frm_cnt = 0, rx_byte_cnt = 0;
7078c2ecf20Sopenharmony_ci	int cleaned_cnt, i;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	cleaned_cnt = enetc_bd_unused(rx_ring);
7108c2ecf20Sopenharmony_ci	/* next descriptor to process */
7118c2ecf20Sopenharmony_ci	i = rx_ring->next_to_clean;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	while (likely(rx_frm_cnt < work_limit)) {
7148c2ecf20Sopenharmony_ci		union enetc_rx_bd *rxbd;
7158c2ecf20Sopenharmony_ci		struct sk_buff *skb;
7168c2ecf20Sopenharmony_ci		u32 bd_status;
7178c2ecf20Sopenharmony_ci		u16 size;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci		if (cleaned_cnt >= ENETC_RXBD_BUNDLE) {
7208c2ecf20Sopenharmony_ci			int count = enetc_refill_rx_ring(rx_ring, cleaned_cnt);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci			/* update ENETC's consumer index */
7238c2ecf20Sopenharmony_ci			enetc_wr_reg_hot(rx_ring->rcir, rx_ring->next_to_use);
7248c2ecf20Sopenharmony_ci			cleaned_cnt -= count;
7258c2ecf20Sopenharmony_ci		}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci		rxbd = enetc_rxbd(rx_ring, i);
7288c2ecf20Sopenharmony_ci		bd_status = le32_to_cpu(rxbd->r.lstatus);
7298c2ecf20Sopenharmony_ci		if (!bd_status)
7308c2ecf20Sopenharmony_ci			break;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci		enetc_wr_reg_hot(rx_ring->idr, BIT(rx_ring->index));
7338c2ecf20Sopenharmony_ci		dma_rmb(); /* for reading other rxbd fields */
7348c2ecf20Sopenharmony_ci		size = le16_to_cpu(rxbd->r.buf_len);
7358c2ecf20Sopenharmony_ci		skb = enetc_map_rx_buff_to_skb(rx_ring, i, size);
7368c2ecf20Sopenharmony_ci		if (!skb)
7378c2ecf20Sopenharmony_ci			break;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		enetc_get_offloads(rx_ring, rxbd, skb);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		cleaned_cnt++;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		rxbd = enetc_rxbd_next(rx_ring, rxbd, i);
7448c2ecf20Sopenharmony_ci		if (unlikely(++i == rx_ring->bd_count))
7458c2ecf20Sopenharmony_ci			i = 0;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		if (unlikely(bd_status &
7488c2ecf20Sopenharmony_ci			     ENETC_RXBD_LSTATUS(ENETC_RXBD_ERR_MASK))) {
7498c2ecf20Sopenharmony_ci			dev_kfree_skb(skb);
7508c2ecf20Sopenharmony_ci			while (!(bd_status & ENETC_RXBD_LSTATUS_F)) {
7518c2ecf20Sopenharmony_ci				dma_rmb();
7528c2ecf20Sopenharmony_ci				bd_status = le32_to_cpu(rxbd->r.lstatus);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci				rxbd = enetc_rxbd_next(rx_ring, rxbd, i);
7558c2ecf20Sopenharmony_ci				if (unlikely(++i == rx_ring->bd_count))
7568c2ecf20Sopenharmony_ci					i = 0;
7578c2ecf20Sopenharmony_ci			}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci			rx_ring->ndev->stats.rx_dropped++;
7608c2ecf20Sopenharmony_ci			rx_ring->ndev->stats.rx_errors++;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci			break;
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci		/* not last BD in frame? */
7668c2ecf20Sopenharmony_ci		while (!(bd_status & ENETC_RXBD_LSTATUS_F)) {
7678c2ecf20Sopenharmony_ci			bd_status = le32_to_cpu(rxbd->r.lstatus);
7688c2ecf20Sopenharmony_ci			size = ENETC_RXB_DMA_SIZE;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci			if (bd_status & ENETC_RXBD_LSTATUS_F) {
7718c2ecf20Sopenharmony_ci				dma_rmb();
7728c2ecf20Sopenharmony_ci				size = le16_to_cpu(rxbd->r.buf_len);
7738c2ecf20Sopenharmony_ci			}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci			enetc_add_rx_buff_to_skb(rx_ring, i, size, skb);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci			cleaned_cnt++;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci			rxbd = enetc_rxbd_next(rx_ring, rxbd, i);
7808c2ecf20Sopenharmony_ci			if (unlikely(++i == rx_ring->bd_count))
7818c2ecf20Sopenharmony_ci				i = 0;
7828c2ecf20Sopenharmony_ci		}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci		rx_byte_cnt += skb->len;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		enetc_process_skb(rx_ring, skb);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		napi_gro_receive(napi, skb);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci		rx_frm_cnt++;
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	rx_ring->next_to_clean = i;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	rx_ring->stats.packets += rx_frm_cnt;
7968c2ecf20Sopenharmony_ci	rx_ring->stats.bytes += rx_byte_cnt;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	return rx_frm_cnt;
7998c2ecf20Sopenharmony_ci}
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci/* Probing and Init */
8028c2ecf20Sopenharmony_ci#define ENETC_MAX_RFS_SIZE 64
8038c2ecf20Sopenharmony_civoid enetc_get_si_caps(struct enetc_si *si)
8048c2ecf20Sopenharmony_ci{
8058c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
8068c2ecf20Sopenharmony_ci	u32 val;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	/* find out how many of various resources we have to work with */
8098c2ecf20Sopenharmony_ci	val = enetc_rd(hw, ENETC_SICAPR0);
8108c2ecf20Sopenharmony_ci	si->num_rx_rings = (val >> 16) & 0xff;
8118c2ecf20Sopenharmony_ci	si->num_tx_rings = val & 0xff;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	val = enetc_rd(hw, ENETC_SIRFSCAPR);
8148c2ecf20Sopenharmony_ci	si->num_fs_entries = ENETC_SIRFSCAPR_GET_NUM_RFS(val);
8158c2ecf20Sopenharmony_ci	si->num_fs_entries = min(si->num_fs_entries, ENETC_MAX_RFS_SIZE);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	si->num_rss = 0;
8188c2ecf20Sopenharmony_ci	val = enetc_rd(hw, ENETC_SIPCAPR0);
8198c2ecf20Sopenharmony_ci	if (val & ENETC_SIPCAPR0_RSS) {
8208c2ecf20Sopenharmony_ci		u32 rss;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci		rss = enetc_rd(hw, ENETC_SIRSSCAPR);
8238c2ecf20Sopenharmony_ci		si->num_rss = ENETC_SIRSSCAPR_GET_NUM_RSS(rss);
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (val & ENETC_SIPCAPR0_QBV)
8278c2ecf20Sopenharmony_ci		si->hw_features |= ENETC_SI_F_QBV;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if (val & ENETC_SIPCAPR0_PSFP)
8308c2ecf20Sopenharmony_ci		si->hw_features |= ENETC_SI_F_PSFP;
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic int enetc_dma_alloc_bdr(struct enetc_bdr *r, size_t bd_size)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	r->bd_base = dma_alloc_coherent(r->dev, r->bd_count * bd_size,
8368c2ecf20Sopenharmony_ci					&r->bd_dma_base, GFP_KERNEL);
8378c2ecf20Sopenharmony_ci	if (!r->bd_base)
8388c2ecf20Sopenharmony_ci		return -ENOMEM;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	/* h/w requires 128B alignment */
8418c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(r->bd_dma_base, 128)) {
8428c2ecf20Sopenharmony_ci		dma_free_coherent(r->dev, r->bd_count * bd_size, r->bd_base,
8438c2ecf20Sopenharmony_ci				  r->bd_dma_base);
8448c2ecf20Sopenharmony_ci		return -EINVAL;
8458c2ecf20Sopenharmony_ci	}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	return 0;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic int enetc_alloc_txbdr(struct enetc_bdr *txr)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	int err;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	txr->tx_swbd = vzalloc(txr->bd_count * sizeof(struct enetc_tx_swbd));
8558c2ecf20Sopenharmony_ci	if (!txr->tx_swbd)
8568c2ecf20Sopenharmony_ci		return -ENOMEM;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	err = enetc_dma_alloc_bdr(txr, sizeof(union enetc_tx_bd));
8598c2ecf20Sopenharmony_ci	if (err) {
8608c2ecf20Sopenharmony_ci		vfree(txr->tx_swbd);
8618c2ecf20Sopenharmony_ci		return err;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	txr->next_to_clean = 0;
8658c2ecf20Sopenharmony_ci	txr->next_to_use = 0;
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	return 0;
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_cistatic void enetc_free_txbdr(struct enetc_bdr *txr)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	int size, i;
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	for (i = 0; i < txr->bd_count; i++)
8758c2ecf20Sopenharmony_ci		enetc_free_tx_skb(txr, &txr->tx_swbd[i]);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	size = txr->bd_count * sizeof(union enetc_tx_bd);
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	dma_free_coherent(txr->dev, size, txr->bd_base, txr->bd_dma_base);
8808c2ecf20Sopenharmony_ci	txr->bd_base = NULL;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	vfree(txr->tx_swbd);
8838c2ecf20Sopenharmony_ci	txr->tx_swbd = NULL;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int enetc_alloc_tx_resources(struct enetc_ndev_priv *priv)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	int i, err;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++) {
8918c2ecf20Sopenharmony_ci		err = enetc_alloc_txbdr(priv->tx_ring[i]);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		if (err)
8948c2ecf20Sopenharmony_ci			goto fail;
8958c2ecf20Sopenharmony_ci	}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	return 0;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cifail:
9008c2ecf20Sopenharmony_ci	while (i-- > 0)
9018c2ecf20Sopenharmony_ci		enetc_free_txbdr(priv->tx_ring[i]);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	return err;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic void enetc_free_tx_resources(struct enetc_ndev_priv *priv)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	int i;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
9118c2ecf20Sopenharmony_ci		enetc_free_txbdr(priv->tx_ring[i]);
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic int enetc_alloc_rxbdr(struct enetc_bdr *rxr, bool extended)
9158c2ecf20Sopenharmony_ci{
9168c2ecf20Sopenharmony_ci	size_t size = sizeof(union enetc_rx_bd);
9178c2ecf20Sopenharmony_ci	int err;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	rxr->rx_swbd = vzalloc(rxr->bd_count * sizeof(struct enetc_rx_swbd));
9208c2ecf20Sopenharmony_ci	if (!rxr->rx_swbd)
9218c2ecf20Sopenharmony_ci		return -ENOMEM;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	if (extended)
9248c2ecf20Sopenharmony_ci		size *= 2;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	err = enetc_dma_alloc_bdr(rxr, size);
9278c2ecf20Sopenharmony_ci	if (err) {
9288c2ecf20Sopenharmony_ci		vfree(rxr->rx_swbd);
9298c2ecf20Sopenharmony_ci		return err;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	rxr->next_to_clean = 0;
9338c2ecf20Sopenharmony_ci	rxr->next_to_use = 0;
9348c2ecf20Sopenharmony_ci	rxr->next_to_alloc = 0;
9358c2ecf20Sopenharmony_ci	rxr->ext_en = extended;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	return 0;
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic void enetc_free_rxbdr(struct enetc_bdr *rxr)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	int size;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	size = rxr->bd_count * sizeof(union enetc_rx_bd);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	dma_free_coherent(rxr->dev, size, rxr->bd_base, rxr->bd_dma_base);
9478c2ecf20Sopenharmony_ci	rxr->bd_base = NULL;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	vfree(rxr->rx_swbd);
9508c2ecf20Sopenharmony_ci	rxr->rx_swbd = NULL;
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_cistatic int enetc_alloc_rx_resources(struct enetc_ndev_priv *priv)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	bool extended = !!(priv->active_offloads & ENETC_F_RX_TSTAMP);
9568c2ecf20Sopenharmony_ci	int i, err;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++) {
9598c2ecf20Sopenharmony_ci		err = enetc_alloc_rxbdr(priv->rx_ring[i], extended);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci		if (err)
9628c2ecf20Sopenharmony_ci			goto fail;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	return 0;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_cifail:
9688c2ecf20Sopenharmony_ci	while (i-- > 0)
9698c2ecf20Sopenharmony_ci		enetc_free_rxbdr(priv->rx_ring[i]);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	return err;
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_cistatic void enetc_free_rx_resources(struct enetc_ndev_priv *priv)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	int i;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
9798c2ecf20Sopenharmony_ci		enetc_free_rxbdr(priv->rx_ring[i]);
9808c2ecf20Sopenharmony_ci}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_cistatic void enetc_free_tx_ring(struct enetc_bdr *tx_ring)
9838c2ecf20Sopenharmony_ci{
9848c2ecf20Sopenharmony_ci	int i;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	if (!tx_ring->tx_swbd)
9878c2ecf20Sopenharmony_ci		return;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	for (i = 0; i < tx_ring->bd_count; i++) {
9908c2ecf20Sopenharmony_ci		struct enetc_tx_swbd *tx_swbd = &tx_ring->tx_swbd[i];
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci		enetc_free_tx_skb(tx_ring, tx_swbd);
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	tx_ring->next_to_clean = 0;
9968c2ecf20Sopenharmony_ci	tx_ring->next_to_use = 0;
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_cistatic void enetc_free_rx_ring(struct enetc_bdr *rx_ring)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	int i;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	if (!rx_ring->rx_swbd)
10048c2ecf20Sopenharmony_ci		return;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	for (i = 0; i < rx_ring->bd_count; i++) {
10078c2ecf20Sopenharmony_ci		struct enetc_rx_swbd *rx_swbd = &rx_ring->rx_swbd[i];
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		if (!rx_swbd->page)
10108c2ecf20Sopenharmony_ci			continue;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci		dma_unmap_page(rx_ring->dev, rx_swbd->dma,
10138c2ecf20Sopenharmony_ci			       PAGE_SIZE, DMA_FROM_DEVICE);
10148c2ecf20Sopenharmony_ci		__free_page(rx_swbd->page);
10158c2ecf20Sopenharmony_ci		rx_swbd->page = NULL;
10168c2ecf20Sopenharmony_ci	}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	rx_ring->next_to_clean = 0;
10198c2ecf20Sopenharmony_ci	rx_ring->next_to_use = 0;
10208c2ecf20Sopenharmony_ci	rx_ring->next_to_alloc = 0;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic void enetc_free_rxtx_rings(struct enetc_ndev_priv *priv)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	int i;
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
10288c2ecf20Sopenharmony_ci		enetc_free_rx_ring(priv->rx_ring[i]);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
10318c2ecf20Sopenharmony_ci		enetc_free_tx_ring(priv->tx_ring[i]);
10328c2ecf20Sopenharmony_ci}
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ciint enetc_alloc_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
10358c2ecf20Sopenharmony_ci{
10368c2ecf20Sopenharmony_ci	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	cbdr->bd_base = dma_alloc_coherent(dev, size, &cbdr->bd_dma_base,
10398c2ecf20Sopenharmony_ci					   GFP_KERNEL);
10408c2ecf20Sopenharmony_ci	if (!cbdr->bd_base)
10418c2ecf20Sopenharmony_ci		return -ENOMEM;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	/* h/w requires 128B alignment */
10448c2ecf20Sopenharmony_ci	if (!IS_ALIGNED(cbdr->bd_dma_base, 128)) {
10458c2ecf20Sopenharmony_ci		dma_free_coherent(dev, size, cbdr->bd_base, cbdr->bd_dma_base);
10468c2ecf20Sopenharmony_ci		return -EINVAL;
10478c2ecf20Sopenharmony_ci	}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	cbdr->next_to_clean = 0;
10508c2ecf20Sopenharmony_ci	cbdr->next_to_use = 0;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	return 0;
10538c2ecf20Sopenharmony_ci}
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_civoid enetc_free_cbdr(struct device *dev, struct enetc_cbdr *cbdr)
10568c2ecf20Sopenharmony_ci{
10578c2ecf20Sopenharmony_ci	int size = cbdr->bd_count * sizeof(struct enetc_cbd);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	dma_free_coherent(dev, size, cbdr->bd_base, cbdr->bd_dma_base);
10608c2ecf20Sopenharmony_ci	cbdr->bd_base = NULL;
10618c2ecf20Sopenharmony_ci}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_civoid enetc_setup_cbdr(struct enetc_hw *hw, struct enetc_cbdr *cbdr)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	/* set CBDR cache attributes */
10668c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICAR2,
10678c2ecf20Sopenharmony_ci		 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRBAR0, lower_32_bits(cbdr->bd_dma_base));
10708c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRBAR1, upper_32_bits(cbdr->bd_dma_base));
10718c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRLENR, ENETC_RTBLENR_LEN(cbdr->bd_count));
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRPIR, 0);
10748c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRCIR, 0);
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	/* enable ring */
10778c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRMR, BIT(31));
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	cbdr->pir = hw->reg + ENETC_SICBDRPIR;
10808c2ecf20Sopenharmony_ci	cbdr->cir = hw->reg + ENETC_SICBDRCIR;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_civoid enetc_clear_cbdr(struct enetc_hw *hw)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICBDRMR, 0);
10868c2ecf20Sopenharmony_ci}
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_cistatic int enetc_setup_default_rss_table(struct enetc_si *si, int num_groups)
10898c2ecf20Sopenharmony_ci{
10908c2ecf20Sopenharmony_ci	int *rss_table;
10918c2ecf20Sopenharmony_ci	int i;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	rss_table = kmalloc_array(si->num_rss, sizeof(*rss_table), GFP_KERNEL);
10948c2ecf20Sopenharmony_ci	if (!rss_table)
10958c2ecf20Sopenharmony_ci		return -ENOMEM;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	/* Set up RSS table defaults */
10988c2ecf20Sopenharmony_ci	for (i = 0; i < si->num_rss; i++)
10998c2ecf20Sopenharmony_ci		rss_table[i] = i % num_groups;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	enetc_set_rss_table(si, rss_table, si->num_rss);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	kfree(rss_table);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	return 0;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ciint enetc_configure_si(struct enetc_ndev_priv *priv)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	struct enetc_si *si = priv->si;
11118c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
11128c2ecf20Sopenharmony_ci	int err;
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	/* set SI cache attributes */
11158c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICAR0,
11168c2ecf20Sopenharmony_ci		 ENETC_SICAR_RD_COHERENT | ENETC_SICAR_WR_COHERENT);
11178c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SICAR1, ENETC_SICAR_MSI);
11188c2ecf20Sopenharmony_ci	/* enable SI */
11198c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SIMR, ENETC_SIMR_EN);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	if (si->num_rss) {
11228c2ecf20Sopenharmony_ci		err = enetc_setup_default_rss_table(si, priv->num_rx_rings);
11238c2ecf20Sopenharmony_ci		if (err)
11248c2ecf20Sopenharmony_ci			return err;
11258c2ecf20Sopenharmony_ci	}
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci	return 0;
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_civoid enetc_init_si_rings_params(struct enetc_ndev_priv *priv)
11318c2ecf20Sopenharmony_ci{
11328c2ecf20Sopenharmony_ci	struct enetc_si *si = priv->si;
11338c2ecf20Sopenharmony_ci	int cpus = num_online_cpus();
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	priv->tx_bd_count = ENETC_TX_RING_DEFAULT_SIZE;
11368c2ecf20Sopenharmony_ci	priv->rx_bd_count = ENETC_RX_RING_DEFAULT_SIZE;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	/* Enable all available TX rings in order to configure as many
11398c2ecf20Sopenharmony_ci	 * priorities as possible, when needed.
11408c2ecf20Sopenharmony_ci	 * TODO: Make # of TX rings run-time configurable
11418c2ecf20Sopenharmony_ci	 */
11428c2ecf20Sopenharmony_ci	priv->num_rx_rings = min_t(int, cpus, si->num_rx_rings);
11438c2ecf20Sopenharmony_ci	priv->num_tx_rings = si->num_tx_rings;
11448c2ecf20Sopenharmony_ci	priv->bdr_int_num = cpus;
11458c2ecf20Sopenharmony_ci	priv->ic_mode = ENETC_IC_RX_ADAPTIVE | ENETC_IC_TX_MANUAL;
11468c2ecf20Sopenharmony_ci	priv->tx_ictt = ENETC_TXIC_TIMETHR;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/* SI specific */
11498c2ecf20Sopenharmony_ci	si->cbd_ring.bd_count = ENETC_CBDR_DEFAULT_SIZE;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ciint enetc_alloc_si_resources(struct enetc_ndev_priv *priv)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	struct enetc_si *si = priv->si;
11558c2ecf20Sopenharmony_ci	int err;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	err = enetc_alloc_cbdr(priv->dev, &si->cbd_ring);
11588c2ecf20Sopenharmony_ci	if (err)
11598c2ecf20Sopenharmony_ci		return err;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	enetc_setup_cbdr(&si->hw, &si->cbd_ring);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	priv->cls_rules = kcalloc(si->num_fs_entries, sizeof(*priv->cls_rules),
11648c2ecf20Sopenharmony_ci				  GFP_KERNEL);
11658c2ecf20Sopenharmony_ci	if (!priv->cls_rules) {
11668c2ecf20Sopenharmony_ci		err = -ENOMEM;
11678c2ecf20Sopenharmony_ci		goto err_alloc_cls;
11688c2ecf20Sopenharmony_ci	}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	return 0;
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cierr_alloc_cls:
11738c2ecf20Sopenharmony_ci	enetc_clear_cbdr(&si->hw);
11748c2ecf20Sopenharmony_ci	enetc_free_cbdr(priv->dev, &si->cbd_ring);
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	return err;
11778c2ecf20Sopenharmony_ci}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_civoid enetc_free_si_resources(struct enetc_ndev_priv *priv)
11808c2ecf20Sopenharmony_ci{
11818c2ecf20Sopenharmony_ci	struct enetc_si *si = priv->si;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	enetc_clear_cbdr(&si->hw);
11848c2ecf20Sopenharmony_ci	enetc_free_cbdr(priv->dev, &si->cbd_ring);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	kfree(priv->cls_rules);
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
11908c2ecf20Sopenharmony_ci{
11918c2ecf20Sopenharmony_ci	int idx = tx_ring->index;
11928c2ecf20Sopenharmony_ci	u32 tbmr;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	enetc_txbdr_wr(hw, idx, ENETC_TBBAR0,
11958c2ecf20Sopenharmony_ci		       lower_32_bits(tx_ring->bd_dma_base));
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	enetc_txbdr_wr(hw, idx, ENETC_TBBAR1,
11988c2ecf20Sopenharmony_ci		       upper_32_bits(tx_ring->bd_dma_base));
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	WARN_ON(!IS_ALIGNED(tx_ring->bd_count, 64)); /* multiple of 64 */
12018c2ecf20Sopenharmony_ci	enetc_txbdr_wr(hw, idx, ENETC_TBLENR,
12028c2ecf20Sopenharmony_ci		       ENETC_RTBLENR_LEN(tx_ring->bd_count));
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	/* clearing PI/CI registers for Tx not supported, adjust sw indexes */
12058c2ecf20Sopenharmony_ci	tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR);
12068c2ecf20Sopenharmony_ci	tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	/* enable Tx ints by setting pkt thr to 1 */
12098c2ecf20Sopenharmony_ci	enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	tbmr = ENETC_TBMR_EN | ENETC_TBMR_SET_PRIO(tx_ring->prio);
12128c2ecf20Sopenharmony_ci	if (tx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_TX)
12138c2ecf20Sopenharmony_ci		tbmr |= ENETC_TBMR_VIH;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	/* enable ring */
12168c2ecf20Sopenharmony_ci	enetc_txbdr_wr(hw, idx, ENETC_TBMR, tbmr);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	tx_ring->tpir = hw->reg + ENETC_BDR(TX, idx, ENETC_TBPIR);
12198c2ecf20Sopenharmony_ci	tx_ring->tcir = hw->reg + ENETC_BDR(TX, idx, ENETC_TBCIR);
12208c2ecf20Sopenharmony_ci	tx_ring->idr = hw->reg + ENETC_SITXIDR;
12218c2ecf20Sopenharmony_ci}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_cistatic void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	int idx = rx_ring->index;
12268c2ecf20Sopenharmony_ci	u32 rbmr;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBBAR0,
12298c2ecf20Sopenharmony_ci		       lower_32_bits(rx_ring->bd_dma_base));
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBBAR1,
12328c2ecf20Sopenharmony_ci		       upper_32_bits(rx_ring->bd_dma_base));
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	WARN_ON(!IS_ALIGNED(rx_ring->bd_count, 64)); /* multiple of 64 */
12358c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBLENR,
12368c2ecf20Sopenharmony_ci		       ENETC_RTBLENR_LEN(rx_ring->bd_count));
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBBSR, ENETC_RXB_DMA_SIZE);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	/* Also prepare the consumer index in case page allocation never
12418c2ecf20Sopenharmony_ci	 * succeeds. In that case, hardware will never advance producer index
12428c2ecf20Sopenharmony_ci	 * to match consumer index, and will drop all frames.
12438c2ecf20Sopenharmony_ci	 */
12448c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBPIR, 0);
12458c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, 1);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	/* enable Rx ints by setting pkt thr to 1 */
12488c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBICR0, ENETC_RBICR0_ICEN | 0x1);
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	rbmr = ENETC_RBMR_EN;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	if (rx_ring->ext_en)
12538c2ecf20Sopenharmony_ci		rbmr |= ENETC_RBMR_BDS;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
12568c2ecf20Sopenharmony_ci		rbmr |= ENETC_RBMR_VTE;
12578c2ecf20Sopenharmony_ci
12588c2ecf20Sopenharmony_ci	rx_ring->rcir = hw->reg + ENETC_BDR(RX, idx, ENETC_RBCIR);
12598c2ecf20Sopenharmony_ci	rx_ring->idr = hw->reg + ENETC_SIRXIDR;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	enetc_refill_rx_ring(rx_ring, enetc_bd_unused(rx_ring));
12628c2ecf20Sopenharmony_ci	/* update ENETC's consumer index */
12638c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBCIR, rx_ring->next_to_use);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	/* enable ring */
12668c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBMR, rbmr);
12678c2ecf20Sopenharmony_ci}
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_cistatic void enetc_setup_bdrs(struct enetc_ndev_priv *priv)
12708c2ecf20Sopenharmony_ci{
12718c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
12728c2ecf20Sopenharmony_ci	int i;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
12758c2ecf20Sopenharmony_ci		enetc_setup_txbdr(hw, priv->tx_ring[i]);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
12788c2ecf20Sopenharmony_ci		enetc_setup_rxbdr(hw, priv->rx_ring[i]);
12798c2ecf20Sopenharmony_ci}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_cistatic void enetc_clear_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
12828c2ecf20Sopenharmony_ci{
12838c2ecf20Sopenharmony_ci	int idx = rx_ring->index;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	/* disable EN bit on ring */
12868c2ecf20Sopenharmony_ci	enetc_rxbdr_wr(hw, idx, ENETC_RBMR, 0);
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_cistatic void enetc_clear_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	int delay = 8, timeout = 100;
12928c2ecf20Sopenharmony_ci	int idx = tx_ring->index;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	/* disable EN bit on ring */
12958c2ecf20Sopenharmony_ci	enetc_txbdr_wr(hw, idx, ENETC_TBMR, 0);
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	/* wait for busy to clear */
12988c2ecf20Sopenharmony_ci	while (delay < timeout &&
12998c2ecf20Sopenharmony_ci	       enetc_txbdr_rd(hw, idx, ENETC_TBSR) & ENETC_TBSR_BUSY) {
13008c2ecf20Sopenharmony_ci		msleep(delay);
13018c2ecf20Sopenharmony_ci		delay *= 2;
13028c2ecf20Sopenharmony_ci	}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	if (delay >= timeout)
13058c2ecf20Sopenharmony_ci		netdev_warn(tx_ring->ndev, "timeout for tx ring #%d clear\n",
13068c2ecf20Sopenharmony_ci			    idx);
13078c2ecf20Sopenharmony_ci}
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic void enetc_clear_bdrs(struct enetc_ndev_priv *priv)
13108c2ecf20Sopenharmony_ci{
13118c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
13128c2ecf20Sopenharmony_ci	int i;
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
13158c2ecf20Sopenharmony_ci		enetc_clear_txbdr(hw, priv->tx_ring[i]);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
13188c2ecf20Sopenharmony_ci		enetc_clear_rxbdr(hw, priv->rx_ring[i]);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	udelay(1);
13218c2ecf20Sopenharmony_ci}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_cistatic int enetc_setup_irqs(struct enetc_ndev_priv *priv)
13248c2ecf20Sopenharmony_ci{
13258c2ecf20Sopenharmony_ci	struct pci_dev *pdev = priv->si->pdev;
13268c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
13278c2ecf20Sopenharmony_ci	int i, j, err;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
13308c2ecf20Sopenharmony_ci		int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i);
13318c2ecf20Sopenharmony_ci		struct enetc_int_vector *v = priv->int_vector[i];
13328c2ecf20Sopenharmony_ci		int entry = ENETC_BDR_INT_BASE_IDX + i;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		snprintf(v->name, sizeof(v->name), "%s-rxtx%d",
13358c2ecf20Sopenharmony_ci			 priv->ndev->name, i);
13368c2ecf20Sopenharmony_ci		err = request_irq(irq, enetc_msix, 0, v->name, v);
13378c2ecf20Sopenharmony_ci		if (err) {
13388c2ecf20Sopenharmony_ci			dev_err(priv->dev, "request_irq() failed!\n");
13398c2ecf20Sopenharmony_ci			goto irq_err;
13408c2ecf20Sopenharmony_ci		}
13418c2ecf20Sopenharmony_ci		disable_irq(irq);
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci		v->tbier_base = hw->reg + ENETC_BDR(TX, 0, ENETC_TBIER);
13448c2ecf20Sopenharmony_ci		v->rbier = hw->reg + ENETC_BDR(RX, i, ENETC_RBIER);
13458c2ecf20Sopenharmony_ci		v->ricr1 = hw->reg + ENETC_BDR(RX, i, ENETC_RBICR1);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci		enetc_wr(hw, ENETC_SIMSIRRV(i), entry);
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci		for (j = 0; j < v->count_tx_rings; j++) {
13508c2ecf20Sopenharmony_ci			int idx = v->tx_ring[j].index;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci			enetc_wr(hw, ENETC_SIMSITRV(idx), entry);
13538c2ecf20Sopenharmony_ci		}
13548c2ecf20Sopenharmony_ci		irq_set_affinity_hint(irq, get_cpu_mask(i % num_online_cpus()));
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	return 0;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ciirq_err:
13608c2ecf20Sopenharmony_ci	while (i--) {
13618c2ecf20Sopenharmony_ci		int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i);
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci		irq_set_affinity_hint(irq, NULL);
13648c2ecf20Sopenharmony_ci		free_irq(irq, priv->int_vector[i]);
13658c2ecf20Sopenharmony_ci	}
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	return err;
13688c2ecf20Sopenharmony_ci}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_cistatic void enetc_free_irqs(struct enetc_ndev_priv *priv)
13718c2ecf20Sopenharmony_ci{
13728c2ecf20Sopenharmony_ci	struct pci_dev *pdev = priv->si->pdev;
13738c2ecf20Sopenharmony_ci	int i;
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
13768c2ecf20Sopenharmony_ci		int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci		irq_set_affinity_hint(irq, NULL);
13798c2ecf20Sopenharmony_ci		free_irq(irq, priv->int_vector[i]);
13808c2ecf20Sopenharmony_ci	}
13818c2ecf20Sopenharmony_ci}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_cistatic void enetc_setup_interrupts(struct enetc_ndev_priv *priv)
13848c2ecf20Sopenharmony_ci{
13858c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
13868c2ecf20Sopenharmony_ci	u32 icpt, ictt;
13878c2ecf20Sopenharmony_ci	int i;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* enable Tx & Rx event indication */
13908c2ecf20Sopenharmony_ci	if (priv->ic_mode &
13918c2ecf20Sopenharmony_ci	    (ENETC_IC_RX_MANUAL | ENETC_IC_RX_ADAPTIVE)) {
13928c2ecf20Sopenharmony_ci		icpt = ENETC_RBICR0_SET_ICPT(ENETC_RXIC_PKTTHR);
13938c2ecf20Sopenharmony_ci		/* init to non-0 minimum, will be adjusted later */
13948c2ecf20Sopenharmony_ci		ictt = 0x1;
13958c2ecf20Sopenharmony_ci	} else {
13968c2ecf20Sopenharmony_ci		icpt = 0x1; /* enable Rx ints by setting pkt thr to 1 */
13978c2ecf20Sopenharmony_ci		ictt = 0;
13988c2ecf20Sopenharmony_ci	}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++) {
14018c2ecf20Sopenharmony_ci		enetc_rxbdr_wr(hw, i, ENETC_RBICR1, ictt);
14028c2ecf20Sopenharmony_ci		enetc_rxbdr_wr(hw, i, ENETC_RBICR0, ENETC_RBICR0_ICEN | icpt);
14038c2ecf20Sopenharmony_ci		enetc_rxbdr_wr(hw, i, ENETC_RBIER, ENETC_RBIER_RXTIE);
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci
14068c2ecf20Sopenharmony_ci	if (priv->ic_mode & ENETC_IC_TX_MANUAL)
14078c2ecf20Sopenharmony_ci		icpt = ENETC_TBICR0_SET_ICPT(ENETC_TXIC_PKTTHR);
14088c2ecf20Sopenharmony_ci	else
14098c2ecf20Sopenharmony_ci		icpt = 0x1; /* enable Tx ints by setting pkt thr to 1 */
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++) {
14128c2ecf20Sopenharmony_ci		enetc_txbdr_wr(hw, i, ENETC_TBICR1, priv->tx_ictt);
14138c2ecf20Sopenharmony_ci		enetc_txbdr_wr(hw, i, ENETC_TBICR0, ENETC_TBICR0_ICEN | icpt);
14148c2ecf20Sopenharmony_ci		enetc_txbdr_wr(hw, i, ENETC_TBIER, ENETC_TBIER_TXTIE);
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ci}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_cistatic void enetc_clear_interrupts(struct enetc_ndev_priv *priv)
14198c2ecf20Sopenharmony_ci{
14208c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
14218c2ecf20Sopenharmony_ci	int i;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
14248c2ecf20Sopenharmony_ci		enetc_txbdr_wr(hw, i, ENETC_TBIER, 0);
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
14278c2ecf20Sopenharmony_ci		enetc_rxbdr_wr(hw, i, ENETC_RBIER, 0);
14288c2ecf20Sopenharmony_ci}
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_cistatic int enetc_phylink_connect(struct net_device *ndev)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
14338c2ecf20Sopenharmony_ci	struct ethtool_eee edata;
14348c2ecf20Sopenharmony_ci	int err;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	if (!priv->phylink)
14378c2ecf20Sopenharmony_ci		return 0; /* phy-less mode */
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	err = phylink_of_phy_connect(priv->phylink, priv->dev->of_node, 0);
14408c2ecf20Sopenharmony_ci	if (err) {
14418c2ecf20Sopenharmony_ci		dev_err(&ndev->dev, "could not attach to PHY\n");
14428c2ecf20Sopenharmony_ci		return err;
14438c2ecf20Sopenharmony_ci	}
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	/* disable EEE autoneg, until ENETC driver supports it */
14468c2ecf20Sopenharmony_ci	memset(&edata, 0, sizeof(struct ethtool_eee));
14478c2ecf20Sopenharmony_ci	phylink_ethtool_set_eee(priv->phylink, &edata);
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	return 0;
14508c2ecf20Sopenharmony_ci}
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_civoid enetc_start(struct net_device *ndev)
14538c2ecf20Sopenharmony_ci{
14548c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
14558c2ecf20Sopenharmony_ci	int i;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	enetc_setup_interrupts(priv);
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
14608c2ecf20Sopenharmony_ci		int irq = pci_irq_vector(priv->si->pdev,
14618c2ecf20Sopenharmony_ci					 ENETC_BDR_INT_BASE_IDX + i);
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci		napi_enable(&priv->int_vector[i]->napi);
14648c2ecf20Sopenharmony_ci		enable_irq(irq);
14658c2ecf20Sopenharmony_ci	}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	if (priv->phylink)
14688c2ecf20Sopenharmony_ci		phylink_start(priv->phylink);
14698c2ecf20Sopenharmony_ci	else
14708c2ecf20Sopenharmony_ci		netif_carrier_on(ndev);
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	netif_tx_start_all_queues(ndev);
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ciint enetc_open(struct net_device *ndev)
14768c2ecf20Sopenharmony_ci{
14778c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
14788c2ecf20Sopenharmony_ci	int err;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	err = enetc_setup_irqs(priv);
14818c2ecf20Sopenharmony_ci	if (err)
14828c2ecf20Sopenharmony_ci		return err;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	err = enetc_phylink_connect(ndev);
14858c2ecf20Sopenharmony_ci	if (err)
14868c2ecf20Sopenharmony_ci		goto err_phy_connect;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	err = enetc_alloc_tx_resources(priv);
14898c2ecf20Sopenharmony_ci	if (err)
14908c2ecf20Sopenharmony_ci		goto err_alloc_tx;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	err = enetc_alloc_rx_resources(priv);
14938c2ecf20Sopenharmony_ci	if (err)
14948c2ecf20Sopenharmony_ci		goto err_alloc_rx;
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	err = netif_set_real_num_tx_queues(ndev, priv->num_tx_rings);
14978c2ecf20Sopenharmony_ci	if (err)
14988c2ecf20Sopenharmony_ci		goto err_set_queues;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	err = netif_set_real_num_rx_queues(ndev, priv->num_rx_rings);
15018c2ecf20Sopenharmony_ci	if (err)
15028c2ecf20Sopenharmony_ci		goto err_set_queues;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	enetc_setup_bdrs(priv);
15058c2ecf20Sopenharmony_ci	enetc_start(ndev);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	return 0;
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_cierr_set_queues:
15108c2ecf20Sopenharmony_ci	enetc_free_rx_resources(priv);
15118c2ecf20Sopenharmony_cierr_alloc_rx:
15128c2ecf20Sopenharmony_ci	enetc_free_tx_resources(priv);
15138c2ecf20Sopenharmony_cierr_alloc_tx:
15148c2ecf20Sopenharmony_ci	if (priv->phylink)
15158c2ecf20Sopenharmony_ci		phylink_disconnect_phy(priv->phylink);
15168c2ecf20Sopenharmony_cierr_phy_connect:
15178c2ecf20Sopenharmony_ci	enetc_free_irqs(priv);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	return err;
15208c2ecf20Sopenharmony_ci}
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_civoid enetc_stop(struct net_device *ndev)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
15258c2ecf20Sopenharmony_ci	int i;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(ndev);
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
15308c2ecf20Sopenharmony_ci		int irq = pci_irq_vector(priv->si->pdev,
15318c2ecf20Sopenharmony_ci					 ENETC_BDR_INT_BASE_IDX + i);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci		disable_irq(irq);
15348c2ecf20Sopenharmony_ci		napi_synchronize(&priv->int_vector[i]->napi);
15358c2ecf20Sopenharmony_ci		napi_disable(&priv->int_vector[i]->napi);
15368c2ecf20Sopenharmony_ci	}
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (priv->phylink)
15398c2ecf20Sopenharmony_ci		phylink_stop(priv->phylink);
15408c2ecf20Sopenharmony_ci	else
15418c2ecf20Sopenharmony_ci		netif_carrier_off(ndev);
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	enetc_clear_interrupts(priv);
15448c2ecf20Sopenharmony_ci}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ciint enetc_close(struct net_device *ndev)
15478c2ecf20Sopenharmony_ci{
15488c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	enetc_stop(ndev);
15518c2ecf20Sopenharmony_ci	enetc_clear_bdrs(priv);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	if (priv->phylink)
15548c2ecf20Sopenharmony_ci		phylink_disconnect_phy(priv->phylink);
15558c2ecf20Sopenharmony_ci	enetc_free_rxtx_rings(priv);
15568c2ecf20Sopenharmony_ci	enetc_free_rx_resources(priv);
15578c2ecf20Sopenharmony_ci	enetc_free_tx_resources(priv);
15588c2ecf20Sopenharmony_ci	enetc_free_irqs(priv);
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	return 0;
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_cistatic int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data)
15648c2ecf20Sopenharmony_ci{
15658c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
15668c2ecf20Sopenharmony_ci	struct tc_mqprio_qopt *mqprio = type_data;
15678c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
15688c2ecf20Sopenharmony_ci	struct enetc_bdr *tx_ring;
15698c2ecf20Sopenharmony_ci	u8 num_tc;
15708c2ecf20Sopenharmony_ci	int i;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS;
15738c2ecf20Sopenharmony_ci	num_tc = mqprio->num_tc;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	if (!num_tc) {
15768c2ecf20Sopenharmony_ci		netdev_reset_tc(ndev);
15778c2ecf20Sopenharmony_ci		netif_set_real_num_tx_queues(ndev, priv->num_tx_rings);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		/* Reset all ring priorities to 0 */
15808c2ecf20Sopenharmony_ci		for (i = 0; i < priv->num_tx_rings; i++) {
15818c2ecf20Sopenharmony_ci			tx_ring = priv->tx_ring[i];
15828c2ecf20Sopenharmony_ci			tx_ring->prio = 0;
15838c2ecf20Sopenharmony_ci			enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio);
15848c2ecf20Sopenharmony_ci		}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_ci		return 0;
15878c2ecf20Sopenharmony_ci	}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	/* Check if we have enough BD rings available to accommodate all TCs */
15908c2ecf20Sopenharmony_ci	if (num_tc > priv->num_tx_rings) {
15918c2ecf20Sopenharmony_ci		netdev_err(ndev, "Max %d traffic classes supported\n",
15928c2ecf20Sopenharmony_ci			   priv->num_tx_rings);
15938c2ecf20Sopenharmony_ci		return -EINVAL;
15948c2ecf20Sopenharmony_ci	}
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	/* For the moment, we use only one BD ring per TC.
15978c2ecf20Sopenharmony_ci	 *
15988c2ecf20Sopenharmony_ci	 * Configure num_tc BD rings with increasing priorities.
15998c2ecf20Sopenharmony_ci	 */
16008c2ecf20Sopenharmony_ci	for (i = 0; i < num_tc; i++) {
16018c2ecf20Sopenharmony_ci		tx_ring = priv->tx_ring[i];
16028c2ecf20Sopenharmony_ci		tx_ring->prio = i;
16038c2ecf20Sopenharmony_ci		enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio);
16048c2ecf20Sopenharmony_ci	}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	/* Reset the number of netdev queues based on the TC count */
16078c2ecf20Sopenharmony_ci	netif_set_real_num_tx_queues(ndev, num_tc);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	netdev_set_num_tc(ndev, num_tc);
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	/* Each TC is associated with one netdev queue */
16128c2ecf20Sopenharmony_ci	for (i = 0; i < num_tc; i++)
16138c2ecf20Sopenharmony_ci		netdev_set_tc_queue(ndev, i, 1, i);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	return 0;
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ciint enetc_setup_tc(struct net_device *ndev, enum tc_setup_type type,
16198c2ecf20Sopenharmony_ci		   void *type_data)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	switch (type) {
16228c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO:
16238c2ecf20Sopenharmony_ci		return enetc_setup_tc_mqprio(ndev, type_data);
16248c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_TAPRIO:
16258c2ecf20Sopenharmony_ci		return enetc_setup_tc_taprio(ndev, type_data);
16268c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_CBS:
16278c2ecf20Sopenharmony_ci		return enetc_setup_tc_cbs(ndev, type_data);
16288c2ecf20Sopenharmony_ci	case TC_SETUP_QDISC_ETF:
16298c2ecf20Sopenharmony_ci		return enetc_setup_tc_txtime(ndev, type_data);
16308c2ecf20Sopenharmony_ci	case TC_SETUP_BLOCK:
16318c2ecf20Sopenharmony_ci		return enetc_setup_tc_psfp(ndev, type_data);
16328c2ecf20Sopenharmony_ci	default:
16338c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
16348c2ecf20Sopenharmony_ci	}
16358c2ecf20Sopenharmony_ci}
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_cistruct net_device_stats *enetc_get_stats(struct net_device *ndev)
16388c2ecf20Sopenharmony_ci{
16398c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
16408c2ecf20Sopenharmony_ci	struct net_device_stats *stats = &ndev->stats;
16418c2ecf20Sopenharmony_ci	unsigned long packets = 0, bytes = 0;
16428c2ecf20Sopenharmony_ci	int i;
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++) {
16458c2ecf20Sopenharmony_ci		packets += priv->rx_ring[i]->stats.packets;
16468c2ecf20Sopenharmony_ci		bytes	+= priv->rx_ring[i]->stats.bytes;
16478c2ecf20Sopenharmony_ci	}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	stats->rx_packets = packets;
16508c2ecf20Sopenharmony_ci	stats->rx_bytes = bytes;
16518c2ecf20Sopenharmony_ci	bytes = 0;
16528c2ecf20Sopenharmony_ci	packets = 0;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++) {
16558c2ecf20Sopenharmony_ci		packets += priv->tx_ring[i]->stats.packets;
16568c2ecf20Sopenharmony_ci		bytes	+= priv->tx_ring[i]->stats.bytes;
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	stats->tx_packets = packets;
16608c2ecf20Sopenharmony_ci	stats->tx_bytes = bytes;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	return stats;
16638c2ecf20Sopenharmony_ci}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_cistatic int enetc_set_rss(struct net_device *ndev, int en)
16668c2ecf20Sopenharmony_ci{
16678c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
16688c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
16698c2ecf20Sopenharmony_ci	u32 reg;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SIRBGCR, priv->num_rx_rings);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	reg = enetc_rd(hw, ENETC_SIMR);
16748c2ecf20Sopenharmony_ci	reg &= ~ENETC_SIMR_RSSE;
16758c2ecf20Sopenharmony_ci	reg |= (en) ? ENETC_SIMR_RSSE : 0;
16768c2ecf20Sopenharmony_ci	enetc_wr(hw, ENETC_SIMR, reg);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	return 0;
16798c2ecf20Sopenharmony_ci}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_cistatic void enetc_enable_rxvlan(struct net_device *ndev, bool en)
16828c2ecf20Sopenharmony_ci{
16838c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
16848c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
16858c2ecf20Sopenharmony_ci	int i;
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
16888c2ecf20Sopenharmony_ci		enetc_bdr_enable_rxvlan(hw, i, en);
16898c2ecf20Sopenharmony_ci}
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_cistatic void enetc_enable_txvlan(struct net_device *ndev, bool en)
16928c2ecf20Sopenharmony_ci{
16938c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
16948c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &priv->si->hw;
16958c2ecf20Sopenharmony_ci	int i;
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
16988c2ecf20Sopenharmony_ci		enetc_bdr_enable_txvlan(hw, i, en);
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_civoid enetc_set_features(struct net_device *ndev, netdev_features_t features)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	netdev_features_t changed = ndev->features ^ features;
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	if (changed & NETIF_F_RXHASH)
17068c2ecf20Sopenharmony_ci		enetc_set_rss(ndev, !!(features & NETIF_F_RXHASH));
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_RX)
17098c2ecf20Sopenharmony_ci		enetc_enable_rxvlan(ndev,
17108c2ecf20Sopenharmony_ci				    !!(features & NETIF_F_HW_VLAN_CTAG_RX));
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	if (changed & NETIF_F_HW_VLAN_CTAG_TX)
17138c2ecf20Sopenharmony_ci		enetc_enable_txvlan(ndev,
17148c2ecf20Sopenharmony_ci				    !!(features & NETIF_F_HW_VLAN_CTAG_TX));
17158c2ecf20Sopenharmony_ci}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
17188c2ecf20Sopenharmony_cistatic int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr)
17198c2ecf20Sopenharmony_ci{
17208c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
17218c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
17228c2ecf20Sopenharmony_ci	int ao;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
17258c2ecf20Sopenharmony_ci		return -EFAULT;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	switch (config.tx_type) {
17288c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_OFF:
17298c2ecf20Sopenharmony_ci		priv->active_offloads &= ~ENETC_F_TX_TSTAMP;
17308c2ecf20Sopenharmony_ci		break;
17318c2ecf20Sopenharmony_ci	case HWTSTAMP_TX_ON:
17328c2ecf20Sopenharmony_ci		priv->active_offloads |= ENETC_F_TX_TSTAMP;
17338c2ecf20Sopenharmony_ci		break;
17348c2ecf20Sopenharmony_ci	default:
17358c2ecf20Sopenharmony_ci		return -ERANGE;
17368c2ecf20Sopenharmony_ci	}
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	ao = priv->active_offloads;
17398c2ecf20Sopenharmony_ci	switch (config.rx_filter) {
17408c2ecf20Sopenharmony_ci	case HWTSTAMP_FILTER_NONE:
17418c2ecf20Sopenharmony_ci		priv->active_offloads &= ~ENETC_F_RX_TSTAMP;
17428c2ecf20Sopenharmony_ci		break;
17438c2ecf20Sopenharmony_ci	default:
17448c2ecf20Sopenharmony_ci		priv->active_offloads |= ENETC_F_RX_TSTAMP;
17458c2ecf20Sopenharmony_ci		config.rx_filter = HWTSTAMP_FILTER_ALL;
17468c2ecf20Sopenharmony_ci	}
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	if (netif_running(ndev) && ao != priv->active_offloads) {
17498c2ecf20Sopenharmony_ci		enetc_close(ndev);
17508c2ecf20Sopenharmony_ci		enetc_open(ndev);
17518c2ecf20Sopenharmony_ci	}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
17548c2ecf20Sopenharmony_ci	       -EFAULT : 0;
17558c2ecf20Sopenharmony_ci}
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_cistatic int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr)
17588c2ecf20Sopenharmony_ci{
17598c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
17608c2ecf20Sopenharmony_ci	struct hwtstamp_config config;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	config.flags = 0;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	if (priv->active_offloads & ENETC_F_TX_TSTAMP)
17658c2ecf20Sopenharmony_ci		config.tx_type = HWTSTAMP_TX_ON;
17668c2ecf20Sopenharmony_ci	else
17678c2ecf20Sopenharmony_ci		config.tx_type = HWTSTAMP_TX_OFF;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	config.rx_filter = (priv->active_offloads & ENETC_F_RX_TSTAMP) ?
17708c2ecf20Sopenharmony_ci			    HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
17718c2ecf20Sopenharmony_ci
17728c2ecf20Sopenharmony_ci	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
17738c2ecf20Sopenharmony_ci	       -EFAULT : 0;
17748c2ecf20Sopenharmony_ci}
17758c2ecf20Sopenharmony_ci#endif
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ciint enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
17788c2ecf20Sopenharmony_ci{
17798c2ecf20Sopenharmony_ci	struct enetc_ndev_priv *priv = netdev_priv(ndev);
17808c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
17818c2ecf20Sopenharmony_ci	if (cmd == SIOCSHWTSTAMP)
17828c2ecf20Sopenharmony_ci		return enetc_hwtstamp_set(ndev, rq);
17838c2ecf20Sopenharmony_ci	if (cmd == SIOCGHWTSTAMP)
17848c2ecf20Sopenharmony_ci		return enetc_hwtstamp_get(ndev, rq);
17858c2ecf20Sopenharmony_ci#endif
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	if (!priv->phylink)
17888c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	return phylink_mii_ioctl(priv->phylink, rq, cmd);
17918c2ecf20Sopenharmony_ci}
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ciint enetc_alloc_msix(struct enetc_ndev_priv *priv)
17948c2ecf20Sopenharmony_ci{
17958c2ecf20Sopenharmony_ci	struct pci_dev *pdev = priv->si->pdev;
17968c2ecf20Sopenharmony_ci	int v_tx_rings;
17978c2ecf20Sopenharmony_ci	int i, n, err, nvec;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci	nvec = ENETC_BDR_INT_BASE_IDX + priv->bdr_int_num;
18008c2ecf20Sopenharmony_ci	/* allocate MSIX for both messaging and Rx/Tx interrupts */
18018c2ecf20Sopenharmony_ci	n = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_MSIX);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	if (n < 0)
18048c2ecf20Sopenharmony_ci		return n;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	if (n != nvec)
18078c2ecf20Sopenharmony_ci		return -EPERM;
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci	/* # of tx rings per int vector */
18108c2ecf20Sopenharmony_ci	v_tx_rings = priv->num_tx_rings / priv->bdr_int_num;
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
18138c2ecf20Sopenharmony_ci		struct enetc_int_vector *v;
18148c2ecf20Sopenharmony_ci		struct enetc_bdr *bdr;
18158c2ecf20Sopenharmony_ci		int j;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci		v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL);
18188c2ecf20Sopenharmony_ci		if (!v) {
18198c2ecf20Sopenharmony_ci			err = -ENOMEM;
18208c2ecf20Sopenharmony_ci			goto fail;
18218c2ecf20Sopenharmony_ci		}
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci		priv->int_vector[i] = v;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci		/* init defaults for adaptive IC */
18268c2ecf20Sopenharmony_ci		if (priv->ic_mode & ENETC_IC_RX_ADAPTIVE) {
18278c2ecf20Sopenharmony_ci			v->rx_ictt = 0x1;
18288c2ecf20Sopenharmony_ci			v->rx_dim_en = true;
18298c2ecf20Sopenharmony_ci		}
18308c2ecf20Sopenharmony_ci		INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work);
18318c2ecf20Sopenharmony_ci		netif_napi_add(priv->ndev, &v->napi, enetc_poll,
18328c2ecf20Sopenharmony_ci			       NAPI_POLL_WEIGHT);
18338c2ecf20Sopenharmony_ci		v->count_tx_rings = v_tx_rings;
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci		for (j = 0; j < v_tx_rings; j++) {
18368c2ecf20Sopenharmony_ci			int idx;
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci			/* default tx ring mapping policy */
18398c2ecf20Sopenharmony_ci			if (priv->bdr_int_num == ENETC_MAX_BDR_INT)
18408c2ecf20Sopenharmony_ci				idx = 2 * j + i; /* 2 CPUs */
18418c2ecf20Sopenharmony_ci			else
18428c2ecf20Sopenharmony_ci				idx = j + i * v_tx_rings; /* default */
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci			__set_bit(idx, &v->tx_rings_map);
18458c2ecf20Sopenharmony_ci			bdr = &v->tx_ring[j];
18468c2ecf20Sopenharmony_ci			bdr->index = idx;
18478c2ecf20Sopenharmony_ci			bdr->ndev = priv->ndev;
18488c2ecf20Sopenharmony_ci			bdr->dev = priv->dev;
18498c2ecf20Sopenharmony_ci			bdr->bd_count = priv->tx_bd_count;
18508c2ecf20Sopenharmony_ci			priv->tx_ring[idx] = bdr;
18518c2ecf20Sopenharmony_ci		}
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci		bdr = &v->rx_ring;
18548c2ecf20Sopenharmony_ci		bdr->index = i;
18558c2ecf20Sopenharmony_ci		bdr->ndev = priv->ndev;
18568c2ecf20Sopenharmony_ci		bdr->dev = priv->dev;
18578c2ecf20Sopenharmony_ci		bdr->bd_count = priv->rx_bd_count;
18588c2ecf20Sopenharmony_ci		priv->rx_ring[i] = bdr;
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	return 0;
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_cifail:
18648c2ecf20Sopenharmony_ci	while (i--) {
18658c2ecf20Sopenharmony_ci		netif_napi_del(&priv->int_vector[i]->napi);
18668c2ecf20Sopenharmony_ci		cancel_work_sync(&priv->int_vector[i]->rx_dim.work);
18678c2ecf20Sopenharmony_ci		kfree(priv->int_vector[i]);
18688c2ecf20Sopenharmony_ci	}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	pci_free_irq_vectors(pdev);
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	return err;
18738c2ecf20Sopenharmony_ci}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_civoid enetc_free_msix(struct enetc_ndev_priv *priv)
18768c2ecf20Sopenharmony_ci{
18778c2ecf20Sopenharmony_ci	int i;
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
18808c2ecf20Sopenharmony_ci		struct enetc_int_vector *v = priv->int_vector[i];
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci		netif_napi_del(&v->napi);
18838c2ecf20Sopenharmony_ci		cancel_work_sync(&v->rx_dim.work);
18848c2ecf20Sopenharmony_ci	}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_rings; i++)
18878c2ecf20Sopenharmony_ci		priv->rx_ring[i] = NULL;
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_tx_rings; i++)
18908c2ecf20Sopenharmony_ci		priv->tx_ring[i] = NULL;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	for (i = 0; i < priv->bdr_int_num; i++) {
18938c2ecf20Sopenharmony_ci		kfree(priv->int_vector[i]);
18948c2ecf20Sopenharmony_ci		priv->int_vector[i] = NULL;
18958c2ecf20Sopenharmony_ci	}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	/* disable all MSIX for this device */
18988c2ecf20Sopenharmony_ci	pci_free_irq_vectors(priv->si->pdev);
18998c2ecf20Sopenharmony_ci}
19008c2ecf20Sopenharmony_ci
19018c2ecf20Sopenharmony_cistatic void enetc_kfree_si(struct enetc_si *si)
19028c2ecf20Sopenharmony_ci{
19038c2ecf20Sopenharmony_ci	char *p = (char *)si - si->pad;
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	kfree(p);
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_cistatic void enetc_detect_errata(struct enetc_si *si)
19098c2ecf20Sopenharmony_ci{
19108c2ecf20Sopenharmony_ci	if (si->pdev->revision == ENETC_REV1)
19118c2ecf20Sopenharmony_ci		si->errata = ENETC_ERR_TXCSUM | ENETC_ERR_VLAN_ISOL |
19128c2ecf20Sopenharmony_ci			     ENETC_ERR_UCMCSWP;
19138c2ecf20Sopenharmony_ci}
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ciint enetc_pci_probe(struct pci_dev *pdev, const char *name, int sizeof_priv)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	struct enetc_si *si, *p;
19188c2ecf20Sopenharmony_ci	struct enetc_hw *hw;
19198c2ecf20Sopenharmony_ci	size_t alloc_size;
19208c2ecf20Sopenharmony_ci	int err, len;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	pcie_flr(pdev);
19238c2ecf20Sopenharmony_ci	err = pci_enable_device_mem(pdev);
19248c2ecf20Sopenharmony_ci	if (err) {
19258c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "device enable failed\n");
19268c2ecf20Sopenharmony_ci		return err;
19278c2ecf20Sopenharmony_ci	}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	/* set up for high or low dma */
19308c2ecf20Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
19318c2ecf20Sopenharmony_ci	if (err) {
19328c2ecf20Sopenharmony_ci		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
19338c2ecf20Sopenharmony_ci		if (err) {
19348c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
19358c2ecf20Sopenharmony_ci				"DMA configuration failed: 0x%x\n", err);
19368c2ecf20Sopenharmony_ci			goto err_dma;
19378c2ecf20Sopenharmony_ci		}
19388c2ecf20Sopenharmony_ci	}
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	err = pci_request_mem_regions(pdev, name);
19418c2ecf20Sopenharmony_ci	if (err) {
19428c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "pci_request_regions failed err=%d\n", err);
19438c2ecf20Sopenharmony_ci		goto err_pci_mem_reg;
19448c2ecf20Sopenharmony_ci	}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci	pci_set_master(pdev);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	alloc_size = sizeof(struct enetc_si);
19498c2ecf20Sopenharmony_ci	if (sizeof_priv) {
19508c2ecf20Sopenharmony_ci		/* align priv to 32B */
19518c2ecf20Sopenharmony_ci		alloc_size = ALIGN(alloc_size, ENETC_SI_ALIGN);
19528c2ecf20Sopenharmony_ci		alloc_size += sizeof_priv;
19538c2ecf20Sopenharmony_ci	}
19548c2ecf20Sopenharmony_ci	/* force 32B alignment for enetc_si */
19558c2ecf20Sopenharmony_ci	alloc_size += ENETC_SI_ALIGN - 1;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	p = kzalloc(alloc_size, GFP_KERNEL);
19588c2ecf20Sopenharmony_ci	if (!p) {
19598c2ecf20Sopenharmony_ci		err = -ENOMEM;
19608c2ecf20Sopenharmony_ci		goto err_alloc_si;
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	si = PTR_ALIGN(p, ENETC_SI_ALIGN);
19648c2ecf20Sopenharmony_ci	si->pad = (char *)si - (char *)p;
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, si);
19678c2ecf20Sopenharmony_ci	si->pdev = pdev;
19688c2ecf20Sopenharmony_ci	hw = &si->hw;
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	len = pci_resource_len(pdev, ENETC_BAR_REGS);
19718c2ecf20Sopenharmony_ci	hw->reg = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), len);
19728c2ecf20Sopenharmony_ci	if (!hw->reg) {
19738c2ecf20Sopenharmony_ci		err = -ENXIO;
19748c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "ioremap() failed\n");
19758c2ecf20Sopenharmony_ci		goto err_ioremap;
19768c2ecf20Sopenharmony_ci	}
19778c2ecf20Sopenharmony_ci	if (len > ENETC_PORT_BASE)
19788c2ecf20Sopenharmony_ci		hw->port = hw->reg + ENETC_PORT_BASE;
19798c2ecf20Sopenharmony_ci	if (len > ENETC_GLOBAL_BASE)
19808c2ecf20Sopenharmony_ci		hw->global = hw->reg + ENETC_GLOBAL_BASE;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci	enetc_detect_errata(si);
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	return 0;
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_cierr_ioremap:
19878c2ecf20Sopenharmony_ci	enetc_kfree_si(si);
19888c2ecf20Sopenharmony_cierr_alloc_si:
19898c2ecf20Sopenharmony_ci	pci_release_mem_regions(pdev);
19908c2ecf20Sopenharmony_cierr_pci_mem_reg:
19918c2ecf20Sopenharmony_cierr_dma:
19928c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci	return err;
19958c2ecf20Sopenharmony_ci}
19968c2ecf20Sopenharmony_ci
19978c2ecf20Sopenharmony_civoid enetc_pci_remove(struct pci_dev *pdev)
19988c2ecf20Sopenharmony_ci{
19998c2ecf20Sopenharmony_ci	struct enetc_si *si = pci_get_drvdata(pdev);
20008c2ecf20Sopenharmony_ci	struct enetc_hw *hw = &si->hw;
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci	iounmap(hw->reg);
20038c2ecf20Sopenharmony_ci	enetc_kfree_si(si);
20048c2ecf20Sopenharmony_ci	pci_release_mem_regions(pdev);
20058c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
20068c2ecf20Sopenharmony_ci}
2007