1 /* $NetBSD: bus.c,v 1.70 2023/12/20 15:29:07 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * 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.c,v 1.70 2023/12/20 15:29:07 thorpej Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/endian.h>
39 #include <sys/bswap.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/proc.h>
43 #include <sys/mbuf.h>
44
45 #define _MIPS_BUS_DMA_PRIVATE
46
47 #include <sys/bus.h>
48 #include <machine/cpu.h>
49 #include <machine/machtype.h>
50
51 #include <uvm/uvm_extern.h>
52
53 #include <mips/cpuregs.h>
54 #include <mips/locore.h>
55 #include <mips/cache.h>
56
57 #include <sgimips/mace/macereg.h>
58
59 #include "opt_sgimace.h"
60
61 struct mips_bus_dma_tag sgimips_default_bus_dma_tag = {
62 ._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER,
63 ._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER,
64 ._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER,
65 };
66
67 static void normal_bus_mem_init(bus_space_tag_t, void *);
68
69 static struct mips_bus_space normal_mbst;
70 bus_space_tag_t normal_memt = NULL;
71
72 /*
73 * XXX
74 * I'm not sure how well the common MIPS bus_dma.c handles MIPS-I and I don't
75 * have any IP1x hardware, so I'll leave this in just in case it needs to be
76 * put back
77 */
78
79 void
sgimips_bus_dma_init(void)80 sgimips_bus_dma_init(void)
81 {
82 normal_bus_mem_init(&normal_mbst, NULL);
83 normal_memt = &normal_mbst;
84
85 #ifdef MIPS1
86 switch (mach_type) {
87 /* R2000/R3000 */
88 case MACH_SGI_IP6 | MACH_SGI_IP10: /* same number... */
89 case MACH_SGI_IP12:
90 sgimips_default_bus_dma_tag._dmamap_ops.dmamap_sync =
91 _bus_dmamap_sync_mips1;
92 break;
93 }
94 #endif
95 }
96
97 /*
98 * XXX
99 * left in for illustrative purposes
100 */
101
102 #if 0
103 u_int8_t
104 bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
105 {
106 wbflush(); /* XXX ? */
107
108 switch (t) {
109 case SGIMIPS_BUS_SPACE_NORMAL:
110 return *(volatile u_int8_t *)(vaddr_t)(h + o);
111 case SGIMIPS_BUS_SPACE_IP6_DPCLOCK:
112 return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2));
113 case SGIMIPS_BUS_SPACE_HPC:
114 return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2) + 3);
115 case SGIMIPS_BUS_SPACE_MEM:
116 case SGIMIPS_BUS_SPACE_IO:
117 return *(volatile u_int8_t *)(vaddr_t)(h + (o | 3) - (o & 3));
118 case SGIMIPS_BUS_SPACE_MACE:
119 return *(volatile u_int8_t *)(vaddr_t)(h + (o << 8) + 7);
120 default:
121 panic("no bus tag");
122 }
123 }
124 #endif
125
126 #ifdef MIPS1
127 /* Common function from DMA map synchronization. May be called
128 * by chipset-specific DMA map synchronization functions.
129 *
130 * This is the R3000 version.
131 */
132 void
_bus_dmamap_sync_mips1(bus_dma_tag_t t,bus_dmamap_t map,bus_addr_t offset,bus_size_t len,int ops)133 _bus_dmamap_sync_mips1(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
134 bus_size_t len, int ops)
135 {
136 bus_size_t minlen;
137 bus_addr_t addr;
138 int i;
139
140 /*
141 * Mixing PRE and POST operations is not allowed.
142 */
143 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
144 (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
145 panic("_bus_dmamap_sync_mips1: mix PRE and POST");
146
147 #ifdef DIAGNOSTIC
148 if (offset >= map->dm_mapsize)
149 panic("_bus_dmamap_sync_mips1: bad offset %"PRIxPSIZE
150 " (map size is %"PRIxPSIZE")"
151 , offset, map->dm_mapsize);
152 if (len == 0 || (offset + len) > map->dm_mapsize)
153 panic("_bus_dmamap_sync_mips1: bad length");
154 #endif
155
156 /*
157 * The R3000 cache is write-through. Therefore, we only need
158 * to drain the write buffer on PREWRITE. The cache is not
159 * coherent, however, so we need to invalidate the data cache
160 * on PREREAD (should we do it POSTREAD instead?).
161 *
162 * POSTWRITE (and POSTREAD, currently) are noops.
163 */
164
165 if (ops & BUS_DMASYNC_PREWRITE) {
166 /*
167 * Flush the write buffer.
168 */
169 wbflush();
170 }
171
172 /*
173 * If we're not doing PREREAD, nothing more to do.
174 */
175 if ((ops & BUS_DMASYNC_PREREAD) == 0)
176 return;
177
178 /*
179 * No cache invalidation is necessary if the DMA map covers
180 * COHERENT DMA-safe memory (which is mapped un-cached).
181 */
182 if (map->_dm_flags & SGIMIPS_DMAMAP_COHERENT)
183 return;
184
185 /*
186 * If we are going to hit something as large or larger
187 * than the entire data cache, just nail the whole thing.
188 *
189 * NOTE: Even though this is `wbinv_all', since the cache is
190 * write-through, it just invalidates it.
191 */
192 if (len >= mips_cache_info.mci_pdcache_size) {
193 mips_dcache_wbinv_all();
194 return;
195 }
196
197 for (i = 0; i < map->dm_nsegs && len != 0; i++) {
198 /* Find the beginning segment. */
199 if (offset >= map->dm_segs[i].ds_len) {
200 offset -= map->dm_segs[i].ds_len;
201 continue;
202 }
203
204 /*
205 * Now at the first segment to sync; nail
206 * each segment until we have exhausted the
207 * length.
208 */
209 minlen = len < map->dm_segs[i].ds_len - offset ?
210 len : map->dm_segs[i].ds_len - offset;
211
212 addr = map->dm_segs[i].ds_addr;
213
214 #ifdef BUS_DMA_DEBUG
215 printf("bus_dmamap_sync_mips1: flushing segment %d "
216 "(0x%"PRIxBUSADDR"..0x%"PRIxBUSADDR") ...", i,
217 addr + offset, addr + offset + minlen - 1);
218 #endif
219 mips_dcache_inv_range(
220 MIPS_PHYS_TO_KSEG0(addr + offset), minlen);
221 #ifdef BUS_DMA_DEBUG
222 printf("\n");
223 #endif
224 offset = 0;
225 len -= minlen;
226 }
227 }
228 #endif
229
230 #define CHIP normal
231 #define CHIP_MEM /* defined */
232 #define CHIP_W1_BUS_START(v) 0x00000000UL
233 #define CHIP_W1_BUS_END(v) 0xffffffffUL
234 #define CHIP_W1_SYS_START(v) 0x00000000UL
235 #define CHIP_W1_SYS_END(v) 0xffffffffUL
236
237 #include <mips/mips/bus_space_alignstride_chipdep.c>
238