Home | History | Annotate | Line # | Download | only in integrator
int_bus_dma.c revision 1.9
      1 /*	$NetBSD: int_bus_dma.c,v 1.9 2002/07/28 17:54:06 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996, 1997, 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  * 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  * The integrator board has memory steering hardware that means that
     41  * the normal physical addresses used by the processor cannot be used
     42  * for DMA.  Instead we have to use the "core module alias mapping
     43  * addresses".  We don't use these for normal processor accesses since
     44  * they are much slower than the direct addresses when accessing
     45  * memory on the local board.
     46  */
     47 
     48 #include <sys/param.h>
     49 #include <sys/systm.h>
     50 #include <sys/kernel.h>
     51 #include <sys/map.h>
     52 #include <sys/proc.h>
     53 #include <sys/buf.h>
     54 #include <sys/reboot.h>
     55 #include <sys/conf.h>
     56 #include <sys/file.h>
     57 #include <sys/malloc.h>
     58 #include <sys/mbuf.h>
     59 #include <sys/vnode.h>
     60 #include <sys/device.h>
     61 
     62 #include <uvm/uvm_extern.h>
     63 
     64 #define _ARM32_BUS_DMA_PRIVATE
     65 #include <evbarm/integrator/int_bus_dma.h>
     66 
     67 #include <machine/cpu.h>
     68 #include <arm/cpufunc.h>
     69 
     70 static int	integrator_bus_dmamap_load_buffer __P((bus_dma_tag_t,
     71 		    bus_dmamap_t, void *, bus_size_t, struct proc *, int,
     72 		    vm_offset_t *, int *, int));
     73 static int	integrator_bus_dma_inrange __P((bus_dma_segment_t *, int,
     74 		    bus_addr_t));
     75 
     76 /*
     77  * Common function for loading a DMA map with a linear buffer.  May
     78  * be called by bus-specific DMA map load functions.
     79  */
     80 int
     81 integrator_bus_dmamap_load(t, map, buf, buflen, p, flags)
     82 	bus_dma_tag_t t;
     83 	bus_dmamap_t map;
     84 	void *buf;
     85 	bus_size_t buflen;
     86 	struct proc *p;
     87 	int flags;
     88 {
     89 	vm_offset_t lastaddr;
     90 	int seg, error;
     91 
     92 #ifdef DEBUG_DMA
     93 	printf("dmamap_load: t=%p map=%p buf=%p len=%lx p=%p f=%d\n",
     94 	    t, map, buf, buflen, p, flags);
     95 #endif	/* DEBUG_DMA */
     96 
     97 	/*
     98 	 * Make sure that on error condition we return "no valid mappings".
     99 	 */
    100 	map->dm_mapsize = 0;
    101 	map->dm_nsegs = 0;
    102 
    103 	if (buflen > map->_dm_size)
    104 		return (EINVAL);
    105 
    106 	seg = 0;
    107 	error = integrator_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
    108 	    &lastaddr, &seg, 1);
    109 	if (error == 0) {
    110 		map->dm_mapsize = buflen;
    111 		map->dm_nsegs = seg + 1;
    112 		map->_dm_origbuf = buf;
    113 		map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
    114 		map->_dm_proc = p;
    115 	}
    116 #ifdef DEBUG_DMA
    117 	printf("dmamap_load: error=%d\n", error);
    118 #endif	/* DEBUG_DMA */
    119 	return (error);
    120 }
    121 
    122 /*
    123  * Like _bus_dmamap_load(), but for mbufs.
    124  */
    125 int
    126 integrator_bus_dmamap_load_mbuf(t, map, m0, flags)
    127 	bus_dma_tag_t t;
    128 	bus_dmamap_t map;
    129 	struct mbuf *m0;
    130 	int flags;
    131 {
    132 	vm_offset_t lastaddr;
    133 	int seg, error, first;
    134 	struct mbuf *m;
    135 
    136 #ifdef DEBUG_DMA
    137 	printf("dmamap_load_mbuf: t=%p map=%p m0=%p f=%d\n",
    138 	    t, map, m0, flags);
    139 #endif	/* DEBUG_DMA */
    140 
    141 	/*
    142 	 * Make sure that on error condition we return "no valid mappings."
    143 	 */
    144 	map->dm_mapsize = 0;
    145 	map->dm_nsegs = 0;
    146 
    147 #ifdef DIAGNOSTIC
    148 	if ((m0->m_flags & M_PKTHDR) == 0)
    149 		panic("integrator_bus_dmamap_load_mbuf: no packet header");
    150 #endif	/* DIAGNOSTIC */
    151 
    152 	if (m0->m_pkthdr.len > map->_dm_size)
    153 		return (EINVAL);
    154 
    155 	first = 1;
    156 	seg = 0;
    157 	error = 0;
    158 	for (m = m0; m != NULL && error == 0; m = m->m_next) {
    159 		error = integrator_bus_dmamap_load_buffer(t, map, m->m_data,
    160 		    m->m_len, NULL, flags, &lastaddr, &seg, first);
    161 		first = 0;
    162 	}
    163 	if (error == 0) {
    164 		map->dm_mapsize = m0->m_pkthdr.len;
    165 		map->dm_nsegs = seg + 1;
    166 		map->_dm_origbuf = m0;
    167 		map->_dm_buftype = ARM32_BUFTYPE_MBUF;
    168 		map->_dm_proc = NULL;	/* always kernel */
    169 	}
    170 #ifdef DEBUG_DMA
    171 	printf("dmamap_load_mbuf: error=%d\n", error);
    172 #endif	/* DEBUG_DMA */
    173 	return (error);
    174 }
    175 
    176 /*
    177  * Like _bus_dmamap_load(), but for uios.
    178  */
    179 int
    180 integrator_bus_dmamap_load_uio(t, map, uio, flags)
    181 	bus_dma_tag_t t;
    182 	bus_dmamap_t map;
    183 	struct uio *uio;
    184 	int flags;
    185 {
    186 	vm_offset_t lastaddr;
    187 	int seg, i, error, first;
    188 	bus_size_t minlen, resid;
    189 	struct proc *p = NULL;
    190 	struct iovec *iov;
    191 	caddr_t addr;
    192 
    193 	/*
    194 	 * Make sure that on error condition we return "no valid mappings."
    195 	 */
    196 	map->dm_mapsize = 0;
    197 	map->dm_nsegs = 0;
    198 
    199 	resid = uio->uio_resid;
    200 	iov = uio->uio_iov;
    201 
    202 	if (uio->uio_segflg == UIO_USERSPACE) {
    203 		p = uio->uio_procp;
    204 #ifdef DIAGNOSTIC
    205 		if (p == NULL)
    206 			panic("integrator_bus_dmamap_load_uio: USERSPACE but no proc");
    207 #endif
    208 	}
    209 
    210 	first = 1;
    211 	seg = 0;
    212 	error = 0;
    213 	for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
    214 		/*
    215 		 * Now at the first iovec to load.  Load each iovec
    216 		 * until we have exhausted the residual count.
    217 		 */
    218 		minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
    219 		addr = (caddr_t)iov[i].iov_base;
    220 
    221 		error = integrator_bus_dmamap_load_buffer(t, map, addr, minlen,
    222 		    p, flags, &lastaddr, &seg, first);
    223 		first = 0;
    224 
    225 		resid -= minlen;
    226 	}
    227 	if (error == 0) {
    228 		map->dm_mapsize = uio->uio_resid;
    229 		map->dm_nsegs = seg + 1;
    230 		map->_dm_origbuf = uio;
    231 		map->_dm_buftype = ARM32_BUFTYPE_UIO;
    232 		map->_dm_proc = p;
    233 	}
    234 	return (error);
    235 }
    236 
    237 /*
    238  * Common function for DMA-safe memory allocation.  May be called
    239  * by bus-specific DMA memory allocation functions.
    240  */
    241 
    242 extern vm_offset_t physical_start;
    243 extern vm_offset_t physical_freestart;
    244 extern vm_offset_t physical_freeend;
    245 extern vm_offset_t physical_end;
    246 
    247 int
    248 integrator_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
    249 	bus_dma_tag_t t;
    250 	bus_size_t size, alignment, boundary;
    251 	bus_dma_segment_t *segs;
    252 	int nsegs;
    253 	int *rsegs;
    254 	int flags;
    255 {
    256 	int error;
    257 #ifdef DEBUG_DMA
    258 	printf("dmamem_alloc t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x\n",
    259 	    t, size, alignment, boundary, segs, nsegs, rsegs, flags);
    260 #endif	/* DEBUG_DMA */
    261 	error =  (integrator_bus_dmamem_alloc_range(t, size, alignment, boundary,
    262 	    segs, nsegs, rsegs, flags, trunc_page(physical_start), trunc_page(physical_end)));
    263 #ifdef DEBUG_DMA
    264 	printf("dmamem_alloc: =%d\n", error);
    265 #endif	/* DEBUG_DMA */
    266 	return(error);
    267 }
    268 
    269 /*
    270  * Common function for freeing DMA-safe memory.  May be called by
    271  * bus-specific DMA memory free functions.
    272  */
    273 void
    274 integrator_bus_dmamem_free(t, segs, nsegs)
    275 	bus_dma_tag_t t;
    276 	bus_dma_segment_t *segs;
    277 	int nsegs;
    278 {
    279 	struct vm_page *m;
    280 	bus_addr_t addr;
    281 	struct pglist mlist;
    282 	int curseg;
    283 
    284 #ifdef DEBUG_DMA
    285 	printf("dmamem_free: t=%p segs=%p nsegs=%x\n", t, segs, nsegs);
    286 #endif	/* DEBUG_DMA */
    287 
    288 	/*
    289 	 * Build a list of pages to free back to the VM system.
    290 	 */
    291 	TAILQ_INIT(&mlist);
    292 	for (curseg = 0; curseg < nsegs; curseg++) {
    293 		for (addr = segs[curseg].ds_addr;
    294 		    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
    295 		    addr += PAGE_SIZE) {
    296 			m = PHYS_TO_VM_PAGE(CM_ALIAS_TO_LOCAL(addr));
    297 			TAILQ_INSERT_TAIL(&mlist, m, pageq);
    298 		}
    299 	}
    300 	uvm_pglistfree(&mlist);
    301 }
    302 
    303 /*
    304  * Common function for mapping DMA-safe memory.  May be called by
    305  * bus-specific DMA memory map functions.
    306  */
    307 int
    308 integrator_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
    309 	bus_dma_tag_t t;
    310 	bus_dma_segment_t *segs;
    311 	int nsegs;
    312 	size_t size;
    313 	caddr_t *kvap;
    314 	int flags;
    315 {
    316 	vm_offset_t va;
    317 	bus_addr_t addr;
    318 	int curseg;
    319 	pt_entry_t *ptep/*, pte*/;
    320 
    321 #ifdef DEBUG_DMA
    322 	printf("dmamem_map: t=%p segs=%p nsegs=%x size=%lx flags=%x\n", t,
    323 	    segs, nsegs, (unsigned long)size, flags);
    324 #endif	/* DEBUG_DMA */
    325 
    326 	size = round_page(size);
    327 	va = uvm_km_valloc(kernel_map, size);
    328 
    329 	if (va == 0)
    330 		return (ENOMEM);
    331 
    332 	*kvap = (caddr_t)va;
    333 
    334 	for (curseg = 0; curseg < nsegs; curseg++) {
    335 		for (addr = segs[curseg].ds_addr;
    336 		    addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
    337 		    addr += NBPG, va += NBPG, size -= NBPG) {
    338 #ifdef DEBUG_DMA
    339 			printf("wiring p%lx to v%lx", CM_ALIAS_TO_LOCAL(addr),
    340 			    va);
    341 #endif	/* DEBUG_DMA */
    342 			if (size == 0)
    343 				panic("integrator_bus_dmamem_map: size botch");
    344 			pmap_enter(pmap_kernel(), va, CM_ALIAS_TO_LOCAL(addr),
    345 			    VM_PROT_READ | VM_PROT_WRITE,
    346 			    VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
    347 			/*
    348 			 * If the memory must remain coherent with the
    349 			 * cache then we must make the memory uncacheable
    350 			 * in order to maintain virtual cache coherency.
    351 			 * We must also guarentee the cache does not already
    352 			 * contain the virtal addresses we are making
    353 			 * uncacheable.
    354 			 */
    355 			if (flags & BUS_DMA_COHERENT) {
    356 				cpu_dcache_wbinv_range(va, NBPG);
    357 				cpu_drain_writebuf();
    358 				ptep = vtopte(va);
    359 				*ptep &= ~(L2_C | L2_B);
    360 				tlb_flush();
    361 			}
    362 #ifdef DEBUG_DMA
    363 			ptep = vtopte(va);
    364 			printf(" pte=v%p *pte=%x\n", ptep, *ptep);
    365 #endif	/* DEBUG_DMA */
    366 		}
    367 	}
    368 	pmap_update(pmap_kernel());
    369 #ifdef DEBUG_DMA
    370 	printf("dmamem_map: =%p\n", *kvap);
    371 #endif	/* DEBUG_DMA */
    372 	return (0);
    373 }
    374 
    375 /*
    376  * Common functin for mmap(2)'ing DMA-safe memory.  May be called by
    377  * bus-specific DMA mmap(2)'ing functions.
    378  */
    379 paddr_t
    380 integrator_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
    381 	bus_dma_tag_t t;
    382 	bus_dma_segment_t *segs;
    383 	int nsegs;
    384 	off_t off;
    385 	int prot, flags;
    386 {
    387 	int i;
    388 
    389 	for (i = 0; i < nsegs; i++) {
    390 #ifdef DIAGNOSTIC
    391 		if (off & PGOFSET)
    392 			panic("integrator_bus_dmamem_mmap: offset unaligned");
    393 		if (segs[i].ds_addr & PGOFSET)
    394 			panic("integrator_bus_dmamem_mmap: segment unaligned");
    395 		if (segs[i].ds_len & PGOFSET)
    396 			panic("integrator_bus_dmamem_mmap: segment size not multiple"
    397 			    " of page size");
    398 #endif	/* DIAGNOSTIC */
    399 		if (off >= segs[i].ds_len) {
    400 			off -= segs[i].ds_len;
    401 			continue;
    402 		}
    403 
    404 		return arm_btop((u_long)CM_ALIAS_TO_LOCAL(segs[i].ds_addr) + off);
    405 	}
    406 
    407 	/* Page not found. */
    408 	return -1;
    409 }
    410 
    411 /**********************************************************************
    412  * DMA utility functions
    413  **********************************************************************/
    414 
    415 /*
    416  * Utility function to load a linear buffer.  lastaddrp holds state
    417  * between invocations (for multiple-buffer loads).  segp contains
    418  * the starting segment on entrace, and the ending segment on exit.
    419  * first indicates if this is the first invocation of this function.
    420  */
    421 static int
    422 integrator_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp,
    423     segp, first)
    424 	bus_dma_tag_t t;
    425 	bus_dmamap_t map;
    426 	void *buf;
    427 	bus_size_t buflen;
    428 	struct proc *p;
    429 	int flags;
    430 	vm_offset_t *lastaddrp;
    431 	int *segp;
    432 	int first;
    433 {
    434 	bus_size_t sgsize;
    435 	bus_addr_t curaddr, lastaddr, baddr, bmask;
    436 	vm_offset_t vaddr = (vm_offset_t)buf;
    437 	int seg;
    438 	pmap_t pmap;
    439 
    440 #ifdef DEBUG_DMA
    441 	printf("integrator_bus_dmamem_load_buffer(buf=%p, len=%lx, flags=%d, 1st=%d)\n",
    442 	    buf, buflen, flags, first);
    443 #endif	/* DEBUG_DMA */
    444 
    445 	if (p != NULL)
    446 		pmap = p->p_vmspace->vm_map.pmap;
    447 	else
    448 		pmap = pmap_kernel();
    449 
    450 	lastaddr = *lastaddrp;
    451 	bmask  = ~(map->_dm_boundary - 1);
    452 
    453 	for (seg = *segp; buflen > 0; ) {
    454 		/*
    455 		 * Get the physical address for this segment.
    456 		 */
    457 		(void) pmap_extract(pmap, (vaddr_t)vaddr, &curaddr);
    458 
    459 		/*
    460 		 * Make sure we're in an allowed DMA range.
    461 		 */
    462 		if (t->_ranges != NULL &&
    463 		    integrator_bus_dma_inrange(t->_ranges, t->_nranges, curaddr) == 0)
    464 			return (EINVAL);
    465 
    466 		/*
    467 		 * Compute the segment size, and adjust counts.
    468 		 */
    469 		sgsize = NBPG - ((u_long)vaddr & PGOFSET);
    470 		if (buflen < sgsize)
    471 			sgsize = buflen;
    472 
    473 		/*
    474 		 * Make sure we don't cross any boundaries.
    475 		 */
    476 		if (map->_dm_boundary > 0) {
    477 			baddr = (curaddr + map->_dm_boundary) & bmask;
    478 			if (sgsize > (baddr - curaddr))
    479 				sgsize = (baddr - curaddr);
    480 		}
    481 
    482 		/*
    483 		 * Insert chunk into a segment, coalescing with
    484 		 * previous segment if possible.
    485 		 */
    486 		if (first) {
    487 			map->dm_segs[seg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
    488 			map->dm_segs[seg].ds_len = sgsize;
    489 			first = 0;
    490 		} else {
    491 			if (curaddr == lastaddr &&
    492 			    (map->dm_segs[seg].ds_len + sgsize) <=
    493 			     map->_dm_maxsegsz &&
    494 			    (map->_dm_boundary == 0 ||
    495 			     (map->dm_segs[seg].ds_addr & bmask) ==
    496 			     (LOCAL_TO_CM_ALIAS(curaddr) & bmask)))
    497 				map->dm_segs[seg].ds_len += sgsize;
    498 			else {
    499 				if (++seg >= map->_dm_segcnt)
    500 					break;
    501 				map->dm_segs[seg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
    502 				map->dm_segs[seg].ds_len = sgsize;
    503 			}
    504 		}
    505 
    506 		lastaddr = curaddr + sgsize;
    507 		vaddr += sgsize;
    508 		buflen -= sgsize;
    509 	}
    510 
    511 	*segp = seg;
    512 	*lastaddrp = lastaddr;
    513 
    514 	/*
    515 	 * Did we fit?
    516 	 */
    517 	if (buflen != 0)
    518 		return (EFBIG);		/* XXX better return value here? */
    519 	return (0);
    520 }
    521 
    522 /*
    523  * Check to see if the specified page is in an allowed DMA range.
    524  */
    525 static int
    526 integrator_bus_dma_inrange(ranges, nranges, curaddr)
    527 	bus_dma_segment_t *ranges;
    528 	int nranges;
    529 	bus_addr_t curaddr;
    530 {
    531 	bus_dma_segment_t *ds;
    532 	int i;
    533 
    534 	for (i = 0, ds = ranges; i < nranges; i++, ds++) {
    535 		if (curaddr >= CM_ALIAS_TO_LOCAL(ds->ds_addr) &&
    536 		    round_page(curaddr) <= (CM_ALIAS_TO_LOCAL(ds->ds_addr) + ds->ds_len))
    537 			return (1);
    538 	}
    539 
    540 	return (0);
    541 }
    542 
    543 /*
    544  * Allocate physical memory from the given physical address range.
    545  * Called by DMA-safe memory allocation methods.
    546  */
    547 int
    548 integrator_bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
    549     flags, low, high)
    550 	bus_dma_tag_t t;
    551 	bus_size_t size, alignment, boundary;
    552 	bus_dma_segment_t *segs;
    553 	int nsegs;
    554 	int *rsegs;
    555 	int flags;
    556 	vm_offset_t low;
    557 	vm_offset_t high;
    558 {
    559 	vm_offset_t curaddr, lastaddr;
    560 	struct vm_page *m;
    561 	struct pglist mlist;
    562 	int curseg, error;
    563 
    564 #ifdef DEBUG_DMA
    565 	printf("alloc_range: t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x lo=%lx hi=%lx\n",
    566 	    t, size, alignment, boundary, segs, nsegs, rsegs, flags, low, high);
    567 #endif	/* DEBUG_DMA */
    568 
    569 	/* Always round the size. */
    570 	size = round_page(size);
    571 
    572 	/*
    573 	 * Allocate pages from the VM system.
    574 	 */
    575 	error = uvm_pglistalloc(size, low, high, alignment, boundary,
    576 	    &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
    577 	if (error)
    578 		return (error);
    579 
    580 	/*
    581 	 * Compute the location, size, and number of segments actually
    582 	 * returned by the VM code.
    583 	 */
    584 	m = mlist.tqh_first;
    585 	curseg = 0;
    586 	lastaddr = VM_PAGE_TO_PHYS(m);
    587 	segs[curseg].ds_addr = LOCAL_TO_CM_ALIAS(lastaddr);
    588 	segs[curseg].ds_len = PAGE_SIZE;
    589 #ifdef DEBUG_DMA
    590 		printf("alloc: page %lx\n", lastaddr);
    591 #endif	/* DEBUG_DMA */
    592 	m = m->pageq.tqe_next;
    593 
    594 	for (; m != NULL; m = m->pageq.tqe_next) {
    595 		curaddr = VM_PAGE_TO_PHYS(m);
    596 #ifdef DIAGNOSTIC
    597 		if (curaddr < low || curaddr >= high) {
    598 			printf("uvm_pglistalloc returned non-sensical"
    599 			    " address 0x%lx\n", curaddr);
    600 			panic("integrator_bus_dmamem_alloc_range");
    601 		}
    602 #endif	/* DIAGNOSTIC */
    603 #ifdef DEBUG_DMA
    604 		printf("alloc: page %lx\n", curaddr);
    605 #endif	/* DEBUG_DMA */
    606 		if (curaddr == (lastaddr + PAGE_SIZE))
    607 			segs[curseg].ds_len += PAGE_SIZE;
    608 		else {
    609 			curseg++;
    610 			segs[curseg].ds_addr = LOCAL_TO_CM_ALIAS(curaddr);
    611 			segs[curseg].ds_len = PAGE_SIZE;
    612 		}
    613 		lastaddr = curaddr;
    614 	}
    615 
    616 	*rsegs = curseg + 1;
    617 
    618 	return (0);
    619 }
    620