1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Copyright (c) 2006 Oracle. All rights reserved. 27 * 28 * This software is available to you under a choice of one of two 29 * licenses. You may choose to be licensed under the terms of the GNU 30 * General Public License (GPL) Version 2, available from the file 31 * COPYING in the main directory of this source tree, or the 32 * OpenIB.org BSD license below: 33 * 34 * Redistribution and use in source and binary forms, with or 35 * without modification, are permitted provided that the following 36 * conditions are met: 37 * 38 * - Redistributions of source code must retain the above 39 * copyright notice, this list of conditions and the following 40 * disclaimer. 41 * 42 * - Redistributions in binary form must reproduce the above 43 * copyright notice, this list of conditions and the following 44 * disclaimer in the documentation and/or other materials 45 * provided with the distribution. 46 * 47 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 48 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 49 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 50 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 51 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 52 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 53 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 54 * SOFTWARE. 55 * 56 */ 57 #include <sys/rds.h> 58 59 #include <sys/ib/clients/rdsv3/rdsv3.h> 60 #include <sys/ib/clients/rdsv3/ib.h> 61 #include <sys/ib/clients/rdsv3/rdsv3_debug.h> 62 63 /* 64 * Locking for IB rings. 65 * We assume that allocation is always protected by a mutex 66 * in the caller (this is a valid assumption for the current 67 * implementation). 68 * 69 * Freeing always happens in an interrupt, and hence only 70 * races with allocations, but not with other free()s. 71 * 72 * The interaction between allocation and freeing is that 73 * the alloc code has to determine the number of free entries. 74 * To this end, we maintain two counters; an allocation counter 75 * and a free counter. Both are allowed to run freely, and wrap 76 * around. 77 * The number of used entries is always (alloc_ctr - free_ctr) % NR. 78 * 79 * The current implementation makes free_ctr atomic. When the 80 * caller finds an allocation fails, it should set an "alloc fail" 81 * bit and retry the allocation. The "alloc fail" bit essentially tells 82 * the CQ completion handlers to wake it up after freeing some 83 * more entries. 84 */ 85 86 /* 87 * This only happens on shutdown. 88 */ 89 rdsv3_wait_queue_t rdsv3_ib_ring_empty_wait; 90 91 void 92 rdsv3_ib_ring_init(struct rdsv3_ib_work_ring *ring, uint32_t nr) 93 { 94 (void) memset(ring, 0, sizeof (*ring)); 95 ring->w_nr = nr; 96 RDSV3_DPRINTF5("rdsv3_ib_ring_init", "ring %p nr %u", ring, ring->w_nr); 97 } 98 99 static inline uint32_t 100 __rdsv3_ib_ring_used(struct rdsv3_ib_work_ring *ring) 101 { 102 uint32_t diff; 103 104 /* This assumes that atomic_t has at least as many bits as uint32_t */ 105 diff = ring->w_alloc_ctr - (uint32_t)atomic_get(&ring->w_free_ctr); 106 ASSERT(diff <= ring->w_nr); 107 108 return (diff); 109 } 110 111 void 112 rdsv3_ib_ring_resize(struct rdsv3_ib_work_ring *ring, uint32_t nr) 113 { 114 /* 115 * We only ever get called from the connection setup code, 116 * prior to creating the QP. 117 */ 118 ASSERT(!__rdsv3_ib_ring_used(ring)); 119 ring->w_nr = nr; 120 } 121 122 static int 123 __rdsv3_ib_ring_empty(struct rdsv3_ib_work_ring *ring) 124 { 125 return (__rdsv3_ib_ring_used(ring) == 0); 126 } 127 128 uint32_t 129 rdsv3_ib_ring_alloc(struct rdsv3_ib_work_ring *ring, uint32_t val, 130 uint32_t *pos) 131 { 132 uint32_t ret = 0, avail; 133 134 avail = ring->w_nr - __rdsv3_ib_ring_used(ring); 135 136 RDSV3_DPRINTF5("rdsv3_ib_ring_alloc", 137 "ring %p val %u next %u free %u", ring, val, 138 ring->w_alloc_ptr, avail); 139 140 if (val && avail) { 141 ret = min(val, avail); 142 *pos = ring->w_alloc_ptr; 143 144 ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr; 145 ring->w_alloc_ctr += ret; 146 } 147 148 return (ret); 149 } 150 151 void 152 rdsv3_ib_ring_free(struct rdsv3_ib_work_ring *ring, uint32_t val) 153 { 154 ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr; 155 atomic_add_32(&ring->w_free_ctr, val); 156 157 if (__rdsv3_ib_ring_empty(ring)) 158 rdsv3_wake_up(&rdsv3_ib_ring_empty_wait); 159 } 160 161 void 162 rdsv3_ib_ring_unalloc(struct rdsv3_ib_work_ring *ring, uint32_t val) 163 { 164 ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr; 165 ring->w_alloc_ctr -= val; 166 } 167 168 int 169 rdsv3_ib_ring_empty(struct rdsv3_ib_work_ring *ring) 170 { 171 return (__rdsv3_ib_ring_empty(ring)); 172 } 173 174 int 175 rdsv3_ib_ring_low(struct rdsv3_ib_work_ring *ring) 176 { 177 return (__rdsv3_ib_ring_used(ring) <= (ring->w_nr >> 1)); 178 } 179 180 /* 181 * returns the oldest alloced ring entry. This will be the next one 182 * freed. This can't be called if there are none allocated. 183 */ 184 uint32_t 185 rdsv3_ib_ring_oldest(struct rdsv3_ib_work_ring *ring) 186 { 187 return (ring->w_free_ptr); 188 } 189 190 /* 191 * returns the number of completed work requests. 192 */ 193 194 uint32_t 195 rdsv3_ib_ring_completed(struct rdsv3_ib_work_ring *ring, 196 uint32_t wr_id, uint32_t oldest) 197 { 198 uint32_t ret; 199 200 if (oldest <= (unsigned long long)wr_id) 201 ret = (unsigned long long)wr_id - oldest + 1; 202 else 203 ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1; 204 205 RDSV3_DPRINTF5("rdsv3_ib_ring_completed", 206 "ring %p ret %u wr_id %u oldest %u", ring, ret, wr_id, oldest); 207 return (ret); 208 } 209