xref: /illumos-gate/usr/src/uts/i86pc/io/ioat/ioat_rs.c (revision 86d949f9497332fe19be6b5d711d265eb957439f)
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