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
@ -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_dma_tag_dmar *tag;
|
||||||
struct bus_dmamap_dmar *map;
|
struct bus_dmamap_dmar *map;
|
||||||
vm_page_t *ma;
|
vm_page_t *ma, fma;
|
||||||
vm_paddr_t pstart, pend;
|
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;
|
tag = (struct bus_dma_tag_dmar *)dmat;
|
||||||
map = (struct bus_dmamap_dmar *)map1;
|
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);
|
pend = round_page(buf + buflen);
|
||||||
offset = buf & PAGE_MASK;
|
offset = buf & PAGE_MASK;
|
||||||
ma_cnt = OFF_TO_IDX(pend - pstart);
|
ma_cnt = OFF_TO_IDX(pend - pstart);
|
||||||
ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, map->cansleep ?
|
mflags = map->cansleep ? M_WAITOK : M_NOWAIT;
|
||||||
M_WAITOK : M_NOWAIT);
|
ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, mflags);
|
||||||
if (ma == NULL)
|
if (ma == NULL)
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
for (i = 0; i < ma_cnt; i++)
|
fma = NULL;
|
||||||
ma[i] = PHYS_TO_VM_PAGE(pstart + i * PAGE_SIZE);
|
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,
|
error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen,
|
||||||
flags, segs, segp);
|
flags, segs, segp);
|
||||||
|
free(fma, M_DEVBUF);
|
||||||
free(ma, M_DEVBUF);
|
free(ma, M_DEVBUF);
|
||||||
return (error);
|
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;
|
struct bus_dmamap_dmar *map;
|
||||||
vm_page_t *ma, fma;
|
vm_page_t *ma, fma;
|
||||||
vm_paddr_t pstart, pend, paddr;
|
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;
|
tag = (struct bus_dma_tag_dmar *)dmat;
|
||||||
map = (struct bus_dmamap_dmar *)map1;
|
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);
|
pend = round_page((vm_offset_t)buf + buflen);
|
||||||
offset = (vm_offset_t)buf & PAGE_MASK;
|
offset = (vm_offset_t)buf & PAGE_MASK;
|
||||||
ma_cnt = OFF_TO_IDX(pend - pstart);
|
ma_cnt = OFF_TO_IDX(pend - pstart);
|
||||||
ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, map->cansleep ?
|
mflags = map->cansleep ? M_WAITOK : M_NOWAIT;
|
||||||
M_WAITOK : M_NOWAIT);
|
ma = malloc(sizeof(vm_page_t) * ma_cnt, M_DEVBUF, mflags);
|
||||||
if (ma == NULL)
|
if (ma == NULL)
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
if (dumping) {
|
fma = NULL;
|
||||||
/*
|
for (i = 0; i < ma_cnt; i++, pstart += PAGE_SIZE) {
|
||||||
* If dumping, do not attempt to call
|
if (pmap == kernel_pmap)
|
||||||
* 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) {
|
|
||||||
paddr = pmap_kextract(pstart);
|
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);
|
vm_page_initfake(&fma[i], paddr, VM_MEMATTR_DEFAULT);
|
||||||
ma[i] = &fma[i];
|
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,
|
error = dmar_bus_dmamap_load_something(tag, map, ma, offset, buflen,
|
||||||
flags, segs, segp);
|
flags, segs, segp);
|
||||||
|
Loading…
Reference in New Issue
Block a user