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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 1999-2002 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 /*
30 * s1394_addr.c
31 * 1394 Address Space Routines
32 * Implements all the routines necessary for alloc/free and lookup
33 * of the 1394 address space
34 */
35
36 #include <sys/conf.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/types.h>
40 #include <sys/kmem.h>
41 #include <sys/tnf_probe.h>
42
43 #include <sys/1394/t1394.h>
44 #include <sys/1394/s1394.h>
45 #include <sys/1394/h1394.h>
46 #include <sys/1394/ieee1394.h>
47
48 static s1394_addr_space_blk_t *s1394_free_list_search(s1394_hal_t *hal,
49 uint64_t addr);
50
51 static s1394_addr_space_blk_t *s1394_free_list_find(s1394_hal_t *hal,
52 uint32_t type, uint32_t length);
53
54 static s1394_addr_space_blk_t *s1394_free_list_delete(s1394_hal_t *hal,
55 s1394_addr_space_blk_t *del_blk);
56
57 static void s1394_used_tree_insert(s1394_hal_t *hal, s1394_addr_space_blk_t *x);
58
59 static void s1394_tree_insert(s1394_addr_space_blk_t **root,
60 s1394_addr_space_blk_t *z);
61
62 static s1394_addr_space_blk_t *s1394_tree_search(s1394_addr_space_blk_t *x,
63 uint64_t address);
64
65 static void s1394_used_tree_delete_fixup(s1394_addr_space_blk_t **root,
66 s1394_addr_space_blk_t *p, s1394_addr_space_blk_t *x,
67 s1394_addr_space_blk_t *w, int side_of_x);
68
69 static void s1394_left_rotate(s1394_addr_space_blk_t **root,
70 s1394_addr_space_blk_t *x);
71
72 static void s1394_right_rotate(s1394_addr_space_blk_t **root,
73 s1394_addr_space_blk_t *x);
74
75 static s1394_addr_space_blk_t *s1394_tree_minimum(s1394_addr_space_blk_t *x);
76
77 static s1394_addr_space_blk_t *s1394_tree_successor(s1394_addr_space_blk_t *x);
78
79 /*
80 * s1394_request_addr_blk()
81 * is called when a target driver is requesting a block of 1394 Address
82 * Space of a particular type without regard for its exact location. It
83 * searches the free list for a block that's big enough and of the specified
84 * type, and it inserts it into the used tree.
85 */
86 int
s1394_request_addr_blk(s1394_hal_t * hal,t1394_alloc_addr_t * addr_allocp)87 s1394_request_addr_blk(s1394_hal_t *hal, t1394_alloc_addr_t *addr_allocp)
88 {
89 s1394_addr_space_blk_t *curr_blk;
90 s1394_addr_space_blk_t *new_blk;
91 uint64_t amount_free;
92
93 TNF_PROBE_0_DEBUG(s1394_request_addr_blk_enter,
94 S1394_TNF_SL_ARREQ_STACK, "");
95
96 ASSERT(hal != NULL);
97
98 /* Lock the address space "free" list */
99 mutex_enter(&hal->addr_space_free_mutex);
100
101 curr_blk = s1394_free_list_find(hal, addr_allocp->aa_type,
102 addr_allocp->aa_length);
103 if (curr_blk == NULL) {
104 /* Unlock the address space "free" list */
105 mutex_exit(&hal->addr_space_free_mutex);
106
107 TNF_PROBE_1(s1394_request_addr_blk_error,
108 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
109 "1394 address space - no more memory");
110 TNF_PROBE_0_DEBUG(s1394_request_addr_blk_exit,
111 S1394_TNF_SL_ARREQ_STACK, "");
112 return (DDI_FAILURE);
113 }
114
115 amount_free = (curr_blk->addr_hi - curr_blk->addr_lo) + 1;
116 /* Does it fit exact? */
117 if (amount_free == addr_allocp->aa_length) {
118 /* Take it out of the "free" list */
119 curr_blk = s1394_free_list_delete(hal, curr_blk);
120
121 /* Unlock the address space "free" list */
122 mutex_exit(&hal->addr_space_free_mutex);
123
124 curr_blk->addr_enable = addr_allocp->aa_enable;
125 curr_blk->kmem_bufp = addr_allocp->aa_kmem_bufp;
126 curr_blk->addr_arg = addr_allocp->aa_arg;
127 curr_blk->addr_events = addr_allocp->aa_evts;
128
129 addr_allocp->aa_address = curr_blk->addr_lo;
130 addr_allocp->aa_hdl = (t1394_addr_handle_t)curr_blk;
131
132 /* Put it into the "used" tree */
133 s1394_used_tree_insert(hal, curr_blk);
134
135 s1394_addr_alloc_kstat(hal, addr_allocp->aa_address);
136
137 TNF_PROBE_0_DEBUG(s1394_request_addr_blk_exit,
138 S1394_TNF_SL_ARREQ_STACK, "");
139 return (DDI_SUCCESS);
140
141 } else {
142 /* Needs to be broken up */
143 new_blk = (s1394_addr_space_blk_t *)
144 kmem_zalloc(sizeof (s1394_addr_space_blk_t), KM_NOSLEEP);
145 if (new_blk == NULL) {
146 /* Unlock the address space "free" list */
147 mutex_exit(&hal->addr_space_free_mutex);
148 TNF_PROBE_0(s1394_request_addr_blk_error,
149 S1394_TNF_SL_ARREQ_ERROR, "");
150 TNF_PROBE_0_DEBUG(s1394_request_addr_blk_exit,
151 S1394_TNF_SL_ARREQ_STACK, "");
152 return (DDI_FAILURE);
153 }
154
155 new_blk->addr_lo = curr_blk->addr_lo;
156 new_blk->addr_hi = curr_blk->addr_lo +
157 (addr_allocp->aa_length - 1);
158 new_blk->addr_type = curr_blk->addr_type;
159 new_blk->addr_enable = addr_allocp->aa_enable;
160 new_blk->kmem_bufp = addr_allocp->aa_kmem_bufp;
161 new_blk->addr_arg = addr_allocp->aa_arg;
162 new_blk->addr_events = addr_allocp->aa_evts;
163
164 curr_blk->addr_lo = new_blk->addr_hi + 1;
165
166 addr_allocp->aa_address = new_blk->addr_lo;
167 addr_allocp->aa_hdl = (t1394_addr_handle_t)new_blk;
168
169 /* Unlock the address space "free" list */
170 mutex_exit(&hal->addr_space_free_mutex);
171
172 /* Put it into the "used" tree */
173 s1394_used_tree_insert(hal, new_blk);
174
175 s1394_addr_alloc_kstat(hal, addr_allocp->aa_address);
176
177 TNF_PROBE_0_DEBUG(s1394_request_addr_blk_exit,
178 S1394_TNF_SL_ARREQ_STACK, "");
179 return (DDI_SUCCESS);
180 }
181 }
182
183 /*
184 * s1394_claim_addr_blk()
185 * is called when a target driver is requesting a block of 1394 Address
186 * Space with a specific address. If the block containing that address
187 * is not in the free list, or if the block is too small, then
188 * s1394_claim_addr_blk() returns failure. If the block is found,
189 * however, it is inserted into the used tree.
190 */
191 int
s1394_claim_addr_blk(s1394_hal_t * hal,t1394_alloc_addr_t * addr_allocp)192 s1394_claim_addr_blk(s1394_hal_t *hal, t1394_alloc_addr_t *addr_allocp)
193 {
194 s1394_addr_space_blk_t *curr_blk;
195 s1394_addr_space_blk_t *new_blk;
196 s1394_addr_space_blk_t *middle_blk;
197 uint64_t upper_bound;
198
199 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_enter,
200 S1394_TNF_SL_ARREQ_STACK, "");
201
202 ASSERT(hal != NULL);
203
204 /* Lock the address space "free" list */
205 mutex_enter(&hal->addr_space_free_mutex);
206
207 /* Find the block in the "free" list */
208 curr_blk = s1394_free_list_search(hal, addr_allocp->aa_address);
209
210 /* If it wasn't found, it isn't free... */
211 if (curr_blk == NULL) {
212 /* Unlock the address space free list */
213 mutex_exit(&hal->addr_space_free_mutex);
214
215 TNF_PROBE_1(s1394_claim_addr_blk_error,
216 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
217 "1394 address space - address unavailable");
218 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_exit,
219 S1394_TNF_SL_ARREQ_STACK, "");
220 return (DDI_FAILURE);
221 }
222
223 /* Does the request fit in the block? */
224 upper_bound = (addr_allocp->aa_address + addr_allocp->aa_length) - 1;
225 if ((upper_bound >= curr_blk->addr_lo) &&
226 (upper_bound <= curr_blk->addr_hi)) {
227
228 /* How does the requested range fit in the current range? */
229 if (addr_allocp->aa_address == curr_blk->addr_lo) {
230 if (upper_bound == curr_blk->addr_hi) {
231 /* Exact fit */
232
233 /* Take it out of the "free" list */
234 curr_blk = s1394_free_list_delete(hal,
235 curr_blk);
236
237 /* Unlock the address space "free" list */
238 mutex_exit(&hal->addr_space_free_mutex);
239
240 curr_blk->addr_enable = addr_allocp->aa_enable;
241 curr_blk->kmem_bufp = addr_allocp->aa_kmem_bufp;
242 curr_blk->addr_arg = addr_allocp->aa_arg;
243 curr_blk->addr_events = addr_allocp->aa_evts;
244
245 addr_allocp->aa_hdl =
246 (t1394_addr_handle_t)curr_blk;
247
248 /* Put it into the "used" tree */
249 s1394_used_tree_insert(hal, curr_blk);
250
251 s1394_addr_alloc_kstat(hal,
252 addr_allocp->aa_address);
253
254 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_exit,
255 S1394_TNF_SL_ARREQ_STACK, "");
256 return (DDI_SUCCESS);
257
258 } else {
259 /* If space is reserved, must claim it all */
260 if (curr_blk->addr_reserved == ADDR_RESERVED) {
261 goto claim_error;
262 }
263
264 /* Front part of range */
265 new_blk = (s1394_addr_space_blk_t *)
266 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
267 KM_NOSLEEP);
268 if (new_blk == NULL) {
269 /* Unlock the addr space "free" list */
270 mutex_exit(&hal->addr_space_free_mutex);
271 TNF_PROBE_0(s1394_claim_addr_blk_error,
272 S1394_TNF_SL_ARREQ_ERROR, "");
273 TNF_PROBE_0_DEBUG(
274 s1394_claim_addr_blk_exit,
275 S1394_TNF_SL_ARREQ_STACK, "");
276 return (DDI_FAILURE);
277 }
278
279 new_blk->addr_lo = curr_blk->addr_lo;
280 new_blk->addr_hi = upper_bound;
281 new_blk->addr_type = curr_blk->addr_type;
282 new_blk->addr_enable = addr_allocp->aa_enable;
283 new_blk->kmem_bufp = addr_allocp->aa_kmem_bufp;
284 new_blk->addr_arg = addr_allocp->aa_arg;
285 new_blk->addr_events = addr_allocp->aa_evts;
286
287 curr_blk->addr_lo = new_blk->addr_hi + 1;
288
289 addr_allocp->aa_hdl =
290 (t1394_addr_handle_t)new_blk;
291
292 /* Unlock the address space free list */
293 mutex_exit(&hal->addr_space_free_mutex);
294
295 /* Put it into the "used" tree */
296 s1394_used_tree_insert(hal, new_blk);
297
298 s1394_addr_alloc_kstat(hal,
299 addr_allocp->aa_address);
300
301 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_exit,
302 S1394_TNF_SL_ARREQ_STACK, "");
303 return (DDI_SUCCESS);
304 }
305
306 } else {
307 if (upper_bound == curr_blk->addr_hi) {
308 /* If space is reserved, must claim it all */
309 if (curr_blk->addr_reserved == ADDR_RESERVED) {
310 goto claim_error;
311 }
312
313 /* End part of range */
314 new_blk = (s1394_addr_space_blk_t *)
315 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
316 KM_NOSLEEP);
317 if (new_blk == NULL) {
318 /* Unlock the addr space "free" list */
319 mutex_exit(&hal->addr_space_free_mutex);
320 TNF_PROBE_0(s1394_claim_addr_blk_error,
321 S1394_TNF_SL_ARREQ_ERROR, "");
322 TNF_PROBE_0_DEBUG
323 (s1394_claim_addr_blk_exit,
324 S1394_TNF_SL_ARREQ_STACK, "");
325 return (DDI_FAILURE);
326 }
327
328 new_blk->addr_lo = addr_allocp->aa_address;
329 new_blk->addr_hi = upper_bound;
330 new_blk->addr_type = curr_blk->addr_type;
331 new_blk->addr_enable = addr_allocp->aa_enable;
332 new_blk->kmem_bufp = addr_allocp->aa_kmem_bufp;
333 new_blk->addr_arg = addr_allocp->aa_arg;
334 new_blk->addr_events = addr_allocp->aa_evts;
335
336 curr_blk->addr_hi = addr_allocp->aa_address - 1;
337
338 addr_allocp->aa_hdl =
339 (t1394_addr_handle_t)new_blk;
340
341 /* Unlock the address space free list */
342 mutex_exit(&hal->addr_space_free_mutex);
343
344 /* Put it into the "used" tree */
345 s1394_used_tree_insert(hal, new_blk);
346
347 s1394_addr_alloc_kstat(hal,
348 addr_allocp->aa_address);
349
350 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_exit,
351 S1394_TNF_SL_ARREQ_STACK, "");
352 return (DDI_SUCCESS);
353
354 } else {
355 /* If space is reserved, must claim it all */
356 if (curr_blk->addr_reserved == ADDR_RESERVED) {
357 goto claim_error;
358 }
359
360 /* Middle part of range */
361 new_blk = (s1394_addr_space_blk_t *)
362 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
363 KM_NOSLEEP);
364 if (new_blk == NULL) {
365 /* Unlock the addr space "free" list */
366 mutex_exit(&hal->addr_space_free_mutex);
367 TNF_PROBE_0(s1394_claim_addr_blk_error,
368 S1394_TNF_SL_ARREQ_ERROR, "");
369 TNF_PROBE_0_DEBUG(
370 s1394_claim_addr_blk_exit,
371 S1394_TNF_SL_ARREQ_STACK, "");
372 return (DDI_FAILURE);
373 }
374
375 middle_blk = (s1394_addr_space_blk_t *)
376 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
377 KM_NOSLEEP);
378 if (middle_blk == NULL) {
379 /* Unlock the addr space "free" list */
380 mutex_exit(&hal->addr_space_free_mutex);
381 kmem_free(new_blk,
382 sizeof (s1394_addr_space_blk_t));
383 TNF_PROBE_0(s1394_claim_addr_blk_error,
384 S1394_TNF_SL_ARREQ_ERROR, "");
385 TNF_PROBE_0_DEBUG
386 (s1394_claim_addr_blk_exit,
387 S1394_TNF_SL_ARREQ_STACK, "");
388 return (DDI_FAILURE);
389 }
390
391 middle_blk->addr_lo = addr_allocp->aa_address;
392 middle_blk->addr_hi = upper_bound;
393 new_blk->addr_lo = upper_bound + 1;
394 new_blk->addr_hi = curr_blk->addr_hi;
395
396 new_blk->addr_type = curr_blk->addr_type;
397
398 middle_blk->addr_type = curr_blk->addr_type;
399 middle_blk->addr_enable =
400 addr_allocp->aa_enable;
401 middle_blk->kmem_bufp =
402 addr_allocp->aa_kmem_bufp;
403 middle_blk->addr_arg = addr_allocp->aa_arg;
404 middle_blk->addr_events = addr_allocp->aa_evts;
405
406 curr_blk->addr_hi = addr_allocp->aa_address - 1;
407
408 addr_allocp->aa_hdl =
409 (t1394_addr_handle_t)middle_blk;
410
411 /* Put part back into the "free" tree */
412 s1394_free_list_insert(hal, new_blk);
413
414 /* Unlock the address space free list */
415 mutex_exit(&hal->addr_space_free_mutex);
416
417 /* Put it into the "used" tree */
418 s1394_used_tree_insert(hal, middle_blk);
419
420 s1394_addr_alloc_kstat(hal,
421 addr_allocp->aa_address);
422
423 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_exit,
424 S1394_TNF_SL_ARREQ_STACK, "");
425 return (DDI_SUCCESS);
426 }
427 }
428 }
429
430 claim_error:
431 /* Unlock the address space free list */
432 mutex_exit(&hal->addr_space_free_mutex);
433
434 TNF_PROBE_0_DEBUG(s1394_claim_addr_blk_exit,
435 S1394_TNF_SL_ARREQ_STACK, "");
436 return (DDI_FAILURE);
437 }
438
439 /*
440 * s1394_free_addr_blk()
441 * An opposite of s1394_claim_addr_blk(): takes the address block
442 * out of the "used" tree and puts it into the "free" tree.
443 */
444 int
s1394_free_addr_blk(s1394_hal_t * hal,s1394_addr_space_blk_t * blk)445 s1394_free_addr_blk(s1394_hal_t *hal, s1394_addr_space_blk_t *blk)
446 {
447 TNF_PROBE_0_DEBUG(s1394_free_addr_blk_enter, S1394_TNF_SL_ARREQ_STACK,
448 "");
449
450 /* Lock the address space "free" list */
451 mutex_enter(&hal->addr_space_free_mutex);
452
453 /* Take it out of the "used" tree */
454 blk = s1394_used_tree_delete(hal, blk);
455
456 if (blk == NULL) {
457 /* Unlock the address space "free" list */
458 mutex_exit(&hal->addr_space_free_mutex);
459 TNF_PROBE_1(s1394_free_addr_blk_error,
460 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
461 "Can't free block not found in used list");
462 TNF_PROBE_0_DEBUG(s1394_free_addr_blk_exit,
463 S1394_TNF_SL_ARREQ_STACK, "");
464 return (DDI_FAILURE);
465 }
466
467 /* Put it into the "free" tree */
468 s1394_free_list_insert(hal, blk);
469
470 /* Unlock the address space "free" list */
471 mutex_exit(&hal->addr_space_free_mutex);
472
473 TNF_PROBE_0_DEBUG(s1394_free_addr_blk_exit, S1394_TNF_SL_ARREQ_STACK,
474 "");
475 return (DDI_SUCCESS);
476 }
477
478 /*
479 * s1394_reserve_addr_blk()
480 * is similar to s1394_claim_addr_blk(), with the difference being that
481 * after the address block is found, it is marked as "reserved" rather
482 * than inserted into the used tree. Blocks of data that are marked
483 * "reserved" cannot be unintentionally allocated by a target, they must
484 * be specifically requested by specifying the exact address and size of
485 * the "reserved" block.
486 */
487 int
s1394_reserve_addr_blk(s1394_hal_t * hal,t1394_alloc_addr_t * addr_allocp)488 s1394_reserve_addr_blk(s1394_hal_t *hal, t1394_alloc_addr_t *addr_allocp)
489 {
490 s1394_addr_space_blk_t *curr_blk;
491 s1394_addr_space_blk_t *new_blk;
492 s1394_addr_space_blk_t *middle_blk;
493 uint64_t upper_bound;
494
495 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_enter,
496 S1394_TNF_SL_ARREQ_STACK, "");
497
498 ASSERT(hal != NULL);
499
500 /* Lock the address space "free" list */
501 mutex_enter(&hal->addr_space_free_mutex);
502
503 /* Find the block in the "free" list */
504 curr_blk = s1394_free_list_search(hal, addr_allocp->aa_address);
505 /* If it wasn't found, it isn't free... */
506 if (curr_blk == NULL) {
507 /* Unlock the address space free list */
508 mutex_exit(&hal->addr_space_free_mutex);
509
510 TNF_PROBE_1(s1394_reserve_addr_blk_error,
511 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
512 "1394 address space - address unavailable");
513 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
514 S1394_TNF_SL_ARREQ_STACK, "");
515 return (DDI_FAILURE);
516 }
517
518 /* Is this block already reserved? */
519 if (curr_blk->addr_reserved == ADDR_RESERVED) {
520 /* Unlock the address space free list */
521 mutex_exit(&hal->addr_space_free_mutex);
522
523 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
524 S1394_TNF_SL_ARREQ_STACK, "");
525 return (DDI_FAILURE);
526 }
527
528 /* Does the request fit in the block? */
529 upper_bound = (addr_allocp->aa_address + addr_allocp->aa_length) - 1;
530 if ((upper_bound >= curr_blk->addr_lo) &&
531 (upper_bound <= curr_blk->addr_hi)) {
532
533 /* How does the requested range fit in the current range? */
534 if (addr_allocp->aa_address == curr_blk->addr_lo) {
535 if (upper_bound == curr_blk->addr_hi) {
536 /* Exact fit */
537 curr_blk->addr_reserved = ADDR_RESERVED;
538
539 /* Unlock the address space "free" list */
540 mutex_exit(&hal->addr_space_free_mutex);
541
542 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
543 S1394_TNF_SL_ARREQ_STACK, "");
544 return (DDI_SUCCESS);
545
546 } else {
547 /* Front part of range */
548 new_blk = (s1394_addr_space_blk_t *)
549 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
550 KM_NOSLEEP);
551 if (new_blk == NULL) {
552 /* Unlock the addr space "free" list */
553 mutex_exit(&hal->addr_space_free_mutex);
554 TNF_PROBE_0(
555 s1394_reserve_addr_blk_error,
556 S1394_TNF_SL_ARREQ_ERROR, "");
557 TNF_PROBE_0_DEBUG(
558 s1394_reserve_addr_blk_exit,
559 S1394_TNF_SL_ARREQ_STACK, "");
560 return (DDI_FAILURE);
561 }
562
563 new_blk->addr_lo = curr_blk->addr_lo;
564 new_blk->addr_hi = upper_bound;
565 new_blk->addr_type = curr_blk->addr_type;
566 new_blk->addr_reserved = ADDR_RESERVED;
567
568 curr_blk->addr_lo = new_blk->addr_hi + 1;
569
570 /* Put it back into the "free" list */
571 s1394_free_list_insert(hal, new_blk);
572
573 /* Unlock the address space free list */
574 mutex_exit(&hal->addr_space_free_mutex);
575
576 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
577 "stacktrace 1394 s1394 arreq", "");
578 return (DDI_SUCCESS);
579 }
580
581 } else {
582 if (upper_bound == curr_blk->addr_hi) {
583 /* End part of range */
584 new_blk = (s1394_addr_space_blk_t *)
585 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
586 KM_NOSLEEP);
587 if (new_blk == NULL) {
588 /* Unlock the addr space "free" list */
589 mutex_exit(&hal->addr_space_free_mutex);
590 TNF_PROBE_0(
591 s1394_reserve_addr_blk_error,
592 S1394_TNF_SL_ARREQ_ERROR, "");
593 TNF_PROBE_0_DEBUG(
594 s1394_reserve_addr_blk_exit,
595 S1394_TNF_SL_ARREQ_STACK, "");
596 return (DDI_FAILURE);
597 }
598
599 new_blk->addr_lo = addr_allocp->aa_address;
600 new_blk->addr_hi = upper_bound;
601 new_blk->addr_type = curr_blk->addr_type;
602 new_blk->addr_reserved = ADDR_RESERVED;
603
604 curr_blk->addr_hi = addr_allocp->aa_address - 1;
605
606 /* Put it back into the "free" list */
607 s1394_free_list_insert(hal, new_blk);
608
609 /* Unlock the address space free list */
610 mutex_exit(&hal->addr_space_free_mutex);
611
612 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
613 S1394_TNF_SL_ARREQ_STACK, "");
614 return (DDI_SUCCESS);
615
616 } else {
617 /* Middle part of range */
618 new_blk = (s1394_addr_space_blk_t *)
619 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
620 KM_NOSLEEP);
621 if (new_blk == NULL) {
622 /* Unlock the addr space "free" list */
623 mutex_exit(&hal->addr_space_free_mutex);
624 TNF_PROBE_0(
625 s1394_reserve_addr_blk_error,
626 S1394_TNF_SL_ARREQ_ERROR, "");
627 TNF_PROBE_0_DEBUG(
628 s1394_reserve_addr_blk_exit,
629 S1394_TNF_SL_ARREQ_STACK, "");
630 return (DDI_FAILURE);
631 }
632
633 middle_blk = (s1394_addr_space_blk_t *)
634 kmem_zalloc(sizeof (s1394_addr_space_blk_t),
635 KM_NOSLEEP);
636 if (middle_blk == NULL) {
637 /* Unlock the addr space "free" list */
638 mutex_exit(&hal->addr_space_free_mutex);
639 kmem_free(new_blk,
640 sizeof (s1394_addr_space_blk_t));
641 TNF_PROBE_0(
642 s1394_reserve_addr_blk_error,
643 S1394_TNF_SL_ARREQ_ERROR, "");
644 TNF_PROBE_0_DEBUG(
645 s1394_reserve_addr_blk_exit,
646 S1394_TNF_SL_ARREQ_STACK, "");
647 return (DDI_FAILURE);
648 }
649
650 middle_blk->addr_lo = addr_allocp->aa_address;
651 middle_blk->addr_hi = upper_bound;
652 new_blk->addr_lo = upper_bound + 1;
653 new_blk->addr_hi = curr_blk->addr_hi;
654
655 new_blk->addr_type = curr_blk->addr_type;
656
657 middle_blk->addr_type = curr_blk->addr_type;
658 middle_blk->addr_reserved = ADDR_RESERVED;
659
660 curr_blk->addr_hi = addr_allocp->aa_address - 1;
661
662 /* Put pieces back into the "free" list */
663 s1394_free_list_insert(hal, middle_blk);
664 s1394_free_list_insert(hal, new_blk);
665
666 /* Unlock the address space free list */
667 mutex_exit(&hal->addr_space_free_mutex);
668
669 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
670 S1394_TNF_SL_ARREQ_STACK, "");
671 return (DDI_SUCCESS);
672 }
673 }
674 }
675
676 /* Unlock the address space free list */
677 mutex_exit(&hal->addr_space_free_mutex);
678
679 TNF_PROBE_0_DEBUG(s1394_reserve_addr_blk_exit,
680 S1394_TNF_SL_ARREQ_STACK, "");
681 return (DDI_FAILURE);
682 }
683
684 /*
685 * s1394_init_addr_space()
686 * is called in the HAL attach routine - h1394_attach() - to setup the
687 * initial address space with the appropriate ranges, etc. At attach,
688 * the HAL specifies not only the type and bounds for each kind of 1394
689 * address space, but also a list of the blocks that are to be marked
690 * �reserved". Prior to marking the "reserved" ranges the local hosts
691 * CSR registers are allocated/setup in s1394_setup_CSR_space().
692 */
693 int
s1394_init_addr_space(s1394_hal_t * hal)694 s1394_init_addr_space(s1394_hal_t *hal)
695 {
696 s1394_addr_space_blk_t *addr_blk;
697 t1394_alloc_addr_t addr_alloc;
698 h1394_addr_map_t *addr_map;
699 h1394_addr_map_t *resv_map;
700 uint_t num_blks;
701 uint64_t lo;
702 uint64_t hi;
703 int i;
704 int ret;
705
706 TNF_PROBE_0_DEBUG(s1394_init_addr_space_enter,
707 S1394_TNF_SL_ARREQ_STACK, "");
708
709 /* Setup Address Space */
710 mutex_init(&hal->addr_space_free_mutex,
711 NULL, MUTEX_DRIVER, NULL);
712 mutex_init(&hal->addr_space_used_mutex,
713 NULL, MUTEX_DRIVER, hal->halinfo.hw_interrupt);
714
715 /* Set address space to NULL (empty) */
716 hal->addr_space_free_list = NULL;
717 hal->addr_space_used_tree = NULL;
718
719 /* Initialize the 1394 Address Space from HAL's description */
720 num_blks = hal->halinfo.addr_map_num_entries;
721 addr_map = hal->halinfo.addr_map;
722
723 /* Lock the address space free list */
724 mutex_enter(&hal->addr_space_free_mutex);
725
726 /* Default to NO posted write space */
727 hal->posted_write_addr_lo = ADDR_LO_INVALID;
728 hal->posted_write_addr_hi = ADDR_HI_INVALID;
729
730 /* Default to NO physical space */
731 hal->physical_addr_lo = ADDR_LO_INVALID;
732 hal->physical_addr_hi = ADDR_HI_INVALID;
733
734 /* Default to NO CSR space */
735 hal->csr_addr_lo = ADDR_LO_INVALID;
736 hal->csr_addr_hi = ADDR_HI_INVALID;
737
738 /* Default to NO normal space */
739 hal->normal_addr_lo = ADDR_LO_INVALID;
740 hal->normal_addr_hi = ADDR_HI_INVALID;
741
742 for (i = 0; i < num_blks; i++) {
743 if (addr_map[i].length == 0)
744 continue;
745 addr_blk = kmem_zalloc(sizeof (s1394_addr_space_blk_t),
746 KM_SLEEP);
747 addr_blk->addr_lo = addr_map[i].address;
748 addr_blk->addr_hi =
749 (addr_blk->addr_lo + addr_map[i].length) - 1;
750
751 switch (addr_map[i].addr_type) {
752 case H1394_ADDR_POSTED_WRITE:
753 addr_blk->addr_type = T1394_ADDR_POSTED_WRITE;
754 hal->posted_write_addr_lo = addr_blk->addr_lo;
755 hal->posted_write_addr_hi = addr_blk->addr_hi;
756 break;
757
758 case H1394_ADDR_NORMAL:
759 addr_blk->addr_type = T1394_ADDR_NORMAL;
760 hal->normal_addr_lo = addr_blk->addr_lo;
761 hal->normal_addr_hi = addr_blk->addr_hi;
762 break;
763
764 case H1394_ADDR_CSR:
765 addr_blk->addr_type = T1394_ADDR_CSR;
766 hal->csr_addr_lo = addr_blk->addr_lo;
767 hal->csr_addr_hi = addr_blk->addr_hi;
768 break;
769
770 case H1394_ADDR_PHYSICAL:
771 addr_blk->addr_type = T1394_ADDR_FIXED;
772 hal->physical_addr_lo = addr_blk->addr_lo;
773 hal->physical_addr_hi = addr_blk->addr_hi;
774 break;
775
776 default:
777 /* Unlock the address space free list */
778 mutex_exit(&hal->addr_space_free_mutex);
779 s1394_destroy_addr_space(hal);
780 TNF_PROBE_1(s1394_init_addr_space_error,
781 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
782 "Invalid addr_type specified");
783 TNF_PROBE_0_DEBUG(s1394_init_addr_space_exit,
784 S1394_TNF_SL_ARREQ_STACK, "");
785 return (DDI_FAILURE);
786 }
787 s1394_free_list_insert(hal, addr_blk);
788 }
789
790 /* Unlock the address space free list */
791 mutex_exit(&hal->addr_space_free_mutex);
792
793 /* Setup the necessary CSR space */
794 if (s1394_setup_CSR_space(hal) != DDI_SUCCESS) {
795 s1394_destroy_addr_space(hal);
796 TNF_PROBE_1(s1394_init_addr_space_error,
797 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
798 "Failed in s1394_setup_CSR_space()");
799 TNF_PROBE_0_DEBUG(s1394_init_addr_space_exit,
800 S1394_TNF_SL_ARREQ_STACK, "");
801 return (DDI_FAILURE);
802 }
803
804
805 /* Handle all the HAL's reserved spaces */
806 num_blks = hal->halinfo.resv_map_num_entries;
807 resv_map = hal->halinfo.resv_map;
808
809 for (i = 0; i < num_blks; i++) {
810 /* Can't reserve physical addresses */
811 lo = resv_map[i].address;
812 hi = (lo + resv_map[i].length) - 1;
813 if ((lo >= hal->physical_addr_lo) &&
814 (hi <= hal->physical_addr_hi)) {
815 s1394_destroy_addr_space(hal);
816 TNF_PROBE_1(s1394_init_addr_space_error,
817 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
818 "Attempted to reserve physical memory");
819 TNF_PROBE_0_DEBUG(s1394_init_addr_space_exit,
820 S1394_TNF_SL_ARREQ_STACK, "");
821 return (DDI_FAILURE);
822 }
823
824 addr_alloc.aa_address = resv_map[i].address;
825 addr_alloc.aa_length = resv_map[i].length;
826 ret = s1394_reserve_addr_blk(hal, &addr_alloc);
827 if (ret != DDI_SUCCESS) {
828 s1394_destroy_addr_space(hal);
829 TNF_PROBE_1(s1394_init_addr_space_error,
830 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
831 "Unable to reserve 1394 address");
832 TNF_PROBE_0_DEBUG(s1394_init_addr_space_exit,
833 S1394_TNF_SL_ARREQ_STACK, "");
834 return (DDI_FAILURE);
835 }
836 }
837
838 TNF_PROBE_0_DEBUG(s1394_init_addr_space_exit, S1394_TNF_SL_ARREQ_STACK,
839 "");
840 return (DDI_SUCCESS);
841 }
842
843 /*
844 * s1394_destroy_addr_space()
845 * is necessary for h1394_detach(). It undoes all the work that
846 * s1394_init_addr_space() had setup and more. By pulling everything out
847 * of the used tree and free list and then freeing the structures,
848 * mutexes, and (if necessary) any backing store memory, the 1394 address
849 * space is completely dismantled.
850 */
851 void
s1394_destroy_addr_space(s1394_hal_t * hal)852 s1394_destroy_addr_space(s1394_hal_t *hal)
853 {
854 s1394_addr_space_blk_t *addr_blk;
855 s1394_addr_space_blk_t *next_blk;
856 uint64_t lo;
857 uint64_t hi;
858 uint_t length;
859
860 TNF_PROBE_0_DEBUG(s1394_destroy_addr_space_enter,
861 S1394_TNF_SL_ARREQ_STACK, "");
862
863 /* Lock the address space "used" tree */
864 mutex_enter(&hal->addr_space_used_mutex);
865
866 addr_blk = hal->addr_space_used_tree;
867
868 while (addr_blk != NULL) {
869 if (addr_blk->asb_left != NULL) {
870 addr_blk = addr_blk->asb_left;
871 } else if (addr_blk->asb_right != NULL) {
872 addr_blk = addr_blk->asb_right;
873 } else {
874 /* Free any of our own backing store (if necessary) */
875 if ((addr_blk->free_kmem_bufp == B_TRUE) &&
876 (addr_blk->kmem_bufp != NULL)) {
877 lo = addr_blk->addr_lo;
878 hi = addr_blk->addr_hi;
879 length = (uint_t)((hi - lo) + 1);
880 kmem_free((void *)addr_blk->kmem_bufp, length);
881 }
882
883 next_blk = addr_blk->asb_parent;
884
885 /* Free the s1394_addr_space_blk_t structure */
886 kmem_free((void *)addr_blk,
887 sizeof (s1394_addr_space_blk_t));
888
889 if (next_blk != NULL) {
890 if (next_blk->asb_left != NULL)
891 next_blk->asb_left = NULL;
892 else
893 next_blk->asb_right = NULL;
894 }
895
896 addr_blk = next_blk;
897 }
898 }
899
900 /* Unlock and destroy the address space "used" tree */
901 mutex_exit(&hal->addr_space_used_mutex);
902 mutex_destroy(&hal->addr_space_used_mutex);
903
904 /* Lock the address space "free" list */
905 mutex_enter(&hal->addr_space_free_mutex);
906
907 addr_blk = hal->addr_space_free_list;
908
909 while (addr_blk != NULL) {
910 next_blk = addr_blk->asb_right;
911
912 /* Free the s1394_addr_space_blk_t structure */
913 kmem_free((void *)addr_blk, sizeof (s1394_addr_space_blk_t));
914 addr_blk = next_blk;
915 }
916
917 /* Unlock & destroy the address space "free" list */
918 mutex_exit(&hal->addr_space_free_mutex);
919 mutex_destroy(&hal->addr_space_free_mutex);
920
921 TNF_PROBE_0_DEBUG(s1394_destroy_addr_space_exit,
922 S1394_TNF_SL_ARREQ_STACK, "");
923 }
924
925 /*
926 * s1394_free_list_insert()
927 * takes an s1394_addr_space_blk_t and inserts it into the free list in the
928 * appropriate place. It will concatenate into a single structure on the
929 * list any two neighboring blocks that can be joined (same type,
930 * consecutive addresses, neither is "reserved", etc.)
931 */
932 void
s1394_free_list_insert(s1394_hal_t * hal,s1394_addr_space_blk_t * new_blk)933 s1394_free_list_insert(s1394_hal_t *hal, s1394_addr_space_blk_t *new_blk)
934 {
935 s1394_addr_space_blk_t *curr_blk;
936 s1394_addr_space_blk_t *left_blk;
937 s1394_addr_space_blk_t *right_blk;
938
939 TNF_PROBE_0_DEBUG(s1394_free_list_insert_enter,
940 S1394_TNF_SL_ARREQ_STACK, "");
941
942 ASSERT(MUTEX_HELD(&hal->addr_space_free_mutex));
943
944 /* Start at the head of the "free" list */
945 curr_blk = hal->addr_space_free_list;
946
947 if (curr_blk != NULL)
948 left_blk = curr_blk->asb_left;
949 else
950 left_blk = NULL;
951
952 while (curr_blk != NULL) {
953 if (new_blk->addr_lo < curr_blk->addr_lo)
954 break;
955 /* Go to the next element in the list */
956 left_blk = curr_blk;
957 curr_blk = curr_blk->asb_right;
958 }
959
960 new_blk->asb_left = left_blk;
961 new_blk->asb_right = curr_blk;
962
963 if (left_blk != NULL)
964 left_blk->asb_right = new_blk;
965 else
966 hal->addr_space_free_list = new_blk;
967
968 if (curr_blk != NULL)
969 curr_blk->asb_left = new_blk;
970
971 right_blk = new_blk->asb_right;
972 left_blk = new_blk->asb_left;
973
974 /* Can we merge with block to the left? */
975 if ((left_blk != NULL) &&
976 (new_blk->addr_type == left_blk->addr_type) &&
977 (new_blk->addr_reserved != ADDR_RESERVED) &&
978 (left_blk->addr_reserved != ADDR_RESERVED) &&
979 (new_blk->addr_lo == left_blk->addr_hi + 1)) {
980
981 new_blk->addr_lo = left_blk->addr_lo;
982 new_blk->asb_left = left_blk->asb_left;
983
984 if (left_blk->asb_left != NULL)
985 left_blk->asb_left->asb_right = new_blk;
986 if (hal->addr_space_free_list == left_blk)
987 hal->addr_space_free_list = new_blk;
988 kmem_free((void *)left_blk, sizeof (s1394_addr_space_blk_t));
989 }
990
991 /* Can we merge with block to the right? */
992 if ((right_blk != NULL) &&
993 (new_blk->addr_type == right_blk->addr_type) &&
994 (new_blk->addr_reserved != ADDR_RESERVED) &&
995 (right_blk->addr_reserved != ADDR_RESERVED) &&
996 (new_blk->addr_hi + 1 == right_blk->addr_lo)) {
997
998 new_blk->addr_hi = right_blk->addr_hi;
999 new_blk->asb_right = right_blk->asb_right;
1000
1001 if (right_blk->asb_right != NULL)
1002 right_blk->asb_right->asb_left = new_blk;
1003 kmem_free((void *)right_blk, sizeof (s1394_addr_space_blk_t));
1004 }
1005
1006 new_blk->addr_enable = 0;
1007 new_blk->kmem_bufp = NULL;
1008 new_blk->addr_arg = NULL;
1009
1010 TNF_PROBE_0_DEBUG(s1394_free_list_insert_exit,
1011 S1394_TNF_SL_ARREQ_STACK, "");
1012 }
1013
1014 /*
1015 * s1394_free_list_search()
1016 * attempts to find a block in the free list that contains the address
1017 * specified. If none is found, it returns NULL.
1018 */
1019 static s1394_addr_space_blk_t *
s1394_free_list_search(s1394_hal_t * hal,uint64_t addr)1020 s1394_free_list_search(s1394_hal_t *hal, uint64_t addr)
1021 {
1022 s1394_addr_space_blk_t *curr_blk;
1023
1024 TNF_PROBE_0_DEBUG(s1394_free_list_search_enter,
1025 S1394_TNF_SL_ARREQ_STACK, "");
1026
1027 ASSERT(MUTEX_HELD(&hal->addr_space_free_mutex));
1028
1029 /* Start at the head of the list */
1030 curr_blk = hal->addr_space_free_list;
1031 while (curr_blk != NULL) {
1032 if ((addr >= curr_blk->addr_lo) && (addr <= curr_blk->addr_hi))
1033 break;
1034 else
1035 curr_blk = curr_blk->asb_right;
1036 }
1037
1038 TNF_PROBE_0_DEBUG(s1394_free_list_search_exit,
1039 S1394_TNF_SL_ARREQ_STACK, "");
1040 return (curr_blk);
1041 }
1042
1043 /*
1044 * s1394_free_list_find()
1045 * attempts to find a block in the free list that is of the specified
1046 * type and size. It will ignore any blocks marked "reserved".
1047 */
1048 static s1394_addr_space_blk_t *
s1394_free_list_find(s1394_hal_t * hal,uint32_t type,uint32_t length)1049 s1394_free_list_find(s1394_hal_t *hal, uint32_t type, uint32_t length)
1050 {
1051 s1394_addr_space_blk_t *curr_blk;
1052 uint64_t size;
1053
1054 TNF_PROBE_0_DEBUG(s1394_free_list_find_enter, S1394_TNF_SL_ARREQ_STACK,
1055 "");
1056
1057 ASSERT(MUTEX_HELD(&hal->addr_space_free_mutex));
1058
1059 /* Start at the head of the list */
1060 curr_blk = hal->addr_space_free_list;
1061
1062 while (curr_blk != NULL) {
1063 /* Find block of right "type" - that isn't "reserved" */
1064 if ((curr_blk->addr_type == type) &&
1065 (curr_blk->addr_reserved != ADDR_RESERVED)) {
1066
1067 /* CSR allocs above IEEE1394_UCSR_RESERVED_BOUNDARY */
1068 if ((type == T1394_ADDR_CSR) &&
1069 (curr_blk->addr_lo <
1070 IEEE1394_UCSR_RESERVED_BOUNDARY)) {
1071 curr_blk = curr_blk->asb_right;
1072 continue;
1073 }
1074
1075 size = (curr_blk->addr_hi - curr_blk->addr_lo) + 1;
1076 if (size >= (uint64_t)length)
1077 break;
1078 }
1079 curr_blk = curr_blk->asb_right;
1080 }
1081
1082 TNF_PROBE_0_DEBUG(s1394_free_list_find_exit, S1394_TNF_SL_ARREQ_STACK,
1083 "");
1084 return (curr_blk);
1085 }
1086
1087 /*
1088 * s1394_free_list_delete()
1089 * will remove the block pointed to by del_blk from the free list.
1090 * Typically, this is done so that it may be inserted into the used tree.
1091 */
1092 static s1394_addr_space_blk_t *
s1394_free_list_delete(s1394_hal_t * hal,s1394_addr_space_blk_t * del_blk)1093 s1394_free_list_delete(s1394_hal_t *hal, s1394_addr_space_blk_t *del_blk)
1094 {
1095 s1394_addr_space_blk_t *left_blk;
1096 s1394_addr_space_blk_t *right_blk;
1097
1098 TNF_PROBE_0_DEBUG(s1394_free_list_delete_enter,
1099 S1394_TNF_SL_ARREQ_STACK, "");
1100
1101 ASSERT(MUTEX_HELD(&hal->addr_space_free_mutex));
1102
1103 left_blk = del_blk->asb_left;
1104 right_blk = del_blk->asb_right;
1105
1106 del_blk->asb_left = NULL;
1107 del_blk->asb_right = NULL;
1108
1109 if (left_blk != NULL)
1110 left_blk->asb_right = right_blk;
1111 else
1112 hal->addr_space_free_list = right_blk;
1113
1114 if (right_blk != NULL)
1115 right_blk->asb_left = left_blk;
1116
1117 TNF_PROBE_0_DEBUG(s1394_free_list_delete_exit,
1118 S1394_TNF_SL_ARREQ_STACK, "");
1119 return (del_blk);
1120 }
1121
1122 /*
1123 * s1394_used_tree_insert()
1124 * is used to insert a 1394 address block that has been removed from the
1125 * free list into the used tree. In the used tree it will be possible
1126 * to search for a given address when an AR request arrives. Since the
1127 * used tree is implemented as a red-black tree, the insertion is done
1128 * with s1394_tree_insert() which does a simple binary tree insertion.
1129 * It is then followed by cleanup of links and red-black coloring. This
1130 * particulat implementation of the red-black tree is modified from code
1131 * included in "Introduction to Algorithms" - Cormen, Leiserson, and Rivest,
1132 * pp. 263 - 277.
1133 */
1134 static void
s1394_used_tree_insert(s1394_hal_t * hal,s1394_addr_space_blk_t * x)1135 s1394_used_tree_insert(s1394_hal_t *hal, s1394_addr_space_blk_t *x)
1136 {
1137 s1394_addr_space_blk_t *y;
1138 s1394_addr_space_blk_t **root;
1139
1140 TNF_PROBE_0_DEBUG(s1394_used_tree_insert_enter,
1141 S1394_TNF_SL_ARREQ_STACK, "");
1142
1143 /* Lock the "used" tree */
1144 mutex_enter(&hal->addr_space_used_mutex);
1145
1146 /* Get the head of the "used" tree */
1147 root = &hal->addr_space_used_tree;
1148
1149 s1394_tree_insert(root, x);
1150
1151 x->asb_color = RED;
1152 while ((x != *root) && (x->asb_parent->asb_color == RED)) {
1153 /* Is x's parent the "left-child" or the "right-child"? */
1154 if (x->asb_parent == x->asb_parent->asb_parent->asb_left) {
1155 /* Left-child, set y to the sibling */
1156 y = x->asb_parent->asb_parent->asb_right;
1157 if ((y != NULL) && (y->asb_color == RED)) {
1158 x->asb_parent->asb_color = BLACK;
1159 y->asb_color = BLACK;
1160 x->asb_parent->asb_parent->asb_color = RED;
1161 x = x->asb_parent->asb_parent;
1162
1163 } else {
1164 if (x == x->asb_parent->asb_right) {
1165 x = x->asb_parent;
1166 s1394_left_rotate(root, x);
1167 }
1168 x->asb_parent->asb_color = BLACK;
1169 x->asb_parent->asb_parent->asb_color = RED;
1170 s1394_right_rotate(root,
1171 x->asb_parent->asb_parent);
1172 }
1173
1174 } else {
1175 /* Right-child, set y to the sibling */
1176 y = x->asb_parent->asb_parent->asb_left;
1177 if ((y != NULL) && (y->asb_color == RED)) {
1178 x->asb_parent->asb_color = BLACK;
1179 y->asb_color = BLACK;
1180 x->asb_parent->asb_parent->asb_color = RED;
1181 x = x->asb_parent->asb_parent;
1182
1183 } else {
1184 if (x == x->asb_parent->asb_left) {
1185 x = x->asb_parent;
1186 s1394_right_rotate(root, x);
1187 }
1188 x->asb_parent->asb_color = BLACK;
1189 x->asb_parent->asb_parent->asb_color = RED;
1190 s1394_left_rotate(root,
1191 x->asb_parent->asb_parent);
1192 }
1193 }
1194 }
1195
1196 (*root)->asb_color = BLACK;
1197
1198 /* Unlock the "used" tree */
1199 mutex_exit(&hal->addr_space_used_mutex);
1200
1201 TNF_PROBE_0_DEBUG(s1394_used_tree_insert_exit,
1202 S1394_TNF_SL_ARREQ_STACK, "");
1203 }
1204
1205 /*
1206 * s1394_tree_insert()
1207 * is a "helper" function for s1394_used_tree_insert(). It inserts an
1208 * address block into a binary tree (red-black tree), and
1209 * s1394_used_tree_insert() then cleans up the links and colorings, etc.
1210 */
1211 static void
s1394_tree_insert(s1394_addr_space_blk_t ** root,s1394_addr_space_blk_t * z)1212 s1394_tree_insert(s1394_addr_space_blk_t **root, s1394_addr_space_blk_t *z)
1213 {
1214 s1394_addr_space_blk_t *y = NULL;
1215 s1394_addr_space_blk_t *x = *root;
1216
1217 TNF_PROBE_0_DEBUG(s1394_tree_insert_enter, S1394_TNF_SL_ARREQ_STACK,
1218 "");
1219
1220 while (x != NULL) {
1221 y = x;
1222 if (z->addr_lo < x->addr_lo)
1223 x = x->asb_left;
1224 else
1225 x = x->asb_right;
1226 }
1227
1228 z->asb_parent = y;
1229 z->asb_right = NULL;
1230 z->asb_left = NULL;
1231
1232 if (y == NULL)
1233 *root = z;
1234 else if (z->addr_lo < y->addr_lo)
1235 y->asb_left = z;
1236 else
1237 y->asb_right = z;
1238
1239 TNF_PROBE_0_DEBUG(s1394_tree_insert_exit, S1394_TNF_SL_ARREQ_STACK,
1240 "");
1241 }
1242
1243 /*
1244 * s1394_used_tree_search()
1245 * is called when an AR request arrives. By calling s1394_tree_search()
1246 * with the destination address, it can quickly find a block for that
1247 * address (if one exists in the used tree) and return a pointer to it.
1248 */
1249 s1394_addr_space_blk_t *
s1394_used_tree_search(s1394_hal_t * hal,uint64_t addr)1250 s1394_used_tree_search(s1394_hal_t *hal, uint64_t addr)
1251 {
1252 s1394_addr_space_blk_t *curr_blk;
1253
1254 TNF_PROBE_0_DEBUG(s1394_used_tree_search_enter,
1255 S1394_TNF_SL_ARREQ_STACK, "");
1256
1257 ASSERT(MUTEX_HELD(&hal->addr_space_used_mutex));
1258
1259 /* Search the HAL's "used" tree for this address */
1260 curr_blk = s1394_tree_search(hal->addr_space_used_tree, addr);
1261
1262 TNF_PROBE_0_DEBUG(s1394_used_tree_search_exit,
1263 S1394_TNF_SL_ARREQ_STACK, "");
1264 return (curr_blk);
1265 }
1266
1267 /*
1268 * s1394_tree_search()
1269 * is a "helper" function for s1394_used_tree_search(). It implements a
1270 * typical binary tree search with the address as the search key.
1271 */
1272 static s1394_addr_space_blk_t *
s1394_tree_search(s1394_addr_space_blk_t * x,uint64_t address)1273 s1394_tree_search(s1394_addr_space_blk_t *x, uint64_t address)
1274 {
1275 TNF_PROBE_0_DEBUG(s1394_tree_search_enter, S1394_TNF_SL_ARREQ_STACK,
1276 "");
1277
1278 while (x != NULL) {
1279 if (x->addr_lo > address)
1280 x = x->asb_left;
1281 else if (x->addr_hi < address)
1282 x = x->asb_right;
1283 else
1284 break;
1285 }
1286
1287 TNF_PROBE_0_DEBUG(s1394_tree_search_exit, S1394_TNF_SL_ARREQ_STACK,
1288 "");
1289 return (x);
1290 }
1291
1292 /*
1293 * s1394_used_tree_delete()
1294 * is used to remove an address block from the used tree. This is
1295 * necessary when address spaces are freed. The removal is accomplished
1296 * in two steps, the removal done by this function and the cleanup done
1297 * by s1394_used_tree_delete_fixup().
1298 */
1299 s1394_addr_space_blk_t *
s1394_used_tree_delete(s1394_hal_t * hal,s1394_addr_space_blk_t * z)1300 s1394_used_tree_delete(s1394_hal_t *hal, s1394_addr_space_blk_t *z)
1301 {
1302 s1394_addr_space_blk_t *y;
1303 s1394_addr_space_blk_t *x;
1304 s1394_addr_space_blk_t *w;
1305 s1394_addr_space_blk_t *p;
1306 s1394_addr_space_blk_t **root;
1307 int old_color;
1308 int side_of_x;
1309
1310 TNF_PROBE_0_DEBUG(s1394_used_tree_delete_enter,
1311 S1394_TNF_SL_ARREQ_STACK, "");
1312
1313 /* Lock the "used" tree */
1314 mutex_enter(&hal->addr_space_used_mutex);
1315
1316 /* Get the head of the "used" tree */
1317 root = &hal->addr_space_used_tree;
1318
1319 if ((z->asb_left == NULL) || (z->asb_right == NULL))
1320 y = z;
1321 else
1322 y = s1394_tree_successor(z);
1323
1324 if (y->asb_parent == z)
1325 p = y;
1326 else
1327 p = y->asb_parent;
1328
1329 if (y->asb_left != NULL) {
1330 x = y->asb_left;
1331 if ((y != *root) && (y == y->asb_parent->asb_left)) {
1332 w = y->asb_parent->asb_right;
1333 side_of_x = LEFT;
1334 }
1335
1336 if ((y != *root) && (y == y->asb_parent->asb_right)) {
1337 w = y->asb_parent->asb_left;
1338 side_of_x = RIGHT;
1339 }
1340
1341 } else {
1342 x = y->asb_right;
1343 if ((y != *root) && (y == y->asb_parent->asb_left)) {
1344 w = y->asb_parent->asb_right;
1345 side_of_x = LEFT;
1346 }
1347
1348 if ((y != *root) && (y == y->asb_parent->asb_right)) {
1349 w = y->asb_parent->asb_left;
1350 side_of_x = RIGHT;
1351 }
1352
1353 }
1354
1355 if (x != NULL)
1356 x->asb_parent = y->asb_parent;
1357
1358 if (y->asb_parent == NULL)
1359 *root = x;
1360 else if (y == y->asb_parent->asb_left)
1361 y->asb_parent->asb_left = x;
1362 else
1363 y->asb_parent->asb_right = x;
1364
1365 old_color = y->asb_color;
1366
1367 /* Substitute the y-node for the z-node (deleted) */
1368 if (y != z) {
1369 y->asb_color = z->asb_color;
1370 y->asb_parent = z->asb_parent;
1371 if (z->asb_parent != NULL) {
1372 if (z->asb_parent->asb_left == z)
1373 z->asb_parent->asb_left = y;
1374 if (z->asb_parent->asb_right == z)
1375 z->asb_parent->asb_right = y;
1376 }
1377
1378 y->asb_left = z->asb_left;
1379 if (z->asb_left != NULL)
1380 z->asb_left->asb_parent = y;
1381 y->asb_right = z->asb_right;
1382 if (z->asb_right != NULL)
1383 z->asb_right->asb_parent = y;
1384
1385 if (z == *root)
1386 *root = y;
1387 }
1388
1389 z->asb_parent = NULL;
1390 z->asb_right = NULL;
1391 z->asb_left = NULL;
1392
1393 if (old_color == BLACK)
1394 s1394_used_tree_delete_fixup(root, p, x, w, side_of_x);
1395
1396 /* Unlock the "used" tree */
1397 mutex_exit(&hal->addr_space_used_mutex);
1398
1399 TNF_PROBE_0_DEBUG(s1394_used_tree_delete_exit,
1400 S1394_TNF_SL_ARREQ_STACK, "");
1401 return (z);
1402 }
1403
1404 /*
1405 * s1394_used_tree_delete_fixup()
1406 * is the "helper" function for s1394_used_tree_delete(). It is used to
1407 * cleanup/enforce the red-black coloring in the tree.
1408 */
1409 static void
s1394_used_tree_delete_fixup(s1394_addr_space_blk_t ** root,s1394_addr_space_blk_t * p,s1394_addr_space_blk_t * x,s1394_addr_space_blk_t * w,int side_of_x)1410 s1394_used_tree_delete_fixup(s1394_addr_space_blk_t **root,
1411 s1394_addr_space_blk_t *p, s1394_addr_space_blk_t *x,
1412 s1394_addr_space_blk_t *w, int side_of_x)
1413 {
1414 boolean_t first_time;
1415
1416 TNF_PROBE_0_DEBUG(s1394_used_tree_delete_fixup_enter,
1417 S1394_TNF_SL_ARREQ_STACK, "");
1418
1419 first_time = B_TRUE;
1420 while ((x != *root) && ((x == NULL) || (x->asb_color == BLACK))) {
1421 if (((first_time == B_TRUE) && (side_of_x == LEFT)) ||
1422 ((first_time == B_FALSE) && (x == p->asb_left))) {
1423
1424 if (first_time != B_TRUE)
1425 w = p->asb_right;
1426
1427 if ((w != NULL) && (w->asb_color == RED)) {
1428 w->asb_color = BLACK;
1429 p->asb_color = RED;
1430 s1394_left_rotate(root, p);
1431 w = p->asb_right;
1432 }
1433
1434 if (w == NULL) {
1435 x = p;
1436 p = p->asb_parent;
1437 first_time = B_FALSE;
1438
1439 } else if (((w->asb_left == NULL) ||
1440 (w->asb_left->asb_color == BLACK)) &&
1441 ((w->asb_right == NULL) ||
1442 (w->asb_right->asb_color == BLACK))) {
1443 w->asb_color = RED;
1444 x = p;
1445 p = p->asb_parent;
1446 first_time = B_FALSE;
1447
1448 } else {
1449 if ((w->asb_right == NULL) ||
1450 (w->asb_right->asb_color == BLACK)) {
1451 w->asb_left->asb_color = BLACK;
1452 w->asb_color = RED;
1453 s1394_right_rotate(root, w);
1454 w = p->asb_right;
1455 }
1456
1457 w->asb_color = p->asb_color;
1458 p->asb_color = BLACK;
1459 if (w->asb_right != NULL)
1460 w->asb_right->asb_color = BLACK;
1461 s1394_left_rotate(root, p);
1462 x = *root;
1463 first_time = B_FALSE;
1464 }
1465
1466 } else {
1467 if (first_time == B_FALSE)
1468 w = p->asb_left;
1469
1470 if ((w != NULL) && (w->asb_color == RED)) {
1471 w->asb_color = BLACK;
1472 p->asb_color = RED;
1473 s1394_right_rotate(root, p);
1474 w = p->asb_left;
1475 }
1476
1477 if (w == NULL) {
1478 x = p;
1479 p = p->asb_parent;
1480 first_time = B_FALSE;
1481
1482 } else if (((w->asb_left == NULL) ||
1483 (w->asb_left->asb_color == BLACK)) &&
1484 ((w->asb_right == NULL) ||
1485 (w->asb_right->asb_color == BLACK))) {
1486 w->asb_color = RED;
1487 x = p;
1488 p = p->asb_parent;
1489 first_time = B_FALSE;
1490
1491 } else {
1492 if ((w->asb_left == NULL) ||
1493 (w->asb_left->asb_color == BLACK)) {
1494
1495 w->asb_right->asb_color = BLACK;
1496 w->asb_color = RED;
1497 s1394_left_rotate(root, w);
1498 w = p->asb_left;
1499 }
1500
1501 w->asb_color = p->asb_color;
1502 p->asb_color = BLACK;
1503 if (w->asb_left != NULL)
1504 w->asb_left->asb_color = BLACK;
1505 s1394_right_rotate(root, p);
1506 x = *root;
1507 first_time = B_FALSE;
1508 }
1509 }
1510 }
1511 if (x != NULL)
1512 x->asb_color = BLACK;
1513
1514 TNF_PROBE_0_DEBUG(s1394_used_tree_delete_fixup_exit,
1515 S1394_TNF_SL_ARREQ_STACK, "");
1516 }
1517
1518 /*
1519 * s1394_left_rotate()
1520 * is necessary with a red-black tree to help maintain the coloring in the
1521 * tree as items are inserted and removed. Its operation, the opposite of
1522 * s1394_right_rotate(), is a fundamental operation on the red-black tree.
1523 */
1524 static void
s1394_left_rotate(s1394_addr_space_blk_t ** root,s1394_addr_space_blk_t * x)1525 s1394_left_rotate(s1394_addr_space_blk_t **root, s1394_addr_space_blk_t *x)
1526 {
1527 s1394_addr_space_blk_t *y;
1528
1529 TNF_PROBE_0_DEBUG(s1394_left_rotate_enter, S1394_TNF_SL_ARREQ_STACK,
1530 "");
1531
1532 y = x->asb_right;
1533 x->asb_right = y->asb_left;
1534
1535 if (y->asb_left != NULL)
1536 y->asb_left->asb_parent = x;
1537
1538 y->asb_parent = x->asb_parent;
1539 if (x->asb_parent == NULL)
1540 *root = y;
1541 else if (x == x->asb_parent->asb_left)
1542 x->asb_parent->asb_left = y;
1543 else
1544 x->asb_parent->asb_right = y;
1545
1546 y->asb_left = x;
1547 x->asb_parent = y;
1548
1549 TNF_PROBE_0_DEBUG(s1394_left_rotate_exit, S1394_TNF_SL_ARREQ_STACK,
1550 "");
1551 }
1552
1553 /*
1554 * s1394_right_rotate()
1555 * is necessary with a red-black tree to help maintain the coloring in the
1556 * tree as items are inserted and removed. Its operation, the opposite of
1557 * s1394_left_rotate(), is a fundamental operation on the red-black tree.
1558 */
1559 static void
s1394_right_rotate(s1394_addr_space_blk_t ** root,s1394_addr_space_blk_t * x)1560 s1394_right_rotate(s1394_addr_space_blk_t **root, s1394_addr_space_blk_t *x)
1561 {
1562 s1394_addr_space_blk_t *y;
1563
1564 TNF_PROBE_0_DEBUG(s1394_right_rotate_enter, S1394_TNF_SL_ARREQ_STACK,
1565 "");
1566
1567 y = x->asb_left;
1568 x->asb_left = y->asb_right;
1569
1570 if (y->asb_right != NULL)
1571 y->asb_right->asb_parent = x;
1572
1573 y->asb_parent = x->asb_parent;
1574 if (x->asb_parent == NULL)
1575 *root = y;
1576 else if (x == x->asb_parent->asb_right)
1577 x->asb_parent->asb_right = y;
1578 else
1579 x->asb_parent->asb_left = y;
1580
1581 y->asb_right = x;
1582 x->asb_parent = y;
1583
1584 TNF_PROBE_0_DEBUG(s1394_right_rotate_exit, S1394_TNF_SL_ARREQ_STACK,
1585 "");
1586 }
1587
1588 /*
1589 * s1394_tree_minimum()
1590 * is used to find the smallest key in a binary tree.
1591 */
1592 static s1394_addr_space_blk_t *
s1394_tree_minimum(s1394_addr_space_blk_t * x)1593 s1394_tree_minimum(s1394_addr_space_blk_t *x)
1594 {
1595 TNF_PROBE_0_DEBUG(s1394_tree_minimum_enter, S1394_TNF_SL_ARREQ_STACK,
1596 "");
1597
1598 while (x->asb_left != NULL)
1599 x = x->asb_left;
1600
1601 TNF_PROBE_0_DEBUG(s1394_tree_minimum_exit, S1394_TNF_SL_ARREQ_STACK,
1602 "");
1603 return (x);
1604 }
1605
1606 /*
1607 * s1394_tree_successor()
1608 * is used to find the next largest key is a binary tree, given a starting
1609 * point.
1610 */
1611 static s1394_addr_space_blk_t *
s1394_tree_successor(s1394_addr_space_blk_t * x)1612 s1394_tree_successor(s1394_addr_space_blk_t *x)
1613 {
1614 s1394_addr_space_blk_t *y;
1615
1616 TNF_PROBE_0_DEBUG(s1394_tree_successor_enter, S1394_TNF_SL_ARREQ_STACK,
1617 "");
1618
1619 if (x->asb_right != NULL) {
1620 y = s1394_tree_minimum(x->asb_right);
1621
1622 TNF_PROBE_0_DEBUG(s1394_tree_successor_exit,
1623 S1394_TNF_SL_ARREQ_STACK, "");
1624 return (y);
1625 }
1626
1627 y = x->asb_parent;
1628 while ((y != NULL) && (x == y->asb_right)) {
1629 x = y;
1630 y = y->asb_parent;
1631 }
1632
1633 TNF_PROBE_0_DEBUG(s1394_tree_successor_exit, S1394_TNF_SL_ARREQ_STACK,
1634 "");
1635 return (y);
1636 }
1637
1638 /*
1639 * s1394_is_posted_write()
1640 * returns a B_TRUE if the given address is in the "posted write" range
1641 * of the given HAL's 1394 address space and B_FALSE if it isn't.
1642 */
1643 boolean_t
s1394_is_posted_write(s1394_hal_t * hal,uint64_t addr)1644 s1394_is_posted_write(s1394_hal_t *hal, uint64_t addr)
1645 {
1646 addr = addr & IEEE1394_ADDR_OFFSET_MASK;
1647
1648 if ((addr >= hal->posted_write_addr_lo) &&
1649 (addr <= hal->posted_write_addr_hi))
1650 return (B_TRUE);
1651 else
1652 return (B_FALSE);
1653 }
1654
1655 /*
1656 * s1394_is_physical_addr()
1657 * returns a B_TRUE if the given address is in the "physical" range of
1658 * the given HAL's 1394 address space and B_FALSE if it isn't.
1659 */
1660 boolean_t
s1394_is_physical_addr(s1394_hal_t * hal,uint64_t addr)1661 s1394_is_physical_addr(s1394_hal_t *hal, uint64_t addr)
1662 {
1663 addr = addr & IEEE1394_ADDR_OFFSET_MASK;
1664
1665 if ((addr >= hal->physical_addr_lo) &&
1666 (addr <= hal->physical_addr_hi))
1667 return (B_TRUE);
1668 else
1669 return (B_FALSE);
1670 }
1671
1672 /*
1673 * s1394_is_csr_addr()
1674 * returns a B_TRUE if the given address is in the "CSR" range of the
1675 * given HAL's 1394 address space and B_FALSE if it isn't.
1676 */
1677 boolean_t
s1394_is_csr_addr(s1394_hal_t * hal,uint64_t addr)1678 s1394_is_csr_addr(s1394_hal_t *hal, uint64_t addr)
1679 {
1680 addr = addr & IEEE1394_ADDR_OFFSET_MASK;
1681
1682 if ((addr >= hal->csr_addr_lo) &&
1683 (addr <= hal->csr_addr_hi))
1684 return (B_TRUE);
1685 else
1686 return (B_FALSE);
1687 }
1688
1689 /*
1690 * s1394_is_normal_addr()
1691 * returns a B_TRUE if the given address is in the "normal" range of
1692 * the given HAL's 1394 address space and B_FALSE if it isn't.
1693 */
1694 boolean_t
s1394_is_normal_addr(s1394_hal_t * hal,uint64_t addr)1695 s1394_is_normal_addr(s1394_hal_t *hal, uint64_t addr)
1696 {
1697 addr = addr & IEEE1394_ADDR_OFFSET_MASK;
1698
1699 if ((addr >= hal->normal_addr_lo) &&
1700 (addr <= hal->normal_addr_hi))
1701 return (B_TRUE);
1702 else
1703 return (B_FALSE);
1704 }
1705