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 void 87 rdsv3_ib_ring_init(struct rdsv3_ib_work_ring *ring, uint32_t nr) 88 { 89 (void) memset(ring, 0, sizeof (*ring)); 90 ring->w_nr = nr; 91 RDSV3_DPRINTF5("rdsv3_ib_ring_init", "ring %p nr %u", ring, ring->w_nr); 92 } 93 94 static inline uint32_t 95 __rdsv3_ib_ring_used(struct rdsv3_ib_work_ring *ring) 96 { 97 uint32_t diff; 98 99 /* This assumes that atomic_t has at least as many bits as uint32_t */ 100 diff = ring->w_alloc_ctr - (uint32_t)atomic_get(&ring->w_free_ctr); 101 ASSERT(diff <= ring->w_nr); 102 103 return (diff); 104 } 105 106 void 107 rdsv3_ib_ring_resize(struct rdsv3_ib_work_ring *ring, uint32_t nr) 108 { 109 /* 110 * We only ever get called from the connection setup code, 111 * prior to creating the QP. 112 */ 113 ASSERT(!__rdsv3_ib_ring_used(ring)); 114 ring->w_nr = nr; 115 } 116 117 static int 118 __rdsv3_ib_ring_empty(struct rdsv3_ib_work_ring *ring) 119 { 120 return (__rdsv3_ib_ring_used(ring) == 0); 121 } 122 123 uint32_t 124 rdsv3_ib_ring_alloc(struct rdsv3_ib_work_ring *ring, uint32_t val, 125 uint32_t *pos) 126 { 127 uint32_t ret = 0, avail; 128 129 avail = ring->w_nr - __rdsv3_ib_ring_used(ring); 130 131 RDSV3_DPRINTF5("rdsv3_ib_ring_alloc", 132 "ring %p val %u next %u free %u", ring, val, 133 ring->w_alloc_ptr, avail); 134 135 if (val && avail) { 136 ret = min(val, avail); 137 *pos = ring->w_alloc_ptr; 138 139 ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr; 140 ring->w_alloc_ctr += ret; 141 } 142 143 return (ret); 144 } 145 146 void 147 rdsv3_ib_ring_free(struct rdsv3_ib_work_ring *ring, uint32_t val) 148 { 149 ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr; 150 atomic_add_32(&ring->w_free_ctr, val); 151 152 if (__rdsv3_ib_ring_empty(ring)) 153 rdsv3_wake_up(&ring->w_empty_wait); 154 } 155 156 void 157 rdsv3_ib_ring_unalloc(struct rdsv3_ib_work_ring *ring, uint32_t val) 158 { 159 ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr; 160 ring->w_alloc_ctr -= val; 161 } 162 163 int 164 rdsv3_ib_ring_empty(struct rdsv3_ib_work_ring *ring) 165 { 166 return (__rdsv3_ib_ring_empty(ring)); 167 } 168 169 int 170 rdsv3_ib_ring_low(struct rdsv3_ib_work_ring *ring) 171 { 172 return (__rdsv3_ib_ring_used(ring) <= (ring->w_nr >> 2)); 173 } 174 175 /* 176 * returns the oldest alloced ring entry. This will be the next one 177 * freed. This can't be called if there are none allocated. 178 */ 179 uint32_t 180 rdsv3_ib_ring_oldest(struct rdsv3_ib_work_ring *ring) 181 { 182 return (ring->w_free_ptr); 183 } 184 185 /* 186 * returns the number of completed work requests. 187 */ 188 189 uint32_t 190 rdsv3_ib_ring_completed(struct rdsv3_ib_work_ring *ring, 191 uint32_t wr_id, uint32_t oldest) 192 { 193 uint32_t ret; 194 195 if (oldest <= (unsigned long long)wr_id) 196 ret = (unsigned long long)wr_id - oldest + 1; 197 else 198 ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1; 199 200 RDSV3_DPRINTF5("rdsv3_ib_ring_completed", 201 "ring %p ret %u wr_id %u oldest %u", ring, ret, wr_id, oldest); 202 return (ret); 203 } 204