@@ -38,6 +38,14 @@ struct resource iomem_resource = {
38
38
};
39
39
EXPORT_SYMBOL (iomem_resource );
40
40
41
+ /* constraints to be met while allocating resources */
42
+ struct resource_constraint {
43
+ resource_size_t min , max , align ;
44
+ resource_size_t (* alignf )(void * , const struct resource * ,
45
+ resource_size_t , resource_size_t );
46
+ void * alignf_data ;
47
+ };
48
+
41
49
static DEFINE_RWLOCK (resource_lock );
42
50
43
51
static void * r_next (struct seq_file * m , void * v , loff_t * pos )
@@ -384,16 +392,13 @@ static bool resource_contains(struct resource *res1, struct resource *res2)
384
392
}
385
393
386
394
/*
387
- * Find empty slot in the resource tree given range and alignment.
395
+ * Find empty slot in the resource tree with the given range and
396
+ * alignment constraints
388
397
*/
389
- static int find_resource (struct resource * root , struct resource * new ,
390
- resource_size_t size , resource_size_t min ,
391
- resource_size_t max , resource_size_t align ,
392
- resource_size_t (* alignf )(void * ,
393
- const struct resource * ,
394
- resource_size_t ,
395
- resource_size_t ),
396
- void * alignf_data )
398
+ static int __find_resource (struct resource * root , struct resource * old ,
399
+ struct resource * new ,
400
+ resource_size_t size ,
401
+ struct resource_constraint * constraint )
397
402
{
398
403
struct resource * this = root -> child ;
399
404
struct resource tmp = * new , avail , alloc ;
@@ -404,25 +409,26 @@ static int find_resource(struct resource *root, struct resource *new,
404
409
* Skip past an allocated resource that starts at 0, since the assignment
405
410
* of this->start - 1 to tmp->end below would cause an underflow.
406
411
*/
407
- if (this && this -> start == 0 ) {
408
- tmp .start = this -> end + 1 ;
412
+ if (this && this -> start == root -> start ) {
413
+ tmp .start = ( this == old ) ? old -> start : this -> end + 1 ;
409
414
this = this -> sibling ;
410
415
}
411
416
for (;;) {
412
417
if (this )
413
- tmp .end = this -> start - 1 ;
418
+ tmp .end = ( this == old ) ? this -> end : this -> start - 1 ;
414
419
else
415
420
tmp .end = root -> end ;
416
421
417
- resource_clip (& tmp , min , max );
422
+ resource_clip (& tmp , constraint -> min , constraint -> max );
418
423
arch_remove_reservations (& tmp );
419
424
420
425
/* Check for overflow after ALIGN() */
421
426
avail = * new ;
422
- avail .start = ALIGN (tmp .start , align );
427
+ avail .start = ALIGN (tmp .start , constraint -> align );
423
428
avail .end = tmp .end ;
424
429
if (avail .start >= tmp .start ) {
425
- alloc .start = alignf (alignf_data , & avail , size , align );
430
+ alloc .start = constraint -> alignf (constraint -> alignf_data , & avail ,
431
+ size , constraint -> align );
426
432
alloc .end = alloc .start + size - 1 ;
427
433
if (resource_contains (& avail , & alloc )) {
428
434
new -> start = alloc .start ;
@@ -432,14 +438,75 @@ static int find_resource(struct resource *root, struct resource *new,
432
438
}
433
439
if (!this )
434
440
break ;
435
- tmp .start = this -> end + 1 ;
441
+ if (this != old )
442
+ tmp .start = this -> end + 1 ;
436
443
this = this -> sibling ;
437
444
}
438
445
return - EBUSY ;
439
446
}
440
447
448
+ /*
449
+ * Find empty slot in the resource tree given range and alignment.
450
+ */
451
+ static int find_resource (struct resource * root , struct resource * new ,
452
+ resource_size_t size ,
453
+ struct resource_constraint * constraint )
454
+ {
455
+ return __find_resource (root , NULL , new , size , constraint );
456
+ }
457
+
441
458
/**
442
- * allocate_resource - allocate empty slot in the resource tree given range & alignment
459
+ * reallocate_resource - allocate a slot in the resource tree given range & alignment.
460
+ * The resource will be relocated if the new size cannot be reallocated in the
461
+ * current location.
462
+ *
463
+ * @root: root resource descriptor
464
+ * @old: resource descriptor desired by caller
465
+ * @newsize: new size of the resource descriptor
466
+ * @constraint: the size and alignment constraints to be met.
467
+ */
468
+ int reallocate_resource (struct resource * root , struct resource * old ,
469
+ resource_size_t newsize ,
470
+ struct resource_constraint * constraint )
471
+ {
472
+ int err = 0 ;
473
+ struct resource new = * old ;
474
+ struct resource * conflict ;
475
+
476
+ write_lock (& resource_lock );
477
+
478
+ if ((err = __find_resource (root , old , & new , newsize , constraint )))
479
+ goto out ;
480
+
481
+ if (resource_contains (& new , old )) {
482
+ old -> start = new .start ;
483
+ old -> end = new .end ;
484
+ goto out ;
485
+ }
486
+
487
+ if (old -> child ) {
488
+ err = - EBUSY ;
489
+ goto out ;
490
+ }
491
+
492
+ if (resource_contains (old , & new )) {
493
+ old -> start = new .start ;
494
+ old -> end = new .end ;
495
+ } else {
496
+ __release_resource (old );
497
+ * old = new ;
498
+ conflict = __request_resource (root , old );
499
+ BUG_ON (conflict );
500
+ }
501
+ out :
502
+ write_unlock (& resource_lock );
503
+ return err ;
504
+ }
505
+
506
+
507
+ /**
508
+ * allocate_resource - allocate empty slot in the resource tree given range & alignment.
509
+ * The resource will be reallocated with a new size if it was already allocated
443
510
* @root: root resource descriptor
444
511
* @new: resource descriptor desired by caller
445
512
* @size: requested resource region size
@@ -459,12 +526,25 @@ int allocate_resource(struct resource *root, struct resource *new,
459
526
void * alignf_data )
460
527
{
461
528
int err ;
529
+ struct resource_constraint constraint ;
462
530
463
531
if (!alignf )
464
532
alignf = simple_align_resource ;
465
533
534
+ constraint .min = min ;
535
+ constraint .max = max ;
536
+ constraint .align = align ;
537
+ constraint .alignf = alignf ;
538
+ constraint .alignf_data = alignf_data ;
539
+
540
+ if ( new -> parent ) {
541
+ /* resource is already allocated, try reallocating with
542
+ the new constraints */
543
+ return reallocate_resource (root , new , size , & constraint );
544
+ }
545
+
466
546
write_lock (& resource_lock );
467
- err = find_resource (root , new , size , min , max , align , alignf , alignf_data );
547
+ err = find_resource (root , new , size , & constraint );
468
548
if (err >= 0 && __request_resource (root , new ))
469
549
err = - EBUSY ;
470
550
write_unlock (& resource_lock );
0 commit comments