162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright(c) 2016 - 2020 Intel Corporation. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/hash.h> 762306a36Sopenharmony_ci#include <linux/bitops.h> 862306a36Sopenharmony_ci#include <linux/lockdep.h> 962306a36Sopenharmony_ci#include <linux/vmalloc.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 1262306a36Sopenharmony_ci#include <rdma/ib_hdrs.h> 1362306a36Sopenharmony_ci#include <rdma/opa_addr.h> 1462306a36Sopenharmony_ci#include <rdma/uverbs_ioctl.h> 1562306a36Sopenharmony_ci#include "qp.h" 1662306a36Sopenharmony_ci#include "vt.h" 1762306a36Sopenharmony_ci#include "trace.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define RVT_RWQ_COUNT_THRESHOLD 16 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void rvt_rc_timeout(struct timer_list *t); 2262306a36Sopenharmony_cistatic void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 2362306a36Sopenharmony_ci enum ib_qp_type type); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Convert the AETH RNR timeout code into the number of microseconds. 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_cistatic const u32 ib_rvt_rnr_table[32] = { 2962306a36Sopenharmony_ci 655360, /* 00: 655.36 */ 3062306a36Sopenharmony_ci 10, /* 01: .01 */ 3162306a36Sopenharmony_ci 20, /* 02 .02 */ 3262306a36Sopenharmony_ci 30, /* 03: .03 */ 3362306a36Sopenharmony_ci 40, /* 04: .04 */ 3462306a36Sopenharmony_ci 60, /* 05: .06 */ 3562306a36Sopenharmony_ci 80, /* 06: .08 */ 3662306a36Sopenharmony_ci 120, /* 07: .12 */ 3762306a36Sopenharmony_ci 160, /* 08: .16 */ 3862306a36Sopenharmony_ci 240, /* 09: .24 */ 3962306a36Sopenharmony_ci 320, /* 0A: .32 */ 4062306a36Sopenharmony_ci 480, /* 0B: .48 */ 4162306a36Sopenharmony_ci 640, /* 0C: .64 */ 4262306a36Sopenharmony_ci 960, /* 0D: .96 */ 4362306a36Sopenharmony_ci 1280, /* 0E: 1.28 */ 4462306a36Sopenharmony_ci 1920, /* 0F: 1.92 */ 4562306a36Sopenharmony_ci 2560, /* 10: 2.56 */ 4662306a36Sopenharmony_ci 3840, /* 11: 3.84 */ 4762306a36Sopenharmony_ci 5120, /* 12: 5.12 */ 4862306a36Sopenharmony_ci 7680, /* 13: 7.68 */ 4962306a36Sopenharmony_ci 10240, /* 14: 10.24 */ 5062306a36Sopenharmony_ci 15360, /* 15: 15.36 */ 5162306a36Sopenharmony_ci 20480, /* 16: 20.48 */ 5262306a36Sopenharmony_ci 30720, /* 17: 30.72 */ 5362306a36Sopenharmony_ci 40960, /* 18: 40.96 */ 5462306a36Sopenharmony_ci 61440, /* 19: 61.44 */ 5562306a36Sopenharmony_ci 81920, /* 1A: 81.92 */ 5662306a36Sopenharmony_ci 122880, /* 1B: 122.88 */ 5762306a36Sopenharmony_ci 163840, /* 1C: 163.84 */ 5862306a36Sopenharmony_ci 245760, /* 1D: 245.76 */ 5962306a36Sopenharmony_ci 327680, /* 1E: 327.68 */ 6062306a36Sopenharmony_ci 491520 /* 1F: 491.52 */ 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * Note that it is OK to post send work requests in the SQE and ERR 6562306a36Sopenharmony_ci * states; rvt_do_send() will process them and generate error 6662306a36Sopenharmony_ci * completions as per IB 1.2 C10-96. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ciconst int ib_rvt_state_ops[IB_QPS_ERR + 1] = { 6962306a36Sopenharmony_ci [IB_QPS_RESET] = 0, 7062306a36Sopenharmony_ci [IB_QPS_INIT] = RVT_POST_RECV_OK, 7162306a36Sopenharmony_ci [IB_QPS_RTR] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK, 7262306a36Sopenharmony_ci [IB_QPS_RTS] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK | 7362306a36Sopenharmony_ci RVT_POST_SEND_OK | RVT_PROCESS_SEND_OK | 7462306a36Sopenharmony_ci RVT_PROCESS_NEXT_SEND_OK, 7562306a36Sopenharmony_ci [IB_QPS_SQD] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK | 7662306a36Sopenharmony_ci RVT_POST_SEND_OK | RVT_PROCESS_SEND_OK, 7762306a36Sopenharmony_ci [IB_QPS_SQE] = RVT_POST_RECV_OK | RVT_PROCESS_RECV_OK | 7862306a36Sopenharmony_ci RVT_POST_SEND_OK | RVT_FLUSH_SEND, 7962306a36Sopenharmony_ci [IB_QPS_ERR] = RVT_POST_RECV_OK | RVT_FLUSH_RECV | 8062306a36Sopenharmony_ci RVT_POST_SEND_OK | RVT_FLUSH_SEND, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ciEXPORT_SYMBOL(ib_rvt_state_ops); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* platform specific: return the last level cache (llc) size, in KiB */ 8562306a36Sopenharmony_cistatic int rvt_wss_llc_size(void) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci /* assume that the boot CPU value is universal for all CPUs */ 8862306a36Sopenharmony_ci return boot_cpu_data.x86_cache_size; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* platform specific: cacheless copy */ 9262306a36Sopenharmony_cistatic void cacheless_memcpy(void *dst, void *src, size_t n) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * Use the only available X64 cacheless copy. Add a __user cast 9662306a36Sopenharmony_ci * to quiet sparse. The src agument is already in the kernel so 9762306a36Sopenharmony_ci * there are no security issues. The extra fault recovery machinery 9862306a36Sopenharmony_ci * is not invoked. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci __copy_user_nocache(dst, (void __user *)src, n); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_civoid rvt_wss_exit(struct rvt_dev_info *rdi) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct rvt_wss *wss = rdi->wss; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (!wss) 10862306a36Sopenharmony_ci return; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* coded to handle partially initialized and repeat callers */ 11162306a36Sopenharmony_ci kfree(wss->entries); 11262306a36Sopenharmony_ci wss->entries = NULL; 11362306a36Sopenharmony_ci kfree(rdi->wss); 11462306a36Sopenharmony_ci rdi->wss = NULL; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * rvt_wss_init - Init wss data structures 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * Return: 0 on success 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ciint rvt_wss_init(struct rvt_dev_info *rdi) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode; 12562306a36Sopenharmony_ci unsigned int wss_threshold = rdi->dparms.wss_threshold; 12662306a36Sopenharmony_ci unsigned int wss_clean_period = rdi->dparms.wss_clean_period; 12762306a36Sopenharmony_ci long llc_size; 12862306a36Sopenharmony_ci long llc_bits; 12962306a36Sopenharmony_ci long table_size; 13062306a36Sopenharmony_ci long table_bits; 13162306a36Sopenharmony_ci struct rvt_wss *wss; 13262306a36Sopenharmony_ci int node = rdi->dparms.node; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (sge_copy_mode != RVT_SGE_COPY_ADAPTIVE) { 13562306a36Sopenharmony_ci rdi->wss = NULL; 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci rdi->wss = kzalloc_node(sizeof(*rdi->wss), GFP_KERNEL, node); 14062306a36Sopenharmony_ci if (!rdi->wss) 14162306a36Sopenharmony_ci return -ENOMEM; 14262306a36Sopenharmony_ci wss = rdi->wss; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* check for a valid percent range - default to 80 if none or invalid */ 14562306a36Sopenharmony_ci if (wss_threshold < 1 || wss_threshold > 100) 14662306a36Sopenharmony_ci wss_threshold = 80; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* reject a wildly large period */ 14962306a36Sopenharmony_ci if (wss_clean_period > 1000000) 15062306a36Sopenharmony_ci wss_clean_period = 256; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* reject a zero period */ 15362306a36Sopenharmony_ci if (wss_clean_period == 0) 15462306a36Sopenharmony_ci wss_clean_period = 1; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * Calculate the table size - the next power of 2 larger than the 15862306a36Sopenharmony_ci * LLC size. LLC size is in KiB. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci llc_size = rvt_wss_llc_size() * 1024; 16162306a36Sopenharmony_ci table_size = roundup_pow_of_two(llc_size); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* one bit per page in rounded up table */ 16462306a36Sopenharmony_ci llc_bits = llc_size / PAGE_SIZE; 16562306a36Sopenharmony_ci table_bits = table_size / PAGE_SIZE; 16662306a36Sopenharmony_ci wss->pages_mask = table_bits - 1; 16762306a36Sopenharmony_ci wss->num_entries = table_bits / BITS_PER_LONG; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci wss->threshold = (llc_bits * wss_threshold) / 100; 17062306a36Sopenharmony_ci if (wss->threshold == 0) 17162306a36Sopenharmony_ci wss->threshold = 1; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci wss->clean_period = wss_clean_period; 17462306a36Sopenharmony_ci atomic_set(&wss->clean_counter, wss_clean_period); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci wss->entries = kcalloc_node(wss->num_entries, sizeof(*wss->entries), 17762306a36Sopenharmony_ci GFP_KERNEL, node); 17862306a36Sopenharmony_ci if (!wss->entries) { 17962306a36Sopenharmony_ci rvt_wss_exit(rdi); 18062306a36Sopenharmony_ci return -ENOMEM; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * Advance the clean counter. When the clean period has expired, 18862306a36Sopenharmony_ci * clean an entry. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * This is implemented in atomics to avoid locking. Because multiple 19162306a36Sopenharmony_ci * variables are involved, it can be racy which can lead to slightly 19262306a36Sopenharmony_ci * inaccurate information. Since this is only a heuristic, this is 19362306a36Sopenharmony_ci * OK. Any innaccuracies will clean themselves out as the counter 19462306a36Sopenharmony_ci * advances. That said, it is unlikely the entry clean operation will 19562306a36Sopenharmony_ci * race - the next possible racer will not start until the next clean 19662306a36Sopenharmony_ci * period. 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * The clean counter is implemented as a decrement to zero. When zero 19962306a36Sopenharmony_ci * is reached an entry is cleaned. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic void wss_advance_clean_counter(struct rvt_wss *wss) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci int entry; 20462306a36Sopenharmony_ci int weight; 20562306a36Sopenharmony_ci unsigned long bits; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* become the cleaner if we decrement the counter to zero */ 20862306a36Sopenharmony_ci if (atomic_dec_and_test(&wss->clean_counter)) { 20962306a36Sopenharmony_ci /* 21062306a36Sopenharmony_ci * Set, not add, the clean period. This avoids an issue 21162306a36Sopenharmony_ci * where the counter could decrement below the clean period. 21262306a36Sopenharmony_ci * Doing a set can result in lost decrements, slowing the 21362306a36Sopenharmony_ci * clean advance. Since this a heuristic, this possible 21462306a36Sopenharmony_ci * slowdown is OK. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * An alternative is to loop, advancing the counter by a 21762306a36Sopenharmony_ci * clean period until the result is > 0. However, this could 21862306a36Sopenharmony_ci * lead to several threads keeping another in the clean loop. 21962306a36Sopenharmony_ci * This could be mitigated by limiting the number of times 22062306a36Sopenharmony_ci * we stay in the loop. 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci atomic_set(&wss->clean_counter, wss->clean_period); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* 22562306a36Sopenharmony_ci * Uniquely grab the entry to clean and move to next. 22662306a36Sopenharmony_ci * The current entry is always the lower bits of 22762306a36Sopenharmony_ci * wss.clean_entry. The table size, wss.num_entries, 22862306a36Sopenharmony_ci * is always a power-of-2. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci entry = (atomic_inc_return(&wss->clean_entry) - 1) 23162306a36Sopenharmony_ci & (wss->num_entries - 1); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* clear the entry and count the bits */ 23462306a36Sopenharmony_ci bits = xchg(&wss->entries[entry], 0); 23562306a36Sopenharmony_ci weight = hweight64((u64)bits); 23662306a36Sopenharmony_ci /* only adjust the contended total count if needed */ 23762306a36Sopenharmony_ci if (weight) 23862306a36Sopenharmony_ci atomic_sub(weight, &wss->total_count); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* 24362306a36Sopenharmony_ci * Insert the given address into the working set array. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_cistatic void wss_insert(struct rvt_wss *wss, void *address) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci u32 page = ((unsigned long)address >> PAGE_SHIFT) & wss->pages_mask; 24862306a36Sopenharmony_ci u32 entry = page / BITS_PER_LONG; /* assumes this ends up a shift */ 24962306a36Sopenharmony_ci u32 nr = page & (BITS_PER_LONG - 1); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!test_and_set_bit(nr, &wss->entries[entry])) 25262306a36Sopenharmony_ci atomic_inc(&wss->total_count); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci wss_advance_clean_counter(wss); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* 25862306a36Sopenharmony_ci * Is the working set larger than the threshold? 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistatic inline bool wss_exceeds_threshold(struct rvt_wss *wss) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci return atomic_read(&wss->total_count) >= wss->threshold; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic void get_map_page(struct rvt_qpn_table *qpt, 26662306a36Sopenharmony_ci struct rvt_qpn_map *map) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * Free the page if someone raced with us installing it. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci spin_lock(&qpt->lock); 27562306a36Sopenharmony_ci if (map->page) 27662306a36Sopenharmony_ci free_page(page); 27762306a36Sopenharmony_ci else 27862306a36Sopenharmony_ci map->page = (void *)page; 27962306a36Sopenharmony_ci spin_unlock(&qpt->lock); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/** 28362306a36Sopenharmony_ci * init_qpn_table - initialize the QP number table for a device 28462306a36Sopenharmony_ci * @rdi: rvt dev struct 28562306a36Sopenharmony_ci * @qpt: the QPN table 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_cistatic int init_qpn_table(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci u32 offset, i; 29062306a36Sopenharmony_ci struct rvt_qpn_map *map; 29162306a36Sopenharmony_ci int ret = 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (!(rdi->dparms.qpn_res_end >= rdi->dparms.qpn_res_start)) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci spin_lock_init(&qpt->lock); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci qpt->last = rdi->dparms.qpn_start; 29962306a36Sopenharmony_ci qpt->incr = rdi->dparms.qpn_inc << rdi->dparms.qos_shift; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* 30262306a36Sopenharmony_ci * Drivers may want some QPs beyond what we need for verbs let them use 30362306a36Sopenharmony_ci * our qpn table. No need for two. Lets go ahead and mark the bitmaps 30462306a36Sopenharmony_ci * for those. The reserved range must be *after* the range which verbs 30562306a36Sopenharmony_ci * will pick from. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Figure out number of bit maps needed before reserved range */ 30962306a36Sopenharmony_ci qpt->nmaps = rdi->dparms.qpn_res_start / RVT_BITS_PER_PAGE; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* This should always be zero */ 31262306a36Sopenharmony_ci offset = rdi->dparms.qpn_res_start & RVT_BITS_PER_PAGE_MASK; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* Starting with the first reserved bit map */ 31562306a36Sopenharmony_ci map = &qpt->map[qpt->nmaps]; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci rvt_pr_info(rdi, "Reserving QPNs from 0x%x to 0x%x for non-verbs use\n", 31862306a36Sopenharmony_ci rdi->dparms.qpn_res_start, rdi->dparms.qpn_res_end); 31962306a36Sopenharmony_ci for (i = rdi->dparms.qpn_res_start; i <= rdi->dparms.qpn_res_end; i++) { 32062306a36Sopenharmony_ci if (!map->page) { 32162306a36Sopenharmony_ci get_map_page(qpt, map); 32262306a36Sopenharmony_ci if (!map->page) { 32362306a36Sopenharmony_ci ret = -ENOMEM; 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci set_bit(offset, map->page); 32862306a36Sopenharmony_ci offset++; 32962306a36Sopenharmony_ci if (offset == RVT_BITS_PER_PAGE) { 33062306a36Sopenharmony_ci /* next page */ 33162306a36Sopenharmony_ci qpt->nmaps++; 33262306a36Sopenharmony_ci map++; 33362306a36Sopenharmony_ci offset = 0; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci return ret; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci/** 34062306a36Sopenharmony_ci * free_qpn_table - free the QP number table for a device 34162306a36Sopenharmony_ci * @qpt: the QPN table 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic void free_qpn_table(struct rvt_qpn_table *qpt) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci int i; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qpt->map); i++) 34862306a36Sopenharmony_ci free_page((unsigned long)qpt->map[i].page); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci/** 35262306a36Sopenharmony_ci * rvt_driver_qp_init - Init driver qp resources 35362306a36Sopenharmony_ci * @rdi: rvt dev strucutre 35462306a36Sopenharmony_ci * 35562306a36Sopenharmony_ci * Return: 0 on success 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ciint rvt_driver_qp_init(struct rvt_dev_info *rdi) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int i; 36062306a36Sopenharmony_ci int ret = -ENOMEM; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (!rdi->dparms.qp_table_size) 36362306a36Sopenharmony_ci return -EINVAL; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * If driver is not doing any QP allocation then make sure it is 36762306a36Sopenharmony_ci * providing the necessary QP functions. 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (!rdi->driver_f.free_all_qps || 37062306a36Sopenharmony_ci !rdi->driver_f.qp_priv_alloc || 37162306a36Sopenharmony_ci !rdi->driver_f.qp_priv_free || 37262306a36Sopenharmony_ci !rdi->driver_f.notify_qp_reset || 37362306a36Sopenharmony_ci !rdi->driver_f.notify_restart_rc) 37462306a36Sopenharmony_ci return -EINVAL; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* allocate parent object */ 37762306a36Sopenharmony_ci rdi->qp_dev = kzalloc_node(sizeof(*rdi->qp_dev), GFP_KERNEL, 37862306a36Sopenharmony_ci rdi->dparms.node); 37962306a36Sopenharmony_ci if (!rdi->qp_dev) 38062306a36Sopenharmony_ci return -ENOMEM; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* allocate hash table */ 38362306a36Sopenharmony_ci rdi->qp_dev->qp_table_size = rdi->dparms.qp_table_size; 38462306a36Sopenharmony_ci rdi->qp_dev->qp_table_bits = ilog2(rdi->dparms.qp_table_size); 38562306a36Sopenharmony_ci rdi->qp_dev->qp_table = 38662306a36Sopenharmony_ci kmalloc_array_node(rdi->qp_dev->qp_table_size, 38762306a36Sopenharmony_ci sizeof(*rdi->qp_dev->qp_table), 38862306a36Sopenharmony_ci GFP_KERNEL, rdi->dparms.node); 38962306a36Sopenharmony_ci if (!rdi->qp_dev->qp_table) 39062306a36Sopenharmony_ci goto no_qp_table; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci for (i = 0; i < rdi->qp_dev->qp_table_size; i++) 39362306a36Sopenharmony_ci RCU_INIT_POINTER(rdi->qp_dev->qp_table[i], NULL); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci spin_lock_init(&rdi->qp_dev->qpt_lock); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* initialize qpn map */ 39862306a36Sopenharmony_ci if (init_qpn_table(rdi, &rdi->qp_dev->qpn_table)) 39962306a36Sopenharmony_ci goto fail_table; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci spin_lock_init(&rdi->n_qps_lock); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cifail_table: 40662306a36Sopenharmony_ci kfree(rdi->qp_dev->qp_table); 40762306a36Sopenharmony_ci free_qpn_table(&rdi->qp_dev->qpn_table); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cino_qp_table: 41062306a36Sopenharmony_ci kfree(rdi->qp_dev); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci/** 41662306a36Sopenharmony_ci * rvt_free_qp_cb - callback function to reset a qp 41762306a36Sopenharmony_ci * @qp: the qp to reset 41862306a36Sopenharmony_ci * @v: a 64-bit value 41962306a36Sopenharmony_ci * 42062306a36Sopenharmony_ci * This function resets the qp and removes it from the 42162306a36Sopenharmony_ci * qp hash table. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_cistatic void rvt_free_qp_cb(struct rvt_qp *qp, u64 v) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci unsigned int *qp_inuse = (unsigned int *)v; 42662306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Reset the qp and remove it from the qp hash list */ 42962306a36Sopenharmony_ci rvt_reset_qp(rdi, qp, qp->ibqp.qp_type); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Increment the qp_inuse count */ 43262306a36Sopenharmony_ci (*qp_inuse)++; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/** 43662306a36Sopenharmony_ci * rvt_free_all_qps - check for QPs still in use 43762306a36Sopenharmony_ci * @rdi: rvt device info structure 43862306a36Sopenharmony_ci * 43962306a36Sopenharmony_ci * There should not be any QPs still in use. 44062306a36Sopenharmony_ci * Free memory for table. 44162306a36Sopenharmony_ci * Return the number of QPs still in use. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistatic unsigned rvt_free_all_qps(struct rvt_dev_info *rdi) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci unsigned int qp_inuse = 0; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci qp_inuse += rvt_mcast_tree_empty(rdi); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci rvt_qp_iter(rdi, (u64)&qp_inuse, rvt_free_qp_cb); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci return qp_inuse; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/** 45562306a36Sopenharmony_ci * rvt_qp_exit - clean up qps on device exit 45662306a36Sopenharmony_ci * @rdi: rvt dev structure 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * Check for qp leaks and free resources. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_civoid rvt_qp_exit(struct rvt_dev_info *rdi) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci u32 qps_inuse = rvt_free_all_qps(rdi); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci if (qps_inuse) 46562306a36Sopenharmony_ci rvt_pr_err(rdi, "QP memory leak! %u still in use\n", 46662306a36Sopenharmony_ci qps_inuse); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci kfree(rdi->qp_dev->qp_table); 46962306a36Sopenharmony_ci free_qpn_table(&rdi->qp_dev->qpn_table); 47062306a36Sopenharmony_ci kfree(rdi->qp_dev); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic inline unsigned mk_qpn(struct rvt_qpn_table *qpt, 47462306a36Sopenharmony_ci struct rvt_qpn_map *map, unsigned off) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci return (map - qpt->map) * RVT_BITS_PER_PAGE + off; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/** 48062306a36Sopenharmony_ci * alloc_qpn - Allocate the next available qpn or zero/one for QP type 48162306a36Sopenharmony_ci * IB_QPT_SMI/IB_QPT_GSI 48262306a36Sopenharmony_ci * @rdi: rvt device info structure 48362306a36Sopenharmony_ci * @qpt: queue pair number table pointer 48462306a36Sopenharmony_ci * @type: the QP type 48562306a36Sopenharmony_ci * @port_num: IB port number, 1 based, comes from core 48662306a36Sopenharmony_ci * @exclude_prefix: prefix of special queue pair number being allocated 48762306a36Sopenharmony_ci * 48862306a36Sopenharmony_ci * Return: The queue pair number 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_cistatic int alloc_qpn(struct rvt_dev_info *rdi, struct rvt_qpn_table *qpt, 49162306a36Sopenharmony_ci enum ib_qp_type type, u8 port_num, u8 exclude_prefix) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci u32 i, offset, max_scan, qpn; 49462306a36Sopenharmony_ci struct rvt_qpn_map *map; 49562306a36Sopenharmony_ci u32 ret; 49662306a36Sopenharmony_ci u32 max_qpn = exclude_prefix == RVT_AIP_QP_PREFIX ? 49762306a36Sopenharmony_ci RVT_AIP_QPN_MAX : RVT_QPN_MAX; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (rdi->driver_f.alloc_qpn) 50062306a36Sopenharmony_ci return rdi->driver_f.alloc_qpn(rdi, qpt, type, port_num); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (type == IB_QPT_SMI || type == IB_QPT_GSI) { 50362306a36Sopenharmony_ci unsigned n; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci ret = type == IB_QPT_GSI; 50662306a36Sopenharmony_ci n = 1 << (ret + 2 * (port_num - 1)); 50762306a36Sopenharmony_ci spin_lock(&qpt->lock); 50862306a36Sopenharmony_ci if (qpt->flags & n) 50962306a36Sopenharmony_ci ret = -EINVAL; 51062306a36Sopenharmony_ci else 51162306a36Sopenharmony_ci qpt->flags |= n; 51262306a36Sopenharmony_ci spin_unlock(&qpt->lock); 51362306a36Sopenharmony_ci goto bail; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci qpn = qpt->last + qpt->incr; 51762306a36Sopenharmony_ci if (qpn >= max_qpn) 51862306a36Sopenharmony_ci qpn = qpt->incr | ((qpt->last & 1) ^ 1); 51962306a36Sopenharmony_ci /* offset carries bit 0 */ 52062306a36Sopenharmony_ci offset = qpn & RVT_BITS_PER_PAGE_MASK; 52162306a36Sopenharmony_ci map = &qpt->map[qpn / RVT_BITS_PER_PAGE]; 52262306a36Sopenharmony_ci max_scan = qpt->nmaps - !offset; 52362306a36Sopenharmony_ci for (i = 0;;) { 52462306a36Sopenharmony_ci if (unlikely(!map->page)) { 52562306a36Sopenharmony_ci get_map_page(qpt, map); 52662306a36Sopenharmony_ci if (unlikely(!map->page)) 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci do { 53062306a36Sopenharmony_ci if (!test_and_set_bit(offset, map->page)) { 53162306a36Sopenharmony_ci qpt->last = qpn; 53262306a36Sopenharmony_ci ret = qpn; 53362306a36Sopenharmony_ci goto bail; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci offset += qpt->incr; 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * This qpn might be bogus if offset >= BITS_PER_PAGE. 53862306a36Sopenharmony_ci * That is OK. It gets re-assigned below 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ci qpn = mk_qpn(qpt, map, offset); 54162306a36Sopenharmony_ci } while (offset < RVT_BITS_PER_PAGE && qpn < RVT_QPN_MAX); 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * In order to keep the number of pages allocated to a 54462306a36Sopenharmony_ci * minimum, we scan the all existing pages before increasing 54562306a36Sopenharmony_ci * the size of the bitmap table. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci if (++i > max_scan) { 54862306a36Sopenharmony_ci if (qpt->nmaps == RVT_QPNMAP_ENTRIES) 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci map = &qpt->map[qpt->nmaps++]; 55162306a36Sopenharmony_ci /* start at incr with current bit 0 */ 55262306a36Sopenharmony_ci offset = qpt->incr | (offset & 1); 55362306a36Sopenharmony_ci } else if (map < &qpt->map[qpt->nmaps]) { 55462306a36Sopenharmony_ci ++map; 55562306a36Sopenharmony_ci /* start at incr with current bit 0 */ 55662306a36Sopenharmony_ci offset = qpt->incr | (offset & 1); 55762306a36Sopenharmony_ci } else { 55862306a36Sopenharmony_ci map = &qpt->map[0]; 55962306a36Sopenharmony_ci /* wrap to first map page, invert bit 0 */ 56062306a36Sopenharmony_ci offset = qpt->incr | ((offset & 1) ^ 1); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci /* there can be no set bits in low-order QoS bits */ 56362306a36Sopenharmony_ci WARN_ON(rdi->dparms.qos_shift > 1 && 56462306a36Sopenharmony_ci offset & ((BIT(rdi->dparms.qos_shift - 1) - 1) << 1)); 56562306a36Sopenharmony_ci qpn = mk_qpn(qpt, map, offset); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ret = -ENOMEM; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cibail: 57162306a36Sopenharmony_ci return ret; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/** 57562306a36Sopenharmony_ci * rvt_clear_mr_refs - Drop help mr refs 57662306a36Sopenharmony_ci * @qp: rvt qp data structure 57762306a36Sopenharmony_ci * @clr_sends: If shoudl clear send side or not 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_cistatic void rvt_clear_mr_refs(struct rvt_qp *qp, int clr_sends) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci unsigned n; 58262306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (test_and_clear_bit(RVT_R_REWIND_SGE, &qp->r_aflags)) 58562306a36Sopenharmony_ci rvt_put_ss(&qp->s_rdma_read_sge); 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (clr_sends) { 59062306a36Sopenharmony_ci while (qp->s_last != qp->s_head) { 59162306a36Sopenharmony_ci struct rvt_swqe *wqe = rvt_get_swqe_ptr(qp, qp->s_last); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci rvt_put_qp_swqe(qp, wqe); 59462306a36Sopenharmony_ci if (++qp->s_last >= qp->s_size) 59562306a36Sopenharmony_ci qp->s_last = 0; 59662306a36Sopenharmony_ci smp_wmb(); /* see qp_set_savail */ 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci if (qp->s_rdma_mr) { 59962306a36Sopenharmony_ci rvt_put_mr(qp->s_rdma_mr); 60062306a36Sopenharmony_ci qp->s_rdma_mr = NULL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci for (n = 0; qp->s_ack_queue && n < rvt_max_atomic(rdi); n++) { 60562306a36Sopenharmony_ci struct rvt_ack_entry *e = &qp->s_ack_queue[n]; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (e->rdma_sge.mr) { 60862306a36Sopenharmony_ci rvt_put_mr(e->rdma_sge.mr); 60962306a36Sopenharmony_ci e->rdma_sge.mr = NULL; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/** 61562306a36Sopenharmony_ci * rvt_swqe_has_lkey - return true if lkey is used by swqe 61662306a36Sopenharmony_ci * @wqe: the send wqe 61762306a36Sopenharmony_ci * @lkey: the lkey 61862306a36Sopenharmony_ci * 61962306a36Sopenharmony_ci * Test the swqe for using lkey 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_cistatic bool rvt_swqe_has_lkey(struct rvt_swqe *wqe, u32 lkey) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci int i; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci for (i = 0; i < wqe->wr.num_sge; i++) { 62662306a36Sopenharmony_ci struct rvt_sge *sge = &wqe->sg_list[i]; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (rvt_mr_has_lkey(sge->mr, lkey)) 62962306a36Sopenharmony_ci return true; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci return false; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci/** 63562306a36Sopenharmony_ci * rvt_qp_sends_has_lkey - return true is qp sends use lkey 63662306a36Sopenharmony_ci * @qp: the rvt_qp 63762306a36Sopenharmony_ci * @lkey: the lkey 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_cistatic bool rvt_qp_sends_has_lkey(struct rvt_qp *qp, u32 lkey) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci u32 s_last = qp->s_last; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci while (s_last != qp->s_head) { 64462306a36Sopenharmony_ci struct rvt_swqe *wqe = rvt_get_swqe_ptr(qp, s_last); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (rvt_swqe_has_lkey(wqe, lkey)) 64762306a36Sopenharmony_ci return true; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (++s_last >= qp->s_size) 65062306a36Sopenharmony_ci s_last = 0; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci if (qp->s_rdma_mr) 65362306a36Sopenharmony_ci if (rvt_mr_has_lkey(qp->s_rdma_mr, lkey)) 65462306a36Sopenharmony_ci return true; 65562306a36Sopenharmony_ci return false; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci/** 65962306a36Sopenharmony_ci * rvt_qp_acks_has_lkey - return true if acks have lkey 66062306a36Sopenharmony_ci * @qp: the qp 66162306a36Sopenharmony_ci * @lkey: the lkey 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_cistatic bool rvt_qp_acks_has_lkey(struct rvt_qp *qp, u32 lkey) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci int i; 66662306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for (i = 0; qp->s_ack_queue && i < rvt_max_atomic(rdi); i++) { 66962306a36Sopenharmony_ci struct rvt_ack_entry *e = &qp->s_ack_queue[i]; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (rvt_mr_has_lkey(e->rdma_sge.mr, lkey)) 67262306a36Sopenharmony_ci return true; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci return false; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci/** 67862306a36Sopenharmony_ci * rvt_qp_mr_clean - clean up remote ops for lkey 67962306a36Sopenharmony_ci * @qp: the qp 68062306a36Sopenharmony_ci * @lkey: the lkey that is being de-registered 68162306a36Sopenharmony_ci * 68262306a36Sopenharmony_ci * This routine checks if the lkey is being used by 68362306a36Sopenharmony_ci * the qp. 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * If so, the qp is put into an error state to elminate 68662306a36Sopenharmony_ci * any references from the qp. 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_civoid rvt_qp_mr_clean(struct rvt_qp *qp, u32 lkey) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci bool lastwqe = false; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_SMI || 69362306a36Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_GSI) 69462306a36Sopenharmony_ci /* avoid special QPs */ 69562306a36Sopenharmony_ci return; 69662306a36Sopenharmony_ci spin_lock_irq(&qp->r_lock); 69762306a36Sopenharmony_ci spin_lock(&qp->s_hlock); 69862306a36Sopenharmony_ci spin_lock(&qp->s_lock); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET) 70162306a36Sopenharmony_ci goto check_lwqe; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (rvt_ss_has_lkey(&qp->r_sge, lkey) || 70462306a36Sopenharmony_ci rvt_qp_sends_has_lkey(qp, lkey) || 70562306a36Sopenharmony_ci rvt_qp_acks_has_lkey(qp, lkey)) 70662306a36Sopenharmony_ci lastwqe = rvt_error_qp(qp, IB_WC_LOC_PROT_ERR); 70762306a36Sopenharmony_cicheck_lwqe: 70862306a36Sopenharmony_ci spin_unlock(&qp->s_lock); 70962306a36Sopenharmony_ci spin_unlock(&qp->s_hlock); 71062306a36Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 71162306a36Sopenharmony_ci if (lastwqe) { 71262306a36Sopenharmony_ci struct ib_event ev; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci ev.device = qp->ibqp.device; 71562306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 71662306a36Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 71762306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci/** 72262306a36Sopenharmony_ci * rvt_remove_qp - remove qp form table 72362306a36Sopenharmony_ci * @rdi: rvt dev struct 72462306a36Sopenharmony_ci * @qp: qp to remove 72562306a36Sopenharmony_ci * 72662306a36Sopenharmony_ci * Remove the QP from the table so it can't be found asynchronously by 72762306a36Sopenharmony_ci * the receive routine. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_cistatic void rvt_remove_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci struct rvt_ibport *rvp = rdi->ports[qp->port_num - 1]; 73262306a36Sopenharmony_ci u32 n = hash_32(qp->ibqp.qp_num, rdi->qp_dev->qp_table_bits); 73362306a36Sopenharmony_ci unsigned long flags; 73462306a36Sopenharmony_ci int removed = 1; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci spin_lock_irqsave(&rdi->qp_dev->qpt_lock, flags); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (rcu_dereference_protected(rvp->qp[0], 73962306a36Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock)) == qp) { 74062306a36Sopenharmony_ci RCU_INIT_POINTER(rvp->qp[0], NULL); 74162306a36Sopenharmony_ci } else if (rcu_dereference_protected(rvp->qp[1], 74262306a36Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock)) == qp) { 74362306a36Sopenharmony_ci RCU_INIT_POINTER(rvp->qp[1], NULL); 74462306a36Sopenharmony_ci } else { 74562306a36Sopenharmony_ci struct rvt_qp *q; 74662306a36Sopenharmony_ci struct rvt_qp __rcu **qpp; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci removed = 0; 74962306a36Sopenharmony_ci qpp = &rdi->qp_dev->qp_table[n]; 75062306a36Sopenharmony_ci for (; (q = rcu_dereference_protected(*qpp, 75162306a36Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock))) != NULL; 75262306a36Sopenharmony_ci qpp = &q->next) { 75362306a36Sopenharmony_ci if (q == qp) { 75462306a36Sopenharmony_ci RCU_INIT_POINTER(*qpp, 75562306a36Sopenharmony_ci rcu_dereference_protected(qp->next, 75662306a36Sopenharmony_ci lockdep_is_held(&rdi->qp_dev->qpt_lock))); 75762306a36Sopenharmony_ci removed = 1; 75862306a36Sopenharmony_ci trace_rvt_qpremove(qp, n); 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci spin_unlock_irqrestore(&rdi->qp_dev->qpt_lock, flags); 76562306a36Sopenharmony_ci if (removed) { 76662306a36Sopenharmony_ci synchronize_rcu(); 76762306a36Sopenharmony_ci rvt_put_qp(qp); 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/** 77262306a36Sopenharmony_ci * rvt_alloc_rq - allocate memory for user or kernel buffer 77362306a36Sopenharmony_ci * @rq: receive queue data structure 77462306a36Sopenharmony_ci * @size: number of request queue entries 77562306a36Sopenharmony_ci * @node: The NUMA node 77662306a36Sopenharmony_ci * @udata: True if user data is available or not false 77762306a36Sopenharmony_ci * 77862306a36Sopenharmony_ci * Return: If memory allocation failed, return -ENONEM 77962306a36Sopenharmony_ci * This function is used by both shared receive 78062306a36Sopenharmony_ci * queues and non-shared receive queues to allocate 78162306a36Sopenharmony_ci * memory. 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_ciint rvt_alloc_rq(struct rvt_rq *rq, u32 size, int node, 78462306a36Sopenharmony_ci struct ib_udata *udata) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci if (udata) { 78762306a36Sopenharmony_ci rq->wq = vmalloc_user(sizeof(struct rvt_rwq) + size); 78862306a36Sopenharmony_ci if (!rq->wq) 78962306a36Sopenharmony_ci goto bail; 79062306a36Sopenharmony_ci /* need kwq with no buffers */ 79162306a36Sopenharmony_ci rq->kwq = kzalloc_node(sizeof(*rq->kwq), GFP_KERNEL, node); 79262306a36Sopenharmony_ci if (!rq->kwq) 79362306a36Sopenharmony_ci goto bail; 79462306a36Sopenharmony_ci rq->kwq->curr_wq = rq->wq->wq; 79562306a36Sopenharmony_ci } else { 79662306a36Sopenharmony_ci /* need kwq with buffers */ 79762306a36Sopenharmony_ci rq->kwq = 79862306a36Sopenharmony_ci vzalloc_node(sizeof(struct rvt_krwq) + size, node); 79962306a36Sopenharmony_ci if (!rq->kwq) 80062306a36Sopenharmony_ci goto bail; 80162306a36Sopenharmony_ci rq->kwq->curr_wq = rq->kwq->wq; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci spin_lock_init(&rq->kwq->p_lock); 80562306a36Sopenharmony_ci spin_lock_init(&rq->kwq->c_lock); 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_cibail: 80862306a36Sopenharmony_ci rvt_free_rq(rq); 80962306a36Sopenharmony_ci return -ENOMEM; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci/** 81362306a36Sopenharmony_ci * rvt_init_qp - initialize the QP state to the reset state 81462306a36Sopenharmony_ci * @rdi: rvt dev struct 81562306a36Sopenharmony_ci * @qp: the QP to init or reinit 81662306a36Sopenharmony_ci * @type: the QP type 81762306a36Sopenharmony_ci * 81862306a36Sopenharmony_ci * This function is called from both rvt_create_qp() and 81962306a36Sopenharmony_ci * rvt_reset_qp(). The difference is that the reset 82062306a36Sopenharmony_ci * patch the necessary locks to protect against concurent 82162306a36Sopenharmony_ci * access. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_cistatic void rvt_init_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 82462306a36Sopenharmony_ci enum ib_qp_type type) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci qp->remote_qpn = 0; 82762306a36Sopenharmony_ci qp->qkey = 0; 82862306a36Sopenharmony_ci qp->qp_access_flags = 0; 82962306a36Sopenharmony_ci qp->s_flags &= RVT_S_SIGNAL_REQ_WR; 83062306a36Sopenharmony_ci qp->s_hdrwords = 0; 83162306a36Sopenharmony_ci qp->s_wqe = NULL; 83262306a36Sopenharmony_ci qp->s_draining = 0; 83362306a36Sopenharmony_ci qp->s_next_psn = 0; 83462306a36Sopenharmony_ci qp->s_last_psn = 0; 83562306a36Sopenharmony_ci qp->s_sending_psn = 0; 83662306a36Sopenharmony_ci qp->s_sending_hpsn = 0; 83762306a36Sopenharmony_ci qp->s_psn = 0; 83862306a36Sopenharmony_ci qp->r_psn = 0; 83962306a36Sopenharmony_ci qp->r_msn = 0; 84062306a36Sopenharmony_ci if (type == IB_QPT_RC) { 84162306a36Sopenharmony_ci qp->s_state = IB_OPCODE_RC_SEND_LAST; 84262306a36Sopenharmony_ci qp->r_state = IB_OPCODE_RC_SEND_LAST; 84362306a36Sopenharmony_ci } else { 84462306a36Sopenharmony_ci qp->s_state = IB_OPCODE_UC_SEND_LAST; 84562306a36Sopenharmony_ci qp->r_state = IB_OPCODE_UC_SEND_LAST; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; 84862306a36Sopenharmony_ci qp->r_nak_state = 0; 84962306a36Sopenharmony_ci qp->r_aflags = 0; 85062306a36Sopenharmony_ci qp->r_flags = 0; 85162306a36Sopenharmony_ci qp->s_head = 0; 85262306a36Sopenharmony_ci qp->s_tail = 0; 85362306a36Sopenharmony_ci qp->s_cur = 0; 85462306a36Sopenharmony_ci qp->s_acked = 0; 85562306a36Sopenharmony_ci qp->s_last = 0; 85662306a36Sopenharmony_ci qp->s_ssn = 1; 85762306a36Sopenharmony_ci qp->s_lsn = 0; 85862306a36Sopenharmony_ci qp->s_mig_state = IB_MIG_MIGRATED; 85962306a36Sopenharmony_ci qp->r_head_ack_queue = 0; 86062306a36Sopenharmony_ci qp->s_tail_ack_queue = 0; 86162306a36Sopenharmony_ci qp->s_acked_ack_queue = 0; 86262306a36Sopenharmony_ci qp->s_num_rd_atomic = 0; 86362306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 86462306a36Sopenharmony_ci atomic_set(&qp->s_reserved_used, 0); 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci/** 86862306a36Sopenharmony_ci * _rvt_reset_qp - initialize the QP state to the reset state 86962306a36Sopenharmony_ci * @rdi: rvt dev struct 87062306a36Sopenharmony_ci * @qp: the QP to reset 87162306a36Sopenharmony_ci * @type: the QP type 87262306a36Sopenharmony_ci * 87362306a36Sopenharmony_ci * r_lock, s_hlock, and s_lock are required to be held by the caller 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_cistatic void _rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 87662306a36Sopenharmony_ci enum ib_qp_type type) 87762306a36Sopenharmony_ci __must_hold(&qp->s_lock) 87862306a36Sopenharmony_ci __must_hold(&qp->s_hlock) 87962306a36Sopenharmony_ci __must_hold(&qp->r_lock) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci lockdep_assert_held(&qp->r_lock); 88262306a36Sopenharmony_ci lockdep_assert_held(&qp->s_hlock); 88362306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 88462306a36Sopenharmony_ci if (qp->state != IB_QPS_RESET) { 88562306a36Sopenharmony_ci qp->state = IB_QPS_RESET; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Let drivers flush their waitlist */ 88862306a36Sopenharmony_ci rdi->driver_f.flush_qp_waiters(qp); 88962306a36Sopenharmony_ci rvt_stop_rc_timers(qp); 89062306a36Sopenharmony_ci qp->s_flags &= ~(RVT_S_TIMER | RVT_S_ANY_WAIT); 89162306a36Sopenharmony_ci spin_unlock(&qp->s_lock); 89262306a36Sopenharmony_ci spin_unlock(&qp->s_hlock); 89362306a36Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Stop the send queue and the retry timer */ 89662306a36Sopenharmony_ci rdi->driver_f.stop_send_queue(qp); 89762306a36Sopenharmony_ci rvt_del_timers_sync(qp); 89862306a36Sopenharmony_ci /* Wait for things to stop */ 89962306a36Sopenharmony_ci rdi->driver_f.quiesce_qp(qp); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* take qp out the hash and wait for it to be unused */ 90262306a36Sopenharmony_ci rvt_remove_qp(rdi, qp); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* grab the lock b/c it was locked at call time */ 90562306a36Sopenharmony_ci spin_lock_irq(&qp->r_lock); 90662306a36Sopenharmony_ci spin_lock(&qp->s_hlock); 90762306a36Sopenharmony_ci spin_lock(&qp->s_lock); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci rvt_clear_mr_refs(qp, 1); 91062306a36Sopenharmony_ci /* 91162306a36Sopenharmony_ci * Let the driver do any tear down or re-init it needs to for 91262306a36Sopenharmony_ci * a qp that has been reset 91362306a36Sopenharmony_ci */ 91462306a36Sopenharmony_ci rdi->driver_f.notify_qp_reset(qp); 91562306a36Sopenharmony_ci } 91662306a36Sopenharmony_ci rvt_init_qp(rdi, qp, type); 91762306a36Sopenharmony_ci lockdep_assert_held(&qp->r_lock); 91862306a36Sopenharmony_ci lockdep_assert_held(&qp->s_hlock); 91962306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/** 92362306a36Sopenharmony_ci * rvt_reset_qp - initialize the QP state to the reset state 92462306a36Sopenharmony_ci * @rdi: the device info 92562306a36Sopenharmony_ci * @qp: the QP to reset 92662306a36Sopenharmony_ci * @type: the QP type 92762306a36Sopenharmony_ci * 92862306a36Sopenharmony_ci * This is the wrapper function to acquire the r_lock, s_hlock, and s_lock 92962306a36Sopenharmony_ci * before calling _rvt_reset_qp(). 93062306a36Sopenharmony_ci */ 93162306a36Sopenharmony_cistatic void rvt_reset_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp, 93262306a36Sopenharmony_ci enum ib_qp_type type) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci spin_lock_irq(&qp->r_lock); 93562306a36Sopenharmony_ci spin_lock(&qp->s_hlock); 93662306a36Sopenharmony_ci spin_lock(&qp->s_lock); 93762306a36Sopenharmony_ci _rvt_reset_qp(rdi, qp, type); 93862306a36Sopenharmony_ci spin_unlock(&qp->s_lock); 93962306a36Sopenharmony_ci spin_unlock(&qp->s_hlock); 94062306a36Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/** 94462306a36Sopenharmony_ci * rvt_free_qpn - Free a qpn from the bit map 94562306a36Sopenharmony_ci * @qpt: QP table 94662306a36Sopenharmony_ci * @qpn: queue pair number to free 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_cistatic void rvt_free_qpn(struct rvt_qpn_table *qpt, u32 qpn) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct rvt_qpn_map *map; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if ((qpn & RVT_AIP_QP_PREFIX_MASK) == RVT_AIP_QP_BASE) 95362306a36Sopenharmony_ci qpn &= RVT_AIP_QP_SUFFIX; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci map = qpt->map + (qpn & RVT_QPN_MASK) / RVT_BITS_PER_PAGE; 95662306a36Sopenharmony_ci if (map->page) 95762306a36Sopenharmony_ci clear_bit(qpn & RVT_BITS_PER_PAGE_MASK, map->page); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci/** 96162306a36Sopenharmony_ci * get_allowed_ops - Given a QP type return the appropriate allowed OP 96262306a36Sopenharmony_ci * @type: valid, supported, QP type 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_cistatic u8 get_allowed_ops(enum ib_qp_type type) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci return type == IB_QPT_RC ? IB_OPCODE_RC : type == IB_QPT_UC ? 96762306a36Sopenharmony_ci IB_OPCODE_UC : IB_OPCODE_UD; 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci/** 97162306a36Sopenharmony_ci * free_ud_wq_attr - Clean up AH attribute cache for UD QPs 97262306a36Sopenharmony_ci * @qp: Valid QP with allowed_ops set 97362306a36Sopenharmony_ci * 97462306a36Sopenharmony_ci * The rvt_swqe data structure being used is a union, so this is 97562306a36Sopenharmony_ci * only valid for UD QPs. 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_cistatic void free_ud_wq_attr(struct rvt_qp *qp) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct rvt_swqe *wqe; 98062306a36Sopenharmony_ci int i; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci for (i = 0; qp->allowed_ops == IB_OPCODE_UD && i < qp->s_size; i++) { 98362306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, i); 98462306a36Sopenharmony_ci kfree(wqe->ud_wr.attr); 98562306a36Sopenharmony_ci wqe->ud_wr.attr = NULL; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci/** 99062306a36Sopenharmony_ci * alloc_ud_wq_attr - AH attribute cache for UD QPs 99162306a36Sopenharmony_ci * @qp: Valid QP with allowed_ops set 99262306a36Sopenharmony_ci * @node: Numa node for allocation 99362306a36Sopenharmony_ci * 99462306a36Sopenharmony_ci * The rvt_swqe data structure being used is a union, so this is 99562306a36Sopenharmony_ci * only valid for UD QPs. 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_cistatic int alloc_ud_wq_attr(struct rvt_qp *qp, int node) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci struct rvt_swqe *wqe; 100062306a36Sopenharmony_ci int i; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci for (i = 0; qp->allowed_ops == IB_OPCODE_UD && i < qp->s_size; i++) { 100362306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, i); 100462306a36Sopenharmony_ci wqe->ud_wr.attr = kzalloc_node(sizeof(*wqe->ud_wr.attr), 100562306a36Sopenharmony_ci GFP_KERNEL, node); 100662306a36Sopenharmony_ci if (!wqe->ud_wr.attr) { 100762306a36Sopenharmony_ci free_ud_wq_attr(qp); 100862306a36Sopenharmony_ci return -ENOMEM; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return 0; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci/** 101662306a36Sopenharmony_ci * rvt_create_qp - create a queue pair for a device 101762306a36Sopenharmony_ci * @ibqp: the queue pair 101862306a36Sopenharmony_ci * @init_attr: the attributes of the queue pair 101962306a36Sopenharmony_ci * @udata: user data for libibverbs.so 102062306a36Sopenharmony_ci * 102162306a36Sopenharmony_ci * Queue pair creation is mostly an rvt issue. However, drivers have their own 102262306a36Sopenharmony_ci * unique idea of what queue pair numbers mean. For instance there is a reserved 102362306a36Sopenharmony_ci * range for PSM. 102462306a36Sopenharmony_ci * 102562306a36Sopenharmony_ci * Return: 0 on success, otherwise returns an errno. 102662306a36Sopenharmony_ci * 102762306a36Sopenharmony_ci * Called by the ib_create_qp() core verbs function. 102862306a36Sopenharmony_ci */ 102962306a36Sopenharmony_ciint rvt_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr, 103062306a36Sopenharmony_ci struct ib_udata *udata) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 103362306a36Sopenharmony_ci int ret = -ENOMEM; 103462306a36Sopenharmony_ci struct rvt_swqe *swq = NULL; 103562306a36Sopenharmony_ci size_t sz; 103662306a36Sopenharmony_ci size_t sg_list_sz = 0; 103762306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 103862306a36Sopenharmony_ci void *priv = NULL; 103962306a36Sopenharmony_ci size_t sqsize; 104062306a36Sopenharmony_ci u8 exclude_prefix = 0; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (!rdi) 104362306a36Sopenharmony_ci return -EINVAL; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (init_attr->create_flags & ~IB_QP_CREATE_NETDEV_USE) 104662306a36Sopenharmony_ci return -EOPNOTSUPP; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (init_attr->cap.max_send_sge > rdi->dparms.props.max_send_sge || 104962306a36Sopenharmony_ci init_attr->cap.max_send_wr > rdi->dparms.props.max_qp_wr) 105062306a36Sopenharmony_ci return -EINVAL; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci /* Check receive queue parameters if no SRQ is specified. */ 105362306a36Sopenharmony_ci if (!init_attr->srq) { 105462306a36Sopenharmony_ci if (init_attr->cap.max_recv_sge > 105562306a36Sopenharmony_ci rdi->dparms.props.max_recv_sge || 105662306a36Sopenharmony_ci init_attr->cap.max_recv_wr > rdi->dparms.props.max_qp_wr) 105762306a36Sopenharmony_ci return -EINVAL; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (init_attr->cap.max_send_sge + 106062306a36Sopenharmony_ci init_attr->cap.max_send_wr + 106162306a36Sopenharmony_ci init_attr->cap.max_recv_sge + 106262306a36Sopenharmony_ci init_attr->cap.max_recv_wr == 0) 106362306a36Sopenharmony_ci return -EINVAL; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci sqsize = 106662306a36Sopenharmony_ci init_attr->cap.max_send_wr + 1 + 106762306a36Sopenharmony_ci rdi->dparms.reserved_operations; 106862306a36Sopenharmony_ci switch (init_attr->qp_type) { 106962306a36Sopenharmony_ci case IB_QPT_SMI: 107062306a36Sopenharmony_ci case IB_QPT_GSI: 107162306a36Sopenharmony_ci if (init_attr->port_num == 0 || 107262306a36Sopenharmony_ci init_attr->port_num > ibqp->device->phys_port_cnt) 107362306a36Sopenharmony_ci return -EINVAL; 107462306a36Sopenharmony_ci fallthrough; 107562306a36Sopenharmony_ci case IB_QPT_UC: 107662306a36Sopenharmony_ci case IB_QPT_RC: 107762306a36Sopenharmony_ci case IB_QPT_UD: 107862306a36Sopenharmony_ci sz = struct_size(swq, sg_list, init_attr->cap.max_send_sge); 107962306a36Sopenharmony_ci swq = vzalloc_node(array_size(sz, sqsize), rdi->dparms.node); 108062306a36Sopenharmony_ci if (!swq) 108162306a36Sopenharmony_ci return -ENOMEM; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (init_attr->srq) { 108462306a36Sopenharmony_ci struct rvt_srq *srq = ibsrq_to_rvtsrq(init_attr->srq); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (srq->rq.max_sge > 1) 108762306a36Sopenharmony_ci sg_list_sz = sizeof(*qp->r_sg_list) * 108862306a36Sopenharmony_ci (srq->rq.max_sge - 1); 108962306a36Sopenharmony_ci } else if (init_attr->cap.max_recv_sge > 1) 109062306a36Sopenharmony_ci sg_list_sz = sizeof(*qp->r_sg_list) * 109162306a36Sopenharmony_ci (init_attr->cap.max_recv_sge - 1); 109262306a36Sopenharmony_ci qp->r_sg_list = 109362306a36Sopenharmony_ci kzalloc_node(sg_list_sz, GFP_KERNEL, rdi->dparms.node); 109462306a36Sopenharmony_ci if (!qp->r_sg_list) 109562306a36Sopenharmony_ci goto bail_qp; 109662306a36Sopenharmony_ci qp->allowed_ops = get_allowed_ops(init_attr->qp_type); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci RCU_INIT_POINTER(qp->next, NULL); 109962306a36Sopenharmony_ci if (init_attr->qp_type == IB_QPT_RC) { 110062306a36Sopenharmony_ci qp->s_ack_queue = 110162306a36Sopenharmony_ci kcalloc_node(rvt_max_atomic(rdi), 110262306a36Sopenharmony_ci sizeof(*qp->s_ack_queue), 110362306a36Sopenharmony_ci GFP_KERNEL, 110462306a36Sopenharmony_ci rdi->dparms.node); 110562306a36Sopenharmony_ci if (!qp->s_ack_queue) 110662306a36Sopenharmony_ci goto bail_qp; 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci /* initialize timers needed for rc qp */ 110962306a36Sopenharmony_ci timer_setup(&qp->s_timer, rvt_rc_timeout, 0); 111062306a36Sopenharmony_ci hrtimer_init(&qp->s_rnr_timer, CLOCK_MONOTONIC, 111162306a36Sopenharmony_ci HRTIMER_MODE_REL); 111262306a36Sopenharmony_ci qp->s_rnr_timer.function = rvt_rc_rnr_retry; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci /* 111562306a36Sopenharmony_ci * Driver needs to set up it's private QP structure and do any 111662306a36Sopenharmony_ci * initialization that is needed. 111762306a36Sopenharmony_ci */ 111862306a36Sopenharmony_ci priv = rdi->driver_f.qp_priv_alloc(rdi, qp); 111962306a36Sopenharmony_ci if (IS_ERR(priv)) { 112062306a36Sopenharmony_ci ret = PTR_ERR(priv); 112162306a36Sopenharmony_ci goto bail_qp; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci qp->priv = priv; 112462306a36Sopenharmony_ci qp->timeout_jiffies = 112562306a36Sopenharmony_ci usecs_to_jiffies((4096UL * (1UL << qp->timeout)) / 112662306a36Sopenharmony_ci 1000UL); 112762306a36Sopenharmony_ci if (init_attr->srq) { 112862306a36Sopenharmony_ci sz = 0; 112962306a36Sopenharmony_ci } else { 113062306a36Sopenharmony_ci qp->r_rq.size = init_attr->cap.max_recv_wr + 1; 113162306a36Sopenharmony_ci qp->r_rq.max_sge = init_attr->cap.max_recv_sge; 113262306a36Sopenharmony_ci sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) + 113362306a36Sopenharmony_ci sizeof(struct rvt_rwqe); 113462306a36Sopenharmony_ci ret = rvt_alloc_rq(&qp->r_rq, qp->r_rq.size * sz, 113562306a36Sopenharmony_ci rdi->dparms.node, udata); 113662306a36Sopenharmony_ci if (ret) 113762306a36Sopenharmony_ci goto bail_driver_priv; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* 114162306a36Sopenharmony_ci * ib_create_qp() will initialize qp->ibqp 114262306a36Sopenharmony_ci * except for qp->ibqp.qp_num. 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci spin_lock_init(&qp->r_lock); 114562306a36Sopenharmony_ci spin_lock_init(&qp->s_hlock); 114662306a36Sopenharmony_ci spin_lock_init(&qp->s_lock); 114762306a36Sopenharmony_ci atomic_set(&qp->refcount, 0); 114862306a36Sopenharmony_ci atomic_set(&qp->local_ops_pending, 0); 114962306a36Sopenharmony_ci init_waitqueue_head(&qp->wait); 115062306a36Sopenharmony_ci INIT_LIST_HEAD(&qp->rspwait); 115162306a36Sopenharmony_ci qp->state = IB_QPS_RESET; 115262306a36Sopenharmony_ci qp->s_wq = swq; 115362306a36Sopenharmony_ci qp->s_size = sqsize; 115462306a36Sopenharmony_ci qp->s_avail = init_attr->cap.max_send_wr; 115562306a36Sopenharmony_ci qp->s_max_sge = init_attr->cap.max_send_sge; 115662306a36Sopenharmony_ci if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR) 115762306a36Sopenharmony_ci qp->s_flags = RVT_S_SIGNAL_REQ_WR; 115862306a36Sopenharmony_ci ret = alloc_ud_wq_attr(qp, rdi->dparms.node); 115962306a36Sopenharmony_ci if (ret) 116062306a36Sopenharmony_ci goto bail_rq_rvt; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (init_attr->create_flags & IB_QP_CREATE_NETDEV_USE) 116362306a36Sopenharmony_ci exclude_prefix = RVT_AIP_QP_PREFIX; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci ret = alloc_qpn(rdi, &rdi->qp_dev->qpn_table, 116662306a36Sopenharmony_ci init_attr->qp_type, 116762306a36Sopenharmony_ci init_attr->port_num, 116862306a36Sopenharmony_ci exclude_prefix); 116962306a36Sopenharmony_ci if (ret < 0) 117062306a36Sopenharmony_ci goto bail_rq_wq; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci qp->ibqp.qp_num = ret; 117362306a36Sopenharmony_ci if (init_attr->create_flags & IB_QP_CREATE_NETDEV_USE) 117462306a36Sopenharmony_ci qp->ibqp.qp_num |= RVT_AIP_QP_BASE; 117562306a36Sopenharmony_ci qp->port_num = init_attr->port_num; 117662306a36Sopenharmony_ci rvt_init_qp(rdi, qp, init_attr->qp_type); 117762306a36Sopenharmony_ci if (rdi->driver_f.qp_priv_init) { 117862306a36Sopenharmony_ci ret = rdi->driver_f.qp_priv_init(rdi, qp, init_attr); 117962306a36Sopenharmony_ci if (ret) 118062306a36Sopenharmony_ci goto bail_rq_wq; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci default: 118562306a36Sopenharmony_ci /* Don't support raw QPs */ 118662306a36Sopenharmony_ci return -EOPNOTSUPP; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci init_attr->cap.max_inline_data = 0; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* 119262306a36Sopenharmony_ci * Return the address of the RWQ as the offset to mmap. 119362306a36Sopenharmony_ci * See rvt_mmap() for details. 119462306a36Sopenharmony_ci */ 119562306a36Sopenharmony_ci if (udata && udata->outlen >= sizeof(__u64)) { 119662306a36Sopenharmony_ci if (!qp->r_rq.wq) { 119762306a36Sopenharmony_ci __u64 offset = 0; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci ret = ib_copy_to_udata(udata, &offset, 120062306a36Sopenharmony_ci sizeof(offset)); 120162306a36Sopenharmony_ci if (ret) 120262306a36Sopenharmony_ci goto bail_qpn; 120362306a36Sopenharmony_ci } else { 120462306a36Sopenharmony_ci u32 s = sizeof(struct rvt_rwq) + qp->r_rq.size * sz; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci qp->ip = rvt_create_mmap_info(rdi, s, udata, 120762306a36Sopenharmony_ci qp->r_rq.wq); 120862306a36Sopenharmony_ci if (IS_ERR(qp->ip)) { 120962306a36Sopenharmony_ci ret = PTR_ERR(qp->ip); 121062306a36Sopenharmony_ci goto bail_qpn; 121162306a36Sopenharmony_ci } 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ret = ib_copy_to_udata(udata, &qp->ip->offset, 121462306a36Sopenharmony_ci sizeof(qp->ip->offset)); 121562306a36Sopenharmony_ci if (ret) 121662306a36Sopenharmony_ci goto bail_ip; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci qp->pid = current->pid; 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci spin_lock(&rdi->n_qps_lock); 122262306a36Sopenharmony_ci if (rdi->n_qps_allocated == rdi->dparms.props.max_qp) { 122362306a36Sopenharmony_ci spin_unlock(&rdi->n_qps_lock); 122462306a36Sopenharmony_ci ret = -ENOMEM; 122562306a36Sopenharmony_ci goto bail_ip; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci rdi->n_qps_allocated++; 122962306a36Sopenharmony_ci /* 123062306a36Sopenharmony_ci * Maintain a busy_jiffies variable that will be added to the timeout 123162306a36Sopenharmony_ci * period in mod_retry_timer and add_retry_timer. This busy jiffies 123262306a36Sopenharmony_ci * is scaled by the number of rc qps created for the device to reduce 123362306a36Sopenharmony_ci * the number of timeouts occurring when there is a large number of 123462306a36Sopenharmony_ci * qps. busy_jiffies is incremented every rc qp scaling interval. 123562306a36Sopenharmony_ci * The scaling interval is selected based on extensive performance 123662306a36Sopenharmony_ci * evaluation of targeted workloads. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_ci if (init_attr->qp_type == IB_QPT_RC) { 123962306a36Sopenharmony_ci rdi->n_rc_qps++; 124062306a36Sopenharmony_ci rdi->busy_jiffies = rdi->n_rc_qps / RC_QP_SCALING_INTERVAL; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci spin_unlock(&rdi->n_qps_lock); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (qp->ip) { 124562306a36Sopenharmony_ci spin_lock_irq(&rdi->pending_lock); 124662306a36Sopenharmony_ci list_add(&qp->ip->pending_mmaps, &rdi->pending_mmaps); 124762306a36Sopenharmony_ci spin_unlock_irq(&rdi->pending_lock); 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci return 0; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cibail_ip: 125362306a36Sopenharmony_ci if (qp->ip) 125462306a36Sopenharmony_ci kref_put(&qp->ip->ref, rvt_release_mmap_info); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cibail_qpn: 125762306a36Sopenharmony_ci rvt_free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cibail_rq_wq: 126062306a36Sopenharmony_ci free_ud_wq_attr(qp); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cibail_rq_rvt: 126362306a36Sopenharmony_ci rvt_free_rq(&qp->r_rq); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cibail_driver_priv: 126662306a36Sopenharmony_ci rdi->driver_f.qp_priv_free(rdi, qp); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cibail_qp: 126962306a36Sopenharmony_ci kfree(qp->s_ack_queue); 127062306a36Sopenharmony_ci kfree(qp->r_sg_list); 127162306a36Sopenharmony_ci vfree(swq); 127262306a36Sopenharmony_ci return ret; 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci/** 127662306a36Sopenharmony_ci * rvt_error_qp - put a QP into the error state 127762306a36Sopenharmony_ci * @qp: the QP to put into the error state 127862306a36Sopenharmony_ci * @err: the receive completion error to signal if a RWQE is active 127962306a36Sopenharmony_ci * 128062306a36Sopenharmony_ci * Flushes both send and receive work queues. 128162306a36Sopenharmony_ci * 128262306a36Sopenharmony_ci * Return: true if last WQE event should be generated. 128362306a36Sopenharmony_ci * The QP r_lock and s_lock should be held and interrupts disabled. 128462306a36Sopenharmony_ci * If we are already in error state, just return. 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_ciint rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci struct ib_wc wc; 128962306a36Sopenharmony_ci int ret = 0; 129062306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci lockdep_assert_held(&qp->r_lock); 129362306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 129462306a36Sopenharmony_ci if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET) 129562306a36Sopenharmony_ci goto bail; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci qp->state = IB_QPS_ERR; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) { 130062306a36Sopenharmony_ci qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR); 130162306a36Sopenharmony_ci del_timer(&qp->s_timer); 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (qp->s_flags & RVT_S_ANY_WAIT_SEND) 130562306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_ANY_WAIT_SEND; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci rdi->driver_f.notify_error_qp(qp); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* Schedule the sending tasklet to drain the send work queue. */ 131062306a36Sopenharmony_ci if (READ_ONCE(qp->s_last) != qp->s_head) 131162306a36Sopenharmony_ci rdi->driver_f.schedule_send(qp); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci rvt_clear_mr_refs(qp, 0); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 131662306a36Sopenharmony_ci wc.qp = &qp->ibqp; 131762306a36Sopenharmony_ci wc.opcode = IB_WC_RECV; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) { 132062306a36Sopenharmony_ci wc.wr_id = qp->r_wr_id; 132162306a36Sopenharmony_ci wc.status = err; 132262306a36Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci wc.status = IB_WC_WR_FLUSH_ERR; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (qp->r_rq.kwq) { 132762306a36Sopenharmony_ci u32 head; 132862306a36Sopenharmony_ci u32 tail; 132962306a36Sopenharmony_ci struct rvt_rwq *wq = NULL; 133062306a36Sopenharmony_ci struct rvt_krwq *kwq = NULL; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci spin_lock(&qp->r_rq.kwq->c_lock); 133362306a36Sopenharmony_ci /* qp->ip used to validate if there is a user buffer mmaped */ 133462306a36Sopenharmony_ci if (qp->ip) { 133562306a36Sopenharmony_ci wq = qp->r_rq.wq; 133662306a36Sopenharmony_ci head = RDMA_READ_UAPI_ATOMIC(wq->head); 133762306a36Sopenharmony_ci tail = RDMA_READ_UAPI_ATOMIC(wq->tail); 133862306a36Sopenharmony_ci } else { 133962306a36Sopenharmony_ci kwq = qp->r_rq.kwq; 134062306a36Sopenharmony_ci head = kwq->head; 134162306a36Sopenharmony_ci tail = kwq->tail; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci /* sanity check pointers before trusting them */ 134462306a36Sopenharmony_ci if (head >= qp->r_rq.size) 134562306a36Sopenharmony_ci head = 0; 134662306a36Sopenharmony_ci if (tail >= qp->r_rq.size) 134762306a36Sopenharmony_ci tail = 0; 134862306a36Sopenharmony_ci while (tail != head) { 134962306a36Sopenharmony_ci wc.wr_id = rvt_get_rwqe_ptr(&qp->r_rq, tail)->wr_id; 135062306a36Sopenharmony_ci if (++tail >= qp->r_rq.size) 135162306a36Sopenharmony_ci tail = 0; 135262306a36Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci if (qp->ip) 135562306a36Sopenharmony_ci RDMA_WRITE_UAPI_ATOMIC(wq->tail, tail); 135662306a36Sopenharmony_ci else 135762306a36Sopenharmony_ci kwq->tail = tail; 135862306a36Sopenharmony_ci spin_unlock(&qp->r_rq.kwq->c_lock); 135962306a36Sopenharmony_ci } else if (qp->ibqp.event_handler) { 136062306a36Sopenharmony_ci ret = 1; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cibail: 136462306a36Sopenharmony_ci return ret; 136562306a36Sopenharmony_ci} 136662306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_error_qp); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci/* 136962306a36Sopenharmony_ci * Put the QP into the hash table. 137062306a36Sopenharmony_ci * The hash table holds a reference to the QP. 137162306a36Sopenharmony_ci */ 137262306a36Sopenharmony_cistatic void rvt_insert_qp(struct rvt_dev_info *rdi, struct rvt_qp *qp) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci struct rvt_ibport *rvp = rdi->ports[qp->port_num - 1]; 137562306a36Sopenharmony_ci unsigned long flags; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci rvt_get_qp(qp); 137862306a36Sopenharmony_ci spin_lock_irqsave(&rdi->qp_dev->qpt_lock, flags); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci if (qp->ibqp.qp_num <= 1) { 138162306a36Sopenharmony_ci rcu_assign_pointer(rvp->qp[qp->ibqp.qp_num], qp); 138262306a36Sopenharmony_ci } else { 138362306a36Sopenharmony_ci u32 n = hash_32(qp->ibqp.qp_num, rdi->qp_dev->qp_table_bits); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci qp->next = rdi->qp_dev->qp_table[n]; 138662306a36Sopenharmony_ci rcu_assign_pointer(rdi->qp_dev->qp_table[n], qp); 138762306a36Sopenharmony_ci trace_rvt_qpinsert(qp, n); 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci spin_unlock_irqrestore(&rdi->qp_dev->qpt_lock, flags); 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci/** 139462306a36Sopenharmony_ci * rvt_modify_qp - modify the attributes of a queue pair 139562306a36Sopenharmony_ci * @ibqp: the queue pair who's attributes we're modifying 139662306a36Sopenharmony_ci * @attr: the new attributes 139762306a36Sopenharmony_ci * @attr_mask: the mask of attributes to modify 139862306a36Sopenharmony_ci * @udata: user data for libibverbs.so 139962306a36Sopenharmony_ci * 140062306a36Sopenharmony_ci * Return: 0 on success, otherwise returns an errno. 140162306a36Sopenharmony_ci */ 140262306a36Sopenharmony_ciint rvt_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 140362306a36Sopenharmony_ci int attr_mask, struct ib_udata *udata) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 140662306a36Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 140762306a36Sopenharmony_ci enum ib_qp_state cur_state, new_state; 140862306a36Sopenharmony_ci struct ib_event ev; 140962306a36Sopenharmony_ci int lastwqe = 0; 141062306a36Sopenharmony_ci int mig = 0; 141162306a36Sopenharmony_ci int pmtu = 0; /* for gcc warning only */ 141262306a36Sopenharmony_ci int opa_ah; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (attr_mask & ~IB_QP_ATTR_STANDARD_BITS) 141562306a36Sopenharmony_ci return -EOPNOTSUPP; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci spin_lock_irq(&qp->r_lock); 141862306a36Sopenharmony_ci spin_lock(&qp->s_hlock); 141962306a36Sopenharmony_ci spin_lock(&qp->s_lock); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci cur_state = attr_mask & IB_QP_CUR_STATE ? 142262306a36Sopenharmony_ci attr->cur_qp_state : qp->state; 142362306a36Sopenharmony_ci new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; 142462306a36Sopenharmony_ci opa_ah = rdma_cap_opa_ah(ibqp->device, qp->port_num); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, 142762306a36Sopenharmony_ci attr_mask)) 142862306a36Sopenharmony_ci goto inval; 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci if (rdi->driver_f.check_modify_qp && 143162306a36Sopenharmony_ci rdi->driver_f.check_modify_qp(qp, attr, attr_mask, udata)) 143262306a36Sopenharmony_ci goto inval; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (attr_mask & IB_QP_AV) { 143562306a36Sopenharmony_ci if (opa_ah) { 143662306a36Sopenharmony_ci if (rdma_ah_get_dlid(&attr->ah_attr) >= 143762306a36Sopenharmony_ci opa_get_mcast_base(OPA_MCAST_NR)) 143862306a36Sopenharmony_ci goto inval; 143962306a36Sopenharmony_ci } else { 144062306a36Sopenharmony_ci if (rdma_ah_get_dlid(&attr->ah_attr) >= 144162306a36Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE)) 144262306a36Sopenharmony_ci goto inval; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci if (rvt_check_ah(qp->ibqp.device, &attr->ah_attr)) 144662306a36Sopenharmony_ci goto inval; 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) { 145062306a36Sopenharmony_ci if (opa_ah) { 145162306a36Sopenharmony_ci if (rdma_ah_get_dlid(&attr->alt_ah_attr) >= 145262306a36Sopenharmony_ci opa_get_mcast_base(OPA_MCAST_NR)) 145362306a36Sopenharmony_ci goto inval; 145462306a36Sopenharmony_ci } else { 145562306a36Sopenharmony_ci if (rdma_ah_get_dlid(&attr->alt_ah_attr) >= 145662306a36Sopenharmony_ci be16_to_cpu(IB_MULTICAST_LID_BASE)) 145762306a36Sopenharmony_ci goto inval; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if (rvt_check_ah(qp->ibqp.device, &attr->alt_ah_attr)) 146162306a36Sopenharmony_ci goto inval; 146262306a36Sopenharmony_ci if (attr->alt_pkey_index >= rvt_get_npkeys(rdi)) 146362306a36Sopenharmony_ci goto inval; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) 146762306a36Sopenharmony_ci if (attr->pkey_index >= rvt_get_npkeys(rdi)) 146862306a36Sopenharmony_ci goto inval; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) 147162306a36Sopenharmony_ci if (attr->min_rnr_timer > 31) 147262306a36Sopenharmony_ci goto inval; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (attr_mask & IB_QP_PORT) 147562306a36Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_SMI || 147662306a36Sopenharmony_ci qp->ibqp.qp_type == IB_QPT_GSI || 147762306a36Sopenharmony_ci attr->port_num == 0 || 147862306a36Sopenharmony_ci attr->port_num > ibqp->device->phys_port_cnt) 147962306a36Sopenharmony_ci goto inval; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if (attr_mask & IB_QP_DEST_QPN) 148262306a36Sopenharmony_ci if (attr->dest_qp_num > RVT_QPN_MASK) 148362306a36Sopenharmony_ci goto inval; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci if (attr_mask & IB_QP_RETRY_CNT) 148662306a36Sopenharmony_ci if (attr->retry_cnt > 7) 148762306a36Sopenharmony_ci goto inval; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (attr_mask & IB_QP_RNR_RETRY) 149062306a36Sopenharmony_ci if (attr->rnr_retry > 7) 149162306a36Sopenharmony_ci goto inval; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* 149462306a36Sopenharmony_ci * Don't allow invalid path_mtu values. OK to set greater 149562306a36Sopenharmony_ci * than the active mtu (or even the max_cap, if we have tuned 149662306a36Sopenharmony_ci * that to a small mtu. We'll set qp->path_mtu 149762306a36Sopenharmony_ci * to the lesser of requested attribute mtu and active, 149862306a36Sopenharmony_ci * for packetizing messages. 149962306a36Sopenharmony_ci * Note that the QP port has to be set in INIT and MTU in RTR. 150062306a36Sopenharmony_ci */ 150162306a36Sopenharmony_ci if (attr_mask & IB_QP_PATH_MTU) { 150262306a36Sopenharmony_ci pmtu = rdi->driver_f.get_pmtu_from_attr(rdi, qp, attr); 150362306a36Sopenharmony_ci if (pmtu < 0) 150462306a36Sopenharmony_ci goto inval; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (attr_mask & IB_QP_PATH_MIG_STATE) { 150862306a36Sopenharmony_ci if (attr->path_mig_state == IB_MIG_REARM) { 150962306a36Sopenharmony_ci if (qp->s_mig_state == IB_MIG_ARMED) 151062306a36Sopenharmony_ci goto inval; 151162306a36Sopenharmony_ci if (new_state != IB_QPS_RTS) 151262306a36Sopenharmony_ci goto inval; 151362306a36Sopenharmony_ci } else if (attr->path_mig_state == IB_MIG_MIGRATED) { 151462306a36Sopenharmony_ci if (qp->s_mig_state == IB_MIG_REARM) 151562306a36Sopenharmony_ci goto inval; 151662306a36Sopenharmony_ci if (new_state != IB_QPS_RTS && new_state != IB_QPS_SQD) 151762306a36Sopenharmony_ci goto inval; 151862306a36Sopenharmony_ci if (qp->s_mig_state == IB_MIG_ARMED) 151962306a36Sopenharmony_ci mig = 1; 152062306a36Sopenharmony_ci } else { 152162306a36Sopenharmony_ci goto inval; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 152662306a36Sopenharmony_ci if (attr->max_dest_rd_atomic > rdi->dparms.max_rdma_atomic) 152762306a36Sopenharmony_ci goto inval; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci switch (new_state) { 153062306a36Sopenharmony_ci case IB_QPS_RESET: 153162306a36Sopenharmony_ci if (qp->state != IB_QPS_RESET) 153262306a36Sopenharmony_ci _rvt_reset_qp(rdi, qp, ibqp->qp_type); 153362306a36Sopenharmony_ci break; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci case IB_QPS_RTR: 153662306a36Sopenharmony_ci /* Allow event to re-trigger if QP set to RTR more than once */ 153762306a36Sopenharmony_ci qp->r_flags &= ~RVT_R_COMM_EST; 153862306a36Sopenharmony_ci qp->state = new_state; 153962306a36Sopenharmony_ci break; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci case IB_QPS_SQD: 154262306a36Sopenharmony_ci qp->s_draining = qp->s_last != qp->s_cur; 154362306a36Sopenharmony_ci qp->state = new_state; 154462306a36Sopenharmony_ci break; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci case IB_QPS_SQE: 154762306a36Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RC) 154862306a36Sopenharmony_ci goto inval; 154962306a36Sopenharmony_ci qp->state = new_state; 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci case IB_QPS_ERR: 155362306a36Sopenharmony_ci lastwqe = rvt_error_qp(qp, IB_WC_WR_FLUSH_ERR); 155462306a36Sopenharmony_ci break; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci default: 155762306a36Sopenharmony_ci qp->state = new_state; 155862306a36Sopenharmony_ci break; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if (attr_mask & IB_QP_PKEY_INDEX) 156262306a36Sopenharmony_ci qp->s_pkey_index = attr->pkey_index; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci if (attr_mask & IB_QP_PORT) 156562306a36Sopenharmony_ci qp->port_num = attr->port_num; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (attr_mask & IB_QP_DEST_QPN) 156862306a36Sopenharmony_ci qp->remote_qpn = attr->dest_qp_num; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (attr_mask & IB_QP_SQ_PSN) { 157162306a36Sopenharmony_ci qp->s_next_psn = attr->sq_psn & rdi->dparms.psn_modify_mask; 157262306a36Sopenharmony_ci qp->s_psn = qp->s_next_psn; 157362306a36Sopenharmony_ci qp->s_sending_psn = qp->s_next_psn; 157462306a36Sopenharmony_ci qp->s_last_psn = qp->s_next_psn - 1; 157562306a36Sopenharmony_ci qp->s_sending_hpsn = qp->s_last_psn; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci if (attr_mask & IB_QP_RQ_PSN) 157962306a36Sopenharmony_ci qp->r_psn = attr->rq_psn & rdi->dparms.psn_modify_mask; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (attr_mask & IB_QP_ACCESS_FLAGS) 158262306a36Sopenharmony_ci qp->qp_access_flags = attr->qp_access_flags; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci if (attr_mask & IB_QP_AV) { 158562306a36Sopenharmony_ci rdma_replace_ah_attr(&qp->remote_ah_attr, &attr->ah_attr); 158662306a36Sopenharmony_ci qp->s_srate = rdma_ah_get_static_rate(&attr->ah_attr); 158762306a36Sopenharmony_ci qp->srate_mbps = ib_rate_to_mbps(qp->s_srate); 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci if (attr_mask & IB_QP_ALT_PATH) { 159162306a36Sopenharmony_ci rdma_replace_ah_attr(&qp->alt_ah_attr, &attr->alt_ah_attr); 159262306a36Sopenharmony_ci qp->s_alt_pkey_index = attr->alt_pkey_index; 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (attr_mask & IB_QP_PATH_MIG_STATE) { 159662306a36Sopenharmony_ci qp->s_mig_state = attr->path_mig_state; 159762306a36Sopenharmony_ci if (mig) { 159862306a36Sopenharmony_ci qp->remote_ah_attr = qp->alt_ah_attr; 159962306a36Sopenharmony_ci qp->port_num = rdma_ah_get_port_num(&qp->alt_ah_attr); 160062306a36Sopenharmony_ci qp->s_pkey_index = qp->s_alt_pkey_index; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (attr_mask & IB_QP_PATH_MTU) { 160562306a36Sopenharmony_ci qp->pmtu = rdi->driver_f.mtu_from_qp(rdi, qp, pmtu); 160662306a36Sopenharmony_ci qp->log_pmtu = ilog2(qp->pmtu); 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci if (attr_mask & IB_QP_RETRY_CNT) { 161062306a36Sopenharmony_ci qp->s_retry_cnt = attr->retry_cnt; 161162306a36Sopenharmony_ci qp->s_retry = attr->retry_cnt; 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (attr_mask & IB_QP_RNR_RETRY) { 161562306a36Sopenharmony_ci qp->s_rnr_retry_cnt = attr->rnr_retry; 161662306a36Sopenharmony_ci qp->s_rnr_retry = attr->rnr_retry; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (attr_mask & IB_QP_MIN_RNR_TIMER) 162062306a36Sopenharmony_ci qp->r_min_rnr_timer = attr->min_rnr_timer; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci if (attr_mask & IB_QP_TIMEOUT) { 162362306a36Sopenharmony_ci qp->timeout = attr->timeout; 162462306a36Sopenharmony_ci qp->timeout_jiffies = rvt_timeout_to_jiffies(qp->timeout); 162562306a36Sopenharmony_ci } 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (attr_mask & IB_QP_QKEY) 162862306a36Sopenharmony_ci qp->qkey = attr->qkey; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) 163162306a36Sopenharmony_ci qp->r_max_rd_atomic = attr->max_dest_rd_atomic; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) 163462306a36Sopenharmony_ci qp->s_max_rd_atomic = attr->max_rd_atomic; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci if (rdi->driver_f.modify_qp) 163762306a36Sopenharmony_ci rdi->driver_f.modify_qp(qp, attr, attr_mask, udata); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci spin_unlock(&qp->s_lock); 164062306a36Sopenharmony_ci spin_unlock(&qp->s_hlock); 164162306a36Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) 164462306a36Sopenharmony_ci rvt_insert_qp(rdi, qp); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci if (lastwqe) { 164762306a36Sopenharmony_ci ev.device = qp->ibqp.device; 164862306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 164962306a36Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 165062306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 165162306a36Sopenharmony_ci } 165262306a36Sopenharmony_ci if (mig) { 165362306a36Sopenharmony_ci ev.device = qp->ibqp.device; 165462306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 165562306a36Sopenharmony_ci ev.event = IB_EVENT_PATH_MIG; 165662306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci return 0; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ciinval: 166162306a36Sopenharmony_ci spin_unlock(&qp->s_lock); 166262306a36Sopenharmony_ci spin_unlock(&qp->s_hlock); 166362306a36Sopenharmony_ci spin_unlock_irq(&qp->r_lock); 166462306a36Sopenharmony_ci return -EINVAL; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci/** 166862306a36Sopenharmony_ci * rvt_destroy_qp - destroy a queue pair 166962306a36Sopenharmony_ci * @ibqp: the queue pair to destroy 167062306a36Sopenharmony_ci * @udata: unused by the driver 167162306a36Sopenharmony_ci * 167262306a36Sopenharmony_ci * Note that this can be called while the QP is actively sending or 167362306a36Sopenharmony_ci * receiving! 167462306a36Sopenharmony_ci * 167562306a36Sopenharmony_ci * Return: 0 on success. 167662306a36Sopenharmony_ci */ 167762306a36Sopenharmony_ciint rvt_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) 167862306a36Sopenharmony_ci{ 167962306a36Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 168062306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci rvt_reset_qp(rdi, qp, ibqp->qp_type); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci wait_event(qp->wait, !atomic_read(&qp->refcount)); 168562306a36Sopenharmony_ci /* qpn is now available for use again */ 168662306a36Sopenharmony_ci rvt_free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num); 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci spin_lock(&rdi->n_qps_lock); 168962306a36Sopenharmony_ci rdi->n_qps_allocated--; 169062306a36Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_RC) { 169162306a36Sopenharmony_ci rdi->n_rc_qps--; 169262306a36Sopenharmony_ci rdi->busy_jiffies = rdi->n_rc_qps / RC_QP_SCALING_INTERVAL; 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci spin_unlock(&rdi->n_qps_lock); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (qp->ip) 169762306a36Sopenharmony_ci kref_put(&qp->ip->ref, rvt_release_mmap_info); 169862306a36Sopenharmony_ci kvfree(qp->r_rq.kwq); 169962306a36Sopenharmony_ci rdi->driver_f.qp_priv_free(rdi, qp); 170062306a36Sopenharmony_ci kfree(qp->s_ack_queue); 170162306a36Sopenharmony_ci kfree(qp->r_sg_list); 170262306a36Sopenharmony_ci rdma_destroy_ah_attr(&qp->remote_ah_attr); 170362306a36Sopenharmony_ci rdma_destroy_ah_attr(&qp->alt_ah_attr); 170462306a36Sopenharmony_ci free_ud_wq_attr(qp); 170562306a36Sopenharmony_ci vfree(qp->s_wq); 170662306a36Sopenharmony_ci return 0; 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci/** 171062306a36Sopenharmony_ci * rvt_query_qp - query an ipbq 171162306a36Sopenharmony_ci * @ibqp: IB qp to query 171262306a36Sopenharmony_ci * @attr: attr struct to fill in 171362306a36Sopenharmony_ci * @attr_mask: attr mask ignored 171462306a36Sopenharmony_ci * @init_attr: struct to fill in 171562306a36Sopenharmony_ci * 171662306a36Sopenharmony_ci * Return: always 0 171762306a36Sopenharmony_ci */ 171862306a36Sopenharmony_ciint rvt_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, 171962306a36Sopenharmony_ci int attr_mask, struct ib_qp_init_attr *init_attr) 172062306a36Sopenharmony_ci{ 172162306a36Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 172262306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci attr->qp_state = qp->state; 172562306a36Sopenharmony_ci attr->cur_qp_state = attr->qp_state; 172662306a36Sopenharmony_ci attr->path_mtu = rdi->driver_f.mtu_to_path_mtu(qp->pmtu); 172762306a36Sopenharmony_ci attr->path_mig_state = qp->s_mig_state; 172862306a36Sopenharmony_ci attr->qkey = qp->qkey; 172962306a36Sopenharmony_ci attr->rq_psn = qp->r_psn & rdi->dparms.psn_mask; 173062306a36Sopenharmony_ci attr->sq_psn = qp->s_next_psn & rdi->dparms.psn_mask; 173162306a36Sopenharmony_ci attr->dest_qp_num = qp->remote_qpn; 173262306a36Sopenharmony_ci attr->qp_access_flags = qp->qp_access_flags; 173362306a36Sopenharmony_ci attr->cap.max_send_wr = qp->s_size - 1 - 173462306a36Sopenharmony_ci rdi->dparms.reserved_operations; 173562306a36Sopenharmony_ci attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1; 173662306a36Sopenharmony_ci attr->cap.max_send_sge = qp->s_max_sge; 173762306a36Sopenharmony_ci attr->cap.max_recv_sge = qp->r_rq.max_sge; 173862306a36Sopenharmony_ci attr->cap.max_inline_data = 0; 173962306a36Sopenharmony_ci attr->ah_attr = qp->remote_ah_attr; 174062306a36Sopenharmony_ci attr->alt_ah_attr = qp->alt_ah_attr; 174162306a36Sopenharmony_ci attr->pkey_index = qp->s_pkey_index; 174262306a36Sopenharmony_ci attr->alt_pkey_index = qp->s_alt_pkey_index; 174362306a36Sopenharmony_ci attr->en_sqd_async_notify = 0; 174462306a36Sopenharmony_ci attr->sq_draining = qp->s_draining; 174562306a36Sopenharmony_ci attr->max_rd_atomic = qp->s_max_rd_atomic; 174662306a36Sopenharmony_ci attr->max_dest_rd_atomic = qp->r_max_rd_atomic; 174762306a36Sopenharmony_ci attr->min_rnr_timer = qp->r_min_rnr_timer; 174862306a36Sopenharmony_ci attr->port_num = qp->port_num; 174962306a36Sopenharmony_ci attr->timeout = qp->timeout; 175062306a36Sopenharmony_ci attr->retry_cnt = qp->s_retry_cnt; 175162306a36Sopenharmony_ci attr->rnr_retry = qp->s_rnr_retry_cnt; 175262306a36Sopenharmony_ci attr->alt_port_num = 175362306a36Sopenharmony_ci rdma_ah_get_port_num(&qp->alt_ah_attr); 175462306a36Sopenharmony_ci attr->alt_timeout = qp->alt_timeout; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci init_attr->event_handler = qp->ibqp.event_handler; 175762306a36Sopenharmony_ci init_attr->qp_context = qp->ibqp.qp_context; 175862306a36Sopenharmony_ci init_attr->send_cq = qp->ibqp.send_cq; 175962306a36Sopenharmony_ci init_attr->recv_cq = qp->ibqp.recv_cq; 176062306a36Sopenharmony_ci init_attr->srq = qp->ibqp.srq; 176162306a36Sopenharmony_ci init_attr->cap = attr->cap; 176262306a36Sopenharmony_ci if (qp->s_flags & RVT_S_SIGNAL_REQ_WR) 176362306a36Sopenharmony_ci init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; 176462306a36Sopenharmony_ci else 176562306a36Sopenharmony_ci init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; 176662306a36Sopenharmony_ci init_attr->qp_type = qp->ibqp.qp_type; 176762306a36Sopenharmony_ci init_attr->port_num = qp->port_num; 176862306a36Sopenharmony_ci return 0; 176962306a36Sopenharmony_ci} 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci/** 177262306a36Sopenharmony_ci * rvt_post_recv - post a receive on a QP 177362306a36Sopenharmony_ci * @ibqp: the QP to post the receive on 177462306a36Sopenharmony_ci * @wr: the WR to post 177562306a36Sopenharmony_ci * @bad_wr: the first bad WR is put here 177662306a36Sopenharmony_ci * 177762306a36Sopenharmony_ci * This may be called from interrupt context. 177862306a36Sopenharmony_ci * 177962306a36Sopenharmony_ci * Return: 0 on success otherwise errno 178062306a36Sopenharmony_ci */ 178162306a36Sopenharmony_ciint rvt_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 178262306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 178362306a36Sopenharmony_ci{ 178462306a36Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 178562306a36Sopenharmony_ci struct rvt_krwq *wq = qp->r_rq.kwq; 178662306a36Sopenharmony_ci unsigned long flags; 178762306a36Sopenharmony_ci int qp_err_flush = (ib_rvt_state_ops[qp->state] & RVT_FLUSH_RECV) && 178862306a36Sopenharmony_ci !qp->ibqp.srq; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* Check that state is OK to post receive. */ 179162306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_POST_RECV_OK) || !wq) { 179262306a36Sopenharmony_ci *bad_wr = wr; 179362306a36Sopenharmony_ci return -EINVAL; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci for (; wr; wr = wr->next) { 179762306a36Sopenharmony_ci struct rvt_rwqe *wqe; 179862306a36Sopenharmony_ci u32 next; 179962306a36Sopenharmony_ci int i; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if ((unsigned)wr->num_sge > qp->r_rq.max_sge) { 180262306a36Sopenharmony_ci *bad_wr = wr; 180362306a36Sopenharmony_ci return -EINVAL; 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci spin_lock_irqsave(&qp->r_rq.kwq->p_lock, flags); 180762306a36Sopenharmony_ci next = wq->head + 1; 180862306a36Sopenharmony_ci if (next >= qp->r_rq.size) 180962306a36Sopenharmony_ci next = 0; 181062306a36Sopenharmony_ci if (next == READ_ONCE(wq->tail)) { 181162306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_rq.kwq->p_lock, flags); 181262306a36Sopenharmony_ci *bad_wr = wr; 181362306a36Sopenharmony_ci return -ENOMEM; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci if (unlikely(qp_err_flush)) { 181662306a36Sopenharmony_ci struct ib_wc wc; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 181962306a36Sopenharmony_ci wc.qp = &qp->ibqp; 182062306a36Sopenharmony_ci wc.opcode = IB_WC_RECV; 182162306a36Sopenharmony_ci wc.wr_id = wr->wr_id; 182262306a36Sopenharmony_ci wc.status = IB_WC_WR_FLUSH_ERR; 182362306a36Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 182462306a36Sopenharmony_ci } else { 182562306a36Sopenharmony_ci wqe = rvt_get_rwqe_ptr(&qp->r_rq, wq->head); 182662306a36Sopenharmony_ci wqe->wr_id = wr->wr_id; 182762306a36Sopenharmony_ci wqe->num_sge = wr->num_sge; 182862306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 182962306a36Sopenharmony_ci wqe->sg_list[i].addr = wr->sg_list[i].addr; 183062306a36Sopenharmony_ci wqe->sg_list[i].length = wr->sg_list[i].length; 183162306a36Sopenharmony_ci wqe->sg_list[i].lkey = wr->sg_list[i].lkey; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci /* 183462306a36Sopenharmony_ci * Make sure queue entry is written 183562306a36Sopenharmony_ci * before the head index. 183662306a36Sopenharmony_ci */ 183762306a36Sopenharmony_ci smp_store_release(&wq->head, next); 183862306a36Sopenharmony_ci } 183962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_rq.kwq->p_lock, flags); 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci return 0; 184262306a36Sopenharmony_ci} 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci/** 184562306a36Sopenharmony_ci * rvt_qp_valid_operation - validate post send wr request 184662306a36Sopenharmony_ci * @qp: the qp 184762306a36Sopenharmony_ci * @post_parms: the post send table for the driver 184862306a36Sopenharmony_ci * @wr: the work request 184962306a36Sopenharmony_ci * 185062306a36Sopenharmony_ci * The routine validates the operation based on the 185162306a36Sopenharmony_ci * validation table an returns the length of the operation 185262306a36Sopenharmony_ci * which can extend beyond the ib_send_bw. Operation 185362306a36Sopenharmony_ci * dependent flags key atomic operation validation. 185462306a36Sopenharmony_ci * 185562306a36Sopenharmony_ci * There is an exception for UD qps that validates the pd and 185662306a36Sopenharmony_ci * overrides the length to include the additional UD specific 185762306a36Sopenharmony_ci * length. 185862306a36Sopenharmony_ci * 185962306a36Sopenharmony_ci * Returns a negative error or the length of the work request 186062306a36Sopenharmony_ci * for building the swqe. 186162306a36Sopenharmony_ci */ 186262306a36Sopenharmony_cistatic inline int rvt_qp_valid_operation( 186362306a36Sopenharmony_ci struct rvt_qp *qp, 186462306a36Sopenharmony_ci const struct rvt_operation_params *post_parms, 186562306a36Sopenharmony_ci const struct ib_send_wr *wr) 186662306a36Sopenharmony_ci{ 186762306a36Sopenharmony_ci int len; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (wr->opcode >= RVT_OPERATION_MAX || !post_parms[wr->opcode].length) 187062306a36Sopenharmony_ci return -EINVAL; 187162306a36Sopenharmony_ci if (!(post_parms[wr->opcode].qpt_support & BIT(qp->ibqp.qp_type))) 187262306a36Sopenharmony_ci return -EINVAL; 187362306a36Sopenharmony_ci if ((post_parms[wr->opcode].flags & RVT_OPERATION_PRIV) && 187462306a36Sopenharmony_ci ibpd_to_rvtpd(qp->ibqp.pd)->user) 187562306a36Sopenharmony_ci return -EINVAL; 187662306a36Sopenharmony_ci if (post_parms[wr->opcode].flags & RVT_OPERATION_ATOMIC_SGE && 187762306a36Sopenharmony_ci (wr->num_sge == 0 || 187862306a36Sopenharmony_ci wr->sg_list[0].length < sizeof(u64) || 187962306a36Sopenharmony_ci wr->sg_list[0].addr & (sizeof(u64) - 1))) 188062306a36Sopenharmony_ci return -EINVAL; 188162306a36Sopenharmony_ci if (post_parms[wr->opcode].flags & RVT_OPERATION_ATOMIC && 188262306a36Sopenharmony_ci !qp->s_max_rd_atomic) 188362306a36Sopenharmony_ci return -EINVAL; 188462306a36Sopenharmony_ci len = post_parms[wr->opcode].length; 188562306a36Sopenharmony_ci /* UD specific */ 188662306a36Sopenharmony_ci if (qp->ibqp.qp_type != IB_QPT_UC && 188762306a36Sopenharmony_ci qp->ibqp.qp_type != IB_QPT_RC) { 188862306a36Sopenharmony_ci if (qp->ibqp.pd != ud_wr(wr)->ah->pd) 188962306a36Sopenharmony_ci return -EINVAL; 189062306a36Sopenharmony_ci len = sizeof(struct ib_ud_wr); 189162306a36Sopenharmony_ci } 189262306a36Sopenharmony_ci return len; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci/** 189662306a36Sopenharmony_ci * rvt_qp_is_avail - determine queue capacity 189762306a36Sopenharmony_ci * @qp: the qp 189862306a36Sopenharmony_ci * @rdi: the rdmavt device 189962306a36Sopenharmony_ci * @reserved_op: is reserved operation 190062306a36Sopenharmony_ci * 190162306a36Sopenharmony_ci * This assumes the s_hlock is held but the s_last 190262306a36Sopenharmony_ci * qp variable is uncontrolled. 190362306a36Sopenharmony_ci * 190462306a36Sopenharmony_ci * For non reserved operations, the qp->s_avail 190562306a36Sopenharmony_ci * may be changed. 190662306a36Sopenharmony_ci * 190762306a36Sopenharmony_ci * The return value is zero or a -ENOMEM. 190862306a36Sopenharmony_ci */ 190962306a36Sopenharmony_cistatic inline int rvt_qp_is_avail( 191062306a36Sopenharmony_ci struct rvt_qp *qp, 191162306a36Sopenharmony_ci struct rvt_dev_info *rdi, 191262306a36Sopenharmony_ci bool reserved_op) 191362306a36Sopenharmony_ci{ 191462306a36Sopenharmony_ci u32 slast; 191562306a36Sopenharmony_ci u32 avail; 191662306a36Sopenharmony_ci u32 reserved_used; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci /* see rvt_qp_wqe_unreserve() */ 191962306a36Sopenharmony_ci smp_mb__before_atomic(); 192062306a36Sopenharmony_ci if (unlikely(reserved_op)) { 192162306a36Sopenharmony_ci /* see rvt_qp_wqe_unreserve() */ 192262306a36Sopenharmony_ci reserved_used = atomic_read(&qp->s_reserved_used); 192362306a36Sopenharmony_ci if (reserved_used >= rdi->dparms.reserved_operations) 192462306a36Sopenharmony_ci return -ENOMEM; 192562306a36Sopenharmony_ci return 0; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci /* non-reserved operations */ 192862306a36Sopenharmony_ci if (likely(qp->s_avail)) 192962306a36Sopenharmony_ci return 0; 193062306a36Sopenharmony_ci /* See rvt_qp_complete_swqe() */ 193162306a36Sopenharmony_ci slast = smp_load_acquire(&qp->s_last); 193262306a36Sopenharmony_ci if (qp->s_head >= slast) 193362306a36Sopenharmony_ci avail = qp->s_size - (qp->s_head - slast); 193462306a36Sopenharmony_ci else 193562306a36Sopenharmony_ci avail = slast - qp->s_head; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci reserved_used = atomic_read(&qp->s_reserved_used); 193862306a36Sopenharmony_ci avail = avail - 1 - 193962306a36Sopenharmony_ci (rdi->dparms.reserved_operations - reserved_used); 194062306a36Sopenharmony_ci /* insure we don't assign a negative s_avail */ 194162306a36Sopenharmony_ci if ((s32)avail <= 0) 194262306a36Sopenharmony_ci return -ENOMEM; 194362306a36Sopenharmony_ci qp->s_avail = avail; 194462306a36Sopenharmony_ci if (WARN_ON(qp->s_avail > 194562306a36Sopenharmony_ci (qp->s_size - 1 - rdi->dparms.reserved_operations))) 194662306a36Sopenharmony_ci rvt_pr_err(rdi, 194762306a36Sopenharmony_ci "More avail entries than QP RB size.\nQP: %u, size: %u, avail: %u\nhead: %u, tail: %u, cur: %u, acked: %u, last: %u", 194862306a36Sopenharmony_ci qp->ibqp.qp_num, qp->s_size, qp->s_avail, 194962306a36Sopenharmony_ci qp->s_head, qp->s_tail, qp->s_cur, 195062306a36Sopenharmony_ci qp->s_acked, qp->s_last); 195162306a36Sopenharmony_ci return 0; 195262306a36Sopenharmony_ci} 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci/** 195562306a36Sopenharmony_ci * rvt_post_one_wr - post one RC, UC, or UD send work request 195662306a36Sopenharmony_ci * @qp: the QP to post on 195762306a36Sopenharmony_ci * @wr: the work request to send 195862306a36Sopenharmony_ci * @call_send: kick the send engine into gear 195962306a36Sopenharmony_ci */ 196062306a36Sopenharmony_cistatic int rvt_post_one_wr(struct rvt_qp *qp, 196162306a36Sopenharmony_ci const struct ib_send_wr *wr, 196262306a36Sopenharmony_ci bool *call_send) 196362306a36Sopenharmony_ci{ 196462306a36Sopenharmony_ci struct rvt_swqe *wqe; 196562306a36Sopenharmony_ci u32 next; 196662306a36Sopenharmony_ci int i; 196762306a36Sopenharmony_ci int j; 196862306a36Sopenharmony_ci int acc; 196962306a36Sopenharmony_ci struct rvt_lkey_table *rkt; 197062306a36Sopenharmony_ci struct rvt_pd *pd; 197162306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 197262306a36Sopenharmony_ci u8 log_pmtu; 197362306a36Sopenharmony_ci int ret; 197462306a36Sopenharmony_ci size_t cplen; 197562306a36Sopenharmony_ci bool reserved_op; 197662306a36Sopenharmony_ci int local_ops_delayed = 0; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci BUILD_BUG_ON(IB_QPT_MAX >= (sizeof(u32) * BITS_PER_BYTE)); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci /* IB spec says that num_sge == 0 is OK. */ 198162306a36Sopenharmony_ci if (unlikely(wr->num_sge > qp->s_max_sge)) 198262306a36Sopenharmony_ci return -EINVAL; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci ret = rvt_qp_valid_operation(qp, rdi->post_parms, wr); 198562306a36Sopenharmony_ci if (ret < 0) 198662306a36Sopenharmony_ci return ret; 198762306a36Sopenharmony_ci cplen = ret; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci /* 199062306a36Sopenharmony_ci * Local operations include fast register and local invalidate. 199162306a36Sopenharmony_ci * Fast register needs to be processed immediately because the 199262306a36Sopenharmony_ci * registered lkey may be used by following work requests and the 199362306a36Sopenharmony_ci * lkey needs to be valid at the time those requests are posted. 199462306a36Sopenharmony_ci * Local invalidate can be processed immediately if fencing is 199562306a36Sopenharmony_ci * not required and no previous local invalidate ops are pending. 199662306a36Sopenharmony_ci * Signaled local operations that have been processed immediately 199762306a36Sopenharmony_ci * need to have requests with "completion only" flags set posted 199862306a36Sopenharmony_ci * to the send queue in order to generate completions. 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_ci if ((rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL)) { 200162306a36Sopenharmony_ci switch (wr->opcode) { 200262306a36Sopenharmony_ci case IB_WR_REG_MR: 200362306a36Sopenharmony_ci ret = rvt_fast_reg_mr(qp, 200462306a36Sopenharmony_ci reg_wr(wr)->mr, 200562306a36Sopenharmony_ci reg_wr(wr)->key, 200662306a36Sopenharmony_ci reg_wr(wr)->access); 200762306a36Sopenharmony_ci if (ret || !(wr->send_flags & IB_SEND_SIGNALED)) 200862306a36Sopenharmony_ci return ret; 200962306a36Sopenharmony_ci break; 201062306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 201162306a36Sopenharmony_ci if ((wr->send_flags & IB_SEND_FENCE) || 201262306a36Sopenharmony_ci atomic_read(&qp->local_ops_pending)) { 201362306a36Sopenharmony_ci local_ops_delayed = 1; 201462306a36Sopenharmony_ci } else { 201562306a36Sopenharmony_ci ret = rvt_invalidate_rkey( 201662306a36Sopenharmony_ci qp, wr->ex.invalidate_rkey); 201762306a36Sopenharmony_ci if (ret || !(wr->send_flags & IB_SEND_SIGNALED)) 201862306a36Sopenharmony_ci return ret; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci break; 202162306a36Sopenharmony_ci default: 202262306a36Sopenharmony_ci return -EINVAL; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci reserved_op = rdi->post_parms[wr->opcode].flags & 202762306a36Sopenharmony_ci RVT_OPERATION_USE_RESERVE; 202862306a36Sopenharmony_ci /* check for avail */ 202962306a36Sopenharmony_ci ret = rvt_qp_is_avail(qp, rdi, reserved_op); 203062306a36Sopenharmony_ci if (ret) 203162306a36Sopenharmony_ci return ret; 203262306a36Sopenharmony_ci next = qp->s_head + 1; 203362306a36Sopenharmony_ci if (next >= qp->s_size) 203462306a36Sopenharmony_ci next = 0; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci rkt = &rdi->lkey_table; 203762306a36Sopenharmony_ci pd = ibpd_to_rvtpd(qp->ibqp.pd); 203862306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(qp, qp->s_head); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci /* cplen has length from above */ 204162306a36Sopenharmony_ci memcpy(&wqe->ud_wr, wr, cplen); 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci wqe->length = 0; 204462306a36Sopenharmony_ci j = 0; 204562306a36Sopenharmony_ci if (wr->num_sge) { 204662306a36Sopenharmony_ci struct rvt_sge *last_sge = NULL; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci acc = wr->opcode >= IB_WR_RDMA_READ ? 204962306a36Sopenharmony_ci IB_ACCESS_LOCAL_WRITE : 0; 205062306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 205162306a36Sopenharmony_ci u32 length = wr->sg_list[i].length; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (length == 0) 205462306a36Sopenharmony_ci continue; 205562306a36Sopenharmony_ci ret = rvt_lkey_ok(rkt, pd, &wqe->sg_list[j], last_sge, 205662306a36Sopenharmony_ci &wr->sg_list[i], acc); 205762306a36Sopenharmony_ci if (unlikely(ret < 0)) 205862306a36Sopenharmony_ci goto bail_inval_free; 205962306a36Sopenharmony_ci wqe->length += length; 206062306a36Sopenharmony_ci if (ret) 206162306a36Sopenharmony_ci last_sge = &wqe->sg_list[j]; 206262306a36Sopenharmony_ci j += ret; 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci wqe->wr.num_sge = j; 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci /* 206862306a36Sopenharmony_ci * Calculate and set SWQE PSN values prior to handing it off 206962306a36Sopenharmony_ci * to the driver's check routine. This give the driver the 207062306a36Sopenharmony_ci * opportunity to adjust PSN values based on internal checks. 207162306a36Sopenharmony_ci */ 207262306a36Sopenharmony_ci log_pmtu = qp->log_pmtu; 207362306a36Sopenharmony_ci if (qp->allowed_ops == IB_OPCODE_UD) { 207462306a36Sopenharmony_ci struct rvt_ah *ah = rvt_get_swqe_ah(wqe); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci log_pmtu = ah->log_pmtu; 207762306a36Sopenharmony_ci rdma_copy_ah_attr(wqe->ud_wr.attr, &ah->attr); 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL) { 208162306a36Sopenharmony_ci if (local_ops_delayed) 208262306a36Sopenharmony_ci atomic_inc(&qp->local_ops_pending); 208362306a36Sopenharmony_ci else 208462306a36Sopenharmony_ci wqe->wr.send_flags |= RVT_SEND_COMPLETION_ONLY; 208562306a36Sopenharmony_ci wqe->ssn = 0; 208662306a36Sopenharmony_ci wqe->psn = 0; 208762306a36Sopenharmony_ci wqe->lpsn = 0; 208862306a36Sopenharmony_ci } else { 208962306a36Sopenharmony_ci wqe->ssn = qp->s_ssn++; 209062306a36Sopenharmony_ci wqe->psn = qp->s_next_psn; 209162306a36Sopenharmony_ci wqe->lpsn = wqe->psn + 209262306a36Sopenharmony_ci (wqe->length ? 209362306a36Sopenharmony_ci ((wqe->length - 1) >> log_pmtu) : 209462306a36Sopenharmony_ci 0); 209562306a36Sopenharmony_ci } 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci /* general part of wqe valid - allow for driver checks */ 209862306a36Sopenharmony_ci if (rdi->driver_f.setup_wqe) { 209962306a36Sopenharmony_ci ret = rdi->driver_f.setup_wqe(qp, wqe, call_send); 210062306a36Sopenharmony_ci if (ret < 0) 210162306a36Sopenharmony_ci goto bail_inval_free_ref; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci if (!(rdi->post_parms[wr->opcode].flags & RVT_OPERATION_LOCAL)) 210562306a36Sopenharmony_ci qp->s_next_psn = wqe->lpsn + 1; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci if (unlikely(reserved_op)) { 210862306a36Sopenharmony_ci wqe->wr.send_flags |= RVT_SEND_RESERVE_USED; 210962306a36Sopenharmony_ci rvt_qp_wqe_reserve(qp, wqe); 211062306a36Sopenharmony_ci } else { 211162306a36Sopenharmony_ci wqe->wr.send_flags &= ~RVT_SEND_RESERVE_USED; 211262306a36Sopenharmony_ci qp->s_avail--; 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci trace_rvt_post_one_wr(qp, wqe, wr->num_sge); 211562306a36Sopenharmony_ci smp_wmb(); /* see request builders */ 211662306a36Sopenharmony_ci qp->s_head = next; 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci return 0; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_cibail_inval_free_ref: 212162306a36Sopenharmony_ci if (qp->allowed_ops == IB_OPCODE_UD) 212262306a36Sopenharmony_ci rdma_destroy_ah_attr(wqe->ud_wr.attr); 212362306a36Sopenharmony_cibail_inval_free: 212462306a36Sopenharmony_ci /* release mr holds */ 212562306a36Sopenharmony_ci while (j) { 212662306a36Sopenharmony_ci struct rvt_sge *sge = &wqe->sg_list[--j]; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci rvt_put_mr(sge->mr); 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci return ret; 213162306a36Sopenharmony_ci} 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci/** 213462306a36Sopenharmony_ci * rvt_post_send - post a send on a QP 213562306a36Sopenharmony_ci * @ibqp: the QP to post the send on 213662306a36Sopenharmony_ci * @wr: the list of work requests to post 213762306a36Sopenharmony_ci * @bad_wr: the first bad WR is put here 213862306a36Sopenharmony_ci * 213962306a36Sopenharmony_ci * This may be called from interrupt context. 214062306a36Sopenharmony_ci * 214162306a36Sopenharmony_ci * Return: 0 on success else errno 214262306a36Sopenharmony_ci */ 214362306a36Sopenharmony_ciint rvt_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 214462306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 214562306a36Sopenharmony_ci{ 214662306a36Sopenharmony_ci struct rvt_qp *qp = ibqp_to_rvtqp(ibqp); 214762306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 214862306a36Sopenharmony_ci unsigned long flags = 0; 214962306a36Sopenharmony_ci bool call_send; 215062306a36Sopenharmony_ci unsigned nreq = 0; 215162306a36Sopenharmony_ci int err = 0; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci spin_lock_irqsave(&qp->s_hlock, flags); 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci /* 215662306a36Sopenharmony_ci * Ensure QP state is such that we can send. If not bail out early, 215762306a36Sopenharmony_ci * there is no need to do this every time we post a send. 215862306a36Sopenharmony_ci */ 215962306a36Sopenharmony_ci if (unlikely(!(ib_rvt_state_ops[qp->state] & RVT_POST_SEND_OK))) { 216062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->s_hlock, flags); 216162306a36Sopenharmony_ci return -EINVAL; 216262306a36Sopenharmony_ci } 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci /* 216562306a36Sopenharmony_ci * If the send queue is empty, and we only have a single WR then just go 216662306a36Sopenharmony_ci * ahead and kick the send engine into gear. Otherwise we will always 216762306a36Sopenharmony_ci * just schedule the send to happen later. 216862306a36Sopenharmony_ci */ 216962306a36Sopenharmony_ci call_send = qp->s_head == READ_ONCE(qp->s_last) && !wr->next; 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci for (; wr; wr = wr->next) { 217262306a36Sopenharmony_ci err = rvt_post_one_wr(qp, wr, &call_send); 217362306a36Sopenharmony_ci if (unlikely(err)) { 217462306a36Sopenharmony_ci *bad_wr = wr; 217562306a36Sopenharmony_ci goto bail; 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci nreq++; 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_cibail: 218062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->s_hlock, flags); 218162306a36Sopenharmony_ci if (nreq) { 218262306a36Sopenharmony_ci /* 218362306a36Sopenharmony_ci * Only call do_send if there is exactly one packet, and the 218462306a36Sopenharmony_ci * driver said it was ok. 218562306a36Sopenharmony_ci */ 218662306a36Sopenharmony_ci if (nreq == 1 && call_send) 218762306a36Sopenharmony_ci rdi->driver_f.do_send(qp); 218862306a36Sopenharmony_ci else 218962306a36Sopenharmony_ci rdi->driver_f.schedule_send_no_lock(qp); 219062306a36Sopenharmony_ci } 219162306a36Sopenharmony_ci return err; 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci/** 219562306a36Sopenharmony_ci * rvt_post_srq_recv - post a receive on a shared receive queue 219662306a36Sopenharmony_ci * @ibsrq: the SRQ to post the receive on 219762306a36Sopenharmony_ci * @wr: the list of work requests to post 219862306a36Sopenharmony_ci * @bad_wr: A pointer to the first WR to cause a problem is put here 219962306a36Sopenharmony_ci * 220062306a36Sopenharmony_ci * This may be called from interrupt context. 220162306a36Sopenharmony_ci * 220262306a36Sopenharmony_ci * Return: 0 on success else errno 220362306a36Sopenharmony_ci */ 220462306a36Sopenharmony_ciint rvt_post_srq_recv(struct ib_srq *ibsrq, const struct ib_recv_wr *wr, 220562306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 220662306a36Sopenharmony_ci{ 220762306a36Sopenharmony_ci struct rvt_srq *srq = ibsrq_to_rvtsrq(ibsrq); 220862306a36Sopenharmony_ci struct rvt_krwq *wq; 220962306a36Sopenharmony_ci unsigned long flags; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci for (; wr; wr = wr->next) { 221262306a36Sopenharmony_ci struct rvt_rwqe *wqe; 221362306a36Sopenharmony_ci u32 next; 221462306a36Sopenharmony_ci int i; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci if ((unsigned)wr->num_sge > srq->rq.max_sge) { 221762306a36Sopenharmony_ci *bad_wr = wr; 221862306a36Sopenharmony_ci return -EINVAL; 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci spin_lock_irqsave(&srq->rq.kwq->p_lock, flags); 222262306a36Sopenharmony_ci wq = srq->rq.kwq; 222362306a36Sopenharmony_ci next = wq->head + 1; 222462306a36Sopenharmony_ci if (next >= srq->rq.size) 222562306a36Sopenharmony_ci next = 0; 222662306a36Sopenharmony_ci if (next == READ_ONCE(wq->tail)) { 222762306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.kwq->p_lock, flags); 222862306a36Sopenharmony_ci *bad_wr = wr; 222962306a36Sopenharmony_ci return -ENOMEM; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci wqe = rvt_get_rwqe_ptr(&srq->rq, wq->head); 223362306a36Sopenharmony_ci wqe->wr_id = wr->wr_id; 223462306a36Sopenharmony_ci wqe->num_sge = wr->num_sge; 223562306a36Sopenharmony_ci for (i = 0; i < wr->num_sge; i++) { 223662306a36Sopenharmony_ci wqe->sg_list[i].addr = wr->sg_list[i].addr; 223762306a36Sopenharmony_ci wqe->sg_list[i].length = wr->sg_list[i].length; 223862306a36Sopenharmony_ci wqe->sg_list[i].lkey = wr->sg_list[i].lkey; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci /* Make sure queue entry is written before the head index. */ 224162306a36Sopenharmony_ci smp_store_release(&wq->head, next); 224262306a36Sopenharmony_ci spin_unlock_irqrestore(&srq->rq.kwq->p_lock, flags); 224362306a36Sopenharmony_ci } 224462306a36Sopenharmony_ci return 0; 224562306a36Sopenharmony_ci} 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci/* 224862306a36Sopenharmony_ci * rvt used the internal kernel struct as part of its ABI, for now make sure 224962306a36Sopenharmony_ci * the kernel struct does not change layout. FIXME: rvt should never cast the 225062306a36Sopenharmony_ci * user struct to a kernel struct. 225162306a36Sopenharmony_ci */ 225262306a36Sopenharmony_cistatic struct ib_sge *rvt_cast_sge(struct rvt_wqe_sge *sge) 225362306a36Sopenharmony_ci{ 225462306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ib_sge, addr) != 225562306a36Sopenharmony_ci offsetof(struct rvt_wqe_sge, addr)); 225662306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ib_sge, length) != 225762306a36Sopenharmony_ci offsetof(struct rvt_wqe_sge, length)); 225862306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct ib_sge, lkey) != 225962306a36Sopenharmony_ci offsetof(struct rvt_wqe_sge, lkey)); 226062306a36Sopenharmony_ci return (struct ib_sge *)sge; 226162306a36Sopenharmony_ci} 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci/* 226462306a36Sopenharmony_ci * Validate a RWQE and fill in the SGE state. 226562306a36Sopenharmony_ci * Return 1 if OK. 226662306a36Sopenharmony_ci */ 226762306a36Sopenharmony_cistatic int init_sge(struct rvt_qp *qp, struct rvt_rwqe *wqe) 226862306a36Sopenharmony_ci{ 226962306a36Sopenharmony_ci int i, j, ret; 227062306a36Sopenharmony_ci struct ib_wc wc; 227162306a36Sopenharmony_ci struct rvt_lkey_table *rkt; 227262306a36Sopenharmony_ci struct rvt_pd *pd; 227362306a36Sopenharmony_ci struct rvt_sge_state *ss; 227462306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci rkt = &rdi->lkey_table; 227762306a36Sopenharmony_ci pd = ibpd_to_rvtpd(qp->ibqp.srq ? qp->ibqp.srq->pd : qp->ibqp.pd); 227862306a36Sopenharmony_ci ss = &qp->r_sge; 227962306a36Sopenharmony_ci ss->sg_list = qp->r_sg_list; 228062306a36Sopenharmony_ci qp->r_len = 0; 228162306a36Sopenharmony_ci for (i = j = 0; i < wqe->num_sge; i++) { 228262306a36Sopenharmony_ci if (wqe->sg_list[i].length == 0) 228362306a36Sopenharmony_ci continue; 228462306a36Sopenharmony_ci /* Check LKEY */ 228562306a36Sopenharmony_ci ret = rvt_lkey_ok(rkt, pd, j ? &ss->sg_list[j - 1] : &ss->sge, 228662306a36Sopenharmony_ci NULL, rvt_cast_sge(&wqe->sg_list[i]), 228762306a36Sopenharmony_ci IB_ACCESS_LOCAL_WRITE); 228862306a36Sopenharmony_ci if (unlikely(ret <= 0)) 228962306a36Sopenharmony_ci goto bad_lkey; 229062306a36Sopenharmony_ci qp->r_len += wqe->sg_list[i].length; 229162306a36Sopenharmony_ci j++; 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci ss->num_sge = j; 229462306a36Sopenharmony_ci ss->total_len = qp->r_len; 229562306a36Sopenharmony_ci return 1; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_cibad_lkey: 229862306a36Sopenharmony_ci while (j) { 229962306a36Sopenharmony_ci struct rvt_sge *sge = --j ? &ss->sg_list[j - 1] : &ss->sge; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci rvt_put_mr(sge->mr); 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci ss->num_sge = 0; 230462306a36Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 230562306a36Sopenharmony_ci wc.wr_id = wqe->wr_id; 230662306a36Sopenharmony_ci wc.status = IB_WC_LOC_PROT_ERR; 230762306a36Sopenharmony_ci wc.opcode = IB_WC_RECV; 230862306a36Sopenharmony_ci wc.qp = &qp->ibqp; 230962306a36Sopenharmony_ci /* Signal solicited completion event. */ 231062306a36Sopenharmony_ci rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, 1); 231162306a36Sopenharmony_ci return 0; 231262306a36Sopenharmony_ci} 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci/** 231562306a36Sopenharmony_ci * get_rvt_head - get head indices of the circular buffer 231662306a36Sopenharmony_ci * @rq: data structure for request queue entry 231762306a36Sopenharmony_ci * @ip: the QP 231862306a36Sopenharmony_ci * 231962306a36Sopenharmony_ci * Return - head index value 232062306a36Sopenharmony_ci */ 232162306a36Sopenharmony_cistatic inline u32 get_rvt_head(struct rvt_rq *rq, void *ip) 232262306a36Sopenharmony_ci{ 232362306a36Sopenharmony_ci u32 head; 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci if (ip) 232662306a36Sopenharmony_ci head = RDMA_READ_UAPI_ATOMIC(rq->wq->head); 232762306a36Sopenharmony_ci else 232862306a36Sopenharmony_ci head = rq->kwq->head; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci return head; 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci/** 233462306a36Sopenharmony_ci * rvt_get_rwqe - copy the next RWQE into the QP's RWQE 233562306a36Sopenharmony_ci * @qp: the QP 233662306a36Sopenharmony_ci * @wr_id_only: update qp->r_wr_id only, not qp->r_sge 233762306a36Sopenharmony_ci * 233862306a36Sopenharmony_ci * Return -1 if there is a local error, 0 if no RWQE is available, 233962306a36Sopenharmony_ci * otherwise return 1. 234062306a36Sopenharmony_ci * 234162306a36Sopenharmony_ci * Can be called from interrupt level. 234262306a36Sopenharmony_ci */ 234362306a36Sopenharmony_ciint rvt_get_rwqe(struct rvt_qp *qp, bool wr_id_only) 234462306a36Sopenharmony_ci{ 234562306a36Sopenharmony_ci unsigned long flags; 234662306a36Sopenharmony_ci struct rvt_rq *rq; 234762306a36Sopenharmony_ci struct rvt_krwq *kwq = NULL; 234862306a36Sopenharmony_ci struct rvt_rwq *wq; 234962306a36Sopenharmony_ci struct rvt_srq *srq; 235062306a36Sopenharmony_ci struct rvt_rwqe *wqe; 235162306a36Sopenharmony_ci void (*handler)(struct ib_event *, void *); 235262306a36Sopenharmony_ci u32 tail; 235362306a36Sopenharmony_ci u32 head; 235462306a36Sopenharmony_ci int ret; 235562306a36Sopenharmony_ci void *ip = NULL; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci if (qp->ibqp.srq) { 235862306a36Sopenharmony_ci srq = ibsrq_to_rvtsrq(qp->ibqp.srq); 235962306a36Sopenharmony_ci handler = srq->ibsrq.event_handler; 236062306a36Sopenharmony_ci rq = &srq->rq; 236162306a36Sopenharmony_ci ip = srq->ip; 236262306a36Sopenharmony_ci } else { 236362306a36Sopenharmony_ci srq = NULL; 236462306a36Sopenharmony_ci handler = NULL; 236562306a36Sopenharmony_ci rq = &qp->r_rq; 236662306a36Sopenharmony_ci ip = qp->ip; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci spin_lock_irqsave(&rq->kwq->c_lock, flags); 237062306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK)) { 237162306a36Sopenharmony_ci ret = 0; 237262306a36Sopenharmony_ci goto unlock; 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ci kwq = rq->kwq; 237562306a36Sopenharmony_ci if (ip) { 237662306a36Sopenharmony_ci wq = rq->wq; 237762306a36Sopenharmony_ci tail = RDMA_READ_UAPI_ATOMIC(wq->tail); 237862306a36Sopenharmony_ci } else { 237962306a36Sopenharmony_ci tail = kwq->tail; 238062306a36Sopenharmony_ci } 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci /* Validate tail before using it since it is user writable. */ 238362306a36Sopenharmony_ci if (tail >= rq->size) 238462306a36Sopenharmony_ci tail = 0; 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci if (kwq->count < RVT_RWQ_COUNT_THRESHOLD) { 238762306a36Sopenharmony_ci head = get_rvt_head(rq, ip); 238862306a36Sopenharmony_ci kwq->count = rvt_get_rq_count(rq, head, tail); 238962306a36Sopenharmony_ci } 239062306a36Sopenharmony_ci if (unlikely(kwq->count == 0)) { 239162306a36Sopenharmony_ci ret = 0; 239262306a36Sopenharmony_ci goto unlock; 239362306a36Sopenharmony_ci } 239462306a36Sopenharmony_ci /* Make sure entry is read after the count is read. */ 239562306a36Sopenharmony_ci smp_rmb(); 239662306a36Sopenharmony_ci wqe = rvt_get_rwqe_ptr(rq, tail); 239762306a36Sopenharmony_ci /* 239862306a36Sopenharmony_ci * Even though we update the tail index in memory, the verbs 239962306a36Sopenharmony_ci * consumer is not supposed to post more entries until a 240062306a36Sopenharmony_ci * completion is generated. 240162306a36Sopenharmony_ci */ 240262306a36Sopenharmony_ci if (++tail >= rq->size) 240362306a36Sopenharmony_ci tail = 0; 240462306a36Sopenharmony_ci if (ip) 240562306a36Sopenharmony_ci RDMA_WRITE_UAPI_ATOMIC(wq->tail, tail); 240662306a36Sopenharmony_ci else 240762306a36Sopenharmony_ci kwq->tail = tail; 240862306a36Sopenharmony_ci if (!wr_id_only && !init_sge(qp, wqe)) { 240962306a36Sopenharmony_ci ret = -1; 241062306a36Sopenharmony_ci goto unlock; 241162306a36Sopenharmony_ci } 241262306a36Sopenharmony_ci qp->r_wr_id = wqe->wr_id; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci kwq->count--; 241562306a36Sopenharmony_ci ret = 1; 241662306a36Sopenharmony_ci set_bit(RVT_R_WRID_VALID, &qp->r_aflags); 241762306a36Sopenharmony_ci if (handler) { 241862306a36Sopenharmony_ci /* 241962306a36Sopenharmony_ci * Validate head pointer value and compute 242062306a36Sopenharmony_ci * the number of remaining WQEs. 242162306a36Sopenharmony_ci */ 242262306a36Sopenharmony_ci if (kwq->count < srq->limit) { 242362306a36Sopenharmony_ci kwq->count = 242462306a36Sopenharmony_ci rvt_get_rq_count(rq, 242562306a36Sopenharmony_ci get_rvt_head(rq, ip), tail); 242662306a36Sopenharmony_ci if (kwq->count < srq->limit) { 242762306a36Sopenharmony_ci struct ib_event ev; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci srq->limit = 0; 243062306a36Sopenharmony_ci spin_unlock_irqrestore(&rq->kwq->c_lock, flags); 243162306a36Sopenharmony_ci ev.device = qp->ibqp.device; 243262306a36Sopenharmony_ci ev.element.srq = qp->ibqp.srq; 243362306a36Sopenharmony_ci ev.event = IB_EVENT_SRQ_LIMIT_REACHED; 243462306a36Sopenharmony_ci handler(&ev, srq->ibsrq.srq_context); 243562306a36Sopenharmony_ci goto bail; 243662306a36Sopenharmony_ci } 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ciunlock: 244062306a36Sopenharmony_ci spin_unlock_irqrestore(&rq->kwq->c_lock, flags); 244162306a36Sopenharmony_cibail: 244262306a36Sopenharmony_ci return ret; 244362306a36Sopenharmony_ci} 244462306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_get_rwqe); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci/** 244762306a36Sopenharmony_ci * rvt_comm_est - handle trap with QP established 244862306a36Sopenharmony_ci * @qp: the QP 244962306a36Sopenharmony_ci */ 245062306a36Sopenharmony_civoid rvt_comm_est(struct rvt_qp *qp) 245162306a36Sopenharmony_ci{ 245262306a36Sopenharmony_ci qp->r_flags |= RVT_R_COMM_EST; 245362306a36Sopenharmony_ci if (qp->ibqp.event_handler) { 245462306a36Sopenharmony_ci struct ib_event ev; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci ev.device = qp->ibqp.device; 245762306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 245862306a36Sopenharmony_ci ev.event = IB_EVENT_COMM_EST; 245962306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 246062306a36Sopenharmony_ci } 246162306a36Sopenharmony_ci} 246262306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_comm_est); 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_civoid rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err) 246562306a36Sopenharmony_ci{ 246662306a36Sopenharmony_ci unsigned long flags; 246762306a36Sopenharmony_ci int lastwqe; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, flags); 247062306a36Sopenharmony_ci lastwqe = rvt_error_qp(qp, err); 247162306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, flags); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci if (lastwqe) { 247462306a36Sopenharmony_ci struct ib_event ev; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci ev.device = qp->ibqp.device; 247762306a36Sopenharmony_ci ev.element.qp = &qp->ibqp; 247862306a36Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 247962306a36Sopenharmony_ci qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_rc_error); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci/* 248562306a36Sopenharmony_ci * rvt_rnr_tbl_to_usec - return index into ib_rvt_rnr_table 248662306a36Sopenharmony_ci * @index - the index 248762306a36Sopenharmony_ci * return usec from an index into ib_rvt_rnr_table 248862306a36Sopenharmony_ci */ 248962306a36Sopenharmony_ciunsigned long rvt_rnr_tbl_to_usec(u32 index) 249062306a36Sopenharmony_ci{ 249162306a36Sopenharmony_ci return ib_rvt_rnr_table[(index & IB_AETH_CREDIT_MASK)]; 249262306a36Sopenharmony_ci} 249362306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_rnr_tbl_to_usec); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_cistatic inline unsigned long rvt_aeth_to_usec(u32 aeth) 249662306a36Sopenharmony_ci{ 249762306a36Sopenharmony_ci return ib_rvt_rnr_table[(aeth >> IB_AETH_CREDIT_SHIFT) & 249862306a36Sopenharmony_ci IB_AETH_CREDIT_MASK]; 249962306a36Sopenharmony_ci} 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci/* 250262306a36Sopenharmony_ci * rvt_add_retry_timer_ext - add/start a retry timer 250362306a36Sopenharmony_ci * @qp - the QP 250462306a36Sopenharmony_ci * @shift - timeout shift to wait for multiple packets 250562306a36Sopenharmony_ci * add a retry timer on the QP 250662306a36Sopenharmony_ci */ 250762306a36Sopenharmony_civoid rvt_add_retry_timer_ext(struct rvt_qp *qp, u8 shift) 250862306a36Sopenharmony_ci{ 250962306a36Sopenharmony_ci struct ib_qp *ibqp = &qp->ibqp; 251062306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(ibqp->device); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 251362306a36Sopenharmony_ci qp->s_flags |= RVT_S_TIMER; 251462306a36Sopenharmony_ci /* 4.096 usec. * (1 << qp->timeout) */ 251562306a36Sopenharmony_ci qp->s_timer.expires = jiffies + rdi->busy_jiffies + 251662306a36Sopenharmony_ci (qp->timeout_jiffies << shift); 251762306a36Sopenharmony_ci add_timer(&qp->s_timer); 251862306a36Sopenharmony_ci} 251962306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_add_retry_timer_ext); 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci/** 252262306a36Sopenharmony_ci * rvt_add_rnr_timer - add/start an rnr timer on the QP 252362306a36Sopenharmony_ci * @qp: the QP 252462306a36Sopenharmony_ci * @aeth: aeth of RNR timeout, simulated aeth for loopback 252562306a36Sopenharmony_ci */ 252662306a36Sopenharmony_civoid rvt_add_rnr_timer(struct rvt_qp *qp, u32 aeth) 252762306a36Sopenharmony_ci{ 252862306a36Sopenharmony_ci u32 to; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 253162306a36Sopenharmony_ci qp->s_flags |= RVT_S_WAIT_RNR; 253262306a36Sopenharmony_ci to = rvt_aeth_to_usec(aeth); 253362306a36Sopenharmony_ci trace_rvt_rnrnak_add(qp, to); 253462306a36Sopenharmony_ci hrtimer_start(&qp->s_rnr_timer, 253562306a36Sopenharmony_ci ns_to_ktime(1000 * to), HRTIMER_MODE_REL_PINNED); 253662306a36Sopenharmony_ci} 253762306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_add_rnr_timer); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci/** 254062306a36Sopenharmony_ci * rvt_stop_rc_timers - stop all timers 254162306a36Sopenharmony_ci * @qp: the QP 254262306a36Sopenharmony_ci * stop any pending timers 254362306a36Sopenharmony_ci */ 254462306a36Sopenharmony_civoid rvt_stop_rc_timers(struct rvt_qp *qp) 254562306a36Sopenharmony_ci{ 254662306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 254762306a36Sopenharmony_ci /* Remove QP from all timers */ 254862306a36Sopenharmony_ci if (qp->s_flags & (RVT_S_TIMER | RVT_S_WAIT_RNR)) { 254962306a36Sopenharmony_ci qp->s_flags &= ~(RVT_S_TIMER | RVT_S_WAIT_RNR); 255062306a36Sopenharmony_ci del_timer(&qp->s_timer); 255162306a36Sopenharmony_ci hrtimer_try_to_cancel(&qp->s_rnr_timer); 255262306a36Sopenharmony_ci } 255362306a36Sopenharmony_ci} 255462306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_stop_rc_timers); 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci/** 255762306a36Sopenharmony_ci * rvt_stop_rnr_timer - stop an rnr timer 255862306a36Sopenharmony_ci * @qp: the QP 255962306a36Sopenharmony_ci * 256062306a36Sopenharmony_ci * stop an rnr timer and return if the timer 256162306a36Sopenharmony_ci * had been pending. 256262306a36Sopenharmony_ci */ 256362306a36Sopenharmony_cistatic void rvt_stop_rnr_timer(struct rvt_qp *qp) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci lockdep_assert_held(&qp->s_lock); 256662306a36Sopenharmony_ci /* Remove QP from rnr timer */ 256762306a36Sopenharmony_ci if (qp->s_flags & RVT_S_WAIT_RNR) { 256862306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_WAIT_RNR; 256962306a36Sopenharmony_ci trace_rvt_rnrnak_stop(qp, 0); 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_ci} 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci/** 257462306a36Sopenharmony_ci * rvt_del_timers_sync - wait for any timeout routines to exit 257562306a36Sopenharmony_ci * @qp: the QP 257662306a36Sopenharmony_ci */ 257762306a36Sopenharmony_civoid rvt_del_timers_sync(struct rvt_qp *qp) 257862306a36Sopenharmony_ci{ 257962306a36Sopenharmony_ci del_timer_sync(&qp->s_timer); 258062306a36Sopenharmony_ci hrtimer_cancel(&qp->s_rnr_timer); 258162306a36Sopenharmony_ci} 258262306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_del_timers_sync); 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci/* 258562306a36Sopenharmony_ci * This is called from s_timer for missing responses. 258662306a36Sopenharmony_ci */ 258762306a36Sopenharmony_cistatic void rvt_rc_timeout(struct timer_list *t) 258862306a36Sopenharmony_ci{ 258962306a36Sopenharmony_ci struct rvt_qp *qp = from_timer(qp, t, s_timer); 259062306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 259162306a36Sopenharmony_ci unsigned long flags; 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 259462306a36Sopenharmony_ci spin_lock(&qp->s_lock); 259562306a36Sopenharmony_ci if (qp->s_flags & RVT_S_TIMER) { 259662306a36Sopenharmony_ci struct rvt_ibport *rvp = rdi->ports[qp->port_num - 1]; 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_ci qp->s_flags &= ~RVT_S_TIMER; 259962306a36Sopenharmony_ci rvp->n_rc_timeouts++; 260062306a36Sopenharmony_ci del_timer(&qp->s_timer); 260162306a36Sopenharmony_ci trace_rvt_rc_timeout(qp, qp->s_last_psn + 1); 260262306a36Sopenharmony_ci if (rdi->driver_f.notify_restart_rc) 260362306a36Sopenharmony_ci rdi->driver_f.notify_restart_rc(qp, 260462306a36Sopenharmony_ci qp->s_last_psn + 1, 260562306a36Sopenharmony_ci 1); 260662306a36Sopenharmony_ci rdi->driver_f.schedule_send(qp); 260762306a36Sopenharmony_ci } 260862306a36Sopenharmony_ci spin_unlock(&qp->s_lock); 260962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 261062306a36Sopenharmony_ci} 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci/* 261362306a36Sopenharmony_ci * This is called from s_timer for RNR timeouts. 261462306a36Sopenharmony_ci */ 261562306a36Sopenharmony_cienum hrtimer_restart rvt_rc_rnr_retry(struct hrtimer *t) 261662306a36Sopenharmony_ci{ 261762306a36Sopenharmony_ci struct rvt_qp *qp = container_of(t, struct rvt_qp, s_rnr_timer); 261862306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 261962306a36Sopenharmony_ci unsigned long flags; 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci spin_lock_irqsave(&qp->s_lock, flags); 262262306a36Sopenharmony_ci rvt_stop_rnr_timer(qp); 262362306a36Sopenharmony_ci trace_rvt_rnrnak_timeout(qp, 0); 262462306a36Sopenharmony_ci rdi->driver_f.schedule_send(qp); 262562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->s_lock, flags); 262662306a36Sopenharmony_ci return HRTIMER_NORESTART; 262762306a36Sopenharmony_ci} 262862306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_rc_rnr_retry); 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci/** 263162306a36Sopenharmony_ci * rvt_qp_iter_init - initial for QP iteration 263262306a36Sopenharmony_ci * @rdi: rvt devinfo 263362306a36Sopenharmony_ci * @v: u64 value 263462306a36Sopenharmony_ci * @cb: user-defined callback 263562306a36Sopenharmony_ci * 263662306a36Sopenharmony_ci * This returns an iterator suitable for iterating QPs 263762306a36Sopenharmony_ci * in the system. 263862306a36Sopenharmony_ci * 263962306a36Sopenharmony_ci * The @cb is a user-defined callback and @v is a 64-bit 264062306a36Sopenharmony_ci * value passed to and relevant for processing in the 264162306a36Sopenharmony_ci * @cb. An example use case would be to alter QP processing 264262306a36Sopenharmony_ci * based on criteria not part of the rvt_qp. 264362306a36Sopenharmony_ci * 264462306a36Sopenharmony_ci * Use cases that require memory allocation to succeed 264562306a36Sopenharmony_ci * must preallocate appropriately. 264662306a36Sopenharmony_ci * 264762306a36Sopenharmony_ci * Return: a pointer to an rvt_qp_iter or NULL 264862306a36Sopenharmony_ci */ 264962306a36Sopenharmony_cistruct rvt_qp_iter *rvt_qp_iter_init(struct rvt_dev_info *rdi, 265062306a36Sopenharmony_ci u64 v, 265162306a36Sopenharmony_ci void (*cb)(struct rvt_qp *qp, u64 v)) 265262306a36Sopenharmony_ci{ 265362306a36Sopenharmony_ci struct rvt_qp_iter *i; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci i = kzalloc(sizeof(*i), GFP_KERNEL); 265662306a36Sopenharmony_ci if (!i) 265762306a36Sopenharmony_ci return NULL; 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci i->rdi = rdi; 266062306a36Sopenharmony_ci /* number of special QPs (SMI/GSI) for device */ 266162306a36Sopenharmony_ci i->specials = rdi->ibdev.phys_port_cnt * 2; 266262306a36Sopenharmony_ci i->v = v; 266362306a36Sopenharmony_ci i->cb = cb; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci return i; 266662306a36Sopenharmony_ci} 266762306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_qp_iter_init); 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci/** 267062306a36Sopenharmony_ci * rvt_qp_iter_next - return the next QP in iter 267162306a36Sopenharmony_ci * @iter: the iterator 267262306a36Sopenharmony_ci * 267362306a36Sopenharmony_ci * Fine grained QP iterator suitable for use 267462306a36Sopenharmony_ci * with debugfs seq_file mechanisms. 267562306a36Sopenharmony_ci * 267662306a36Sopenharmony_ci * Updates iter->qp with the current QP when the return 267762306a36Sopenharmony_ci * value is 0. 267862306a36Sopenharmony_ci * 267962306a36Sopenharmony_ci * Return: 0 - iter->qp is valid 1 - no more QPs 268062306a36Sopenharmony_ci */ 268162306a36Sopenharmony_ciint rvt_qp_iter_next(struct rvt_qp_iter *iter) 268262306a36Sopenharmony_ci __must_hold(RCU) 268362306a36Sopenharmony_ci{ 268462306a36Sopenharmony_ci int n = iter->n; 268562306a36Sopenharmony_ci int ret = 1; 268662306a36Sopenharmony_ci struct rvt_qp *pqp = iter->qp; 268762306a36Sopenharmony_ci struct rvt_qp *qp; 268862306a36Sopenharmony_ci struct rvt_dev_info *rdi = iter->rdi; 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci /* 269162306a36Sopenharmony_ci * The approach is to consider the special qps 269262306a36Sopenharmony_ci * as additional table entries before the 269362306a36Sopenharmony_ci * real hash table. Since the qp code sets 269462306a36Sopenharmony_ci * the qp->next hash link to NULL, this works just fine. 269562306a36Sopenharmony_ci * 269662306a36Sopenharmony_ci * iter->specials is 2 * # ports 269762306a36Sopenharmony_ci * 269862306a36Sopenharmony_ci * n = 0..iter->specials is the special qp indices 269962306a36Sopenharmony_ci * 270062306a36Sopenharmony_ci * n = iter->specials..rdi->qp_dev->qp_table_size+iter->specials are 270162306a36Sopenharmony_ci * the potential hash bucket entries 270262306a36Sopenharmony_ci * 270362306a36Sopenharmony_ci */ 270462306a36Sopenharmony_ci for (; n < rdi->qp_dev->qp_table_size + iter->specials; n++) { 270562306a36Sopenharmony_ci if (pqp) { 270662306a36Sopenharmony_ci qp = rcu_dereference(pqp->next); 270762306a36Sopenharmony_ci } else { 270862306a36Sopenharmony_ci if (n < iter->specials) { 270962306a36Sopenharmony_ci struct rvt_ibport *rvp; 271062306a36Sopenharmony_ci int pidx; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci pidx = n % rdi->ibdev.phys_port_cnt; 271362306a36Sopenharmony_ci rvp = rdi->ports[pidx]; 271462306a36Sopenharmony_ci qp = rcu_dereference(rvp->qp[n & 1]); 271562306a36Sopenharmony_ci } else { 271662306a36Sopenharmony_ci qp = rcu_dereference( 271762306a36Sopenharmony_ci rdi->qp_dev->qp_table[ 271862306a36Sopenharmony_ci (n - iter->specials)]); 271962306a36Sopenharmony_ci } 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci pqp = qp; 272262306a36Sopenharmony_ci if (qp) { 272362306a36Sopenharmony_ci iter->qp = qp; 272462306a36Sopenharmony_ci iter->n = n; 272562306a36Sopenharmony_ci return 0; 272662306a36Sopenharmony_ci } 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci return ret; 272962306a36Sopenharmony_ci} 273062306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_qp_iter_next); 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci/** 273362306a36Sopenharmony_ci * rvt_qp_iter - iterate all QPs 273462306a36Sopenharmony_ci * @rdi: rvt devinfo 273562306a36Sopenharmony_ci * @v: a 64-bit value 273662306a36Sopenharmony_ci * @cb: a callback 273762306a36Sopenharmony_ci * 273862306a36Sopenharmony_ci * This provides a way for iterating all QPs. 273962306a36Sopenharmony_ci * 274062306a36Sopenharmony_ci * The @cb is a user-defined callback and @v is a 64-bit 274162306a36Sopenharmony_ci * value passed to and relevant for processing in the 274262306a36Sopenharmony_ci * cb. An example use case would be to alter QP processing 274362306a36Sopenharmony_ci * based on criteria not part of the rvt_qp. 274462306a36Sopenharmony_ci * 274562306a36Sopenharmony_ci * The code has an internal iterator to simplify 274662306a36Sopenharmony_ci * non seq_file use cases. 274762306a36Sopenharmony_ci */ 274862306a36Sopenharmony_civoid rvt_qp_iter(struct rvt_dev_info *rdi, 274962306a36Sopenharmony_ci u64 v, 275062306a36Sopenharmony_ci void (*cb)(struct rvt_qp *qp, u64 v)) 275162306a36Sopenharmony_ci{ 275262306a36Sopenharmony_ci int ret; 275362306a36Sopenharmony_ci struct rvt_qp_iter i = { 275462306a36Sopenharmony_ci .rdi = rdi, 275562306a36Sopenharmony_ci .specials = rdi->ibdev.phys_port_cnt * 2, 275662306a36Sopenharmony_ci .v = v, 275762306a36Sopenharmony_ci .cb = cb 275862306a36Sopenharmony_ci }; 275962306a36Sopenharmony_ci 276062306a36Sopenharmony_ci rcu_read_lock(); 276162306a36Sopenharmony_ci do { 276262306a36Sopenharmony_ci ret = rvt_qp_iter_next(&i); 276362306a36Sopenharmony_ci if (!ret) { 276462306a36Sopenharmony_ci rvt_get_qp(i.qp); 276562306a36Sopenharmony_ci rcu_read_unlock(); 276662306a36Sopenharmony_ci i.cb(i.qp, i.v); 276762306a36Sopenharmony_ci rcu_read_lock(); 276862306a36Sopenharmony_ci rvt_put_qp(i.qp); 276962306a36Sopenharmony_ci } 277062306a36Sopenharmony_ci } while (!ret); 277162306a36Sopenharmony_ci rcu_read_unlock(); 277262306a36Sopenharmony_ci} 277362306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_qp_iter); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci/* 277662306a36Sopenharmony_ci * This should be called with s_lock and r_lock held. 277762306a36Sopenharmony_ci */ 277862306a36Sopenharmony_civoid rvt_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, 277962306a36Sopenharmony_ci enum ib_wc_status status) 278062306a36Sopenharmony_ci{ 278162306a36Sopenharmony_ci u32 old_last, last; 278262306a36Sopenharmony_ci struct rvt_dev_info *rdi; 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) 278562306a36Sopenharmony_ci return; 278662306a36Sopenharmony_ci rdi = ib_to_rvt(qp->ibqp.device); 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci old_last = qp->s_last; 278962306a36Sopenharmony_ci trace_rvt_qp_send_completion(qp, wqe, old_last); 279062306a36Sopenharmony_ci last = rvt_qp_complete_swqe(qp, wqe, rdi->wc_opcode[wqe->wr.opcode], 279162306a36Sopenharmony_ci status); 279262306a36Sopenharmony_ci if (qp->s_acked == old_last) 279362306a36Sopenharmony_ci qp->s_acked = last; 279462306a36Sopenharmony_ci if (qp->s_cur == old_last) 279562306a36Sopenharmony_ci qp->s_cur = last; 279662306a36Sopenharmony_ci if (qp->s_tail == old_last) 279762306a36Sopenharmony_ci qp->s_tail = last; 279862306a36Sopenharmony_ci if (qp->state == IB_QPS_SQD && last == qp->s_cur) 279962306a36Sopenharmony_ci qp->s_draining = 0; 280062306a36Sopenharmony_ci} 280162306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_send_complete); 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci/** 280462306a36Sopenharmony_ci * rvt_copy_sge - copy data to SGE memory 280562306a36Sopenharmony_ci * @qp: associated QP 280662306a36Sopenharmony_ci * @ss: the SGE state 280762306a36Sopenharmony_ci * @data: the data to copy 280862306a36Sopenharmony_ci * @length: the length of the data 280962306a36Sopenharmony_ci * @release: boolean to release MR 281062306a36Sopenharmony_ci * @copy_last: do a separate copy of the last 8 bytes 281162306a36Sopenharmony_ci */ 281262306a36Sopenharmony_civoid rvt_copy_sge(struct rvt_qp *qp, struct rvt_sge_state *ss, 281362306a36Sopenharmony_ci void *data, u32 length, 281462306a36Sopenharmony_ci bool release, bool copy_last) 281562306a36Sopenharmony_ci{ 281662306a36Sopenharmony_ci struct rvt_sge *sge = &ss->sge; 281762306a36Sopenharmony_ci int i; 281862306a36Sopenharmony_ci bool in_last = false; 281962306a36Sopenharmony_ci bool cacheless_copy = false; 282062306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(qp->ibqp.device); 282162306a36Sopenharmony_ci struct rvt_wss *wss = rdi->wss; 282262306a36Sopenharmony_ci unsigned int sge_copy_mode = rdi->dparms.sge_copy_mode; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci if (sge_copy_mode == RVT_SGE_COPY_CACHELESS) { 282562306a36Sopenharmony_ci cacheless_copy = length >= PAGE_SIZE; 282662306a36Sopenharmony_ci } else if (sge_copy_mode == RVT_SGE_COPY_ADAPTIVE) { 282762306a36Sopenharmony_ci if (length >= PAGE_SIZE) { 282862306a36Sopenharmony_ci /* 282962306a36Sopenharmony_ci * NOTE: this *assumes*: 283062306a36Sopenharmony_ci * o The first vaddr is the dest. 283162306a36Sopenharmony_ci * o If multiple pages, then vaddr is sequential. 283262306a36Sopenharmony_ci */ 283362306a36Sopenharmony_ci wss_insert(wss, sge->vaddr); 283462306a36Sopenharmony_ci if (length >= (2 * PAGE_SIZE)) 283562306a36Sopenharmony_ci wss_insert(wss, (sge->vaddr + PAGE_SIZE)); 283662306a36Sopenharmony_ci 283762306a36Sopenharmony_ci cacheless_copy = wss_exceeds_threshold(wss); 283862306a36Sopenharmony_ci } else { 283962306a36Sopenharmony_ci wss_advance_clean_counter(wss); 284062306a36Sopenharmony_ci } 284162306a36Sopenharmony_ci } 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci if (copy_last) { 284462306a36Sopenharmony_ci if (length > 8) { 284562306a36Sopenharmony_ci length -= 8; 284662306a36Sopenharmony_ci } else { 284762306a36Sopenharmony_ci copy_last = false; 284862306a36Sopenharmony_ci in_last = true; 284962306a36Sopenharmony_ci } 285062306a36Sopenharmony_ci } 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ciagain: 285362306a36Sopenharmony_ci while (length) { 285462306a36Sopenharmony_ci u32 len = rvt_get_sge_length(sge, length); 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci WARN_ON_ONCE(len == 0); 285762306a36Sopenharmony_ci if (unlikely(in_last)) { 285862306a36Sopenharmony_ci /* enforce byte transfer ordering */ 285962306a36Sopenharmony_ci for (i = 0; i < len; i++) 286062306a36Sopenharmony_ci ((u8 *)sge->vaddr)[i] = ((u8 *)data)[i]; 286162306a36Sopenharmony_ci } else if (cacheless_copy) { 286262306a36Sopenharmony_ci cacheless_memcpy(sge->vaddr, data, len); 286362306a36Sopenharmony_ci } else { 286462306a36Sopenharmony_ci memcpy(sge->vaddr, data, len); 286562306a36Sopenharmony_ci } 286662306a36Sopenharmony_ci rvt_update_sge(ss, len, release); 286762306a36Sopenharmony_ci data += len; 286862306a36Sopenharmony_ci length -= len; 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci if (copy_last) { 287262306a36Sopenharmony_ci copy_last = false; 287362306a36Sopenharmony_ci in_last = true; 287462306a36Sopenharmony_ci length = 8; 287562306a36Sopenharmony_ci goto again; 287662306a36Sopenharmony_ci } 287762306a36Sopenharmony_ci} 287862306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_copy_sge); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_cistatic enum ib_wc_status loopback_qp_drop(struct rvt_ibport *rvp, 288162306a36Sopenharmony_ci struct rvt_qp *sqp) 288262306a36Sopenharmony_ci{ 288362306a36Sopenharmony_ci rvp->n_pkt_drops++; 288462306a36Sopenharmony_ci /* 288562306a36Sopenharmony_ci * For RC, the requester would timeout and retry so 288662306a36Sopenharmony_ci * shortcut the timeouts and just signal too many retries. 288762306a36Sopenharmony_ci */ 288862306a36Sopenharmony_ci return sqp->ibqp.qp_type == IB_QPT_RC ? 288962306a36Sopenharmony_ci IB_WC_RETRY_EXC_ERR : IB_WC_SUCCESS; 289062306a36Sopenharmony_ci} 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci/** 289362306a36Sopenharmony_ci * rvt_ruc_loopback - handle UC and RC loopback requests 289462306a36Sopenharmony_ci * @sqp: the sending QP 289562306a36Sopenharmony_ci * 289662306a36Sopenharmony_ci * This is called from rvt_do_send() to forward a WQE addressed to the same HFI 289762306a36Sopenharmony_ci * Note that although we are single threaded due to the send engine, we still 289862306a36Sopenharmony_ci * have to protect against post_send(). We don't have to worry about 289962306a36Sopenharmony_ci * receive interrupts since this is a connected protocol and all packets 290062306a36Sopenharmony_ci * will pass through here. 290162306a36Sopenharmony_ci */ 290262306a36Sopenharmony_civoid rvt_ruc_loopback(struct rvt_qp *sqp) 290362306a36Sopenharmony_ci{ 290462306a36Sopenharmony_ci struct rvt_ibport *rvp = NULL; 290562306a36Sopenharmony_ci struct rvt_dev_info *rdi = ib_to_rvt(sqp->ibqp.device); 290662306a36Sopenharmony_ci struct rvt_qp *qp; 290762306a36Sopenharmony_ci struct rvt_swqe *wqe; 290862306a36Sopenharmony_ci struct rvt_sge *sge; 290962306a36Sopenharmony_ci unsigned long flags; 291062306a36Sopenharmony_ci struct ib_wc wc; 291162306a36Sopenharmony_ci u64 sdata; 291262306a36Sopenharmony_ci atomic64_t *maddr; 291362306a36Sopenharmony_ci enum ib_wc_status send_status; 291462306a36Sopenharmony_ci bool release; 291562306a36Sopenharmony_ci int ret; 291662306a36Sopenharmony_ci bool copy_last = false; 291762306a36Sopenharmony_ci int local_ops = 0; 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci rcu_read_lock(); 292062306a36Sopenharmony_ci rvp = rdi->ports[sqp->port_num - 1]; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci /* 292362306a36Sopenharmony_ci * Note that we check the responder QP state after 292462306a36Sopenharmony_ci * checking the requester's state. 292562306a36Sopenharmony_ci */ 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci qp = rvt_lookup_qpn(ib_to_rvt(sqp->ibqp.device), rvp, 292862306a36Sopenharmony_ci sqp->remote_qpn); 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci /* Return if we are already busy processing a work request. */ 293362306a36Sopenharmony_ci if ((sqp->s_flags & (RVT_S_BUSY | RVT_S_ANY_WAIT)) || 293462306a36Sopenharmony_ci !(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_OR_FLUSH_SEND)) 293562306a36Sopenharmony_ci goto unlock; 293662306a36Sopenharmony_ci 293762306a36Sopenharmony_ci sqp->s_flags |= RVT_S_BUSY; 293862306a36Sopenharmony_ci 293962306a36Sopenharmony_ciagain: 294062306a36Sopenharmony_ci if (sqp->s_last == READ_ONCE(sqp->s_head)) 294162306a36Sopenharmony_ci goto clr_busy; 294262306a36Sopenharmony_ci wqe = rvt_get_swqe_ptr(sqp, sqp->s_last); 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci /* Return if it is not OK to start a new work request. */ 294562306a36Sopenharmony_ci if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_NEXT_SEND_OK)) { 294662306a36Sopenharmony_ci if (!(ib_rvt_state_ops[sqp->state] & RVT_FLUSH_SEND)) 294762306a36Sopenharmony_ci goto clr_busy; 294862306a36Sopenharmony_ci /* We are in the error state, flush the work request. */ 294962306a36Sopenharmony_ci send_status = IB_WC_WR_FLUSH_ERR; 295062306a36Sopenharmony_ci goto flush_send; 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci /* 295462306a36Sopenharmony_ci * We can rely on the entry not changing without the s_lock 295562306a36Sopenharmony_ci * being held until we update s_last. 295662306a36Sopenharmony_ci * We increment s_cur to indicate s_last is in progress. 295762306a36Sopenharmony_ci */ 295862306a36Sopenharmony_ci if (sqp->s_last == sqp->s_cur) { 295962306a36Sopenharmony_ci if (++sqp->s_cur >= sqp->s_size) 296062306a36Sopenharmony_ci sqp->s_cur = 0; 296162306a36Sopenharmony_ci } 296262306a36Sopenharmony_ci spin_unlock_irqrestore(&sqp->s_lock, flags); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_ci if (!qp) { 296562306a36Sopenharmony_ci send_status = loopback_qp_drop(rvp, sqp); 296662306a36Sopenharmony_ci goto serr_no_r_lock; 296762306a36Sopenharmony_ci } 296862306a36Sopenharmony_ci spin_lock_irqsave(&qp->r_lock, flags); 296962306a36Sopenharmony_ci if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) || 297062306a36Sopenharmony_ci qp->ibqp.qp_type != sqp->ibqp.qp_type) { 297162306a36Sopenharmony_ci send_status = loopback_qp_drop(rvp, sqp); 297262306a36Sopenharmony_ci goto serr; 297362306a36Sopenharmony_ci } 297462306a36Sopenharmony_ci 297562306a36Sopenharmony_ci memset(&wc, 0, sizeof(wc)); 297662306a36Sopenharmony_ci send_status = IB_WC_SUCCESS; 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_ci release = true; 297962306a36Sopenharmony_ci sqp->s_sge.sge = wqe->sg_list[0]; 298062306a36Sopenharmony_ci sqp->s_sge.sg_list = wqe->sg_list + 1; 298162306a36Sopenharmony_ci sqp->s_sge.num_sge = wqe->wr.num_sge; 298262306a36Sopenharmony_ci sqp->s_len = wqe->length; 298362306a36Sopenharmony_ci switch (wqe->wr.opcode) { 298462306a36Sopenharmony_ci case IB_WR_REG_MR: 298562306a36Sopenharmony_ci goto send_comp; 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci case IB_WR_LOCAL_INV: 298862306a36Sopenharmony_ci if (!(wqe->wr.send_flags & RVT_SEND_COMPLETION_ONLY)) { 298962306a36Sopenharmony_ci if (rvt_invalidate_rkey(sqp, 299062306a36Sopenharmony_ci wqe->wr.ex.invalidate_rkey)) 299162306a36Sopenharmony_ci send_status = IB_WC_LOC_PROT_ERR; 299262306a36Sopenharmony_ci local_ops = 1; 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci goto send_comp; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 299762306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 299862306a36Sopenharmony_ci case IB_WR_SEND: 299962306a36Sopenharmony_ci ret = rvt_get_rwqe(qp, false); 300062306a36Sopenharmony_ci if (ret < 0) 300162306a36Sopenharmony_ci goto op_err; 300262306a36Sopenharmony_ci if (!ret) 300362306a36Sopenharmony_ci goto rnr_nak; 300462306a36Sopenharmony_ci if (wqe->length > qp->r_len) 300562306a36Sopenharmony_ci goto inv_err; 300662306a36Sopenharmony_ci switch (wqe->wr.opcode) { 300762306a36Sopenharmony_ci case IB_WR_SEND_WITH_INV: 300862306a36Sopenharmony_ci if (!rvt_invalidate_rkey(qp, 300962306a36Sopenharmony_ci wqe->wr.ex.invalidate_rkey)) { 301062306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_INVALIDATE; 301162306a36Sopenharmony_ci wc.ex.invalidate_rkey = 301262306a36Sopenharmony_ci wqe->wr.ex.invalidate_rkey; 301362306a36Sopenharmony_ci } 301462306a36Sopenharmony_ci break; 301562306a36Sopenharmony_ci case IB_WR_SEND_WITH_IMM: 301662306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 301762306a36Sopenharmony_ci wc.ex.imm_data = wqe->wr.ex.imm_data; 301862306a36Sopenharmony_ci break; 301962306a36Sopenharmony_ci default: 302062306a36Sopenharmony_ci break; 302162306a36Sopenharmony_ci } 302262306a36Sopenharmony_ci break; 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_ci case IB_WR_RDMA_WRITE_WITH_IMM: 302562306a36Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) 302662306a36Sopenharmony_ci goto inv_err; 302762306a36Sopenharmony_ci wc.wc_flags = IB_WC_WITH_IMM; 302862306a36Sopenharmony_ci wc.ex.imm_data = wqe->wr.ex.imm_data; 302962306a36Sopenharmony_ci ret = rvt_get_rwqe(qp, true); 303062306a36Sopenharmony_ci if (ret < 0) 303162306a36Sopenharmony_ci goto op_err; 303262306a36Sopenharmony_ci if (!ret) 303362306a36Sopenharmony_ci goto rnr_nak; 303462306a36Sopenharmony_ci /* skip copy_last set and qp_access_flags recheck */ 303562306a36Sopenharmony_ci goto do_write; 303662306a36Sopenharmony_ci case IB_WR_RDMA_WRITE: 303762306a36Sopenharmony_ci copy_last = rvt_is_user_qp(qp); 303862306a36Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) 303962306a36Sopenharmony_ci goto inv_err; 304062306a36Sopenharmony_cido_write: 304162306a36Sopenharmony_ci if (wqe->length == 0) 304262306a36Sopenharmony_ci break; 304362306a36Sopenharmony_ci if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, wqe->length, 304462306a36Sopenharmony_ci wqe->rdma_wr.remote_addr, 304562306a36Sopenharmony_ci wqe->rdma_wr.rkey, 304662306a36Sopenharmony_ci IB_ACCESS_REMOTE_WRITE))) 304762306a36Sopenharmony_ci goto acc_err; 304862306a36Sopenharmony_ci qp->r_sge.sg_list = NULL; 304962306a36Sopenharmony_ci qp->r_sge.num_sge = 1; 305062306a36Sopenharmony_ci qp->r_sge.total_len = wqe->length; 305162306a36Sopenharmony_ci break; 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_ci case IB_WR_RDMA_READ: 305462306a36Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) 305562306a36Sopenharmony_ci goto inv_err; 305662306a36Sopenharmony_ci if (unlikely(!rvt_rkey_ok(qp, &sqp->s_sge.sge, wqe->length, 305762306a36Sopenharmony_ci wqe->rdma_wr.remote_addr, 305862306a36Sopenharmony_ci wqe->rdma_wr.rkey, 305962306a36Sopenharmony_ci IB_ACCESS_REMOTE_READ))) 306062306a36Sopenharmony_ci goto acc_err; 306162306a36Sopenharmony_ci release = false; 306262306a36Sopenharmony_ci sqp->s_sge.sg_list = NULL; 306362306a36Sopenharmony_ci sqp->s_sge.num_sge = 1; 306462306a36Sopenharmony_ci qp->r_sge.sge = wqe->sg_list[0]; 306562306a36Sopenharmony_ci qp->r_sge.sg_list = wqe->sg_list + 1; 306662306a36Sopenharmony_ci qp->r_sge.num_sge = wqe->wr.num_sge; 306762306a36Sopenharmony_ci qp->r_sge.total_len = wqe->length; 306862306a36Sopenharmony_ci break; 306962306a36Sopenharmony_ci 307062306a36Sopenharmony_ci case IB_WR_ATOMIC_CMP_AND_SWP: 307162306a36Sopenharmony_ci case IB_WR_ATOMIC_FETCH_AND_ADD: 307262306a36Sopenharmony_ci if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) 307362306a36Sopenharmony_ci goto inv_err; 307462306a36Sopenharmony_ci if (unlikely(wqe->atomic_wr.remote_addr & (sizeof(u64) - 1))) 307562306a36Sopenharmony_ci goto inv_err; 307662306a36Sopenharmony_ci if (unlikely(!rvt_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), 307762306a36Sopenharmony_ci wqe->atomic_wr.remote_addr, 307862306a36Sopenharmony_ci wqe->atomic_wr.rkey, 307962306a36Sopenharmony_ci IB_ACCESS_REMOTE_ATOMIC))) 308062306a36Sopenharmony_ci goto acc_err; 308162306a36Sopenharmony_ci /* Perform atomic OP and save result. */ 308262306a36Sopenharmony_ci maddr = (atomic64_t *)qp->r_sge.sge.vaddr; 308362306a36Sopenharmony_ci sdata = wqe->atomic_wr.compare_add; 308462306a36Sopenharmony_ci *(u64 *)sqp->s_sge.sge.vaddr = 308562306a36Sopenharmony_ci (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? 308662306a36Sopenharmony_ci (u64)atomic64_add_return(sdata, maddr) - sdata : 308762306a36Sopenharmony_ci (u64)cmpxchg((u64 *)qp->r_sge.sge.vaddr, 308862306a36Sopenharmony_ci sdata, wqe->atomic_wr.swap); 308962306a36Sopenharmony_ci rvt_put_mr(qp->r_sge.sge.mr); 309062306a36Sopenharmony_ci qp->r_sge.num_sge = 0; 309162306a36Sopenharmony_ci goto send_comp; 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci default: 309462306a36Sopenharmony_ci send_status = IB_WC_LOC_QP_OP_ERR; 309562306a36Sopenharmony_ci goto serr; 309662306a36Sopenharmony_ci } 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci sge = &sqp->s_sge.sge; 309962306a36Sopenharmony_ci while (sqp->s_len) { 310062306a36Sopenharmony_ci u32 len = rvt_get_sge_length(sge, sqp->s_len); 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci WARN_ON_ONCE(len == 0); 310362306a36Sopenharmony_ci rvt_copy_sge(qp, &qp->r_sge, sge->vaddr, 310462306a36Sopenharmony_ci len, release, copy_last); 310562306a36Sopenharmony_ci rvt_update_sge(&sqp->s_sge, len, !release); 310662306a36Sopenharmony_ci sqp->s_len -= len; 310762306a36Sopenharmony_ci } 310862306a36Sopenharmony_ci if (release) 310962306a36Sopenharmony_ci rvt_put_ss(&qp->r_sge); 311062306a36Sopenharmony_ci 311162306a36Sopenharmony_ci if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) 311262306a36Sopenharmony_ci goto send_comp; 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) 311562306a36Sopenharmony_ci wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; 311662306a36Sopenharmony_ci else 311762306a36Sopenharmony_ci wc.opcode = IB_WC_RECV; 311862306a36Sopenharmony_ci wc.wr_id = qp->r_wr_id; 311962306a36Sopenharmony_ci wc.status = IB_WC_SUCCESS; 312062306a36Sopenharmony_ci wc.byte_len = wqe->length; 312162306a36Sopenharmony_ci wc.qp = &qp->ibqp; 312262306a36Sopenharmony_ci wc.src_qp = qp->remote_qpn; 312362306a36Sopenharmony_ci wc.slid = rdma_ah_get_dlid(&qp->remote_ah_attr) & U16_MAX; 312462306a36Sopenharmony_ci wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr); 312562306a36Sopenharmony_ci wc.port_num = 1; 312662306a36Sopenharmony_ci /* Signal completion event if the solicited bit is set. */ 312762306a36Sopenharmony_ci rvt_recv_cq(qp, &wc, wqe->wr.send_flags & IB_SEND_SOLICITED); 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_cisend_comp: 313062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 313162306a36Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 313262306a36Sopenharmony_ci rvp->n_loop_pkts++; 313362306a36Sopenharmony_ciflush_send: 313462306a36Sopenharmony_ci sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; 313562306a36Sopenharmony_ci spin_lock(&sqp->r_lock); 313662306a36Sopenharmony_ci rvt_send_complete(sqp, wqe, send_status); 313762306a36Sopenharmony_ci spin_unlock(&sqp->r_lock); 313862306a36Sopenharmony_ci if (local_ops) { 313962306a36Sopenharmony_ci atomic_dec(&sqp->local_ops_pending); 314062306a36Sopenharmony_ci local_ops = 0; 314162306a36Sopenharmony_ci } 314262306a36Sopenharmony_ci goto again; 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_cirnr_nak: 314562306a36Sopenharmony_ci /* Handle RNR NAK */ 314662306a36Sopenharmony_ci if (qp->ibqp.qp_type == IB_QPT_UC) 314762306a36Sopenharmony_ci goto send_comp; 314862306a36Sopenharmony_ci rvp->n_rnr_naks++; 314962306a36Sopenharmony_ci /* 315062306a36Sopenharmony_ci * Note: we don't need the s_lock held since the BUSY flag 315162306a36Sopenharmony_ci * makes this single threaded. 315262306a36Sopenharmony_ci */ 315362306a36Sopenharmony_ci if (sqp->s_rnr_retry == 0) { 315462306a36Sopenharmony_ci send_status = IB_WC_RNR_RETRY_EXC_ERR; 315562306a36Sopenharmony_ci goto serr; 315662306a36Sopenharmony_ci } 315762306a36Sopenharmony_ci if (sqp->s_rnr_retry_cnt < 7) 315862306a36Sopenharmony_ci sqp->s_rnr_retry--; 315962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 316062306a36Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 316162306a36Sopenharmony_ci if (!(ib_rvt_state_ops[sqp->state] & RVT_PROCESS_RECV_OK)) 316262306a36Sopenharmony_ci goto clr_busy; 316362306a36Sopenharmony_ci rvt_add_rnr_timer(sqp, qp->r_min_rnr_timer << 316462306a36Sopenharmony_ci IB_AETH_CREDIT_SHIFT); 316562306a36Sopenharmony_ci goto clr_busy; 316662306a36Sopenharmony_ci 316762306a36Sopenharmony_ciop_err: 316862306a36Sopenharmony_ci send_status = IB_WC_REM_OP_ERR; 316962306a36Sopenharmony_ci wc.status = IB_WC_LOC_QP_OP_ERR; 317062306a36Sopenharmony_ci goto err; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ciinv_err: 317362306a36Sopenharmony_ci send_status = 317462306a36Sopenharmony_ci sqp->ibqp.qp_type == IB_QPT_RC ? 317562306a36Sopenharmony_ci IB_WC_REM_INV_REQ_ERR : 317662306a36Sopenharmony_ci IB_WC_SUCCESS; 317762306a36Sopenharmony_ci wc.status = IB_WC_LOC_QP_OP_ERR; 317862306a36Sopenharmony_ci goto err; 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ciacc_err: 318162306a36Sopenharmony_ci send_status = IB_WC_REM_ACCESS_ERR; 318262306a36Sopenharmony_ci wc.status = IB_WC_LOC_PROT_ERR; 318362306a36Sopenharmony_cierr: 318462306a36Sopenharmony_ci /* responder goes to error state */ 318562306a36Sopenharmony_ci rvt_rc_error(qp, wc.status); 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ciserr: 318862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->r_lock, flags); 318962306a36Sopenharmony_ciserr_no_r_lock: 319062306a36Sopenharmony_ci spin_lock_irqsave(&sqp->s_lock, flags); 319162306a36Sopenharmony_ci spin_lock(&sqp->r_lock); 319262306a36Sopenharmony_ci rvt_send_complete(sqp, wqe, send_status); 319362306a36Sopenharmony_ci spin_unlock(&sqp->r_lock); 319462306a36Sopenharmony_ci if (sqp->ibqp.qp_type == IB_QPT_RC) { 319562306a36Sopenharmony_ci int lastwqe; 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci spin_lock(&sqp->r_lock); 319862306a36Sopenharmony_ci lastwqe = rvt_error_qp(sqp, IB_WC_WR_FLUSH_ERR); 319962306a36Sopenharmony_ci spin_unlock(&sqp->r_lock); 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ci sqp->s_flags &= ~RVT_S_BUSY; 320262306a36Sopenharmony_ci spin_unlock_irqrestore(&sqp->s_lock, flags); 320362306a36Sopenharmony_ci if (lastwqe) { 320462306a36Sopenharmony_ci struct ib_event ev; 320562306a36Sopenharmony_ci 320662306a36Sopenharmony_ci ev.device = sqp->ibqp.device; 320762306a36Sopenharmony_ci ev.element.qp = &sqp->ibqp; 320862306a36Sopenharmony_ci ev.event = IB_EVENT_QP_LAST_WQE_REACHED; 320962306a36Sopenharmony_ci sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); 321062306a36Sopenharmony_ci } 321162306a36Sopenharmony_ci goto done; 321262306a36Sopenharmony_ci } 321362306a36Sopenharmony_ciclr_busy: 321462306a36Sopenharmony_ci sqp->s_flags &= ~RVT_S_BUSY; 321562306a36Sopenharmony_ciunlock: 321662306a36Sopenharmony_ci spin_unlock_irqrestore(&sqp->s_lock, flags); 321762306a36Sopenharmony_cidone: 321862306a36Sopenharmony_ci rcu_read_unlock(); 321962306a36Sopenharmony_ci} 322062306a36Sopenharmony_ciEXPORT_SYMBOL(rvt_ruc_loopback); 3221