xref: /netbsd/sys/arch/mipsco/mipsco/bus_space.c (revision 72e6205f)
1 /*	$NetBSD: bus_space.c,v 1.12 2012/01/27 18:52:59 para 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: bus_space.c,v 1.12 2012/01/27 18:52:59 para Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
39 #include <sys/extent.h>
40 
41 #include <uvm/uvm_extern.h>
42 
43 #include <machine/bus.h>
44 
45 void
mipsco_bus_space_init(bus_space_tag_t bst,const char * name,paddr_t paddr,vaddr_t vaddr,bus_addr_t start,bus_size_t size)46 mipsco_bus_space_init(bus_space_tag_t bst, const char *name, paddr_t paddr, vaddr_t vaddr, bus_addr_t start, bus_size_t size)
47 {
48 	bst->bs_name = name;
49 	bst->bs_extent = NULL;
50 	bst->bs_start = start;
51 	bst->bs_size = size;
52 	bst->bs_pbase = paddr;
53 	bst->bs_vbase = vaddr;
54 	bst->bs_compose_handle = mipsco_bus_space_compose_handle;
55 	bst->bs_dispose_handle = mipsco_bus_space_dispose_handle;
56 	bst->bs_paddr = mipsco_bus_space_paddr;
57 	bst->bs_map = mipsco_bus_space_map;
58 	bst->bs_unmap = mipsco_bus_space_unmap;
59 	bst->bs_subregion = mipsco_bus_space_subregion;
60 	bst->bs_mmap = mipsco_bus_space_mmap;
61 	bst->bs_alloc = mipsco_bus_space_alloc;
62 	bst->bs_free = mipsco_bus_space_free;
63 	bst->bs_aux = NULL;
64 	bst->bs_bswap = 0; /* No byte swap for stream methods */
65 	mipsco_bus_space_set_aligned_stride(bst, 0);
66 }
67 
68 void
mipsco_bus_space_init_extent(bus_space_tag_t bst,void * storage,size_t storagesize)69 mipsco_bus_space_init_extent(bus_space_tag_t bst, void *storage, size_t storagesize)
70 {
71 	bst->bs_extent = extent_create(bst->bs_name,
72 	    bst->bs_start, bst->bs_start + bst->bs_size,
73 	    storage, storagesize, EX_NOWAIT);
74 	if (bst->bs_extent == NULL)
75 	    panic("mipsco_bus_space_init_extent: cannot create extent map %s",
76 		  bst->bs_name);
77 }
78 
79 void
mipsco_bus_space_set_aligned_stride(bus_space_tag_t bst,unsigned int shift)80 mipsco_bus_space_set_aligned_stride(bus_space_tag_t bst, unsigned int shift)
81 	/* shift:		 log2(alignment) */
82 {
83 	bst->bs_stride = shift;
84 
85 	if (shift == 2) {		/* XXX Assumes Big Endian & 4B */
86 	    bst->bs_offset_1 = 3;
87 	    bst->bs_offset_2 = 2;
88 	} else {
89 	    bst->bs_offset_1 = 0;
90 	    bst->bs_offset_2 = 0;
91 	}
92 	bst->bs_offset_4 = 0;
93 	bst->bs_offset_8 = 0;
94 }
95 
96 static int malloc_safe = 0;
97 
98 void
mipsco_bus_space_malloc_set_safe(void)99 mipsco_bus_space_malloc_set_safe(void)
100 {
101 	malloc_safe = EX_MALLOCOK;
102 }
103 
104 int
mipsco_bus_space_extent_malloc_flag(void)105 mipsco_bus_space_extent_malloc_flag(void)
106 {
107 	return (malloc_safe);
108 }
109 
110 int
mipsco_bus_space_compose_handle(bus_space_tag_t bst,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)111 mipsco_bus_space_compose_handle(bus_space_tag_t bst, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *bshp)
112 {
113 	bus_space_handle_t bsh = bst->bs_vbase +
114 	    ((addr - bst->bs_start) << bst->bs_stride);
115 
116 	/*
117 	 * Since all buses can be linearly mappable, we don't have to check
118 	 * BUS_SPACE_MAP_LINEAR and BUS_SPACE_MAP_PREFETCHABLE.
119 	 */
120 	if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) {
121 		*bshp = bsh;
122 		return (0);
123 	}
124 	if (bsh < MIPS_KSEG1_START) /* KUSEG or KSEG0 */
125 		panic("mipsco_bus_space_compose_handle: bad address 0x%x", bsh);
126 	if (bsh < MIPS_KSEG2_START) { /* KSEG1 */
127 		*bshp = MIPS_PHYS_TO_KSEG0(MIPS_KSEG1_TO_PHYS(bsh));
128 		return (0);
129 	}
130 	/*
131 	 * KSEG2:
132 	 * Do not make the page cacheable in this case, since:
133 	 * - the page which this bus_space belongs might include
134 	 *   other bus_spaces.
135 	 * or
136 	 * - this bus might be mapped by wired TLB, in that case,
137 	 *   we cannot manupulate cacheable attribute with page granularity.
138 	 */
139 #ifdef DIAGNOSTIC
140 	printf("mipsco_bus_space_compose_handle: ignore cacheable 0x%x\n", bsh);
141 #endif
142 	*bshp = bsh;
143 	return (0);
144 }
145 
146 int
mipsco_bus_space_dispose_handle(bus_space_tag_t bst,bus_space_handle_t bsh,bus_size_t size)147 mipsco_bus_space_dispose_handle(bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t size)
148 {
149 	return (0);
150 }
151 
152 int
mipsco_bus_space_paddr(bus_space_tag_t bst,bus_space_handle_t bsh,paddr_t * pap)153 mipsco_bus_space_paddr(bus_space_tag_t bst, bus_space_handle_t bsh, paddr_t *pap)
154 {
155 	if (bsh < MIPS_KSEG0_START) /* KUSEG */
156 		panic("mipsco_bus_space_paddr(%p): bad address", (void *)bsh);
157 	else if (bsh < MIPS_KSEG1_START) /* KSEG0 */
158 		*pap = MIPS_KSEG0_TO_PHYS(bsh);
159 	else if (bsh < MIPS_KSEG2_START) /* KSEG1 */
160 		*pap = MIPS_KSEG1_TO_PHYS(bsh);
161 	else { /* KSEG2 */
162 		/*
163 		 * Since this region may be mapped by wired TLB,
164 		 * kvtophys() is not always available.
165 		 */
166 		*pap = bst->bs_pbase + (bsh - bst->bs_vbase);
167 	}
168 	return (0);
169 }
170 
171 int
mipsco_bus_space_map(bus_space_tag_t bst,bus_addr_t addr,bus_size_t size,int flags,bus_space_handle_t * bshp)172 mipsco_bus_space_map(bus_space_tag_t bst, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *bshp)
173 {
174 	int err;
175 
176 	if (addr < bst->bs_start || addr + size > bst->bs_start + bst->bs_size)
177 		return (EINVAL);
178 
179 	if (bst->bs_extent != NULL) {
180 		err = extent_alloc_region(bst->bs_extent, addr, size,
181 		    EX_NOWAIT | malloc_safe);
182 		if (err)
183 			return (err);
184 	}
185 
186 	return (bus_space_compose_handle(bst, addr, size, flags, bshp));
187 }
188 
189 void
mipsco_bus_space_unmap(bus_space_tag_t bst,bus_space_handle_t bsh,bus_size_t size)190 mipsco_bus_space_unmap(bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t size)
191 {
192 	if (bst->bs_extent != NULL) {
193 		paddr_t pa;
194 		bus_addr_t addr;
195 		int err;
196 
197 		/* bus_space_paddr() becomes unavailable after unmapping */
198 		err = bus_space_paddr(bst, bsh, &pa);
199 		if (err)
200 			panic("mipsco_bus_space_unmap: %s va %p: error %d",
201 			    bst->bs_name, (void *)bsh, err);
202 		addr = (bus_size_t)(pa - bst->bs_pbase) + bst->bs_start;
203 		extent_free(bst->bs_extent, addr, size,
204 		    EX_NOWAIT | malloc_safe);
205 	}
206 	bus_space_dispose_handle(bst, bsh, size);
207 }
208 
209 int
mipsco_bus_space_subregion(bus_space_tag_t bst,bus_space_handle_t bsh,bus_size_t offset,bus_size_t size,bus_space_handle_t * nbshp)210 mipsco_bus_space_subregion(bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
211 {
212 	*nbshp = bsh + (offset << bst->bs_stride);
213 	return (0);
214 }
215 
216 paddr_t
mipsco_bus_space_mmap(bus_space_tag_t bst,bus_addr_t addr,off_t off,int prot,int flags)217 mipsco_bus_space_mmap(bus_space_tag_t bst, bus_addr_t addr, off_t off, int prot, int flags)
218 {
219 
220 	/*
221 	 * XXX We do not disallow mmap'ing of I/O space here,
222 	 * XXX which we should be doing.
223 	 */
224 
225 	if (addr < bst->bs_start ||
226 	    (addr + off) >= (bst->bs_start + bst->bs_size))
227 		return (-1);
228 
229 	return (mips_btop(bst->bs_pbase + (addr - bst->bs_start) + off));
230 }
231 
232 int
mipsco_bus_space_alloc(bus_space_tag_t bst,bus_addr_t start,bus_addr_t end,bus_size_t size,bus_size_t align,bus_size_t boundary,int flags,bus_addr_t * addrp,bus_space_handle_t * bshp)233 mipsco_bus_space_alloc(bus_space_tag_t bst, bus_addr_t start, bus_addr_t end, bus_size_t size, bus_size_t align, bus_size_t boundary, int flags, bus_addr_t *addrp, bus_space_handle_t *bshp)
234 {
235 	u_long addr;
236 	int err;
237 
238 	if (bst->bs_extent == NULL)
239 		panic("mipsco_bus_space_alloc: extent map %s not available",
240 		    bst->bs_name);
241 
242 	if (start < bst->bs_start ||
243 	    start + size > bst->bs_start + bst->bs_size)
244 		return (EINVAL);
245 
246 	err = extent_alloc_subregion(bst->bs_extent, start, end, size,
247 	    align, boundary, EX_FAST | EX_NOWAIT | malloc_safe, &addr);
248 	if (err)
249 		return (err);
250 
251 	*addrp = addr;
252 	return (bus_space_compose_handle(bst, addr, size, flags, bshp));
253 }
254