1 1.29 thorpej /* $NetBSD: apbus.c,v 1.29 2021/08/07 16:19:01 thorpej Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.1 tsubai * Copyright (C) 1999 SHIMIZU Ryo. All rights reserved. 5 1.1 tsubai * 6 1.1 tsubai * Redistribution and use in source and binary forms, with or without 7 1.1 tsubai * modification, are permitted provided that the following conditions 8 1.1 tsubai * are met: 9 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 10 1.1 tsubai * notice, this list of conditions and the following disclaimer. 11 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 13 1.1 tsubai * documentation and/or other materials provided with the distribution. 14 1.1 tsubai * 3. The name of the author may not be used to endorse or promote products 15 1.1 tsubai * derived from this software without specific prior written permission. 16 1.1 tsubai * 17 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 tsubai */ 28 1.17 lukem 29 1.17 lukem #include <sys/cdefs.h> 30 1.29 thorpej __KERNEL_RCSID(0, "$NetBSD: apbus.c,v 1.29 2021/08/07 16:19:01 thorpej Exp $"); 31 1.22 matt 32 1.22 matt #define __INTR_PRIVATE 33 1.1 tsubai 34 1.1 tsubai #include <sys/param.h> 35 1.1 tsubai #include <sys/systm.h> 36 1.27 thorpej #include <sys/kmem.h> 37 1.1 tsubai #include <sys/device.h> 38 1.7 chs #include <sys/proc.h> 39 1.22 matt #include <sys/intr.h> 40 1.1 tsubai 41 1.4 onoe #include <uvm/uvm_extern.h> 42 1.4 onoe 43 1.1 tsubai #include <machine/adrsmap.h> 44 1.1 tsubai #include <machine/autoconf.h> 45 1.3 onoe #define _NEWSMIPS_BUS_DMA_PRIVATE 46 1.3 onoe #include <machine/bus.h> 47 1.1 tsubai #include <newsmips/apbus/apbusvar.h> 48 1.1 tsubai 49 1.21 tsutsui static int apbusmatch(device_t, cfdata_t, void *); 50 1.21 tsutsui static void apbusattach(device_t, device_t, void *); 51 1.18 tsutsui static int apbusprint(void *, const char *); 52 1.18 tsutsui #if 0 53 1.18 tsutsui static void *aptokseg0 (void *); 54 1.18 tsutsui #endif 55 1.18 tsutsui static void apbus_dma_unmapped(bus_dma_tag_t, bus_dmamap_t); 56 1.18 tsutsui static int apbus_dma_mapalloc(bus_dma_tag_t, bus_dmamap_t, int); 57 1.18 tsutsui static void apbus_dma_mapfree(bus_dma_tag_t, bus_dmamap_t); 58 1.18 tsutsui static void apbus_dma_mapset(bus_dma_tag_t, bus_dmamap_t); 59 1.18 tsutsui static int apbus_dmamap_create(bus_dma_tag_t, bus_size_t, int, bus_size_t, 60 1.18 tsutsui bus_size_t, int, bus_dmamap_t *); 61 1.18 tsutsui static void apbus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); 62 1.18 tsutsui static int apbus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, 63 1.18 tsutsui struct proc *, int); 64 1.18 tsutsui static int apbus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, 65 1.18 tsutsui int); 66 1.18 tsutsui static int apbus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, 67 1.18 tsutsui int); 68 1.18 tsutsui static int apbus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, 69 1.18 tsutsui bus_dma_segment_t *, int, bus_size_t, int); 70 1.18 tsutsui static void apbus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, 71 1.18 tsutsui bus_size_t, int); 72 1.1 tsubai 73 1.1 tsubai #define MAXAPDEVNUM 32 74 1.1 tsubai 75 1.21 tsutsui CFATTACH_DECL_NEW(ap, 0, 76 1.10 thorpej apbusmatch, apbusattach, NULL, NULL); 77 1.1 tsubai 78 1.1 tsubai #define NLEVEL 2 79 1.15 tsutsui static struct newsmips_intr apintr_tab[NLEVEL]; 80 1.1 tsubai 81 1.25 tsutsui volatile uint32_t *news_wbflush; 82 1.25 tsutsui 83 1.1 tsubai static int 84 1.21 tsutsui apbusmatch(device_t parent, cfdata_t cf, void *aux) 85 1.1 tsubai { 86 1.1 tsubai struct confargs *ca = aux; 87 1.1 tsubai 88 1.1 tsubai if (strcmp(ca->ca_name, "ap") != 0) 89 1.1 tsubai return 0; 90 1.1 tsubai 91 1.1 tsubai return 1; 92 1.1 tsubai } 93 1.1 tsubai 94 1.1 tsubai 95 1.1 tsubai static void 96 1.21 tsutsui apbusattach(device_t parent, device_t self, void *aux) 97 1.1 tsubai { 98 1.1 tsubai struct apbus_attach_args child; 99 1.2 tsubai struct apbus_dev *apdev; 100 1.1 tsubai struct apbus_ctl *apctl; 101 1.15 tsutsui struct newsmips_intr *ip; 102 1.15 tsutsui int i; 103 1.1 tsubai 104 1.23 tsutsui apbus_map_romwork(); 105 1.22 matt mips_set_wbflush(apbus_wbflush); 106 1.22 matt 107 1.25 tsutsui if (systype == NEWS5000) { 108 1.25 tsutsui *(volatile uint32_t *)(NEWS5000_APBUS_INTST) = 0xffffffff; 109 1.25 tsutsui *(volatile uint32_t *)(NEWS5000_APBUS_INTMSK) = 0xffffffff; 110 1.25 tsutsui *(volatile uint32_t *)(NEWS5000_APBUS_CTRL) = 0x00000004; 111 1.25 tsutsui *(volatile uint32_t *)(NEWS5000_APBUS_DMA) = 0xffffffff; 112 1.25 tsutsui } 113 1.25 tsutsui if (systype == NEWS4000) { 114 1.25 tsutsui *(volatile uint32_t *)0xb60000a4 = 0x1fffffff; 115 1.25 tsutsui *(volatile uint32_t *)0xb6000070 = 0xffffffff; 116 1.25 tsutsui *(volatile uint32_t *)0xb6000098 = 0xffffffff; 117 1.25 tsutsui } 118 1.1 tsubai 119 1.21 tsutsui aprint_normal("\n"); 120 1.1 tsubai 121 1.15 tsutsui for (i = 0; i < NLEVEL; i++) { 122 1.15 tsutsui ip = &apintr_tab[i]; 123 1.15 tsutsui LIST_INIT(&ip->intr_q); 124 1.15 tsutsui } 125 1.15 tsutsui 126 1.1 tsubai /* 127 1.1 tsubai * get first ap-device 128 1.1 tsubai */ 129 1.1 tsubai apdev = apbus_lookupdev(NULL); 130 1.1 tsubai 131 1.1 tsubai /* 132 1.1 tsubai * trace device chain 133 1.1 tsubai */ 134 1.1 tsubai while (apdev) { 135 1.1 tsubai apctl = apdev->apbd_ctl; 136 1.1 tsubai 137 1.1 tsubai /* 138 1.1 tsubai * probe physical device only 139 1.1 tsubai * (no pseudo device) 140 1.1 tsubai */ 141 1.1 tsubai if (apctl && apctl->apbc_hwbase) { 142 1.1 tsubai /* 143 1.1 tsubai * ... and, all units 144 1.1 tsubai */ 145 1.1 tsubai while (apctl) { 146 1.1 tsubai /* make apbus_attach_args for devices */ 147 1.1 tsubai child.apa_name = apdev->apbd_name; 148 1.1 tsubai child.apa_ctlnum = apctl->apbc_ctlno; 149 1.1 tsubai child.apa_slotno = apctl->apbc_sl; 150 1.1 tsubai child.apa_hwbase = apctl->apbc_hwbase; 151 1.1 tsubai 152 1.28 thorpej config_found(self, &child, apbusprint, 153 1.29 thorpej CFARGS_NONE); 154 1.1 tsubai 155 1.1 tsubai apctl = apctl->apbc_link; 156 1.1 tsubai } 157 1.1 tsubai } 158 1.1 tsubai 159 1.1 tsubai apdev = apdev->apbd_link; 160 1.1 tsubai } 161 1.1 tsubai } 162 1.1 tsubai 163 1.1 tsubai int 164 1.18 tsutsui apbusprint(void *aux, const char *pnp) 165 1.1 tsubai { 166 1.1 tsubai struct apbus_attach_args *a = aux; 167 1.1 tsubai 168 1.1 tsubai if (pnp) 169 1.11 thorpej aprint_normal("%s at %s slot%d addr 0x%lx", 170 1.21 tsutsui a->apa_name, pnp, a->apa_slotno, a->apa_hwbase); 171 1.1 tsubai 172 1.1 tsubai return UNCONF; 173 1.1 tsubai } 174 1.1 tsubai 175 1.1 tsubai #if 0 176 1.1 tsubai void * 177 1.21 tsutsui aptokseg0(void *va) 178 1.1 tsubai { 179 1.1 tsubai vaddr_t addr = (vaddr_t)va; 180 1.1 tsubai 181 1.1 tsubai if (addr >= 0xfff00000) { 182 1.1 tsubai addr -= 0xfff00000; 183 1.1 tsubai addr += physmem << PGSHIFT; 184 1.1 tsubai addr += 0x80000000; 185 1.1 tsubai va = (void *)addr; 186 1.1 tsubai } 187 1.1 tsubai return va; 188 1.1 tsubai } 189 1.1 tsubai #endif 190 1.1 tsubai 191 1.1 tsubai void 192 1.18 tsutsui apbus_wbflush(void) 193 1.1 tsubai { 194 1.1 tsubai 195 1.22 matt (*mips_locore_jumpvec.ljv_wbflush)(); 196 1.25 tsutsui (void)*news_wbflush; 197 1.1 tsubai } 198 1.1 tsubai 199 1.1 tsubai /* 200 1.1 tsubai * called by hardware interrupt routine 201 1.1 tsubai */ 202 1.1 tsubai int 203 1.18 tsutsui apbus_intr_dispatch(int level, int stat) 204 1.1 tsubai { 205 1.15 tsutsui struct newsmips_intr *ip; 206 1.15 tsutsui struct newsmips_intrhand *ih; 207 1.15 tsutsui int nintr; 208 1.15 tsutsui 209 1.15 tsutsui ip = &apintr_tab[level]; 210 1.15 tsutsui 211 1.15 tsutsui nintr = 0; 212 1.15 tsutsui LIST_FOREACH(ih, &ip->intr_q, ih_q) { 213 1.24 tsutsui if (ih->ih_mask & stat) { 214 1.15 tsutsui nintr += (*ih->ih_func)(ih->ih_arg); 215 1.24 tsutsui ih->intr_count.ev_count++; 216 1.24 tsutsui } 217 1.1 tsubai } 218 1.1 tsubai return nintr; 219 1.1 tsubai } 220 1.1 tsubai 221 1.1 tsubai /* 222 1.1 tsubai * register device interrupt routine 223 1.1 tsubai */ 224 1.1 tsubai void * 225 1.18 tsutsui apbus_intr_establish(int level, int mask, int priority, int (*func)(void *), 226 1.19 tsutsui void *arg, const char *name, int ctlno) 227 1.1 tsubai { 228 1.15 tsutsui struct newsmips_intr *ip; 229 1.15 tsutsui struct newsmips_intrhand *ih, *curih; 230 1.18 tsutsui volatile uint32_t *inten0, *inten1; 231 1.15 tsutsui 232 1.15 tsutsui ip = &apintr_tab[level]; 233 1.3 onoe 234 1.27 thorpej ih = kmem_alloc(sizeof(*ih), KM_SLEEP); 235 1.15 tsutsui ih->ih_mask = mask; 236 1.15 tsutsui ih->ih_priority = priority; 237 1.15 tsutsui ih->ih_func = func; 238 1.15 tsutsui ih->ih_arg = arg; 239 1.24 tsutsui evcnt_attach_dynamic(&ih->intr_count, EVCNT_TYPE_INTR, 240 1.24 tsutsui NULL, "apbus", name); 241 1.15 tsutsui 242 1.15 tsutsui if (LIST_EMPTY(&ip->intr_q)) { 243 1.15 tsutsui LIST_INSERT_HEAD(&ip->intr_q, ih, ih_q); 244 1.15 tsutsui goto done; 245 1.1 tsubai } 246 1.15 tsutsui 247 1.15 tsutsui for (curih = LIST_FIRST(&ip->intr_q); 248 1.15 tsutsui LIST_NEXT(curih, ih_q) != NULL; 249 1.15 tsutsui curih = LIST_NEXT(curih, ih_q)) { 250 1.15 tsutsui if (ih->ih_priority > curih->ih_priority) { 251 1.15 tsutsui LIST_INSERT_BEFORE(curih, ih, ih_q); 252 1.15 tsutsui goto done; 253 1.15 tsutsui } 254 1.15 tsutsui } 255 1.15 tsutsui 256 1.15 tsutsui LIST_INSERT_AFTER(curih, ih, ih_q); 257 1.15 tsutsui 258 1.15 tsutsui done: 259 1.25 tsutsui if (systype == NEWS5000) { 260 1.25 tsutsui inten0 = (uint32_t *)NEWS5000_INTEN0; 261 1.25 tsutsui inten1 = (uint32_t *)NEWS5000_INTEN1; 262 1.25 tsutsui } 263 1.25 tsutsui if (systype == NEWS4000) { 264 1.25 tsutsui inten0 = (uint32_t *)NEWS4000_INTEN0; 265 1.25 tsutsui inten1 = (uint32_t *)NEWS4000_INTEN1; 266 1.25 tsutsui } 267 1.3 onoe switch (level) { 268 1.3 onoe case 0: 269 1.3 onoe *inten0 |= mask; 270 1.3 onoe break; 271 1.3 onoe case 1: 272 1.3 onoe *inten1 |= mask; 273 1.3 onoe break; 274 1.3 onoe } 275 1.3 onoe 276 1.15 tsutsui return (void *)ih; 277 1.3 onoe } 278 1.3 onoe 279 1.4 onoe static void 280 1.18 tsutsui apbus_dma_unmapped(bus_dma_tag_t t, bus_dmamap_t map) 281 1.4 onoe { 282 1.4 onoe int seg; 283 1.4 onoe 284 1.4 onoe for (seg = 0; seg < map->dm_nsegs; seg++) { 285 1.4 onoe /* 286 1.4 onoe * set MSB to indicate unmapped DMA. 287 1.4 onoe * also need bit 30 for memory over 256MB. 288 1.4 onoe */ 289 1.4 onoe if ((map->dm_segs[seg].ds_addr & 0x30000000) == 0) 290 1.4 onoe map->dm_segs[seg].ds_addr |= 0x80000000; 291 1.4 onoe else 292 1.4 onoe map->dm_segs[seg].ds_addr |= 0xc0000000; 293 1.4 onoe } 294 1.4 onoe } 295 1.4 onoe 296 1.4 onoe #define APBUS_NDMAMAP (NEWS5000_APBUS_MAPSIZE / NEWS5000_APBUS_MAPENT) 297 1.21 tsutsui #define APBUS_MAPTBL(n, v) \ 298 1.21 tsutsui (*(volatile uint32_t *)(NEWS5000_APBUS_DMAMAP + \ 299 1.4 onoe NEWS5000_APBUS_MAPENT * (n) + 1) = (v)) 300 1.21 tsutsui static uint8_t apbus_dma_maptbl[APBUS_NDMAMAP]; 301 1.4 onoe 302 1.4 onoe static int 303 1.18 tsutsui apbus_dma_mapalloc(bus_dma_tag_t t, bus_dmamap_t map, int flags) 304 1.4 onoe { 305 1.4 onoe int i, j, cnt; 306 1.4 onoe 307 1.12 thorpej cnt = round_page(map->_dm_size) / PAGE_SIZE; 308 1.4 onoe 309 1.13 tsutsui again: 310 1.4 onoe for (i = 0; i < APBUS_NDMAMAP; i += j + 1) { 311 1.4 onoe for (j = 0; j < cnt; j++) { 312 1.4 onoe if (apbus_dma_maptbl[i + j]) 313 1.4 onoe break; 314 1.4 onoe } 315 1.4 onoe if (j == cnt) { 316 1.4 onoe for (j = 0; j < cnt; j++) 317 1.4 onoe apbus_dma_maptbl[i + j] = 1; 318 1.4 onoe map->_dm_maptbl = i; 319 1.4 onoe map->_dm_maptblcnt = cnt; 320 1.4 onoe return 0; 321 1.4 onoe } 322 1.4 onoe } 323 1.4 onoe if ((flags & BUS_DMA_NOWAIT) == 0) { 324 1.4 onoe tsleep(&apbus_dma_maptbl, PRIBIO, "apdmat", 0); 325 1.4 onoe goto again; 326 1.4 onoe } 327 1.4 onoe return ENOMEM; 328 1.4 onoe } 329 1.4 onoe 330 1.4 onoe static void 331 1.18 tsutsui apbus_dma_mapfree(bus_dma_tag_t t, bus_dmamap_t map) 332 1.4 onoe { 333 1.4 onoe int i, n; 334 1.4 onoe 335 1.4 onoe if (map->_dm_maptblcnt > 0) { 336 1.4 onoe n = map->_dm_maptbl; 337 1.4 onoe for (i = 0; i < map->_dm_maptblcnt; i++, n++) { 338 1.4 onoe #ifdef DIAGNOSTIC 339 1.4 onoe if (apbus_dma_maptbl[n] == 0) 340 1.14 wiz panic("freeing free DMA map"); 341 1.4 onoe APBUS_MAPTBL(n, 0xffffffff); /* causes DMA error */ 342 1.4 onoe #endif 343 1.4 onoe apbus_dma_maptbl[n] = 0; 344 1.4 onoe } 345 1.4 onoe wakeup(&apbus_dma_maptbl); 346 1.4 onoe map->_dm_maptblcnt = 0; 347 1.4 onoe } 348 1.4 onoe } 349 1.4 onoe 350 1.4 onoe static void 351 1.18 tsutsui apbus_dma_mapset(bus_dma_tag_t t, bus_dmamap_t map) 352 1.4 onoe { 353 1.4 onoe int i; 354 1.4 onoe bus_addr_t addr, eaddr; 355 1.4 onoe int seg; 356 1.4 onoe bus_dma_segment_t *segs; 357 1.4 onoe 358 1.4 onoe i = 0; 359 1.4 onoe for (seg = 0; seg < map->dm_nsegs; seg++) { 360 1.4 onoe segs = &map->dm_segs[seg]; 361 1.4 onoe for (addr = segs->ds_addr, eaddr = addr + segs->ds_len; 362 1.12 thorpej addr < eaddr; addr += PAGE_SIZE, i++) { 363 1.4 onoe #ifdef DIAGNOSTIC 364 1.4 onoe if (i >= map->_dm_maptblcnt) 365 1.14 wiz panic("DMA map table overflow"); 366 1.4 onoe #endif 367 1.4 onoe APBUS_MAPTBL(map->_dm_maptbl + i, 368 1.4 onoe NEWS5000_APBUS_MAP_VALID | 369 1.4 onoe NEWS5000_APBUS_MAP_COHERENT | 370 1.4 onoe (addr >> PGSHIFT)); 371 1.4 onoe } 372 1.4 onoe } 373 1.4 onoe map->dm_segs[0].ds_addr = map->_dm_maptbl << PGSHIFT; 374 1.4 onoe map->dm_segs[0].ds_len = map->dm_mapsize; 375 1.4 onoe map->dm_nsegs = 1; 376 1.4 onoe } 377 1.4 onoe 378 1.5 matt static int 379 1.18 tsutsui apbus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, 380 1.18 tsutsui bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) 381 1.4 onoe { 382 1.4 onoe int error; 383 1.4 onoe 384 1.4 onoe if (flags & NEWSMIPS_DMAMAP_MAPTBL) 385 1.12 thorpej nsegments = round_page(size) / PAGE_SIZE; 386 1.4 onoe error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, 387 1.4 onoe flags, dmamp); 388 1.4 onoe if (error == 0 && (flags & NEWSMIPS_DMAMAP_MAPTBL)) { 389 1.4 onoe error = apbus_dma_mapalloc(t, *dmamp, flags); 390 1.4 onoe if (error) { 391 1.4 onoe _bus_dmamap_destroy(t, *dmamp); 392 1.4 onoe *dmamp = NULL; 393 1.4 onoe } 394 1.4 onoe } 395 1.4 onoe return error; 396 1.4 onoe } 397 1.4 onoe 398 1.5 matt static void 399 1.18 tsutsui apbus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) 400 1.4 onoe { 401 1.18 tsutsui 402 1.4 onoe if (map->_dm_flags & NEWSMIPS_DMAMAP_MAPTBL) 403 1.4 onoe apbus_dma_mapfree(t, map); 404 1.4 onoe _bus_dmamap_destroy(t, map); 405 1.4 onoe } 406 1.4 onoe 407 1.5 matt static int 408 1.18 tsutsui apbus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 409 1.18 tsutsui bus_size_t buflen, struct proc *p, int flags) 410 1.4 onoe { 411 1.4 onoe int error; 412 1.4 onoe 413 1.4 onoe error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 414 1.4 onoe if (error == 0) { 415 1.4 onoe if (map->_dm_flags & NEWSMIPS_DMAMAP_MAPTBL) 416 1.4 onoe apbus_dma_mapset(t, map); 417 1.4 onoe else 418 1.4 onoe apbus_dma_unmapped(t, map); 419 1.4 onoe } 420 1.4 onoe return error; 421 1.4 onoe } 422 1.4 onoe 423 1.5 matt static int 424 1.18 tsutsui apbus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0, 425 1.18 tsutsui int flags) 426 1.4 onoe { 427 1.4 onoe int error; 428 1.4 onoe 429 1.4 onoe error = _bus_dmamap_load_mbuf(t, map, m0, flags); 430 1.4 onoe if (error == 0) { 431 1.4 onoe if (map->_dm_flags & NEWSMIPS_DMAMAP_MAPTBL) 432 1.4 onoe apbus_dma_mapset(t, map); 433 1.4 onoe else 434 1.4 onoe apbus_dma_unmapped(t, map); 435 1.4 onoe } 436 1.4 onoe return error; 437 1.4 onoe } 438 1.4 onoe 439 1.5 matt static int 440 1.18 tsutsui apbus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, 441 1.18 tsutsui int flags) 442 1.4 onoe { 443 1.4 onoe int error; 444 1.4 onoe 445 1.4 onoe error = _bus_dmamap_load_uio(t, map, uio, flags); 446 1.4 onoe if (error == 0) { 447 1.4 onoe if (map->_dm_flags & NEWSMIPS_DMAMAP_MAPTBL) 448 1.4 onoe apbus_dma_mapset(t, map); 449 1.4 onoe else 450 1.4 onoe apbus_dma_unmapped(t, map); 451 1.4 onoe } 452 1.4 onoe return error; 453 1.4 onoe } 454 1.4 onoe 455 1.5 matt static int 456 1.18 tsutsui apbus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 457 1.18 tsutsui bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 458 1.4 onoe { 459 1.4 onoe int error; 460 1.4 onoe 461 1.4 onoe error = _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags); 462 1.4 onoe if (error == 0) { 463 1.4 onoe if (map->_dm_flags & NEWSMIPS_DMAMAP_MAPTBL) 464 1.4 onoe apbus_dma_mapset(t, map); 465 1.4 onoe else 466 1.4 onoe apbus_dma_unmapped(t, map); 467 1.4 onoe } 468 1.4 onoe return error; 469 1.4 onoe } 470 1.4 onoe 471 1.5 matt static void 472 1.18 tsutsui apbus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 473 1.18 tsutsui bus_size_t len, int ops) 474 1.3 onoe { 475 1.1 tsubai 476 1.3 onoe /* 477 1.6 wiz * Flush DMA cache by issuing IO read for the AProm of specified slot. 478 1.3 onoe */ 479 1.3 onoe bus_space_read_4(t->_slotbaset, t->_slotbaseh, 0); 480 1.3 onoe 481 1.8 thorpej bus_dmamap_sync(&newsmips_default_bus_dma_tag, map, offset, len, ops); 482 1.3 onoe } 483 1.1 tsubai 484 1.3 onoe struct newsmips_bus_dma_tag apbus_dma_tag = { 485 1.4 onoe apbus_dmamap_create, 486 1.4 onoe apbus_dmamap_destroy, 487 1.4 onoe apbus_dmamap_load, 488 1.4 onoe apbus_dmamap_load_mbuf, 489 1.4 onoe apbus_dmamap_load_uio, 490 1.4 onoe apbus_dmamap_load_raw, 491 1.3 onoe _bus_dmamap_unload, 492 1.3 onoe apbus_dmamap_sync, 493 1.3 onoe _bus_dmamem_alloc, 494 1.3 onoe _bus_dmamem_free, 495 1.3 onoe _bus_dmamem_map, 496 1.3 onoe _bus_dmamem_unmap, 497 1.3 onoe _bus_dmamem_mmap, 498 1.3 onoe }; 499 1.3 onoe 500 1.3 onoe struct newsmips_bus_dma_tag * 501 1.18 tsutsui apbus_dmatag_init(struct apbus_attach_args *apa) 502 1.3 onoe { 503 1.3 onoe struct newsmips_bus_dma_tag *dmat; 504 1.1 tsubai 505 1.27 thorpej dmat = kmem_alloc(sizeof(*dmat), KM_SLEEP); 506 1.26 chs memcpy(dmat, &apbus_dma_tag, sizeof(*dmat)); 507 1.26 chs dmat->_slotno = apa->apa_slotno; 508 1.26 chs dmat->_slotbaset = 0; 509 1.26 chs dmat->_slotbaseh = apa->apa_hwbase; 510 1.3 onoe return dmat; 511 1.1 tsubai } 512