Annotation of sys/arch/alpha/pci/cia_dma.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cia_dma.c,v 1.8 2007/04/18 16:56:34 martin Exp $ */
! 2: /* $NetBSD: cia_dma.c,v 1.16 2000/06/29 08:58:46 mrg Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 10: * NASA Ames Research Center.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40:
! 41: /*
! 42: * XXX - We should define this before including bus.h, but since other stuff
! 43: * pulls in bus.h we must do this here.
! 44: */
! 45: #define _ALPHA_BUS_DMA_PRIVATE
! 46:
! 47: #include <sys/param.h>
! 48: #include <sys/systm.h>
! 49: #include <sys/kernel.h>
! 50: #include <sys/device.h>
! 51: #include <sys/malloc.h>
! 52:
! 53: #include <uvm/uvm_extern.h>
! 54:
! 55: #include <machine/bus.h>
! 56:
! 57: #include <dev/pci/pcireg.h>
! 58: #include <dev/pci/pcivar.h>
! 59: #include <alpha/pci/ciareg.h>
! 60: #include <alpha/pci/ciavar.h>
! 61:
! 62: bus_dma_tag_t cia_dma_get_tag(bus_dma_tag_t, alpha_bus_t);
! 63:
! 64: int cia_bus_dmamap_create_direct(bus_dma_tag_t, bus_size_t, int,
! 65: bus_size_t, bus_size_t, int, bus_dmamap_t *);
! 66:
! 67: int cia_bus_dmamap_load_sgmap(bus_dma_tag_t, bus_dmamap_t, void *,
! 68: bus_size_t, struct proc *, int);
! 69:
! 70: int cia_bus_dmamap_load_mbuf_sgmap(bus_dma_tag_t, bus_dmamap_t,
! 71: struct mbuf *, int);
! 72:
! 73: int cia_bus_dmamap_load_uio_sgmap(bus_dma_tag_t, bus_dmamap_t,
! 74: struct uio *, int);
! 75:
! 76: int cia_bus_dmamap_load_raw_sgmap(bus_dma_tag_t, bus_dmamap_t,
! 77: bus_dma_segment_t *, int, bus_size_t, int);
! 78:
! 79: void cia_bus_dmamap_unload_sgmap(bus_dma_tag_t, bus_dmamap_t);
! 80:
! 81: /*
! 82: * Direct-mapped window: 1G at 1G
! 83: */
! 84: #define CIA_DIRECT_MAPPED_BASE (1*1024*1024*1024)
! 85: #define CIA_DIRECT_MAPPED_SIZE (1*1024*1024*1024)
! 86:
! 87: /*
! 88: * SGMAP window: 8M at 8M
! 89: */
! 90: #define CIA_SGMAP_MAPPED_BASE (8*1024*1024)
! 91: #define CIA_SGMAP_MAPPED_SIZE (8*1024*1024)
! 92:
! 93: /* ALCOR/ALGOR2/PYXIS have a 256-byte out-bound DMA prefetch threshold. */
! 94: #define CIA_SGMAP_PFTHRESH 256
! 95:
! 96: void cia_tlb_invalidate(void);
! 97: void cia_broken_pyxis_tlb_invalidate(void);
! 98:
! 99: void (*cia_tlb_invalidate_fn)(void);
! 100:
! 101: #define CIA_TLB_INVALIDATE() (*cia_tlb_invalidate_fn)()
! 102:
! 103: struct alpha_sgmap cia_pyxis_bug_sgmap;
! 104: #define CIA_PYXIS_BUG_BASE (128*1024*1024)
! 105: #define CIA_PYXIS_BUG_SIZE (2*1024*1024)
! 106:
! 107: void
! 108: cia_dma_init(ccp)
! 109: struct cia_config *ccp;
! 110: {
! 111: bus_addr_t tbase;
! 112: bus_dma_tag_t t;
! 113:
! 114: /*
! 115: * Initialize the DMA tag used for direct-mapped DMA.
! 116: */
! 117: t = &ccp->cc_dmat_direct;
! 118: t->_cookie = ccp;
! 119: t->_wbase = CIA_DIRECT_MAPPED_BASE;
! 120: t->_wsize = CIA_DIRECT_MAPPED_SIZE;
! 121: t->_next_window = &ccp->cc_dmat_sgmap;
! 122: t->_boundary = 0;
! 123: t->_sgmap = NULL;
! 124: t->_get_tag = cia_dma_get_tag;
! 125: t->_dmamap_create = cia_bus_dmamap_create_direct;
! 126: t->_dmamap_destroy = _bus_dmamap_destroy;
! 127: t->_dmamap_load = _bus_dmamap_load_direct;
! 128: t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
! 129: t->_dmamap_load_uio = _bus_dmamap_load_uio_direct;
! 130: t->_dmamap_load_raw = _bus_dmamap_load_raw_direct;
! 131: t->_dmamap_unload = _bus_dmamap_unload;
! 132: t->_dmamap_sync = _bus_dmamap_sync;
! 133:
! 134: t->_dmamem_alloc = _bus_dmamem_alloc;
! 135: t->_dmamem_free = _bus_dmamem_free;
! 136: t->_dmamem_map = _bus_dmamem_map;
! 137: t->_dmamem_unmap = _bus_dmamem_unmap;
! 138: t->_dmamem_mmap = _bus_dmamem_mmap;
! 139:
! 140: /*
! 141: * Initialize the DMA tag used for sgmap-mapped DMA.
! 142: */
! 143: t = &ccp->cc_dmat_sgmap;
! 144: t->_cookie = ccp;
! 145: t->_wbase = CIA_SGMAP_MAPPED_BASE;
! 146: t->_wsize = CIA_SGMAP_MAPPED_SIZE;
! 147: t->_next_window = NULL;
! 148: t->_boundary = 0;
! 149: t->_sgmap = &ccp->cc_sgmap;
! 150: t->_pfthresh = CIA_SGMAP_PFTHRESH;
! 151: t->_get_tag = cia_dma_get_tag;
! 152: t->_dmamap_create = alpha_sgmap_dmamap_create;
! 153: t->_dmamap_destroy = alpha_sgmap_dmamap_destroy;
! 154: t->_dmamap_load = cia_bus_dmamap_load_sgmap;
! 155: t->_dmamap_load_mbuf = cia_bus_dmamap_load_mbuf_sgmap;
! 156: t->_dmamap_load_uio = cia_bus_dmamap_load_uio_sgmap;
! 157: t->_dmamap_load_raw = cia_bus_dmamap_load_raw_sgmap;
! 158: t->_dmamap_unload = cia_bus_dmamap_unload_sgmap;
! 159: t->_dmamap_sync = _bus_dmamap_sync;
! 160:
! 161: t->_dmamem_alloc = _bus_dmamem_alloc;
! 162: t->_dmamem_free = _bus_dmamem_free;
! 163: t->_dmamem_map = _bus_dmamem_map;
! 164: t->_dmamem_unmap = _bus_dmamem_unmap;
! 165: t->_dmamem_mmap = _bus_dmamem_mmap;
! 166:
! 167: /*
! 168: * The firmware has set up window 1 as a 1G direct-mapped DMA
! 169: * window beginning at 1G. We leave it alone. Leave window
! 170: * 0 alone until we reconfigure it for SGMAP-mapped DMA.
! 171: * Windows 2 and 3 are already disabled.
! 172: */
! 173:
! 174: /*
! 175: * Initialize the SGMAP. Must align page table to 32k
! 176: * (hardware bug?).
! 177: */
! 178: alpha_sgmap_init(t, &ccp->cc_sgmap, "cia_sgmap",
! 179: CIA_SGMAP_MAPPED_BASE, 0, CIA_SGMAP_MAPPED_SIZE,
! 180: sizeof(u_int64_t), NULL, (32*1024));
! 181:
! 182: /*
! 183: * Set up window 0 as an 8MB SGMAP-mapped window
! 184: * starting at 8MB.
! 185: */
! 186: REGVAL(CIA_PCI_W0BASE) = CIA_SGMAP_MAPPED_BASE |
! 187: CIA_PCI_WnBASE_SG_EN | CIA_PCI_WnBASE_W_EN;
! 188: alpha_mb();
! 189:
! 190: REGVAL(CIA_PCI_W0MASK) = CIA_PCI_WnMASK_8M;
! 191: alpha_mb();
! 192:
! 193: tbase = ccp->cc_sgmap.aps_ptpa >> CIA_PCI_TnBASE_SHIFT;
! 194: if ((tbase & CIA_PCI_TnBASE_MASK) != tbase)
! 195: panic("cia_dma_init: bad page table address");
! 196: REGVAL(CIA_PCI_T0BASE) = tbase;
! 197: alpha_mb();
! 198:
! 199: /*
! 200: * Pass 1 and 2 (i.e. revision <= 1) of the Pyxis have a
! 201: * broken scatter/gather TLB; it cannot be invalidated. To
! 202: * work around this problem, we configure window 2 as an SG
! 203: * 2M window at 128M, which we use in DMA loopback mode to
! 204: * read a spill page. This works by causing TLB misses,
! 205: * causing the old entries to be purged to make room for
! 206: * the new entries coming in for the spill page.
! 207: */
! 208: if ((ccp->cc_flags & CCF_ISPYXIS) != 0 && ccp->cc_rev <= 1) {
! 209: u_int64_t *page_table;
! 210: int i;
! 211:
! 212: cia_tlb_invalidate_fn =
! 213: cia_broken_pyxis_tlb_invalidate;
! 214:
! 215: alpha_sgmap_init(t, &cia_pyxis_bug_sgmap,
! 216: "pyxis_bug_sgmap", CIA_PYXIS_BUG_BASE, 0,
! 217: CIA_PYXIS_BUG_SIZE, sizeof(u_int64_t), NULL,
! 218: (32*1024));
! 219:
! 220: REGVAL(CIA_PCI_W2BASE) = CIA_PYXIS_BUG_BASE |
! 221: CIA_PCI_WnBASE_SG_EN | CIA_PCI_WnBASE_W_EN;
! 222: alpha_mb();
! 223:
! 224: REGVAL(CIA_PCI_W2MASK) = CIA_PCI_WnMASK_2M;
! 225: alpha_mb();
! 226:
! 227: tbase = cia_pyxis_bug_sgmap.aps_ptpa >>
! 228: CIA_PCI_TnBASE_SHIFT;
! 229: if ((tbase & CIA_PCI_TnBASE_MASK) != tbase)
! 230: panic("cia_dma_init: bad page table address");
! 231: REGVAL(CIA_PCI_T2BASE) = tbase;
! 232: alpha_mb();
! 233:
! 234: /*
! 235: * Initialize the page table to point at the spill
! 236: * page. Leave the last entry invalid.
! 237: */
! 238: pci_sgmap_pte64_init_spill_page_pte();
! 239: for (i = 0, page_table = cia_pyxis_bug_sgmap.aps_pt;
! 240: i < (CIA_PYXIS_BUG_SIZE / PAGE_SIZE) - 1; i++) {
! 241: page_table[i] =
! 242: pci_sgmap_pte64_prefetch_spill_page_pte;
! 243: }
! 244: alpha_mb();
! 245: } else
! 246: cia_tlb_invalidate_fn = cia_tlb_invalidate;
! 247:
! 248: CIA_TLB_INVALIDATE();
! 249:
! 250: /* XXX XXX BEGIN XXX XXX */
! 251: { /* XXX */
! 252: extern paddr_t alpha_XXX_dmamap_or; /* XXX */
! 253: alpha_XXX_dmamap_or = CIA_DIRECT_MAPPED_BASE; /* XXX */
! 254: } /* XXX */
! 255: /* XXX XXX END XXX XXX */
! 256: }
! 257:
! 258: /*
! 259: * Return the bus dma tag to be used for the specified bus type.
! 260: * INTERNAL USE ONLY!
! 261: */
! 262: bus_dma_tag_t
! 263: cia_dma_get_tag(t, bustype)
! 264: bus_dma_tag_t t;
! 265: alpha_bus_t bustype;
! 266: {
! 267: struct cia_config *ccp = t->_cookie;
! 268:
! 269: switch (bustype) {
! 270: case ALPHA_BUS_PCI:
! 271: case ALPHA_BUS_EISA:
! 272: /*
! 273: * Systems with a CIA can only support 1G
! 274: * of memory, so we use the direct-mapped window
! 275: * on busses that have 32-bit DMA.
! 276: *
! 277: * Ahem: I have a PWS 500au with 1.5G of memory, and it
! 278: * had problems doing DMA because it was not falling back
! 279: * to using SGMAPs. I've fixed that and my PWS now works with
! 280: * 1.5G. There have been other reports about failures with
! 281: * more than 1.0G of memory. Michael Hitch
! 282: */
! 283: return (&ccp->cc_dmat_direct);
! 284:
! 285: case ALPHA_BUS_ISA:
! 286: /*
! 287: * ISA doesn't have enough address bits to use
! 288: * the direct-mapped DMA window, so we must use
! 289: * SGMAPs.
! 290: */
! 291: return (&ccp->cc_dmat_sgmap);
! 292:
! 293: default:
! 294: panic("cia_dma_get_tag: shouldn't be here, really...");
! 295: }
! 296: }
! 297:
! 298: /*
! 299: * Create a CIA direct-mapped DMA map.
! 300: */
! 301: int
! 302: cia_bus_dmamap_create_direct(t, size, nsegments, maxsegsz, boundary,
! 303: flags, dmamp)
! 304: bus_dma_tag_t t;
! 305: bus_size_t size;
! 306: int nsegments;
! 307: bus_size_t maxsegsz;
! 308: bus_size_t boundary;
! 309: int flags;
! 310: bus_dmamap_t *dmamp;
! 311: {
! 312: struct cia_config *ccp = t->_cookie;
! 313: bus_dmamap_t map;
! 314: int error;
! 315:
! 316: error = _bus_dmamap_create(t, size, nsegments, maxsegsz,
! 317: boundary, flags, dmamp);
! 318: if (error)
! 319: return (error);
! 320:
! 321: map = *dmamp;
! 322:
! 323: if ((ccp->cc_flags & CCF_PYXISBUG) != 0 &&
! 324: map->_dm_segcnt > 1) {
! 325: /*
! 326: * We have a Pyxis with the DMA page crossing bug, make
! 327: * sure we don't coalesce adjacent DMA segments.
! 328: *
! 329: * NOTE: We can only do this if the max segment count
! 330: * is greater than 1. This is because many network
! 331: * drivers allocate large contiguous blocks of memory
! 332: * for control data structures, even though they won't
! 333: * do any single DMA that crosses a page boundary.
! 334: * -- thorpej@netbsd.org, 2/5/2000
! 335: */
! 336: map->_dm_flags |= DMAMAP_NO_COALESCE;
! 337: }
! 338:
! 339: return (0);
! 340: }
! 341:
! 342: /*
! 343: * Load a CIA SGMAP-mapped DMA map with a linear buffer.
! 344: */
! 345: int
! 346: cia_bus_dmamap_load_sgmap(t, map, buf, buflen, p, flags)
! 347: bus_dma_tag_t t;
! 348: bus_dmamap_t map;
! 349: void *buf;
! 350: bus_size_t buflen;
! 351: struct proc *p;
! 352: int flags;
! 353: {
! 354: int error;
! 355:
! 356: error = pci_sgmap_pte64_load(t, map, buf, buflen, p, flags,
! 357: t->_sgmap);
! 358: if (error == 0)
! 359: CIA_TLB_INVALIDATE();
! 360:
! 361: return (error);
! 362: }
! 363:
! 364: /*
! 365: * Load a CIA SGMAP-mapped DMA map with an mbuf chain.
! 366: */
! 367: int
! 368: cia_bus_dmamap_load_mbuf_sgmap(t, map, m, flags)
! 369: bus_dma_tag_t t;
! 370: bus_dmamap_t map;
! 371: struct mbuf *m;
! 372: int flags;
! 373: {
! 374: int error;
! 375:
! 376: error = pci_sgmap_pte64_load_mbuf(t, map, m, flags, t->_sgmap);
! 377: if (error == 0)
! 378: CIA_TLB_INVALIDATE();
! 379:
! 380: return (error);
! 381: }
! 382:
! 383: /*
! 384: * Load a CIA SGMAP-mapped DMA map with a uio.
! 385: */
! 386: int
! 387: cia_bus_dmamap_load_uio_sgmap(t, map, uio, flags)
! 388: bus_dma_tag_t t;
! 389: bus_dmamap_t map;
! 390: struct uio *uio;
! 391: int flags;
! 392: {
! 393: int error;
! 394:
! 395: error = pci_sgmap_pte64_load_uio(t, map, uio, flags, t->_sgmap);
! 396: if (error == 0)
! 397: CIA_TLB_INVALIDATE();
! 398:
! 399: return (error);
! 400: }
! 401:
! 402: /*
! 403: * Load a CIA SGMAP-mapped DMA map with raw memory.
! 404: */
! 405: int
! 406: cia_bus_dmamap_load_raw_sgmap(t, map, segs, nsegs, size, flags)
! 407: bus_dma_tag_t t;
! 408: bus_dmamap_t map;
! 409: bus_dma_segment_t *segs;
! 410: int nsegs;
! 411: bus_size_t size;
! 412: int flags;
! 413: {
! 414: int error;
! 415:
! 416: error = pci_sgmap_pte64_load_raw(t, map, segs, nsegs, size, flags,
! 417: t->_sgmap);
! 418: if (error == 0)
! 419: CIA_TLB_INVALIDATE();
! 420:
! 421: return (error);
! 422: }
! 423:
! 424: /*
! 425: * Unload a CIA DMA map.
! 426: */
! 427: void
! 428: cia_bus_dmamap_unload_sgmap(t, map)
! 429: bus_dma_tag_t t;
! 430: bus_dmamap_t map;
! 431: {
! 432:
! 433: /*
! 434: * Invalidate any SGMAP page table entries used by this
! 435: * mapping.
! 436: */
! 437: pci_sgmap_pte64_unload(t, map, t->_sgmap);
! 438: CIA_TLB_INVALIDATE();
! 439:
! 440: /*
! 441: * Do the generic bits of the unload.
! 442: */
! 443: _bus_dmamap_unload(t, map);
! 444: }
! 445:
! 446: /*
! 447: * Flush the CIA scatter/gather TLB.
! 448: */
! 449: void
! 450: cia_tlb_invalidate()
! 451: {
! 452:
! 453: alpha_mb();
! 454: REGVAL(CIA_PCI_TBIA) = CIA_PCI_TBIA_ALL;
! 455: alpha_mb();
! 456: }
! 457:
! 458: /*
! 459: * Flush the scatter/gather TLB on broken Pyxis chips.
! 460: */
! 461: void
! 462: cia_broken_pyxis_tlb_invalidate()
! 463: {
! 464: volatile u_int64_t dummy;
! 465: u_int32_t ctrl;
! 466: int i, s;
! 467:
! 468: s = splhigh();
! 469:
! 470: /*
! 471: * Put the Pyxis into PCI loopback mode.
! 472: */
! 473: alpha_mb();
! 474: ctrl = REGVAL(CIA_CSR_CTRL);
! 475: REGVAL(CIA_CSR_CTRL) = ctrl | CTRL_PCI_LOOP_EN;
! 476: alpha_mb();
! 477:
! 478: /*
! 479: * Now, read from PCI dense memory space at offset 128M (our
! 480: * target window base), skipping 64k on each read. This forces
! 481: * S/G TLB misses.
! 482: *
! 483: * XXX Looks like the TLB entries are `not quite LRU'. We need
! 484: * XXX to read more times than there are actual tags!
! 485: */
! 486: for (i = 0; i < CIA_TLB_NTAGS + 4; i++) {
! 487: dummy = *((volatile u_int64_t *)
! 488: ALPHA_PHYS_TO_K0SEG(CIA_PCI_DENSE + CIA_PYXIS_BUG_BASE +
! 489: (i * 65536)));
! 490: }
! 491:
! 492: /*
! 493: * Restore normal PCI operation.
! 494: */
! 495: alpha_mb();
! 496: REGVAL(CIA_CSR_CTRL) = ctrl;
! 497: alpha_mb();
! 498:
! 499: splx(s);
! 500: }
CVSweb