1 /* $Id: ioport.c,v 1.14 1996/01/03 03:34:41 davem Exp $ 2 * ioport.c: Simple io mapping allocator. 3 * 4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 5 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 6 * 7 * The routines in this file should be changed for a memory allocator 8 * that would be setup just like NetBSD does : you create regions that 9 * are administered by a general purpose allocator, and then you call 10 * that allocator with your handle and the block size instead of this 11 * weak stuff. 12 * 13 * XXX No joke, this needs to be rewritten badly. XXX 14 */ 15
16 #include <linux/sched.h>
17 #include <linux/kernel.h>
18 #include <linux/errno.h>
19 #include <linux/types.h>
20 #include <linux/ioport.h>
21 #include <linux/mm.h>
22
23 #include <asm/io.h>
24 #include <asm/vaddrs.h>
25 #include <asm/oplib.h>
26 #include <asm/page.h>
27 #include <asm/pgtable.h>
28
29 /* This points to the next to use virtual memory for io mappings */ 30 staticlongnext_free_region = IOBASE_VADDR;
31 staticlongdvma_next_free = DVMA_VADDR;
32
33 /* 34 * sparc_alloc_dev: 35 * Map and allocates an obio device. 36 * Implements a simple linear allocator, you can force the function 37 * to use your own mapping, but in practice this should not be used. 38 * 39 * Input: 40 * address: the obio address to map 41 * virtual: if non zero, specifies a fixed virtual address where 42 * the mapping should take place. 43 * len: the length of the mapping 44 * bus_type: The bus on which this io area sits. 45 * 46 * Returns: 47 * The virtual address where the mapping actually took place. 48 */ 49
50 void *sparc_alloc_io (void *address, void *virtual, intlen, char *name,
/* */ 51 intbus_type, intrdonly)
52 { 53 unsignedlongvaddr, base_address;
54 unsignedlongaddr = (unsignedlong) address;
55 unsignedlongoffset = (addr & (~PAGE_MASK));
56
57 if (virtual)
58 vaddr = (unsignedlong) virtual;
59 else 60 vaddr = next_free_region;
61
62 len += offset;
63 if(((unsignedlong) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) { 64 prom_printf("alloc_io: Mapping ouside IOBASE area\n");
65 prom_halt();
66 } 67 if(check_region ((vaddr | offset), len)) { 68 prom_printf("alloc_io: 0x%lx is already in use\n", vaddr);
69 prom_halt();
70 } 71
72 /* Tell Linux resource manager about the mapping */ 73 request_region ((vaddr | offset), len, name);
74
75 base_address = vaddr;
76 /* Do the actual mapping */ 77 for (; len > 0; len -= PAGE_SIZE) { 78 mapioaddr(addr, vaddr, bus_type, rdonly);
79 vaddr += PAGE_SIZE;
80 addr += PAGE_SIZE;
81 if (!virtual)
82 next_free_region += PAGE_SIZE;
83 } 84 return (void *) (base_address | offset);
85 } 86
87 /* Does DVMA allocations with PAGE_SIZE granulatity. How this basically 88 * works is that the ESP chip can do DVMA transfers at ANY address with 89 * certain size and boundry restrictions. But other devices that are 90 * attached to it and would like to do DVMA have to set things up in 91 * a special way, if the DVMA see's a device attached to it transfer data 92 * at addresses above DVMA_VADDR it will grab them, this way it does not 93 * now have to know the peculiarities of where to read the Lance data 94 * from. (for example) 95 */ 96 void *sparc_dvma_malloc (intlen, char *name)
/* */ 97 { 98 unsignedlongvaddr, base_address;
99
100 vaddr = dvma_next_free;
101 if(check_region (vaddr, len)) { 102 prom_printf("alloc_dma: 0x%lx is already in use\n", vaddr);
103 prom_halt();
104 } 105 if(vaddr + len > (DVMA_VADDR + DVMA_LEN)) { 106 prom_printf("alloc_dvma: out of dvma memory\n");
107 prom_halt();
108 } 109
110 /* Basically these can be mapped just like any old 111 * IO pages, cacheable bit off, etc. The physical 112 * pages are pre-mapped in paging_init() 113 */ 114 base_address = vaddr;
115 /* Assign the memory area. */ 116 dvma_next_free = PAGE_ALIGN(dvma_next_free+len);
117
118 request_region(base_address, len, name);
119
120 return (void *) base_address;
121 }