162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2020 Intel Corporation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci/* 862306a36Sopenharmony_ci * This file contains HFI1 support for netdev RX functionality 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "sdma.h" 1262306a36Sopenharmony_ci#include "verbs.h" 1362306a36Sopenharmony_ci#include "netdev.h" 1462306a36Sopenharmony_ci#include "hfi.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/netdevice.h> 1762306a36Sopenharmony_ci#include <linux/etherdevice.h> 1862306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int hfi1_netdev_setup_ctxt(struct hfi1_netdev_rx *rx, 2162306a36Sopenharmony_ci struct hfi1_ctxtdata *uctxt) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci unsigned int rcvctrl_ops; 2462306a36Sopenharmony_ci struct hfi1_devdata *dd = rx->dd; 2562306a36Sopenharmony_ci int ret; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci uctxt->rhf_rcv_function_map = netdev_rhf_rcv_functions; 2862306a36Sopenharmony_ci uctxt->do_interrupt = &handle_receive_interrupt_napi_sp; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci /* Now allocate the RcvHdr queue and eager buffers. */ 3162306a36Sopenharmony_ci ret = hfi1_create_rcvhdrq(dd, uctxt); 3262306a36Sopenharmony_ci if (ret) 3362306a36Sopenharmony_ci goto done; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci ret = hfi1_setup_eagerbufs(uctxt); 3662306a36Sopenharmony_ci if (ret) 3762306a36Sopenharmony_ci goto done; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci clear_rcvhdrtail(uctxt); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci rcvctrl_ops = HFI1_RCVCTRL_CTXT_DIS; 4262306a36Sopenharmony_ci rcvctrl_ops |= HFI1_RCVCTRL_INTRAVAIL_DIS; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (!HFI1_CAP_KGET_MASK(uctxt->flags, MULTI_PKT_EGR)) 4562306a36Sopenharmony_ci rcvctrl_ops |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB; 4662306a36Sopenharmony_ci if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_EGR_FULL)) 4762306a36Sopenharmony_ci rcvctrl_ops |= HFI1_RCVCTRL_NO_EGR_DROP_ENB; 4862306a36Sopenharmony_ci if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_RHQ_FULL)) 4962306a36Sopenharmony_ci rcvctrl_ops |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB; 5062306a36Sopenharmony_ci if (HFI1_CAP_KGET_MASK(uctxt->flags, DMA_RTAIL)) 5162306a36Sopenharmony_ci rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_ENB; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci hfi1_rcvctrl(uctxt->dd, rcvctrl_ops, uctxt); 5462306a36Sopenharmony_cidone: 5562306a36Sopenharmony_ci return ret; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int hfi1_netdev_allocate_ctxt(struct hfi1_devdata *dd, 5962306a36Sopenharmony_ci struct hfi1_ctxtdata **ctxt) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct hfi1_ctxtdata *uctxt; 6262306a36Sopenharmony_ci int ret; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (dd->flags & HFI1_FROZEN) 6562306a36Sopenharmony_ci return -EIO; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = hfi1_create_ctxtdata(dd->pport, dd->node, &uctxt); 6862306a36Sopenharmony_ci if (ret < 0) { 6962306a36Sopenharmony_ci dd_dev_err(dd, "Unable to create ctxtdata, failing open\n"); 7062306a36Sopenharmony_ci return -ENOMEM; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci uctxt->flags = HFI1_CAP_KGET(MULTI_PKT_EGR) | 7462306a36Sopenharmony_ci HFI1_CAP_KGET(NODROP_RHQ_FULL) | 7562306a36Sopenharmony_ci HFI1_CAP_KGET(NODROP_EGR_FULL) | 7662306a36Sopenharmony_ci HFI1_CAP_KGET(DMA_RTAIL); 7762306a36Sopenharmony_ci /* Netdev contexts are always NO_RDMA_RTAIL */ 7862306a36Sopenharmony_ci uctxt->fast_handler = handle_receive_interrupt_napi_fp; 7962306a36Sopenharmony_ci uctxt->slow_handler = handle_receive_interrupt_napi_sp; 8062306a36Sopenharmony_ci hfi1_set_seq_cnt(uctxt, 1); 8162306a36Sopenharmony_ci uctxt->is_vnic = true; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci hfi1_stats.sps_ctxts++; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci dd_dev_info(dd, "created netdev context %d\n", uctxt->ctxt); 8662306a36Sopenharmony_ci *ctxt = uctxt; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void hfi1_netdev_deallocate_ctxt(struct hfi1_devdata *dd, 9262306a36Sopenharmony_ci struct hfi1_ctxtdata *uctxt) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci flush_wc(); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci /* 9762306a36Sopenharmony_ci * Disable receive context and interrupt available, reset all 9862306a36Sopenharmony_ci * RcvCtxtCtrl bits to default values. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_DIS | 10162306a36Sopenharmony_ci HFI1_RCVCTRL_TIDFLOW_DIS | 10262306a36Sopenharmony_ci HFI1_RCVCTRL_INTRAVAIL_DIS | 10362306a36Sopenharmony_ci HFI1_RCVCTRL_ONE_PKT_EGR_DIS | 10462306a36Sopenharmony_ci HFI1_RCVCTRL_NO_RHQ_DROP_DIS | 10562306a36Sopenharmony_ci HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (uctxt->msix_intr != CCE_NUM_MSIX_VECTORS) 10862306a36Sopenharmony_ci msix_free_irq(dd, uctxt->msix_intr); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci uctxt->msix_intr = CCE_NUM_MSIX_VECTORS; 11162306a36Sopenharmony_ci uctxt->event_flags = 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci hfi1_clear_tids(uctxt); 11462306a36Sopenharmony_ci hfi1_clear_ctxt_pkey(dd, uctxt); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci hfi1_stats.sps_ctxts--; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci hfi1_free_ctxt(uctxt); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int hfi1_netdev_allot_ctxt(struct hfi1_netdev_rx *rx, 12262306a36Sopenharmony_ci struct hfi1_ctxtdata **ctxt) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci int rc; 12562306a36Sopenharmony_ci struct hfi1_devdata *dd = rx->dd; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci rc = hfi1_netdev_allocate_ctxt(dd, ctxt); 12862306a36Sopenharmony_ci if (rc) { 12962306a36Sopenharmony_ci dd_dev_err(dd, "netdev ctxt alloc failed %d\n", rc); 13062306a36Sopenharmony_ci return rc; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci rc = hfi1_netdev_setup_ctxt(rx, *ctxt); 13462306a36Sopenharmony_ci if (rc) { 13562306a36Sopenharmony_ci dd_dev_err(dd, "netdev ctxt setup failed %d\n", rc); 13662306a36Sopenharmony_ci hfi1_netdev_deallocate_ctxt(dd, *ctxt); 13762306a36Sopenharmony_ci *ctxt = NULL; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return rc; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/** 14462306a36Sopenharmony_ci * hfi1_num_netdev_contexts - Count of netdev recv contexts to use. 14562306a36Sopenharmony_ci * @dd: device on which to allocate netdev contexts 14662306a36Sopenharmony_ci * @available_contexts: count of available receive contexts 14762306a36Sopenharmony_ci * @cpu_mask: mask of possible cpus to include for contexts 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * Return: count of physical cores on a node or the remaining available recv 15062306a36Sopenharmony_ci * contexts for netdev recv context usage up to the maximum of 15162306a36Sopenharmony_ci * HFI1_MAX_NETDEV_CTXTS. 15262306a36Sopenharmony_ci * A value of 0 can be returned when acceleration is explicitly turned off, 15362306a36Sopenharmony_ci * a memory allocation error occurs or when there are no available contexts. 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ciu32 hfi1_num_netdev_contexts(struct hfi1_devdata *dd, u32 available_contexts, 15762306a36Sopenharmony_ci struct cpumask *cpu_mask) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci cpumask_var_t node_cpu_mask; 16062306a36Sopenharmony_ci unsigned int available_cpus; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!HFI1_CAP_IS_KSET(AIP)) 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Always give user contexts priority over netdev contexts */ 16662306a36Sopenharmony_ci if (available_contexts == 0) { 16762306a36Sopenharmony_ci dd_dev_info(dd, "No receive contexts available for netdevs.\n"); 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!zalloc_cpumask_var(&node_cpu_mask, GFP_KERNEL)) { 17262306a36Sopenharmony_ci dd_dev_err(dd, "Unable to allocate cpu_mask for netdevs.\n"); 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci cpumask_and(node_cpu_mask, cpu_mask, cpumask_of_node(dd->node)); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci available_cpus = cpumask_weight(node_cpu_mask); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci free_cpumask_var(node_cpu_mask); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return min3(available_cpus, available_contexts, 18362306a36Sopenharmony_ci (u32)HFI1_MAX_NETDEV_CTXTS); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int hfi1_netdev_rxq_init(struct hfi1_netdev_rx *rx) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci int i; 18962306a36Sopenharmony_ci int rc; 19062306a36Sopenharmony_ci struct hfi1_devdata *dd = rx->dd; 19162306a36Sopenharmony_ci struct net_device *dev = &rx->rx_napi; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci rx->num_rx_q = dd->num_netdev_contexts; 19462306a36Sopenharmony_ci rx->rxq = kcalloc_node(rx->num_rx_q, sizeof(*rx->rxq), 19562306a36Sopenharmony_ci GFP_KERNEL, dd->node); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (!rx->rxq) { 19862306a36Sopenharmony_ci dd_dev_err(dd, "Unable to allocate netdev queue data\n"); 19962306a36Sopenharmony_ci return (-ENOMEM); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci for (i = 0; i < rx->num_rx_q; i++) { 20362306a36Sopenharmony_ci struct hfi1_netdev_rxq *rxq = &rx->rxq[i]; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci rc = hfi1_netdev_allot_ctxt(rx, &rxq->rcd); 20662306a36Sopenharmony_ci if (rc) 20762306a36Sopenharmony_ci goto bail_context_irq_failure; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci hfi1_rcd_get(rxq->rcd); 21062306a36Sopenharmony_ci rxq->rx = rx; 21162306a36Sopenharmony_ci rxq->rcd->napi = &rxq->napi; 21262306a36Sopenharmony_ci dd_dev_info(dd, "Setting rcv queue %d napi to context %d\n", 21362306a36Sopenharmony_ci i, rxq->rcd->ctxt); 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Disable BUSY_POLL on this NAPI as this is not supported 21662306a36Sopenharmony_ci * right now. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci set_bit(NAPI_STATE_NO_BUSY_POLL, &rxq->napi.state); 21962306a36Sopenharmony_ci netif_napi_add(dev, &rxq->napi, hfi1_netdev_rx_napi); 22062306a36Sopenharmony_ci rc = msix_netdev_request_rcd_irq(rxq->rcd); 22162306a36Sopenharmony_ci if (rc) 22262306a36Sopenharmony_ci goto bail_context_irq_failure; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cibail_context_irq_failure: 22862306a36Sopenharmony_ci dd_dev_err(dd, "Unable to allot receive context\n"); 22962306a36Sopenharmony_ci for (; i >= 0; i--) { 23062306a36Sopenharmony_ci struct hfi1_netdev_rxq *rxq = &rx->rxq[i]; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (rxq->rcd) { 23362306a36Sopenharmony_ci hfi1_netdev_deallocate_ctxt(dd, rxq->rcd); 23462306a36Sopenharmony_ci hfi1_rcd_put(rxq->rcd); 23562306a36Sopenharmony_ci rxq->rcd = NULL; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci kfree(rx->rxq); 23962306a36Sopenharmony_ci rx->rxq = NULL; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return rc; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void hfi1_netdev_rxq_deinit(struct hfi1_netdev_rx *rx) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci int i; 24762306a36Sopenharmony_ci struct hfi1_devdata *dd = rx->dd; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < rx->num_rx_q; i++) { 25062306a36Sopenharmony_ci struct hfi1_netdev_rxq *rxq = &rx->rxq[i]; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci netif_napi_del(&rxq->napi); 25362306a36Sopenharmony_ci hfi1_netdev_deallocate_ctxt(dd, rxq->rcd); 25462306a36Sopenharmony_ci hfi1_rcd_put(rxq->rcd); 25562306a36Sopenharmony_ci rxq->rcd = NULL; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci kfree(rx->rxq); 25962306a36Sopenharmony_ci rx->rxq = NULL; 26062306a36Sopenharmony_ci rx->num_rx_q = 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic void enable_queues(struct hfi1_netdev_rx *rx) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci int i; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci for (i = 0; i < rx->num_rx_q; i++) { 26862306a36Sopenharmony_ci struct hfi1_netdev_rxq *rxq = &rx->rxq[i]; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci dd_dev_info(rx->dd, "enabling queue %d on context %d\n", i, 27162306a36Sopenharmony_ci rxq->rcd->ctxt); 27262306a36Sopenharmony_ci napi_enable(&rxq->napi); 27362306a36Sopenharmony_ci hfi1_rcvctrl(rx->dd, 27462306a36Sopenharmony_ci HFI1_RCVCTRL_CTXT_ENB | HFI1_RCVCTRL_INTRAVAIL_ENB, 27562306a36Sopenharmony_ci rxq->rcd); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void disable_queues(struct hfi1_netdev_rx *rx) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci int i; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci msix_netdev_synchronize_irq(rx->dd); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci for (i = 0; i < rx->num_rx_q; i++) { 28662306a36Sopenharmony_ci struct hfi1_netdev_rxq *rxq = &rx->rxq[i]; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dd_dev_info(rx->dd, "disabling queue %d on context %d\n", i, 28962306a36Sopenharmony_ci rxq->rcd->ctxt); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* wait for napi if it was scheduled */ 29262306a36Sopenharmony_ci hfi1_rcvctrl(rx->dd, 29362306a36Sopenharmony_ci HFI1_RCVCTRL_CTXT_DIS | HFI1_RCVCTRL_INTRAVAIL_DIS, 29462306a36Sopenharmony_ci rxq->rcd); 29562306a36Sopenharmony_ci napi_synchronize(&rxq->napi); 29662306a36Sopenharmony_ci napi_disable(&rxq->napi); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/** 30162306a36Sopenharmony_ci * hfi1_netdev_rx_init - Incrememnts netdevs counter. When called first time, 30262306a36Sopenharmony_ci * it allocates receive queue data and calls netif_napi_add 30362306a36Sopenharmony_ci * for each queue. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * @dd: hfi1 dev data 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ciint hfi1_netdev_rx_init(struct hfi1_devdata *dd) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct hfi1_netdev_rx *rx = dd->netdev_rx; 31062306a36Sopenharmony_ci int res; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (atomic_fetch_inc(&rx->netdevs)) 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci mutex_lock(&hfi1_mutex); 31662306a36Sopenharmony_ci res = hfi1_netdev_rxq_init(rx); 31762306a36Sopenharmony_ci mutex_unlock(&hfi1_mutex); 31862306a36Sopenharmony_ci return res; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/** 32262306a36Sopenharmony_ci * hfi1_netdev_rx_destroy - Decrements netdevs counter, when it reaches 0 32362306a36Sopenharmony_ci * napi is deleted and receive queses memory is freed. 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * @dd: hfi1 dev data 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ciint hfi1_netdev_rx_destroy(struct hfi1_devdata *dd) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct hfi1_netdev_rx *rx = dd->netdev_rx; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* destroy the RX queues only if it is the last netdev going away */ 33262306a36Sopenharmony_ci if (atomic_fetch_add_unless(&rx->netdevs, -1, 0) == 1) { 33362306a36Sopenharmony_ci mutex_lock(&hfi1_mutex); 33462306a36Sopenharmony_ci hfi1_netdev_rxq_deinit(rx); 33562306a36Sopenharmony_ci mutex_unlock(&hfi1_mutex); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/** 34262306a36Sopenharmony_ci * hfi1_alloc_rx - Allocates the rx support structure 34362306a36Sopenharmony_ci * @dd: hfi1 dev data 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * Allocate the rx structure to support gathering the receive 34662306a36Sopenharmony_ci * resources and the dummy netdev. 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * Updates dd struct pointer upon success. 34962306a36Sopenharmony_ci * 35062306a36Sopenharmony_ci * Return: 0 (success) -error on failure 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ciint hfi1_alloc_rx(struct hfi1_devdata *dd) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct hfi1_netdev_rx *rx; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci dd_dev_info(dd, "allocating rx size %ld\n", sizeof(*rx)); 35862306a36Sopenharmony_ci rx = kzalloc_node(sizeof(*rx), GFP_KERNEL, dd->node); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (!rx) 36162306a36Sopenharmony_ci return -ENOMEM; 36262306a36Sopenharmony_ci rx->dd = dd; 36362306a36Sopenharmony_ci init_dummy_netdev(&rx->rx_napi); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci xa_init(&rx->dev_tbl); 36662306a36Sopenharmony_ci atomic_set(&rx->enabled, 0); 36762306a36Sopenharmony_ci atomic_set(&rx->netdevs, 0); 36862306a36Sopenharmony_ci dd->netdev_rx = rx; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_civoid hfi1_free_rx(struct hfi1_devdata *dd) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci if (dd->netdev_rx) { 37662306a36Sopenharmony_ci dd_dev_info(dd, "hfi1 rx freed\n"); 37762306a36Sopenharmony_ci kfree(dd->netdev_rx); 37862306a36Sopenharmony_ci dd->netdev_rx = NULL; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci/** 38362306a36Sopenharmony_ci * hfi1_netdev_enable_queues - This is napi enable function. 38462306a36Sopenharmony_ci * It enables napi objects associated with queues. 38562306a36Sopenharmony_ci * When at least one device has called it it increments atomic counter. 38662306a36Sopenharmony_ci * Disable function decrements counter and when it is 0, 38762306a36Sopenharmony_ci * calls napi_disable for every queue. 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * @dd: hfi1 dev data 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_civoid hfi1_netdev_enable_queues(struct hfi1_devdata *dd) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct hfi1_netdev_rx *rx; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!dd->netdev_rx) 39662306a36Sopenharmony_ci return; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci rx = dd->netdev_rx; 39962306a36Sopenharmony_ci if (atomic_fetch_inc(&rx->enabled)) 40062306a36Sopenharmony_ci return; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci mutex_lock(&hfi1_mutex); 40362306a36Sopenharmony_ci enable_queues(rx); 40462306a36Sopenharmony_ci mutex_unlock(&hfi1_mutex); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_civoid hfi1_netdev_disable_queues(struct hfi1_devdata *dd) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct hfi1_netdev_rx *rx; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (!dd->netdev_rx) 41262306a36Sopenharmony_ci return; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci rx = dd->netdev_rx; 41562306a36Sopenharmony_ci if (atomic_dec_if_positive(&rx->enabled)) 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci mutex_lock(&hfi1_mutex); 41962306a36Sopenharmony_ci disable_queues(rx); 42062306a36Sopenharmony_ci mutex_unlock(&hfi1_mutex); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/** 42462306a36Sopenharmony_ci * hfi1_netdev_add_data - Registers data with unique identifier 42562306a36Sopenharmony_ci * to be requested later this is needed for VNIC and IPoIB VLANs 42662306a36Sopenharmony_ci * implementations. 42762306a36Sopenharmony_ci * This call is protected by mutex idr_lock. 42862306a36Sopenharmony_ci * 42962306a36Sopenharmony_ci * @dd: hfi1 dev data 43062306a36Sopenharmony_ci * @id: requested integer id up to INT_MAX 43162306a36Sopenharmony_ci * @data: data to be associated with index 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_ciint hfi1_netdev_add_data(struct hfi1_devdata *dd, int id, void *data) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct hfi1_netdev_rx *rx = dd->netdev_rx; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return xa_insert(&rx->dev_tbl, id, data, GFP_NOWAIT); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * hfi1_netdev_remove_data - Removes data with previously given id. 44262306a36Sopenharmony_ci * Returns the reference to removed entry. 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * @dd: hfi1 dev data 44562306a36Sopenharmony_ci * @id: requested integer id up to INT_MAX 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_civoid *hfi1_netdev_remove_data(struct hfi1_devdata *dd, int id) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct hfi1_netdev_rx *rx = dd->netdev_rx; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci return xa_erase(&rx->dev_tbl, id); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/** 45562306a36Sopenharmony_ci * hfi1_netdev_get_data - Gets data with given id 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci * @dd: hfi1 dev data 45862306a36Sopenharmony_ci * @id: requested integer id up to INT_MAX 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_civoid *hfi1_netdev_get_data(struct hfi1_devdata *dd, int id) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct hfi1_netdev_rx *rx = dd->netdev_rx; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci return xa_load(&rx->dev_tbl, id); 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/** 46862306a36Sopenharmony_ci * hfi1_netdev_get_first_data - Gets first entry with greater or equal id. 46962306a36Sopenharmony_ci * 47062306a36Sopenharmony_ci * @dd: hfi1 dev data 47162306a36Sopenharmony_ci * @start_id: requested integer id up to INT_MAX 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_civoid *hfi1_netdev_get_first_data(struct hfi1_devdata *dd, int *start_id) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct hfi1_netdev_rx *rx = dd->netdev_rx; 47662306a36Sopenharmony_ci unsigned long index = *start_id; 47762306a36Sopenharmony_ci void *ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ret = xa_find(&rx->dev_tbl, &index, UINT_MAX, XA_PRESENT); 48062306a36Sopenharmony_ci *start_id = (int)index; 48162306a36Sopenharmony_ci return ret; 48262306a36Sopenharmony_ci} 483