18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright(c) 2016 - 2020 Intel Corporation. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is provided under a dual BSD/GPLv2 license. When using or 58c2ecf20Sopenharmony_ci * redistributing this file, you may do so under either license. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * GPL LICENSE SUMMARY 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of version 2 of the GNU General Public License as 118c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 148c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 158c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 168c2ecf20Sopenharmony_ci * General Public License for more details. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * BSD LICENSE 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 218c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 228c2ecf20Sopenharmony_ci * are met: 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above copyright 258c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 268c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above copyright 278c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 288c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 298c2ecf20Sopenharmony_ci * distribution. 308c2ecf20Sopenharmony_ci * - Neither the name of Intel Corporation nor the names of its 318c2ecf20Sopenharmony_ci * contributors may be used to endorse or promote products derived 328c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 358c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 368c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 378c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 388c2ecf20Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 398c2ecf20Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 408c2ecf20Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 418c2ecf20Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 428c2ecf20Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 438c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 448c2ecf20Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#include <linux/hash.h> 498c2ecf20Sopenharmony_ci#include <linux/bitops.h> 508c2ecf20Sopenharmony_ci#include <linux/lockdep.h> 518c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 528c2ecf20Sopenharmony_ci#include <linux/slab.h> 538c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 548c2ecf20Sopenharmony_ci#include <rdma/ib_hdrs.h> 558c2ecf20Sopenharmony_ci#include <rdma/opa_addr.h> 568c2ecf20Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 578c2ecf20Sopenharmony_ci#include "qp.h" 588c2ecf20Sopenharmony_ci#include "vt.h" 598c2ecf20Sopenharmony_ci#include "trace.h" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define RVT_RWQ_COUNT_THRESHOLD 16 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void rvt_rc_timeout(struct timer_list *t); 648c2ecf20Sopenharmony_cistatic void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 658c2ecf20Sopenharmony_ci enum ib_qp_type type); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Convert the AETH RNR timeout code into the number of microseconds. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistatic const u32 ib_rvt_rnr_table[32] = { 718c2ecf20Sopenharmony_ci 655360, /* 00: 655.36 */ 728c2ecf20Sopenharmony_ci 10, /* 01: .01 */ 738c2ecf20Sopenharmony_ci 20, /* 02 .02 */ 748c2ecf20Sopenharmony_ci 30, /* 03: .03 */ 758c2ecf20Sopenharmony_ci 40, /* 04: .04 */ 768c2ecf20Sopenharmony_ci 60, /* 05: .06 */ 778c2ecf20Sopenharmony_ci 80, /* 06: .08 */ 788c2ecf20Sopenharmony_ci 120, /* 07: .12 */ 798c2ecf20Sopenharmony_ci 160, /* 08: .16 */ 808c2ecf20Sopenharmony_ci 240, /* 09: .24 */ 818c2ecf20Sopenharmony_ci 320, /* 0A: .32 */ 828c2ecf20Sopenharmony_ci 480, /* 0B: .48 */ 838c2ecf20Sopenharmony_ci 640, /* 0C: .64 */ 848c2ecf20Sopenharmony_ci 960, /* 0D: .96 */ 858c2ecf20Sopenharmony_ci 1280, /* 0E: 1.28 */ 868c2ecf20Sopenharmony_ci 1920, /* 0F: 1.92 */ 878c2ecf20Sopenharmony_ci 2560, /* 10: 2.56 */ 888c2ecf20Sopenharmony_ci 3840, /* 11: 3.84 */ 898c2ecf20Sopenharmony_ci 5120, /* 12: 5.12 */ 908c2ecf20Sopenharmony_ci 7680, /* 13: 7.68 */ 918c2ecf20Sopenharmony_ci 10240, /* 14: 10.24 */ 928c2ecf20Sopenharmony_ci 15360, /* 15: 15.36 */ 938c2ecf20Sopenharmony_ci 20480, /* 16: 20.48 */ 948c2ecf20Sopenharmony_ci 30720, /* 17: 30.72 */ 958c2ecf20Sopenharmony_ci 40960, /* 18: 40.96 */ 968c2ecf20Sopenharmony_ci 61440, /* 19: 61.44 */ 978c2ecf20Sopenharmony_ci 81920, /* 1A: 81.92 */ 988c2ecf20Sopenharmony_ci 122880, /* 1B: 122.88 */ 998c2ecf20Sopenharmony_ci 163840, /* 1C: 163.84 */ 1008c2ecf20Sopenharmony_ci 245760, /* 1D: 245.76 */ 1018c2ecf20Sopenharmony_ci 327680, /* 1E: 327.68 */ 1028c2ecf20Sopenharmony_ci 491520 /* 1F: 491.52 */ 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * Note that it is OK to post send work requests in the SQE and ERR 1078c2ecf20Sopenharmony_ci * states; rvt_do_send() will process them and generate error 1088c2ecf20Sopenharmony_ci * completions as per IB 1.2 C10-96. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ciconst int ib_rvt_state_ops[IB_QPS_ERR + 1] = { 1118c2ecf20Sopenharmony_ci [IB_QPS_RESET] = 0, 1128c2ecf20Sopenharmony_ci [IB_QPS_INIT] = RVT_POST_RECV_OK, 1138c2ecf20Sopenharmony_ci [IB_QPS_RTR] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK, 1148c2ecf20Sopenharmony_ci [IB_QPS_RTS] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK | 1158c2ecf20Sopenharmony_ci RVT_POST_SEND_OK | RVT_PROCESS_SEND_OK | 1168c2ecf20Sopenharmony_ci RVT_PROCESS_NEXT_SEND_OK, 1178c2ecf20Sopenharmony_ci [IB_QPS_SQD] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK | 1188c2ecf20Sopenharmony_ci RVT_POST_SEND_OK | RVT_PROCESS_SEND_OK, 1198c2ecf20Sopenharmony_ci [IB_QPS_SQE] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK | 1208c2ecf20Sopenharmony_ci RVT_POST_SEND_OK | RVT_FLUSH_SEND, 1218c2ecf20Sopenharmony_ci [IB_QPS_ERR] = RVT_POST_RECV_OK | RVT_FLUSH_RECV | 1228c2ecf20Sopenharmony_ci RVT_POST_SEND_OK | RVT_FLUSH_SEND, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ib_rvt_state_ops); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* platform specific: return the last level cache (llc) size, in KiB */ 1278c2ecf20Sopenharmony_cistatic int rvt_wss_llc_size(void) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci /* assume that the boot CPU value is universal for all CPUs */ 1308c2ecf20Sopenharmony_ci return boot_cpu_data.x86_cache_size; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* platform specific: cacheless copy */ 1348c2ecf20Sopenharmony_cistatic void cacheless_memcpy(void *dst, void *src, size_t n) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci /* 1378c2ecf20Sopenharmony_ci * Use the only available X64 cacheless copy. Add a __user cast 1388c2ecf20Sopenharmony_ci * to quiet sparse. The src agument is already in the kernel so 1398c2ecf20Sopenharmony_ci * there are no security issues. The extra fault recovery machinery 1408c2ecf20Sopenharmony_ci * is not invoked. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci __copy_user_nocache(dst, (void __user *)src, n, 0); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_civoid rvt_wss_exit(struct rvt_dev_info *rdi) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct rvt_wss *wss = rdi->wss; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!wss) 1508c2ecf20Sopenharmony_ci return; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* coded to handle partially initialized and repeat callers */ 1538c2ecf20Sopenharmony_ci kfree(wss->entries); 1548c2ecf20Sopenharmony_ci wss->entries = NULL; 1558c2ecf20Sopenharmony_ci kfree(rdi->wss); 1568c2ecf20Sopenharmony_ci rdi->wss = NULL; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * rvt_wss_init - Init wss data structures 1618c2ecf20Sopenharmony_ci * 1628c2ecf20Sopenharmony_ci * Return: 0 on success 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ciint rvt_wss_init(struct rvt_dev_info *rdi) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode; 1678c2ecf20Sopenharmony_ci unsigned int wss_threshold = rdi->dparms.wss_threshold; 1688c2ecf20Sopenharmony_ci unsigned int wss_clean_period = rdi->dparms.wss_clean_period; 1698c2ecf20Sopenharmony_ci long llc_size; 1708c2ecf20Sopenharmony_ci long llc_bits; 1718c2ecf20Sopenharmony_ci long table_size; 1728c2ecf20Sopenharmony_ci long table_bits; 1738c2ecf20Sopenharmony_ci struct rvt_wss *wss; 1748c2ecf20Sopenharmony_ci int node = rdi->dparms.node; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (sge_copy_mode != RVT_SGE_COPY_ADAPTIVE) { 1778c2ecf20Sopenharmony_ci rdi->wss = NULL; 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci rdi->wss = kzalloc_node(sizeof(*rdi->wss), GFP_KERNEL, node); 1828c2ecf20Sopenharmony_ci if (!rdi->wss) 1838c2ecf20Sopenharmony_ci return -ENOMEM; 1848c2ecf20Sopenharmony_ci wss = rdi->wss; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* check for a valid percent range - default to 80 if none or invalid */ 1878c2ecf20Sopenharmony_ci if (wss_threshold < 1 || wss_threshold > 100) 1888c2ecf20Sopenharmony_ci wss_threshold = 80; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* reject a wildly large period */ 1918c2ecf20Sopenharmony_ci if (wss_clean_period > 1000000) 1928c2ecf20Sopenharmony_ci wss_clean_period = 256; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* reject a zero period */ 1958c2ecf20Sopenharmony_ci if (wss_clean_period == 0) 1968c2ecf20Sopenharmony_ci wss_clean_period = 1; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * Calculate the table size - the next power of 2 larger than the 2008c2ecf20Sopenharmony_ci * LLC size. LLC size is in KiB. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci llc_size = rvt_wss_llc_size() * 1024; 2038c2ecf20Sopenharmony_ci table_size = roundup_pow_of_two(llc_size); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci /* one bit per page in rounded up table */ 2068c2ecf20Sopenharmony_ci llc_bits = llc_size / PAGE_SIZE; 2078c2ecf20Sopenharmony_ci table_bits = table_size / PAGE_SIZE; 2088c2ecf20Sopenharmony_ci wss->pages_mask = table_bits - 1; 2098c2ecf20Sopenharmony_ci wss->num_entries = table_bits / BITS_PER_LONG; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci wss->threshold = (llc_bits * wss_threshold) / 100; 2128c2ecf20Sopenharmony_ci if (wss->threshold == 0) 2138c2ecf20Sopenharmony_ci wss->threshold = 1; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci wss->clean_period = wss_clean_period; 2168c2ecf20Sopenharmony_ci atomic_set(&wss->clean_counter, wss_clean_period); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci wss->entries = kcalloc_node(wss->num_entries, sizeof(*wss->entries), 2198c2ecf20Sopenharmony_ci GFP_KERNEL, node); 2208c2ecf20Sopenharmony_ci if (!wss->entries) { 2218c2ecf20Sopenharmony_ci rvt_wss_exit(rdi); 2228c2ecf20Sopenharmony_ci return -ENOMEM; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* 2298c2ecf20Sopenharmony_ci * Advance the clean counter. When the clean period has expired, 2308c2ecf20Sopenharmony_ci * clean an entry. 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * This is implemented in atomics to avoid locking. Because multiple 2338c2ecf20Sopenharmony_ci * variables are involved, it can be racy which can lead to slightly 2348c2ecf20Sopenharmony_ci * inaccurate information. Since this is only a heuristic, this is 2358c2ecf20Sopenharmony_ci * OK. Any innaccuracies will clean themselves out as the counter 2368c2ecf20Sopenharmony_ci * advances. That said, it is unlikely the entry clean operation will 2378c2ecf20Sopenharmony_ci * race - the next possible racer will not start until the next clean 2388c2ecf20Sopenharmony_ci * period. 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * The clean counter is implemented as a decrement to zero. When zero 2418c2ecf20Sopenharmony_ci * is reached an entry is cleaned. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic void wss_advance_clean_counter(struct rvt_wss *wss) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci int entry; 2468c2ecf20Sopenharmony_ci int weight; 2478c2ecf20Sopenharmony_ci unsigned long bits; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* become the cleaner if we decrement the counter to zero */ 2508c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&wss->clean_counter)) { 2518c2ecf20Sopenharmony_ci /* 2528c2ecf20Sopenharmony_ci * Set, not add, the clean period. This avoids an issue 2538c2ecf20Sopenharmony_ci * where the counter could decrement below the clean period. 2548c2ecf20Sopenharmony_ci * Doing a set can result in lost decrements, slowing the 2558c2ecf20Sopenharmony_ci * clean advance. Since this a heuristic, this possible 2568c2ecf20Sopenharmony_ci * slowdown is OK. 2578c2ecf20Sopenharmony_ci * 2588c2ecf20Sopenharmony_ci * An alternative is to loop, advancing the counter by a 2598c2ecf20Sopenharmony_ci * clean period until the result is > 0. However, this could 2608c2ecf20Sopenharmony_ci * lead to several threads keeping another in the clean loop. 2618c2ecf20Sopenharmony_ci * This could be mitigated by limiting the number of times 2628c2ecf20Sopenharmony_ci * we stay in the loop. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci atomic_set(&wss->clean_counter, wss->clean_period); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * Uniquely grab the entry to clean and move to next. 2688c2ecf20Sopenharmony_ci * The current entry is always the lower bits of 2698c2ecf20Sopenharmony_ci * wss.clean_entry. The table size, wss.num_entries, 2708c2ecf20Sopenharmony_ci * is always a power-of-2. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci entry = (atomic_inc_return(&wss->clean_entry) - 1) 2738c2ecf20Sopenharmony_ci & (wss->num_entries - 1); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* clear the entry and count the bits */ 2768c2ecf20Sopenharmony_ci bits = xchg(&wss->entries[entry], 0); 2778c2ecf20Sopenharmony_ci weight = hweight64((u64)bits); 2788c2ecf20Sopenharmony_ci /* only adjust the contended total count if needed */ 2798c2ecf20Sopenharmony_ci if (weight) 2808c2ecf20Sopenharmony_ci atomic_sub(weight, &wss->total_count); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* 2858c2ecf20Sopenharmony_ci * Insert the given address into the working set array. 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_cistatic void wss_insert(struct rvt_wss *wss, void *address) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci u32 page = ((unsigned long)address >> PAGE_SHIFT) & wss->pages_mask; 2908c2ecf20Sopenharmony_ci u32 entry = page / BITS_PER_LONG; /* assumes this ends up a shift */ 2918c2ecf20Sopenharmony_ci u32 nr = page & (BITS_PER_LONG - 1); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (!test_and_set_bit(nr, &wss->entries[entry])) 2948c2ecf20Sopenharmony_ci atomic_inc(&wss->total_count); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci wss_advance_clean_counter(wss); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* 3008c2ecf20Sopenharmony_ci * Is the working set larger than the threshold? 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic inline bool wss_exceeds_threshold(struct rvt_wss *wss) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci return atomic_read(&wss->total_count) >= wss->threshold; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void get_map_page(struct rvt_qpn_table *qpt, 3088c2ecf20Sopenharmony_ci struct rvt_qpn_map *map) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * Free the page if someone raced with us installing it. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci spin_lock(&qpt->lock); 3178c2ecf20Sopenharmony_ci if (map->page) 3188c2ecf20Sopenharmony_ci free_page(page); 3198c2ecf20Sopenharmony_ci else 3208c2ecf20Sopenharmony_ci map->page = (void *)page; 3218c2ecf20Sopenharmony_ci spin_unlock(&qpt->lock); 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/** 3258c2ecf20Sopenharmony_ci * init_qpn_table - initialize the QP number table for a device 3268c2ecf20Sopenharmony_ci * @qpt: the QPN table 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_cistatic int init_qpn_table(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci u32 offset, i; 3318c2ecf20Sopenharmony_ci struct rvt_qpn_map *map; 3328c2ecf20Sopenharmony_ci int ret = 0; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!(rdi->dparms.qpn_res_end >= rdi->dparms.qpn_res_start)) 3358c2ecf20Sopenharmony_ci return -EINVAL; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci spin_lock_init(&qpt->lock); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci qpt->last = rdi->dparms.qpn_start; 3408c2ecf20Sopenharmony_ci qpt->incr = rdi->dparms.qpn_inc << rdi->dparms.qos_shift; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Drivers may want some QPs beyond what we need for verbs let them use 3448c2ecf20Sopenharmony_ci * our qpn table. No need for two. Lets go ahead and mark the bitmaps 3458c2ecf20Sopenharmony_ci * for those. The reserved range must be *after* the range which verbs 3468c2ecf20Sopenharmony_ci * will pick from. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* Figure out number of bit maps needed before reserved range */ 3508c2ecf20Sopenharmony_ci qpt->nmaps = rdi->dparms.qpn_res_start / RVT_BITS_PER_PAGE; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* This should always be zero */ 3538c2ecf20Sopenharmony_ci offset = rdi->dparms.qpn_res_start & RVT_BITS_PER_PAGE_MASK; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Starting with the first reserved bit map */ 3568c2ecf20Sopenharmony_ci map = &qpt->map[qpt->nmaps]; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci rvt_pr_info(rdi, "Reserving QPNs from 0x%x to 0x%x for non-verbs use\n", 3598c2ecf20Sopenharmony_ci rdi->dparms.qpn_res_start, rdi->dparms.qpn_res_end); 3608c2ecf20Sopenharmony_ci for (i = rdi->dparms.qpn_res_start; i <= rdi->dparms.qpn_res_end; i++) { 3618c2ecf20Sopenharmony_ci if (!map->page) { 3628c2ecf20Sopenharmony_ci get_map_page(qpt, map); 3638c2ecf20Sopenharmony_ci if (!map->page) { 3648c2ecf20Sopenharmony_ci ret = -ENOMEM; 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci set_bit(offset, map->page); 3698c2ecf20Sopenharmony_ci offset++; 3708c2ecf20Sopenharmony_ci if (offset == RVT_BITS_PER_PAGE) { 3718c2ecf20Sopenharmony_ci /* next page */ 3728c2ecf20Sopenharmony_ci qpt->nmaps++; 3738c2ecf20Sopenharmony_ci map++; 3748c2ecf20Sopenharmony_ci offset = 0; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci return ret; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/** 3818c2ecf20Sopenharmony_ci * free_qpn_table - free the QP number table for a device 3828c2ecf20Sopenharmony_ci * @qpt: the QPN table 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_cistatic void free_qpn_table(struct rvt_qpn_table *qpt) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci int i; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qpt->map); i++) 3898c2ecf20Sopenharmony_ci free_page((unsigned long)qpt->map[i].page); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/** 3938c2ecf20Sopenharmony_ci * rvt_driver_qp_init - Init driver qp resources 3948c2ecf20Sopenharmony_ci * @rdi: rvt dev strucutre 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * Return: 0 on success 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ciint rvt_driver_qp_init(struct rvt_dev_info *rdi) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci int i; 4018c2ecf20Sopenharmony_ci int ret = -ENOMEM; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (!rdi->dparms.qp_table_size) 4048c2ecf20Sopenharmony_ci return -EINVAL; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* 4078c2ecf20Sopenharmony_ci * If driver is not doing any QP allocation then make sure it is 4088c2ecf20Sopenharmony_ci * providing the necessary QP functions. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_ci if (!rdi->driver_f.free_all_qps || 4118c2ecf20Sopenharmony_ci !rdi->driver_f.qp_priv_alloc || 4128c2ecf20Sopenharmony_ci !rdi->driver_f.qp_priv_free || 4138c2ecf20Sopenharmony_ci !rdi->driver_f.notify_qp_reset || 4148c2ecf20Sopenharmony_ci !rdi->driver_f.notify_restart_rc) 4158c2ecf20Sopenharmony_ci return -EINVAL; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* allocate parent object */ 4188c2ecf20Sopenharmony_ci rdi->qp_dev = kzalloc_node(sizeof(*rdi->qp_dev), GFP_KERNEL, 4198c2ecf20Sopenharmony_ci rdi->dparms.node); 4208c2ecf20Sopenharmony_ci if (!rdi->qp_dev) 4218c2ecf20Sopenharmony_ci return -ENOMEM; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* allocate hash table */ 4248c2ecf20Sopenharmony_ci rdi->qp_dev->qp_table_size = rdi->dparms.qp_table_size; 4258c2ecf20Sopenharmony_ci rdi->qp_dev->qp_table_bits = ilog2(rdi->dparms.qp_table_size); 4268c2ecf20Sopenharmony_ci rdi->qp_dev->qp_table = 4278c2ecf20Sopenharmony_ci kmalloc_array_node(rdi->qp_dev->qp_table_size, 4288c2ecf20Sopenharmony_ci sizeof(*rdi->qp_dev->qp_table), 4298c2ecf20Sopenharmony_ci GFP_KERNEL, rdi->dparms.node); 4308c2ecf20Sopenharmony_ci if (!rdi->qp_dev->qp_table) 4318c2ecf20Sopenharmony_ci goto no_qp_table; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci for (i = 0; i < rdi->qp_dev->qp_table_size; i++) 4348c2ecf20Sopenharmony_ci RCU_INIT_POINTER(rdi->qp_dev->qp_table[i], NULL); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci spin_lock_init(&rdi->qp_dev->qpt_lock); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* initialize qpn map */ 4398c2ecf20Sopenharmony_ci if (init_qpn_table(rdi, &rdi->qp_dev->qpn_table)) 4408c2ecf20Sopenharmony_ci goto fail_table; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci spin_lock_init(&rdi->n_qps_lock); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cifail_table: 4478c2ecf20Sopenharmony_ci kfree(rdi->qp_dev->qp_table); 4488c2ecf20Sopenharmony_ci free_qpn_table(&rdi->qp_dev->qpn_table); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cino_qp_table: 4518c2ecf20Sopenharmony_ci kfree(rdi->qp_dev); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/** 4578c2ecf20Sopenharmony_ci * rvt_free_qp_cb - callback function to reset a qp 4588c2ecf20Sopenharmony_ci * @qp: the qp to reset 4598c2ecf20Sopenharmony_ci * @v: a 64-bit value 4608c2ecf20Sopenharmony_ci * 4618c2ecf20Sopenharmony_ci * This function resets the qp and removes it from the 4628c2ecf20Sopenharmony_ci * qp hash table. 4638c2ecf20Sopenharmony_ci */ 4648c2ecf20Sopenharmony_cistatic void rvt_free_qp_cb(struct rvt_qp *qp, u64 v) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci unsigned int *qp_inuse = (unsigned int *)v; 4678c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Reset the qp and remove it from the qp hash list */ 4708c2ecf20Sopenharmony_ci rvt_reset_qp(rdi, qp, qp->ibqp.qp_type); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Increment the qp_inuse count */ 4738c2ecf20Sopenharmony_ci (*qp_inuse)++; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * rvt_free_all_qps - check for QPs still in use 4788c2ecf20Sopenharmony_ci * @rdi: rvt device info structure 4798c2ecf20Sopenharmony_ci * 4808c2ecf20Sopenharmony_ci * There should not be any QPs still in use. 4818c2ecf20Sopenharmony_ci * Free memory for table. 4828c2ecf20Sopenharmony_ci * Return the number of QPs still in use. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_cistatic unsigned rvt_free_all_qps(struct rvt_dev_info *rdi) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci unsigned int qp_inuse = 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci qp_inuse += rvt_mcast_tree_empty(rdi); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci rvt_qp_iter(rdi, (u64)&qp_inuse, rvt_free_qp_cb); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return qp_inuse; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/** 4968c2ecf20Sopenharmony_ci * rvt_qp_exit - clean up qps on device exit 4978c2ecf20Sopenharmony_ci * @rdi: rvt dev structure 4988c2ecf20Sopenharmony_ci * 4998c2ecf20Sopenharmony_ci * Check for qp leaks and free resources. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_civoid rvt_qp_exit(struct rvt_dev_info *rdi) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci u32 qps_inuse = rvt_free_all_qps(rdi); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (qps_inuse) 5068c2ecf20Sopenharmony_ci rvt_pr_err(rdi, "QP memory leak! %u still in use\n", 5078c2ecf20Sopenharmony_ci qps_inuse); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci kfree(rdi->qp_dev->qp_table); 5108c2ecf20Sopenharmony_ci free_qpn_table(&rdi->qp_dev->qpn_table); 5118c2ecf20Sopenharmony_ci kfree(rdi->qp_dev); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic inline unsigned mk_qpn(struct rvt_qpn_table *qpt, 5158c2ecf20Sopenharmony_ci struct rvt_qpn_map *map, unsigned off) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci return (map - qpt->map) * RVT_BITS_PER_PAGE + off; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci/** 5218c2ecf20Sopenharmony_ci * alloc_qpn - Allocate the next available qpn or zero/one for QP type 5228c2ecf20Sopenharmony_ci * IB_QPT_SMI/IB_QPT_GSI 5238c2ecf20Sopenharmony_ci * @rdi: rvt device info structure 5248c2ecf20Sopenharmony_ci * @qpt: queue pair number table pointer 5258c2ecf20Sopenharmony_ci * @port_num: IB port number, 1 based, comes from core 5268c2ecf20Sopenharmony_ci * @exclude_prefix: prefix of special queue pair number being allocated 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Return: The queue pair number 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_cistatic int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt, 5318c2ecf20Sopenharmony_ci enum ib_qp_type type, u8 port_num, u8 exclude_prefix) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci u32 i, offset, max_scan, qpn; 5348c2ecf20Sopenharmony_ci struct rvt_qpn_map *map; 5358c2ecf20Sopenharmony_ci u32 ret; 5368c2ecf20Sopenharmony_ci u32 max_qpn = exclude_prefix == RVT_AIP_QP_PREFIX ? 5378c2ecf20Sopenharmony_ci RVT_AIP_QPN_MAX : RVT_QPN_MAX; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (rdi->driver_f.alloc_qpn) 5408c2ecf20Sopenharmony_ci return rdi->driver_f.alloc_qpn(rdi, qpt, type, port_num); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (type == IB_QPT_SMI || type == IB_QPT_GSI) { 5438c2ecf20Sopenharmony_ci unsigned n; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci ret = type == IB_QPT_GSI; 5468c2ecf20Sopenharmony_ci n = 1 << (ret + 2 * (port_num - 1)); 5478c2ecf20Sopenharmony_ci spin_lock(&qpt->lock); 5488c2ecf20Sopenharmony_ci if (qpt->flags & n) 5498c2ecf20Sopenharmony_ci ret = -EINVAL; 5508c2ecf20Sopenharmony_ci else 5518c2ecf20Sopenharmony_ci qpt->flags |= n; 5528c2ecf20Sopenharmony_ci spin_unlock(&qpt->lock); 5538c2ecf20Sopenharmony_ci goto bail; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci qpn = qpt->last + qpt->incr; 5578c2ecf20Sopenharmony_ci if (qpn >= max_qpn) 5588c2ecf20Sopenharmony_ci qpn = qpt->incr | ((qpt->last & 1) ^ 1); 5598c2ecf20Sopenharmony_ci /* offset carries bit 0 */ 5608c2ecf20Sopenharmony_ci offset = qpn & RVT_BITS_PER_PAGE_MASK; 5618c2ecf20Sopenharmony_ci map = &qpt->map[qpn / RVT_BITS_PER_PAGE]; 5628c2ecf20Sopenharmony_ci max_scan = qpt->nmaps - !offset; 5638c2ecf20Sopenharmony_ci for (i = 0;;) { 5648c2ecf20Sopenharmony_ci if (unlikely(!map->page)) { 5658c2ecf20Sopenharmony_ci get_map_page(qpt, map); 5668c2ecf20Sopenharmony_ci if (unlikely(!map->page)) 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci do { 5708c2ecf20Sopenharmony_ci if (!test_and_set_bit(offset, map->page)) { 5718c2ecf20Sopenharmony_ci qpt->last = qpn; 5728c2ecf20Sopenharmony_ci ret = qpn; 5738c2ecf20Sopenharmony_ci goto bail; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci offset += qpt->incr; 5768c2ecf20Sopenharmony_ci /* 5778c2ecf20Sopenharmony_ci * This qpn might be bogus if offset >= BITS_PER_PAGE. 5788c2ecf20Sopenharmony_ci * That is OK. It gets re-assigned below 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci qpn = mk_qpn(qpt, map, offset); 5818c2ecf20Sopenharmony_ci } while (offset < RVT_BITS_PER_PAGE && qpn < RVT_QPN_MAX); 5828c2ecf20Sopenharmony_ci /* 5838c2ecf20Sopenharmony_ci * In order to keep the number of pages allocated to a 5848c2ecf20Sopenharmony_ci * minimum, we scan the all existing pages before increasing 5858c2ecf20Sopenharmony_ci * the size of the bitmap table. 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_ci if (++i > max_scan) { 5888c2ecf20Sopenharmony_ci if (qpt->nmaps == RVT_QPNMAP_ENTRIES) 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci map = &qpt->map[qpt->nmaps++]; 5918c2ecf20Sopenharmony_ci /* start at incr with current bit 0 */ 5928c2ecf20Sopenharmony_ci offset = qpt->incr | (offset & 1); 5938c2ecf20Sopenharmony_ci } else if (map < &qpt->map[qpt->nmaps]) { 5948c2ecf20Sopenharmony_ci ++map; 5958c2ecf20Sopenharmony_ci /* start at incr with current bit 0 */ 5968c2ecf20Sopenharmony_ci offset = qpt->incr | (offset & 1); 5978c2ecf20Sopenharmony_ci } else { 5988c2ecf20Sopenharmony_ci map = &qpt->map[0]; 5998c2ecf20Sopenharmony_ci /* wrap to first map page, invert bit 0 */ 6008c2ecf20Sopenharmony_ci offset = qpt->incr | ((offset & 1) ^ 1); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci /* there can be no set bits in low-order QoS bits */ 6038c2ecf20Sopenharmony_ci WARN_ON(rdi->dparms.qos_shift > 1 && 6048c2ecf20Sopenharmony_ci offset & ((BIT(rdi->dparms.qos_shift - 1) - 1) << 1)); 6058c2ecf20Sopenharmony_ci qpn = mk_qpn(qpt, map, offset); 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci ret = -ENOMEM; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cibail: 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/** 6158c2ecf20Sopenharmony_ci * rvt_clear_mr_refs - Drop help mr refs 6168c2ecf20Sopenharmony_ci * @qp: rvt qp data structure 6178c2ecf20Sopenharmony_ci * @clr_sends: If shoudl clear send side or not 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_cistatic void rvt_clear_mr_refs(struct rvt_qp *qp, int clr_sends) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci unsigned n; 6228c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) 6258c2ecf20Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (clr_sends) { 6308c2ecf20Sopenharmony_ci while (qp->s_last != qp->s_head) { 6318c2ecf20Sopenharmony_ci struct rvt_swqe *wqe = rvt_get_swqe_ptr(qp, qp->s_last); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci rvt_put_qp_swqe(qp, wqe); 6348c2ecf20Sopenharmony_ci if (++qp->s_last >= qp->s_size) 6358c2ecf20Sopenharmony_ci qp->s_last = 0; 6368c2ecf20Sopenharmony_ci smp_wmb(); /* see qp_set_savail */ 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci if (qp->s_rdma_mr) { 6398c2ecf20Sopenharmony_ci rvt_put_mr(qp->s_rdma_mr); 6408c2ecf20Sopenharmony_ci qp->s_rdma_mr = NULL; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci for (n = 0; qp->s_ack_queue && n < rvt_max_atomic(rdi); n++) { 6458c2ecf20Sopenharmony_ci struct rvt_ack_entry *e = &qp->s_ack_queue[n]; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (e->rdma_sge.mr) { 6488c2ecf20Sopenharmony_ci rvt_put_mr(e->rdma_sge.mr); 6498c2ecf20Sopenharmony_ci e->rdma_sge.mr = NULL; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci/** 6558c2ecf20Sopenharmony_ci * rvt_swqe_has_lkey - return true if lkey is used by swqe 6568c2ecf20Sopenharmony_ci * @wqe - the send wqe 6578c2ecf20Sopenharmony_ci * @lkey - the lkey 6588c2ecf20Sopenharmony_ci * 6598c2ecf20Sopenharmony_ci * Test the swqe for using lkey 6608c2ecf20Sopenharmony_ci */ 6618c2ecf20Sopenharmony_cistatic bool rvt_swqe_has_lkey(struct rvt_swqe *wqe, u32 lkey) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci int i; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci for (i = 0; i < wqe->wr.num_sge; i++) { 6668c2ecf20Sopenharmony_ci struct rvt_sge *sge = &wqe->sg_list[i]; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci if (rvt_mr_has_lkey(sge->mr, lkey)) 6698c2ecf20Sopenharmony_ci return true; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci return false; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci/** 6758c2ecf20Sopenharmony_ci * rvt_qp_sends_has_lkey - return true is qp sends use lkey 6768c2ecf20Sopenharmony_ci * @qp - the rvt_qp 6778c2ecf20Sopenharmony_ci * @lkey - the lkey 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_cistatic bool rvt_qp_sends_has_lkey(struct rvt_qp *qp, u32 lkey) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci u32 s_last = qp->s_last; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci while (s_last != qp->s_head) { 6848c2ecf20Sopenharmony_ci struct rvt_swqe *wqe = rvt_get_swqe_ptr(qp, s_last); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (rvt_swqe_has_lkey(wqe, lkey)) 6878c2ecf20Sopenharmony_ci return true; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (++s_last >= qp->s_size) 6908c2ecf20Sopenharmony_ci s_last = 0; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci if (qp->s_rdma_mr) 6938c2ecf20Sopenharmony_ci if (rvt_mr_has_lkey(qp->s_rdma_mr, lkey)) 6948c2ecf20Sopenharmony_ci return true; 6958c2ecf20Sopenharmony_ci return false; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/** 6998c2ecf20Sopenharmony_ci * rvt_qp_acks_has_lkey - return true if acks have lkey 7008c2ecf20Sopenharmony_ci * @qp - the qp 7018c2ecf20Sopenharmony_ci * @lkey - the lkey 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_cistatic bool rvt_qp_acks_has_lkey(struct rvt_qp *qp, u32 lkey) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci int i; 7068c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci for (i = 0; qp->s_ack_queue && i < rvt_max_atomic(rdi); i++) { 7098c2ecf20Sopenharmony_ci struct rvt_ack_entry *e = &qp->s_ack_queue[i]; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (rvt_mr_has_lkey(e->rdma_sge.mr, lkey)) 7128c2ecf20Sopenharmony_ci return true; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci return false; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci/* 7188c2ecf20Sopenharmony_ci * rvt_qp_mr_clean - clean up remote ops for lkey 7198c2ecf20Sopenharmony_ci * @qp - the qp 7208c2ecf20Sopenharmony_ci * @lkey - the lkey that is being de-registered 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * This routine checks if the lkey is being used by 7238c2ecf20Sopenharmony_ci * the qp. 7248c2ecf20Sopenharmony_ci * 7258c2ecf20Sopenharmony_ci * If so, the qp is put into an error state to elminate 7268c2ecf20Sopenharmony_ci * any references from the qp. 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_civoid rvt_qp_mr_clean(struct rvt_qp *qp, u32 lkey) 7298c2ecf20Sopenharmony_ci{ 7308c2ecf20Sopenharmony_ci bool lastwqe = false; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_SMI || 7338c2ecf20Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_GSI) 7348c2ecf20Sopenharmony_ci /* avoid special QPs */ 7358c2ecf20Sopenharmony_ci return; 7368c2ecf20Sopenharmony_ci spin_lock_irq(&qp->r_lock); 7378c2ecf20Sopenharmony_ci spin_lock(&qp->s_hlock); 7388c2ecf20Sopenharmony_ci spin_lock(&qp->s_lock); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET) 7418c2ecf20Sopenharmony_ci goto check_lwqe; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (rvt_ss_has_lkey(&qp->r_sge, lkey) || 7448c2ecf20Sopenharmony_ci rvt_qp_sends_has_lkey(qp, lkey) || 7458c2ecf20Sopenharmony_ci rvt_qp_acks_has_lkey(qp, lkey)) 7468c2ecf20Sopenharmony_ci lastwqe = rvt_error_qp(qp, IB_WC_LOC_PROT_ERR); 7478c2ecf20Sopenharmony_cicheck_lwqe: 7488c2ecf20Sopenharmony_ci spin_unlock(&qp->s_lock); 7498c2ecf20Sopenharmony_ci spin_unlock(&qp->s_hlock); 7508c2ecf20Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 7518c2ecf20Sopenharmony_ci if (lastwqe) { 7528c2ecf20Sopenharmony_ci struct ib_event ev; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 7558c2ecf20Sopenharmony_ci ev.element.qp = &qp->ibqp; 7568c2ecf20Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 7578c2ecf20Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci/** 7628c2ecf20Sopenharmony_ci * rvt_remove_qp - remove qp form table 7638c2ecf20Sopenharmony_ci * @rdi: rvt dev struct 7648c2ecf20Sopenharmony_ci * @qp: qp to remove 7658c2ecf20Sopenharmony_ci * 7668c2ecf20Sopenharmony_ci * Remove the QP from the table so it can't be found asynchronously by 7678c2ecf20Sopenharmony_ci * the receive routine. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_cistatic void rvt_remove_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct rvt_ibport *rvp = rdi->ports[qp->port_num - 1]; 7728c2ecf20Sopenharmony_ci u32 n = hash_32(qp->ibqp.qp_num, rdi->qp_dev->qp_table_bits); 7738c2ecf20Sopenharmony_ci unsigned long flags; 7748c2ecf20Sopenharmony_ci int removed = 1; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci spin_lock_irqsave(&rdi->qp_dev->qpt_lock, flags); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (rcu_dereference_protected(rvp->qp[0], 7798c2ecf20Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock)) == qp) { 7808c2ecf20Sopenharmony_ci RCU_INIT_POINTER(rvp->qp[0], NULL); 7818c2ecf20Sopenharmony_ci } else if (rcu_dereference_protected(rvp->qp[1], 7828c2ecf20Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock)) == qp) { 7838c2ecf20Sopenharmony_ci RCU_INIT_POINTER(rvp->qp[1], NULL); 7848c2ecf20Sopenharmony_ci } else { 7858c2ecf20Sopenharmony_ci struct rvt_qp *q; 7868c2ecf20Sopenharmony_ci struct rvt_qp __rcu **qpp; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci removed = 0; 7898c2ecf20Sopenharmony_ci qpp = &rdi->qp_dev->qp_table[n]; 7908c2ecf20Sopenharmony_ci for (; (q = rcu_dereference_protected(*qpp, 7918c2ecf20Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock))) != NULL; 7928c2ecf20Sopenharmony_ci qpp = &q->next) { 7938c2ecf20Sopenharmony_ci if (q == qp) { 7948c2ecf20Sopenharmony_ci RCU_INIT_POINTER(*qpp, 7958c2ecf20Sopenharmony_ci rcu_dereference_protected(qp->next, 7968c2ecf20Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock))); 7978c2ecf20Sopenharmony_ci removed = 1; 7988c2ecf20Sopenharmony_ci trace_rvt_qpremove(qp, n); 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rdi->qp_dev->qpt_lock, flags); 8058c2ecf20Sopenharmony_ci if (removed) { 8068c2ecf20Sopenharmony_ci synchronize_rcu(); 8078c2ecf20Sopenharmony_ci rvt_put_qp(qp); 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci/** 8128c2ecf20Sopenharmony_ci * rvt_alloc_rq - allocate memory for user or kernel buffer 8138c2ecf20Sopenharmony_ci * @rq: receive queue data structure 8148c2ecf20Sopenharmony_ci * @size: number of request queue entries 8158c2ecf20Sopenharmony_ci * @node: The NUMA node 8168c2ecf20Sopenharmony_ci * @udata: True if user data is available or not false 8178c2ecf20Sopenharmony_ci * 8188c2ecf20Sopenharmony_ci * Return: If memory allocation failed, return -ENONEM 8198c2ecf20Sopenharmony_ci * This function is used by both shared receive 8208c2ecf20Sopenharmony_ci * queues and non-shared receive queues to allocate 8218c2ecf20Sopenharmony_ci * memory. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ciint rvt_alloc_rq(struct rvt_rq *rq, u32 size, int node, 8248c2ecf20Sopenharmony_ci struct ib_udata *udata) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci if (udata) { 8278c2ecf20Sopenharmony_ci rq->wq = vmalloc_user(sizeof(struct rvt_rwq) + size); 8288c2ecf20Sopenharmony_ci if (!rq->wq) 8298c2ecf20Sopenharmony_ci goto bail; 8308c2ecf20Sopenharmony_ci /* need kwq with no buffers */ 8318c2ecf20Sopenharmony_ci rq->kwq = kzalloc_node(sizeof(*rq->kwq), GFP_KERNEL, node); 8328c2ecf20Sopenharmony_ci if (!rq->kwq) 8338c2ecf20Sopenharmony_ci goto bail; 8348c2ecf20Sopenharmony_ci rq->kwq->curr_wq = rq->wq->wq; 8358c2ecf20Sopenharmony_ci } else { 8368c2ecf20Sopenharmony_ci /* need kwq with buffers */ 8378c2ecf20Sopenharmony_ci rq->kwq = 8388c2ecf20Sopenharmony_ci vzalloc_node(sizeof(struct rvt_krwq) + size, node); 8398c2ecf20Sopenharmony_ci if (!rq->kwq) 8408c2ecf20Sopenharmony_ci goto bail; 8418c2ecf20Sopenharmony_ci rq->kwq->curr_wq = rq->kwq->wq; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci spin_lock_init(&rq->kwq->p_lock); 8458c2ecf20Sopenharmony_ci spin_lock_init(&rq->kwq->c_lock); 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_cibail: 8488c2ecf20Sopenharmony_ci rvt_free_rq(rq); 8498c2ecf20Sopenharmony_ci return -ENOMEM; 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/** 8538c2ecf20Sopenharmony_ci * rvt_init_qp - initialize the QP state to the reset state 8548c2ecf20Sopenharmony_ci * @qp: the QP to init or reinit 8558c2ecf20Sopenharmony_ci * @type: the QP type 8568c2ecf20Sopenharmony_ci * 8578c2ecf20Sopenharmony_ci * This function is called from both rvt_create_qp() and 8588c2ecf20Sopenharmony_ci * rvt_reset_qp(). The difference is that the reset 8598c2ecf20Sopenharmony_ci * patch the necessary locks to protect against concurent 8608c2ecf20Sopenharmony_ci * access. 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_cistatic void rvt_init_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 8638c2ecf20Sopenharmony_ci enum ib_qp_type type) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci qp->remote_qpn = 0; 8668c2ecf20Sopenharmony_ci qp->qkey = 0; 8678c2ecf20Sopenharmony_ci qp->qp_access_flags = 0; 8688c2ecf20Sopenharmony_ci qp->s_flags &= RVT_S_SIGNAL_REQ_WR; 8698c2ecf20Sopenharmony_ci qp->s_hdrwords = 0; 8708c2ecf20Sopenharmony_ci qp->s_wqe = NULL; 8718c2ecf20Sopenharmony_ci qp->s_draining = 0; 8728c2ecf20Sopenharmony_ci qp->s_next_psn = 0; 8738c2ecf20Sopenharmony_ci qp->s_last_psn = 0; 8748c2ecf20Sopenharmony_ci qp->s_sending_psn = 0; 8758c2ecf20Sopenharmony_ci qp->s_sending_hpsn = 0; 8768c2ecf20Sopenharmony_ci qp->s_psn = 0; 8778c2ecf20Sopenharmony_ci qp->r_psn = 0; 8788c2ecf20Sopenharmony_ci qp->r_msn = 0; 8798c2ecf20Sopenharmony_ci if (type == IB_QPT_RC) { 8808c2ecf20Sopenharmony_ci qp->s_state = IB_OPCODE_RC_SEND_LAST; 8818c2ecf20Sopenharmony_ci qp->r_state = IB_OPCODE_RC_SEND_LAST; 8828c2ecf20Sopenharmony_ci } else { 8838c2ecf20Sopenharmony_ci qp->s_state = IB_OPCODE_UC_SEND_LAST; 8848c2ecf20Sopenharmony_ci qp->r_state = IB_OPCODE_UC_SEND_LAST; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; 8878c2ecf20Sopenharmony_ci qp->r_nak_state = 0; 8888c2ecf20Sopenharmony_ci qp->r_aflags = 0; 8898c2ecf20Sopenharmony_ci qp->r_flags = 0; 8908c2ecf20Sopenharmony_ci qp->s_head = 0; 8918c2ecf20Sopenharmony_ci qp->s_tail = 0; 8928c2ecf20Sopenharmony_ci qp->s_cur = 0; 8938c2ecf20Sopenharmony_ci qp->s_acked = 0; 8948c2ecf20Sopenharmony_ci qp->s_last = 0; 8958c2ecf20Sopenharmony_ci qp->s_ssn = 1; 8968c2ecf20Sopenharmony_ci qp->s_lsn = 0; 8978c2ecf20Sopenharmony_ci qp->s_mig_state = IB_MIG_MIGRATED; 8988c2ecf20Sopenharmony_ci qp->r_head_ack_queue = 0; 8998c2ecf20Sopenharmony_ci qp->s_tail_ack_queue = 0; 9008c2ecf20Sopenharmony_ci qp->s_acked_ack_queue = 0; 9018c2ecf20Sopenharmony_ci qp->s_num_rd_atomic = 0; 9028c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 0; 9038c2ecf20Sopenharmony_ci atomic_set(&qp->s_reserved_used, 0); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/** 9078c2ecf20Sopenharmony_ci * _rvt_reset_qp - initialize the QP state to the reset state 9088c2ecf20Sopenharmony_ci * @qp: the QP to reset 9098c2ecf20Sopenharmony_ci * @type: the QP type 9108c2ecf20Sopenharmony_ci * 9118c2ecf20Sopenharmony_ci * r_lock, s_hlock, and s_lock are required to be held by the caller 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_cistatic void _rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 9148c2ecf20Sopenharmony_ci enum ib_qp_type type) 9158c2ecf20Sopenharmony_ci __must_hold(&qp->s_lock) 9168c2ecf20Sopenharmony_ci __must_hold(&qp->s_hlock) 9178c2ecf20Sopenharmony_ci __must_hold(&qp->r_lock) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->r_lock); 9208c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_hlock); 9218c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 9228c2ecf20Sopenharmony_ci if (qp->state != IB_QPS_RESET) { 9238c2ecf20Sopenharmony_ci qp->state = IB_QPS_RESET; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Let drivers flush their waitlist */ 9268c2ecf20Sopenharmony_ci rdi->driver_f.flush_qp_waiters(qp); 9278c2ecf20Sopenharmony_ci rvt_stop_rc_timers(qp); 9288c2ecf20Sopenharmony_ci qp->s_flags &= ~(RVT_S_TIMER | RVT_S_ANY_WAIT); 9298c2ecf20Sopenharmony_ci spin_unlock(&qp->s_lock); 9308c2ecf20Sopenharmony_ci spin_unlock(&qp->s_hlock); 9318c2ecf20Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* Stop the send queue and the retry timer */ 9348c2ecf20Sopenharmony_ci rdi->driver_f.stop_send_queue(qp); 9358c2ecf20Sopenharmony_ci rvt_del_timers_sync(qp); 9368c2ecf20Sopenharmony_ci /* Wait for things to stop */ 9378c2ecf20Sopenharmony_ci rdi->driver_f.quiesce_qp(qp); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci /* take qp out the hash and wait for it to be unused */ 9408c2ecf20Sopenharmony_ci rvt_remove_qp(rdi, qp); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* grab the lock b/c it was locked at call time */ 9438c2ecf20Sopenharmony_ci spin_lock_irq(&qp->r_lock); 9448c2ecf20Sopenharmony_ci spin_lock(&qp->s_hlock); 9458c2ecf20Sopenharmony_ci spin_lock(&qp->s_lock); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci rvt_clear_mr_refs(qp, 1); 9488c2ecf20Sopenharmony_ci /* 9498c2ecf20Sopenharmony_ci * Let the driver do any tear down or re-init it needs to for 9508c2ecf20Sopenharmony_ci * a qp that has been reset 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_ci rdi->driver_f.notify_qp_reset(qp); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci rvt_init_qp(rdi, qp, type); 9558c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->r_lock); 9568c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_hlock); 9578c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci/** 9618c2ecf20Sopenharmony_ci * rvt_reset_qp - initialize the QP state to the reset state 9628c2ecf20Sopenharmony_ci * @rdi: the device info 9638c2ecf20Sopenharmony_ci * @qp: the QP to reset 9648c2ecf20Sopenharmony_ci * @type: the QP type 9658c2ecf20Sopenharmony_ci * 9668c2ecf20Sopenharmony_ci * This is the wrapper function to acquire the r_lock, s_hlock, and s_lock 9678c2ecf20Sopenharmony_ci * before calling _rvt_reset_qp(). 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_cistatic void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 9708c2ecf20Sopenharmony_ci enum ib_qp_type type) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci spin_lock_irq(&qp->r_lock); 9738c2ecf20Sopenharmony_ci spin_lock(&qp->s_hlock); 9748c2ecf20Sopenharmony_ci spin_lock(&qp->s_lock); 9758c2ecf20Sopenharmony_ci _rvt_reset_qp(rdi, qp, type); 9768c2ecf20Sopenharmony_ci spin_unlock(&qp->s_lock); 9778c2ecf20Sopenharmony_ci spin_unlock(&qp->s_hlock); 9788c2ecf20Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci/** rvt_free_qpn - Free a qpn from the bit map 9828c2ecf20Sopenharmony_ci * @qpt: QP table 9838c2ecf20Sopenharmony_ci * @qpn: queue pair number to free 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_cistatic void rvt_free_qpn(struct rvt_qpn_table *qpt, u32 qpn) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct rvt_qpn_map *map; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if ((qpn & RVT_AIP_QP_PREFIX_MASK) == RVT_AIP_QP_BASE) 9908c2ecf20Sopenharmony_ci qpn &= RVT_AIP_QP_SUFFIX; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci map = qpt->map + (qpn & RVT_QPN_MASK) / RVT_BITS_PER_PAGE; 9938c2ecf20Sopenharmony_ci if (map->page) 9948c2ecf20Sopenharmony_ci clear_bit(qpn & RVT_BITS_PER_PAGE_MASK, map->page); 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci/** 9988c2ecf20Sopenharmony_ci * get_allowed_ops - Given a QP type return the appropriate allowed OP 9998c2ecf20Sopenharmony_ci * @type: valid, supported, QP type 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_cistatic u8 get_allowed_ops(enum ib_qp_type type) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci return type == IB_QPT_RC ? IB_OPCODE_RC : type == IB_QPT_UC ? 10048c2ecf20Sopenharmony_ci IB_OPCODE_UC : IB_OPCODE_UD; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/** 10088c2ecf20Sopenharmony_ci * free_ud_wq_attr - Clean up AH attribute cache for UD QPs 10098c2ecf20Sopenharmony_ci * @qp: Valid QP with allowed_ops set 10108c2ecf20Sopenharmony_ci * 10118c2ecf20Sopenharmony_ci * The rvt_swqe data structure being used is a union, so this is 10128c2ecf20Sopenharmony_ci * only valid for UD QPs. 10138c2ecf20Sopenharmony_ci */ 10148c2ecf20Sopenharmony_cistatic void free_ud_wq_attr(struct rvt_qp *qp) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci struct rvt_swqe *wqe; 10178c2ecf20Sopenharmony_ci int i; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci for (i = 0; qp->allowed_ops == IB_OPCODE_UD && i < qp->s_size; i++) { 10208c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, i); 10218c2ecf20Sopenharmony_ci kfree(wqe->ud_wr.attr); 10228c2ecf20Sopenharmony_ci wqe->ud_wr.attr = NULL; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci} 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci/** 10278c2ecf20Sopenharmony_ci * alloc_ud_wq_attr - AH attribute cache for UD QPs 10288c2ecf20Sopenharmony_ci * @qp: Valid QP with allowed_ops set 10298c2ecf20Sopenharmony_ci * @node: Numa node for allocation 10308c2ecf20Sopenharmony_ci * 10318c2ecf20Sopenharmony_ci * The rvt_swqe data structure being used is a union, so this is 10328c2ecf20Sopenharmony_ci * only valid for UD QPs. 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_cistatic int alloc_ud_wq_attr(struct rvt_qp *qp, int node) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct rvt_swqe *wqe; 10378c2ecf20Sopenharmony_ci int i; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci for (i = 0; qp->allowed_ops == IB_OPCODE_UD && i < qp->s_size; i++) { 10408c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, i); 10418c2ecf20Sopenharmony_ci wqe->ud_wr.attr = kzalloc_node(sizeof(*wqe->ud_wr.attr), 10428c2ecf20Sopenharmony_ci GFP_KERNEL, node); 10438c2ecf20Sopenharmony_ci if (!wqe->ud_wr.attr) { 10448c2ecf20Sopenharmony_ci free_ud_wq_attr(qp); 10458c2ecf20Sopenharmony_ci return -ENOMEM; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci return 0; 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci/** 10538c2ecf20Sopenharmony_ci * rvt_create_qp - create a queue pair for a device 10548c2ecf20Sopenharmony_ci * @ibpd: the protection domain who's device we create the queue pair for 10558c2ecf20Sopenharmony_ci * @init_attr: the attributes of the queue pair 10568c2ecf20Sopenharmony_ci * @udata: user data for libibverbs.so 10578c2ecf20Sopenharmony_ci * 10588c2ecf20Sopenharmony_ci * Queue pair creation is mostly an rvt issue. However, drivers have their own 10598c2ecf20Sopenharmony_ci * unique idea of what queue pair numbers mean. For instance there is a reserved 10608c2ecf20Sopenharmony_ci * range for PSM. 10618c2ecf20Sopenharmony_ci * 10628c2ecf20Sopenharmony_ci * Return: the queue pair on success, otherwise returns an errno. 10638c2ecf20Sopenharmony_ci * 10648c2ecf20Sopenharmony_ci * Called by the ib_create_qp() core verbs function. 10658c2ecf20Sopenharmony_ci */ 10668c2ecf20Sopenharmony_cistruct ib_qp *rvt_create_qp(struct ib_pd *ibpd, 10678c2ecf20Sopenharmony_ci struct ib_qp_init_attr *init_attr, 10688c2ecf20Sopenharmony_ci struct ib_udata *udata) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct rvt_qp *qp; 10718c2ecf20Sopenharmony_ci int err; 10728c2ecf20Sopenharmony_ci struct rvt_swqe *swq = NULL; 10738c2ecf20Sopenharmony_ci size_t sz; 10748c2ecf20Sopenharmony_ci size_t sg_list_sz; 10758c2ecf20Sopenharmony_ci struct ib_qp *ret = ERR_PTR(-ENOMEM); 10768c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibpd->device); 10778c2ecf20Sopenharmony_ci void *priv = NULL; 10788c2ecf20Sopenharmony_ci size_t sqsize; 10798c2ecf20Sopenharmony_ci u8 exclude_prefix = 0; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (!rdi) 10828c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (init_attr->cap.max_send_sge > rdi->dparms.props.max_send_sge || 10858c2ecf20Sopenharmony_ci init_attr->cap.max_send_wr > rdi->dparms.props.max_qp_wr || 10868c2ecf20Sopenharmony_ci (init_attr->create_flags && 10878c2ecf20Sopenharmony_ci init_attr->create_flags != IB_QP_CREATE_NETDEV_USE)) 10888c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci /* Check receive queue parameters if no SRQ is specified. */ 10918c2ecf20Sopenharmony_ci if (!init_attr->srq) { 10928c2ecf20Sopenharmony_ci if (init_attr->cap.max_recv_sge > 10938c2ecf20Sopenharmony_ci rdi->dparms.props.max_recv_sge || 10948c2ecf20Sopenharmony_ci init_attr->cap.max_recv_wr > rdi->dparms.props.max_qp_wr) 10958c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (init_attr->cap.max_send_sge + 10988c2ecf20Sopenharmony_ci init_attr->cap.max_send_wr + 10998c2ecf20Sopenharmony_ci init_attr->cap.max_recv_sge + 11008c2ecf20Sopenharmony_ci init_attr->cap.max_recv_wr == 0) 11018c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci sqsize = 11048c2ecf20Sopenharmony_ci init_attr->cap.max_send_wr + 1 + 11058c2ecf20Sopenharmony_ci rdi->dparms.reserved_operations; 11068c2ecf20Sopenharmony_ci switch (init_attr->qp_type) { 11078c2ecf20Sopenharmony_ci case IB_QPT_SMI: 11088c2ecf20Sopenharmony_ci case IB_QPT_GSI: 11098c2ecf20Sopenharmony_ci if (init_attr->port_num == 0 || 11108c2ecf20Sopenharmony_ci init_attr->port_num > ibpd->device->phys_port_cnt) 11118c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 11128c2ecf20Sopenharmony_ci fallthrough; 11138c2ecf20Sopenharmony_ci case IB_QPT_UC: 11148c2ecf20Sopenharmony_ci case IB_QPT_RC: 11158c2ecf20Sopenharmony_ci case IB_QPT_UD: 11168c2ecf20Sopenharmony_ci sz = struct_size(swq, sg_list, init_attr->cap.max_send_sge); 11178c2ecf20Sopenharmony_ci swq = vzalloc_node(array_size(sz, sqsize), rdi->dparms.node); 11188c2ecf20Sopenharmony_ci if (!swq) 11198c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci sz = sizeof(*qp); 11228c2ecf20Sopenharmony_ci sg_list_sz = 0; 11238c2ecf20Sopenharmony_ci if (init_attr->srq) { 11248c2ecf20Sopenharmony_ci struct rvt_srq *srq = ibsrq_to_rvtsrq(init_attr->srq); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (srq->rq.max_sge > 1) 11278c2ecf20Sopenharmony_ci sg_list_sz = sizeof(*qp->r_sg_list) * 11288c2ecf20Sopenharmony_ci (srq->rq.max_sge - 1); 11298c2ecf20Sopenharmony_ci } else if (init_attr->cap.max_recv_sge > 1) 11308c2ecf20Sopenharmony_ci sg_list_sz = sizeof(*qp->r_sg_list) * 11318c2ecf20Sopenharmony_ci (init_attr->cap.max_recv_sge - 1); 11328c2ecf20Sopenharmony_ci qp = kzalloc_node(sz + sg_list_sz, GFP_KERNEL, 11338c2ecf20Sopenharmony_ci rdi->dparms.node); 11348c2ecf20Sopenharmony_ci if (!qp) 11358c2ecf20Sopenharmony_ci goto bail_swq; 11368c2ecf20Sopenharmony_ci qp->allowed_ops = get_allowed_ops(init_attr->qp_type); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci RCU_INIT_POINTER(qp->next, NULL); 11398c2ecf20Sopenharmony_ci if (init_attr->qp_type == IB_QPT_RC) { 11408c2ecf20Sopenharmony_ci qp->s_ack_queue = 11418c2ecf20Sopenharmony_ci kcalloc_node(rvt_max_atomic(rdi), 11428c2ecf20Sopenharmony_ci sizeof(*qp->s_ack_queue), 11438c2ecf20Sopenharmony_ci GFP_KERNEL, 11448c2ecf20Sopenharmony_ci rdi->dparms.node); 11458c2ecf20Sopenharmony_ci if (!qp->s_ack_queue) 11468c2ecf20Sopenharmony_ci goto bail_qp; 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci /* initialize timers needed for rc qp */ 11498c2ecf20Sopenharmony_ci timer_setup(&qp->s_timer, rvt_rc_timeout, 0); 11508c2ecf20Sopenharmony_ci hrtimer_init(&qp->s_rnr_timer, CLOCK_MONOTONIC, 11518c2ecf20Sopenharmony_ci HRTIMER_MODE_REL); 11528c2ecf20Sopenharmony_ci qp->s_rnr_timer.function = rvt_rc_rnr_retry; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* 11558c2ecf20Sopenharmony_ci * Driver needs to set up it's private QP structure and do any 11568c2ecf20Sopenharmony_ci * initialization that is needed. 11578c2ecf20Sopenharmony_ci */ 11588c2ecf20Sopenharmony_ci priv = rdi->driver_f.qp_priv_alloc(rdi, qp); 11598c2ecf20Sopenharmony_ci if (IS_ERR(priv)) { 11608c2ecf20Sopenharmony_ci ret = priv; 11618c2ecf20Sopenharmony_ci goto bail_qp; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci qp->priv = priv; 11648c2ecf20Sopenharmony_ci qp->timeout_jiffies = 11658c2ecf20Sopenharmony_ci usecs_to_jiffies((4096UL * (1UL << qp->timeout)) / 11668c2ecf20Sopenharmony_ci 1000UL); 11678c2ecf20Sopenharmony_ci if (init_attr->srq) { 11688c2ecf20Sopenharmony_ci sz = 0; 11698c2ecf20Sopenharmony_ci } else { 11708c2ecf20Sopenharmony_ci qp->r_rq.size = init_attr->cap.max_recv_wr + 1; 11718c2ecf20Sopenharmony_ci qp->r_rq.max_sge = init_attr->cap.max_recv_sge; 11728c2ecf20Sopenharmony_ci sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) + 11738c2ecf20Sopenharmony_ci sizeof(struct rvt_rwqe); 11748c2ecf20Sopenharmony_ci err = rvt_alloc_rq(&qp->r_rq, qp->r_rq.size * sz, 11758c2ecf20Sopenharmony_ci rdi->dparms.node, udata); 11768c2ecf20Sopenharmony_ci if (err) { 11778c2ecf20Sopenharmony_ci ret = ERR_PTR(err); 11788c2ecf20Sopenharmony_ci goto bail_driver_priv; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci /* 11838c2ecf20Sopenharmony_ci * ib_create_qp() will initialize qp->ibqp 11848c2ecf20Sopenharmony_ci * except for qp->ibqp.qp_num. 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci spin_lock_init(&qp->r_lock); 11878c2ecf20Sopenharmony_ci spin_lock_init(&qp->s_hlock); 11888c2ecf20Sopenharmony_ci spin_lock_init(&qp->s_lock); 11898c2ecf20Sopenharmony_ci atomic_set(&qp->refcount, 0); 11908c2ecf20Sopenharmony_ci atomic_set(&qp->local_ops_pending, 0); 11918c2ecf20Sopenharmony_ci init_waitqueue_head(&qp->wait); 11928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qp->rspwait); 11938c2ecf20Sopenharmony_ci qp->state = IB_QPS_RESET; 11948c2ecf20Sopenharmony_ci qp->s_wq = swq; 11958c2ecf20Sopenharmony_ci qp->s_size = sqsize; 11968c2ecf20Sopenharmony_ci qp->s_avail = init_attr->cap.max_send_wr; 11978c2ecf20Sopenharmony_ci qp->s_max_sge = init_attr->cap.max_send_sge; 11988c2ecf20Sopenharmony_ci if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR) 11998c2ecf20Sopenharmony_ci qp->s_flags = RVT_S_SIGNAL_REQ_WR; 12008c2ecf20Sopenharmony_ci err = alloc_ud_wq_attr(qp, rdi->dparms.node); 12018c2ecf20Sopenharmony_ci if (err) { 12028c2ecf20Sopenharmony_ci ret = (ERR_PTR(err)); 12038c2ecf20Sopenharmony_ci goto bail_rq_rvt; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (init_attr->create_flags & IB_QP_CREATE_NETDEV_USE) 12078c2ecf20Sopenharmony_ci exclude_prefix = RVT_AIP_QP_PREFIX; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci err = alloc_qpn(rdi, &rdi->qp_dev->qpn_table, 12108c2ecf20Sopenharmony_ci init_attr->qp_type, 12118c2ecf20Sopenharmony_ci init_attr->port_num, 12128c2ecf20Sopenharmony_ci exclude_prefix); 12138c2ecf20Sopenharmony_ci if (err < 0) { 12148c2ecf20Sopenharmony_ci ret = ERR_PTR(err); 12158c2ecf20Sopenharmony_ci goto bail_rq_wq; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci qp->ibqp.qp_num = err; 12188c2ecf20Sopenharmony_ci if (init_attr->create_flags & IB_QP_CREATE_NETDEV_USE) 12198c2ecf20Sopenharmony_ci qp->ibqp.qp_num |= RVT_AIP_QP_BASE; 12208c2ecf20Sopenharmony_ci qp->port_num = init_attr->port_num; 12218c2ecf20Sopenharmony_ci rvt_init_qp(rdi, qp, init_attr->qp_type); 12228c2ecf20Sopenharmony_ci if (rdi->driver_f.qp_priv_init) { 12238c2ecf20Sopenharmony_ci err = rdi->driver_f.qp_priv_init(rdi, qp, init_attr); 12248c2ecf20Sopenharmony_ci if (err) { 12258c2ecf20Sopenharmony_ci ret = ERR_PTR(err); 12268c2ecf20Sopenharmony_ci goto bail_rq_wq; 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci break; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci default: 12328c2ecf20Sopenharmony_ci /* Don't support raw QPs */ 12338c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci init_attr->cap.max_inline_data = 0; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* 12398c2ecf20Sopenharmony_ci * Return the address of the RWQ as the offset to mmap. 12408c2ecf20Sopenharmony_ci * See rvt_mmap() for details. 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_ci if (udata && udata->outlen >= sizeof(__u64)) { 12438c2ecf20Sopenharmony_ci if (!qp->r_rq.wq) { 12448c2ecf20Sopenharmony_ci __u64 offset = 0; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, &offset, 12478c2ecf20Sopenharmony_ci sizeof(offset)); 12488c2ecf20Sopenharmony_ci if (err) { 12498c2ecf20Sopenharmony_ci ret = ERR_PTR(err); 12508c2ecf20Sopenharmony_ci goto bail_qpn; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci } else { 12538c2ecf20Sopenharmony_ci u32 s = sizeof(struct rvt_rwq) + qp->r_rq.size * sz; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci qp->ip = rvt_create_mmap_info(rdi, s, udata, 12568c2ecf20Sopenharmony_ci qp->r_rq.wq); 12578c2ecf20Sopenharmony_ci if (IS_ERR(qp->ip)) { 12588c2ecf20Sopenharmony_ci ret = ERR_CAST(qp->ip); 12598c2ecf20Sopenharmony_ci goto bail_qpn; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci err = ib_copy_to_udata(udata, &qp->ip->offset, 12638c2ecf20Sopenharmony_ci sizeof(qp->ip->offset)); 12648c2ecf20Sopenharmony_ci if (err) { 12658c2ecf20Sopenharmony_ci ret = ERR_PTR(err); 12668c2ecf20Sopenharmony_ci goto bail_ip; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci qp->pid = current->pid; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci spin_lock(&rdi->n_qps_lock); 12738c2ecf20Sopenharmony_ci if (rdi->n_qps_allocated == rdi->dparms.props.max_qp) { 12748c2ecf20Sopenharmony_ci spin_unlock(&rdi->n_qps_lock); 12758c2ecf20Sopenharmony_ci ret = ERR_PTR(-ENOMEM); 12768c2ecf20Sopenharmony_ci goto bail_ip; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci rdi->n_qps_allocated++; 12808c2ecf20Sopenharmony_ci /* 12818c2ecf20Sopenharmony_ci * Maintain a busy_jiffies variable that will be added to the timeout 12828c2ecf20Sopenharmony_ci * period in mod_retry_timer and add_retry_timer. This busy jiffies 12838c2ecf20Sopenharmony_ci * is scaled by the number of rc qps created for the device to reduce 12848c2ecf20Sopenharmony_ci * the number of timeouts occurring when there is a large number of 12858c2ecf20Sopenharmony_ci * qps. busy_jiffies is incremented every rc qp scaling interval. 12868c2ecf20Sopenharmony_ci * The scaling interval is selected based on extensive performance 12878c2ecf20Sopenharmony_ci * evaluation of targeted workloads. 12888c2ecf20Sopenharmony_ci */ 12898c2ecf20Sopenharmony_ci if (init_attr->qp_type == IB_QPT_RC) { 12908c2ecf20Sopenharmony_ci rdi->n_rc_qps++; 12918c2ecf20Sopenharmony_ci rdi->busy_jiffies = rdi->n_rc_qps / RC_QP_SCALING_INTERVAL; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci spin_unlock(&rdi->n_qps_lock); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (qp->ip) { 12968c2ecf20Sopenharmony_ci spin_lock_irq(&rdi->pending_lock); 12978c2ecf20Sopenharmony_ci list_add(&qp->ip->pending_mmaps, &rdi->pending_mmaps); 12988c2ecf20Sopenharmony_ci spin_unlock_irq(&rdi->pending_lock); 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci ret = &qp->ibqp; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci return ret; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cibail_ip: 13068c2ecf20Sopenharmony_ci if (qp->ip) 13078c2ecf20Sopenharmony_ci kref_put(&qp->ip->ref, rvt_release_mmap_info); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cibail_qpn: 13108c2ecf20Sopenharmony_ci rvt_free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cibail_rq_wq: 13138c2ecf20Sopenharmony_ci free_ud_wq_attr(qp); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cibail_rq_rvt: 13168c2ecf20Sopenharmony_ci rvt_free_rq(&qp->r_rq); 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cibail_driver_priv: 13198c2ecf20Sopenharmony_ci rdi->driver_f.qp_priv_free(rdi, qp); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_cibail_qp: 13228c2ecf20Sopenharmony_ci kfree(qp->s_ack_queue); 13238c2ecf20Sopenharmony_ci kfree(qp); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cibail_swq: 13268c2ecf20Sopenharmony_ci vfree(swq); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return ret; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci/** 13328c2ecf20Sopenharmony_ci * rvt_error_qp - put a QP into the error state 13338c2ecf20Sopenharmony_ci * @qp: the QP to put into the error state 13348c2ecf20Sopenharmony_ci * @err: the receive completion error to signal if a RWQE is active 13358c2ecf20Sopenharmony_ci * 13368c2ecf20Sopenharmony_ci * Flushes both send and receive work queues. 13378c2ecf20Sopenharmony_ci * 13388c2ecf20Sopenharmony_ci * Return: true if last WQE event should be generated. 13398c2ecf20Sopenharmony_ci * The QP r_lock and s_lock should be held and interrupts disabled. 13408c2ecf20Sopenharmony_ci * If we are already in error state, just return. 13418c2ecf20Sopenharmony_ci */ 13428c2ecf20Sopenharmony_ciint rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err) 13438c2ecf20Sopenharmony_ci{ 13448c2ecf20Sopenharmony_ci struct ib_wc wc; 13458c2ecf20Sopenharmony_ci int ret = 0; 13468c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->r_lock); 13498c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 13508c2ecf20Sopenharmony_ci if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET) 13518c2ecf20Sopenharmony_ci goto bail; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci qp->state = IB_QPS_ERR; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) { 13568c2ecf20Sopenharmony_ci qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR); 13578c2ecf20Sopenharmony_ci del_timer(&qp->s_timer); 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (qp->s_flags & RVT_S_ANY_WAIT_SEND) 13618c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_ANY_WAIT_SEND; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci rdi->driver_f.notify_error_qp(qp); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* Schedule the sending tasklet to drain the send work queue. */ 13668c2ecf20Sopenharmony_ci if (READ_ONCE(qp->s_last) != qp->s_head) 13678c2ecf20Sopenharmony_ci rdi->driver_f.schedule_send(qp); 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci rvt_clear_mr_refs(qp, 0); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 13728c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 13738c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) { 13768c2ecf20Sopenharmony_ci wc.wr_id = qp->r_wr_id; 13778c2ecf20Sopenharmony_ci wc.status = err; 13788c2ecf20Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci wc.status = IB_WC_WR_FLUSH_ERR; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (qp->r_rq.kwq) { 13838c2ecf20Sopenharmony_ci u32 head; 13848c2ecf20Sopenharmony_ci u32 tail; 13858c2ecf20Sopenharmony_ci struct rvt_rwq *wq = NULL; 13868c2ecf20Sopenharmony_ci struct rvt_krwq *kwq = NULL; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci spin_lock(&qp->r_rq.kwq->c_lock); 13898c2ecf20Sopenharmony_ci /* qp->ip used to validate if there is a user buffer mmaped */ 13908c2ecf20Sopenharmony_ci if (qp->ip) { 13918c2ecf20Sopenharmony_ci wq = qp->r_rq.wq; 13928c2ecf20Sopenharmony_ci head = RDMA_READ_UAPI_ATOMIC(wq->head); 13938c2ecf20Sopenharmony_ci tail = RDMA_READ_UAPI_ATOMIC(wq->tail); 13948c2ecf20Sopenharmony_ci } else { 13958c2ecf20Sopenharmony_ci kwq = qp->r_rq.kwq; 13968c2ecf20Sopenharmony_ci head = kwq->head; 13978c2ecf20Sopenharmony_ci tail = kwq->tail; 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci /* sanity check pointers before trusting them */ 14008c2ecf20Sopenharmony_ci if (head >= qp->r_rq.size) 14018c2ecf20Sopenharmony_ci head = 0; 14028c2ecf20Sopenharmony_ci if (tail >= qp->r_rq.size) 14038c2ecf20Sopenharmony_ci tail = 0; 14048c2ecf20Sopenharmony_ci while (tail != head) { 14058c2ecf20Sopenharmony_ci wc.wr_id = rvt_get_rwqe_ptr(&qp->r_rq, tail)->wr_id; 14068c2ecf20Sopenharmony_ci if (++tail >= qp->r_rq.size) 14078c2ecf20Sopenharmony_ci tail = 0; 14088c2ecf20Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci if (qp->ip) 14118c2ecf20Sopenharmony_ci RDMA_WRITE_UAPI_ATOMIC(wq->tail, tail); 14128c2ecf20Sopenharmony_ci else 14138c2ecf20Sopenharmony_ci kwq->tail = tail; 14148c2ecf20Sopenharmony_ci spin_unlock(&qp->r_rq.kwq->c_lock); 14158c2ecf20Sopenharmony_ci } else if (qp->ibqp.event_handler) { 14168c2ecf20Sopenharmony_ci ret = 1; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cibail: 14208c2ecf20Sopenharmony_ci return ret; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_error_qp); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci/* 14258c2ecf20Sopenharmony_ci * Put the QP into the hash table. 14268c2ecf20Sopenharmony_ci * The hash table holds a reference to the QP. 14278c2ecf20Sopenharmony_ci */ 14288c2ecf20Sopenharmony_cistatic void rvt_insert_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp) 14298c2ecf20Sopenharmony_ci{ 14308c2ecf20Sopenharmony_ci struct rvt_ibport *rvp = rdi->ports[qp->port_num - 1]; 14318c2ecf20Sopenharmony_ci unsigned long flags; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci rvt_get_qp(qp); 14348c2ecf20Sopenharmony_ci spin_lock_irqsave(&rdi->qp_dev->qpt_lock, flags); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci if (qp->ibqp.qp_num <= 1) { 14378c2ecf20Sopenharmony_ci rcu_assign_pointer(rvp->qp[qp->ibqp.qp_num], qp); 14388c2ecf20Sopenharmony_ci } else { 14398c2ecf20Sopenharmony_ci u32 n = hash_32(qp->ibqp.qp_num, rdi->qp_dev->qp_table_bits); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci qp->next = rdi->qp_dev->qp_table[n]; 14428c2ecf20Sopenharmony_ci rcu_assign_pointer(rdi->qp_dev->qp_table[n], qp); 14438c2ecf20Sopenharmony_ci trace_rvt_qpinsert(qp, n); 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rdi->qp_dev->qpt_lock, flags); 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci/** 14508c2ecf20Sopenharmony_ci * rvt_modify_qp - modify the attributes of a queue pair 14518c2ecf20Sopenharmony_ci * @ibqp: the queue pair who's attributes we're modifying 14528c2ecf20Sopenharmony_ci * @attr: the new attributes 14538c2ecf20Sopenharmony_ci * @attr_mask: the mask of attributes to modify 14548c2ecf20Sopenharmony_ci * @udata: user data for libibverbs.so 14558c2ecf20Sopenharmony_ci * 14568c2ecf20Sopenharmony_ci * Return: 0 on success, otherwise returns an errno. 14578c2ecf20Sopenharmony_ci */ 14588c2ecf20Sopenharmony_ciint rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 14598c2ecf20Sopenharmony_ci int attr_mask, struct ib_udata *udata) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 14628c2ecf20Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 14638c2ecf20Sopenharmony_ci enum ib_qp_state cur_state, new_state; 14648c2ecf20Sopenharmony_ci struct ib_event ev; 14658c2ecf20Sopenharmony_ci int lastwqe = 0; 14668c2ecf20Sopenharmony_ci int mig = 0; 14678c2ecf20Sopenharmony_ci int pmtu = 0; /* for gcc warning only */ 14688c2ecf20Sopenharmony_ci int opa_ah; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci spin_lock_irq(&qp->r_lock); 14718c2ecf20Sopenharmony_ci spin_lock(&qp->s_hlock); 14728c2ecf20Sopenharmony_ci spin_lock(&qp->s_lock); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci cur_state = attr_mask & IB_QP_CUR_STATE ? 14758c2ecf20Sopenharmony_ci attr->cur_qp_state : qp->state; 14768c2ecf20Sopenharmony_ci new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; 14778c2ecf20Sopenharmony_ci opa_ah = rdma_cap_opa_ah(ibqp->device, qp->port_num); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, 14808c2ecf20Sopenharmony_ci attr_mask)) 14818c2ecf20Sopenharmony_ci goto inval; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (rdi->driver_f.check_modify_qp && 14848c2ecf20Sopenharmony_ci rdi->driver_f.check_modify_qp(qp, attr, attr_mask, udata)) 14858c2ecf20Sopenharmony_ci goto inval; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_AV) { 14888c2ecf20Sopenharmony_ci if (opa_ah) { 14898c2ecf20Sopenharmony_ci if (rdma_ah_get_dlid(&attr->ah_attr) >= 14908c2ecf20Sopenharmony_ci opa_get_mcast_base(OPA_MCAST_NR)) 14918c2ecf20Sopenharmony_ci goto inval; 14928c2ecf20Sopenharmony_ci } else { 14938c2ecf20Sopenharmony_ci if (rdma_ah_get_dlid(&attr->ah_attr) >= 14948c2ecf20Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE)) 14958c2ecf20Sopenharmony_ci goto inval; 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci if (rvt_check_ah(qp->ibqp.device, &attr->ah_attr)) 14998c2ecf20Sopenharmony_ci goto inval; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) { 15038c2ecf20Sopenharmony_ci if (opa_ah) { 15048c2ecf20Sopenharmony_ci if (rdma_ah_get_dlid(&attr->alt_ah_attr) >= 15058c2ecf20Sopenharmony_ci opa_get_mcast_base(OPA_MCAST_NR)) 15068c2ecf20Sopenharmony_ci goto inval; 15078c2ecf20Sopenharmony_ci } else { 15088c2ecf20Sopenharmony_ci if (rdma_ah_get_dlid(&attr->alt_ah_attr) >= 15098c2ecf20Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE)) 15108c2ecf20Sopenharmony_ci goto inval; 15118c2ecf20Sopenharmony_ci } 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci if (rvt_check_ah(qp->ibqp.device, &attr->alt_ah_attr)) 15148c2ecf20Sopenharmony_ci goto inval; 15158c2ecf20Sopenharmony_ci if (attr->alt_pkey_index >= rvt_get_npkeys(rdi)) 15168c2ecf20Sopenharmony_ci goto inval; 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) 15208c2ecf20Sopenharmony_ci if (attr->pkey_index >= rvt_get_npkeys(rdi)) 15218c2ecf20Sopenharmony_ci goto inval; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) 15248c2ecf20Sopenharmony_ci if (attr->min_rnr_timer > 31) 15258c2ecf20Sopenharmony_ci goto inval; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PORT) 15288c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_SMI || 15298c2ecf20Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_GSI || 15308c2ecf20Sopenharmony_ci attr->port_num == 0 || 15318c2ecf20Sopenharmony_ci attr->port_num > ibqp->device->phys_port_cnt) 15328c2ecf20Sopenharmony_ci goto inval; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_DEST_QPN) 15358c2ecf20Sopenharmony_ci if (attr->dest_qp_num > RVT_QPN_MASK) 15368c2ecf20Sopenharmony_ci goto inval; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RETRY_CNT) 15398c2ecf20Sopenharmony_ci if (attr->retry_cnt > 7) 15408c2ecf20Sopenharmony_ci goto inval; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RNR_RETRY) 15438c2ecf20Sopenharmony_ci if (attr->rnr_retry > 7) 15448c2ecf20Sopenharmony_ci goto inval; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci /* 15478c2ecf20Sopenharmony_ci * Don't allow invalid path_mtu values. OK to set greater 15488c2ecf20Sopenharmony_ci * than the active mtu (or even the max_cap, if we have tuned 15498c2ecf20Sopenharmony_ci * that to a small mtu. We'll set qp->path_mtu 15508c2ecf20Sopenharmony_ci * to the lesser of requested attribute mtu and active, 15518c2ecf20Sopenharmony_ci * for packetizing messages. 15528c2ecf20Sopenharmony_ci * Note that the QP port has to be set in INIT and MTU in RTR. 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PATH_MTU) { 15558c2ecf20Sopenharmony_ci pmtu = rdi->driver_f.get_pmtu_from_attr(rdi, qp, attr); 15568c2ecf20Sopenharmony_ci if (pmtu < 0) 15578c2ecf20Sopenharmony_ci goto inval; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PATH_MIG_STATE) { 15618c2ecf20Sopenharmony_ci if (attr->path_mig_state == IB_MIG_REARM) { 15628c2ecf20Sopenharmony_ci if (qp->s_mig_state == IB_MIG_ARMED) 15638c2ecf20Sopenharmony_ci goto inval; 15648c2ecf20Sopenharmony_ci if (new_state != IB_QPS_RTS) 15658c2ecf20Sopenharmony_ci goto inval; 15668c2ecf20Sopenharmony_ci } else if (attr->path_mig_state == IB_MIG_MIGRATED) { 15678c2ecf20Sopenharmony_ci if (qp->s_mig_state == IB_MIG_REARM) 15688c2ecf20Sopenharmony_ci goto inval; 15698c2ecf20Sopenharmony_ci if (new_state != IB_QPS_RTS && new_state != IB_QPS_SQD) 15708c2ecf20Sopenharmony_ci goto inval; 15718c2ecf20Sopenharmony_ci if (qp->s_mig_state == IB_MIG_ARMED) 15728c2ecf20Sopenharmony_ci mig = 1; 15738c2ecf20Sopenharmony_ci } else { 15748c2ecf20Sopenharmony_ci goto inval; 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 15798c2ecf20Sopenharmony_ci if (attr->max_dest_rd_atomic > rdi->dparms.max_rdma_atomic) 15808c2ecf20Sopenharmony_ci goto inval; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci switch (new_state) { 15838c2ecf20Sopenharmony_ci case IB_QPS_RESET: 15848c2ecf20Sopenharmony_ci if (qp->state != IB_QPS_RESET) 15858c2ecf20Sopenharmony_ci _rvt_reset_qp(rdi, qp, ibqp->qp_type); 15868c2ecf20Sopenharmony_ci break; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci case IB_QPS_RTR: 15898c2ecf20Sopenharmony_ci /* Allow event to re-trigger if QP set to RTR more than once */ 15908c2ecf20Sopenharmony_ci qp->r_flags &= ~RVT_R_COMM_EST; 15918c2ecf20Sopenharmony_ci qp->state = new_state; 15928c2ecf20Sopenharmony_ci break; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci case IB_QPS_SQD: 15958c2ecf20Sopenharmony_ci qp->s_draining = qp->s_last != qp->s_cur; 15968c2ecf20Sopenharmony_ci qp->state = new_state; 15978c2ecf20Sopenharmony_ci break; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci case IB_QPS_SQE: 16008c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RC) 16018c2ecf20Sopenharmony_ci goto inval; 16028c2ecf20Sopenharmony_ci qp->state = new_state; 16038c2ecf20Sopenharmony_ci break; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci case IB_QPS_ERR: 16068c2ecf20Sopenharmony_ci lastwqe = rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); 16078c2ecf20Sopenharmony_ci break; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci default: 16108c2ecf20Sopenharmony_ci qp->state = new_state; 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) 16158c2ecf20Sopenharmony_ci qp->s_pkey_index = attr->pkey_index; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PORT) 16188c2ecf20Sopenharmony_ci qp->port_num = attr->port_num; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_DEST_QPN) 16218c2ecf20Sopenharmony_ci qp->remote_qpn = attr->dest_qp_num; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_SQ_PSN) { 16248c2ecf20Sopenharmony_ci qp->s_next_psn = attr->sq_psn & rdi->dparms.psn_modify_mask; 16258c2ecf20Sopenharmony_ci qp->s_psn = qp->s_next_psn; 16268c2ecf20Sopenharmony_ci qp->s_sending_psn = qp->s_next_psn; 16278c2ecf20Sopenharmony_ci qp->s_last_psn = qp->s_next_psn - 1; 16288c2ecf20Sopenharmony_ci qp->s_sending_hpsn = qp->s_last_psn; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RQ_PSN) 16328c2ecf20Sopenharmony_ci qp->r_psn = attr->rq_psn & rdi->dparms.psn_modify_mask; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ACCESS_FLAGS) 16358c2ecf20Sopenharmony_ci qp->qp_access_flags = attr->qp_access_flags; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_AV) { 16388c2ecf20Sopenharmony_ci rdma_replace_ah_attr(&qp->remote_ah_attr, &attr->ah_attr); 16398c2ecf20Sopenharmony_ci qp->s_srate = rdma_ah_get_static_rate(&attr->ah_attr); 16408c2ecf20Sopenharmony_ci qp->srate_mbps = ib_rate_to_mbps(qp->s_srate); 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) { 16448c2ecf20Sopenharmony_ci rdma_replace_ah_attr(&qp->alt_ah_attr, &attr->alt_ah_attr); 16458c2ecf20Sopenharmony_ci qp->s_alt_pkey_index = attr->alt_pkey_index; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PATH_MIG_STATE) { 16498c2ecf20Sopenharmony_ci qp->s_mig_state = attr->path_mig_state; 16508c2ecf20Sopenharmony_ci if (mig) { 16518c2ecf20Sopenharmony_ci qp->remote_ah_attr = qp->alt_ah_attr; 16528c2ecf20Sopenharmony_ci qp->port_num = rdma_ah_get_port_num(&qp->alt_ah_attr); 16538c2ecf20Sopenharmony_ci qp->s_pkey_index = qp->s_alt_pkey_index; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_PATH_MTU) { 16588c2ecf20Sopenharmony_ci qp->pmtu = rdi->driver_f.mtu_from_qp(rdi, qp, pmtu); 16598c2ecf20Sopenharmony_ci qp->log_pmtu = ilog2(qp->pmtu); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RETRY_CNT) { 16638c2ecf20Sopenharmony_ci qp->s_retry_cnt = attr->retry_cnt; 16648c2ecf20Sopenharmony_ci qp->s_retry = attr->retry_cnt; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_RNR_RETRY) { 16688c2ecf20Sopenharmony_ci qp->s_rnr_retry_cnt = attr->rnr_retry; 16698c2ecf20Sopenharmony_ci qp->s_rnr_retry = attr->rnr_retry; 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) 16738c2ecf20Sopenharmony_ci qp->r_min_rnr_timer = attr->min_rnr_timer; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_TIMEOUT) { 16768c2ecf20Sopenharmony_ci qp->timeout = attr->timeout; 16778c2ecf20Sopenharmony_ci qp->timeout_jiffies = rvt_timeout_to_jiffies(qp->timeout); 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_QKEY) 16818c2ecf20Sopenharmony_ci qp->qkey = attr->qkey; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 16848c2ecf20Sopenharmony_ci qp->r_max_rd_atomic = attr->max_dest_rd_atomic; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) 16878c2ecf20Sopenharmony_ci qp->s_max_rd_atomic = attr->max_rd_atomic; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci if (rdi->driver_f.modify_qp) 16908c2ecf20Sopenharmony_ci rdi->driver_f.modify_qp(qp, attr, attr_mask, udata); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci spin_unlock(&qp->s_lock); 16938c2ecf20Sopenharmony_ci spin_unlock(&qp->s_hlock); 16948c2ecf20Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) 16978c2ecf20Sopenharmony_ci rvt_insert_qp(rdi, qp); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci if (lastwqe) { 17008c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 17018c2ecf20Sopenharmony_ci ev.element.qp = &qp->ibqp; 17028c2ecf20Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 17038c2ecf20Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 17048c2ecf20Sopenharmony_ci } 17058c2ecf20Sopenharmony_ci if (mig) { 17068c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 17078c2ecf20Sopenharmony_ci ev.element.qp = &qp->ibqp; 17088c2ecf20Sopenharmony_ci ev.event = IB_EVENT_PATH_MIG; 17098c2ecf20Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci return 0; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ciinval: 17148c2ecf20Sopenharmony_ci spin_unlock(&qp->s_lock); 17158c2ecf20Sopenharmony_ci spin_unlock(&qp->s_hlock); 17168c2ecf20Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 17178c2ecf20Sopenharmony_ci return -EINVAL; 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci/** 17218c2ecf20Sopenharmony_ci * rvt_destroy_qp - destroy a queue pair 17228c2ecf20Sopenharmony_ci * @ibqp: the queue pair to destroy 17238c2ecf20Sopenharmony_ci * 17248c2ecf20Sopenharmony_ci * Note that this can be called while the QP is actively sending or 17258c2ecf20Sopenharmony_ci * receiving! 17268c2ecf20Sopenharmony_ci * 17278c2ecf20Sopenharmony_ci * Return: 0 on success. 17288c2ecf20Sopenharmony_ci */ 17298c2ecf20Sopenharmony_ciint rvt_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 17328c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci rvt_reset_qp(rdi, qp, ibqp->qp_type); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci wait_event(qp->wait, !atomic_read(&qp->refcount)); 17378c2ecf20Sopenharmony_ci /* qpn is now available for use again */ 17388c2ecf20Sopenharmony_ci rvt_free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num); 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci spin_lock(&rdi->n_qps_lock); 17418c2ecf20Sopenharmony_ci rdi->n_qps_allocated--; 17428c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RC) { 17438c2ecf20Sopenharmony_ci rdi->n_rc_qps--; 17448c2ecf20Sopenharmony_ci rdi->busy_jiffies = rdi->n_rc_qps / RC_QP_SCALING_INTERVAL; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci spin_unlock(&rdi->n_qps_lock); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (qp->ip) 17498c2ecf20Sopenharmony_ci kref_put(&qp->ip->ref, rvt_release_mmap_info); 17508c2ecf20Sopenharmony_ci kvfree(qp->r_rq.kwq); 17518c2ecf20Sopenharmony_ci rdi->driver_f.qp_priv_free(rdi, qp); 17528c2ecf20Sopenharmony_ci kfree(qp->s_ack_queue); 17538c2ecf20Sopenharmony_ci rdma_destroy_ah_attr(&qp->remote_ah_attr); 17548c2ecf20Sopenharmony_ci rdma_destroy_ah_attr(&qp->alt_ah_attr); 17558c2ecf20Sopenharmony_ci free_ud_wq_attr(qp); 17568c2ecf20Sopenharmony_ci vfree(qp->s_wq); 17578c2ecf20Sopenharmony_ci kfree(qp); 17588c2ecf20Sopenharmony_ci return 0; 17598c2ecf20Sopenharmony_ci} 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci/** 17628c2ecf20Sopenharmony_ci * rvt_query_qp - query an ipbq 17638c2ecf20Sopenharmony_ci * @ibqp: IB qp to query 17648c2ecf20Sopenharmony_ci * @attr: attr struct to fill in 17658c2ecf20Sopenharmony_ci * @attr_mask: attr mask ignored 17668c2ecf20Sopenharmony_ci * @init_attr: struct to fill in 17678c2ecf20Sopenharmony_ci * 17688c2ecf20Sopenharmony_ci * Return: always 0 17698c2ecf20Sopenharmony_ci */ 17708c2ecf20Sopenharmony_ciint rvt_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 17718c2ecf20Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *init_attr) 17728c2ecf20Sopenharmony_ci{ 17738c2ecf20Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 17748c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci attr->qp_state = qp->state; 17778c2ecf20Sopenharmony_ci attr->cur_qp_state = attr->qp_state; 17788c2ecf20Sopenharmony_ci attr->path_mtu = rdi->driver_f.mtu_to_path_mtu(qp->pmtu); 17798c2ecf20Sopenharmony_ci attr->path_mig_state = qp->s_mig_state; 17808c2ecf20Sopenharmony_ci attr->qkey = qp->qkey; 17818c2ecf20Sopenharmony_ci attr->rq_psn = qp->r_psn & rdi->dparms.psn_mask; 17828c2ecf20Sopenharmony_ci attr->sq_psn = qp->s_next_psn & rdi->dparms.psn_mask; 17838c2ecf20Sopenharmony_ci attr->dest_qp_num = qp->remote_qpn; 17848c2ecf20Sopenharmony_ci attr->qp_access_flags = qp->qp_access_flags; 17858c2ecf20Sopenharmony_ci attr->cap.max_send_wr = qp->s_size - 1 - 17868c2ecf20Sopenharmony_ci rdi->dparms.reserved_operations; 17878c2ecf20Sopenharmony_ci attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1; 17888c2ecf20Sopenharmony_ci attr->cap.max_send_sge = qp->s_max_sge; 17898c2ecf20Sopenharmony_ci attr->cap.max_recv_sge = qp->r_rq.max_sge; 17908c2ecf20Sopenharmony_ci attr->cap.max_inline_data = 0; 17918c2ecf20Sopenharmony_ci attr->ah_attr = qp->remote_ah_attr; 17928c2ecf20Sopenharmony_ci attr->alt_ah_attr = qp->alt_ah_attr; 17938c2ecf20Sopenharmony_ci attr->pkey_index = qp->s_pkey_index; 17948c2ecf20Sopenharmony_ci attr->alt_pkey_index = qp->s_alt_pkey_index; 17958c2ecf20Sopenharmony_ci attr->en_sqd_async_notify = 0; 17968c2ecf20Sopenharmony_ci attr->sq_draining = qp->s_draining; 17978c2ecf20Sopenharmony_ci attr->max_rd_atomic = qp->s_max_rd_atomic; 17988c2ecf20Sopenharmony_ci attr->max_dest_rd_atomic = qp->r_max_rd_atomic; 17998c2ecf20Sopenharmony_ci attr->min_rnr_timer = qp->r_min_rnr_timer; 18008c2ecf20Sopenharmony_ci attr->port_num = qp->port_num; 18018c2ecf20Sopenharmony_ci attr->timeout = qp->timeout; 18028c2ecf20Sopenharmony_ci attr->retry_cnt = qp->s_retry_cnt; 18038c2ecf20Sopenharmony_ci attr->rnr_retry = qp->s_rnr_retry_cnt; 18048c2ecf20Sopenharmony_ci attr->alt_port_num = 18058c2ecf20Sopenharmony_ci rdma_ah_get_port_num(&qp->alt_ah_attr); 18068c2ecf20Sopenharmony_ci attr->alt_timeout = qp->alt_timeout; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci init_attr->event_handler = qp->ibqp.event_handler; 18098c2ecf20Sopenharmony_ci init_attr->qp_context = qp->ibqp.qp_context; 18108c2ecf20Sopenharmony_ci init_attr->send_cq = qp->ibqp.send_cq; 18118c2ecf20Sopenharmony_ci init_attr->recv_cq = qp->ibqp.recv_cq; 18128c2ecf20Sopenharmony_ci init_attr->srq = qp->ibqp.srq; 18138c2ecf20Sopenharmony_ci init_attr->cap = attr->cap; 18148c2ecf20Sopenharmony_ci if (qp->s_flags & RVT_S_SIGNAL_REQ_WR) 18158c2ecf20Sopenharmony_ci init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; 18168c2ecf20Sopenharmony_ci else 18178c2ecf20Sopenharmony_ci init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; 18188c2ecf20Sopenharmony_ci init_attr->qp_type = qp->ibqp.qp_type; 18198c2ecf20Sopenharmony_ci init_attr->port_num = qp->port_num; 18208c2ecf20Sopenharmony_ci return 0; 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci/** 18248c2ecf20Sopenharmony_ci * rvt_post_receive - post a receive on a QP 18258c2ecf20Sopenharmony_ci * @ibqp: the QP to post the receive on 18268c2ecf20Sopenharmony_ci * @wr: the WR to post 18278c2ecf20Sopenharmony_ci * @bad_wr: the first bad WR is put here 18288c2ecf20Sopenharmony_ci * 18298c2ecf20Sopenharmony_ci * This may be called from interrupt context. 18308c2ecf20Sopenharmony_ci * 18318c2ecf20Sopenharmony_ci * Return: 0 on success otherwise errno 18328c2ecf20Sopenharmony_ci */ 18338c2ecf20Sopenharmony_ciint rvt_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 18348c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 18378c2ecf20Sopenharmony_ci struct rvt_krwq *wq = qp->r_rq.kwq; 18388c2ecf20Sopenharmony_ci unsigned long flags; 18398c2ecf20Sopenharmony_ci int qp_err_flush = (ib_rvt_state_ops[qp->state] & RVT_FLUSH_RECV) && 18408c2ecf20Sopenharmony_ci !qp->ibqp.srq; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* Check that state is OK to post receive. */ 18438c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_POST_RECV_OK) || !wq) { 18448c2ecf20Sopenharmony_ci *bad_wr = wr; 18458c2ecf20Sopenharmony_ci return -EINVAL; 18468c2ecf20Sopenharmony_ci } 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci for (; wr; wr = wr->next) { 18498c2ecf20Sopenharmony_ci struct rvt_rwqe *wqe; 18508c2ecf20Sopenharmony_ci u32 next; 18518c2ecf20Sopenharmony_ci int i; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci if ((unsigned)wr->num_sge > qp->r_rq.max_sge) { 18548c2ecf20Sopenharmony_ci *bad_wr = wr; 18558c2ecf20Sopenharmony_ci return -EINVAL; 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->r_rq.kwq->p_lock, flags); 18598c2ecf20Sopenharmony_ci next = wq->head + 1; 18608c2ecf20Sopenharmony_ci if (next >= qp->r_rq.size) 18618c2ecf20Sopenharmony_ci next = 0; 18628c2ecf20Sopenharmony_ci if (next == READ_ONCE(wq->tail)) { 18638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_rq.kwq->p_lock, flags); 18648c2ecf20Sopenharmony_ci *bad_wr = wr; 18658c2ecf20Sopenharmony_ci return -ENOMEM; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci if (unlikely(qp_err_flush)) { 18688c2ecf20Sopenharmony_ci struct ib_wc wc; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 18718c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 18728c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 18738c2ecf20Sopenharmony_ci wc.wr_id = wr->wr_id; 18748c2ecf20Sopenharmony_ci wc.status = IB_WC_WR_FLUSH_ERR; 18758c2ecf20Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 18768c2ecf20Sopenharmony_ci } else { 18778c2ecf20Sopenharmony_ci wqe = rvt_get_rwqe_ptr(&qp->r_rq, wq->head); 18788c2ecf20Sopenharmony_ci wqe->wr_id = wr->wr_id; 18798c2ecf20Sopenharmony_ci wqe->num_sge = wr->num_sge; 18808c2ecf20Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 18818c2ecf20Sopenharmony_ci wqe->sg_list[i].addr = wr->sg_list[i].addr; 18828c2ecf20Sopenharmony_ci wqe->sg_list[i].length = wr->sg_list[i].length; 18838c2ecf20Sopenharmony_ci wqe->sg_list[i].lkey = wr->sg_list[i].lkey; 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci /* 18868c2ecf20Sopenharmony_ci * Make sure queue entry is written 18878c2ecf20Sopenharmony_ci * before the head index. 18888c2ecf20Sopenharmony_ci */ 18898c2ecf20Sopenharmony_ci smp_store_release(&wq->head, next); 18908c2ecf20Sopenharmony_ci } 18918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_rq.kwq->p_lock, flags); 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci return 0; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci/** 18978c2ecf20Sopenharmony_ci * rvt_qp_valid_operation - validate post send wr request 18988c2ecf20Sopenharmony_ci * @qp - the qp 18998c2ecf20Sopenharmony_ci * @post-parms - the post send table for the driver 19008c2ecf20Sopenharmony_ci * @wr - the work request 19018c2ecf20Sopenharmony_ci * 19028c2ecf20Sopenharmony_ci * The routine validates the operation based on the 19038c2ecf20Sopenharmony_ci * validation table an returns the length of the operation 19048c2ecf20Sopenharmony_ci * which can extend beyond the ib_send_bw. Operation 19058c2ecf20Sopenharmony_ci * dependent flags key atomic operation validation. 19068c2ecf20Sopenharmony_ci * 19078c2ecf20Sopenharmony_ci * There is an exception for UD qps that validates the pd and 19088c2ecf20Sopenharmony_ci * overrides the length to include the additional UD specific 19098c2ecf20Sopenharmony_ci * length. 19108c2ecf20Sopenharmony_ci * 19118c2ecf20Sopenharmony_ci * Returns a negative error or the length of the work request 19128c2ecf20Sopenharmony_ci * for building the swqe. 19138c2ecf20Sopenharmony_ci */ 19148c2ecf20Sopenharmony_cistatic inline int rvt_qp_valid_operation( 19158c2ecf20Sopenharmony_ci struct rvt_qp *qp, 19168c2ecf20Sopenharmony_ci const struct rvt_operation_params *post_parms, 19178c2ecf20Sopenharmony_ci const struct ib_send_wr *wr) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci int len; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (wr->opcode >= RVT_OPERATION_MAX || !post_parms[wr->opcode].length) 19228c2ecf20Sopenharmony_ci return -EINVAL; 19238c2ecf20Sopenharmony_ci if (!(post_parms[wr->opcode].qpt_support & BIT(qp->ibqp.qp_type))) 19248c2ecf20Sopenharmony_ci return -EINVAL; 19258c2ecf20Sopenharmony_ci if ((post_parms[wr->opcode].flags & RVT_OPERATION_PRIV) && 19268c2ecf20Sopenharmony_ci ibpd_to_rvtpd(qp->ibqp.pd)->user) 19278c2ecf20Sopenharmony_ci return -EINVAL; 19288c2ecf20Sopenharmony_ci if (post_parms[wr->opcode].flags & RVT_OPERATION_ATOMIC_SGE && 19298c2ecf20Sopenharmony_ci (wr->num_sge == 0 || 19308c2ecf20Sopenharmony_ci wr->sg_list[0].length < sizeof(u64) || 19318c2ecf20Sopenharmony_ci wr->sg_list[0].addr & (sizeof(u64) - 1))) 19328c2ecf20Sopenharmony_ci return -EINVAL; 19338c2ecf20Sopenharmony_ci if (post_parms[wr->opcode].flags & RVT_OPERATION_ATOMIC && 19348c2ecf20Sopenharmony_ci !qp->s_max_rd_atomic) 19358c2ecf20Sopenharmony_ci return -EINVAL; 19368c2ecf20Sopenharmony_ci len = post_parms[wr->opcode].length; 19378c2ecf20Sopenharmony_ci /* UD specific */ 19388c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type != IB_QPT_UC && 19398c2ecf20Sopenharmony_ci qp->ibqp.qp_type != IB_QPT_RC) { 19408c2ecf20Sopenharmony_ci if (qp->ibqp.pd != ud_wr(wr)->ah->pd) 19418c2ecf20Sopenharmony_ci return -EINVAL; 19428c2ecf20Sopenharmony_ci len = sizeof(struct ib_ud_wr); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci return len; 19458c2ecf20Sopenharmony_ci} 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci/** 19488c2ecf20Sopenharmony_ci * rvt_qp_is_avail - determine queue capacity 19498c2ecf20Sopenharmony_ci * @qp: the qp 19508c2ecf20Sopenharmony_ci * @rdi: the rdmavt device 19518c2ecf20Sopenharmony_ci * @reserved_op: is reserved operation 19528c2ecf20Sopenharmony_ci * 19538c2ecf20Sopenharmony_ci * This assumes the s_hlock is held but the s_last 19548c2ecf20Sopenharmony_ci * qp variable is uncontrolled. 19558c2ecf20Sopenharmony_ci * 19568c2ecf20Sopenharmony_ci * For non reserved operations, the qp->s_avail 19578c2ecf20Sopenharmony_ci * may be changed. 19588c2ecf20Sopenharmony_ci * 19598c2ecf20Sopenharmony_ci * The return value is zero or a -ENOMEM. 19608c2ecf20Sopenharmony_ci */ 19618c2ecf20Sopenharmony_cistatic inline int rvt_qp_is_avail( 19628c2ecf20Sopenharmony_ci struct rvt_qp *qp, 19638c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi, 19648c2ecf20Sopenharmony_ci bool reserved_op) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci u32 slast; 19678c2ecf20Sopenharmony_ci u32 avail; 19688c2ecf20Sopenharmony_ci u32 reserved_used; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci /* see rvt_qp_wqe_unreserve() */ 19718c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 19728c2ecf20Sopenharmony_ci if (unlikely(reserved_op)) { 19738c2ecf20Sopenharmony_ci /* see rvt_qp_wqe_unreserve() */ 19748c2ecf20Sopenharmony_ci reserved_used = atomic_read(&qp->s_reserved_used); 19758c2ecf20Sopenharmony_ci if (reserved_used >= rdi->dparms.reserved_operations) 19768c2ecf20Sopenharmony_ci return -ENOMEM; 19778c2ecf20Sopenharmony_ci return 0; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci /* non-reserved operations */ 19808c2ecf20Sopenharmony_ci if (likely(qp->s_avail)) 19818c2ecf20Sopenharmony_ci return 0; 19828c2ecf20Sopenharmony_ci /* See rvt_qp_complete_swqe() */ 19838c2ecf20Sopenharmony_ci slast = smp_load_acquire(&qp->s_last); 19848c2ecf20Sopenharmony_ci if (qp->s_head >= slast) 19858c2ecf20Sopenharmony_ci avail = qp->s_size - (qp->s_head - slast); 19868c2ecf20Sopenharmony_ci else 19878c2ecf20Sopenharmony_ci avail = slast - qp->s_head; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci reserved_used = atomic_read(&qp->s_reserved_used); 19908c2ecf20Sopenharmony_ci avail = avail - 1 - 19918c2ecf20Sopenharmony_ci (rdi->dparms.reserved_operations - reserved_used); 19928c2ecf20Sopenharmony_ci /* insure we don't assign a negative s_avail */ 19938c2ecf20Sopenharmony_ci if ((s32)avail <= 0) 19948c2ecf20Sopenharmony_ci return -ENOMEM; 19958c2ecf20Sopenharmony_ci qp->s_avail = avail; 19968c2ecf20Sopenharmony_ci if (WARN_ON(qp->s_avail > 19978c2ecf20Sopenharmony_ci (qp->s_size - 1 - rdi->dparms.reserved_operations))) 19988c2ecf20Sopenharmony_ci rvt_pr_err(rdi, 19998c2ecf20Sopenharmony_ci "More avail entries than QP RB size.\nQP: %u, size: %u, avail: %u\nhead: %u, tail: %u, cur: %u, acked: %u, last: %u", 20008c2ecf20Sopenharmony_ci qp->ibqp.qp_num, qp->s_size, qp->s_avail, 20018c2ecf20Sopenharmony_ci qp->s_head, qp->s_tail, qp->s_cur, 20028c2ecf20Sopenharmony_ci qp->s_acked, qp->s_last); 20038c2ecf20Sopenharmony_ci return 0; 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci/** 20078c2ecf20Sopenharmony_ci * rvt_post_one_wr - post one RC, UC, or UD send work request 20088c2ecf20Sopenharmony_ci * @qp: the QP to post on 20098c2ecf20Sopenharmony_ci * @wr: the work request to send 20108c2ecf20Sopenharmony_ci */ 20118c2ecf20Sopenharmony_cistatic int rvt_post_one_wr(struct rvt_qp *qp, 20128c2ecf20Sopenharmony_ci const struct ib_send_wr *wr, 20138c2ecf20Sopenharmony_ci bool *call_send) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct rvt_swqe *wqe; 20168c2ecf20Sopenharmony_ci u32 next; 20178c2ecf20Sopenharmony_ci int i; 20188c2ecf20Sopenharmony_ci int j; 20198c2ecf20Sopenharmony_ci int acc; 20208c2ecf20Sopenharmony_ci struct rvt_lkey_table *rkt; 20218c2ecf20Sopenharmony_ci struct rvt_pd *pd; 20228c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 20238c2ecf20Sopenharmony_ci u8 log_pmtu; 20248c2ecf20Sopenharmony_ci int ret; 20258c2ecf20Sopenharmony_ci size_t cplen; 20268c2ecf20Sopenharmony_ci bool reserved_op; 20278c2ecf20Sopenharmony_ci int local_ops_delayed = 0; 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci BUILD_BUG_ON(IB_QPT_MAX >= (sizeof(u32) * BITS_PER_BYTE)); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci /* IB spec says that num_sge == 0 is OK. */ 20328c2ecf20Sopenharmony_ci if (unlikely(wr->num_sge > qp->s_max_sge)) 20338c2ecf20Sopenharmony_ci return -EINVAL; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci ret = rvt_qp_valid_operation(qp, rdi->post_parms, wr); 20368c2ecf20Sopenharmony_ci if (ret < 0) 20378c2ecf20Sopenharmony_ci return ret; 20388c2ecf20Sopenharmony_ci cplen = ret; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci /* 20418c2ecf20Sopenharmony_ci * Local operations include fast register and local invalidate. 20428c2ecf20Sopenharmony_ci * Fast register needs to be processed immediately because the 20438c2ecf20Sopenharmony_ci * registered lkey may be used by following work requests and the 20448c2ecf20Sopenharmony_ci * lkey needs to be valid at the time those requests are posted. 20458c2ecf20Sopenharmony_ci * Local invalidate can be processed immediately if fencing is 20468c2ecf20Sopenharmony_ci * not required and no previous local invalidate ops are pending. 20478c2ecf20Sopenharmony_ci * Signaled local operations that have been processed immediately 20488c2ecf20Sopenharmony_ci * need to have requests with "completion only" flags set posted 20498c2ecf20Sopenharmony_ci * to the send queue in order to generate completions. 20508c2ecf20Sopenharmony_ci */ 20518c2ecf20Sopenharmony_ci if ((rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL)) { 20528c2ecf20Sopenharmony_ci switch (wr->opcode) { 20538c2ecf20Sopenharmony_ci case IB_WR_REG_MR: 20548c2ecf20Sopenharmony_ci ret = rvt_fast_reg_mr(qp, 20558c2ecf20Sopenharmony_ci reg_wr(wr)->mr, 20568c2ecf20Sopenharmony_ci reg_wr(wr)->key, 20578c2ecf20Sopenharmony_ci reg_wr(wr)->access); 20588c2ecf20Sopenharmony_ci if (ret || !(wr->send_flags & IB_SEND_SIGNALED)) 20598c2ecf20Sopenharmony_ci return ret; 20608c2ecf20Sopenharmony_ci break; 20618c2ecf20Sopenharmony_ci case IB_WR_LOCAL_INV: 20628c2ecf20Sopenharmony_ci if ((wr->send_flags & IB_SEND_FENCE) || 20638c2ecf20Sopenharmony_ci atomic_read(&qp->local_ops_pending)) { 20648c2ecf20Sopenharmony_ci local_ops_delayed = 1; 20658c2ecf20Sopenharmony_ci } else { 20668c2ecf20Sopenharmony_ci ret = rvt_invalidate_rkey( 20678c2ecf20Sopenharmony_ci qp, wr->ex.invalidate_rkey); 20688c2ecf20Sopenharmony_ci if (ret || !(wr->send_flags & IB_SEND_SIGNALED)) 20698c2ecf20Sopenharmony_ci return ret; 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci break; 20728c2ecf20Sopenharmony_ci default: 20738c2ecf20Sopenharmony_ci return -EINVAL; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci reserved_op = rdi->post_parms[wr->opcode].flags & 20788c2ecf20Sopenharmony_ci RVT_OPERATION_USE_RESERVE; 20798c2ecf20Sopenharmony_ci /* check for avail */ 20808c2ecf20Sopenharmony_ci ret = rvt_qp_is_avail(qp, rdi, reserved_op); 20818c2ecf20Sopenharmony_ci if (ret) 20828c2ecf20Sopenharmony_ci return ret; 20838c2ecf20Sopenharmony_ci next = qp->s_head + 1; 20848c2ecf20Sopenharmony_ci if (next >= qp->s_size) 20858c2ecf20Sopenharmony_ci next = 0; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci rkt = &rdi->lkey_table; 20888c2ecf20Sopenharmony_ci pd = ibpd_to_rvtpd(qp->ibqp.pd); 20898c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_head); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci /* cplen has length from above */ 20928c2ecf20Sopenharmony_ci memcpy(&wqe->wr, wr, cplen); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci wqe->length = 0; 20958c2ecf20Sopenharmony_ci j = 0; 20968c2ecf20Sopenharmony_ci if (wr->num_sge) { 20978c2ecf20Sopenharmony_ci struct rvt_sge *last_sge = NULL; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci acc = wr->opcode >= IB_WR_RDMA_READ ? 21008c2ecf20Sopenharmony_ci IB_ACCESS_LOCAL_WRITE : 0; 21018c2ecf20Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 21028c2ecf20Sopenharmony_ci u32 length = wr->sg_list[i].length; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci if (length == 0) 21058c2ecf20Sopenharmony_ci continue; 21068c2ecf20Sopenharmony_ci ret = rvt_lkey_ok(rkt, pd, &wqe->sg_list[j], last_sge, 21078c2ecf20Sopenharmony_ci &wr->sg_list[i], acc); 21088c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 21098c2ecf20Sopenharmony_ci goto bail_inval_free; 21108c2ecf20Sopenharmony_ci wqe->length += length; 21118c2ecf20Sopenharmony_ci if (ret) 21128c2ecf20Sopenharmony_ci last_sge = &wqe->sg_list[j]; 21138c2ecf20Sopenharmony_ci j += ret; 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci wqe->wr.num_sge = j; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci /* 21198c2ecf20Sopenharmony_ci * Calculate and set SWQE PSN values prior to handing it off 21208c2ecf20Sopenharmony_ci * to the driver's check routine. This give the driver the 21218c2ecf20Sopenharmony_ci * opportunity to adjust PSN values based on internal checks. 21228c2ecf20Sopenharmony_ci */ 21238c2ecf20Sopenharmony_ci log_pmtu = qp->log_pmtu; 21248c2ecf20Sopenharmony_ci if (qp->allowed_ops == IB_OPCODE_UD) { 21258c2ecf20Sopenharmony_ci struct rvt_ah *ah = rvt_get_swqe_ah(wqe); 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci log_pmtu = ah->log_pmtu; 21288c2ecf20Sopenharmony_ci rdma_copy_ah_attr(wqe->ud_wr.attr, &ah->attr); 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci if (rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL) { 21328c2ecf20Sopenharmony_ci if (local_ops_delayed) 21338c2ecf20Sopenharmony_ci atomic_inc(&qp->local_ops_pending); 21348c2ecf20Sopenharmony_ci else 21358c2ecf20Sopenharmony_ci wqe->wr.send_flags |= RVT_SEND_COMPLETION_ONLY; 21368c2ecf20Sopenharmony_ci wqe->ssn = 0; 21378c2ecf20Sopenharmony_ci wqe->psn = 0; 21388c2ecf20Sopenharmony_ci wqe->lpsn = 0; 21398c2ecf20Sopenharmony_ci } else { 21408c2ecf20Sopenharmony_ci wqe->ssn = qp->s_ssn++; 21418c2ecf20Sopenharmony_ci wqe->psn = qp->s_next_psn; 21428c2ecf20Sopenharmony_ci wqe->lpsn = wqe->psn + 21438c2ecf20Sopenharmony_ci (wqe->length ? 21448c2ecf20Sopenharmony_ci ((wqe->length - 1) >> log_pmtu) : 21458c2ecf20Sopenharmony_ci 0); 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci /* general part of wqe valid - allow for driver checks */ 21498c2ecf20Sopenharmony_ci if (rdi->driver_f.setup_wqe) { 21508c2ecf20Sopenharmony_ci ret = rdi->driver_f.setup_wqe(qp, wqe, call_send); 21518c2ecf20Sopenharmony_ci if (ret < 0) 21528c2ecf20Sopenharmony_ci goto bail_inval_free_ref; 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (!(rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL)) 21568c2ecf20Sopenharmony_ci qp->s_next_psn = wqe->lpsn + 1; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci if (unlikely(reserved_op)) { 21598c2ecf20Sopenharmony_ci wqe->wr.send_flags |= RVT_SEND_RESERVE_USED; 21608c2ecf20Sopenharmony_ci rvt_qp_wqe_reserve(qp, wqe); 21618c2ecf20Sopenharmony_ci } else { 21628c2ecf20Sopenharmony_ci wqe->wr.send_flags &= ~RVT_SEND_RESERVE_USED; 21638c2ecf20Sopenharmony_ci qp->s_avail--; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci trace_rvt_post_one_wr(qp, wqe, wr->num_sge); 21668c2ecf20Sopenharmony_ci smp_wmb(); /* see request builders */ 21678c2ecf20Sopenharmony_ci qp->s_head = next; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci return 0; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_cibail_inval_free_ref: 21728c2ecf20Sopenharmony_ci if (qp->allowed_ops == IB_OPCODE_UD) 21738c2ecf20Sopenharmony_ci rdma_destroy_ah_attr(wqe->ud_wr.attr); 21748c2ecf20Sopenharmony_cibail_inval_free: 21758c2ecf20Sopenharmony_ci /* release mr holds */ 21768c2ecf20Sopenharmony_ci while (j) { 21778c2ecf20Sopenharmony_ci struct rvt_sge *sge = &wqe->sg_list[--j]; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci rvt_put_mr(sge->mr); 21808c2ecf20Sopenharmony_ci } 21818c2ecf20Sopenharmony_ci return ret; 21828c2ecf20Sopenharmony_ci} 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci/** 21858c2ecf20Sopenharmony_ci * rvt_post_send - post a send on a QP 21868c2ecf20Sopenharmony_ci * @ibqp: the QP to post the send on 21878c2ecf20Sopenharmony_ci * @wr: the list of work requests to post 21888c2ecf20Sopenharmony_ci * @bad_wr: the first bad WR is put here 21898c2ecf20Sopenharmony_ci * 21908c2ecf20Sopenharmony_ci * This may be called from interrupt context. 21918c2ecf20Sopenharmony_ci * 21928c2ecf20Sopenharmony_ci * Return: 0 on success else errno 21938c2ecf20Sopenharmony_ci */ 21948c2ecf20Sopenharmony_ciint rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 21958c2ecf20Sopenharmony_ci const struct ib_send_wr **bad_wr) 21968c2ecf20Sopenharmony_ci{ 21978c2ecf20Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 21988c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 21998c2ecf20Sopenharmony_ci unsigned long flags = 0; 22008c2ecf20Sopenharmony_ci bool call_send; 22018c2ecf20Sopenharmony_ci unsigned nreq = 0; 22028c2ecf20Sopenharmony_ci int err = 0; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->s_hlock, flags); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci /* 22078c2ecf20Sopenharmony_ci * Ensure QP state is such that we can send. If not bail out early, 22088c2ecf20Sopenharmony_ci * there is no need to do this every time we post a send. 22098c2ecf20Sopenharmony_ci */ 22108c2ecf20Sopenharmony_ci if (unlikely(!(ib_rvt_state_ops[qp->state] & RVT_POST_SEND_OK))) { 22118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->s_hlock, flags); 22128c2ecf20Sopenharmony_ci return -EINVAL; 22138c2ecf20Sopenharmony_ci } 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci /* 22168c2ecf20Sopenharmony_ci * If the send queue is empty, and we only have a single WR then just go 22178c2ecf20Sopenharmony_ci * ahead and kick the send engine into gear. Otherwise we will always 22188c2ecf20Sopenharmony_ci * just schedule the send to happen later. 22198c2ecf20Sopenharmony_ci */ 22208c2ecf20Sopenharmony_ci call_send = qp->s_head == READ_ONCE(qp->s_last) && !wr->next; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci for (; wr; wr = wr->next) { 22238c2ecf20Sopenharmony_ci err = rvt_post_one_wr(qp, wr, &call_send); 22248c2ecf20Sopenharmony_ci if (unlikely(err)) { 22258c2ecf20Sopenharmony_ci *bad_wr = wr; 22268c2ecf20Sopenharmony_ci goto bail; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci nreq++; 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_cibail: 22318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->s_hlock, flags); 22328c2ecf20Sopenharmony_ci if (nreq) { 22338c2ecf20Sopenharmony_ci /* 22348c2ecf20Sopenharmony_ci * Only call do_send if there is exactly one packet, and the 22358c2ecf20Sopenharmony_ci * driver said it was ok. 22368c2ecf20Sopenharmony_ci */ 22378c2ecf20Sopenharmony_ci if (nreq == 1 && call_send) 22388c2ecf20Sopenharmony_ci rdi->driver_f.do_send(qp); 22398c2ecf20Sopenharmony_ci else 22408c2ecf20Sopenharmony_ci rdi->driver_f.schedule_send_no_lock(qp); 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci return err; 22438c2ecf20Sopenharmony_ci} 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci/** 22468c2ecf20Sopenharmony_ci * rvt_post_srq_receive - post a receive on a shared receive queue 22478c2ecf20Sopenharmony_ci * @ibsrq: the SRQ to post the receive on 22488c2ecf20Sopenharmony_ci * @wr: the list of work requests to post 22498c2ecf20Sopenharmony_ci * @bad_wr: A pointer to the first WR to cause a problem is put here 22508c2ecf20Sopenharmony_ci * 22518c2ecf20Sopenharmony_ci * This may be called from interrupt context. 22528c2ecf20Sopenharmony_ci * 22538c2ecf20Sopenharmony_ci * Return: 0 on success else errno 22548c2ecf20Sopenharmony_ci */ 22558c2ecf20Sopenharmony_ciint rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 22568c2ecf20Sopenharmony_ci const struct ib_recv_wr **bad_wr) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci struct rvt_srq *srq = ibsrq_to_rvtsrq(ibsrq); 22598c2ecf20Sopenharmony_ci struct rvt_krwq *wq; 22608c2ecf20Sopenharmony_ci unsigned long flags; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci for (; wr; wr = wr->next) { 22638c2ecf20Sopenharmony_ci struct rvt_rwqe *wqe; 22648c2ecf20Sopenharmony_ci u32 next; 22658c2ecf20Sopenharmony_ci int i; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if ((unsigned)wr->num_sge > srq->rq.max_sge) { 22688c2ecf20Sopenharmony_ci *bad_wr = wr; 22698c2ecf20Sopenharmony_ci return -EINVAL; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci spin_lock_irqsave(&srq->rq.kwq->p_lock, flags); 22738c2ecf20Sopenharmony_ci wq = srq->rq.kwq; 22748c2ecf20Sopenharmony_ci next = wq->head + 1; 22758c2ecf20Sopenharmony_ci if (next >= srq->rq.size) 22768c2ecf20Sopenharmony_ci next = 0; 22778c2ecf20Sopenharmony_ci if (next == READ_ONCE(wq->tail)) { 22788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.kwq->p_lock, flags); 22798c2ecf20Sopenharmony_ci *bad_wr = wr; 22808c2ecf20Sopenharmony_ci return -ENOMEM; 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci wqe = rvt_get_rwqe_ptr(&srq->rq, wq->head); 22848c2ecf20Sopenharmony_ci wqe->wr_id = wr->wr_id; 22858c2ecf20Sopenharmony_ci wqe->num_sge = wr->num_sge; 22868c2ecf20Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 22878c2ecf20Sopenharmony_ci wqe->sg_list[i].addr = wr->sg_list[i].addr; 22888c2ecf20Sopenharmony_ci wqe->sg_list[i].length = wr->sg_list[i].length; 22898c2ecf20Sopenharmony_ci wqe->sg_list[i].lkey = wr->sg_list[i].lkey; 22908c2ecf20Sopenharmony_ci } 22918c2ecf20Sopenharmony_ci /* Make sure queue entry is written before the head index. */ 22928c2ecf20Sopenharmony_ci smp_store_release(&wq->head, next); 22938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.kwq->p_lock, flags); 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci return 0; 22968c2ecf20Sopenharmony_ci} 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci/* 22998c2ecf20Sopenharmony_ci * rvt used the internal kernel struct as part of its ABI, for now make sure 23008c2ecf20Sopenharmony_ci * the kernel struct does not change layout. FIXME: rvt should never cast the 23018c2ecf20Sopenharmony_ci * user struct to a kernel struct. 23028c2ecf20Sopenharmony_ci */ 23038c2ecf20Sopenharmony_cistatic struct ib_sge *rvt_cast_sge(struct rvt_wqe_sge *sge) 23048c2ecf20Sopenharmony_ci{ 23058c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ib_sge, addr) != 23068c2ecf20Sopenharmony_ci offsetof(struct rvt_wqe_sge, addr)); 23078c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ib_sge, length) != 23088c2ecf20Sopenharmony_ci offsetof(struct rvt_wqe_sge, length)); 23098c2ecf20Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ib_sge, lkey) != 23108c2ecf20Sopenharmony_ci offsetof(struct rvt_wqe_sge, lkey)); 23118c2ecf20Sopenharmony_ci return (struct ib_sge *)sge; 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci/* 23158c2ecf20Sopenharmony_ci * Validate a RWQE and fill in the SGE state. 23168c2ecf20Sopenharmony_ci * Return 1 if OK. 23178c2ecf20Sopenharmony_ci */ 23188c2ecf20Sopenharmony_cistatic int init_sge(struct rvt_qp *qp, struct rvt_rwqe *wqe) 23198c2ecf20Sopenharmony_ci{ 23208c2ecf20Sopenharmony_ci int i, j, ret; 23218c2ecf20Sopenharmony_ci struct ib_wc wc; 23228c2ecf20Sopenharmony_ci struct rvt_lkey_table *rkt; 23238c2ecf20Sopenharmony_ci struct rvt_pd *pd; 23248c2ecf20Sopenharmony_ci struct rvt_sge_state *ss; 23258c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci rkt = &rdi->lkey_table; 23288c2ecf20Sopenharmony_ci pd = ibpd_to_rvtpd(qp->ibqp.srq ? qp->ibqp.srq->pd : qp->ibqp.pd); 23298c2ecf20Sopenharmony_ci ss = &qp->r_sge; 23308c2ecf20Sopenharmony_ci ss->sg_list = qp->r_sg_list; 23318c2ecf20Sopenharmony_ci qp->r_len = 0; 23328c2ecf20Sopenharmony_ci for (i = j = 0; i < wqe->num_sge; i++) { 23338c2ecf20Sopenharmony_ci if (wqe->sg_list[i].length == 0) 23348c2ecf20Sopenharmony_ci continue; 23358c2ecf20Sopenharmony_ci /* Check LKEY */ 23368c2ecf20Sopenharmony_ci ret = rvt_lkey_ok(rkt, pd, j ? &ss->sg_list[j - 1] : &ss->sge, 23378c2ecf20Sopenharmony_ci NULL, rvt_cast_sge(&wqe->sg_list[i]), 23388c2ecf20Sopenharmony_ci IB_ACCESS_LOCAL_WRITE); 23398c2ecf20Sopenharmony_ci if (unlikely(ret <= 0)) 23408c2ecf20Sopenharmony_ci goto bad_lkey; 23418c2ecf20Sopenharmony_ci qp->r_len += wqe->sg_list[i].length; 23428c2ecf20Sopenharmony_ci j++; 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci ss->num_sge = j; 23458c2ecf20Sopenharmony_ci ss->total_len = qp->r_len; 23468c2ecf20Sopenharmony_ci return 1; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_cibad_lkey: 23498c2ecf20Sopenharmony_ci while (j) { 23508c2ecf20Sopenharmony_ci struct rvt_sge *sge = --j ? &ss->sg_list[j - 1] : &ss->sge; 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci rvt_put_mr(sge->mr); 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci ss->num_sge = 0; 23558c2ecf20Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 23568c2ecf20Sopenharmony_ci wc.wr_id = wqe->wr_id; 23578c2ecf20Sopenharmony_ci wc.status = IB_WC_LOC_PROT_ERR; 23588c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 23598c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 23608c2ecf20Sopenharmony_ci /* Signal solicited completion event. */ 23618c2ecf20Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 23628c2ecf20Sopenharmony_ci return 0; 23638c2ecf20Sopenharmony_ci} 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci/** 23668c2ecf20Sopenharmony_ci * get_rvt_head - get head indices of the circular buffer 23678c2ecf20Sopenharmony_ci * @rq: data structure for request queue entry 23688c2ecf20Sopenharmony_ci * @ip: the QP 23698c2ecf20Sopenharmony_ci * 23708c2ecf20Sopenharmony_ci * Return - head index value 23718c2ecf20Sopenharmony_ci */ 23728c2ecf20Sopenharmony_cistatic inline u32 get_rvt_head(struct rvt_rq *rq, void *ip) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci u32 head; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci if (ip) 23778c2ecf20Sopenharmony_ci head = RDMA_READ_UAPI_ATOMIC(rq->wq->head); 23788c2ecf20Sopenharmony_ci else 23798c2ecf20Sopenharmony_ci head = rq->kwq->head; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci return head; 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci/** 23858c2ecf20Sopenharmony_ci * rvt_get_rwqe - copy the next RWQE into the QP's RWQE 23868c2ecf20Sopenharmony_ci * @qp: the QP 23878c2ecf20Sopenharmony_ci * @wr_id_only: update qp->r_wr_id only, not qp->r_sge 23888c2ecf20Sopenharmony_ci * 23898c2ecf20Sopenharmony_ci * Return -1 if there is a local error, 0 if no RWQE is available, 23908c2ecf20Sopenharmony_ci * otherwise return 1. 23918c2ecf20Sopenharmony_ci * 23928c2ecf20Sopenharmony_ci * Can be called from interrupt level. 23938c2ecf20Sopenharmony_ci */ 23948c2ecf20Sopenharmony_ciint rvt_get_rwqe(struct rvt_qp *qp, bool wr_id_only) 23958c2ecf20Sopenharmony_ci{ 23968c2ecf20Sopenharmony_ci unsigned long flags; 23978c2ecf20Sopenharmony_ci struct rvt_rq *rq; 23988c2ecf20Sopenharmony_ci struct rvt_krwq *kwq = NULL; 23998c2ecf20Sopenharmony_ci struct rvt_rwq *wq; 24008c2ecf20Sopenharmony_ci struct rvt_srq *srq; 24018c2ecf20Sopenharmony_ci struct rvt_rwqe *wqe; 24028c2ecf20Sopenharmony_ci void (*handler)(struct ib_event *, void *); 24038c2ecf20Sopenharmony_ci u32 tail; 24048c2ecf20Sopenharmony_ci u32 head; 24058c2ecf20Sopenharmony_ci int ret; 24068c2ecf20Sopenharmony_ci void *ip = NULL; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci if (qp->ibqp.srq) { 24098c2ecf20Sopenharmony_ci srq = ibsrq_to_rvtsrq(qp->ibqp.srq); 24108c2ecf20Sopenharmony_ci handler = srq->ibsrq.event_handler; 24118c2ecf20Sopenharmony_ci rq = &srq->rq; 24128c2ecf20Sopenharmony_ci ip = srq->ip; 24138c2ecf20Sopenharmony_ci } else { 24148c2ecf20Sopenharmony_ci srq = NULL; 24158c2ecf20Sopenharmony_ci handler = NULL; 24168c2ecf20Sopenharmony_ci rq = &qp->r_rq; 24178c2ecf20Sopenharmony_ci ip = qp->ip; 24188c2ecf20Sopenharmony_ci } 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci spin_lock_irqsave(&rq->kwq->c_lock, flags); 24218c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK)) { 24228c2ecf20Sopenharmony_ci ret = 0; 24238c2ecf20Sopenharmony_ci goto unlock; 24248c2ecf20Sopenharmony_ci } 24258c2ecf20Sopenharmony_ci kwq = rq->kwq; 24268c2ecf20Sopenharmony_ci if (ip) { 24278c2ecf20Sopenharmony_ci wq = rq->wq; 24288c2ecf20Sopenharmony_ci tail = RDMA_READ_UAPI_ATOMIC(wq->tail); 24298c2ecf20Sopenharmony_ci } else { 24308c2ecf20Sopenharmony_ci tail = kwq->tail; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci /* Validate tail before using it since it is user writable. */ 24348c2ecf20Sopenharmony_ci if (tail >= rq->size) 24358c2ecf20Sopenharmony_ci tail = 0; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci if (kwq->count < RVT_RWQ_COUNT_THRESHOLD) { 24388c2ecf20Sopenharmony_ci head = get_rvt_head(rq, ip); 24398c2ecf20Sopenharmony_ci kwq->count = rvt_get_rq_count(rq, head, tail); 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci if (unlikely(kwq->count == 0)) { 24428c2ecf20Sopenharmony_ci ret = 0; 24438c2ecf20Sopenharmony_ci goto unlock; 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci /* Make sure entry is read after the count is read. */ 24468c2ecf20Sopenharmony_ci smp_rmb(); 24478c2ecf20Sopenharmony_ci wqe = rvt_get_rwqe_ptr(rq, tail); 24488c2ecf20Sopenharmony_ci /* 24498c2ecf20Sopenharmony_ci * Even though we update the tail index in memory, the verbs 24508c2ecf20Sopenharmony_ci * consumer is not supposed to post more entries until a 24518c2ecf20Sopenharmony_ci * completion is generated. 24528c2ecf20Sopenharmony_ci */ 24538c2ecf20Sopenharmony_ci if (++tail >= rq->size) 24548c2ecf20Sopenharmony_ci tail = 0; 24558c2ecf20Sopenharmony_ci if (ip) 24568c2ecf20Sopenharmony_ci RDMA_WRITE_UAPI_ATOMIC(wq->tail, tail); 24578c2ecf20Sopenharmony_ci else 24588c2ecf20Sopenharmony_ci kwq->tail = tail; 24598c2ecf20Sopenharmony_ci if (!wr_id_only && !init_sge(qp, wqe)) { 24608c2ecf20Sopenharmony_ci ret = -1; 24618c2ecf20Sopenharmony_ci goto unlock; 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci qp->r_wr_id = wqe->wr_id; 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci kwq->count--; 24668c2ecf20Sopenharmony_ci ret = 1; 24678c2ecf20Sopenharmony_ci set_bit(RVT_R_WRID_VALID, &qp->r_aflags); 24688c2ecf20Sopenharmony_ci if (handler) { 24698c2ecf20Sopenharmony_ci /* 24708c2ecf20Sopenharmony_ci * Validate head pointer value and compute 24718c2ecf20Sopenharmony_ci * the number of remaining WQEs. 24728c2ecf20Sopenharmony_ci */ 24738c2ecf20Sopenharmony_ci if (kwq->count < srq->limit) { 24748c2ecf20Sopenharmony_ci kwq->count = 24758c2ecf20Sopenharmony_ci rvt_get_rq_count(rq, 24768c2ecf20Sopenharmony_ci get_rvt_head(rq, ip), tail); 24778c2ecf20Sopenharmony_ci if (kwq->count < srq->limit) { 24788c2ecf20Sopenharmony_ci struct ib_event ev; 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci srq->limit = 0; 24818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rq->kwq->c_lock, flags); 24828c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 24838c2ecf20Sopenharmony_ci ev.element.srq = qp->ibqp.srq; 24848c2ecf20Sopenharmony_ci ev.event = IB_EVENT_SRQ_LIMIT_REACHED; 24858c2ecf20Sopenharmony_ci handler(&ev, srq->ibsrq.srq_context); 24868c2ecf20Sopenharmony_ci goto bail; 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ciunlock: 24918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rq->kwq->c_lock, flags); 24928c2ecf20Sopenharmony_cibail: 24938c2ecf20Sopenharmony_ci return ret; 24948c2ecf20Sopenharmony_ci} 24958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_get_rwqe); 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci/** 24988c2ecf20Sopenharmony_ci * qp_comm_est - handle trap with QP established 24998c2ecf20Sopenharmony_ci * @qp: the QP 25008c2ecf20Sopenharmony_ci */ 25018c2ecf20Sopenharmony_civoid rvt_comm_est(struct rvt_qp *qp) 25028c2ecf20Sopenharmony_ci{ 25038c2ecf20Sopenharmony_ci qp->r_flags |= RVT_R_COMM_EST; 25048c2ecf20Sopenharmony_ci if (qp->ibqp.event_handler) { 25058c2ecf20Sopenharmony_ci struct ib_event ev; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 25088c2ecf20Sopenharmony_ci ev.element.qp = &qp->ibqp; 25098c2ecf20Sopenharmony_ci ev.event = IB_EVENT_COMM_EST; 25108c2ecf20Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_comm_est); 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_civoid rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci unsigned long flags; 25188c2ecf20Sopenharmony_ci int lastwqe; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, flags); 25218c2ecf20Sopenharmony_ci lastwqe = rvt_error_qp(qp, err); 25228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, flags); 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci if (lastwqe) { 25258c2ecf20Sopenharmony_ci struct ib_event ev; 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci ev.device = qp->ibqp.device; 25288c2ecf20Sopenharmony_ci ev.element.qp = &qp->ibqp; 25298c2ecf20Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 25308c2ecf20Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci} 25338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_rc_error); 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci/* 25368c2ecf20Sopenharmony_ci * rvt_rnr_tbl_to_usec - return index into ib_rvt_rnr_table 25378c2ecf20Sopenharmony_ci * @index - the index 25388c2ecf20Sopenharmony_ci * return usec from an index into ib_rvt_rnr_table 25398c2ecf20Sopenharmony_ci */ 25408c2ecf20Sopenharmony_ciunsigned long rvt_rnr_tbl_to_usec(u32 index) 25418c2ecf20Sopenharmony_ci{ 25428c2ecf20Sopenharmony_ci return ib_rvt_rnr_table[(index & IB_AETH_CREDIT_MASK)]; 25438c2ecf20Sopenharmony_ci} 25448c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_rnr_tbl_to_usec); 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_cistatic inline unsigned long rvt_aeth_to_usec(u32 aeth) 25478c2ecf20Sopenharmony_ci{ 25488c2ecf20Sopenharmony_ci return ib_rvt_rnr_table[(aeth >> IB_AETH_CREDIT_SHIFT) & 25498c2ecf20Sopenharmony_ci IB_AETH_CREDIT_MASK]; 25508c2ecf20Sopenharmony_ci} 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci/* 25538c2ecf20Sopenharmony_ci * rvt_add_retry_timer_ext - add/start a retry timer 25548c2ecf20Sopenharmony_ci * @qp - the QP 25558c2ecf20Sopenharmony_ci * @shift - timeout shift to wait for multiple packets 25568c2ecf20Sopenharmony_ci * add a retry timer on the QP 25578c2ecf20Sopenharmony_ci */ 25588c2ecf20Sopenharmony_civoid rvt_add_retry_timer_ext(struct rvt_qp *qp, u8 shift) 25598c2ecf20Sopenharmony_ci{ 25608c2ecf20Sopenharmony_ci struct ib_qp *ibqp = &qp->ibqp; 25618c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 25648c2ecf20Sopenharmony_ci qp->s_flags |= RVT_S_TIMER; 25658c2ecf20Sopenharmony_ci /* 4.096 usec. * (1 << qp->timeout) */ 25668c2ecf20Sopenharmony_ci qp->s_timer.expires = jiffies + rdi->busy_jiffies + 25678c2ecf20Sopenharmony_ci (qp->timeout_jiffies << shift); 25688c2ecf20Sopenharmony_ci add_timer(&qp->s_timer); 25698c2ecf20Sopenharmony_ci} 25708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_add_retry_timer_ext); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci/** 25738c2ecf20Sopenharmony_ci * rvt_add_rnr_timer - add/start an rnr timer on the QP 25748c2ecf20Sopenharmony_ci * @qp: the QP 25758c2ecf20Sopenharmony_ci * @aeth: aeth of RNR timeout, simulated aeth for loopback 25768c2ecf20Sopenharmony_ci */ 25778c2ecf20Sopenharmony_civoid rvt_add_rnr_timer(struct rvt_qp *qp, u32 aeth) 25788c2ecf20Sopenharmony_ci{ 25798c2ecf20Sopenharmony_ci u32 to; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 25828c2ecf20Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_RNR; 25838c2ecf20Sopenharmony_ci to = rvt_aeth_to_usec(aeth); 25848c2ecf20Sopenharmony_ci trace_rvt_rnrnak_add(qp, to); 25858c2ecf20Sopenharmony_ci hrtimer_start(&qp->s_rnr_timer, 25868c2ecf20Sopenharmony_ci ns_to_ktime(1000 * to), HRTIMER_MODE_REL_PINNED); 25878c2ecf20Sopenharmony_ci} 25888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_add_rnr_timer); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci/** 25918c2ecf20Sopenharmony_ci * rvt_stop_rc_timers - stop all timers 25928c2ecf20Sopenharmony_ci * @qp: the QP 25938c2ecf20Sopenharmony_ci * stop any pending timers 25948c2ecf20Sopenharmony_ci */ 25958c2ecf20Sopenharmony_civoid rvt_stop_rc_timers(struct rvt_qp *qp) 25968c2ecf20Sopenharmony_ci{ 25978c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 25988c2ecf20Sopenharmony_ci /* Remove QP from all timers */ 25998c2ecf20Sopenharmony_ci if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) { 26008c2ecf20Sopenharmony_ci qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR); 26018c2ecf20Sopenharmony_ci del_timer(&qp->s_timer); 26028c2ecf20Sopenharmony_ci hrtimer_try_to_cancel(&qp->s_rnr_timer); 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci} 26058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_stop_rc_timers); 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci/** 26088c2ecf20Sopenharmony_ci * rvt_stop_rnr_timer - stop an rnr timer 26098c2ecf20Sopenharmony_ci * @qp - the QP 26108c2ecf20Sopenharmony_ci * 26118c2ecf20Sopenharmony_ci * stop an rnr timer and return if the timer 26128c2ecf20Sopenharmony_ci * had been pending. 26138c2ecf20Sopenharmony_ci */ 26148c2ecf20Sopenharmony_cistatic void rvt_stop_rnr_timer(struct rvt_qp *qp) 26158c2ecf20Sopenharmony_ci{ 26168c2ecf20Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 26178c2ecf20Sopenharmony_ci /* Remove QP from rnr timer */ 26188c2ecf20Sopenharmony_ci if (qp->s_flags & RVT_S_WAIT_RNR) { 26198c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_WAIT_RNR; 26208c2ecf20Sopenharmony_ci trace_rvt_rnrnak_stop(qp, 0); 26218c2ecf20Sopenharmony_ci } 26228c2ecf20Sopenharmony_ci} 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci/** 26258c2ecf20Sopenharmony_ci * rvt_del_timers_sync - wait for any timeout routines to exit 26268c2ecf20Sopenharmony_ci * @qp: the QP 26278c2ecf20Sopenharmony_ci */ 26288c2ecf20Sopenharmony_civoid rvt_del_timers_sync(struct rvt_qp *qp) 26298c2ecf20Sopenharmony_ci{ 26308c2ecf20Sopenharmony_ci del_timer_sync(&qp->s_timer); 26318c2ecf20Sopenharmony_ci hrtimer_cancel(&qp->s_rnr_timer); 26328c2ecf20Sopenharmony_ci} 26338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_del_timers_sync); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci/* 26368c2ecf20Sopenharmony_ci * This is called from s_timer for missing responses. 26378c2ecf20Sopenharmony_ci */ 26388c2ecf20Sopenharmony_cistatic void rvt_rc_timeout(struct timer_list *t) 26398c2ecf20Sopenharmony_ci{ 26408c2ecf20Sopenharmony_ci struct rvt_qp *qp = from_timer(qp, t, s_timer); 26418c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 26428c2ecf20Sopenharmony_ci unsigned long flags; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 26458c2ecf20Sopenharmony_ci spin_lock(&qp->s_lock); 26468c2ecf20Sopenharmony_ci if (qp->s_flags & RVT_S_TIMER) { 26478c2ecf20Sopenharmony_ci struct rvt_ibport *rvp = rdi->ports[qp->port_num - 1]; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci qp->s_flags &= ~RVT_S_TIMER; 26508c2ecf20Sopenharmony_ci rvp->n_rc_timeouts++; 26518c2ecf20Sopenharmony_ci del_timer(&qp->s_timer); 26528c2ecf20Sopenharmony_ci trace_rvt_rc_timeout(qp, qp->s_last_psn + 1); 26538c2ecf20Sopenharmony_ci if (rdi->driver_f.notify_restart_rc) 26548c2ecf20Sopenharmony_ci rdi->driver_f.notify_restart_rc(qp, 26558c2ecf20Sopenharmony_ci qp->s_last_psn + 1, 26568c2ecf20Sopenharmony_ci 1); 26578c2ecf20Sopenharmony_ci rdi->driver_f.schedule_send(qp); 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci spin_unlock(&qp->s_lock); 26608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 26618c2ecf20Sopenharmony_ci} 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci/* 26648c2ecf20Sopenharmony_ci * This is called from s_timer for RNR timeouts. 26658c2ecf20Sopenharmony_ci */ 26668c2ecf20Sopenharmony_cienum hrtimer_restart rvt_rc_rnr_retry(struct hrtimer *t) 26678c2ecf20Sopenharmony_ci{ 26688c2ecf20Sopenharmony_ci struct rvt_qp *qp = container_of(t, struct rvt_qp, s_rnr_timer); 26698c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 26708c2ecf20Sopenharmony_ci unsigned long flags; 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, flags); 26738c2ecf20Sopenharmony_ci rvt_stop_rnr_timer(qp); 26748c2ecf20Sopenharmony_ci trace_rvt_rnrnak_timeout(qp, 0); 26758c2ecf20Sopenharmony_ci rdi->driver_f.schedule_send(qp); 26768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, flags); 26778c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 26788c2ecf20Sopenharmony_ci} 26798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_rc_rnr_retry); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci/** 26828c2ecf20Sopenharmony_ci * rvt_qp_iter_init - initial for QP iteration 26838c2ecf20Sopenharmony_ci * @rdi: rvt devinfo 26848c2ecf20Sopenharmony_ci * @v: u64 value 26858c2ecf20Sopenharmony_ci * @cb: user-defined callback 26868c2ecf20Sopenharmony_ci * 26878c2ecf20Sopenharmony_ci * This returns an iterator suitable for iterating QPs 26888c2ecf20Sopenharmony_ci * in the system. 26898c2ecf20Sopenharmony_ci * 26908c2ecf20Sopenharmony_ci * The @cb is a user-defined callback and @v is a 64-bit 26918c2ecf20Sopenharmony_ci * value passed to and relevant for processing in the 26928c2ecf20Sopenharmony_ci * @cb. An example use case would be to alter QP processing 26938c2ecf20Sopenharmony_ci * based on criteria not part of the rvt_qp. 26948c2ecf20Sopenharmony_ci * 26958c2ecf20Sopenharmony_ci * Use cases that require memory allocation to succeed 26968c2ecf20Sopenharmony_ci * must preallocate appropriately. 26978c2ecf20Sopenharmony_ci * 26988c2ecf20Sopenharmony_ci * Return: a pointer to an rvt_qp_iter or NULL 26998c2ecf20Sopenharmony_ci */ 27008c2ecf20Sopenharmony_cistruct rvt_qp_iter *rvt_qp_iter_init(struct rvt_dev_info *rdi, 27018c2ecf20Sopenharmony_ci u64 v, 27028c2ecf20Sopenharmony_ci void (*cb)(struct rvt_qp *qp, u64 v)) 27038c2ecf20Sopenharmony_ci{ 27048c2ecf20Sopenharmony_ci struct rvt_qp_iter *i; 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci i = kzalloc(sizeof(*i), GFP_KERNEL); 27078c2ecf20Sopenharmony_ci if (!i) 27088c2ecf20Sopenharmony_ci return NULL; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci i->rdi = rdi; 27118c2ecf20Sopenharmony_ci /* number of special QPs (SMI/GSI) for device */ 27128c2ecf20Sopenharmony_ci i->specials = rdi->ibdev.phys_port_cnt * 2; 27138c2ecf20Sopenharmony_ci i->v = v; 27148c2ecf20Sopenharmony_ci i->cb = cb; 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci return i; 27178c2ecf20Sopenharmony_ci} 27188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_qp_iter_init); 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci/** 27218c2ecf20Sopenharmony_ci * rvt_qp_iter_next - return the next QP in iter 27228c2ecf20Sopenharmony_ci * @iter: the iterator 27238c2ecf20Sopenharmony_ci * 27248c2ecf20Sopenharmony_ci * Fine grained QP iterator suitable for use 27258c2ecf20Sopenharmony_ci * with debugfs seq_file mechanisms. 27268c2ecf20Sopenharmony_ci * 27278c2ecf20Sopenharmony_ci * Updates iter->qp with the current QP when the return 27288c2ecf20Sopenharmony_ci * value is 0. 27298c2ecf20Sopenharmony_ci * 27308c2ecf20Sopenharmony_ci * Return: 0 - iter->qp is valid 1 - no more QPs 27318c2ecf20Sopenharmony_ci */ 27328c2ecf20Sopenharmony_ciint rvt_qp_iter_next(struct rvt_qp_iter *iter) 27338c2ecf20Sopenharmony_ci __must_hold(RCU) 27348c2ecf20Sopenharmony_ci{ 27358c2ecf20Sopenharmony_ci int n = iter->n; 27368c2ecf20Sopenharmony_ci int ret = 1; 27378c2ecf20Sopenharmony_ci struct rvt_qp *pqp = iter->qp; 27388c2ecf20Sopenharmony_ci struct rvt_qp *qp; 27398c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = iter->rdi; 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci /* 27428c2ecf20Sopenharmony_ci * The approach is to consider the special qps 27438c2ecf20Sopenharmony_ci * as additional table entries before the 27448c2ecf20Sopenharmony_ci * real hash table. Since the qp code sets 27458c2ecf20Sopenharmony_ci * the qp->next hash link to NULL, this works just fine. 27468c2ecf20Sopenharmony_ci * 27478c2ecf20Sopenharmony_ci * iter->specials is 2 * # ports 27488c2ecf20Sopenharmony_ci * 27498c2ecf20Sopenharmony_ci * n = 0..iter->specials is the special qp indices 27508c2ecf20Sopenharmony_ci * 27518c2ecf20Sopenharmony_ci * n = iter->specials..rdi->qp_dev->qp_table_size+iter->specials are 27528c2ecf20Sopenharmony_ci * the potential hash bucket entries 27538c2ecf20Sopenharmony_ci * 27548c2ecf20Sopenharmony_ci */ 27558c2ecf20Sopenharmony_ci for (; n < rdi->qp_dev->qp_table_size + iter->specials; n++) { 27568c2ecf20Sopenharmony_ci if (pqp) { 27578c2ecf20Sopenharmony_ci qp = rcu_dereference(pqp->next); 27588c2ecf20Sopenharmony_ci } else { 27598c2ecf20Sopenharmony_ci if (n < iter->specials) { 27608c2ecf20Sopenharmony_ci struct rvt_ibport *rvp; 27618c2ecf20Sopenharmony_ci int pidx; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci pidx = n % rdi->ibdev.phys_port_cnt; 27648c2ecf20Sopenharmony_ci rvp = rdi->ports[pidx]; 27658c2ecf20Sopenharmony_ci qp = rcu_dereference(rvp->qp[n & 1]); 27668c2ecf20Sopenharmony_ci } else { 27678c2ecf20Sopenharmony_ci qp = rcu_dereference( 27688c2ecf20Sopenharmony_ci rdi->qp_dev->qp_table[ 27698c2ecf20Sopenharmony_ci (n - iter->specials)]); 27708c2ecf20Sopenharmony_ci } 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci pqp = qp; 27738c2ecf20Sopenharmony_ci if (qp) { 27748c2ecf20Sopenharmony_ci iter->qp = qp; 27758c2ecf20Sopenharmony_ci iter->n = n; 27768c2ecf20Sopenharmony_ci return 0; 27778c2ecf20Sopenharmony_ci } 27788c2ecf20Sopenharmony_ci } 27798c2ecf20Sopenharmony_ci return ret; 27808c2ecf20Sopenharmony_ci} 27818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_qp_iter_next); 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci/** 27848c2ecf20Sopenharmony_ci * rvt_qp_iter - iterate all QPs 27858c2ecf20Sopenharmony_ci * @rdi: rvt devinfo 27868c2ecf20Sopenharmony_ci * @v: a 64-bit value 27878c2ecf20Sopenharmony_ci * @cb: a callback 27888c2ecf20Sopenharmony_ci * 27898c2ecf20Sopenharmony_ci * This provides a way for iterating all QPs. 27908c2ecf20Sopenharmony_ci * 27918c2ecf20Sopenharmony_ci * The @cb is a user-defined callback and @v is a 64-bit 27928c2ecf20Sopenharmony_ci * value passed to and relevant for processing in the 27938c2ecf20Sopenharmony_ci * cb. An example use case would be to alter QP processing 27948c2ecf20Sopenharmony_ci * based on criteria not part of the rvt_qp. 27958c2ecf20Sopenharmony_ci * 27968c2ecf20Sopenharmony_ci * The code has an internal iterator to simplify 27978c2ecf20Sopenharmony_ci * non seq_file use cases. 27988c2ecf20Sopenharmony_ci */ 27998c2ecf20Sopenharmony_civoid rvt_qp_iter(struct rvt_dev_info *rdi, 28008c2ecf20Sopenharmony_ci u64 v, 28018c2ecf20Sopenharmony_ci void (*cb)(struct rvt_qp *qp, u64 v)) 28028c2ecf20Sopenharmony_ci{ 28038c2ecf20Sopenharmony_ci int ret; 28048c2ecf20Sopenharmony_ci struct rvt_qp_iter i = { 28058c2ecf20Sopenharmony_ci .rdi = rdi, 28068c2ecf20Sopenharmony_ci .specials = rdi->ibdev.phys_port_cnt * 2, 28078c2ecf20Sopenharmony_ci .v = v, 28088c2ecf20Sopenharmony_ci .cb = cb 28098c2ecf20Sopenharmony_ci }; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci rcu_read_lock(); 28128c2ecf20Sopenharmony_ci do { 28138c2ecf20Sopenharmony_ci ret = rvt_qp_iter_next(&i); 28148c2ecf20Sopenharmony_ci if (!ret) { 28158c2ecf20Sopenharmony_ci rvt_get_qp(i.qp); 28168c2ecf20Sopenharmony_ci rcu_read_unlock(); 28178c2ecf20Sopenharmony_ci i.cb(i.qp, i.v); 28188c2ecf20Sopenharmony_ci rcu_read_lock(); 28198c2ecf20Sopenharmony_ci rvt_put_qp(i.qp); 28208c2ecf20Sopenharmony_ci } 28218c2ecf20Sopenharmony_ci } while (!ret); 28228c2ecf20Sopenharmony_ci rcu_read_unlock(); 28238c2ecf20Sopenharmony_ci} 28248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_qp_iter); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci/* 28278c2ecf20Sopenharmony_ci * This should be called with s_lock and r_lock held. 28288c2ecf20Sopenharmony_ci */ 28298c2ecf20Sopenharmony_civoid rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, 28308c2ecf20Sopenharmony_ci enum ib_wc_status status) 28318c2ecf20Sopenharmony_ci{ 28328c2ecf20Sopenharmony_ci u32 old_last, last; 28338c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) 28368c2ecf20Sopenharmony_ci return; 28378c2ecf20Sopenharmony_ci rdi = ib_to_rvt(qp->ibqp.device); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci old_last = qp->s_last; 28408c2ecf20Sopenharmony_ci trace_rvt_qp_send_completion(qp, wqe, old_last); 28418c2ecf20Sopenharmony_ci last = rvt_qp_complete_swqe(qp, wqe, rdi->wc_opcode[wqe->wr.opcode], 28428c2ecf20Sopenharmony_ci status); 28438c2ecf20Sopenharmony_ci if (qp->s_acked == old_last) 28448c2ecf20Sopenharmony_ci qp->s_acked = last; 28458c2ecf20Sopenharmony_ci if (qp->s_cur == old_last) 28468c2ecf20Sopenharmony_ci qp->s_cur = last; 28478c2ecf20Sopenharmony_ci if (qp->s_tail == old_last) 28488c2ecf20Sopenharmony_ci qp->s_tail = last; 28498c2ecf20Sopenharmony_ci if (qp->state == IB_QPS_SQD && last == qp->s_cur) 28508c2ecf20Sopenharmony_ci qp->s_draining = 0; 28518c2ecf20Sopenharmony_ci} 28528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_send_complete); 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci/** 28558c2ecf20Sopenharmony_ci * rvt_copy_sge - copy data to SGE memory 28568c2ecf20Sopenharmony_ci * @qp: associated QP 28578c2ecf20Sopenharmony_ci * @ss: the SGE state 28588c2ecf20Sopenharmony_ci * @data: the data to copy 28598c2ecf20Sopenharmony_ci * @length: the length of the data 28608c2ecf20Sopenharmony_ci * @release: boolean to release MR 28618c2ecf20Sopenharmony_ci * @copy_last: do a separate copy of the last 8 bytes 28628c2ecf20Sopenharmony_ci */ 28638c2ecf20Sopenharmony_civoid rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss, 28648c2ecf20Sopenharmony_ci void *data, u32 length, 28658c2ecf20Sopenharmony_ci bool release, bool copy_last) 28668c2ecf20Sopenharmony_ci{ 28678c2ecf20Sopenharmony_ci struct rvt_sge *sge = &ss->sge; 28688c2ecf20Sopenharmony_ci int i; 28698c2ecf20Sopenharmony_ci bool in_last = false; 28708c2ecf20Sopenharmony_ci bool cacheless_copy = false; 28718c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 28728c2ecf20Sopenharmony_ci struct rvt_wss *wss = rdi->wss; 28738c2ecf20Sopenharmony_ci unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci if (sge_copy_mode == RVT_SGE_COPY_CACHELESS) { 28768c2ecf20Sopenharmony_ci cacheless_copy = length >= PAGE_SIZE; 28778c2ecf20Sopenharmony_ci } else if (sge_copy_mode == RVT_SGE_COPY_ADAPTIVE) { 28788c2ecf20Sopenharmony_ci if (length >= PAGE_SIZE) { 28798c2ecf20Sopenharmony_ci /* 28808c2ecf20Sopenharmony_ci * NOTE: this *assumes*: 28818c2ecf20Sopenharmony_ci * o The first vaddr is the dest. 28828c2ecf20Sopenharmony_ci * o If multiple pages, then vaddr is sequential. 28838c2ecf20Sopenharmony_ci */ 28848c2ecf20Sopenharmony_ci wss_insert(wss, sge->vaddr); 28858c2ecf20Sopenharmony_ci if (length >= (2 * PAGE_SIZE)) 28868c2ecf20Sopenharmony_ci wss_insert(wss, (sge->vaddr + PAGE_SIZE)); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci cacheless_copy = wss_exceeds_threshold(wss); 28898c2ecf20Sopenharmony_ci } else { 28908c2ecf20Sopenharmony_ci wss_advance_clean_counter(wss); 28918c2ecf20Sopenharmony_ci } 28928c2ecf20Sopenharmony_ci } 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (copy_last) { 28958c2ecf20Sopenharmony_ci if (length > 8) { 28968c2ecf20Sopenharmony_ci length -= 8; 28978c2ecf20Sopenharmony_ci } else { 28988c2ecf20Sopenharmony_ci copy_last = false; 28998c2ecf20Sopenharmony_ci in_last = true; 29008c2ecf20Sopenharmony_ci } 29018c2ecf20Sopenharmony_ci } 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ciagain: 29048c2ecf20Sopenharmony_ci while (length) { 29058c2ecf20Sopenharmony_ci u32 len = rvt_get_sge_length(sge, length); 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci WARN_ON_ONCE(len == 0); 29088c2ecf20Sopenharmony_ci if (unlikely(in_last)) { 29098c2ecf20Sopenharmony_ci /* enforce byte transfer ordering */ 29108c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 29118c2ecf20Sopenharmony_ci ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i]; 29128c2ecf20Sopenharmony_ci } else if (cacheless_copy) { 29138c2ecf20Sopenharmony_ci cacheless_memcpy(sge->vaddr, data, len); 29148c2ecf20Sopenharmony_ci } else { 29158c2ecf20Sopenharmony_ci memcpy(sge->vaddr, data, len); 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci rvt_update_sge(ss, len, release); 29188c2ecf20Sopenharmony_ci data += len; 29198c2ecf20Sopenharmony_ci length -= len; 29208c2ecf20Sopenharmony_ci } 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci if (copy_last) { 29238c2ecf20Sopenharmony_ci copy_last = false; 29248c2ecf20Sopenharmony_ci in_last = true; 29258c2ecf20Sopenharmony_ci length = 8; 29268c2ecf20Sopenharmony_ci goto again; 29278c2ecf20Sopenharmony_ci } 29288c2ecf20Sopenharmony_ci} 29298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_copy_sge); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_cistatic enum ib_wc_status loopback_qp_drop(struct rvt_ibport *rvp, 29328c2ecf20Sopenharmony_ci struct rvt_qp *sqp) 29338c2ecf20Sopenharmony_ci{ 29348c2ecf20Sopenharmony_ci rvp->n_pkt_drops++; 29358c2ecf20Sopenharmony_ci /* 29368c2ecf20Sopenharmony_ci * For RC, the requester would timeout and retry so 29378c2ecf20Sopenharmony_ci * shortcut the timeouts and just signal too many retries. 29388c2ecf20Sopenharmony_ci */ 29398c2ecf20Sopenharmony_ci return sqp->ibqp.qp_type == IB_QPT_RC ? 29408c2ecf20Sopenharmony_ci IB_WC_RETRY_EXC_ERR : IB_WC_SUCCESS; 29418c2ecf20Sopenharmony_ci} 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci/** 29448c2ecf20Sopenharmony_ci * ruc_loopback - handle UC and RC loopback requests 29458c2ecf20Sopenharmony_ci * @sqp: the sending QP 29468c2ecf20Sopenharmony_ci * 29478c2ecf20Sopenharmony_ci * This is called from rvt_do_send() to forward a WQE addressed to the same HFI 29488c2ecf20Sopenharmony_ci * Note that although we are single threaded due to the send engine, we still 29498c2ecf20Sopenharmony_ci * have to protect against post_send(). We don't have to worry about 29508c2ecf20Sopenharmony_ci * receive interrupts since this is a connected protocol and all packets 29518c2ecf20Sopenharmony_ci * will pass through here. 29528c2ecf20Sopenharmony_ci */ 29538c2ecf20Sopenharmony_civoid rvt_ruc_loopback(struct rvt_qp *sqp) 29548c2ecf20Sopenharmony_ci{ 29558c2ecf20Sopenharmony_ci struct rvt_ibport *rvp = NULL; 29568c2ecf20Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(sqp->ibqp.device); 29578c2ecf20Sopenharmony_ci struct rvt_qp *qp; 29588c2ecf20Sopenharmony_ci struct rvt_swqe *wqe; 29598c2ecf20Sopenharmony_ci struct rvt_sge *sge; 29608c2ecf20Sopenharmony_ci unsigned long flags; 29618c2ecf20Sopenharmony_ci struct ib_wc wc; 29628c2ecf20Sopenharmony_ci u64 sdata; 29638c2ecf20Sopenharmony_ci atomic64_t *maddr; 29648c2ecf20Sopenharmony_ci enum ib_wc_status send_status; 29658c2ecf20Sopenharmony_ci bool release; 29668c2ecf20Sopenharmony_ci int ret; 29678c2ecf20Sopenharmony_ci bool copy_last = false; 29688c2ecf20Sopenharmony_ci int local_ops = 0; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci rcu_read_lock(); 29718c2ecf20Sopenharmony_ci rvp = rdi->ports[sqp->port_num - 1]; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci /* 29748c2ecf20Sopenharmony_ci * Note that we check the responder QP state after 29758c2ecf20Sopenharmony_ci * checking the requester's state. 29768c2ecf20Sopenharmony_ci */ 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), rvp, 29798c2ecf20Sopenharmony_ci sqp->remote_qpn); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci /* Return if we are already busy processing a work request. */ 29848c2ecf20Sopenharmony_ci if ((sqp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT)) || 29858c2ecf20Sopenharmony_ci !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND)) 29868c2ecf20Sopenharmony_ci goto unlock; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci sqp->s_flags |= RVT_S_BUSY; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ciagain: 29918c2ecf20Sopenharmony_ci if (sqp->s_last == READ_ONCE(sqp->s_head)) 29928c2ecf20Sopenharmony_ci goto clr_busy; 29938c2ecf20Sopenharmony_ci wqe = rvt_get_swqe_ptr(sqp, sqp->s_last); 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci /* Return if it is not OK to start a new work request. */ 29968c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) { 29978c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND)) 29988c2ecf20Sopenharmony_ci goto clr_busy; 29998c2ecf20Sopenharmony_ci /* We are in the error state, flush the work request. */ 30008c2ecf20Sopenharmony_ci send_status = IB_WC_WR_FLUSH_ERR; 30018c2ecf20Sopenharmony_ci goto flush_send; 30028c2ecf20Sopenharmony_ci } 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci /* 30058c2ecf20Sopenharmony_ci * We can rely on the entry not changing without the s_lock 30068c2ecf20Sopenharmony_ci * being held until we update s_last. 30078c2ecf20Sopenharmony_ci * We increment s_cur to indicate s_last is in progress. 30088c2ecf20Sopenharmony_ci */ 30098c2ecf20Sopenharmony_ci if (sqp->s_last == sqp->s_cur) { 30108c2ecf20Sopenharmony_ci if (++sqp->s_cur >= sqp->s_size) 30118c2ecf20Sopenharmony_ci sqp->s_cur = 0; 30128c2ecf20Sopenharmony_ci } 30138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sqp->s_lock, flags); 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci if (!qp) { 30168c2ecf20Sopenharmony_ci send_status = loopback_qp_drop(rvp, sqp); 30178c2ecf20Sopenharmony_ci goto serr_no_r_lock; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 30208c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) || 30218c2ecf20Sopenharmony_ci qp->ibqp.qp_type != sqp->ibqp.qp_type) { 30228c2ecf20Sopenharmony_ci send_status = loopback_qp_drop(rvp, sqp); 30238c2ecf20Sopenharmony_ci goto serr; 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 30278c2ecf20Sopenharmony_ci send_status = IB_WC_SUCCESS; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci release = true; 30308c2ecf20Sopenharmony_ci sqp->s_sge.sge = wqe->sg_list[0]; 30318c2ecf20Sopenharmony_ci sqp->s_sge.sg_list = wqe->sg_list + 1; 30328c2ecf20Sopenharmony_ci sqp->s_sge.num_sge = wqe->wr.num_sge; 30338c2ecf20Sopenharmony_ci sqp->s_len = wqe->length; 30348c2ecf20Sopenharmony_ci switch (wqe->wr.opcode) { 30358c2ecf20Sopenharmony_ci case IB_WR_REG_MR: 30368c2ecf20Sopenharmony_ci goto send_comp; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci case IB_WR_LOCAL_INV: 30398c2ecf20Sopenharmony_ci if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) { 30408c2ecf20Sopenharmony_ci if (rvt_invalidate_rkey(sqp, 30418c2ecf20Sopenharmony_ci wqe->wr.ex.invalidate_rkey)) 30428c2ecf20Sopenharmony_ci send_status = IB_WC_LOC_PROT_ERR; 30438c2ecf20Sopenharmony_ci local_ops = 1; 30448c2ecf20Sopenharmony_ci } 30458c2ecf20Sopenharmony_ci goto send_comp; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_INV: 30488c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 30498c2ecf20Sopenharmony_ci case IB_WR_SEND: 30508c2ecf20Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 30518c2ecf20Sopenharmony_ci if (ret < 0) 30528c2ecf20Sopenharmony_ci goto op_err; 30538c2ecf20Sopenharmony_ci if (!ret) 30548c2ecf20Sopenharmony_ci goto rnr_nak; 30558c2ecf20Sopenharmony_ci if (wqe->length > qp->r_len) 30568c2ecf20Sopenharmony_ci goto inv_err; 30578c2ecf20Sopenharmony_ci switch (wqe->wr.opcode) { 30588c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_INV: 30598c2ecf20Sopenharmony_ci if (!rvt_invalidate_rkey(qp, 30608c2ecf20Sopenharmony_ci wqe->wr.ex.invalidate_rkey)) { 30618c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_INVALIDATE; 30628c2ecf20Sopenharmony_ci wc.ex.invalidate_rkey = 30638c2ecf20Sopenharmony_ci wqe->wr.ex.invalidate_rkey; 30648c2ecf20Sopenharmony_ci } 30658c2ecf20Sopenharmony_ci break; 30668c2ecf20Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 30678c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 30688c2ecf20Sopenharmony_ci wc.ex.imm_data = wqe->wr.ex.imm_data; 30698c2ecf20Sopenharmony_ci break; 30708c2ecf20Sopenharmony_ci default: 30718c2ecf20Sopenharmony_ci break; 30728c2ecf20Sopenharmony_ci } 30738c2ecf20Sopenharmony_ci break; 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 30768c2ecf20Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) 30778c2ecf20Sopenharmony_ci goto inv_err; 30788c2ecf20Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 30798c2ecf20Sopenharmony_ci wc.ex.imm_data = wqe->wr.ex.imm_data; 30808c2ecf20Sopenharmony_ci ret = rvt_get_rwqe(qp, true); 30818c2ecf20Sopenharmony_ci if (ret < 0) 30828c2ecf20Sopenharmony_ci goto op_err; 30838c2ecf20Sopenharmony_ci if (!ret) 30848c2ecf20Sopenharmony_ci goto rnr_nak; 30858c2ecf20Sopenharmony_ci /* skip copy_last set and qp_access_flags recheck */ 30868c2ecf20Sopenharmony_ci goto do_write; 30878c2ecf20Sopenharmony_ci case IB_WR_RDMA_WRITE: 30888c2ecf20Sopenharmony_ci copy_last = rvt_is_user_qp(qp); 30898c2ecf20Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) 30908c2ecf20Sopenharmony_ci goto inv_err; 30918c2ecf20Sopenharmony_cido_write: 30928c2ecf20Sopenharmony_ci if (wqe->length == 0) 30938c2ecf20Sopenharmony_ci break; 30948c2ecf20Sopenharmony_ci if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length, 30958c2ecf20Sopenharmony_ci wqe->rdma_wr.remote_addr, 30968c2ecf20Sopenharmony_ci wqe->rdma_wr.rkey, 30978c2ecf20Sopenharmony_ci IB_ACCESS_REMOTE_WRITE))) 30988c2ecf20Sopenharmony_ci goto acc_err; 30998c2ecf20Sopenharmony_ci qp->r_sge.sg_list = NULL; 31008c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 1; 31018c2ecf20Sopenharmony_ci qp->r_sge.total_len = wqe->length; 31028c2ecf20Sopenharmony_ci break; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci case IB_WR_RDMA_READ: 31058c2ecf20Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) 31068c2ecf20Sopenharmony_ci goto inv_err; 31078c2ecf20Sopenharmony_ci if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length, 31088c2ecf20Sopenharmony_ci wqe->rdma_wr.remote_addr, 31098c2ecf20Sopenharmony_ci wqe->rdma_wr.rkey, 31108c2ecf20Sopenharmony_ci IB_ACCESS_REMOTE_READ))) 31118c2ecf20Sopenharmony_ci goto acc_err; 31128c2ecf20Sopenharmony_ci release = false; 31138c2ecf20Sopenharmony_ci sqp->s_sge.sg_list = NULL; 31148c2ecf20Sopenharmony_ci sqp->s_sge.num_sge = 1; 31158c2ecf20Sopenharmony_ci qp->r_sge.sge = wqe->sg_list[0]; 31168c2ecf20Sopenharmony_ci qp->r_sge.sg_list = wqe->sg_list + 1; 31178c2ecf20Sopenharmony_ci qp->r_sge.num_sge = wqe->wr.num_sge; 31188c2ecf20Sopenharmony_ci qp->r_sge.total_len = wqe->length; 31198c2ecf20Sopenharmony_ci break; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 31228c2ecf20Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 31238c2ecf20Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) 31248c2ecf20Sopenharmony_ci goto inv_err; 31258c2ecf20Sopenharmony_ci if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1))) 31268c2ecf20Sopenharmony_ci goto inv_err; 31278c2ecf20Sopenharmony_ci if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), 31288c2ecf20Sopenharmony_ci wqe->atomic_wr.remote_addr, 31298c2ecf20Sopenharmony_ci wqe->atomic_wr.rkey, 31308c2ecf20Sopenharmony_ci IB_ACCESS_REMOTE_ATOMIC))) 31318c2ecf20Sopenharmony_ci goto acc_err; 31328c2ecf20Sopenharmony_ci /* Perform atomic OP and save result. */ 31338c2ecf20Sopenharmony_ci maddr = (atomic64_t *)qp->r_sge.sge.vaddr; 31348c2ecf20Sopenharmony_ci sdata = wqe->atomic_wr.compare_add; 31358c2ecf20Sopenharmony_ci *(u64 *)sqp->s_sge.sge.vaddr = 31368c2ecf20Sopenharmony_ci (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? 31378c2ecf20Sopenharmony_ci (u64)atomic64_add_return(sdata, maddr) - sdata : 31388c2ecf20Sopenharmony_ci (u64)cmpxchg((u64 *)qp->r_sge.sge.vaddr, 31398c2ecf20Sopenharmony_ci sdata, wqe->atomic_wr.swap); 31408c2ecf20Sopenharmony_ci rvt_put_mr(qp->r_sge.sge.mr); 31418c2ecf20Sopenharmony_ci qp->r_sge.num_sge = 0; 31428c2ecf20Sopenharmony_ci goto send_comp; 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci default: 31458c2ecf20Sopenharmony_ci send_status = IB_WC_LOC_QP_OP_ERR; 31468c2ecf20Sopenharmony_ci goto serr; 31478c2ecf20Sopenharmony_ci } 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci sge = &sqp->s_sge.sge; 31508c2ecf20Sopenharmony_ci while (sqp->s_len) { 31518c2ecf20Sopenharmony_ci u32 len = rvt_get_sge_length(sge, sqp->s_len); 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci WARN_ON_ONCE(len == 0); 31548c2ecf20Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, 31558c2ecf20Sopenharmony_ci len, release, copy_last); 31568c2ecf20Sopenharmony_ci rvt_update_sge(&sqp->s_sge, len, !release); 31578c2ecf20Sopenharmony_ci sqp->s_len -= len; 31588c2ecf20Sopenharmony_ci } 31598c2ecf20Sopenharmony_ci if (release) 31608c2ecf20Sopenharmony_ci rvt_put_ss(&qp->r_sge); 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) 31638c2ecf20Sopenharmony_ci goto send_comp; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) 31668c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; 31678c2ecf20Sopenharmony_ci else 31688c2ecf20Sopenharmony_ci wc.opcode = IB_WC_RECV; 31698c2ecf20Sopenharmony_ci wc.wr_id = qp->r_wr_id; 31708c2ecf20Sopenharmony_ci wc.status = IB_WC_SUCCESS; 31718c2ecf20Sopenharmony_ci wc.byte_len = wqe->length; 31728c2ecf20Sopenharmony_ci wc.qp = &qp->ibqp; 31738c2ecf20Sopenharmony_ci wc.src_qp = qp->remote_qpn; 31748c2ecf20Sopenharmony_ci wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX; 31758c2ecf20Sopenharmony_ci wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); 31768c2ecf20Sopenharmony_ci wc.port_num = 1; 31778c2ecf20Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 31788c2ecf20Sopenharmony_ci rvt_recv_cq(qp, &wc, wqe->wr.send_flags & IB_SEND_SOLICITED); 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_cisend_comp: 31818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 31828c2ecf20Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 31838c2ecf20Sopenharmony_ci rvp->n_loop_pkts++; 31848c2ecf20Sopenharmony_ciflush_send: 31858c2ecf20Sopenharmony_ci sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; 31868c2ecf20Sopenharmony_ci spin_lock(&sqp->r_lock); 31878c2ecf20Sopenharmony_ci rvt_send_complete(sqp, wqe, send_status); 31888c2ecf20Sopenharmony_ci spin_unlock(&sqp->r_lock); 31898c2ecf20Sopenharmony_ci if (local_ops) { 31908c2ecf20Sopenharmony_ci atomic_dec(&sqp->local_ops_pending); 31918c2ecf20Sopenharmony_ci local_ops = 0; 31928c2ecf20Sopenharmony_ci } 31938c2ecf20Sopenharmony_ci goto again; 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_cirnr_nak: 31968c2ecf20Sopenharmony_ci /* Handle RNR NAK */ 31978c2ecf20Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_UC) 31988c2ecf20Sopenharmony_ci goto send_comp; 31998c2ecf20Sopenharmony_ci rvp->n_rnr_naks++; 32008c2ecf20Sopenharmony_ci /* 32018c2ecf20Sopenharmony_ci * Note: we don't need the s_lock held since the BUSY flag 32028c2ecf20Sopenharmony_ci * makes this single threaded. 32038c2ecf20Sopenharmony_ci */ 32048c2ecf20Sopenharmony_ci if (sqp->s_rnr_retry == 0) { 32058c2ecf20Sopenharmony_ci send_status = IB_WC_RNR_RETRY_EXC_ERR; 32068c2ecf20Sopenharmony_ci goto serr; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci if (sqp->s_rnr_retry_cnt < 7) 32098c2ecf20Sopenharmony_ci sqp->s_rnr_retry--; 32108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 32118c2ecf20Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 32128c2ecf20Sopenharmony_ci if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK)) 32138c2ecf20Sopenharmony_ci goto clr_busy; 32148c2ecf20Sopenharmony_ci rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer << 32158c2ecf20Sopenharmony_ci IB_AETH_CREDIT_SHIFT); 32168c2ecf20Sopenharmony_ci goto clr_busy; 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_ciop_err: 32198c2ecf20Sopenharmony_ci send_status = IB_WC_REM_OP_ERR; 32208c2ecf20Sopenharmony_ci wc.status = IB_WC_LOC_QP_OP_ERR; 32218c2ecf20Sopenharmony_ci goto err; 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ciinv_err: 32248c2ecf20Sopenharmony_ci send_status = 32258c2ecf20Sopenharmony_ci sqp->ibqp.qp_type == IB_QPT_RC ? 32268c2ecf20Sopenharmony_ci IB_WC_REM_INV_REQ_ERR : 32278c2ecf20Sopenharmony_ci IB_WC_SUCCESS; 32288c2ecf20Sopenharmony_ci wc.status = IB_WC_LOC_QP_OP_ERR; 32298c2ecf20Sopenharmony_ci goto err; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ciacc_err: 32328c2ecf20Sopenharmony_ci send_status = IB_WC_REM_ACCESS_ERR; 32338c2ecf20Sopenharmony_ci wc.status = IB_WC_LOC_PROT_ERR; 32348c2ecf20Sopenharmony_cierr: 32358c2ecf20Sopenharmony_ci /* responder goes to error state */ 32368c2ecf20Sopenharmony_ci rvt_rc_error(qp, wc.status); 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ciserr: 32398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 32408c2ecf20Sopenharmony_ciserr_no_r_lock: 32418c2ecf20Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 32428c2ecf20Sopenharmony_ci spin_lock(&sqp->r_lock); 32438c2ecf20Sopenharmony_ci rvt_send_complete(sqp, wqe, send_status); 32448c2ecf20Sopenharmony_ci spin_unlock(&sqp->r_lock); 32458c2ecf20Sopenharmony_ci if (sqp->ibqp.qp_type == IB_QPT_RC) { 32468c2ecf20Sopenharmony_ci int lastwqe; 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci spin_lock(&sqp->r_lock); 32498c2ecf20Sopenharmony_ci lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); 32508c2ecf20Sopenharmony_ci spin_unlock(&sqp->r_lock); 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci sqp->s_flags &= ~RVT_S_BUSY; 32538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sqp->s_lock, flags); 32548c2ecf20Sopenharmony_ci if (lastwqe) { 32558c2ecf20Sopenharmony_ci struct ib_event ev; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci ev.device = sqp->ibqp.device; 32588c2ecf20Sopenharmony_ci ev.element.qp = &sqp->ibqp; 32598c2ecf20Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 32608c2ecf20Sopenharmony_ci sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); 32618c2ecf20Sopenharmony_ci } 32628c2ecf20Sopenharmony_ci goto done; 32638c2ecf20Sopenharmony_ci } 32648c2ecf20Sopenharmony_ciclr_busy: 32658c2ecf20Sopenharmony_ci sqp->s_flags &= ~RVT_S_BUSY; 32668c2ecf20Sopenharmony_ciunlock: 32678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sqp->s_lock, flags); 32688c2ecf20Sopenharmony_cidone: 32698c2ecf20Sopenharmony_ci rcu_read_unlock(); 32708c2ecf20Sopenharmony_ci} 32718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rvt_ruc_loopback); 3272