svn commit: r345811 - head/sys/x86/iommu
Tycho Nightingale
tychon at FreeBSD.org
Tue Apr 2 18:50:53 UTC 2019
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,
More information about the svn-src-all
mailing list