1 |
1624 |
jcastillo |
/* $Id: ioport.c,v 1.1 2005-12-20 09:50:43 jcastillo 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 |
|
|
static long next_free_region = IOBASE_VADDR;
|
31 |
|
|
static long dvma_next_free = DVMA_VADDR;
|
32 |
|
|
|
33 |
|
|
/*
|
34 |
|
|
* sparc_alloc_io:
|
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, int len, char *name,
|
51 |
|
|
int bus_type, int rdonly)
|
52 |
|
|
{
|
53 |
|
|
unsigned long vaddr, base_address;
|
54 |
|
|
unsigned long addr = (unsigned long) address;
|
55 |
|
|
unsigned long offset = (addr & (~PAGE_MASK));
|
56 |
|
|
|
57 |
|
|
if (virtual)
|
58 |
|
|
vaddr = (unsigned long) virtual;
|
59 |
|
|
else
|
60 |
|
|
vaddr = next_free_region;
|
61 |
|
|
|
62 |
|
|
len += offset;
|
63 |
|
|
if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) {
|
64 |
|
|
prom_printf("alloc_io: Mapping outside 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 granularity. How this basically
|
88 |
|
|
* works is that the ESP chip can do DVMA transfers at ANY address with
|
89 |
|
|
* certain size and boundary 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 sees 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 (int len, char *name)
|
97 |
|
|
{
|
98 |
|
|
unsigned long vaddr, 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 |
|
|
}
|