1 /* $NetBSD: apecs_dma.c,v 1.2 1997/06/06 23:59:23 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 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 * 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 <machine/options.h> /* Config options headers */ 41 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 42 43 __KERNEL_RCSID(0, "$NetBSD: apecs_dma.c,v 1.2 1997/06/06 23:59:23 thorpej Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/device.h> 49 #include <sys/malloc.h> 50 #include <vm/vm.h> 51 52 #define _ALPHA_BUS_DMA_PRIVATE 53 #include <machine/bus.h> 54 55 #include <dev/pci/pcireg.h> 56 #include <dev/pci/pcivar.h> 57 #include <alpha/pci/apecsreg.h> 58 #include <alpha/pci/apecsvar.h> 59 60 bus_dma_tag_t apecs_dma_get_tag __P((bus_dma_tag_t, alpha_bus_t)); 61 62 int apecs_bus_dmamap_create_sgmap __P((bus_dma_tag_t, bus_size_t, int, 63 bus_size_t, bus_size_t, int, bus_dmamap_t *)); 64 65 void apecs_bus_dmamap_destroy_sgmap __P((bus_dma_tag_t, bus_dmamap_t)); 66 67 int apecs_bus_dmamap_load_direct __P((bus_dma_tag_t, bus_dmamap_t, void *, 68 bus_size_t, struct proc *, int)); 69 int apecs_bus_dmamap_load_sgmap __P((bus_dma_tag_t, bus_dmamap_t, void *, 70 bus_size_t, struct proc *, int)); 71 72 int apecs_bus_dmamap_load_mbuf_direct __P((bus_dma_tag_t, bus_dmamap_t, 73 struct mbuf *, int)); 74 int apecs_bus_dmamap_load_mbuf_sgmap __P((bus_dma_tag_t, bus_dmamap_t, 75 struct mbuf *, int)); 76 77 int apecs_bus_dmamap_load_uio_direct __P((bus_dma_tag_t, bus_dmamap_t, 78 struct uio *, int)); 79 int apecs_bus_dmamap_load_uio_sgmap __P((bus_dma_tag_t, bus_dmamap_t, 80 struct uio *, int)); 81 82 int apecs_bus_dmamap_load_raw_direct __P((bus_dma_tag_t, bus_dmamap_t, 83 bus_dma_segment_t *, int, bus_size_t, int)); 84 int apecs_bus_dmamap_load_raw_sgmap __P((bus_dma_tag_t, bus_dmamap_t, 85 bus_dma_segment_t *, int, bus_size_t, int)); 86 87 void apecs_bus_dmamap_unload_sgmap __P((bus_dma_tag_t, bus_dmamap_t)); 88 89 /* 90 * The 1G direct-mapped DMA window begins at this PCI address. 91 */ 92 #define APECS_DIRECT_MAPPED_BASE 0x40000000 93 94 /* 95 * The 8M SGMAP-mapped DMA window begins at this PCI address. 96 */ 97 #define APECS_SGMAP_MAPPED_BASE (8*1024*1024) 98 99 /* 100 * Macro to flush APECS scatter/gather TLB. 101 */ 102 #define APECS_TLB_INVALIDATE() \ 103 do { \ 104 alpha_mb(); \ 105 REGVAL(EPIC_TBIA) = 0; \ 106 alpha_mb(); \ 107 } while (0) 108 109 void 110 apecs_dma_init(acp) 111 struct apecs_config *acp; 112 { 113 bus_addr_t tbase; 114 bus_dma_tag_t t; 115 116 /* 117 * Initialize the DMA tag used for direct-mapped DMA. 118 */ 119 t = &acp->ac_dmat_direct; 120 t->_cookie = acp; 121 t->_get_tag = apecs_dma_get_tag; 122 t->_dmamap_create = _bus_dmamap_create; 123 t->_dmamap_destroy = _bus_dmamap_destroy; 124 t->_dmamap_load = apecs_bus_dmamap_load_direct; 125 t->_dmamap_load_mbuf = apecs_bus_dmamap_load_mbuf_direct; 126 t->_dmamap_load_uio = apecs_bus_dmamap_load_uio_direct; 127 t->_dmamap_load_raw = apecs_bus_dmamap_load_raw_direct; 128 t->_dmamap_unload = _bus_dmamap_unload; 129 t->_dmamap_sync = NULL; /* Nothing to do. */ 130 131 t->_dmamem_alloc = _bus_dmamem_alloc; 132 t->_dmamem_free = _bus_dmamem_free; 133 t->_dmamem_map = _bus_dmamem_map; 134 t->_dmamem_unmap = _bus_dmamem_unmap; 135 t->_dmamem_mmap = _bus_dmamem_mmap; 136 137 /* 138 * Initialize the DMA tag used for sgmap-mapped DMA. 139 */ 140 t = &acp->ac_dmat_sgmap; 141 t->_cookie = acp; 142 t->_get_tag = apecs_dma_get_tag; 143 t->_dmamap_create = apecs_bus_dmamap_create_sgmap; 144 t->_dmamap_destroy = apecs_bus_dmamap_destroy_sgmap; 145 t->_dmamap_load = apecs_bus_dmamap_load_sgmap; 146 t->_dmamap_load_mbuf = apecs_bus_dmamap_load_mbuf_sgmap; 147 t->_dmamap_load_uio = apecs_bus_dmamap_load_uio_sgmap; 148 t->_dmamap_load_raw = apecs_bus_dmamap_load_raw_sgmap; 149 t->_dmamap_unload = apecs_bus_dmamap_unload_sgmap; 150 t->_dmamap_sync = NULL; /* Nothing to do. */ 151 152 t->_dmamem_alloc = _bus_dmamem_alloc; 153 t->_dmamem_free = _bus_dmamem_free; 154 t->_dmamem_map = _bus_dmamem_map; 155 t->_dmamem_unmap = _bus_dmamem_unmap; 156 t->_dmamem_mmap = _bus_dmamem_mmap; 157 158 /* 159 * The firmware has set up window 2 as a 1G direct-mapped DMA 160 * window beginning at 1G. We leave it alone. Disable 161 * window 1. 162 */ 163 REGVAL(EPIC_PCI_BASE_1) = 0; 164 alpha_mb(); 165 166 /* 167 * Initialize the SGMAP if safe to do so. 168 */ 169 if (acp->ac_mallocsafe) { 170 alpha_sgmap_init(t, &acp->ac_sgmap, "apecs_sgmap", 171 APECS_SGMAP_MAPPED_BASE, 0, (8*1024*1024), 172 sizeof(u_int64_t), NULL); 173 174 /* 175 * Set up window 1 as an 8MB SGMAP-mapped window 176 * starting at 8MB. 177 */ 178 tbase = acp->ac_sgmap.aps_ptpa >> EPIC_TBASE_SHIFT; 179 if ((tbase & EPIC_TBASE_T_BASE) != tbase) 180 panic("apecs_dma_init: bad page table address"); 181 REGVAL(EPIC_TBASE_1) = tbase; 182 REGVAL(EPIC_PCI_MASK_1) = EPIC_PCI_MASK_8M; 183 alpha_mb(); 184 185 REGVAL(EPIC_PCI_BASE_1) = APECS_SGMAP_MAPPED_BASE | 186 EPIC_PCI_BASE_SGEN | EPIC_PCI_BASE_WENB; 187 alpha_mb(); 188 189 APECS_TLB_INVALIDATE(); 190 } 191 192 /* XXX XXX BEGIN XXX XXX */ 193 { /* XXX */ 194 extern vm_offset_t alpha_XXX_dmamap_or; /* XXX */ 195 alpha_XXX_dmamap_or = APECS_DIRECT_MAPPED_BASE; /* XXX */ 196 } /* XXX */ 197 /* XXX XXX END XXX XXX */ 198 } 199 200 /* 201 * Return the bus dma tag to be used for the specified bus type. 202 * INTERNAL USE ONLY! 203 */ 204 bus_dma_tag_t 205 apecs_dma_get_tag(t, bustype) 206 bus_dma_tag_t t; 207 alpha_bus_t bustype; 208 { 209 struct apecs_config *acp = t->_cookie; 210 211 switch (bustype) { 212 case ALPHA_BUS_PCI: 213 case ALPHA_BUS_EISA: 214 /* 215 * Systems with an APECS can only support 1G 216 * of memory, so we use the direct-mapped window 217 * on busses that have 32-bit DMA. 218 */ 219 return (&acp->ac_dmat_direct); 220 221 case ALPHA_BUS_ISA: 222 /* 223 * ISA doesn't have enough address bits to use 224 * the direct-mapped DMA window, so we must use 225 * SGMAPs. 226 */ 227 return (&acp->ac_dmat_sgmap); 228 229 default: 230 panic("apecs_dma_get_tag: shouldn't be here, really..."); 231 } 232 } 233 234 /* 235 * Create an APECS SGMAP-mapped DMA map. 236 */ 237 int 238 apecs_bus_dmamap_create_sgmap(t, size, nsegments, maxsegsz, boundary, 239 flags, dmamp) 240 bus_dma_tag_t t; 241 bus_size_t size; 242 int nsegments; 243 bus_size_t maxsegsz; 244 bus_size_t boundary; 245 int flags; 246 bus_dmamap_t *dmamp; 247 { 248 struct apecs_config *acp = t->_cookie; 249 struct alpha_sgmap_cookie *a; 250 bus_dmamap_t map; 251 int error; 252 253 error = _bus_dmamap_create(t, size, nsegments, maxsegsz, 254 boundary, flags, dmamp); 255 if (error) 256 return (error); 257 258 map = *dmamp; 259 260 a = malloc(sizeof(struct alpha_sgmap_cookie), M_DEVBUF, 261 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK); 262 if (a == NULL) { 263 _bus_dmamap_destroy(t, map); 264 return (ENOMEM); 265 } 266 bzero(a, sizeof(struct alpha_sgmap_cookie)); 267 map->_dm_sgcookie = a; 268 269 if (flags & BUS_DMA_ALLOCNOW) { 270 error = alpha_sgmap_alloc(map, round_page(size), 271 &acp->ac_sgmap, flags); 272 if (error) 273 apecs_bus_dmamap_destroy_sgmap(t, map); 274 } 275 276 return (error); 277 } 278 279 /* 280 * Destroy an APECS SGMAP-mapped DMA map. 281 */ 282 void 283 apecs_bus_dmamap_destroy_sgmap(t, map) 284 bus_dma_tag_t t; 285 bus_dmamap_t map; 286 { 287 struct apecs_config *acp = t->_cookie; 288 struct alpha_sgmap_cookie *a = map->_dm_sgcookie; 289 290 if (a->apdc_flags & APDC_HAS_SGMAP) 291 alpha_sgmap_free(&acp->ac_sgmap, a); 292 293 free(a, M_DEVBUF); 294 _bus_dmamap_destroy(t, map); 295 } 296 297 /* 298 * Load an APECS direct-mapped DMA map with a linear buffer. 299 */ 300 int 301 apecs_bus_dmamap_load_direct(t, map, buf, buflen, p, flags) 302 bus_dma_tag_t t; 303 bus_dmamap_t map; 304 void *buf; 305 bus_size_t buflen; 306 struct proc *p; 307 int flags; 308 { 309 310 return (_bus_dmamap_load_direct_common(t, map, buf, buflen, p, 311 flags, APECS_DIRECT_MAPPED_BASE)); 312 } 313 314 /* 315 * Load an APECS SGMAP-mapped DMA map with a linear buffer. 316 */ 317 int 318 apecs_bus_dmamap_load_sgmap(t, map, buf, buflen, p, flags) 319 bus_dma_tag_t t; 320 bus_dmamap_t map; 321 void *buf; 322 bus_size_t buflen; 323 struct proc *p; 324 int flags; 325 { 326 struct apecs_config *acp = t->_cookie; 327 int error; 328 329 error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags, 330 &acp->ac_sgmap); 331 if (error == 0) 332 APECS_TLB_INVALIDATE(); 333 334 return (error); 335 } 336 337 /* 338 * Load an APECS direct-mapped DMA map with an mbuf chain. 339 */ 340 int 341 apecs_bus_dmamap_load_mbuf_direct(t, map, m, flags) 342 bus_dma_tag_t t; 343 bus_dmamap_t map; 344 struct mbuf *m; 345 int flags; 346 { 347 348 return (_bus_dmamap_load_mbuf_direct_common(t, map, m, 349 flags, APECS_DIRECT_MAPPED_BASE)); 350 } 351 352 /* 353 * Load an APECS SGMAP-mapped DMA map with an mbuf chain. 354 */ 355 int 356 apecs_bus_dmamap_load_mbuf_sgmap(t, map, m, flags) 357 bus_dma_tag_t t; 358 bus_dmamap_t map; 359 struct mbuf *m; 360 int flags; 361 { 362 struct apecs_config *acp = t->_cookie; 363 int error; 364 365 error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, &acp->ac_sgmap); 366 if (error == 0) 367 APECS_TLB_INVALIDATE(); 368 369 return (error); 370 } 371 372 /* 373 * Load an APECS direct-mapped DMA map with a uio. 374 */ 375 int 376 apecs_bus_dmamap_load_uio_direct(t, map, uio, flags) 377 bus_dma_tag_t t; 378 bus_dmamap_t map; 379 struct uio *uio; 380 int flags; 381 { 382 383 return (_bus_dmamap_load_uio_direct_common(t, map, uio, 384 flags, APECS_DIRECT_MAPPED_BASE)); 385 } 386 387 /* 388 * Load an APECS SGMAP-mapped DMA map with a uio. 389 */ 390 int 391 apecs_bus_dmamap_load_uio_sgmap(t, map, uio, flags) 392 bus_dma_tag_t t; 393 bus_dmamap_t map; 394 struct uio *uio; 395 int flags; 396 { 397 struct apecs_config *acp = t->_cookie; 398 int error; 399 400 error = pci_sgmap_pte64_load_uio(t, map, uio, flags, &acp->ac_sgmap); 401 if (error == 0) 402 APECS_TLB_INVALIDATE(); 403 404 return (error); 405 } 406 407 /* 408 * Load an APECS direct-mapped DMA map with raw memory. 409 */ 410 int 411 apecs_bus_dmamap_load_raw_direct(t, map, segs, nsegs, size, flags) 412 bus_dma_tag_t t; 413 bus_dmamap_t map; 414 bus_dma_segment_t *segs; 415 int nsegs; 416 bus_size_t size; 417 int flags; 418 { 419 420 return (_bus_dmamap_load_raw_direct_common(t, map, segs, nsegs, 421 size, flags, APECS_DIRECT_MAPPED_BASE)); 422 } 423 424 /* 425 * Load an APECS SGMAP-mapped DMA map with raw memory. 426 */ 427 int 428 apecs_bus_dmamap_load_raw_sgmap(t, map, segs, nsegs, size, flags) 429 bus_dma_tag_t t; 430 bus_dmamap_t map; 431 bus_dma_segment_t *segs; 432 int nsegs; 433 bus_size_t size; 434 int flags; 435 { 436 struct apecs_config *acp = t->_cookie; 437 int error; 438 439 error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags, 440 &acp->ac_sgmap); 441 if (error == 0) 442 APECS_TLB_INVALIDATE(); 443 444 return (error); 445 } 446 447 /* 448 * Unload an APECS DMA map. 449 */ 450 void 451 apecs_bus_dmamap_unload_sgmap(t, map) 452 bus_dma_tag_t t; 453 bus_dmamap_t map; 454 { 455 struct apecs_config *acp = t->_cookie; 456 457 /* 458 * Invalidate any SGMAP page table entries used by this 459 * mapping. 460 */ 461 pci_sgmap_pte64_unload(t, map, &acp->ac_sgmap); 462 APECS_TLB_INVALIDATE(); 463 464 /* 465 * Do the generic bits of the unload. 466 */ 467 _bus_dmamap_unload(t, map); 468 } 469