From 0c4c97303c7ec6caeb5dea08eb5fcdf485f70d72 Mon Sep 17 00:00:00 2001 From: visa Date: Sat, 15 Apr 2017 04:38:27 +0000 Subject: [PATCH] Sync bus_dmamap_load_raw() with amd64 for better constraint checking. Needed by xhci(4). --- sys/arch/octeon/octeon/bus_dma.c | 90 +++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/sys/arch/octeon/octeon/bus_dma.c b/sys/arch/octeon/octeon/bus_dma.c index 09d8553bf59..5c14b454350 100644 --- a/sys/arch/octeon/octeon/bus_dma.c +++ b/sys/arch/octeon/octeon/bus_dma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bus_dma.c,v 1.14 2014/11/16 12:30:58 deraadt Exp $ */ +/* $OpenBSD: bus_dma.c,v 1.15 2017/04/15 04:38:27 visa Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -256,30 +256,82 @@ int _dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) { - if (nsegs > map->_dm_segcnt || size > map->_dm_size) - return (EINVAL); + bus_addr_t paddr, baddr, bmask, lastaddr = 0; + bus_size_t plen, sgsize, mapsize; + int first = 1; + int i, seg = 0; /* - * Make sure we don't cross any boundaries. + * Make sure that on error condition we return "no valid mappings". */ - if (map->_dm_boundary) { - bus_addr_t bmask = ~(map->_dm_boundary - 1); - int i; - - if (t->_dma_mask != 0) - bmask &= t->_dma_mask; - for (i = 0; i < nsegs; i++) { - if (segs[i].ds_len > map->_dm_maxsegsz) - return (EINVAL); - if ((segs[i].ds_addr & bmask) != - ((segs[i].ds_addr + segs[i].ds_len - 1) & bmask)) - return (EINVAL); + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + if (nsegs > map->_dm_segcnt || size > map->_dm_size) + return (EINVAL); + + mapsize = size; + bmask = ~(map->_dm_boundary - 1); + + for (i = 0; i < nsegs && size > 0; i++) { + paddr = segs[i].ds_addr; + plen = MIN(segs[i].ds_len, size); + + while (plen > 0) { + /* + * Compute the segment size, and adjust counts. + */ + sgsize = PAGE_SIZE - ((u_long)paddr & PGOFSET); + if (plen < sgsize) + sgsize = plen; + + if (paddr > dma_constraint.ucr_high) + panic("Non dma-reachable buffer at " + "paddr %#lx(raw)", paddr); + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary > 0) { + baddr = (paddr + map->_dm_boundary) & bmask; + if (sgsize > (baddr - paddr)) + sgsize = (baddr - paddr); + } + + /* + * Insert chunk into a segment, coalescing with + * previous segment if possible. + */ + if (first) { + map->dm_segs[seg].ds_addr = paddr; + map->dm_segs[seg].ds_len = sgsize; + first = 0; + } else { + if (paddr == lastaddr && + (map->dm_segs[seg].ds_len + sgsize) <= + map->_dm_maxsegsz && + (map->_dm_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + (paddr & bmask))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + return (EINVAL); + map->dm_segs[seg].ds_addr = paddr; + map->dm_segs[seg].ds_len = sgsize; + } + } + + paddr += sgsize; + plen -= sgsize; + size -= sgsize; + + lastaddr = paddr; } } - bcopy(segs, map->dm_segs, nsegs * sizeof(*segs)); - map->dm_nsegs = nsegs; - map->dm_mapsize = size; + map->dm_mapsize = mapsize; + map->dm_nsegs = seg + 1; return (0); } -- 2.20.1