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