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
This commit is contained in:
parent
1b3fc371b7
commit
9708c3a2b8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345811
@ -665,9 +665,9 @@ dmar_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map1,
|
||||
{
|
||||
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_dmamap_t map1,
|
||||
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_dmamap_t map1, void *buf,
|
||||
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,42 +726,34 @@ dmar_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map1, void *buf,
|
||||
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,
|
||||
flags, segs, segp);
|
||||
|
Loading…
Reference in New Issue
Block a user