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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/kmem.h> 30 #include <sys/types.h> 31 #include <sys/conf.h> 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 35 #include <sys/ioat.h> 36 37 38 /* structure used to keep track of resources */ 39 typedef struct ioat_rs_s { 40 /* 41 * Bounds of resource allocation. We will start allocating at rs_min 42 * and rollover at rs_max+1 (rs_max is included). e.g. for rs_min=0 43 * and rs_max=7, we will have 8 total resources which can be alloced. 44 */ 45 uint_t rs_min; 46 uint_t rs_max; 47 48 /* 49 * rs_free points to an array of 64-bit values used to track resource 50 * allocation. rs_free_size is the free buffer size in bytes. 51 */ 52 uint64_t *rs_free; 53 uint_t rs_free_size; 54 55 /* 56 * last tracks the last alloc'd resource. This allows us to do a round 57 * robin allocation. 58 */ 59 uint_t rs_last; 60 61 kmutex_t rs_mutex; 62 } ioat_rs_t; 63 64 65 /* 66 * ioat_rs_init() 67 * Initialize the resource structure. This structure will be protected 68 * by a mutex at the iblock_cookie passed in. init() returns a handle to be 69 * used for the rest of the resource functions. This code is written assuming 70 * that min_val will be close to 0. Therefore, we will allocate the free 71 * buffer only taking max_val into account. 72 */ 73 void 74 ioat_rs_init(ioat_state_t *state, uint_t min_val, uint_t max_val, 75 ioat_rs_hdl_t *handle) 76 { 77 ioat_rs_t *rstruct; 78 uint_t array_size; 79 uint_t index; 80 81 82 ASSERT(handle != NULL); 83 ASSERT(min_val < max_val); 84 85 /* alloc space for resource structure */ 86 rstruct = kmem_alloc(sizeof (ioat_rs_t), KM_SLEEP); 87 88 /* 89 * Test to see if the max value is 64-bit aligned. If so, we don't need 90 * to allocate an extra 64-bit word. alloc space for free buffer 91 * (8 bytes per uint64_t). 92 */ 93 if ((max_val & 0x3F) == 0) { 94 rstruct->rs_free_size = (max_val >> 6) * 8; 95 } else { 96 rstruct->rs_free_size = ((max_val >> 6) + 1) * 8; 97 } 98 rstruct->rs_free = kmem_alloc(rstruct->rs_free_size, KM_SLEEP); 99 100 /* Initialize resource structure */ 101 rstruct->rs_min = min_val; 102 rstruct->rs_last = min_val; 103 rstruct->rs_max = max_val; 104 mutex_init(&rstruct->rs_mutex, NULL, MUTEX_DRIVER, 105 state->is_iblock_cookie); 106 107 /* Mark all resources as free */ 108 array_size = rstruct->rs_free_size >> 3; 109 for (index = 0; index < array_size; index++) { 110 rstruct->rs_free[index] = (uint64_t)0xFFFFFFFFFFFFFFFF; 111 } 112 113 /* setup handle which is returned from this function */ 114 *handle = rstruct; 115 } 116 117 118 /* 119 * ioat_rs_fini() 120 * Frees up the space allocated in init(). Notice that a pointer to the 121 * handle is used for the parameter. fini() will set the handle to NULL 122 * before returning. 123 */ 124 void 125 ioat_rs_fini(ioat_rs_hdl_t *handle) 126 { 127 ioat_rs_t *rstruct; 128 129 130 ASSERT(handle != NULL); 131 132 rstruct = (ioat_rs_t *)*handle; 133 134 mutex_destroy(&rstruct->rs_mutex); 135 kmem_free(rstruct->rs_free, rstruct->rs_free_size); 136 kmem_free(rstruct, sizeof (ioat_rs_t)); 137 138 /* set handle to null. This helps catch bugs. */ 139 *handle = NULL; 140 } 141 142 143 /* 144 * ioat_rs_alloc() 145 * alloc a resource. If alloc fails, we are out of resources. 146 */ 147 int 148 ioat_rs_alloc(ioat_rs_hdl_t handle, uint_t *resource) 149 { 150 ioat_rs_t *rstruct; 151 uint_t array_idx; 152 uint64_t free; 153 uint_t index; 154 uint_t last; 155 uint_t min; 156 uint_t max; 157 158 159 ASSERT(handle != NULL); 160 ASSERT(resource != NULL); 161 162 rstruct = (ioat_rs_t *)handle; 163 164 mutex_enter(&rstruct->rs_mutex); 165 min = rstruct->rs_min; 166 max = rstruct->rs_max; 167 168 /* 169 * Find a free resource. This will return out of the loop once it finds 170 * a free resource. There are a total of 'max'-'min'+1 resources. 171 * Performs a round robin allocation. 172 */ 173 for (index = min; index <= max; index++) { 174 175 array_idx = rstruct->rs_last >> 6; 176 free = rstruct->rs_free[array_idx]; 177 last = rstruct->rs_last & 0x3F; 178 179 /* if the next resource to check is free */ 180 if ((free & ((uint64_t)1 << last)) != 0) { 181 /* we are using this resource */ 182 *resource = rstruct->rs_last; 183 184 /* take it out of the free list */ 185 rstruct->rs_free[array_idx] &= ~((uint64_t)1 << last); 186 187 /* 188 * increment the last count so we start checking the 189 * next resource on the next alloc(). Note the rollover 190 * at 'max'+1. 191 */ 192 rstruct->rs_last++; 193 if (rstruct->rs_last > max) { 194 rstruct->rs_last = rstruct->rs_min; 195 } 196 197 /* unlock the resource structure */ 198 mutex_exit(&rstruct->rs_mutex); 199 200 return (DDI_SUCCESS); 201 } 202 203 /* 204 * This resource is not free, lets go to the next one. Note the 205 * rollover at 'max'. 206 */ 207 rstruct->rs_last++; 208 if (rstruct->rs_last > max) { 209 rstruct->rs_last = rstruct->rs_min; 210 } 211 } 212 213 mutex_exit(&rstruct->rs_mutex); 214 215 return (DDI_FAILURE); 216 } 217 218 219 /* 220 * ioat_rs_free() 221 * Free the previously alloc'd resource. Once a resource has been free'd, 222 * it can be used again when alloc is called. 223 */ 224 void 225 ioat_rs_free(ioat_rs_hdl_t handle, uint_t resource) 226 { 227 ioat_rs_t *rstruct; 228 uint_t array_idx; 229 uint_t offset; 230 231 232 ASSERT(handle != NULL); 233 234 rstruct = (ioat_rs_t *)handle; 235 ASSERT(resource >= rstruct->rs_min); 236 ASSERT(resource <= rstruct->rs_max); 237 238 mutex_enter(&rstruct->rs_mutex); 239 240 /* Put the resource back in the free list */ 241 array_idx = resource >> 6; 242 offset = resource & 0x3F; 243 rstruct->rs_free[array_idx] |= ((uint64_t)1 << offset); 244 245 mutex_exit(&rstruct->rs_mutex); 246 } 247