- Kai Germaschewski: ymfpci cleanups and resource leak fixes
[davej-history.git] / drivers / pcmcia / rsrc_mgr.c
blob4e06af9c519ccc9820b01846c0ca12a3feac5854
1 /*======================================================================
3 Resource management routines
5 rsrc_mgr.c 1.79 2000/08/30 20:23:58
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
17 The initial developer of the original code is David A. Hinds
18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
32 ======================================================================*/
34 #define __NO_VERSION__
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/init.h>
39 #include <linux/sched.h>
40 #include <linux/kernel.h>
41 #include <linux/errno.h>
42 #include <linux/types.h>
43 #include <linux/malloc.h>
44 #include <linux/ioport.h>
45 #include <linux/timer.h>
46 #include <asm/irq.h>
47 #include <asm/io.h>
49 #include <pcmcia/cs_types.h>
50 #include <pcmcia/ss.h>
51 #include <pcmcia/cs.h>
52 #include <pcmcia/bulkmem.h>
53 #include <pcmcia/cistpl.h>
54 #include "cs_internal.h"
55 #include "rsrc_mgr.h"
57 /*====================================================================*/
59 /* Parameters that can be set with 'insmod' */
61 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
63 INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
64 #ifdef CONFIG_ISA
65 INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
66 INT_MODULE_PARM(mem_limit, 0x10000);
67 #endif
69 /*======================================================================
71 The resource_map_t structures are used to track what resources are
72 available for allocation for PC Card devices.
74 ======================================================================*/
76 typedef struct resource_map_t {
77 u_long base, num;
78 struct resource_map_t *next;
79 } resource_map_t;
81 /* Memory resource database */
82 static resource_map_t mem_db = { 0, 0, &mem_db };
84 /* IO port resource database */
85 static resource_map_t io_db = { 0, 0, &io_db };
87 #ifdef CONFIG_ISA
89 typedef struct irq_info_t {
90 u_int Attributes;
91 int time_share, dyn_share;
92 struct socket_info_t *Socket;
93 } irq_info_t;
95 /* Table of IRQ assignments */
96 static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ };
98 #endif
100 /*======================================================================
102 Linux resource management extensions
104 ======================================================================*/
106 #define check_io_resource(b,n) check_resource(&ioport_resource, (b), (n))
107 #define check_mem_resource(b,n) check_resource(&iomem_resource, (b), (n))
109 /*======================================================================
111 These manage the internal databases of available resources.
113 ======================================================================*/
115 static int add_interval(resource_map_t *map, u_long base, u_long num)
117 resource_map_t *p, *q;
119 for (p = map; ; p = p->next) {
120 if ((p != map) && (p->base+p->num-1 >= base))
121 return -1;
122 if ((p->next == map) || (p->next->base > base+num-1))
123 break;
125 q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
126 if (!q) return CS_OUT_OF_RESOURCE;
127 q->base = base; q->num = num;
128 q->next = p->next; p->next = q;
129 return CS_SUCCESS;
132 /*====================================================================*/
134 static int sub_interval(resource_map_t *map, u_long base, u_long num)
136 resource_map_t *p, *q;
138 for (p = map; ; p = q) {
139 q = p->next;
140 if (q == map)
141 break;
142 if ((q->base+q->num > base) && (base+num > q->base)) {
143 if (q->base >= base) {
144 if (q->base+q->num <= base+num) {
145 /* Delete whole block */
146 p->next = q->next;
147 kfree(q);
148 /* don't advance the pointer yet */
149 q = p;
150 } else {
151 /* Cut off bit from the front */
152 q->num = q->base + q->num - base - num;
153 q->base = base + num;
155 } else if (q->base+q->num <= base+num) {
156 /* Cut off bit from the end */
157 q->num = base - q->base;
158 } else {
159 /* Split the block into two pieces */
160 p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
161 if (!p) return CS_OUT_OF_RESOURCE;
162 p->base = base+num;
163 p->num = q->base+q->num - p->base;
164 q->num = base - q->base;
165 p->next = q->next ; q->next = p;
169 return CS_SUCCESS;
172 /*======================================================================
174 These routines examine a region of IO or memory addresses to
175 determine what ranges might be genuinely available.
177 ======================================================================*/
179 #ifdef CONFIG_ISA
180 static void do_io_probe(ioaddr_t base, ioaddr_t num)
183 ioaddr_t i, j, bad, any;
184 u_char *b, hole, most;
186 printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
187 base, base+num-1);
189 /* First, what does a floating port look like? */
190 b = kmalloc(256, GFP_KERNEL);
191 memset(b, 0, 256);
192 for (i = base, most = 0; i < base+num; i += 8) {
193 if (check_io_resource(i, 8))
194 continue;
195 hole = inb(i);
196 for (j = 1; j < 8; j++)
197 if (inb(i+j) != hole) break;
198 if ((j == 8) && (++b[hole] > b[most]))
199 most = hole;
200 if (b[most] == 127) break;
202 kfree(b);
204 bad = any = 0;
205 for (i = base; i < base+num; i += 8) {
206 if (check_io_resource(i, 8))
207 continue;
208 for (j = 0; j < 8; j++)
209 if (inb(i+j) != most) break;
210 if (j < 8) {
211 if (!any)
212 printk(" excluding");
213 if (!bad)
214 bad = any = i;
215 } else {
216 if (bad) {
217 sub_interval(&io_db, bad, i-bad);
218 printk(" %#04x-%#04x", bad, i-1);
219 bad = 0;
223 if (bad) {
224 if ((num > 16) && (bad == base) && (i == base+num)) {
225 printk(" nothing: probe failed.\n");
226 return;
227 } else {
228 sub_interval(&io_db, bad, i-bad);
229 printk(" %#04x-%#04x", bad, i-1);
233 printk(any ? "\n" : " clean.\n");
235 #endif
237 /*======================================================================
239 The memory probe. If the memory list includes a 64K-aligned block
240 below 1MB, we probe in 64K chunks, and as soon as we accumulate at
241 least mem_limit free space, we quit.
243 ======================================================================*/
245 static int do_mem_probe(u_long base, u_long num,
246 int (*is_valid)(u_long), int (*do_cksum)(u_long))
248 u_long i, j, bad, fail, step;
250 printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
251 base, base+num-1);
252 bad = fail = 0;
253 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
254 for (i = base; i < base+num; i = j + step) {
255 if (!fail) {
256 for (j = i; j < base+num; j += step)
257 if ((check_mem_resource(j, step) == 0) && is_valid(j))
258 break;
259 fail = ((i == base) && (j == base+num));
261 if (fail) {
262 for (j = i; j < base+num; j += 2*step)
263 if ((check_mem_resource(j, 2*step) == 0) &&
264 do_cksum(j) && do_cksum(j+step))
265 break;
267 if (i != j) {
268 if (!bad) printk(" excluding");
269 printk(" %#05lx-%#05lx", i, j-1);
270 sub_interval(&mem_db, i, j-i);
271 bad += j-i;
274 printk(bad ? "\n" : " clean.\n");
275 return (num - bad);
278 #ifdef CONFIG_ISA
280 static u_long inv_probe(int (*is_valid)(u_long),
281 int (*do_cksum)(u_long),
282 resource_map_t *m)
284 u_long ok;
285 if (m == &mem_db)
286 return 0;
287 ok = inv_probe(is_valid, do_cksum, m->next);
288 if (ok) {
289 if (m->base >= 0x100000)
290 sub_interval(&mem_db, m->base, m->num);
291 return ok;
293 if (m->base < 0x100000)
294 return 0;
295 return do_mem_probe(m->base, m->num, is_valid, do_cksum);
298 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
299 int force_low)
301 resource_map_t *m, *n;
302 static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
303 static int hi = 0, lo = 0;
304 u_long b, i, ok = 0;
306 if (!probe_mem) return;
307 /* We do up to four passes through the list */
308 if (!force_low) {
309 if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
310 return;
311 printk(KERN_NOTICE "cs: warning: no high memory space "
312 "available!\n");
314 if (lo++) return;
315 for (m = mem_db.next; m != &mem_db; m = n) {
316 n = m->next;
317 /* Only probe < 1 MB */
318 if (m->base >= 0x100000) continue;
319 if ((m->base | m->num) & 0xffff) {
320 ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
321 continue;
323 /* Special probe for 64K-aligned block */
324 for (i = 0; i < 4; i++) {
325 b = order[i] << 12;
326 if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) {
327 if (ok >= mem_limit)
328 sub_interval(&mem_db, b, 0x10000);
329 else
330 ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
336 #else /* CONFIG_ISA */
338 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
339 int force_low)
341 resource_map_t *m;
342 static int done = 0;
344 if (!probe_mem || done++)
345 return;
346 for (m = mem_db.next; m != &mem_db; m = m->next)
347 if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
348 return;
351 #endif /* CONFIG_ISA */
353 /*======================================================================
355 These find ranges of I/O ports or memory addresses that are not
356 currently allocated by other devices.
358 The 'align' field should reflect the number of bits of address
359 that need to be preserved from the initial value of *base. It
360 should be a power of two, greater than or equal to 'num'. A value
361 of 0 means that all bits of *base are significant. *base should
362 also be strictly less than 'align'.
364 ======================================================================*/
366 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
367 char *name)
369 ioaddr_t try;
370 resource_map_t *m;
372 for (m = io_db.next; m != &io_db; m = m->next) {
373 try = (m->base & ~(align-1)) + *base;
374 for (try = (try >= m->base) ? try : try+align;
375 (try >= m->base) && (try+num <= m->base+m->num);
376 try += align) {
377 if (check_io_resource(try, num) == 0) {
378 *base = try;
379 request_region(try, num, name);
380 return 0;
382 if (!align) break;
385 return -1;
388 int find_mem_region(u_long *base, u_long num, u_long align,
389 int force_low, char *name)
391 u_long try;
392 resource_map_t *m;
394 while (1) {
395 for (m = mem_db.next; m != &mem_db; m = m->next) {
396 /* first pass >1MB, second pass <1MB */
397 if ((force_low != 0) ^ (m->base < 0x100000)) continue;
398 try = (m->base & ~(align-1)) + *base;
399 for (try = (try >= m->base) ? try : try+align;
400 (try >= m->base) && (try+num <= m->base+m->num);
401 try += align) {
402 if (check_mem_resource(try, num) == 0) {
403 request_mem_region(try, num, name);
404 *base = try;
405 return 0;
407 if (!align) break;
410 if (force_low) break;
411 force_low++;
413 return -1;
416 /*======================================================================
418 This checks to see if an interrupt is available, with support
419 for interrupt sharing. We don't support reserving interrupts
420 yet. If the interrupt is available, we allocate it.
422 ======================================================================*/
424 #ifdef CONFIG_ISA
426 static void fake_irq(int i, void *d, struct pt_regs *r) { }
427 static inline int check_irq(int irq)
429 if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
430 return -1;
431 free_irq(irq, NULL);
432 return 0;
435 int try_irq(u_int Attributes, int irq, int specific)
437 irq_info_t *info = &irq_table[irq];
438 if (info->Attributes & RES_ALLOCATED) {
439 switch (Attributes & IRQ_TYPE) {
440 case IRQ_TYPE_EXCLUSIVE:
441 return CS_IN_USE;
442 case IRQ_TYPE_TIME:
443 if ((info->Attributes & RES_IRQ_TYPE)
444 != RES_IRQ_TYPE_TIME)
445 return CS_IN_USE;
446 if (Attributes & IRQ_FIRST_SHARED)
447 return CS_BAD_ATTRIBUTE;
448 info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
449 info->time_share++;
450 break;
451 case IRQ_TYPE_DYNAMIC_SHARING:
452 if ((info->Attributes & RES_IRQ_TYPE)
453 != RES_IRQ_TYPE_DYNAMIC)
454 return CS_IN_USE;
455 if (Attributes & IRQ_FIRST_SHARED)
456 return CS_BAD_ATTRIBUTE;
457 info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
458 info->dyn_share++;
459 break;
461 } else {
462 if ((info->Attributes & RES_RESERVED) && !specific)
463 return CS_IN_USE;
464 if (check_irq(irq) != 0)
465 return CS_IN_USE;
466 switch (Attributes & IRQ_TYPE) {
467 case IRQ_TYPE_EXCLUSIVE:
468 info->Attributes |= RES_ALLOCATED;
469 break;
470 case IRQ_TYPE_TIME:
471 if (!(Attributes & IRQ_FIRST_SHARED))
472 return CS_BAD_ATTRIBUTE;
473 info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
474 info->time_share = 1;
475 break;
476 case IRQ_TYPE_DYNAMIC_SHARING:
477 if (!(Attributes & IRQ_FIRST_SHARED))
478 return CS_BAD_ATTRIBUTE;
479 info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
480 info->dyn_share = 1;
481 break;
484 return 0;
487 #endif
489 /*====================================================================*/
491 #ifdef CONFIG_ISA
493 void undo_irq(u_int Attributes, int irq)
495 irq_info_t *info;
497 info = &irq_table[irq];
498 switch (Attributes & IRQ_TYPE) {
499 case IRQ_TYPE_EXCLUSIVE:
500 info->Attributes &= RES_RESERVED;
501 break;
502 case IRQ_TYPE_TIME:
503 info->time_share--;
504 if (info->time_share == 0)
505 info->Attributes &= RES_RESERVED;
506 break;
507 case IRQ_TYPE_DYNAMIC_SHARING:
508 info->dyn_share--;
509 if (info->dyn_share == 0)
510 info->Attributes &= RES_RESERVED;
511 break;
515 #endif
517 /*======================================================================
519 The various adjust_* calls form the external interface to the
520 resource database.
522 ======================================================================*/
524 static int adjust_memory(adjust_t *adj)
526 u_long base, num;
527 int i, ret;
529 base = adj->resource.memory.Base;
530 num = adj->resource.memory.Size;
531 if ((num == 0) || (base+num-1 < base))
532 return CS_BAD_SIZE;
534 ret = CS_SUCCESS;
535 switch (adj->Action) {
536 case ADD_MANAGED_RESOURCE:
537 ret = add_interval(&mem_db, base, num);
538 break;
539 case REMOVE_MANAGED_RESOURCE:
540 ret = sub_interval(&mem_db, base, num);
541 if (ret == CS_SUCCESS) {
542 for (i = 0; i < sockets; i++) {
543 release_cis_mem(socket_table[i]);
544 #ifdef CONFIG_CARDBUS
545 cb_release_cis_mem(socket_table[i]);
546 #endif
549 break;
550 default:
551 ret = CS_UNSUPPORTED_FUNCTION;
554 return ret;
557 /*====================================================================*/
559 static int adjust_io(adjust_t *adj)
561 int base, num;
563 base = adj->resource.io.BasePort;
564 num = adj->resource.io.NumPorts;
565 if ((base < 0) || (base > 0xffff))
566 return CS_BAD_BASE;
567 if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
568 return CS_BAD_SIZE;
570 switch (adj->Action) {
571 case ADD_MANAGED_RESOURCE:
572 if (add_interval(&io_db, base, num) != 0)
573 return CS_IN_USE;
574 #ifdef CONFIG_ISA
575 if (probe_io)
576 do_io_probe(base, num);
577 #endif
578 break;
579 case REMOVE_MANAGED_RESOURCE:
580 sub_interval(&io_db, base, num);
581 break;
582 default:
583 return CS_UNSUPPORTED_FUNCTION;
584 break;
587 return CS_SUCCESS;
590 /*====================================================================*/
592 static int adjust_irq(adjust_t *adj)
594 #ifdef CONFIG_ISA
595 int irq;
596 irq_info_t *info;
598 irq = adj->resource.irq.IRQ;
599 if ((irq < 0) || (irq > 15))
600 return CS_BAD_IRQ;
601 info = &irq_table[irq];
603 switch (adj->Action) {
604 case ADD_MANAGED_RESOURCE:
605 if (info->Attributes & RES_REMOVED)
606 info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
607 else
608 if (adj->Attributes & RES_ALLOCATED)
609 return CS_IN_USE;
610 if (adj->Attributes & RES_RESERVED)
611 info->Attributes |= RES_RESERVED;
612 else
613 info->Attributes &= ~RES_RESERVED;
614 break;
615 case REMOVE_MANAGED_RESOURCE:
616 if (info->Attributes & RES_REMOVED)
617 return 0;
618 if (info->Attributes & RES_ALLOCATED)
619 return CS_IN_USE;
620 info->Attributes |= RES_ALLOCATED|RES_REMOVED;
621 info->Attributes &= ~RES_RESERVED;
622 break;
623 default:
624 return CS_UNSUPPORTED_FUNCTION;
625 break;
627 #endif
628 return CS_SUCCESS;
631 /*====================================================================*/
633 int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
635 if (CHECK_HANDLE(handle))
636 return CS_BAD_HANDLE;
638 switch (adj->Resource) {
639 case RES_MEMORY_RANGE:
640 return adjust_memory(adj);
641 break;
642 case RES_IO_RANGE:
643 return adjust_io(adj);
644 break;
645 case RES_IRQ:
646 return adjust_irq(adj);
647 break;
649 return CS_UNSUPPORTED_FUNCTION;
652 /*====================================================================*/
654 void release_resource_db(void)
656 resource_map_t *p, *q;
658 for (p = mem_db.next; p != &mem_db; p = q) {
659 q = p->next;
660 kfree(p);
662 for (p = io_db.next; p != &io_db; p = q) {
663 q = p->next;
664 kfree(p);