18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright(c) 2020 Intel Corporation.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/*
88c2ecf20Sopenharmony_ci * This file contains HFI1 support for netdev RX functionality
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "sdma.h"
128c2ecf20Sopenharmony_ci#include "verbs.h"
138c2ecf20Sopenharmony_ci#include "netdev.h"
148c2ecf20Sopenharmony_ci#include "hfi.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
178c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
188c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic int hfi1_netdev_setup_ctxt(struct hfi1_netdev_priv *priv,
218c2ecf20Sopenharmony_ci				  struct hfi1_ctxtdata *uctxt)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	unsigned int rcvctrl_ops;
248c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = priv->dd;
258c2ecf20Sopenharmony_ci	int ret;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	uctxt->rhf_rcv_function_map = netdev_rhf_rcv_functions;
288c2ecf20Sopenharmony_ci	uctxt->do_interrupt = &handle_receive_interrupt_napi_sp;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* Now allocate the RcvHdr queue and eager buffers. */
318c2ecf20Sopenharmony_ci	ret = hfi1_create_rcvhdrq(dd, uctxt);
328c2ecf20Sopenharmony_ci	if (ret)
338c2ecf20Sopenharmony_ci		goto done;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	ret = hfi1_setup_eagerbufs(uctxt);
368c2ecf20Sopenharmony_ci	if (ret)
378c2ecf20Sopenharmony_ci		goto done;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	clear_rcvhdrtail(uctxt);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	rcvctrl_ops = HFI1_RCVCTRL_CTXT_DIS;
428c2ecf20Sopenharmony_ci	rcvctrl_ops |= HFI1_RCVCTRL_INTRAVAIL_DIS;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (!HFI1_CAP_KGET_MASK(uctxt->flags, MULTI_PKT_EGR))
458c2ecf20Sopenharmony_ci		rcvctrl_ops |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB;
468c2ecf20Sopenharmony_ci	if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_EGR_FULL))
478c2ecf20Sopenharmony_ci		rcvctrl_ops |= HFI1_RCVCTRL_NO_EGR_DROP_ENB;
488c2ecf20Sopenharmony_ci	if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_RHQ_FULL))
498c2ecf20Sopenharmony_ci		rcvctrl_ops |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB;
508c2ecf20Sopenharmony_ci	if (HFI1_CAP_KGET_MASK(uctxt->flags, DMA_RTAIL))
518c2ecf20Sopenharmony_ci		rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_ENB;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	hfi1_rcvctrl(uctxt->dd, rcvctrl_ops, uctxt);
548c2ecf20Sopenharmony_cidone:
558c2ecf20Sopenharmony_ci	return ret;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int hfi1_netdev_allocate_ctxt(struct hfi1_devdata *dd,
598c2ecf20Sopenharmony_ci				     struct hfi1_ctxtdata **ctxt)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct hfi1_ctxtdata *uctxt;
628c2ecf20Sopenharmony_ci	int ret;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (dd->flags & HFI1_FROZEN)
658c2ecf20Sopenharmony_ci		return -EIO;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	ret = hfi1_create_ctxtdata(dd->pport, dd->node, &uctxt);
688c2ecf20Sopenharmony_ci	if (ret < 0) {
698c2ecf20Sopenharmony_ci		dd_dev_err(dd, "Unable to create ctxtdata, failing open\n");
708c2ecf20Sopenharmony_ci		return -ENOMEM;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	uctxt->flags = HFI1_CAP_KGET(MULTI_PKT_EGR) |
748c2ecf20Sopenharmony_ci		HFI1_CAP_KGET(NODROP_RHQ_FULL) |
758c2ecf20Sopenharmony_ci		HFI1_CAP_KGET(NODROP_EGR_FULL) |
768c2ecf20Sopenharmony_ci		HFI1_CAP_KGET(DMA_RTAIL);
778c2ecf20Sopenharmony_ci	/* Netdev contexts are always NO_RDMA_RTAIL */
788c2ecf20Sopenharmony_ci	uctxt->fast_handler = handle_receive_interrupt_napi_fp;
798c2ecf20Sopenharmony_ci	uctxt->slow_handler = handle_receive_interrupt_napi_sp;
808c2ecf20Sopenharmony_ci	hfi1_set_seq_cnt(uctxt, 1);
818c2ecf20Sopenharmony_ci	uctxt->is_vnic = true;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	hfi1_stats.sps_ctxts++;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	dd_dev_info(dd, "created netdev context %d\n", uctxt->ctxt);
868c2ecf20Sopenharmony_ci	*ctxt = uctxt;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic void hfi1_netdev_deallocate_ctxt(struct hfi1_devdata *dd,
928c2ecf20Sopenharmony_ci					struct hfi1_ctxtdata *uctxt)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	flush_wc();
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	/*
978c2ecf20Sopenharmony_ci	 * Disable receive context and interrupt available, reset all
988c2ecf20Sopenharmony_ci	 * RcvCtxtCtrl bits to default values.
998c2ecf20Sopenharmony_ci	 */
1008c2ecf20Sopenharmony_ci	hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_DIS |
1018c2ecf20Sopenharmony_ci		     HFI1_RCVCTRL_TIDFLOW_DIS |
1028c2ecf20Sopenharmony_ci		     HFI1_RCVCTRL_INTRAVAIL_DIS |
1038c2ecf20Sopenharmony_ci		     HFI1_RCVCTRL_ONE_PKT_EGR_DIS |
1048c2ecf20Sopenharmony_ci		     HFI1_RCVCTRL_NO_RHQ_DROP_DIS |
1058c2ecf20Sopenharmony_ci		     HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (uctxt->msix_intr != CCE_NUM_MSIX_VECTORS)
1088c2ecf20Sopenharmony_ci		msix_free_irq(dd, uctxt->msix_intr);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	uctxt->msix_intr = CCE_NUM_MSIX_VECTORS;
1118c2ecf20Sopenharmony_ci	uctxt->event_flags = 0;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	hfi1_clear_tids(uctxt);
1148c2ecf20Sopenharmony_ci	hfi1_clear_ctxt_pkey(dd, uctxt);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	hfi1_stats.sps_ctxts--;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	hfi1_free_ctxt(uctxt);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic int hfi1_netdev_allot_ctxt(struct hfi1_netdev_priv *priv,
1228c2ecf20Sopenharmony_ci				  struct hfi1_ctxtdata **ctxt)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	int rc;
1258c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = priv->dd;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	rc = hfi1_netdev_allocate_ctxt(dd, ctxt);
1288c2ecf20Sopenharmony_ci	if (rc) {
1298c2ecf20Sopenharmony_ci		dd_dev_err(dd, "netdev ctxt alloc failed %d\n", rc);
1308c2ecf20Sopenharmony_ci		return rc;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	rc = hfi1_netdev_setup_ctxt(priv, *ctxt);
1348c2ecf20Sopenharmony_ci	if (rc) {
1358c2ecf20Sopenharmony_ci		dd_dev_err(dd, "netdev ctxt setup failed %d\n", rc);
1368c2ecf20Sopenharmony_ci		hfi1_netdev_deallocate_ctxt(dd, *ctxt);
1378c2ecf20Sopenharmony_ci		*ctxt = NULL;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return rc;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/**
1448c2ecf20Sopenharmony_ci * hfi1_num_netdev_contexts - Count of netdev recv contexts to use.
1458c2ecf20Sopenharmony_ci * @dd: device on which to allocate netdev contexts
1468c2ecf20Sopenharmony_ci * @available_contexts: count of available receive contexts
1478c2ecf20Sopenharmony_ci * @cpu_mask: mask of possible cpus to include for contexts
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * Return: count of physical cores on a node or the remaining available recv
1508c2ecf20Sopenharmony_ci * contexts for netdev recv context usage up to the maximum of
1518c2ecf20Sopenharmony_ci * HFI1_MAX_NETDEV_CTXTS.
1528c2ecf20Sopenharmony_ci * A value of 0 can be returned when acceleration is explicitly turned off,
1538c2ecf20Sopenharmony_ci * a memory allocation error occurs or when there are no available contexts.
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci */
1568c2ecf20Sopenharmony_ciu32 hfi1_num_netdev_contexts(struct hfi1_devdata *dd, u32 available_contexts,
1578c2ecf20Sopenharmony_ci			     struct cpumask *cpu_mask)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	cpumask_var_t node_cpu_mask;
1608c2ecf20Sopenharmony_ci	unsigned int available_cpus;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (!HFI1_CAP_IS_KSET(AIP))
1638c2ecf20Sopenharmony_ci		return 0;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* Always give user contexts priority over netdev contexts */
1668c2ecf20Sopenharmony_ci	if (available_contexts == 0) {
1678c2ecf20Sopenharmony_ci		dd_dev_info(dd, "No receive contexts available for netdevs.\n");
1688c2ecf20Sopenharmony_ci		return 0;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (!zalloc_cpumask_var(&node_cpu_mask, GFP_KERNEL)) {
1728c2ecf20Sopenharmony_ci		dd_dev_err(dd, "Unable to allocate cpu_mask for netdevs.\n");
1738c2ecf20Sopenharmony_ci		return 0;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	cpumask_and(node_cpu_mask, cpu_mask, cpumask_of_node(dd->node));
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	available_cpus = cpumask_weight(node_cpu_mask);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	free_cpumask_var(node_cpu_mask);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	return min3(available_cpus, available_contexts,
1838c2ecf20Sopenharmony_ci		    (u32)HFI1_MAX_NETDEV_CTXTS);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int hfi1_netdev_rxq_init(struct net_device *dev)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	int i;
1898c2ecf20Sopenharmony_ci	int rc;
1908c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dev);
1918c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = priv->dd;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	priv->num_rx_q = dd->num_netdev_contexts;
1948c2ecf20Sopenharmony_ci	priv->rxq = kcalloc_node(priv->num_rx_q, sizeof(struct hfi1_netdev_rxq),
1958c2ecf20Sopenharmony_ci				 GFP_KERNEL, dd->node);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (!priv->rxq) {
1988c2ecf20Sopenharmony_ci		dd_dev_err(dd, "Unable to allocate netdev queue data\n");
1998c2ecf20Sopenharmony_ci		return (-ENOMEM);
2008c2ecf20Sopenharmony_ci	}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_q; i++) {
2038c2ecf20Sopenharmony_ci		struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci		rc = hfi1_netdev_allot_ctxt(priv, &rxq->rcd);
2068c2ecf20Sopenharmony_ci		if (rc)
2078c2ecf20Sopenharmony_ci			goto bail_context_irq_failure;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		hfi1_rcd_get(rxq->rcd);
2108c2ecf20Sopenharmony_ci		rxq->priv = priv;
2118c2ecf20Sopenharmony_ci		rxq->rcd->napi = &rxq->napi;
2128c2ecf20Sopenharmony_ci		dd_dev_info(dd, "Setting rcv queue %d napi to context %d\n",
2138c2ecf20Sopenharmony_ci			    i, rxq->rcd->ctxt);
2148c2ecf20Sopenharmony_ci		/*
2158c2ecf20Sopenharmony_ci		 * Disable BUSY_POLL on this NAPI as this is not supported
2168c2ecf20Sopenharmony_ci		 * right now.
2178c2ecf20Sopenharmony_ci		 */
2188c2ecf20Sopenharmony_ci		set_bit(NAPI_STATE_NO_BUSY_POLL, &rxq->napi.state);
2198c2ecf20Sopenharmony_ci		netif_napi_add(dev, &rxq->napi, hfi1_netdev_rx_napi, 64);
2208c2ecf20Sopenharmony_ci		rc = msix_netdev_request_rcd_irq(rxq->rcd);
2218c2ecf20Sopenharmony_ci		if (rc)
2228c2ecf20Sopenharmony_ci			goto bail_context_irq_failure;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return 0;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cibail_context_irq_failure:
2288c2ecf20Sopenharmony_ci	dd_dev_err(dd, "Unable to allot receive context\n");
2298c2ecf20Sopenharmony_ci	for (; i >= 0; i--) {
2308c2ecf20Sopenharmony_ci		struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci		if (rxq->rcd) {
2338c2ecf20Sopenharmony_ci			hfi1_netdev_deallocate_ctxt(dd, rxq->rcd);
2348c2ecf20Sopenharmony_ci			hfi1_rcd_put(rxq->rcd);
2358c2ecf20Sopenharmony_ci			rxq->rcd = NULL;
2368c2ecf20Sopenharmony_ci		}
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci	kfree(priv->rxq);
2398c2ecf20Sopenharmony_ci	priv->rxq = NULL;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return rc;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void hfi1_netdev_rxq_deinit(struct net_device *dev)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	int i;
2478c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dev);
2488c2ecf20Sopenharmony_ci	struct hfi1_devdata *dd = priv->dd;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_q; i++) {
2518c2ecf20Sopenharmony_ci		struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		netif_napi_del(&rxq->napi);
2548c2ecf20Sopenharmony_ci		hfi1_netdev_deallocate_ctxt(dd, rxq->rcd);
2558c2ecf20Sopenharmony_ci		hfi1_rcd_put(rxq->rcd);
2568c2ecf20Sopenharmony_ci		rxq->rcd = NULL;
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	kfree(priv->rxq);
2608c2ecf20Sopenharmony_ci	priv->rxq = NULL;
2618c2ecf20Sopenharmony_ci	priv->num_rx_q = 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic void enable_queues(struct hfi1_netdev_priv *priv)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	int i;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_q; i++) {
2698c2ecf20Sopenharmony_ci		struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci		dd_dev_info(priv->dd, "enabling queue %d on context %d\n", i,
2728c2ecf20Sopenharmony_ci			    rxq->rcd->ctxt);
2738c2ecf20Sopenharmony_ci		napi_enable(&rxq->napi);
2748c2ecf20Sopenharmony_ci		hfi1_rcvctrl(priv->dd,
2758c2ecf20Sopenharmony_ci			     HFI1_RCVCTRL_CTXT_ENB | HFI1_RCVCTRL_INTRAVAIL_ENB,
2768c2ecf20Sopenharmony_ci			     rxq->rcd);
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic void disable_queues(struct hfi1_netdev_priv *priv)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	int i;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	msix_netdev_synchronize_irq(priv->dd);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	for (i = 0; i < priv->num_rx_q; i++) {
2878c2ecf20Sopenharmony_ci		struct hfi1_netdev_rxq *rxq = &priv->rxq[i];
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		dd_dev_info(priv->dd, "disabling queue %d on context %d\n", i,
2908c2ecf20Sopenharmony_ci			    rxq->rcd->ctxt);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		/* wait for napi if it was scheduled */
2938c2ecf20Sopenharmony_ci		hfi1_rcvctrl(priv->dd,
2948c2ecf20Sopenharmony_ci			     HFI1_RCVCTRL_CTXT_DIS | HFI1_RCVCTRL_INTRAVAIL_DIS,
2958c2ecf20Sopenharmony_ci			     rxq->rcd);
2968c2ecf20Sopenharmony_ci		napi_synchronize(&rxq->napi);
2978c2ecf20Sopenharmony_ci		napi_disable(&rxq->napi);
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci/**
3028c2ecf20Sopenharmony_ci * hfi1_netdev_rx_init - Incrememnts netdevs counter. When called first time,
3038c2ecf20Sopenharmony_ci * it allocates receive queue data and calls netif_napi_add
3048c2ecf20Sopenharmony_ci * for each queue.
3058c2ecf20Sopenharmony_ci *
3068c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
3078c2ecf20Sopenharmony_ci */
3088c2ecf20Sopenharmony_ciint hfi1_netdev_rx_init(struct hfi1_devdata *dd)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
3118c2ecf20Sopenharmony_ci	int res;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (atomic_fetch_inc(&priv->netdevs))
3148c2ecf20Sopenharmony_ci		return 0;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	mutex_lock(&hfi1_mutex);
3178c2ecf20Sopenharmony_ci	init_dummy_netdev(dd->dummy_netdev);
3188c2ecf20Sopenharmony_ci	res = hfi1_netdev_rxq_init(dd->dummy_netdev);
3198c2ecf20Sopenharmony_ci	mutex_unlock(&hfi1_mutex);
3208c2ecf20Sopenharmony_ci	return res;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci/**
3248c2ecf20Sopenharmony_ci * hfi1_netdev_rx_destroy - Decrements netdevs counter, when it reaches 0
3258c2ecf20Sopenharmony_ci * napi is deleted and receive queses memory is freed.
3268c2ecf20Sopenharmony_ci *
3278c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
3288c2ecf20Sopenharmony_ci */
3298c2ecf20Sopenharmony_ciint hfi1_netdev_rx_destroy(struct hfi1_devdata *dd)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	/* destroy the RX queues only if it is the last netdev going away */
3348c2ecf20Sopenharmony_ci	if (atomic_fetch_add_unless(&priv->netdevs, -1, 0) == 1) {
3358c2ecf20Sopenharmony_ci		mutex_lock(&hfi1_mutex);
3368c2ecf20Sopenharmony_ci		hfi1_netdev_rxq_deinit(dd->dummy_netdev);
3378c2ecf20Sopenharmony_ci		mutex_unlock(&hfi1_mutex);
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return 0;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/**
3448c2ecf20Sopenharmony_ci * hfi1_netdev_alloc - Allocates netdev and private data. It is required
3458c2ecf20Sopenharmony_ci * because RMT index and MSI-X interrupt can be set only
3468c2ecf20Sopenharmony_ci * during driver initialization.
3478c2ecf20Sopenharmony_ci *
3488c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
3498c2ecf20Sopenharmony_ci */
3508c2ecf20Sopenharmony_ciint hfi1_netdev_alloc(struct hfi1_devdata *dd)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv;
3538c2ecf20Sopenharmony_ci	const int netdev_size = sizeof(*dd->dummy_netdev) +
3548c2ecf20Sopenharmony_ci		sizeof(struct hfi1_netdev_priv);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	dd_dev_info(dd, "allocating netdev size %d\n", netdev_size);
3578c2ecf20Sopenharmony_ci	dd->dummy_netdev = kcalloc_node(1, netdev_size, GFP_KERNEL, dd->node);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (!dd->dummy_netdev)
3608c2ecf20Sopenharmony_ci		return -ENOMEM;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	priv = hfi1_netdev_priv(dd->dummy_netdev);
3638c2ecf20Sopenharmony_ci	priv->dd = dd;
3648c2ecf20Sopenharmony_ci	xa_init(&priv->dev_tbl);
3658c2ecf20Sopenharmony_ci	atomic_set(&priv->enabled, 0);
3668c2ecf20Sopenharmony_ci	atomic_set(&priv->netdevs, 0);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return 0;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_civoid hfi1_netdev_free(struct hfi1_devdata *dd)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	if (dd->dummy_netdev) {
3748c2ecf20Sopenharmony_ci		dd_dev_info(dd, "hfi1 netdev freed\n");
3758c2ecf20Sopenharmony_ci		kfree(dd->dummy_netdev);
3768c2ecf20Sopenharmony_ci		dd->dummy_netdev = NULL;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/**
3818c2ecf20Sopenharmony_ci * hfi1_netdev_enable_queues - This is napi enable function.
3828c2ecf20Sopenharmony_ci * It enables napi objects associated with queues.
3838c2ecf20Sopenharmony_ci * When at least one device has called it it increments atomic counter.
3848c2ecf20Sopenharmony_ci * Disable function decrements counter and when it is 0,
3858c2ecf20Sopenharmony_ci * calls napi_disable for every queue.
3868c2ecf20Sopenharmony_ci *
3878c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
3888c2ecf20Sopenharmony_ci */
3898c2ecf20Sopenharmony_civoid hfi1_netdev_enable_queues(struct hfi1_devdata *dd)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	if (!dd->dummy_netdev)
3948c2ecf20Sopenharmony_ci		return;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	priv = hfi1_netdev_priv(dd->dummy_netdev);
3978c2ecf20Sopenharmony_ci	if (atomic_fetch_inc(&priv->enabled))
3988c2ecf20Sopenharmony_ci		return;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	mutex_lock(&hfi1_mutex);
4018c2ecf20Sopenharmony_ci	enable_queues(priv);
4028c2ecf20Sopenharmony_ci	mutex_unlock(&hfi1_mutex);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_civoid hfi1_netdev_disable_queues(struct hfi1_devdata *dd)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	if (!dd->dummy_netdev)
4108c2ecf20Sopenharmony_ci		return;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	priv = hfi1_netdev_priv(dd->dummy_netdev);
4138c2ecf20Sopenharmony_ci	if (atomic_dec_if_positive(&priv->enabled))
4148c2ecf20Sopenharmony_ci		return;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	mutex_lock(&hfi1_mutex);
4178c2ecf20Sopenharmony_ci	disable_queues(priv);
4188c2ecf20Sopenharmony_ci	mutex_unlock(&hfi1_mutex);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/**
4228c2ecf20Sopenharmony_ci * hfi1_netdev_add_data - Registers data with unique identifier
4238c2ecf20Sopenharmony_ci * to be requested later this is needed for VNIC and IPoIB VLANs
4248c2ecf20Sopenharmony_ci * implementations.
4258c2ecf20Sopenharmony_ci * This call is protected by mutex idr_lock.
4268c2ecf20Sopenharmony_ci *
4278c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
4288c2ecf20Sopenharmony_ci * @id: requested integer id up to INT_MAX
4298c2ecf20Sopenharmony_ci * @data: data to be associated with index
4308c2ecf20Sopenharmony_ci */
4318c2ecf20Sopenharmony_ciint hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	return xa_insert(&priv->dev_tbl, id, data, GFP_NOWAIT);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci/**
4398c2ecf20Sopenharmony_ci * hfi1_netdev_remove_data - Removes data with previously given id.
4408c2ecf20Sopenharmony_ci * Returns the reference to removed entry.
4418c2ecf20Sopenharmony_ci *
4428c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
4438c2ecf20Sopenharmony_ci * @id: requested integer id up to INT_MAX
4448c2ecf20Sopenharmony_ci */
4458c2ecf20Sopenharmony_civoid *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return xa_erase(&priv->dev_tbl, id);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci/**
4538c2ecf20Sopenharmony_ci * hfi1_netdev_get_data - Gets data with given id
4548c2ecf20Sopenharmony_ci *
4558c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
4568c2ecf20Sopenharmony_ci * @id: requested integer id up to INT_MAX
4578c2ecf20Sopenharmony_ci */
4588c2ecf20Sopenharmony_civoid *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return xa_load(&priv->dev_tbl, id);
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci/**
4668c2ecf20Sopenharmony_ci * hfi1_netdev_get_first_dat - Gets first entry with greater or equal id.
4678c2ecf20Sopenharmony_ci *
4688c2ecf20Sopenharmony_ci * @dd: hfi1 dev data
4698c2ecf20Sopenharmony_ci * @id: requested integer id up to INT_MAX
4708c2ecf20Sopenharmony_ci */
4718c2ecf20Sopenharmony_civoid *hfi1_netdev_get_first_data(struct hfi1_devdata *dd, int *start_id)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct hfi1_netdev_priv *priv = hfi1_netdev_priv(dd->dummy_netdev);
4748c2ecf20Sopenharmony_ci	unsigned long index = *start_id;
4758c2ecf20Sopenharmony_ci	void *ret;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	ret = xa_find(&priv->dev_tbl, &index, UINT_MAX, XA_PRESENT);
4788c2ecf20Sopenharmony_ci	*start_id = (int)index;
4798c2ecf20Sopenharmony_ci	return ret;
4808c2ecf20Sopenharmony_ci}
481