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