File: /usr/src/linux/drivers/pcmcia/rsrc_mgr.c
1 /*======================================================================
2
3 Resource management routines
4
5 rsrc_mgr.c 1.79 2000/08/30 20:23:58
6
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/
11
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.
16
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.
20
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU General 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.
31
32 ======================================================================*/
33
34 #define __NO_VERSION__
35
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/slab.h>
44 #include <linux/ioport.h>
45 #include <linux/timer.h>
46 #include <linux/proc_fs.h>
47 #include <asm/irq.h>
48 #include <asm/io.h>
49
50 #include <pcmcia/cs_types.h>
51 #include <pcmcia/ss.h>
52 #include <pcmcia/cs.h>
53 #include <pcmcia/bulkmem.h>
54 #include <pcmcia/cistpl.h>
55 #include "cs_internal.h"
56 #include "rsrc_mgr.h"
57
58 /*====================================================================*/
59
60 /* Parameters that can be set with 'insmod' */
61
62 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
63
64 INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
65 #ifdef CONFIG_ISA
66 INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
67 INT_MODULE_PARM(mem_limit, 0x10000);
68 #endif
69
70 /*======================================================================
71
72 The resource_map_t structures are used to track what resources are
73 available for allocation for PC Card devices.
74
75 ======================================================================*/
76
77 typedef struct resource_map_t {
78 u_long base, num;
79 struct resource_map_t *next;
80 } resource_map_t;
81
82 /* Memory resource database */
83 static resource_map_t mem_db = { 0, 0, &mem_db };
84
85 /* IO port resource database */
86 static resource_map_t io_db = { 0, 0, &io_db };
87
88 #ifdef CONFIG_ISA
89
90 typedef struct irq_info_t {
91 u_int Attributes;
92 int time_share, dyn_share;
93 struct socket_info_t *Socket;
94 } irq_info_t;
95
96 /* Table of IRQ assignments */
97 static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ };
98
99 #endif
100
101 /*======================================================================
102
103 Linux resource management extensions
104
105 ======================================================================*/
106
107 #define check_io_resource(b,n) check_resource(&ioport_resource, (b), (n))
108 #define check_mem_resource(b,n) check_resource(&iomem_resource, (b), (n))
109
110 /*======================================================================
111
112 These manage the internal databases of available resources.
113
114 ======================================================================*/
115
116 static int add_interval(resource_map_t *map, u_long base, u_long num)
117 {
118 resource_map_t *p, *q;
119
120 for (p = map; ; p = p->next) {
121 if ((p != map) && (p->base+p->num-1 >= base))
122 return -1;
123 if ((p->next == map) || (p->next->base > base+num-1))
124 break;
125 }
126 q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
127 if (!q) return CS_OUT_OF_RESOURCE;
128 q->base = base; q->num = num;
129 q->next = p->next; p->next = q;
130 return CS_SUCCESS;
131 }
132
133 /*====================================================================*/
134
135 static int sub_interval(resource_map_t *map, u_long base, u_long num)
136 {
137 resource_map_t *p, *q;
138
139 for (p = map; ; p = q) {
140 q = p->next;
141 if (q == map)
142 break;
143 if ((q->base+q->num > base) && (base+num > q->base)) {
144 if (q->base >= base) {
145 if (q->base+q->num <= base+num) {
146 /* Delete whole block */
147 p->next = q->next;
148 kfree(q);
149 /* don't advance the pointer yet */
150 q = p;
151 } else {
152 /* Cut off bit from the front */
153 q->num = q->base + q->num - base - num;
154 q->base = base + num;
155 }
156 } else if (q->base+q->num <= base+num) {
157 /* Cut off bit from the end */
158 q->num = base - q->base;
159 } else {
160 /* Split the block into two pieces */
161 p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
162 if (!p) return CS_OUT_OF_RESOURCE;
163 p->base = base+num;
164 p->num = q->base+q->num - p->base;
165 q->num = base - q->base;
166 p->next = q->next ; q->next = p;
167 }
168 }
169 }
170 return CS_SUCCESS;
171 }
172
173 /*======================================================================
174
175 These routines examine a region of IO or memory addresses to
176 determine what ranges might be genuinely available.
177
178 ======================================================================*/
179
180 #ifdef CONFIG_ISA
181 static void do_io_probe(ioaddr_t base, ioaddr_t num)
182 {
183
184 ioaddr_t i, j, bad, any;
185 u_char *b, hole, most;
186
187 printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
188 base, base+num-1);
189
190 /* First, what does a floating port look like? */
191 b = kmalloc(256, GFP_KERNEL);
192 if (!b) {
193 printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes");
194 return;
195 }
196 memset(b, 0, 256);
197 for (i = base, most = 0; i < base+num; i += 8) {
198 if (check_io_resource(i, 8))
199 continue;
200 hole = inb(i);
201 for (j = 1; j < 8; j++)
202 if (inb(i+j) != hole) break;
203 if ((j == 8) && (++b[hole] > b[most]))
204 most = hole;
205 if (b[most] == 127) break;
206 }
207 kfree(b);
208
209 bad = any = 0;
210 for (i = base; i < base+num; i += 8) {
211 if (check_io_resource(i, 8))
212 continue;
213 for (j = 0; j < 8; j++)
214 if (inb(i+j) != most) break;
215 if (j < 8) {
216 if (!any)
217 printk(" excluding");
218 if (!bad)
219 bad = any = i;
220 } else {
221 if (bad) {
222 sub_interval(&io_db, bad, i-bad);
223 printk(" %#04x-%#04x", bad, i-1);
224 bad = 0;
225 }
226 }
227 }
228 if (bad) {
229 if ((num > 16) && (bad == base) && (i == base+num)) {
230 printk(" nothing: probe failed.\n");
231 return;
232 } else {
233 sub_interval(&io_db, bad, i-bad);
234 printk(" %#04x-%#04x", bad, i-1);
235 }
236 }
237
238 printk(any ? "\n" : " clean.\n");
239 }
240 #endif
241
242 /*======================================================================
243
244 The memory probe. If the memory list includes a 64K-aligned block
245 below 1MB, we probe in 64K chunks, and as soon as we accumulate at
246 least mem_limit free space, we quit.
247
248 ======================================================================*/
249
250 static int do_mem_probe(u_long base, u_long num,
251 int (*is_valid)(u_long), int (*do_cksum)(u_long))
252 {
253 u_long i, j, bad, fail, step;
254
255 printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
256 base, base+num-1);
257 bad = fail = 0;
258 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
259 for (i = j = base; i < base+num; i = j + step) {
260 if (!fail) {
261 for (j = i; j < base+num; j += step)
262 if ((check_mem_resource(j, step) == 0) && is_valid(j))
263 break;
264 fail = ((i == base) && (j == base+num));
265 }
266 if (fail) {
267 for (j = i; j < base+num; j += 2*step)
268 if ((check_mem_resource(j, 2*step) == 0) &&
269 do_cksum(j) && do_cksum(j+step))
270 break;
271 }
272 if (i != j) {
273 if (!bad) printk(" excluding");
274 printk(" %#05lx-%#05lx", i, j-1);
275 sub_interval(&mem_db, i, j-i);
276 bad += j-i;
277 }
278 }
279 printk(bad ? "\n" : " clean.\n");
280 return (num - bad);
281 }
282
283 #ifdef CONFIG_ISA
284
285 static u_long inv_probe(int (*is_valid)(u_long),
286 int (*do_cksum)(u_long),
287 resource_map_t *m)
288 {
289 u_long ok;
290 if (m == &mem_db)
291 return 0;
292 ok = inv_probe(is_valid, do_cksum, m->next);
293 if (ok) {
294 if (m->base >= 0x100000)
295 sub_interval(&mem_db, m->base, m->num);
296 return ok;
297 }
298 if (m->base < 0x100000)
299 return 0;
300 return do_mem_probe(m->base, m->num, is_valid, do_cksum);
301 }
302
303 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
304 int force_low)
305 {
306 resource_map_t *m, *n;
307 static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
308 static int hi = 0, lo = 0;
309 u_long b, i, ok = 0;
310
311 if (!probe_mem) return;
312 /* We do up to four passes through the list */
313 if (!force_low) {
314 if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
315 return;
316 printk(KERN_NOTICE "cs: warning: no high memory space "
317 "available!\n");
318 }
319 if (lo++) return;
320 for (m = mem_db.next; m != &mem_db; m = n) {
321 n = m->next;
322 /* Only probe < 1 MB */
323 if (m->base >= 0x100000) continue;
324 if ((m->base | m->num) & 0xffff) {
325 ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
326 continue;
327 }
328 /* Special probe for 64K-aligned block */
329 for (i = 0; i < 4; i++) {
330 b = order[i] << 12;
331 if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) {
332 if (ok >= mem_limit)
333 sub_interval(&mem_db, b, 0x10000);
334 else
335 ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
336 }
337 }
338 }
339 }
340
341 #else /* CONFIG_ISA */
342
343 void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
344 int force_low)
345 {
346 resource_map_t *m;
347 static int done = 0;
348
349 if (!probe_mem || done++)
350 return;
351 for (m = mem_db.next; m != &mem_db; m = m->next)
352 if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
353 return;
354 }
355
356 #endif /* CONFIG_ISA */
357
358 /*======================================================================
359
360 These find ranges of I/O ports or memory addresses that are not
361 currently allocated by other devices.
362
363 The 'align' field should reflect the number of bits of address
364 that need to be preserved from the initial value of *base. It
365 should be a power of two, greater than or equal to 'num'. A value
366 of 0 means that all bits of *base are significant. *base should
367 also be strictly less than 'align'.
368
369 ======================================================================*/
370
371 int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
372 char *name)
373 {
374 ioaddr_t try;
375 resource_map_t *m;
376
377 for (m = io_db.next; m != &io_db; m = m->next) {
378 try = (m->base & ~(align-1)) + *base;
379 for (try = (try >= m->base) ? try : try+align;
380 (try >= m->base) && (try+num <= m->base+m->num);
381 try += align) {
382 if (check_io_resource(try, num) == 0) {
383 *base = try;
384 request_region(try, num, name);
385 return 0;
386 }
387 if (!align) break;
388 }
389 }
390 return -1;
391 }
392
393 int find_mem_region(u_long *base, u_long num, u_long align,
394 int force_low, char *name)
395 {
396 u_long try;
397 resource_map_t *m;
398
399 while (1) {
400 for (m = mem_db.next; m != &mem_db; m = m->next) {
401 /* first pass >1MB, second pass <1MB */
402 if ((force_low != 0) ^ (m->base < 0x100000)) continue;
403 try = (m->base & ~(align-1)) + *base;
404 for (try = (try >= m->base) ? try : try+align;
405 (try >= m->base) && (try+num <= m->base+m->num);
406 try += align) {
407 if (check_mem_resource(try, num) == 0) {
408 request_mem_region(try, num, name);
409 *base = try;
410 return 0;
411 }
412 if (!align) break;
413 }
414 }
415 if (force_low) break;
416 force_low++;
417 }
418 return -1;
419 }
420
421 /*======================================================================
422
423 This checks to see if an interrupt is available, with support
424 for interrupt sharing. We don't support reserving interrupts
425 yet. If the interrupt is available, we allocate it.
426
427 ======================================================================*/
428
429 #ifdef CONFIG_ISA
430
431 static void fake_irq(int i, void *d, struct pt_regs *r) { }
432 static inline int check_irq(int irq)
433 {
434 if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
435 return -1;
436 free_irq(irq, NULL);
437 return 0;
438 }
439
440 int try_irq(u_int Attributes, int irq, int specific)
441 {
442 irq_info_t *info = &irq_table[irq];
443 if (info->Attributes & RES_ALLOCATED) {
444 switch (Attributes & IRQ_TYPE) {
445 case IRQ_TYPE_EXCLUSIVE:
446 return CS_IN_USE;
447 case IRQ_TYPE_TIME:
448 if ((info->Attributes & RES_IRQ_TYPE)
449 != RES_IRQ_TYPE_TIME)
450 return CS_IN_USE;
451 if (Attributes & IRQ_FIRST_SHARED)
452 return CS_BAD_ATTRIBUTE;
453 info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
454 info->time_share++;
455 break;
456 case IRQ_TYPE_DYNAMIC_SHARING:
457 if ((info->Attributes & RES_IRQ_TYPE)
458 != RES_IRQ_TYPE_DYNAMIC)
459 return CS_IN_USE;
460 if (Attributes & IRQ_FIRST_SHARED)
461 return CS_BAD_ATTRIBUTE;
462 info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
463 info->dyn_share++;
464 break;
465 }
466 } else {
467 if ((info->Attributes & RES_RESERVED) && !specific)
468 return CS_IN_USE;
469 if (check_irq(irq) != 0)
470 return CS_IN_USE;
471 switch (Attributes & IRQ_TYPE) {
472 case IRQ_TYPE_EXCLUSIVE:
473 info->Attributes |= RES_ALLOCATED;
474 break;
475 case IRQ_TYPE_TIME:
476 if (!(Attributes & IRQ_FIRST_SHARED))
477 return CS_BAD_ATTRIBUTE;
478 info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
479 info->time_share = 1;
480 break;
481 case IRQ_TYPE_DYNAMIC_SHARING:
482 if (!(Attributes & IRQ_FIRST_SHARED))
483 return CS_BAD_ATTRIBUTE;
484 info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
485 info->dyn_share = 1;
486 break;
487 }
488 }
489 return 0;
490 }
491
492 #endif
493
494 /*====================================================================*/
495
496 #ifdef CONFIG_ISA
497
498 void undo_irq(u_int Attributes, int irq)
499 {
500 irq_info_t *info;
501
502 info = &irq_table[irq];
503 switch (Attributes & IRQ_TYPE) {
504 case IRQ_TYPE_EXCLUSIVE:
505 info->Attributes &= RES_RESERVED;
506 break;
507 case IRQ_TYPE_TIME:
508 info->time_share--;
509 if (info->time_share == 0)
510 info->Attributes &= RES_RESERVED;
511 break;
512 case IRQ_TYPE_DYNAMIC_SHARING:
513 info->dyn_share--;
514 if (info->dyn_share == 0)
515 info->Attributes &= RES_RESERVED;
516 break;
517 }
518 }
519
520 #endif
521
522 /*======================================================================
523
524 The various adjust_* calls form the external interface to the
525 resource database.
526
527 ======================================================================*/
528
529 static int adjust_memory(adjust_t *adj)
530 {
531 u_long base, num;
532 int i, ret;
533
534 base = adj->resource.memory.Base;
535 num = adj->resource.memory.Size;
536 if ((num == 0) || (base+num-1 < base))
537 return CS_BAD_SIZE;
538
539 ret = CS_SUCCESS;
540 switch (adj->Action) {
541 case ADD_MANAGED_RESOURCE:
542 ret = add_interval(&mem_db, base, num);
543 break;
544 case REMOVE_MANAGED_RESOURCE:
545 ret = sub_interval(&mem_db, base, num);
546 if (ret == CS_SUCCESS) {
547 for (i = 0; i < sockets; i++) {
548 release_cis_mem(socket_table[i]);
549 #ifdef CONFIG_CARDBUS
550 cb_release_cis_mem(socket_table[i]);
551 #endif
552 }
553 }
554 break;
555 default:
556 ret = CS_UNSUPPORTED_FUNCTION;
557 }
558
559 return ret;
560 }
561
562 /*====================================================================*/
563
564 static int adjust_io(adjust_t *adj)
565 {
566 int base, num;
567
568 base = adj->resource.io.BasePort;
569 num = adj->resource.io.NumPorts;
570 if ((base < 0) || (base > 0xffff))
571 return CS_BAD_BASE;
572 if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
573 return CS_BAD_SIZE;
574
575 switch (adj->Action) {
576 case ADD_MANAGED_RESOURCE:
577 if (add_interval(&io_db, base, num) != 0)
578 return CS_IN_USE;
579 #ifdef CONFIG_ISA
580 if (probe_io)
581 do_io_probe(base, num);
582 #endif
583 break;
584 case REMOVE_MANAGED_RESOURCE:
585 sub_interval(&io_db, base, num);
586 break;
587 default:
588 return CS_UNSUPPORTED_FUNCTION;
589 break;
590 }
591
592 return CS_SUCCESS;
593 }
594
595 /*====================================================================*/
596
597 static int adjust_irq(adjust_t *adj)
598 {
599 #ifdef CONFIG_ISA
600 int irq;
601 irq_info_t *info;
602
603 irq = adj->resource.irq.IRQ;
604 if ((irq < 0) || (irq > 15))
605 return CS_BAD_IRQ;
606 info = &irq_table[irq];
607
608 switch (adj->Action) {
609 case ADD_MANAGED_RESOURCE:
610 if (info->Attributes & RES_REMOVED)
611 info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
612 else
613 if (adj->Attributes & RES_ALLOCATED)
614 return CS_IN_USE;
615 if (adj->Attributes & RES_RESERVED)
616 info->Attributes |= RES_RESERVED;
617 else
618 info->Attributes &= ~RES_RESERVED;
619 break;
620 case REMOVE_MANAGED_RESOURCE:
621 if (info->Attributes & RES_REMOVED)
622 return 0;
623 if (info->Attributes & RES_ALLOCATED)
624 return CS_IN_USE;
625 info->Attributes |= RES_ALLOCATED|RES_REMOVED;
626 info->Attributes &= ~RES_RESERVED;
627 break;
628 default:
629 return CS_UNSUPPORTED_FUNCTION;
630 break;
631 }
632 #endif
633 return CS_SUCCESS;
634 }
635
636 /*====================================================================*/
637
638 int pcmcia_adjust_resource_info(client_handle_t handle, adjust_t *adj)
639 {
640 if (CHECK_HANDLE(handle))
641 return CS_BAD_HANDLE;
642
643 switch (adj->Resource) {
644 case RES_MEMORY_RANGE:
645 return adjust_memory(adj);
646 break;
647 case RES_IO_RANGE:
648 return adjust_io(adj);
649 break;
650 case RES_IRQ:
651 return adjust_irq(adj);
652 break;
653 }
654 return CS_UNSUPPORTED_FUNCTION;
655 }
656
657 /*====================================================================*/
658
659 void release_resource_db(void)
660 {
661 resource_map_t *p, *q;
662
663 for (p = mem_db.next; p != &mem_db; p = q) {
664 q = p->next;
665 kfree(p);
666 }
667 for (p = io_db.next; p != &io_db; p = q) {
668 q = p->next;
669 kfree(p);
670 }
671 }
672