Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Apr 2019 18:50:49 +0000 (UTC)
From:      Tycho Nightingale <tychon@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r345811 - head/sys/x86/iommu
Message-ID:  <201904021850.x32Iondm041953@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tychon
Date: Tue Apr  2 18:50:49 2019
New Revision: 345811
URL: https://svnweb.freebsd.org/changeset/base/345811

Log:
  DMAR driver assumes all physical addresses are backed by a fully
  initialized struct vm_page.
  
  Reviewed by:	kib
  Sponsored by:	Dell EMC Isilon
  Differential Revision:	https://reviews.freebsd.org/D19753

Modified:
  head/sys/x86/iommu/busdma_dmar.c

Modified: head/sys/x86/iommu/busdma_dmar.c
==============================================================================
--- head/sys/x86/iommu/busdma_dmar.c	Tue Apr  2 18:50:33 2019	(r345810)
+++ head/sys/x86/iommu/busdma_dmar.c	Tue Apr  2 18:50:49 2019	(r345811)
@@ -665,9 +665,9 @@ dmar_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmam
 {
 	struct bus_dma_tag_dmar *tag;
 	struct bus_dmamap_dmar *map;
-	vm_page_t *ma;
-	vm_paddr_t pstart, pend;
-	int error, i, ma_cnt, offset;
+	vm_page_t *ma, fma;
+	vm_paddr_t pstart, pend, paddr;
+	int error, i, ma_cnt, mflags, offset;
 
 	tag = (struct bus_dma_tag_dmar *)dmat;
 	map = (struct bus_dmamap_dmar *)map1;
@@ -675,14 +675,36 @@ dmar_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmam
 	pend = round_page(buf + buflen);
 	offset = buf & PAGE_MASK;
 	ma_cnt = OFF_TO_IDX(pend - pstart);
-	ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, map->cansleep ?
-	    M_WAITOK : M_NOWAIT);
+	mflags = map->cansleep ? M_WAITOK : M_NOWAIT;
+	ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, mflags);
 	if (ma == NULL)
 		return (ENOMEM);
-	for (i = 0; i < ma_cnt; i++)
-		ma[i] = PHYS_TO_VM_PAGE(pstart + i * PAGE_SIZE);
+	fma = NULL;
+	for (i = 0; i < ma_cnt; i++) {
+		paddr = pstart + i * PAGE_SIZE;
+		ma[i] = PHYS_TO_VM_PAGE(paddr);
+		if (ma[i] == NULL || VM_PAGE_TO_PHYS(ma[i]) != paddr) {
+			/*
+			 * If PHYS_TO_VM_PAGE() returned NULL or the
+			 * vm_page was not initialized we'll use a
+			 * fake page.
+			 */
+			if (fma == NULL) {
+				fma = malloc(sizeof(struct vm_page) * ma_cnt,
+				    M_DEVBUF, mflags);
+				if (fma == NULL) {
+					free(ma, M_DEVBUF);
+					return (ENOMEM);
+				}
+			}
+			vm_page_initfake(&fma[i], pstart + i * PAGE_SIZE,
+			    VM_MEMATTR_DEFAULT);
+			ma[i] = &fma[i];
+		}
+	}
 	error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen,
 	    flags, segs, segp);
+	free(fma, M_DEVBUF);
 	free(ma, M_DEVBUF);
 	return (error);
 }
@@ -696,7 +718,7 @@ dmar_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dm
 	struct bus_dmamap_dmar *map;
 	vm_page_t *ma, fma;
 	vm_paddr_t pstart, pend, paddr;
-	int error, i, ma_cnt, offset;
+	int error, i, ma_cnt, mflags, offset;
 
 	tag = (struct bus_dma_tag_dmar *)dmat;
 	map = (struct bus_dmamap_dmar *)map1;
@@ -704,41 +726,33 @@ dmar_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dm
 	pend = round_page((vm_offset_t)buf + buflen);
 	offset = (vm_offset_t)buf & PAGE_MASK;
 	ma_cnt = OFF_TO_IDX(pend - pstart);
-	ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, map->cansleep ?
-	    M_WAITOK : M_NOWAIT);
+	mflags = map->cansleep ? M_WAITOK : M_NOWAIT;
+	ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, mflags);
 	if (ma == NULL)
 		return (ENOMEM);
-	if (dumping) {
-		/*
-		 * If dumping, do not attempt to call
-		 * PHYS_TO_VM_PAGE() at all.  It may return non-NULL
-		 * but the vm_page returned might be not initialized,
-		 * e.g. for the kernel itself.
-		 */
-		KASSERT(pmap == kernel_pmap, ("non-kernel address write"));
-		fma = malloc(sizeof(struct vm_page) * ma_cnt, M_DEVBUF,
-		    M_ZERO | (map->cansleep ? M_WAITOK : M_NOWAIT));
-		if (fma == NULL) {
-			free(ma, M_DEVBUF);
-			return (ENOMEM);
-		}
-		for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) {
+	fma = NULL;
+	for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) {
+		if (pmap == kernel_pmap)
 			paddr = pmap_kextract(pstart);
+		else
+			paddr = pmap_extract(pmap, pstart);
+		ma[i] = PHYS_TO_VM_PAGE(paddr);
+		if (ma[i] == NULL || VM_PAGE_TO_PHYS(ma[i]) != paddr) {
+			/*
+			 * If PHYS_TO_VM_PAGE() returned NULL or the
+			 * vm_page was not initialized we'll use a
+			 * fake page.
+			 */
+			if (fma == NULL) {
+				fma = malloc(sizeof(struct vm_page) * ma_cnt,
+				    M_DEVBUF, mflags);
+				if (fma == NULL) {
+					free(ma, M_DEVBUF);
+					return (ENOMEM);
+				}
+			}
 			vm_page_initfake(&fma[i], paddr, VM_MEMATTR_DEFAULT);
 			ma[i] = &fma[i];
-		}
-	} else {
-		fma = NULL;
-		for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) {
-			if (pmap == kernel_pmap)
-				paddr = pmap_kextract(pstart);
-			else
-				paddr = pmap_extract(pmap, pstart);
-			ma[i] = PHYS_TO_VM_PAGE(paddr);
-			KASSERT(VM_PAGE_TO_PHYS(ma[i]) == paddr,
-			    ("PHYS_TO_VM_PAGE failed %jx %jx m %p",
-			    (uintmax_t)paddr, (uintmax_t)VM_PAGE_TO_PHYS(ma[i]),
-			    ma[i]));
 		}
 	}
 	error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904021850.x32Iondm041953>