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