1 /* $NetBSD: bus.c,v 1.39 2024/01/07 07:58:35 isaki 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. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * bus_space(9) and bus_dma(9) implementation for NetBSD/x68k. 34 * These are default implementations; some buses may use their own. 35 */ 36 37 #include "opt_m68k_arch.h" 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.39 2024/01/07 07:58:35 isaki Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/kernel.h> 47 #include <sys/conf.h> 48 #include <sys/device.h> 49 #include <sys/proc.h> 50 51 #include <uvm/uvm_extern.h> 52 53 #include <m68k/cacheops.h> 54 #include <machine/bus.h> 55 56 #include <dev/bus_dma/bus_dmamem_common.h> 57 58 #if defined(M68040) || defined(M68060) 59 static inline void dmasync_flush(bus_addr_t, bus_size_t); 60 static inline void dmasync_inval(bus_addr_t, bus_size_t); 61 #endif 62 63 int 64 x68k_bus_space_alloc(bus_space_tag_t t, bus_addr_t rstart, bus_addr_t rend, 65 bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, 66 bus_addr_t *bpap, bus_space_handle_t *bshp) 67 { 68 return (EINVAL); 69 } 70 71 void 72 x68k_bus_space_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) 73 { 74 panic("bus_space_free: shouldn't be here"); 75 } 76 77 78 extern paddr_t avail_end; 79 80 /* 81 * Common function for DMA map creation. May be called by bus-specific 82 * DMA map creation functions. 83 */ 84 int 85 x68k_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, 86 bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) 87 { 88 struct x68k_bus_dmamap *map; 89 void *mapstore; 90 size_t mapsize; 91 92 /* 93 * Allocate and initialize the DMA map. The end of the map 94 * is a variable-sized array of segments, so we allocate enough 95 * room for them in one shot. 96 * 97 * Note we don't preserve the WAITOK or NOWAIT flags. Preservation 98 * of ALLOCNOW notifies others that we've reserved these resources, 99 * and they are not to be freed. 100 * 101 * The bus_dmamap_t includes one bus_dma_segment_t, hence 102 * the (nsegments - 1). 103 */ 104 mapsize = sizeof(struct x68k_bus_dmamap) + 105 (sizeof(bus_dma_segment_t) * (nsegments - 1)); 106 if ((mapstore = malloc(mapsize, M_DMAMAP, 107 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) 108 return (ENOMEM); 109 110 memset(mapstore, 0, mapsize); 111 map = (struct x68k_bus_dmamap *)mapstore; 112 map->x68k_dm_size = size; 113 map->x68k_dm_segcnt = nsegments; 114 map->x68k_dm_maxmaxsegsz = maxsegsz; 115 map->x68k_dm_boundary = boundary; 116 map->x68k_dm_bounce_thresh = t->_bounce_thresh; 117 map->x68k_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT); 118 map->dm_maxsegsz = maxsegsz; 119 map->dm_mapsize = 0; /* no valid mappings */ 120 map->dm_nsegs = 0; 121 122 *dmamp = map; 123 return (0); 124 } 125 126 /* 127 * Common function for DMA map destruction. May be called by bus-specific 128 * DMA map destruction functions. 129 */ 130 void 131 x68k_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) 132 { 133 134 free(map, M_DMAMAP); 135 } 136 137 /* 138 * Common function for loading a DMA map with a linear buffer. May 139 * be called by bus-specific DMA map load functions. 140 */ 141 int 142 x68k_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 143 bus_size_t buflen, struct proc *p, int flags) 144 { 145 paddr_t lastaddr; 146 int seg, error; 147 148 /* 149 * Make sure that on error condition we return "no valid mappings". 150 */ 151 map->dm_mapsize = 0; 152 map->dm_nsegs = 0; 153 KASSERT(map->dm_maxsegsz <= map->x68k_dm_maxmaxsegsz); 154 155 if (buflen > map->x68k_dm_size) 156 return (EINVAL); 157 158 seg = 0; 159 error = x68k_bus_dmamap_load_buffer(map, buf, buflen, p, flags, 160 &lastaddr, &seg, 1); 161 if (error == 0) { 162 map->dm_mapsize = buflen; 163 map->dm_nsegs = seg + 1; 164 } 165 return (error); 166 } 167 168 /* 169 * Like x68k_bus_dmamap_load(), but for mbufs. 170 */ 171 int 172 x68k_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0, 173 int flags) 174 { 175 paddr_t lastaddr; 176 int seg, error, first; 177 struct mbuf *m; 178 179 /* 180 * Make sure that on error condition we return "no valid mappings." 181 */ 182 map->dm_mapsize = 0; 183 map->dm_nsegs = 0; 184 KASSERT(map->dm_maxsegsz <= map->x68k_dm_maxmaxsegsz); 185 186 #ifdef DIAGNOSTIC 187 if ((m0->m_flags & M_PKTHDR) == 0) 188 panic("x68k_bus_dmamap_load_mbuf: no packet header"); 189 #endif 190 191 if (m0->m_pkthdr.len > map->x68k_dm_size) 192 return (EINVAL); 193 194 first = 1; 195 seg = 0; 196 error = 0; 197 for (m = m0; m != NULL && error == 0; m = m->m_next) { 198 if (m->m_len == 0) 199 continue; 200 error = x68k_bus_dmamap_load_buffer(map, m->m_data, m->m_len, 201 NULL, flags, &lastaddr, &seg, first); 202 first = 0; 203 } 204 if (error == 0) { 205 map->dm_mapsize = m0->m_pkthdr.len; 206 map->dm_nsegs = seg + 1; 207 } 208 return (error); 209 } 210 211 /* 212 * Like x68k_bus_dmamap_load(), but for uios. 213 */ 214 int 215 x68k_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, 216 int flags) 217 { 218 #if 0 219 paddr_t lastaddr; 220 int seg, i, error, first; 221 bus_size_t minlen, resid; 222 struct proc *p = NULL; 223 struct iovec *iov; 224 void *addr; 225 226 /* 227 * Make sure that on error condition we return "no valid mappings." 228 */ 229 map->dm_mapsize = 0; 230 map->dm_nsegs = 0; 231 KASSERT(map->dm_maxsegsz <= map->x68k_dm_maxmaxsegsz); 232 233 resid = uio->uio_resid; 234 iov = uio->uio_iov; 235 236 if (uio->uio_segflg == UIO_USERSPACE) { 237 p = uio->uio_lwp ? uio->uio_lwp->l_proc : NULL; 238 #ifdef DIAGNOSTIC 239 if (p == NULL) 240 panic("_bus_dmamap_load_uio: USERSPACE but no proc"); 241 #endif 242 } 243 244 first = 1; 245 seg = 0; 246 error = 0; 247 for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { 248 /* 249 * Now at the first iovec to load. Load each iovec 250 * until we have exhausted the residual count. 251 */ 252 minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len; 253 addr = (void *)iov[i].iov_base; 254 255 error = x68k_bus_dmamap_load_buffer(map, addr, minlen, 256 p, flags, &lastaddr, &seg, first); 257 first = 0; 258 259 resid -= minlen; 260 } 261 if (error == 0) { 262 map->dm_mapsize = uio->uio_resid; 263 map->dm_nsegs = seg + 1; 264 } 265 return (error); 266 #else 267 panic ("x68k_bus_dmamap_load_uio: not implemented"); 268 #endif 269 } 270 271 /* 272 * Like x68k_bus_dmamap_load(), but for raw memory allocated with 273 * bus_dmamem_alloc(). 274 */ 275 int 276 x68k_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 277 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 278 { 279 280 panic("x68k_bus_dmamap_load_raw: not implemented"); 281 } 282 283 /* 284 * Common function for unloading a DMA map. May be called by 285 * bus-specific DMA map unload functions. 286 */ 287 void 288 x68k_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 289 { 290 291 /* 292 * No resources to free; just mark the mappings as 293 * invalid. 294 */ 295 map->dm_maxsegsz = map->x68k_dm_maxmaxsegsz; 296 map->dm_mapsize = 0; 297 map->dm_nsegs = 0; 298 } 299 300 #if defined(M68040) || defined(M68060) 301 static inline void 302 dmasync_flush(bus_addr_t addr, bus_size_t len) 303 { 304 bus_addr_t end = addr+len; 305 306 if (len <= 1024) { 307 addr = addr & ~0xF; 308 309 do { 310 DCFL(addr); 311 addr += 16; 312 } while (addr < end); 313 } else { 314 addr = m68k_trunc_page(addr); 315 316 do { 317 DCFP(addr); 318 addr += PAGE_SIZE; 319 } while (addr < end); 320 } 321 } 322 323 static inline void 324 dmasync_inval(bus_addr_t addr, bus_size_t len) 325 { 326 bus_addr_t end = addr+len; 327 328 if (len <= 1024) { 329 addr = addr & ~0xF; 330 331 do { 332 DCFL(addr); 333 ICPL(addr); 334 addr += 16; 335 } while (addr < end); 336 } else { 337 addr = m68k_trunc_page(addr); 338 339 do { 340 DCPL(addr); 341 ICPP(addr); 342 addr += PAGE_SIZE; 343 } while (addr < end); 344 } 345 } 346 #endif 347 348 /* 349 * Common function for DMA map synchronization. May be called 350 * by bus-specific DMA map synchronization functions. 351 */ 352 void 353 x68k_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 354 bus_size_t len, int ops) 355 { 356 #if defined(M68040) || defined(M68060) 357 bus_dma_segment_t *ds = map->dm_segs; 358 bus_addr_t seg; 359 int i; 360 361 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_POSTWRITE)) == 0) 362 return; 363 #if defined(M68020) || defined(M68030) 364 if (mmutype != MMU_68040) { 365 if ((ops & BUS_DMASYNC_POSTWRITE) == 0) 366 return; /* no copyback cache */ 367 ICIA(); /* no per-page/per-line control */ 368 DCIA(); 369 return; 370 } 371 #endif 372 if (offset >= map->dm_mapsize) 373 return; /* driver bug; warn it? */ 374 if (offset+len > map->dm_mapsize) 375 len = map->dm_mapsize; /* driver bug; warn it? */ 376 377 i = 0; 378 while (ds[i].ds_len <= offset) { 379 offset -= ds[i++].ds_len; 380 continue; 381 } 382 while (len > 0) { 383 seg = ds[i].ds_len - offset; 384 if (seg > len) 385 seg = len; 386 if (mmutype == MMU_68040 && (ops & BUS_DMASYNC_PREWRITE)) 387 dmasync_flush(ds[i].ds_addr+offset, seg); 388 if (ops & BUS_DMASYNC_POSTREAD) 389 dmasync_inval(ds[i].ds_addr+offset, seg); 390 offset = 0; 391 len -= seg; 392 i++; 393 } 394 #else /* no 040/060 */ 395 if ((ops & BUS_DMASYNC_POSTWRITE)) { 396 ICIA(); /* no per-page/per-line control */ 397 DCIA(); 398 } 399 #endif 400 } 401 402 /* 403 * Common function for DMA-safe memory allocation. May be called 404 * by bus-specific DMA memory allocation functions. 405 */ 406 int 407 x68k_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, 408 bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, 409 int flags) 410 { 411 412 return (x68k_bus_dmamem_alloc_range(t, size, alignment, boundary, 413 segs, nsegs, rsegs, flags, 0, trunc_page(avail_end))); 414 } 415 416 /* 417 * Common function for freeing DMA-safe memory. May be called by 418 * bus-specific DMA memory free functions. 419 */ 420 void 421 x68k_bus_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) 422 { 423 424 _bus_dmamem_free_common(t, segs, nsegs); 425 } 426 427 /* 428 * Common function for mapping DMA-safe memory. May be called by 429 * bus-specific DMA memory map functions. 430 */ 431 int 432 x68k_bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 433 size_t size, void **kvap, int flags) 434 { 435 436 /* XXX BUS_DMA_COHERENT */ 437 return (_bus_dmamem_map_common(t, segs, nsegs, size, kvap, flags, 0)); 438 } 439 440 /* 441 * Common function for unmapping DMA-safe memory. May be called by 442 * bus-specific DMA memory unmapping functions. 443 */ 444 void 445 x68k_bus_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) 446 { 447 448 _bus_dmamem_unmap_common(t, kva, size); 449 } 450 451 /* 452 * Common function for mmap(2)'ing DMA-safe memory. May be called by 453 * bus-specific DMA mmap(2)'ing functions. 454 */ 455 paddr_t 456 x68k_bus_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, 457 off_t off, int prot, int flags) 458 { 459 bus_addr_t rv; 460 461 rv = _bus_dmamem_mmap_common(t, segs, nsegs, off, prot, flags); 462 if (rv == (bus_addr_t)-1) 463 return (-1); 464 465 return (m68k_btop((char *)rv)); 466 } 467 468 469 /********************************************************************** 470 * DMA utility functions 471 **********************************************************************/ 472 473 /* 474 * Utility function to load a linear buffer. lastaddrp holds state 475 * between invocations (for multiple-buffer loads). segp contains 476 * the starting segment on entrance, and the ending segment on exit. 477 * first indicates if this is the first invocation of this function. 478 */ 479 int 480 x68k_bus_dmamap_load_buffer(bus_dmamap_t map, void *buf, bus_size_t buflen, 481 struct proc *p, int flags, paddr_t *lastaddrp, int *segp, int first) 482 { 483 bus_size_t sgsize; 484 bus_addr_t curaddr, lastaddr, baddr, bmask; 485 vaddr_t vaddr = (vaddr_t)buf; 486 int seg; 487 pmap_t pmap; 488 489 if (p != NULL) 490 pmap = p->p_vmspace->vm_map.pmap; 491 else 492 pmap = pmap_kernel(); 493 494 lastaddr = *lastaddrp; 495 bmask = ~(map->x68k_dm_boundary - 1); 496 497 for (seg = *segp; buflen > 0 ; ) { 498 /* 499 * Get the physical address for this segment. 500 */ 501 (void) pmap_extract(pmap, vaddr, &curaddr); 502 503 /* 504 * If we're beyond the bounce threshold, notify 505 * the caller. 506 */ 507 if (map->x68k_dm_bounce_thresh != 0 && 508 curaddr >= map->x68k_dm_bounce_thresh) 509 return (EINVAL); 510 511 /* 512 * Compute the segment size, and adjust counts. 513 */ 514 sgsize = PAGE_SIZE - m68k_page_offset(vaddr); 515 if (buflen < sgsize) 516 sgsize = buflen; 517 518 /* 519 * Make sure we don't cross any boundaries. 520 */ 521 if (map->x68k_dm_boundary > 0) { 522 baddr = (curaddr + map->x68k_dm_boundary) & bmask; 523 if (sgsize > (baddr - curaddr)) 524 sgsize = (baddr - curaddr); 525 } 526 527 /* 528 * Insert chunk into a segment, coalescing with 529 * previous segment if possible. 530 */ 531 if (first) { 532 map->dm_segs[seg].ds_addr = curaddr; 533 map->dm_segs[seg].ds_len = sgsize; 534 first = 0; 535 } else { 536 if (curaddr == lastaddr && 537 (map->dm_segs[seg].ds_len + sgsize) <= 538 map->dm_maxsegsz && 539 (map->x68k_dm_boundary == 0 || 540 (map->dm_segs[seg].ds_addr & bmask) == 541 (curaddr & bmask))) 542 map->dm_segs[seg].ds_len += sgsize; 543 else { 544 if (++seg >= map->x68k_dm_segcnt) 545 break; 546 map->dm_segs[seg].ds_addr = curaddr; 547 map->dm_segs[seg].ds_len = sgsize; 548 } 549 } 550 551 lastaddr = curaddr + sgsize; 552 vaddr += sgsize; 553 buflen -= sgsize; 554 } 555 556 *segp = seg; 557 *lastaddrp = lastaddr; 558 559 /* 560 * Did we fit? 561 */ 562 if (buflen != 0) 563 return (EFBIG); /* XXX better return value here? */ 564 return (0); 565 } 566 567 /* 568 * Allocate physical memory from the given physical address range. 569 * Called by DMA-safe memory allocation methods. 570 */ 571 int 572 x68k_bus_dmamem_alloc_range(bus_dma_tag_t t, bus_size_t size, 573 bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, 574 int nsegs, int *rsegs, int flags, paddr_t low, paddr_t high) 575 { 576 577 return (_bus_dmamem_alloc_range_common(t, size, alignment, boundary, 578 segs, nsegs, rsegs, flags, 579 low, high)); 580 } 581