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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <sys/types.h>
33 #include <sys/sunddi.h>
38 /* structure used to keep track of resources */
39 typedef struct ioat_rs_s
{
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.
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.
56 * last tracks the last alloc'd resource. This allows us to do a round
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.
74 ioat_rs_init(ioat_state_t
*state
, uint_t min_val
, uint_t max_val
,
75 ioat_rs_hdl_t
*handle
)
82 ASSERT(handle
!= NULL
);
83 ASSERT(min_val
< max_val
);
85 /* alloc space for resource structure */
86 rstruct
= kmem_alloc(sizeof (ioat_rs_t
), KM_SLEEP
);
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).
93 if ((max_val
& 0x3F) == 0) {
94 rstruct
->rs_free_size
= (max_val
>> 6) * 8;
96 rstruct
->rs_free_size
= ((max_val
>> 6) + 1) * 8;
98 rstruct
->rs_free
= kmem_alloc(rstruct
->rs_free_size
, KM_SLEEP
);
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
);
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;
113 /* setup handle which is returned from this function */
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
125 ioat_rs_fini(ioat_rs_hdl_t
*handle
)
130 ASSERT(handle
!= NULL
);
132 rstruct
= (ioat_rs_t
*)*handle
;
134 mutex_destroy(&rstruct
->rs_mutex
);
135 kmem_free(rstruct
->rs_free
, rstruct
->rs_free_size
);
136 kmem_free(rstruct
, sizeof (ioat_rs_t
));
138 /* set handle to null. This helps catch bugs. */
145 * alloc a resource. If alloc fails, we are out of resources.
148 ioat_rs_alloc(ioat_rs_hdl_t handle
, uint_t
*resource
)
159 ASSERT(handle
!= NULL
);
160 ASSERT(resource
!= NULL
);
162 rstruct
= (ioat_rs_t
*)handle
;
164 mutex_enter(&rstruct
->rs_mutex
);
165 min
= rstruct
->rs_min
;
166 max
= rstruct
->rs_max
;
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.
173 for (index
= min
; index
<= max
; index
++) {
175 array_idx
= rstruct
->rs_last
>> 6;
176 free
= rstruct
->rs_free
[array_idx
];
177 last
= rstruct
->rs_last
& 0x3F;
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
;
184 /* take it out of the free list */
185 rstruct
->rs_free
[array_idx
] &= ~((uint64_t)1 << last
);
188 * increment the last count so we start checking the
189 * next resource on the next alloc(). Note the rollover
193 if (rstruct
->rs_last
> max
) {
194 rstruct
->rs_last
= rstruct
->rs_min
;
197 /* unlock the resource structure */
198 mutex_exit(&rstruct
->rs_mutex
);
200 return (DDI_SUCCESS
);
204 * This resource is not free, lets go to the next one. Note the
208 if (rstruct
->rs_last
> max
) {
209 rstruct
->rs_last
= rstruct
->rs_min
;
213 mutex_exit(&rstruct
->rs_mutex
);
215 return (DDI_FAILURE
);
221 * Free the previously alloc'd resource. Once a resource has been free'd,
222 * it can be used again when alloc is called.
225 ioat_rs_free(ioat_rs_hdl_t handle
, uint_t resource
)
232 ASSERT(handle
!= NULL
);
234 rstruct
= (ioat_rs_t
*)handle
;
235 ASSERT(resource
>= rstruct
->rs_min
);
236 ASSERT(resource
<= rstruct
->rs_max
);
238 mutex_enter(&rstruct
->rs_mutex
);
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
);
245 mutex_exit(&rstruct
->rs_mutex
);