diff options
author | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-03-20 08:10:47 -0400 |
---|---|---|
committer | Dominik Brodowski <linux@dominikbrodowski.net> | 2010-05-10 04:23:19 -0400 |
commit | b19a7275dec4b470ea9abaae6129d21a0d75ab2f (patch) | |
tree | 9a3824270dee0494a198f969ae5b8c53e4950165 /drivers | |
parent | 49b1153adfe18a3cce7e70aa26c690f275917cd0 (diff) |
pcmcia: clarify alloc_io_space, move it to resource handlers
Clean up the alloc_io_space() function by moving most of it to
the actual resource_ops. This allows for a bit less re-directions.
Future cleanups will follow, and will make up for the code
duplication currently present between rsrc_iodyn and rsrc_nonstatic
(which are hardly ever built at the same time anyway, therefore no
increase in built size).
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 12 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 71 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_iodyn.c | 92 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_mgr.c | 14 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 105 |
5 files changed, 195 insertions, 99 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index ab000ea67296..4126a75445ea 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h | |||
@@ -52,13 +52,11 @@ struct cis_cache_entry { | |||
52 | 52 | ||
53 | struct pccard_resource_ops { | 53 | struct pccard_resource_ops { |
54 | int (*validate_mem) (struct pcmcia_socket *s); | 54 | int (*validate_mem) (struct pcmcia_socket *s); |
55 | int (*adjust_io_region) (struct resource *res, | 55 | int (*find_io) (struct pcmcia_socket *s, |
56 | unsigned long r_start, | 56 | unsigned int attr, |
57 | unsigned long r_end, | 57 | unsigned int *base, |
58 | struct pcmcia_socket *s); | 58 | unsigned int num, |
59 | struct resource* (*find_io) (unsigned long base, int num, | 59 | unsigned int align); |
60 | unsigned long align, | ||
61 | struct pcmcia_socket *s); | ||
62 | struct resource* (*find_mem) (unsigned long base, unsigned long num, | 60 | struct resource* (*find_mem) (unsigned long base, unsigned long num, |
63 | unsigned long align, int low, | 61 | unsigned long align, int low, |
64 | struct pcmcia_socket *s); | 62 | struct pcmcia_socket *s); |
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 9c5f9cd5e03d..c6419c18a6c8 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c | |||
@@ -40,23 +40,6 @@ static int io_speed; | |||
40 | module_param(io_speed, int, 0444); | 40 | module_param(io_speed, int, 0444); |
41 | 41 | ||
42 | 42 | ||
43 | static int pcmcia_adjust_io_region(struct resource *res, unsigned long start, | ||
44 | unsigned long end, struct pcmcia_socket *s) | ||
45 | { | ||
46 | if (s->resource_ops->adjust_io_region) | ||
47 | return s->resource_ops->adjust_io_region(res, start, end, s); | ||
48 | return -ENOMEM; | ||
49 | } | ||
50 | |||
51 | static struct resource *pcmcia_find_io_region(unsigned long base, int num, | ||
52 | unsigned long align, | ||
53 | struct pcmcia_socket *s) | ||
54 | { | ||
55 | if (s->resource_ops->find_io) | ||
56 | return s->resource_ops->find_io(base, num, align, s); | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | int pcmcia_validate_mem(struct pcmcia_socket *s) | 43 | int pcmcia_validate_mem(struct pcmcia_socket *s) |
61 | { | 44 | { |
62 | if (s->resource_ops->validate_mem) | 45 | if (s->resource_ops->validate_mem) |
@@ -82,8 +65,7 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align, | |||
82 | static int alloc_io_space(struct pcmcia_socket *s, u_int attr, | 65 | static int alloc_io_space(struct pcmcia_socket *s, u_int attr, |
83 | unsigned int *base, unsigned int num, u_int lines) | 66 | unsigned int *base, unsigned int num, u_int lines) |
84 | { | 67 | { |
85 | int i; | 68 | unsigned int align; |
86 | unsigned int try, align; | ||
87 | 69 | ||
88 | align = (*base) ? (lines ? 1<<lines : 0) : 1; | 70 | align = (*base) ? (lines ? 1<<lines : 0) : 1; |
89 | if (align && (align < num)) { | 71 | if (align && (align < num)) { |
@@ -100,50 +82,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, | |||
100 | *base, align); | 82 | *base, align); |
101 | align = 0; | 83 | align = 0; |
102 | } | 84 | } |
103 | if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) { | 85 | |
104 | *base = s->io_offset | (*base & 0x0fff); | 86 | return s->resource_ops->find_io(s, attr, base, num, align); |
105 | return 0; | ||
106 | } | ||
107 | /* Check for an already-allocated window that must conflict with | ||
108 | * what was asked for. It is a hack because it does not catch all | ||
109 | * potential conflicts, just the most obvious ones. | ||
110 | */ | ||
111 | for (i = 0; i < MAX_IO_WIN; i++) | ||
112 | if ((s->io[i].res) && *base && | ||
113 | ((s->io[i].res->start & (align-1)) == *base)) | ||
114 | return 1; | ||
115 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
116 | if (!s->io[i].res) { | ||
117 | s->io[i].res = pcmcia_find_io_region(*base, num, align, s); | ||
118 | if (s->io[i].res) { | ||
119 | *base = s->io[i].res->start; | ||
120 | s->io[i].res->flags = (s->io[i].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS); | ||
121 | s->io[i].InUse = num; | ||
122 | break; | ||
123 | } else | ||
124 | return 1; | ||
125 | } else if ((s->io[i].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS)) | ||
126 | continue; | ||
127 | /* Try to extend top of window */ | ||
128 | try = s->io[i].res->end + 1; | ||
129 | if ((*base == 0) || (*base == try)) | ||
130 | if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start, | ||
131 | s->io[i].res->end + num, s) == 0) { | ||
132 | *base = try; | ||
133 | s->io[i].InUse += num; | ||
134 | break; | ||
135 | } | ||
136 | /* Try to extend bottom of window */ | ||
137 | try = s->io[i].res->start - num; | ||
138 | if ((*base == 0) || (*base == try)) | ||
139 | if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num, | ||
140 | s->io[i].res->end, s) == 0) { | ||
141 | *base = try; | ||
142 | s->io[i].InUse += num; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | return (i == MAX_IO_WIN); | ||
147 | } /* alloc_io_space */ | 87 | } /* alloc_io_space */ |
148 | 88 | ||
149 | 89 | ||
@@ -683,7 +623,8 @@ EXPORT_SYMBOL(pcmcia_request_irq); | |||
683 | * free_irq themselves, too), or the pcmcia_request_irq() function. | 623 | * free_irq themselves, too), or the pcmcia_request_irq() function. |
684 | */ | 624 | */ |
685 | int __must_check | 625 | int __must_check |
686 | pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, irq_handler_t handler) | 626 | __pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, |
627 | irq_handler_t handler) | ||
687 | { | 628 | { |
688 | int ret; | 629 | int ret; |
689 | 630 | ||
@@ -705,7 +646,7 @@ pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, irq_handler_t handler) | |||
705 | 646 | ||
706 | return ret; | 647 | return ret; |
707 | } /* pcmcia_request_exclusive_irq */ | 648 | } /* pcmcia_request_exclusive_irq */ |
708 | EXPORT_SYMBOL(pcmcia_request_exclusive_irq); | 649 | EXPORT_SYMBOL(__pcmcia_request_exclusive_irq); |
709 | 650 | ||
710 | 651 | ||
711 | #ifdef CONFIG_PCMCIA_PROBE | 652 | #ifdef CONFIG_PCMCIA_PROBE |
diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c index 3fa808b582f6..779137561580 100644 --- a/drivers/pcmcia/rsrc_iodyn.c +++ b/drivers/pcmcia/rsrc_iodyn.c | |||
@@ -56,15 +56,9 @@ static resource_size_t pcmcia_align(void *align_data, | |||
56 | } | 56 | } |
57 | 57 | ||
58 | 58 | ||
59 | static int iodyn_adjust_io_region(struct resource *res, unsigned long r_start, | 59 | static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s, |
60 | unsigned long r_end, struct pcmcia_socket *s) | 60 | unsigned long base, int num, |
61 | { | 61 | unsigned long align) |
62 | return adjust_resource(res, r_start, r_end - r_start + 1); | ||
63 | } | ||
64 | |||
65 | |||
66 | static struct resource *iodyn_find_io_region(unsigned long base, int num, | ||
67 | unsigned long align, struct pcmcia_socket *s) | ||
68 | { | 62 | { |
69 | struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, | 63 | struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, |
70 | dev_name(&s->dev)); | 64 | dev_name(&s->dev)); |
@@ -72,9 +66,6 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num, | |||
72 | unsigned long min = base; | 66 | unsigned long min = base; |
73 | int ret; | 67 | int ret; |
74 | 68 | ||
75 | if (align == 0) | ||
76 | align = 0x10000; | ||
77 | |||
78 | data.mask = align - 1; | 69 | data.mask = align - 1; |
79 | data.offset = base & data.mask; | 70 | data.offset = base & data.mask; |
80 | 71 | ||
@@ -94,10 +85,83 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num, | |||
94 | return res; | 85 | return res; |
95 | } | 86 | } |
96 | 87 | ||
88 | static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr, | ||
89 | unsigned int *base, unsigned int num, | ||
90 | unsigned int align) | ||
91 | { | ||
92 | int i, ret = 0; | ||
93 | |||
94 | /* Check for an already-allocated window that must conflict with | ||
95 | * what was asked for. It is a hack because it does not catch all | ||
96 | * potential conflicts, just the most obvious ones. | ||
97 | */ | ||
98 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
99 | if (!s->io[i].res) | ||
100 | continue; | ||
101 | |||
102 | if (!*base) | ||
103 | continue; | ||
104 | |||
105 | if ((s->io[i].res->start & (align-1)) == *base) | ||
106 | return -EBUSY; | ||
107 | } | ||
108 | |||
109 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
110 | struct resource *res = s->io[i].res; | ||
111 | unsigned int try; | ||
112 | |||
113 | if (res && (res->flags & IORESOURCE_BITS) != | ||
114 | (attr & IORESOURCE_BITS)) | ||
115 | continue; | ||
116 | |||
117 | if (!res) { | ||
118 | if (align == 0) | ||
119 | align = 0x10000; | ||
120 | |||
121 | res = s->io[i].res = __iodyn_find_io_region(s, *base, | ||
122 | num, align); | ||
123 | if (!res) | ||
124 | return -EINVAL; | ||
125 | |||
126 | *base = res->start; | ||
127 | s->io[i].res->flags = | ||
128 | ((res->flags & ~IORESOURCE_BITS) | | ||
129 | (attr & IORESOURCE_BITS)); | ||
130 | s->io[i].InUse = num; | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /* Try to extend top of window */ | ||
135 | try = res->end + 1; | ||
136 | if ((*base == 0) || (*base == try)) { | ||
137 | if (adjust_resource(s->io[i].res, res->start, | ||
138 | res->end - res->start + num + 1)) | ||
139 | continue; | ||
140 | *base = try; | ||
141 | s->io[i].InUse += num; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* Try to extend bottom of window */ | ||
146 | try = res->start - num; | ||
147 | if ((*base == 0) || (*base == try)) { | ||
148 | if (adjust_resource(s->io[i].res, | ||
149 | res->start - num, | ||
150 | res->end - res->start + num + 1)) | ||
151 | continue; | ||
152 | *base = try; | ||
153 | s->io[i].InUse += num; | ||
154 | return 0; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | return -EINVAL; | ||
159 | } | ||
160 | |||
161 | |||
97 | struct pccard_resource_ops pccard_iodyn_ops = { | 162 | struct pccard_resource_ops pccard_iodyn_ops = { |
98 | .validate_mem = NULL, | 163 | .validate_mem = NULL, |
99 | .adjust_io_region = iodyn_adjust_io_region, | 164 | .find_io = iodyn_find_io, |
100 | .find_io = iodyn_find_io_region, | ||
101 | .find_mem = NULL, | 165 | .find_mem = NULL, |
102 | .add_io = NULL, | 166 | .add_io = NULL, |
103 | .add_mem = NULL, | 167 | .add_mem = NULL, |
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 71838cae890c..142efac3c387 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c | |||
@@ -46,11 +46,21 @@ struct resource *pcmcia_make_resource(unsigned long start, unsigned long end, | |||
46 | return res; | 46 | return res; |
47 | } | 47 | } |
48 | 48 | ||
49 | static int static_find_io(struct pcmcia_socket *s, unsigned int attr, | ||
50 | unsigned int *base, unsigned int num, | ||
51 | unsigned int align) | ||
52 | { | ||
53 | if (!s->io_offset) | ||
54 | return -EINVAL; | ||
55 | *base = s->io_offset | (*base & 0x0fff); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
49 | 60 | ||
50 | struct pccard_resource_ops pccard_static_ops = { | 61 | struct pccard_resource_ops pccard_static_ops = { |
51 | .validate_mem = NULL, | 62 | .validate_mem = NULL, |
52 | .adjust_io_region = NULL, | 63 | .find_io = static_find_io, |
53 | .find_io = NULL, | ||
54 | .find_mem = NULL, | 64 | .find_mem = NULL, |
55 | .add_io = NULL, | 65 | .add_io = NULL, |
56 | .add_mem = NULL, | 66 | .add_mem = NULL, |
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index c5ebc603b058..ba5256debde2 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -649,8 +649,9 @@ pcmcia_align(void *align_data, const struct resource *res, | |||
649 | * Adjust an existing IO region allocation, but making sure that we don't | 649 | * Adjust an existing IO region allocation, but making sure that we don't |
650 | * encroach outside the resources which the user supplied. | 650 | * encroach outside the resources which the user supplied. |
651 | */ | 651 | */ |
652 | static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start, | 652 | static int __nonstatic_adjust_io_region(struct pcmcia_socket *s, |
653 | unsigned long r_end, struct pcmcia_socket *s) | 653 | unsigned long r_start, |
654 | unsigned long r_end) | ||
654 | { | 655 | { |
655 | struct resource_map *m; | 656 | struct resource_map *m; |
656 | struct socket_data *s_data = s->resource_data; | 657 | struct socket_data *s_data = s->resource_data; |
@@ -663,8 +664,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
663 | if (start > r_start || r_end > end) | 664 | if (start > r_start || r_end > end) |
664 | continue; | 665 | continue; |
665 | 666 | ||
666 | ret = adjust_resource(res, r_start, r_end - r_start + 1); | 667 | ret = 0; |
667 | break; | ||
668 | } | 668 | } |
669 | 669 | ||
670 | return ret; | 670 | return ret; |
@@ -683,8 +683,9 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
683 | 683 | ||
684 | ======================================================================*/ | 684 | ======================================================================*/ |
685 | 685 | ||
686 | static struct resource *nonstatic_find_io_region(unsigned long base, int num, | 686 | static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s, |
687 | unsigned long align, struct pcmcia_socket *s) | 687 | unsigned long base, int num, |
688 | unsigned long align) | ||
688 | { | 689 | { |
689 | struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, | 690 | struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, |
690 | dev_name(&s->dev)); | 691 | dev_name(&s->dev)); |
@@ -693,9 +694,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, | |||
693 | unsigned long min = base; | 694 | unsigned long min = base; |
694 | int ret; | 695 | int ret; |
695 | 696 | ||
696 | if (align == 0) | ||
697 | align = 0x10000; | ||
698 | |||
699 | data.mask = align - 1; | 697 | data.mask = align - 1; |
700 | data.offset = base & data.mask; | 698 | data.offset = base & data.mask; |
701 | data.map = &s_data->io_db; | 699 | data.map = &s_data->io_db; |
@@ -716,6 +714,92 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, | |||
716 | return res; | 714 | return res; |
717 | } | 715 | } |
718 | 716 | ||
717 | static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr, | ||
718 | unsigned int *base, unsigned int num, | ||
719 | unsigned int align) | ||
720 | { | ||
721 | int i, ret = 0; | ||
722 | |||
723 | /* Check for an already-allocated window that must conflict with | ||
724 | * what was asked for. It is a hack because it does not catch all | ||
725 | * potential conflicts, just the most obvious ones. | ||
726 | */ | ||
727 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
728 | if (!s->io[i].res) | ||
729 | continue; | ||
730 | |||
731 | if (!*base) | ||
732 | continue; | ||
733 | |||
734 | if ((s->io[i].res->start & (align-1)) == *base) | ||
735 | return -EBUSY; | ||
736 | } | ||
737 | |||
738 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
739 | struct resource *res = s->io[i].res; | ||
740 | unsigned int try; | ||
741 | |||
742 | if (res && (res->flags & IORESOURCE_BITS) != | ||
743 | (attr & IORESOURCE_BITS)) | ||
744 | continue; | ||
745 | |||
746 | if (!res) { | ||
747 | if (align == 0) | ||
748 | align = 0x10000; | ||
749 | |||
750 | res = s->io[i].res = __nonstatic_find_io_region(s, | ||
751 | *base, num, | ||
752 | align); | ||
753 | if (!res) | ||
754 | return -EINVAL; | ||
755 | |||
756 | *base = res->start; | ||
757 | s->io[i].res->flags = | ||
758 | ((res->flags & ~IORESOURCE_BITS) | | ||
759 | (attr & IORESOURCE_BITS)); | ||
760 | s->io[i].InUse = num; | ||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* Try to extend top of window */ | ||
765 | try = res->end + 1; | ||
766 | if ((*base == 0) || (*base == try)) { | ||
767 | ret = __nonstatic_adjust_io_region(s, res->start, | ||
768 | res->end + num); | ||
769 | if (!ret) { | ||
770 | ret = adjust_resource(s->io[i].res, res->start, | ||
771 | res->end - res->start + num + 1); | ||
772 | if (ret) | ||
773 | continue; | ||
774 | *base = try; | ||
775 | s->io[i].InUse += num; | ||
776 | return 0; | ||
777 | } | ||
778 | } | ||
779 | |||
780 | /* Try to extend bottom of window */ | ||
781 | try = res->start - num; | ||
782 | if ((*base == 0) || (*base == try)) { | ||
783 | ret = __nonstatic_adjust_io_region(s, | ||
784 | res->start - num, | ||
785 | res->end); | ||
786 | if (!ret) { | ||
787 | ret = adjust_resource(s->io[i].res, | ||
788 | res->start - num, | ||
789 | res->end - res->start + num + 1); | ||
790 | if (ret) | ||
791 | continue; | ||
792 | *base = try; | ||
793 | s->io[i].InUse += num; | ||
794 | return 0; | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | |||
799 | return -EINVAL; | ||
800 | } | ||
801 | |||
802 | |||
719 | static struct resource *nonstatic_find_mem_region(u_long base, u_long num, | 803 | static struct resource *nonstatic_find_mem_region(u_long base, u_long num, |
720 | u_long align, int low, struct pcmcia_socket *s) | 804 | u_long align, int low, struct pcmcia_socket *s) |
721 | { | 805 | { |
@@ -946,8 +1030,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) | |||
946 | 1030 | ||
947 | struct pccard_resource_ops pccard_nonstatic_ops = { | 1031 | struct pccard_resource_ops pccard_nonstatic_ops = { |
948 | .validate_mem = pcmcia_nonstatic_validate_mem, | 1032 | .validate_mem = pcmcia_nonstatic_validate_mem, |
949 | .adjust_io_region = nonstatic_adjust_io_region, | 1033 | .find_io = nonstatic_find_io, |
950 | .find_io = nonstatic_find_io_region, | ||
951 | .find_mem = nonstatic_find_mem_region, | 1034 | .find_mem = nonstatic_find_mem_region, |
952 | .add_io = adjust_io, | 1035 | .add_io = adjust_io, |
953 | .add_mem = adjust_memory, | 1036 | .add_mem = adjust_memory, |