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,


_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to