xref: /netbsd/sys/arch/mipsco/mipsco/bus_space.c (revision bf9ec67e)
1 /*	$NetBSD: bus_space.c,v 1.3 2001/09/15 00:49:54 wdk Exp $ 	*/
2 
3 /*
4  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9  * Simulation Facility, NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/extent.h>
44 
45 #include <uvm/uvm_extern.h>
46 
47 #include <machine/bus.h>
48 
49 void
50 mipsco_bus_space_init(bst, name, paddr, vaddr, start, size)
51 	bus_space_tag_t bst;
52 	const char *name;
53 	paddr_t paddr;
54 	vaddr_t vaddr;
55 	bus_addr_t start;
56 	bus_size_t size;
57 {
58 	bst->bs_name = name;
59 	bst->bs_extent = NULL;
60 	bst->bs_start = start;
61 	bst->bs_size = size;
62 	bst->bs_pbase = paddr;
63 	bst->bs_vbase = vaddr;
64 	bst->bs_compose_handle = mipsco_bus_space_compose_handle;
65 	bst->bs_dispose_handle = mipsco_bus_space_dispose_handle;
66 	bst->bs_paddr = mipsco_bus_space_paddr;
67 	bst->bs_map = mipsco_bus_space_map;
68 	bst->bs_unmap = mipsco_bus_space_unmap;
69 	bst->bs_subregion = mipsco_bus_space_subregion;
70 	bst->bs_mmap = mipsco_bus_space_mmap;
71 	bst->bs_alloc = mipsco_bus_space_alloc;
72 	bst->bs_free = mipsco_bus_space_free;
73 	bst->bs_aux = NULL;
74 	bst->bs_bswap = 0; /* No byte swap for stream methods */
75 	mipsco_bus_space_set_aligned_stride(bst, 0);
76 }
77 
78 void
79 mipsco_bus_space_init_extent(bst, storage, storagesize)
80 	bus_space_tag_t bst;
81 	caddr_t storage;
82 	size_t storagesize;
83 {
84 	bst->bs_extent = extent_create(bst->bs_name,
85 	    bst->bs_start, bst->bs_start + bst->bs_size, M_DEVBUF,
86 	    storage, storagesize, EX_NOWAIT);
87 	if (bst->bs_extent == NULL)
88 	    panic("mipsco_bus_space_init_extent: cannot create extent map %s",
89 		  bst->bs_name);
90 }
91 
92 void
93 mipsco_bus_space_set_aligned_stride(bst, shift)
94 	bus_space_tag_t bst;
95 	unsigned int shift;		/* log2(alignment) */
96 {
97 	bst->bs_stride = shift;
98 
99 	if (shift == 2) {		/* XXX Assumes Big Endian & 4B */
100 	    bst->bs_offset_1 = 3;
101 	    bst->bs_offset_2 = 2;
102 	} else {
103 	    bst->bs_offset_1 = 0;
104 	    bst->bs_offset_2 = 0;
105 	}
106 	bst->bs_offset_4 = 0;
107 	bst->bs_offset_8 = 0;
108 }
109 
110 static int malloc_safe = 0;
111 
112 void
113 mipsco_bus_space_malloc_set_safe()
114 {
115 	malloc_safe = EX_MALLOCOK;
116 }
117 
118 int
119 mipsco_bus_space_extent_malloc_flag()
120 {
121 	return (malloc_safe);
122 }
123 
124 int
125 mipsco_bus_space_compose_handle(bst, addr, size, flags, bshp)
126 	bus_space_tag_t bst;
127 	bus_addr_t addr;
128 	bus_size_t size;
129 	int flags;
130 	bus_space_handle_t *bshp;
131 {
132 	bus_space_handle_t bsh = bst->bs_vbase +
133 	    ((addr - bst->bs_start) << bst->bs_stride);
134 
135 	/*
136 	 * Since all buses can be linearly mappable, we don't have to check
137 	 * BUS_SPACE_MAP_LINEAR and BUS_SPACE_MAP_PREFETCHABLE.
138 	 */
139 	if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) {
140 		*bshp = bsh;
141 		return (0);
142 	}
143 	if (bsh < MIPS_KSEG1_START) /* KUSEG or KSEG0 */
144 		panic("mipsco_bus_space_compose_handle: bad address 0x%x", bsh);
145 	if (bsh < MIPS_KSEG2_START) { /* KSEG1 */
146 		*bshp = MIPS_PHYS_TO_KSEG0(MIPS_KSEG1_TO_PHYS(bsh));
147 		return (0);
148 	}
149 	/*
150 	 * KSEG2:
151 	 * Do not make the page cacheable in this case, since:
152 	 * - the page which this bus_space belongs might include
153 	 *   other bus_spaces.
154 	 * or
155 	 * - this bus might be mapped by wired TLB, in that case,
156 	 *   we cannot manupulate cacheable attribute with page granularity.
157 	 */
158 #ifdef DIAGNOSTIC
159 	printf("mipsco_bus_space_compose_handle: ignore cacheable 0x%x\n", bsh);
160 #endif
161 	*bshp = bsh;
162 	return (0);
163 }
164 
165 int
166 mipsco_bus_space_dispose_handle(bst, bsh, size)
167 	bus_space_tag_t bst;
168 	bus_space_handle_t bsh;
169 	bus_size_t size;
170 {
171 	return (0);
172 }
173 
174 int
175 mipsco_bus_space_paddr(bst, bsh, pap)
176 	bus_space_tag_t bst;
177 	bus_space_handle_t bsh;
178 	paddr_t *pap;
179 {
180 	if (bsh < MIPS_KSEG0_START) /* KUSEG */
181 		panic("mipsco_bus_space_paddr(%p): bad address", (caddr_t)bsh);
182 	else if (bsh < MIPS_KSEG1_START) /* KSEG0 */
183 		*pap = MIPS_KSEG0_TO_PHYS(bsh);
184 	else if (bsh < MIPS_KSEG2_START) /* KSEG1 */
185 		*pap = MIPS_KSEG1_TO_PHYS(bsh);
186 	else { /* KSEG2 */
187 		/*
188 		 * Since this region may be mapped by wired TLB,
189 		 * kvtophys() is not always available.
190 		 */
191 		*pap = bst->bs_pbase + (bsh - bst->bs_vbase);
192 	}
193 	return (0);
194 }
195 
196 int
197 mipsco_bus_space_map(bst, addr, size, flags, bshp)
198 	bus_space_tag_t bst;
199 	bus_addr_t addr;
200 	bus_size_t size;
201 	int flags;
202 	bus_space_handle_t *bshp;
203 {
204 	int err;
205 
206 	if (addr < bst->bs_start || addr + size > bst->bs_start + bst->bs_size)
207 		return (EINVAL);
208 
209 	if (bst->bs_extent != NULL) {
210 		err = extent_alloc_region(bst->bs_extent, addr, size,
211 		    EX_NOWAIT | malloc_safe);
212 		if (err)
213 			return (err);
214 	}
215 
216 	return (bus_space_compose_handle(bst, addr, size, flags, bshp));
217 }
218 
219 void
220 mipsco_bus_space_unmap(bst, bsh, size)
221 	bus_space_tag_t bst;
222 	bus_space_handle_t bsh;
223 	bus_size_t size;
224 {
225 	if (bst->bs_extent != NULL) {
226 		paddr_t pa;
227 		bus_addr_t addr;
228 		int err;
229 
230 		/* bus_space_paddr() becomes unavailable after unmapping */
231 		err = bus_space_paddr(bst, bsh, &pa);
232 		if (err)
233 			panic("mipsco_bus_space_unmap: %s va %p: error %d\n",
234 			    bst->bs_name, (caddr_t)bsh, err);
235 		addr = (bus_size_t)(pa - bst->bs_pbase) + bst->bs_start;
236 		extent_free(bst->bs_extent, addr, size,
237 		    EX_NOWAIT | malloc_safe);
238 	}
239 	bus_space_dispose_handle(bst, bsh, size);
240 }
241 
242 int
243 mipsco_bus_space_subregion(bst, bsh, offset, size, nbshp)
244 	bus_space_tag_t bst;
245 	bus_space_handle_t bsh;
246 	bus_size_t offset;
247 	bus_size_t size;
248 	bus_space_handle_t *nbshp;
249 {
250 	*nbshp = bsh + (offset << bst->bs_stride);
251 	return (0);
252 }
253 
254 paddr_t
255 mipsco_bus_space_mmap(bst, addr, off, prot, flags)
256 	bus_space_tag_t bst;
257 	bus_addr_t addr;
258 	off_t off;
259 	int prot;
260 	int flags;
261 {
262 
263 	/*
264 	 * XXX We do not disallow mmap'ing of I/O space here,
265 	 * XXX which we should be doing.
266 	 */
267 
268 	if (addr < bst->bs_start ||
269 	    (addr + off) >= (bst->bs_start + bst->bs_size))
270 		return (-1);
271 
272 	return (mips_btop(bst->bs_pbase + (addr - bst->bs_start) + off));
273 }
274 
275 int
276 mipsco_bus_space_alloc(bst, start, end, size, align, boundary, flags, addrp, bshp)
277 	bus_space_tag_t bst;
278 	bus_addr_t start;
279 	bus_addr_t end;
280 	bus_size_t size;
281 	bus_size_t align;
282 	bus_size_t boundary;
283 	int flags;
284 	bus_addr_t *addrp;
285 	bus_space_handle_t *bshp;
286 {
287 	u_long addr;
288 	int err;
289 
290 	if (bst->bs_extent == NULL)
291 		panic("mipsco_bus_space_alloc: extent map %s not available",
292 		    bst->bs_name);
293 
294 	if (start < bst->bs_start ||
295 	    start + size > bst->bs_start + bst->bs_size)
296 		return (EINVAL);
297 
298 	err = extent_alloc_subregion(bst->bs_extent, start, end, size,
299 	    align, boundary, EX_FAST | EX_NOWAIT | malloc_safe, &addr);
300 	if (err)
301 		return (err);
302 
303 	*addrp = addr;
304 	return (bus_space_compose_handle(bst, addr, size, flags, bshp));
305 }
306