aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/resource.c')
-rw-r--r--kernel/resource.c152
1 files changed, 128 insertions, 24 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index 03d796c1b2e9..4337063663ef 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -17,6 +17,7 @@
17#include <linux/proc_fs.h> 17#include <linux/proc_fs.h>
18#include <linux/seq_file.h> 18#include <linux/seq_file.h>
19#include <linux/device.h> 19#include <linux/device.h>
20#include <linux/pfn.h>
20#include <asm/io.h> 21#include <asm/io.h>
21 22
22 23
@@ -38,10 +39,6 @@ EXPORT_SYMBOL(iomem_resource);
38 39
39static DEFINE_RWLOCK(resource_lock); 40static DEFINE_RWLOCK(resource_lock);
40 41
41#ifdef CONFIG_PROC_FS
42
43enum { MAX_IORES_LEVEL = 5 };
44
45static void *r_next(struct seq_file *m, void *v, loff_t *pos) 42static void *r_next(struct seq_file *m, void *v, loff_t *pos)
46{ 43{
47 struct resource *p = v; 44 struct resource *p = v;
@@ -53,6 +50,10 @@ static void *r_next(struct seq_file *m, void *v, loff_t *pos)
53 return p->sibling; 50 return p->sibling;
54} 51}
55 52
53#ifdef CONFIG_PROC_FS
54
55enum { MAX_IORES_LEVEL = 5 };
56
56static void *r_start(struct seq_file *m, loff_t *pos) 57static void *r_start(struct seq_file *m, loff_t *pos)
57 __acquires(resource_lock) 58 __acquires(resource_lock)
58{ 59{
@@ -516,6 +517,70 @@ int adjust_resource(struct resource *res, resource_size_t start, resource_size_t
516 return result; 517 return result;
517} 518}
518 519
520static void __init __reserve_region_with_split(struct resource *root,
521 resource_size_t start, resource_size_t end,
522 const char *name)
523{
524 struct resource *parent = root;
525 struct resource *conflict;
526 struct resource *res = kzalloc(sizeof(*res), GFP_ATOMIC);
527
528 if (!res)
529 return;
530
531 res->name = name;
532 res->start = start;
533 res->end = end;
534 res->flags = IORESOURCE_BUSY;
535
536 for (;;) {
537 conflict = __request_resource(parent, res);
538 if (!conflict)
539 break;
540 if (conflict != parent) {
541 parent = conflict;
542 if (!(conflict->flags & IORESOURCE_BUSY))
543 continue;
544 }
545
546 /* Uhhuh, that didn't work out.. */
547 kfree(res);
548 res = NULL;
549 break;
550 }
551
552 if (!res) {
553 /* failed, split and try again */
554
555 /* conflict covered whole area */
556 if (conflict->start <= start && conflict->end >= end)
557 return;
558
559 if (conflict->start > start)
560 __reserve_region_with_split(root, start, conflict->start-1, name);
561 if (!(conflict->flags & IORESOURCE_BUSY)) {
562 resource_size_t common_start, common_end;
563
564 common_start = max(conflict->start, start);
565 common_end = min(conflict->end, end);
566 if (common_start < common_end)
567 __reserve_region_with_split(root, common_start, common_end, name);
568 }
569 if (conflict->end < end)
570 __reserve_region_with_split(root, conflict->end+1, end, name);
571 }
572
573}
574
575void __init reserve_region_with_split(struct resource *root,
576 resource_size_t start, resource_size_t end,
577 const char *name)
578{
579 write_lock(&resource_lock);
580 __reserve_region_with_split(root, start, end, name);
581 write_unlock(&resource_lock);
582}
583
519EXPORT_SYMBOL(adjust_resource); 584EXPORT_SYMBOL(adjust_resource);
520 585
521/** 586/**
@@ -562,33 +627,34 @@ struct resource * __request_region(struct resource *parent,
562{ 627{
563 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); 628 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
564 629
565 if (res) { 630 if (!res)
566 res->name = name; 631 return NULL;
567 res->start = start;
568 res->end = start + n - 1;
569 res->flags = IORESOURCE_BUSY;
570 632
571 write_lock(&resource_lock); 633 res->name = name;
634 res->start = start;
635 res->end = start + n - 1;
636 res->flags = IORESOURCE_BUSY;
572 637
573 for (;;) { 638 write_lock(&resource_lock);
574 struct resource *conflict;
575 639
576 conflict = __request_resource(parent, res); 640 for (;;) {
577 if (!conflict) 641 struct resource *conflict;
578 break;
579 if (conflict != parent) {
580 parent = conflict;
581 if (!(conflict->flags & IORESOURCE_BUSY))
582 continue;
583 }
584 642
585 /* Uhhuh, that didn't work out.. */ 643 conflict = __request_resource(parent, res);
586 kfree(res); 644 if (!conflict)
587 res = NULL;
588 break; 645 break;
646 if (conflict != parent) {
647 parent = conflict;
648 if (!(conflict->flags & IORESOURCE_BUSY))
649 continue;
589 } 650 }
590 write_unlock(&resource_lock); 651
652 /* Uhhuh, that didn't work out.. */
653 kfree(res);
654 res = NULL;
655 break;
591 } 656 }
657 write_unlock(&resource_lock);
592 return res; 658 return res;
593} 659}
594EXPORT_SYMBOL(__request_region); 660EXPORT_SYMBOL(__request_region);
@@ -763,3 +829,41 @@ static int __init reserve_setup(char *str)
763} 829}
764 830
765__setup("reserve=", reserve_setup); 831__setup("reserve=", reserve_setup);
832
833/*
834 * Check if the requested addr and size spans more than any slot in the
835 * iomem resource tree.
836 */
837int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
838{
839 struct resource *p = &iomem_resource;
840 int err = 0;
841 loff_t l;
842
843 read_lock(&resource_lock);
844 for (p = p->child; p ; p = r_next(NULL, p, &l)) {
845 /*
846 * We can probably skip the resources without
847 * IORESOURCE_IO attribute?
848 */
849 if (p->start >= addr + size)
850 continue;
851 if (p->end < addr)
852 continue;
853 if (PFN_DOWN(p->start) <= PFN_DOWN(addr) &&
854 PFN_DOWN(p->end) >= PFN_DOWN(addr + size - 1))
855 continue;
856 printk(KERN_WARNING "resource map sanity check conflict: "
857 "0x%llx 0x%llx 0x%llx 0x%llx %s\n",
858 (unsigned long long)addr,
859 (unsigned long long)(addr + size - 1),
860 (unsigned long long)p->start,
861 (unsigned long long)p->end,
862 p->name);
863 err = -1;
864 break;
865 }
866 read_unlock(&resource_lock);
867
868 return err;
869}