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