19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM * CDDL HEADER START
39517SBill.Taylor@Sun.COM *
49517SBill.Taylor@Sun.COM * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM *
89517SBill.Taylor@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM * and limitations under the License.
129517SBill.Taylor@Sun.COM *
139517SBill.Taylor@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM *
199517SBill.Taylor@Sun.COM * CDDL HEADER END
209517SBill.Taylor@Sun.COM */
219517SBill.Taylor@Sun.COM
229517SBill.Taylor@Sun.COM /*
23*12965SWilliam.Taylor@Oracle.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM */
259517SBill.Taylor@Sun.COM
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM * hermon_srq.c
289517SBill.Taylor@Sun.COM * Hermon Shared Receive Queue Processing Routines
299517SBill.Taylor@Sun.COM *
309517SBill.Taylor@Sun.COM * Implements all the routines necessary for allocating, freeing, querying,
319517SBill.Taylor@Sun.COM * modifying and posting shared receive queues.
329517SBill.Taylor@Sun.COM */
339517SBill.Taylor@Sun.COM
349517SBill.Taylor@Sun.COM #include <sys/types.h>
359517SBill.Taylor@Sun.COM #include <sys/conf.h>
369517SBill.Taylor@Sun.COM #include <sys/ddi.h>
379517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
389517SBill.Taylor@Sun.COM #include <sys/modctl.h>
399517SBill.Taylor@Sun.COM #include <sys/bitmap.h>
409517SBill.Taylor@Sun.COM
419517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
429517SBill.Taylor@Sun.COM
439517SBill.Taylor@Sun.COM static void hermon_srq_sgl_to_logwqesz(hermon_state_t *state, uint_t num_sgl,
449517SBill.Taylor@Sun.COM hermon_qp_wq_type_t wq_type, uint_t *logwqesz, uint_t *max_sgl);
459517SBill.Taylor@Sun.COM
469517SBill.Taylor@Sun.COM /*
479517SBill.Taylor@Sun.COM * hermon_srq_alloc()
489517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
499517SBill.Taylor@Sun.COM */
509517SBill.Taylor@Sun.COM int
hermon_srq_alloc(hermon_state_t * state,hermon_srq_info_t * srqinfo,uint_t sleepflag)519517SBill.Taylor@Sun.COM hermon_srq_alloc(hermon_state_t *state, hermon_srq_info_t *srqinfo,
529517SBill.Taylor@Sun.COM uint_t sleepflag)
539517SBill.Taylor@Sun.COM {
549517SBill.Taylor@Sun.COM ibt_srq_hdl_t ibt_srqhdl;
559517SBill.Taylor@Sun.COM hermon_pdhdl_t pd;
569517SBill.Taylor@Sun.COM ibt_srq_sizes_t *sizes;
579517SBill.Taylor@Sun.COM ibt_srq_sizes_t *real_sizes;
589517SBill.Taylor@Sun.COM hermon_srqhdl_t *srqhdl;
599517SBill.Taylor@Sun.COM ibt_srq_flags_t flags;
609517SBill.Taylor@Sun.COM hermon_rsrc_t *srqc, *rsrc;
619517SBill.Taylor@Sun.COM hermon_hw_srqc_t srqc_entry;
629517SBill.Taylor@Sun.COM uint32_t *buf;
639517SBill.Taylor@Sun.COM hermon_srqhdl_t srq;
649517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *umapdb;
659517SBill.Taylor@Sun.COM ibt_mr_attr_t mr_attr;
669517SBill.Taylor@Sun.COM hermon_mr_options_t mr_op;
679517SBill.Taylor@Sun.COM hermon_mrhdl_t mr;
689517SBill.Taylor@Sun.COM uint64_t value, srq_desc_off;
699517SBill.Taylor@Sun.COM uint32_t log_srq_size;
709517SBill.Taylor@Sun.COM uint32_t uarpg;
719517SBill.Taylor@Sun.COM uint_t srq_is_umap;
729517SBill.Taylor@Sun.COM int flag, status;
739517SBill.Taylor@Sun.COM uint_t max_sgl;
749517SBill.Taylor@Sun.COM uint_t wqesz;
759517SBill.Taylor@Sun.COM uint_t srq_wr_sz;
769517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sizes))
779517SBill.Taylor@Sun.COM
789517SBill.Taylor@Sun.COM /*
799517SBill.Taylor@Sun.COM * options-->wq_location used to be for location, now explicitly
809517SBill.Taylor@Sun.COM * LOCATION_NORMAL
819517SBill.Taylor@Sun.COM */
829517SBill.Taylor@Sun.COM
839517SBill.Taylor@Sun.COM /*
849517SBill.Taylor@Sun.COM * Extract the necessary info from the hermon_srq_info_t structure
859517SBill.Taylor@Sun.COM */
869517SBill.Taylor@Sun.COM real_sizes = srqinfo->srqi_real_sizes;
879517SBill.Taylor@Sun.COM sizes = srqinfo->srqi_sizes;
889517SBill.Taylor@Sun.COM pd = srqinfo->srqi_pd;
899517SBill.Taylor@Sun.COM ibt_srqhdl = srqinfo->srqi_ibt_srqhdl;
909517SBill.Taylor@Sun.COM flags = srqinfo->srqi_flags;
919517SBill.Taylor@Sun.COM srqhdl = srqinfo->srqi_srqhdl;
929517SBill.Taylor@Sun.COM
939517SBill.Taylor@Sun.COM /*
949517SBill.Taylor@Sun.COM * Determine whether SRQ is being allocated for userland access or
959517SBill.Taylor@Sun.COM * whether it is being allocated for kernel access. If the SRQ is
969517SBill.Taylor@Sun.COM * being allocated for userland access, then lookup the UAR doorbell
979517SBill.Taylor@Sun.COM * page number for the current process. Note: If this is not found
989517SBill.Taylor@Sun.COM * (e.g. if the process has not previously open()'d the Hermon driver),
999517SBill.Taylor@Sun.COM * then an error is returned.
1009517SBill.Taylor@Sun.COM */
1019517SBill.Taylor@Sun.COM srq_is_umap = (flags & IBT_SRQ_USER_MAP) ? 1 : 0;
1029517SBill.Taylor@Sun.COM if (srq_is_umap) {
1039517SBill.Taylor@Sun.COM status = hermon_umap_db_find(state->hs_instance, ddi_get_pid(),
1049517SBill.Taylor@Sun.COM MLNX_UMAP_UARPG_RSRC, &value, 0, NULL);
1059517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
1069517SBill.Taylor@Sun.COM status = IBT_INVALID_PARAM;
1079517SBill.Taylor@Sun.COM goto srqalloc_fail3;
1089517SBill.Taylor@Sun.COM }
1099517SBill.Taylor@Sun.COM uarpg = ((hermon_rsrc_t *)(uintptr_t)value)->hr_indx;
1109517SBill.Taylor@Sun.COM } else {
1119517SBill.Taylor@Sun.COM uarpg = state->hs_kernel_uar_index;
1129517SBill.Taylor@Sun.COM }
1139517SBill.Taylor@Sun.COM
1149517SBill.Taylor@Sun.COM /* Increase PD refcnt */
1159517SBill.Taylor@Sun.COM hermon_pd_refcnt_inc(pd);
1169517SBill.Taylor@Sun.COM
1179517SBill.Taylor@Sun.COM /* Allocate an SRQ context entry */
1189517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_SRQC, 1, sleepflag, &srqc);
1199517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
1209517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
1219517SBill.Taylor@Sun.COM goto srqalloc_fail1;
1229517SBill.Taylor@Sun.COM }
1239517SBill.Taylor@Sun.COM
1249517SBill.Taylor@Sun.COM /* Allocate the SRQ Handle entry */
1259517SBill.Taylor@Sun.COM status = hermon_rsrc_alloc(state, HERMON_SRQHDL, 1, sleepflag, &rsrc);
1269517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
1279517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
1289517SBill.Taylor@Sun.COM goto srqalloc_fail2;
1299517SBill.Taylor@Sun.COM }
1309517SBill.Taylor@Sun.COM
1319517SBill.Taylor@Sun.COM srq = (hermon_srqhdl_t)rsrc->hr_addr;
1329517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*srq))
1339517SBill.Taylor@Sun.COM
1349517SBill.Taylor@Sun.COM bzero(srq, sizeof (struct hermon_sw_srq_s));
1359517SBill.Taylor@Sun.COM /* Calculate the SRQ number */
1369517SBill.Taylor@Sun.COM
1379517SBill.Taylor@Sun.COM /* just use the index, implicit in Hermon */
1389517SBill.Taylor@Sun.COM srq->srq_srqnum = srqc->hr_indx;
1399517SBill.Taylor@Sun.COM
1409517SBill.Taylor@Sun.COM /*
1419517SBill.Taylor@Sun.COM * If this will be a user-mappable SRQ, then allocate an entry for
1429517SBill.Taylor@Sun.COM * the "userland resources database". This will later be added to
1439517SBill.Taylor@Sun.COM * the database (after all further SRQ operations are successful).
1449517SBill.Taylor@Sun.COM * If we fail here, we must undo the reference counts and the
1459517SBill.Taylor@Sun.COM * previous resource allocation.
1469517SBill.Taylor@Sun.COM */
1479517SBill.Taylor@Sun.COM if (srq_is_umap) {
1489517SBill.Taylor@Sun.COM umapdb = hermon_umap_db_alloc(state->hs_instance,
1499517SBill.Taylor@Sun.COM srq->srq_srqnum, MLNX_UMAP_SRQMEM_RSRC,
1509517SBill.Taylor@Sun.COM (uint64_t)(uintptr_t)rsrc);
1519517SBill.Taylor@Sun.COM if (umapdb == NULL) {
1529517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
1539517SBill.Taylor@Sun.COM goto srqalloc_fail3;
1549517SBill.Taylor@Sun.COM }
1559517SBill.Taylor@Sun.COM }
1569517SBill.Taylor@Sun.COM
1579517SBill.Taylor@Sun.COM /*
1589517SBill.Taylor@Sun.COM * Allocate the doorbell record. Hermon just needs one for the
1599517SBill.Taylor@Sun.COM * SRQ, and use uarpg (above) as the uar index
1609517SBill.Taylor@Sun.COM */
1619517SBill.Taylor@Sun.COM
1629517SBill.Taylor@Sun.COM status = hermon_dbr_alloc(state, uarpg, &srq->srq_wq_dbr_acchdl,
1639517SBill.Taylor@Sun.COM &srq->srq_wq_vdbr, &srq->srq_wq_pdbr, &srq->srq_rdbr_mapoffset);
1649517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
1659517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
1669517SBill.Taylor@Sun.COM goto srqalloc_fail4;
1679517SBill.Taylor@Sun.COM }
1689517SBill.Taylor@Sun.COM
1699517SBill.Taylor@Sun.COM /*
1709517SBill.Taylor@Sun.COM * Calculate the appropriate size for the SRQ.
1719517SBill.Taylor@Sun.COM * Note: All Hermon SRQs must be a power-of-2 in size. Also
1729517SBill.Taylor@Sun.COM * they may not be any smaller than HERMON_SRQ_MIN_SIZE. This step
1739517SBill.Taylor@Sun.COM * is to round the requested size up to the next highest power-of-2
1749517SBill.Taylor@Sun.COM */
1759517SBill.Taylor@Sun.COM srq_wr_sz = max(sizes->srq_wr_sz + 1, HERMON_SRQ_MIN_SIZE);
1769517SBill.Taylor@Sun.COM log_srq_size = highbit(srq_wr_sz);
1779517SBill.Taylor@Sun.COM if ((srq_wr_sz & (srq_wr_sz - 1)) == 0) {
1789517SBill.Taylor@Sun.COM log_srq_size = log_srq_size - 1;
1799517SBill.Taylor@Sun.COM }
1809517SBill.Taylor@Sun.COM
1819517SBill.Taylor@Sun.COM /*
1829517SBill.Taylor@Sun.COM * Next we verify that the rounded-up size is valid (i.e. consistent
1839517SBill.Taylor@Sun.COM * with the device limits and/or software-configured limits). If not,
1849517SBill.Taylor@Sun.COM * then obviously we have a lot of cleanup to do before returning.
1859517SBill.Taylor@Sun.COM */
1869517SBill.Taylor@Sun.COM if (log_srq_size > state->hs_cfg_profile->cp_log_max_srq_sz) {
1879517SBill.Taylor@Sun.COM status = IBT_HCA_WR_EXCEEDED;
1889517SBill.Taylor@Sun.COM goto srqalloc_fail4a;
1899517SBill.Taylor@Sun.COM }
1909517SBill.Taylor@Sun.COM
1919517SBill.Taylor@Sun.COM /*
1929517SBill.Taylor@Sun.COM * Next we verify that the requested number of SGL is valid (i.e.
1939517SBill.Taylor@Sun.COM * consistent with the device limits and/or software-configured
1949517SBill.Taylor@Sun.COM * limits). If not, then obviously the same cleanup needs to be done.
1959517SBill.Taylor@Sun.COM */
1969517SBill.Taylor@Sun.COM max_sgl = state->hs_ibtfinfo.hca_attr->hca_max_srq_sgl;
1979517SBill.Taylor@Sun.COM if (sizes->srq_sgl_sz > max_sgl) {
1989517SBill.Taylor@Sun.COM status = IBT_HCA_SGL_EXCEEDED;
1999517SBill.Taylor@Sun.COM goto srqalloc_fail4a;
2009517SBill.Taylor@Sun.COM }
2019517SBill.Taylor@Sun.COM
2029517SBill.Taylor@Sun.COM /*
2039517SBill.Taylor@Sun.COM * Determine the SRQ's WQE sizes. This depends on the requested
2049517SBill.Taylor@Sun.COM * number of SGLs. Note: This also has the side-effect of
2059517SBill.Taylor@Sun.COM * calculating the real number of SGLs (for the calculated WQE size)
2069517SBill.Taylor@Sun.COM */
2079517SBill.Taylor@Sun.COM hermon_srq_sgl_to_logwqesz(state, sizes->srq_sgl_sz,
2089517SBill.Taylor@Sun.COM HERMON_QP_WQ_TYPE_RECVQ, &srq->srq_wq_log_wqesz,
2099517SBill.Taylor@Sun.COM &srq->srq_wq_sgl);
2109517SBill.Taylor@Sun.COM
2119517SBill.Taylor@Sun.COM /*
2129517SBill.Taylor@Sun.COM * Allocate the memory for SRQ work queues. Note: The location from
2139517SBill.Taylor@Sun.COM * which we will allocate these work queues is always
2149517SBill.Taylor@Sun.COM * QUEUE_LOCATION_NORMAL. Since Hermon work queues are not
2159517SBill.Taylor@Sun.COM * allowed to cross a 32-bit (4GB) boundary, the alignment of the work
2169517SBill.Taylor@Sun.COM * queue memory is very important. We used to allocate work queues
2179517SBill.Taylor@Sun.COM * (the combined receive and send queues) so that they would be aligned
2189517SBill.Taylor@Sun.COM * on their combined size. That alignment guaranteed that they would
2199517SBill.Taylor@Sun.COM * never cross the 4GB boundary (Hermon work queues are on the order of
2209517SBill.Taylor@Sun.COM * MBs at maximum). Now we are able to relax this alignment constraint
2219517SBill.Taylor@Sun.COM * by ensuring that the IB address assigned to the queue memory (as a
2229517SBill.Taylor@Sun.COM * result of the hermon_mr_register() call) is offset from zero.
2239517SBill.Taylor@Sun.COM * Previously, we had wanted to use the ddi_dma_mem_alloc() routine to
2249517SBill.Taylor@Sun.COM * guarantee the alignment, but when attempting to use IOMMU bypass
2259517SBill.Taylor@Sun.COM * mode we found that we were not allowed to specify any alignment that
2269517SBill.Taylor@Sun.COM * was more restrictive than the system page size. So we avoided this
2279517SBill.Taylor@Sun.COM * constraint by passing two alignment values, one for the memory
2289517SBill.Taylor@Sun.COM * allocation itself and the other for the DMA handle (for later bind).
2299517SBill.Taylor@Sun.COM * This used to cause more memory than necessary to be allocated (in
2309517SBill.Taylor@Sun.COM * order to guarantee the more restrictive alignment contraint). But
2319517SBill.Taylor@Sun.COM * be guaranteeing the zero-based IB virtual address for the queue, we
2329517SBill.Taylor@Sun.COM * are able to conserve this memory.
2339517SBill.Taylor@Sun.COM *
2349517SBill.Taylor@Sun.COM * Note: If SRQ is not user-mappable, then it may come from either
2359517SBill.Taylor@Sun.COM * kernel system memory or from HCA-attached local DDR memory.
2369517SBill.Taylor@Sun.COM *
2379517SBill.Taylor@Sun.COM * Note2: We align this queue on a pagesize boundary. This is required
2389517SBill.Taylor@Sun.COM * to make sure that all the resulting IB addresses will start at 0, for
2399517SBill.Taylor@Sun.COM * a zero-based queue. By making sure we are aligned on at least a
2409517SBill.Taylor@Sun.COM * page, any offset we use into our queue will be the same as when we
2419517SBill.Taylor@Sun.COM * perform hermon_srq_modify() operations later.
2429517SBill.Taylor@Sun.COM */
2439517SBill.Taylor@Sun.COM wqesz = (1 << srq->srq_wq_log_wqesz);
2449517SBill.Taylor@Sun.COM srq->srq_wqinfo.qa_size = (1 << log_srq_size) * wqesz;
2459517SBill.Taylor@Sun.COM srq->srq_wqinfo.qa_alloc_align = PAGESIZE;
2469517SBill.Taylor@Sun.COM srq->srq_wqinfo.qa_bind_align = PAGESIZE;
2479517SBill.Taylor@Sun.COM if (srq_is_umap) {
2489517SBill.Taylor@Sun.COM srq->srq_wqinfo.qa_location = HERMON_QUEUE_LOCATION_USERLAND;
2499517SBill.Taylor@Sun.COM } else {
2509517SBill.Taylor@Sun.COM srq->srq_wqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
2519517SBill.Taylor@Sun.COM }
2529517SBill.Taylor@Sun.COM status = hermon_queue_alloc(state, &srq->srq_wqinfo, sleepflag);
2539517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
2549517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
2559517SBill.Taylor@Sun.COM goto srqalloc_fail4a;
2569517SBill.Taylor@Sun.COM }
2579517SBill.Taylor@Sun.COM buf = (uint32_t *)srq->srq_wqinfo.qa_buf_aligned;
2589517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*buf))
2599517SBill.Taylor@Sun.COM
2609517SBill.Taylor@Sun.COM /*
2619517SBill.Taylor@Sun.COM * Register the memory for the SRQ work queues. The memory for the SRQ
2629517SBill.Taylor@Sun.COM * must be registered in the Hermon cMPT tables. This gives us the LKey
2639517SBill.Taylor@Sun.COM * to specify in the SRQ context later. Note: If the work queue is to
2649517SBill.Taylor@Sun.COM * be allocated from DDR memory, then only a "bypass" mapping is
2659517SBill.Taylor@Sun.COM * appropriate. And if the SRQ memory is user-mappable, then we force
2669517SBill.Taylor@Sun.COM * DDI_DMA_CONSISTENT mapping. Also, in order to meet the alignment
2679517SBill.Taylor@Sun.COM * restriction, we pass the "mro_bind_override_addr" flag in the call
2689517SBill.Taylor@Sun.COM * to hermon_mr_register(). This guarantees that the resulting IB vaddr
2699517SBill.Taylor@Sun.COM * will be zero-based (modulo the offset into the first page). If we
2709517SBill.Taylor@Sun.COM * fail here, we still have the bunch of resource and reference count
2719517SBill.Taylor@Sun.COM * cleanup to do.
2729517SBill.Taylor@Sun.COM */
2739517SBill.Taylor@Sun.COM flag = (sleepflag == HERMON_SLEEP) ? IBT_MR_SLEEP :
2749517SBill.Taylor@Sun.COM IBT_MR_NOSLEEP;
2759517SBill.Taylor@Sun.COM mr_attr.mr_vaddr = (uint64_t)(uintptr_t)buf;
2769517SBill.Taylor@Sun.COM mr_attr.mr_len = srq->srq_wqinfo.qa_size;
2779517SBill.Taylor@Sun.COM mr_attr.mr_as = NULL;
2789517SBill.Taylor@Sun.COM mr_attr.mr_flags = flag | IBT_MR_ENABLE_LOCAL_WRITE;
2799517SBill.Taylor@Sun.COM mr_op.mro_bind_type = state->hs_cfg_profile->cp_iommu_bypass;
2809517SBill.Taylor@Sun.COM mr_op.mro_bind_dmahdl = srq->srq_wqinfo.qa_dmahdl;
2819517SBill.Taylor@Sun.COM mr_op.mro_bind_override_addr = 1;
2829517SBill.Taylor@Sun.COM status = hermon_mr_register(state, pd, &mr_attr, &mr,
2839517SBill.Taylor@Sun.COM &mr_op, HERMON_SRQ_CMPT);
2849517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
2859517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
2869517SBill.Taylor@Sun.COM goto srqalloc_fail5;
2879517SBill.Taylor@Sun.COM }
2889517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mr))
2899517SBill.Taylor@Sun.COM
2909517SBill.Taylor@Sun.COM /*
2919517SBill.Taylor@Sun.COM * Calculate the offset between the kernel virtual address space
2929517SBill.Taylor@Sun.COM * and the IB virtual address space. This will be used when
2939517SBill.Taylor@Sun.COM * posting work requests to properly initialize each WQE.
2949517SBill.Taylor@Sun.COM */
2959517SBill.Taylor@Sun.COM srq_desc_off = (uint64_t)(uintptr_t)srq->srq_wqinfo.qa_buf_aligned -
2969517SBill.Taylor@Sun.COM (uint64_t)mr->mr_bindinfo.bi_addr;
2979517SBill.Taylor@Sun.COM
2989517SBill.Taylor@Sun.COM srq->srq_wq_wqhdr = hermon_wrid_wqhdr_create(1 << log_srq_size);
2999517SBill.Taylor@Sun.COM
3009517SBill.Taylor@Sun.COM /*
3019517SBill.Taylor@Sun.COM * Fill in all the return arguments (if necessary). This includes
3029517SBill.Taylor@Sun.COM * real queue size and real SGLs.
3039517SBill.Taylor@Sun.COM */
3049517SBill.Taylor@Sun.COM if (real_sizes != NULL) {
3059517SBill.Taylor@Sun.COM real_sizes->srq_wr_sz = (1 << log_srq_size) - 1;
3069517SBill.Taylor@Sun.COM real_sizes->srq_sgl_sz = srq->srq_wq_sgl;
3079517SBill.Taylor@Sun.COM }
3089517SBill.Taylor@Sun.COM
3099517SBill.Taylor@Sun.COM /*
3109517SBill.Taylor@Sun.COM * Fill in the SRQC entry. This is the final step before passing
3119517SBill.Taylor@Sun.COM * ownership of the SRQC entry to the Hermon hardware. We use all of
3129517SBill.Taylor@Sun.COM * the information collected/calculated above to fill in the
3139517SBill.Taylor@Sun.COM * requisite portions of the SRQC. Note: If this SRQ is going to be
3149517SBill.Taylor@Sun.COM * used for userland access, then we need to set the UAR page number
3159517SBill.Taylor@Sun.COM * appropriately (otherwise it's a "don't care")
3169517SBill.Taylor@Sun.COM */
3179517SBill.Taylor@Sun.COM bzero(&srqc_entry, sizeof (hermon_hw_srqc_t));
3189517SBill.Taylor@Sun.COM srqc_entry.state = HERMON_SRQ_STATE_HW_OWNER;
3199517SBill.Taylor@Sun.COM srqc_entry.log_srq_size = log_srq_size;
3209517SBill.Taylor@Sun.COM srqc_entry.srqn = srq->srq_srqnum;
3219517SBill.Taylor@Sun.COM srqc_entry.log_rq_stride = srq->srq_wq_log_wqesz - 4;
3229517SBill.Taylor@Sun.COM /* 16-byte chunks */
3239517SBill.Taylor@Sun.COM
3249517SBill.Taylor@Sun.COM srqc_entry.page_offs = srq->srq_wqinfo.qa_pgoffs >> 6;
3259517SBill.Taylor@Sun.COM srqc_entry.log2_pgsz = mr->mr_log2_pgsz;
3269517SBill.Taylor@Sun.COM srqc_entry.mtt_base_addrh = (uint32_t)((mr->mr_mttaddr >> 32) & 0xFF);
3279517SBill.Taylor@Sun.COM srqc_entry.mtt_base_addrl = mr->mr_mttaddr >> 3;
3289517SBill.Taylor@Sun.COM srqc_entry.pd = pd->pd_pdnum;
3299517SBill.Taylor@Sun.COM srqc_entry.dbr_addrh = (uint32_t)((uint64_t)srq->srq_wq_pdbr >> 32);
3309517SBill.Taylor@Sun.COM srqc_entry.dbr_addrl = (uint32_t)((uint64_t)srq->srq_wq_pdbr >> 2);
3319517SBill.Taylor@Sun.COM
3329517SBill.Taylor@Sun.COM /*
3339517SBill.Taylor@Sun.COM * all others - specifically, xrcd, cqn_xrc, lwm, wqe_cnt, and wqe_cntr
3349517SBill.Taylor@Sun.COM * are zero thanks to the bzero of the structure
3359517SBill.Taylor@Sun.COM */
3369517SBill.Taylor@Sun.COM
3379517SBill.Taylor@Sun.COM /*
3389517SBill.Taylor@Sun.COM * Write the SRQC entry to hardware. Lastly, we pass ownership of
3399517SBill.Taylor@Sun.COM * the entry to the hardware (using the Hermon SW2HW_SRQ firmware
3409517SBill.Taylor@Sun.COM * command). Note: In general, this operation shouldn't fail. But
3419517SBill.Taylor@Sun.COM * if it does, we have to undo everything we've done above before
3429517SBill.Taylor@Sun.COM * returning error.
3439517SBill.Taylor@Sun.COM */
3449517SBill.Taylor@Sun.COM status = hermon_cmn_ownership_cmd_post(state, SW2HW_SRQ, &srqc_entry,
3459517SBill.Taylor@Sun.COM sizeof (hermon_hw_srqc_t), srq->srq_srqnum,
3469517SBill.Taylor@Sun.COM sleepflag);
3479517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
3489517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: SW2HW_SRQ command failed: %08x\n",
3499517SBill.Taylor@Sun.COM status);
3509517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
3519517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
3529517SBill.Taylor@Sun.COM }
3539517SBill.Taylor@Sun.COM status = ibc_get_ci_failure(0);
3549517SBill.Taylor@Sun.COM goto srqalloc_fail8;
3559517SBill.Taylor@Sun.COM }
3569517SBill.Taylor@Sun.COM
3579517SBill.Taylor@Sun.COM /*
3589517SBill.Taylor@Sun.COM * Fill in the rest of the Hermon SRQ handle. We can update
3599517SBill.Taylor@Sun.COM * the following fields for use in further operations on the SRQ.
3609517SBill.Taylor@Sun.COM */
3619517SBill.Taylor@Sun.COM srq->srq_srqcrsrcp = srqc;
3629517SBill.Taylor@Sun.COM srq->srq_rsrcp = rsrc;
3639517SBill.Taylor@Sun.COM srq->srq_mrhdl = mr;
3649517SBill.Taylor@Sun.COM srq->srq_refcnt = 0;
3659517SBill.Taylor@Sun.COM srq->srq_is_umap = srq_is_umap;
3669517SBill.Taylor@Sun.COM srq->srq_uarpg = uarpg;
3679517SBill.Taylor@Sun.COM srq->srq_umap_dhp = (devmap_cookie_t)NULL;
3689517SBill.Taylor@Sun.COM srq->srq_pdhdl = pd;
3699517SBill.Taylor@Sun.COM srq->srq_wq_bufsz = (1 << log_srq_size);
3709517SBill.Taylor@Sun.COM srq->srq_wq_buf = buf;
3719517SBill.Taylor@Sun.COM srq->srq_desc_off = srq_desc_off;
3729517SBill.Taylor@Sun.COM srq->srq_hdlrarg = (void *)ibt_srqhdl;
3739517SBill.Taylor@Sun.COM srq->srq_state = 0;
3749517SBill.Taylor@Sun.COM srq->srq_real_sizes.srq_wr_sz = (1 << log_srq_size);
3759517SBill.Taylor@Sun.COM srq->srq_real_sizes.srq_sgl_sz = srq->srq_wq_sgl;
3769517SBill.Taylor@Sun.COM
3779517SBill.Taylor@Sun.COM /*
3789517SBill.Taylor@Sun.COM * Put SRQ handle in Hermon SRQNum-to-SRQhdl list. Then fill in the
3799517SBill.Taylor@Sun.COM * "srqhdl" and return success
3809517SBill.Taylor@Sun.COM */
381*12965SWilliam.Taylor@Oracle.COM hermon_icm_set_num_to_hdl(state, HERMON_SRQC, srqc->hr_indx, srq);
3829517SBill.Taylor@Sun.COM
3839517SBill.Taylor@Sun.COM /*
3849517SBill.Taylor@Sun.COM * If this is a user-mappable SRQ, then we need to insert the
3859517SBill.Taylor@Sun.COM * previously allocated entry into the "userland resources database".
3869517SBill.Taylor@Sun.COM * This will allow for later lookup during devmap() (i.e. mmap())
3879517SBill.Taylor@Sun.COM * calls.
3889517SBill.Taylor@Sun.COM */
3899517SBill.Taylor@Sun.COM if (srq->srq_is_umap) {
3909517SBill.Taylor@Sun.COM hermon_umap_db_add(umapdb);
3919517SBill.Taylor@Sun.COM } else { /* initialize work queue for kernel SRQs */
3929517SBill.Taylor@Sun.COM int i, len, last;
3939517SBill.Taylor@Sun.COM uint16_t *desc;
3949517SBill.Taylor@Sun.COM
3959517SBill.Taylor@Sun.COM desc = (uint16_t *)buf;
3969517SBill.Taylor@Sun.COM len = wqesz / sizeof (*desc);
3979517SBill.Taylor@Sun.COM last = srq->srq_wq_bufsz - 1;
3989517SBill.Taylor@Sun.COM for (i = 0; i < last; i++) {
3999517SBill.Taylor@Sun.COM desc[1] = htons(i + 1);
4009517SBill.Taylor@Sun.COM desc += len;
4019517SBill.Taylor@Sun.COM }
4029517SBill.Taylor@Sun.COM srq->srq_wq_wqhdr->wq_tail = last;
4039517SBill.Taylor@Sun.COM srq->srq_wq_wqhdr->wq_head = 0;
4049517SBill.Taylor@Sun.COM }
4059517SBill.Taylor@Sun.COM
4069517SBill.Taylor@Sun.COM *srqhdl = srq;
4079517SBill.Taylor@Sun.COM
4089517SBill.Taylor@Sun.COM return (status);
4099517SBill.Taylor@Sun.COM
4109517SBill.Taylor@Sun.COM /*
4119517SBill.Taylor@Sun.COM * The following is cleanup for all possible failure cases in this routine
4129517SBill.Taylor@Sun.COM */
4139517SBill.Taylor@Sun.COM srqalloc_fail8:
4149517SBill.Taylor@Sun.COM hermon_wrid_wqhdr_destroy(srq->srq_wq_wqhdr);
4159517SBill.Taylor@Sun.COM srqalloc_fail7:
4169517SBill.Taylor@Sun.COM if (hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
4179517SBill.Taylor@Sun.COM HERMON_SLEEPFLAG_FOR_CONTEXT()) != DDI_SUCCESS) {
4189517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to deregister SRQ memory");
4199517SBill.Taylor@Sun.COM }
4209517SBill.Taylor@Sun.COM srqalloc_fail5:
4219517SBill.Taylor@Sun.COM hermon_queue_free(&srq->srq_wqinfo);
4229517SBill.Taylor@Sun.COM srqalloc_fail4a:
4239517SBill.Taylor@Sun.COM hermon_dbr_free(state, uarpg, srq->srq_wq_vdbr);
4249517SBill.Taylor@Sun.COM srqalloc_fail4:
4259517SBill.Taylor@Sun.COM if (srq_is_umap) {
4269517SBill.Taylor@Sun.COM hermon_umap_db_free(umapdb);
4279517SBill.Taylor@Sun.COM }
4289517SBill.Taylor@Sun.COM srqalloc_fail3:
4299517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
4309517SBill.Taylor@Sun.COM srqalloc_fail2:
4319517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &srqc);
4329517SBill.Taylor@Sun.COM srqalloc_fail1:
4339517SBill.Taylor@Sun.COM hermon_pd_refcnt_dec(pd);
4349517SBill.Taylor@Sun.COM srqalloc_fail:
4359517SBill.Taylor@Sun.COM return (status);
4369517SBill.Taylor@Sun.COM }
4379517SBill.Taylor@Sun.COM
4389517SBill.Taylor@Sun.COM
4399517SBill.Taylor@Sun.COM /*
4409517SBill.Taylor@Sun.COM * hermon_srq_free()
4419517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
4429517SBill.Taylor@Sun.COM */
4439517SBill.Taylor@Sun.COM /* ARGSUSED */
4449517SBill.Taylor@Sun.COM int
hermon_srq_free(hermon_state_t * state,hermon_srqhdl_t * srqhdl,uint_t sleepflag)4459517SBill.Taylor@Sun.COM hermon_srq_free(hermon_state_t *state, hermon_srqhdl_t *srqhdl,
4469517SBill.Taylor@Sun.COM uint_t sleepflag)
4479517SBill.Taylor@Sun.COM {
4489517SBill.Taylor@Sun.COM hermon_rsrc_t *srqc, *rsrc;
4499517SBill.Taylor@Sun.COM hermon_umap_db_entry_t *umapdb;
4509517SBill.Taylor@Sun.COM uint64_t value;
4519517SBill.Taylor@Sun.COM hermon_srqhdl_t srq;
4529517SBill.Taylor@Sun.COM hermon_mrhdl_t mr;
4539517SBill.Taylor@Sun.COM hermon_pdhdl_t pd;
4549517SBill.Taylor@Sun.COM hermon_hw_srqc_t srqc_entry;
4559517SBill.Taylor@Sun.COM uint32_t srqnum;
4569517SBill.Taylor@Sun.COM uint_t maxprot;
4579517SBill.Taylor@Sun.COM int status;
4589517SBill.Taylor@Sun.COM
4599517SBill.Taylor@Sun.COM /*
4609517SBill.Taylor@Sun.COM * Pull all the necessary information from the Hermon Shared Receive
4619517SBill.Taylor@Sun.COM * Queue handle. This is necessary here because the resource for the
4629517SBill.Taylor@Sun.COM * SRQ handle is going to be freed up as part of this operation.
4639517SBill.Taylor@Sun.COM */
4649517SBill.Taylor@Sun.COM srq = *srqhdl;
4659517SBill.Taylor@Sun.COM mutex_enter(&srq->srq_lock);
4669517SBill.Taylor@Sun.COM srqc = srq->srq_srqcrsrcp;
4679517SBill.Taylor@Sun.COM rsrc = srq->srq_rsrcp;
4689517SBill.Taylor@Sun.COM pd = srq->srq_pdhdl;
4699517SBill.Taylor@Sun.COM mr = srq->srq_mrhdl;
4709517SBill.Taylor@Sun.COM srqnum = srq->srq_srqnum;
4719517SBill.Taylor@Sun.COM
4729517SBill.Taylor@Sun.COM /*
4739517SBill.Taylor@Sun.COM * If there are work queues still associated with the SRQ, then return
4749517SBill.Taylor@Sun.COM * an error. Otherwise, we will be holding the SRQ lock.
4759517SBill.Taylor@Sun.COM */
4769517SBill.Taylor@Sun.COM if (srq->srq_refcnt != 0) {
4779517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
4789517SBill.Taylor@Sun.COM return (IBT_SRQ_IN_USE);
4799517SBill.Taylor@Sun.COM }
4809517SBill.Taylor@Sun.COM
4819517SBill.Taylor@Sun.COM /*
4829517SBill.Taylor@Sun.COM * If this was a user-mappable SRQ, then we need to remove its entry
4839517SBill.Taylor@Sun.COM * from the "userland resources database". If it is also currently
4849517SBill.Taylor@Sun.COM * mmap()'d out to a user process, then we need to call
4859517SBill.Taylor@Sun.COM * devmap_devmem_remap() to remap the SRQ memory to an invalid mapping.
4869517SBill.Taylor@Sun.COM * We also need to invalidate the SRQ tracking information for the
4879517SBill.Taylor@Sun.COM * user mapping.
4889517SBill.Taylor@Sun.COM */
4899517SBill.Taylor@Sun.COM if (srq->srq_is_umap) {
4909517SBill.Taylor@Sun.COM status = hermon_umap_db_find(state->hs_instance,
4919517SBill.Taylor@Sun.COM srq->srq_srqnum, MLNX_UMAP_SRQMEM_RSRC, &value,
4929517SBill.Taylor@Sun.COM HERMON_UMAP_DB_REMOVE, &umapdb);
4939517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
4949517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
4959517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to find in database");
4969517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
4979517SBill.Taylor@Sun.COM }
4989517SBill.Taylor@Sun.COM hermon_umap_db_free(umapdb);
4999517SBill.Taylor@Sun.COM if (srq->srq_umap_dhp != NULL) {
5009517SBill.Taylor@Sun.COM maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
5019517SBill.Taylor@Sun.COM status = devmap_devmem_remap(srq->srq_umap_dhp,
5029517SBill.Taylor@Sun.COM state->hs_dip, 0, 0, srq->srq_wqinfo.qa_size,
5039517SBill.Taylor@Sun.COM maxprot, DEVMAP_MAPPING_INVALID, NULL);
5049517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
5059517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
5069517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed in SRQ memory "
5079517SBill.Taylor@Sun.COM "devmap_devmem_remap()");
5089517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
5099517SBill.Taylor@Sun.COM }
5109517SBill.Taylor@Sun.COM srq->srq_umap_dhp = (devmap_cookie_t)NULL;
5119517SBill.Taylor@Sun.COM }
5129517SBill.Taylor@Sun.COM }
5139517SBill.Taylor@Sun.COM
5149517SBill.Taylor@Sun.COM /*
5159517SBill.Taylor@Sun.COM * Put NULL into the Hermon SRQNum-to-SRQHdl list. This will allow any
5169517SBill.Taylor@Sun.COM * in-progress events to detect that the SRQ corresponding to this
5179517SBill.Taylor@Sun.COM * number has been freed.
5189517SBill.Taylor@Sun.COM */
519*12965SWilliam.Taylor@Oracle.COM hermon_icm_set_num_to_hdl(state, HERMON_SRQC, srqc->hr_indx, NULL);
5209517SBill.Taylor@Sun.COM
5219517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
5229517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*srq));
5239517SBill.Taylor@Sun.COM
5249517SBill.Taylor@Sun.COM /*
5259517SBill.Taylor@Sun.COM * Reclaim SRQC entry from hardware (using the Hermon HW2SW_SRQ
5269517SBill.Taylor@Sun.COM * firmware command). If the ownership transfer fails for any reason,
5279517SBill.Taylor@Sun.COM * then it is an indication that something (either in HW or SW) has
5289517SBill.Taylor@Sun.COM * gone seriously wrong.
5299517SBill.Taylor@Sun.COM */
5309517SBill.Taylor@Sun.COM status = hermon_cmn_ownership_cmd_post(state, HW2SW_SRQ, &srqc_entry,
5319517SBill.Taylor@Sun.COM sizeof (hermon_hw_srqc_t), srqnum, sleepflag);
5329517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
5339517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to reclaim SRQC ownership");
5349517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: HW2SW_SRQ command failed: %08x\n",
5359517SBill.Taylor@Sun.COM status);
5369517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
5379517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
5389517SBill.Taylor@Sun.COM }
5399517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
5409517SBill.Taylor@Sun.COM }
5419517SBill.Taylor@Sun.COM
5429517SBill.Taylor@Sun.COM /*
5439517SBill.Taylor@Sun.COM * Deregister the memory for the Shared Receive Queue. If this fails
5449517SBill.Taylor@Sun.COM * for any reason, then it is an indication that something (either
5459517SBill.Taylor@Sun.COM * in HW or SW) has gone seriously wrong. So we print a warning
5469517SBill.Taylor@Sun.COM * message and return.
5479517SBill.Taylor@Sun.COM */
5489517SBill.Taylor@Sun.COM status = hermon_mr_deregister(state, &mr, HERMON_MR_DEREG_ALL,
5499517SBill.Taylor@Sun.COM sleepflag);
5509517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
5519517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to deregister SRQ memory");
5529517SBill.Taylor@Sun.COM return (IBT_FAILURE);
5539517SBill.Taylor@Sun.COM }
5549517SBill.Taylor@Sun.COM
5559517SBill.Taylor@Sun.COM hermon_wrid_wqhdr_destroy(srq->srq_wq_wqhdr);
5569517SBill.Taylor@Sun.COM
5579517SBill.Taylor@Sun.COM /* Free the memory for the SRQ */
5589517SBill.Taylor@Sun.COM hermon_queue_free(&srq->srq_wqinfo);
5599517SBill.Taylor@Sun.COM
5609517SBill.Taylor@Sun.COM /* Free the dbr */
5619517SBill.Taylor@Sun.COM hermon_dbr_free(state, srq->srq_uarpg, srq->srq_wq_vdbr);
5629517SBill.Taylor@Sun.COM
5639517SBill.Taylor@Sun.COM /* Free the Hermon SRQ Handle */
5649517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &rsrc);
5659517SBill.Taylor@Sun.COM
5669517SBill.Taylor@Sun.COM /* Free the SRQC entry resource */
5679517SBill.Taylor@Sun.COM hermon_rsrc_free(state, &srqc);
5689517SBill.Taylor@Sun.COM
5699517SBill.Taylor@Sun.COM /* Decrement the reference count on the protection domain (PD) */
5709517SBill.Taylor@Sun.COM hermon_pd_refcnt_dec(pd);
5719517SBill.Taylor@Sun.COM
5729517SBill.Taylor@Sun.COM /* Set the srqhdl pointer to NULL and return success */
5739517SBill.Taylor@Sun.COM *srqhdl = NULL;
5749517SBill.Taylor@Sun.COM
5759517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
5769517SBill.Taylor@Sun.COM }
5779517SBill.Taylor@Sun.COM
5789517SBill.Taylor@Sun.COM
5799517SBill.Taylor@Sun.COM /*
5809517SBill.Taylor@Sun.COM * hermon_srq_modify()
5819517SBill.Taylor@Sun.COM * Context: Can be called only from user or kernel context.
5829517SBill.Taylor@Sun.COM */
5839517SBill.Taylor@Sun.COM int
hermon_srq_modify(hermon_state_t * state,hermon_srqhdl_t srq,uint_t size,uint_t * real_size,uint_t sleepflag)5849517SBill.Taylor@Sun.COM hermon_srq_modify(hermon_state_t *state, hermon_srqhdl_t srq, uint_t size,
5859517SBill.Taylor@Sun.COM uint_t *real_size, uint_t sleepflag)
5869517SBill.Taylor@Sun.COM {
5879517SBill.Taylor@Sun.COM hermon_qalloc_info_t new_srqinfo, old_srqinfo;
5889517SBill.Taylor@Sun.COM hermon_rsrc_t *mtt, *old_mtt;
5899517SBill.Taylor@Sun.COM hermon_bind_info_t bind;
5909517SBill.Taylor@Sun.COM hermon_bind_info_t old_bind;
5919517SBill.Taylor@Sun.COM hermon_mrhdl_t mr;
5929517SBill.Taylor@Sun.COM hermon_hw_srqc_t srqc_entry;
5939517SBill.Taylor@Sun.COM hermon_hw_dmpt_t mpt_entry;
5949517SBill.Taylor@Sun.COM uint64_t *wre_new, *wre_old;
5959517SBill.Taylor@Sun.COM uint64_t mtt_addr;
5969517SBill.Taylor@Sun.COM uint64_t srq_pgoffs;
5979517SBill.Taylor@Sun.COM uint64_t srq_desc_off;
5989517SBill.Taylor@Sun.COM uint32_t *buf, srq_old_bufsz;
5999517SBill.Taylor@Sun.COM uint32_t wqesz;
6009517SBill.Taylor@Sun.COM uint_t max_srq_size;
6019517SBill.Taylor@Sun.COM uint_t mtt_pgsize_bits;
6029517SBill.Taylor@Sun.COM uint_t log_srq_size, maxprot;
6039517SBill.Taylor@Sun.COM int status;
6049517SBill.Taylor@Sun.COM
6059517SBill.Taylor@Sun.COM if ((state->hs_devlim.mod_wr_srq == 0) ||
6069517SBill.Taylor@Sun.COM (state->hs_cfg_profile->cp_srq_resize_enabled == 0))
6079517SBill.Taylor@Sun.COM return (IBT_NOT_SUPPORTED);
6089517SBill.Taylor@Sun.COM
6099517SBill.Taylor@Sun.COM /*
6109517SBill.Taylor@Sun.COM * If size requested is larger than device capability, return
6119517SBill.Taylor@Sun.COM * Insufficient Resources
6129517SBill.Taylor@Sun.COM */
6139517SBill.Taylor@Sun.COM max_srq_size = (1 << state->hs_cfg_profile->cp_log_max_srq_sz);
6149517SBill.Taylor@Sun.COM if (size > max_srq_size) {
6159517SBill.Taylor@Sun.COM return (IBT_HCA_WR_EXCEEDED);
6169517SBill.Taylor@Sun.COM }
6179517SBill.Taylor@Sun.COM
6189517SBill.Taylor@Sun.COM /*
6199517SBill.Taylor@Sun.COM * Calculate the appropriate size for the SRQ.
6209517SBill.Taylor@Sun.COM * Note: All Hermon SRQs must be a power-of-2 in size. Also
6219517SBill.Taylor@Sun.COM * they may not be any smaller than HERMON_SRQ_MIN_SIZE. This step
6229517SBill.Taylor@Sun.COM * is to round the requested size up to the next highest power-of-2
6239517SBill.Taylor@Sun.COM */
6249517SBill.Taylor@Sun.COM size = max(size, HERMON_SRQ_MIN_SIZE);
6259517SBill.Taylor@Sun.COM log_srq_size = highbit(size);
6269517SBill.Taylor@Sun.COM if ((size & (size - 1)) == 0) {
6279517SBill.Taylor@Sun.COM log_srq_size = log_srq_size - 1;
6289517SBill.Taylor@Sun.COM }
6299517SBill.Taylor@Sun.COM
6309517SBill.Taylor@Sun.COM /*
6319517SBill.Taylor@Sun.COM * Next we verify that the rounded-up size is valid (i.e. consistent
6329517SBill.Taylor@Sun.COM * with the device limits and/or software-configured limits).
6339517SBill.Taylor@Sun.COM */
6349517SBill.Taylor@Sun.COM if (log_srq_size > state->hs_cfg_profile->cp_log_max_srq_sz) {
6359517SBill.Taylor@Sun.COM status = IBT_HCA_WR_EXCEEDED;
6369517SBill.Taylor@Sun.COM goto srqmodify_fail;
6379517SBill.Taylor@Sun.COM }
6389517SBill.Taylor@Sun.COM
6399517SBill.Taylor@Sun.COM /*
6409517SBill.Taylor@Sun.COM * Allocate the memory for newly resized Shared Receive Queue.
6419517SBill.Taylor@Sun.COM *
6429517SBill.Taylor@Sun.COM * Note: If SRQ is not user-mappable, then it may come from either
6439517SBill.Taylor@Sun.COM * kernel system memory or from HCA-attached local DDR memory.
6449517SBill.Taylor@Sun.COM *
6459517SBill.Taylor@Sun.COM * Note2: We align this queue on a pagesize boundary. This is required
6469517SBill.Taylor@Sun.COM * to make sure that all the resulting IB addresses will start at 0,
6479517SBill.Taylor@Sun.COM * for a zero-based queue. By making sure we are aligned on at least a
6489517SBill.Taylor@Sun.COM * page, any offset we use into our queue will be the same as it was
6499517SBill.Taylor@Sun.COM * when we allocated it at hermon_srq_alloc() time.
6509517SBill.Taylor@Sun.COM */
6519517SBill.Taylor@Sun.COM wqesz = (1 << srq->srq_wq_log_wqesz);
6529517SBill.Taylor@Sun.COM new_srqinfo.qa_size = (1 << log_srq_size) * wqesz;
6539517SBill.Taylor@Sun.COM new_srqinfo.qa_alloc_align = PAGESIZE;
6549517SBill.Taylor@Sun.COM new_srqinfo.qa_bind_align = PAGESIZE;
6559517SBill.Taylor@Sun.COM if (srq->srq_is_umap) {
6569517SBill.Taylor@Sun.COM new_srqinfo.qa_location = HERMON_QUEUE_LOCATION_USERLAND;
6579517SBill.Taylor@Sun.COM } else {
6589517SBill.Taylor@Sun.COM new_srqinfo.qa_location = HERMON_QUEUE_LOCATION_NORMAL;
6599517SBill.Taylor@Sun.COM }
6609517SBill.Taylor@Sun.COM status = hermon_queue_alloc(state, &new_srqinfo, sleepflag);
6619517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
6629517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
6639517SBill.Taylor@Sun.COM goto srqmodify_fail;
6649517SBill.Taylor@Sun.COM }
6659517SBill.Taylor@Sun.COM buf = (uint32_t *)new_srqinfo.qa_buf_aligned;
6669517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*buf))
6679517SBill.Taylor@Sun.COM
6689517SBill.Taylor@Sun.COM /*
6699517SBill.Taylor@Sun.COM * Allocate the memory for the new WRE list. This will be used later
6709517SBill.Taylor@Sun.COM * when we resize the wridlist based on the new SRQ size.
6719517SBill.Taylor@Sun.COM */
6729517SBill.Taylor@Sun.COM wre_new = kmem_zalloc((1 << log_srq_size) * sizeof (uint64_t),
6739517SBill.Taylor@Sun.COM sleepflag);
6749517SBill.Taylor@Sun.COM if (wre_new == NULL) {
6759517SBill.Taylor@Sun.COM status = IBT_INSUFF_RESOURCE;
6769517SBill.Taylor@Sun.COM goto srqmodify_fail;
6779517SBill.Taylor@Sun.COM }
6789517SBill.Taylor@Sun.COM
6799517SBill.Taylor@Sun.COM /*
6809517SBill.Taylor@Sun.COM * Fill in the "bind" struct. This struct provides the majority
6819517SBill.Taylor@Sun.COM * of the information that will be used to distinguish between an
6829517SBill.Taylor@Sun.COM * "addr" binding (as is the case here) and a "buf" binding (see
6839517SBill.Taylor@Sun.COM * below). The "bind" struct is later passed to hermon_mr_mem_bind()
6849517SBill.Taylor@Sun.COM * which does most of the "heavy lifting" for the Hermon memory
6859517SBill.Taylor@Sun.COM * registration routines.
6869517SBill.Taylor@Sun.COM */
6879517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(bind))
6889517SBill.Taylor@Sun.COM bzero(&bind, sizeof (hermon_bind_info_t));
6899517SBill.Taylor@Sun.COM bind.bi_type = HERMON_BINDHDL_VADDR;
6909517SBill.Taylor@Sun.COM bind.bi_addr = (uint64_t)(uintptr_t)buf;
6919517SBill.Taylor@Sun.COM bind.bi_len = new_srqinfo.qa_size;
6929517SBill.Taylor@Sun.COM bind.bi_as = NULL;
6939517SBill.Taylor@Sun.COM bind.bi_flags = sleepflag == HERMON_SLEEP ? IBT_MR_SLEEP :
6949517SBill.Taylor@Sun.COM IBT_MR_NOSLEEP | IBT_MR_ENABLE_LOCAL_WRITE;
6959517SBill.Taylor@Sun.COM bind.bi_bypass = state->hs_cfg_profile->cp_iommu_bypass;
6969517SBill.Taylor@Sun.COM
6979517SBill.Taylor@Sun.COM status = hermon_mr_mtt_bind(state, &bind, new_srqinfo.qa_dmahdl, &mtt,
6989517SBill.Taylor@Sun.COM &mtt_pgsize_bits, 0); /* no relaxed ordering */
6999517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
7009517SBill.Taylor@Sun.COM status = status;
7019517SBill.Taylor@Sun.COM kmem_free(wre_new, (1 << log_srq_size) *
7029517SBill.Taylor@Sun.COM sizeof (uint64_t));
7039517SBill.Taylor@Sun.COM hermon_queue_free(&new_srqinfo);
7049517SBill.Taylor@Sun.COM goto srqmodify_fail;
7059517SBill.Taylor@Sun.COM }
7069517SBill.Taylor@Sun.COM
7079517SBill.Taylor@Sun.COM /*
7089517SBill.Taylor@Sun.COM * Calculate the offset between the kernel virtual address space
7099517SBill.Taylor@Sun.COM * and the IB virtual address space. This will be used when
7109517SBill.Taylor@Sun.COM * posting work requests to properly initialize each WQE.
7119517SBill.Taylor@Sun.COM *
7129517SBill.Taylor@Sun.COM * Note: bind addr is zero-based (from alloc) so we calculate the
7139517SBill.Taylor@Sun.COM * correct new offset here.
7149517SBill.Taylor@Sun.COM */
7159517SBill.Taylor@Sun.COM bind.bi_addr = bind.bi_addr & ((1 << mtt_pgsize_bits) - 1);
7169517SBill.Taylor@Sun.COM srq_desc_off = (uint64_t)(uintptr_t)new_srqinfo.qa_buf_aligned -
7179517SBill.Taylor@Sun.COM (uint64_t)bind.bi_addr;
7189517SBill.Taylor@Sun.COM srq_pgoffs = (uint_t)
71911972SBill.Taylor@Sun.COM ((uintptr_t)new_srqinfo.qa_buf_aligned & HERMON_PAGEOFFSET);
7209517SBill.Taylor@Sun.COM
7219517SBill.Taylor@Sun.COM /*
7229517SBill.Taylor@Sun.COM * Fill in the MPT entry. This is the final step before passing
7239517SBill.Taylor@Sun.COM * ownership of the MPT entry to the Hermon hardware. We use all of
7249517SBill.Taylor@Sun.COM * the information collected/calculated above to fill in the
7259517SBill.Taylor@Sun.COM * requisite portions of the MPT.
7269517SBill.Taylor@Sun.COM */
7279517SBill.Taylor@Sun.COM bzero(&mpt_entry, sizeof (hermon_hw_dmpt_t));
7289517SBill.Taylor@Sun.COM mpt_entry.reg_win_len = bind.bi_len;
7299517SBill.Taylor@Sun.COM mtt_addr = (mtt->hr_indx << HERMON_MTT_SIZE_SHIFT);
7309517SBill.Taylor@Sun.COM mpt_entry.mtt_addr_h = mtt_addr >> 32;
7319517SBill.Taylor@Sun.COM mpt_entry.mtt_addr_l = mtt_addr >> 3;
7329517SBill.Taylor@Sun.COM
7339517SBill.Taylor@Sun.COM /*
7349517SBill.Taylor@Sun.COM * for hermon we build up a new srqc and pass that (partially filled
7359517SBill.Taylor@Sun.COM * to resize SRQ instead of modifying the (d)mpt directly
7369517SBill.Taylor@Sun.COM */
7379517SBill.Taylor@Sun.COM
7389517SBill.Taylor@Sun.COM
7399517SBill.Taylor@Sun.COM
7409517SBill.Taylor@Sun.COM /*
7419517SBill.Taylor@Sun.COM * Now we grab the SRQ lock. Since we will be updating the actual
7429517SBill.Taylor@Sun.COM * SRQ location and the producer/consumer indexes, we should hold
7439517SBill.Taylor@Sun.COM * the lock.
7449517SBill.Taylor@Sun.COM *
7459517SBill.Taylor@Sun.COM * We do a HERMON_NOSLEEP here (and below), though, because we are
7469517SBill.Taylor@Sun.COM * holding the "srq_lock" and if we got raised to interrupt level
7479517SBill.Taylor@Sun.COM * by priority inversion, we would not want to block in this routine
7489517SBill.Taylor@Sun.COM * waiting for success.
7499517SBill.Taylor@Sun.COM */
7509517SBill.Taylor@Sun.COM mutex_enter(&srq->srq_lock);
7519517SBill.Taylor@Sun.COM
7529517SBill.Taylor@Sun.COM /*
7539517SBill.Taylor@Sun.COM * Copy old entries to new buffer
7549517SBill.Taylor@Sun.COM */
7559517SBill.Taylor@Sun.COM srq_old_bufsz = srq->srq_wq_bufsz;
7569517SBill.Taylor@Sun.COM bcopy(srq->srq_wq_buf, buf, srq_old_bufsz * wqesz);
7579517SBill.Taylor@Sun.COM
7589517SBill.Taylor@Sun.COM /*
7599517SBill.Taylor@Sun.COM * Setup MPT information for use in the MODIFY_MPT command
7609517SBill.Taylor@Sun.COM */
7619517SBill.Taylor@Sun.COM mr = srq->srq_mrhdl;
7629517SBill.Taylor@Sun.COM mutex_enter(&mr->mr_lock);
7639517SBill.Taylor@Sun.COM
7649517SBill.Taylor@Sun.COM /*
7659517SBill.Taylor@Sun.COM * now, setup the srqc information needed for resize - limit the
7669517SBill.Taylor@Sun.COM * values, but use the same structure as the srqc
7679517SBill.Taylor@Sun.COM */
7689517SBill.Taylor@Sun.COM
7699517SBill.Taylor@Sun.COM srqc_entry.log_srq_size = log_srq_size;
7709517SBill.Taylor@Sun.COM srqc_entry.page_offs = srq_pgoffs >> 6;
7719517SBill.Taylor@Sun.COM srqc_entry.log2_pgsz = mr->mr_log2_pgsz;
7729517SBill.Taylor@Sun.COM srqc_entry.mtt_base_addrl = (uint64_t)mtt_addr >> 32;
7739517SBill.Taylor@Sun.COM srqc_entry.mtt_base_addrh = mtt_addr >> 3;
7749517SBill.Taylor@Sun.COM
7759517SBill.Taylor@Sun.COM /*
7769517SBill.Taylor@Sun.COM * RESIZE_SRQ
7779517SBill.Taylor@Sun.COM *
7789517SBill.Taylor@Sun.COM * If this fails for any reason, then it is an indication that
7799517SBill.Taylor@Sun.COM * something (either in HW or SW) has gone seriously wrong. So we
7809517SBill.Taylor@Sun.COM * print a warning message and return.
7819517SBill.Taylor@Sun.COM */
7829517SBill.Taylor@Sun.COM status = hermon_resize_srq_cmd_post(state, &srqc_entry,
7839517SBill.Taylor@Sun.COM srq->srq_srqnum, sleepflag);
7849517SBill.Taylor@Sun.COM if (status != HERMON_CMD_SUCCESS) {
7859517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "Hermon: RESIZE_SRQ command failed: %08x\n",
7869517SBill.Taylor@Sun.COM status);
7879517SBill.Taylor@Sun.COM if (status == HERMON_CMD_INVALID_STATUS) {
7889517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
7899517SBill.Taylor@Sun.COM }
7909517SBill.Taylor@Sun.COM (void) hermon_mr_mtt_unbind(state, &bind, mtt);
7919517SBill.Taylor@Sun.COM kmem_free(wre_new, (1 << log_srq_size) *
7929517SBill.Taylor@Sun.COM sizeof (uint64_t));
7939517SBill.Taylor@Sun.COM hermon_queue_free(&new_srqinfo);
7949517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
7959517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
7969517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
7979517SBill.Taylor@Sun.COM }
7989517SBill.Taylor@Sun.COM /*
7999517SBill.Taylor@Sun.COM * Update the Hermon Shared Receive Queue handle with all the new
8009517SBill.Taylor@Sun.COM * information. At the same time, save away all the necessary
8019517SBill.Taylor@Sun.COM * information for freeing up the old resources
8029517SBill.Taylor@Sun.COM */
8039517SBill.Taylor@Sun.COM old_srqinfo = srq->srq_wqinfo;
8049517SBill.Taylor@Sun.COM old_mtt = srq->srq_mrhdl->mr_mttrsrcp;
8059517SBill.Taylor@Sun.COM bcopy(&srq->srq_mrhdl->mr_bindinfo, &old_bind,
8069517SBill.Taylor@Sun.COM sizeof (hermon_bind_info_t));
8079517SBill.Taylor@Sun.COM
8089517SBill.Taylor@Sun.COM /* Now set the new info */
8099517SBill.Taylor@Sun.COM srq->srq_wqinfo = new_srqinfo;
8109517SBill.Taylor@Sun.COM srq->srq_wq_buf = buf;
8119517SBill.Taylor@Sun.COM srq->srq_wq_bufsz = (1 << log_srq_size);
8129517SBill.Taylor@Sun.COM bcopy(&bind, &srq->srq_mrhdl->mr_bindinfo, sizeof (hermon_bind_info_t));
8139517SBill.Taylor@Sun.COM srq->srq_mrhdl->mr_mttrsrcp = mtt;
8149517SBill.Taylor@Sun.COM srq->srq_desc_off = srq_desc_off;
8159517SBill.Taylor@Sun.COM srq->srq_real_sizes.srq_wr_sz = (1 << log_srq_size);
8169517SBill.Taylor@Sun.COM
8179517SBill.Taylor@Sun.COM /* Update MR mtt pagesize */
8189517SBill.Taylor@Sun.COM mr->mr_logmttpgsz = mtt_pgsize_bits;
8199517SBill.Taylor@Sun.COM mutex_exit(&mr->mr_lock);
8209517SBill.Taylor@Sun.COM
8219517SBill.Taylor@Sun.COM /*
8229517SBill.Taylor@Sun.COM * Initialize new wridlist, if needed.
8239517SBill.Taylor@Sun.COM *
8249517SBill.Taylor@Sun.COM * If a wridlist already is setup on an SRQ (the QP associated with an
8259517SBill.Taylor@Sun.COM * SRQ has moved "from_reset") then we must update this wridlist based
8269517SBill.Taylor@Sun.COM * on the new SRQ size. We allocate the new size of Work Request ID
8279517SBill.Taylor@Sun.COM * Entries, copy over the old entries to the new list, and
8289517SBill.Taylor@Sun.COM * re-initialize the srq wridlist in non-umap case
8299517SBill.Taylor@Sun.COM */
8309517SBill.Taylor@Sun.COM wre_old = srq->srq_wq_wqhdr->wq_wrid;
8319517SBill.Taylor@Sun.COM
8329517SBill.Taylor@Sun.COM bcopy(wre_old, wre_new, srq_old_bufsz * sizeof (uint64_t));
8339517SBill.Taylor@Sun.COM
8349517SBill.Taylor@Sun.COM /* Setup new sizes in wre */
8359517SBill.Taylor@Sun.COM srq->srq_wq_wqhdr->wq_wrid = wre_new;
8369517SBill.Taylor@Sun.COM
8379517SBill.Taylor@Sun.COM /*
8389517SBill.Taylor@Sun.COM * If "old" SRQ was a user-mappable SRQ that is currently mmap()'d out
8399517SBill.Taylor@Sun.COM * to a user process, then we need to call devmap_devmem_remap() to
8409517SBill.Taylor@Sun.COM * invalidate the mapping to the SRQ memory. We also need to
8419517SBill.Taylor@Sun.COM * invalidate the SRQ tracking information for the user mapping.
8429517SBill.Taylor@Sun.COM *
8439517SBill.Taylor@Sun.COM * Note: On failure, the remap really shouldn't ever happen. So, if it
8449517SBill.Taylor@Sun.COM * does, it is an indication that something has gone seriously wrong.
8459517SBill.Taylor@Sun.COM * So we print a warning message and return error (knowing, of course,
8469517SBill.Taylor@Sun.COM * that the "old" SRQ memory will be leaked)
8479517SBill.Taylor@Sun.COM */
8489517SBill.Taylor@Sun.COM if ((srq->srq_is_umap) && (srq->srq_umap_dhp != NULL)) {
8499517SBill.Taylor@Sun.COM maxprot = (PROT_READ | PROT_WRITE | PROT_USER);
8509517SBill.Taylor@Sun.COM status = devmap_devmem_remap(srq->srq_umap_dhp,
8519517SBill.Taylor@Sun.COM state->hs_dip, 0, 0, srq->srq_wqinfo.qa_size, maxprot,
8529517SBill.Taylor@Sun.COM DEVMAP_MAPPING_INVALID, NULL);
8539517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
8549517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
8559517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed in SRQ memory "
8569517SBill.Taylor@Sun.COM "devmap_devmem_remap()");
8579517SBill.Taylor@Sun.COM /* We can, however, free the memory for old wre */
8589517SBill.Taylor@Sun.COM kmem_free(wre_old, srq_old_bufsz * sizeof (uint64_t));
8599517SBill.Taylor@Sun.COM return (ibc_get_ci_failure(0));
8609517SBill.Taylor@Sun.COM }
8619517SBill.Taylor@Sun.COM srq->srq_umap_dhp = (devmap_cookie_t)NULL;
8629517SBill.Taylor@Sun.COM }
8639517SBill.Taylor@Sun.COM
8649517SBill.Taylor@Sun.COM /*
8659517SBill.Taylor@Sun.COM * Drop the SRQ lock now. The only thing left to do is to free up
8669517SBill.Taylor@Sun.COM * the old resources.
8679517SBill.Taylor@Sun.COM */
8689517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
8699517SBill.Taylor@Sun.COM
8709517SBill.Taylor@Sun.COM /*
8719517SBill.Taylor@Sun.COM * Unbind the MTT entries.
8729517SBill.Taylor@Sun.COM */
8739517SBill.Taylor@Sun.COM status = hermon_mr_mtt_unbind(state, &old_bind, old_mtt);
8749517SBill.Taylor@Sun.COM if (status != DDI_SUCCESS) {
8759517SBill.Taylor@Sun.COM HERMON_WARNING(state, "failed to unbind old SRQ memory");
8769517SBill.Taylor@Sun.COM status = ibc_get_ci_failure(0);
8779517SBill.Taylor@Sun.COM goto srqmodify_fail;
8789517SBill.Taylor@Sun.COM }
8799517SBill.Taylor@Sun.COM
8809517SBill.Taylor@Sun.COM /* Free the memory for old wre */
8819517SBill.Taylor@Sun.COM kmem_free(wre_old, srq_old_bufsz * sizeof (uint64_t));
8829517SBill.Taylor@Sun.COM
8839517SBill.Taylor@Sun.COM /* Free the memory for the old SRQ */
8849517SBill.Taylor@Sun.COM hermon_queue_free(&old_srqinfo);
8859517SBill.Taylor@Sun.COM
8869517SBill.Taylor@Sun.COM /*
8879517SBill.Taylor@Sun.COM * Fill in the return arguments (if necessary). This includes the
8889517SBill.Taylor@Sun.COM * real new completion queue size.
8899517SBill.Taylor@Sun.COM */
8909517SBill.Taylor@Sun.COM if (real_size != NULL) {
8919517SBill.Taylor@Sun.COM *real_size = (1 << log_srq_size);
8929517SBill.Taylor@Sun.COM }
8939517SBill.Taylor@Sun.COM
8949517SBill.Taylor@Sun.COM return (DDI_SUCCESS);
8959517SBill.Taylor@Sun.COM
8969517SBill.Taylor@Sun.COM srqmodify_fail:
8979517SBill.Taylor@Sun.COM return (status);
8989517SBill.Taylor@Sun.COM }
8999517SBill.Taylor@Sun.COM
9009517SBill.Taylor@Sun.COM
9019517SBill.Taylor@Sun.COM /*
9029517SBill.Taylor@Sun.COM * hermon_srq_refcnt_inc()
9039517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
9049517SBill.Taylor@Sun.COM */
9059517SBill.Taylor@Sun.COM void
hermon_srq_refcnt_inc(hermon_srqhdl_t srq)9069517SBill.Taylor@Sun.COM hermon_srq_refcnt_inc(hermon_srqhdl_t srq)
9079517SBill.Taylor@Sun.COM {
9089517SBill.Taylor@Sun.COM mutex_enter(&srq->srq_lock);
9099517SBill.Taylor@Sun.COM srq->srq_refcnt++;
9109517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
9119517SBill.Taylor@Sun.COM }
9129517SBill.Taylor@Sun.COM
9139517SBill.Taylor@Sun.COM
9149517SBill.Taylor@Sun.COM /*
9159517SBill.Taylor@Sun.COM * hermon_srq_refcnt_dec()
9169517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
9179517SBill.Taylor@Sun.COM */
9189517SBill.Taylor@Sun.COM void
hermon_srq_refcnt_dec(hermon_srqhdl_t srq)9199517SBill.Taylor@Sun.COM hermon_srq_refcnt_dec(hermon_srqhdl_t srq)
9209517SBill.Taylor@Sun.COM {
9219517SBill.Taylor@Sun.COM mutex_enter(&srq->srq_lock);
9229517SBill.Taylor@Sun.COM srq->srq_refcnt--;
9239517SBill.Taylor@Sun.COM mutex_exit(&srq->srq_lock);
9249517SBill.Taylor@Sun.COM }
9259517SBill.Taylor@Sun.COM
9269517SBill.Taylor@Sun.COM
9279517SBill.Taylor@Sun.COM /*
9289517SBill.Taylor@Sun.COM * hermon_srqhdl_from_srqnum()
9299517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
9309517SBill.Taylor@Sun.COM *
9319517SBill.Taylor@Sun.COM * This routine is important because changing the unconstrained
9329517SBill.Taylor@Sun.COM * portion of the SRQ number is critical to the detection of a
9339517SBill.Taylor@Sun.COM * potential race condition in the SRQ handler code (i.e. the case
9349517SBill.Taylor@Sun.COM * where a SRQ is freed and alloc'd again before an event for the
9359517SBill.Taylor@Sun.COM * "old" SRQ can be handled).
9369517SBill.Taylor@Sun.COM *
9379517SBill.Taylor@Sun.COM * While this is not a perfect solution (not sure that one exists)
9389517SBill.Taylor@Sun.COM * it does help to mitigate the chance that this race condition will
9399517SBill.Taylor@Sun.COM * cause us to deliver a "stale" event to the new SRQ owner. Note:
9409517SBill.Taylor@Sun.COM * this solution does not scale well because the number of constrained
9419517SBill.Taylor@Sun.COM * bits increases (and, hence, the number of unconstrained bits
9429517SBill.Taylor@Sun.COM * decreases) as the number of supported SRQ grows. For small and
9439517SBill.Taylor@Sun.COM * intermediate values, it should hopefully provide sufficient
9449517SBill.Taylor@Sun.COM * protection.
9459517SBill.Taylor@Sun.COM */
9469517SBill.Taylor@Sun.COM hermon_srqhdl_t
hermon_srqhdl_from_srqnum(hermon_state_t * state,uint_t srqnum)9479517SBill.Taylor@Sun.COM hermon_srqhdl_from_srqnum(hermon_state_t *state, uint_t srqnum)
9489517SBill.Taylor@Sun.COM {
9499517SBill.Taylor@Sun.COM uint_t srqindx, srqmask;
9509517SBill.Taylor@Sun.COM
9519517SBill.Taylor@Sun.COM /* Calculate the SRQ table index from the srqnum */
9529517SBill.Taylor@Sun.COM srqmask = (1 << state->hs_cfg_profile->cp_log_num_srq) - 1;
9539517SBill.Taylor@Sun.COM srqindx = srqnum & srqmask;
954*12965SWilliam.Taylor@Oracle.COM return (hermon_icm_num_to_hdl(state, HERMON_SRQC, srqindx));
9559517SBill.Taylor@Sun.COM }
9569517SBill.Taylor@Sun.COM
9579517SBill.Taylor@Sun.COM
9589517SBill.Taylor@Sun.COM /*
9599517SBill.Taylor@Sun.COM * hermon_srq_sgl_to_logwqesz()
9609517SBill.Taylor@Sun.COM * Context: Can be called from interrupt or base context.
9619517SBill.Taylor@Sun.COM */
9629517SBill.Taylor@Sun.COM static void
hermon_srq_sgl_to_logwqesz(hermon_state_t * state,uint_t num_sgl,hermon_qp_wq_type_t wq_type,uint_t * logwqesz,uint_t * max_sgl)9639517SBill.Taylor@Sun.COM hermon_srq_sgl_to_logwqesz(hermon_state_t *state, uint_t num_sgl,
9649517SBill.Taylor@Sun.COM hermon_qp_wq_type_t wq_type, uint_t *logwqesz, uint_t *max_sgl)
9659517SBill.Taylor@Sun.COM {
9669517SBill.Taylor@Sun.COM uint_t max_size, log2, actual_sgl;
9679517SBill.Taylor@Sun.COM
9689517SBill.Taylor@Sun.COM switch (wq_type) {
9699517SBill.Taylor@Sun.COM case HERMON_QP_WQ_TYPE_RECVQ:
9709517SBill.Taylor@Sun.COM /*
9719517SBill.Taylor@Sun.COM * Use requested maximum SGL to calculate max descriptor size
9729517SBill.Taylor@Sun.COM * (while guaranteeing that the descriptor size is a
9739517SBill.Taylor@Sun.COM * power-of-2 cachelines).
9749517SBill.Taylor@Sun.COM */
9759517SBill.Taylor@Sun.COM max_size = (HERMON_QP_WQE_MLX_SRQ_HDRS + (num_sgl << 4));
9769517SBill.Taylor@Sun.COM log2 = highbit(max_size);
9779517SBill.Taylor@Sun.COM if ((max_size & (max_size - 1)) == 0) {
9789517SBill.Taylor@Sun.COM log2 = log2 - 1;
9799517SBill.Taylor@Sun.COM }
9809517SBill.Taylor@Sun.COM
9819517SBill.Taylor@Sun.COM /* Make sure descriptor is at least the minimum size */
9829517SBill.Taylor@Sun.COM log2 = max(log2, HERMON_QP_WQE_LOG_MINIMUM);
9839517SBill.Taylor@Sun.COM
9849517SBill.Taylor@Sun.COM /* Calculate actual number of SGL (given WQE size) */
9859517SBill.Taylor@Sun.COM actual_sgl = ((1 << log2) - HERMON_QP_WQE_MLX_SRQ_HDRS) >> 4;
9869517SBill.Taylor@Sun.COM break;
9879517SBill.Taylor@Sun.COM
9889517SBill.Taylor@Sun.COM default:
9899517SBill.Taylor@Sun.COM HERMON_WARNING(state, "unexpected work queue type");
9909517SBill.Taylor@Sun.COM break;
9919517SBill.Taylor@Sun.COM }
9929517SBill.Taylor@Sun.COM
9939517SBill.Taylor@Sun.COM /* Fill in the return values */
9949517SBill.Taylor@Sun.COM *logwqesz = log2;
9959517SBill.Taylor@Sun.COM *max_sgl = min(state->hs_cfg_profile->cp_srq_max_sgl, actual_sgl);
9969517SBill.Taylor@Sun.COM }
997