Some bus_dma(9) fixes for Xen:
- Attempt to gracefully recover from a failed decrease_reservation or increase_reservation, by avoiding physical memory loss. - always store a machine address in ds_addr; this avoids some mistakes where machine address would in some case be freed at physical address, or mapped as physical address.
This commit is contained in:
parent
4c2420029f
commit
aeeb0b33ca
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: bus_private.h,v 1.5 2006/02/16 20:17:15 perry Exp $ */
|
/* $NetBSD: bus_private.h,v 1.6 2006/08/28 19:58:56 bouyer Exp $ */
|
||||||
/* NetBSD: bus.h,v 1.8 2005/03/09 19:04:46 matt Exp */
|
/* NetBSD: bus.h,v 1.8 2005/03/09 19:04:46 matt Exp */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
|
@ -150,10 +150,23 @@ struct x86_bus_dma_cookie {
|
||||||
#define _BUS_PHYS_TO_BUS(pa) ((bus_addr_t)(pa))
|
#define _BUS_PHYS_TO_BUS(pa) ((bus_addr_t)(pa))
|
||||||
#endif /* !defined(_BUS_PHYS_TO_BUS) */
|
#endif /* !defined(_BUS_PHYS_TO_BUS) */
|
||||||
|
|
||||||
|
#if !defined(_BUS_BUS_TO_PHYS)
|
||||||
|
#define _BUS_BUS_TO_PHYS(ba) ((paddr_t)(ba))
|
||||||
|
#endif /* !defined(_BUS_BUS_TO_PHYS) */
|
||||||
|
|
||||||
#if !defined(_BUS_VM_PAGE_TO_BUS)
|
#if !defined(_BUS_VM_PAGE_TO_BUS)
|
||||||
#define _BUS_VM_PAGE_TO_BUS(pg) _BUS_PHYS_TO_BUS(VM_PAGE_TO_PHYS(pg))
|
#define _BUS_VM_PAGE_TO_BUS(pg) _BUS_PHYS_TO_BUS(VM_PAGE_TO_PHYS(pg))
|
||||||
#endif /* !defined(_BUS_VM_PAGE_TO_BUS) */
|
#endif /* !defined(_BUS_VM_PAGE_TO_BUS) */
|
||||||
|
|
||||||
|
#if !defined(_BUS_BUS_TO_VM_PAGE)
|
||||||
|
#define _BUS_BUS_TO_VM_PAGE(ba) PHYS_TO_VM_PAGE(ba)
|
||||||
|
#endif /* !defined(_BUS_BUS_TO_VM_PAGE) */
|
||||||
|
|
||||||
|
#if !defined(_BUS_PMAP_ENTER)
|
||||||
|
#define _BUS_PMAP_ENTER(pmap, va, ba, prot, flags) \
|
||||||
|
pmap_enter(pmap, va, ba, prot, flags)
|
||||||
|
#endif /* _BUS_PMAP_ENTER */
|
||||||
|
|
||||||
#if !defined(_BUS_VIRT_TO_BUS)
|
#if !defined(_BUS_VIRT_TO_BUS)
|
||||||
#include <uvm/uvm_extern.h>
|
#include <uvm/uvm_extern.h>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: bus_dma.c,v 1.29 2006/03/01 12:38:12 yamt Exp $ */
|
/* $NetBSD: bus_dma.c,v 1.30 2006/08/28 19:58:57 bouyer Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.29 2006/03/01 12:38:12 yamt Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.30 2006/08/28 19:58:57 bouyer Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following is included because _bus_dma_uiomove is derived from
|
* The following is included because _bus_dma_uiomove is derived from
|
||||||
|
@ -994,7 +994,7 @@ _bus_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
|
||||||
for (addr = segs[curseg].ds_addr;
|
for (addr = segs[curseg].ds_addr;
|
||||||
addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
|
addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
|
||||||
addr += PAGE_SIZE) {
|
addr += PAGE_SIZE) {
|
||||||
m = PHYS_TO_VM_PAGE(addr);
|
m = _BUS_BUS_TO_VM_PAGE(addr);
|
||||||
TAILQ_INSERT_TAIL(&mlist, m, pageq);
|
TAILQ_INSERT_TAIL(&mlist, m, pageq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1039,7 +1039,7 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
|
||||||
addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) {
|
addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
panic("_bus_dmamem_map: size botch");
|
panic("_bus_dmamem_map: size botch");
|
||||||
pmap_enter(pmap_kernel(), va, addr,
|
_BUS_PMAP_ENTER(pmap_kernel(), va, addr,
|
||||||
VM_PROT_READ | VM_PROT_WRITE,
|
VM_PROT_READ | VM_PROT_WRITE,
|
||||||
PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE);
|
PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE);
|
||||||
/*
|
/*
|
||||||
|
@ -1129,7 +1129,7 @@ _bus_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (x86_btop((caddr_t)segs[i].ds_addr + off));
|
return (x86_btop(_BUS_BUS_TO_PHYS(segs[i].ds_addr + off)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Page not found. */
|
/* Page not found. */
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: bus_private.h,v 1.6 2006/02/16 20:17:15 perry Exp $ */
|
/* $NetBSD: bus_private.h,v 1.7 2006/08/28 19:58:57 bouyer Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c)2005 YAMAMOTO Takashi,
|
* Copyright (c)2005 YAMAMOTO Takashi,
|
||||||
|
@ -29,7 +29,11 @@
|
||||||
#include <uvm/uvm_extern.h>
|
#include <uvm/uvm_extern.h>
|
||||||
|
|
||||||
#define _BUS_PHYS_TO_BUS(pa) ((bus_addr_t)xpmap_ptom(pa))
|
#define _BUS_PHYS_TO_BUS(pa) ((bus_addr_t)xpmap_ptom(pa))
|
||||||
|
#define _BUS_BUS_TO_PHYS(ba) ((paddr_t)xpmap_mtop(ba))
|
||||||
#define _BUS_VIRT_TO_BUS(pm, va) _bus_virt_to_bus((pm), (va))
|
#define _BUS_VIRT_TO_BUS(pm, va) _bus_virt_to_bus((pm), (va))
|
||||||
|
#define _BUS_BUS_TO_VM_PAGE(ba) (PHYS_TO_VM_PAGE(xpmap_mtop(ba)))
|
||||||
|
#define _BUS_PMAP_ENTER(pmap, va, ba, prot, flags) \
|
||||||
|
pmap_enter(pmap, va, xpmap_mtop(ba), prot, flags)
|
||||||
|
|
||||||
static __inline bus_addr_t _bus_virt_to_bus(struct pmap *, vaddr_t);
|
static __inline bus_addr_t _bus_virt_to_bus(struct pmap *, vaddr_t);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: xen_bus_dma.c,v 1.6 2006/01/15 22:09:52 bouyer Exp $ */
|
/* $NetBSD: xen_bus_dma.c,v 1.7 2006/08/28 19:58:57 bouyer Exp $ */
|
||||||
/* NetBSD bus_dma.c,v 1.21 2005/04/16 07:53:35 yamt Exp */
|
/* NetBSD bus_dma.c,v 1.21 2005/04/16 07:53:35 yamt Exp */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
|
@ -39,7 +39,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: xen_bus_dma.c,v 1.6 2006/01/15 22:09:52 bouyer Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: xen_bus_dma.c,v 1.7 2006/08/28 19:58:57 bouyer Exp $");
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/systm.h>
|
#include <sys/systm.h>
|
||||||
|
@ -75,14 +75,11 @@ _xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary,
|
||||||
unsigned long npagesreq, npages, mfn;
|
unsigned long npagesreq, npages, mfn;
|
||||||
bus_addr_t pa;
|
bus_addr_t pa;
|
||||||
struct vm_page *pg, *pgnext;
|
struct vm_page *pg, *pgnext;
|
||||||
struct pglist freelist;
|
|
||||||
int s, error;
|
int s, error;
|
||||||
#ifdef XEN3
|
#ifdef XEN3
|
||||||
struct xen_memory_reservation res;
|
struct xen_memory_reservation res;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TAILQ_INIT(&freelist);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When requesting a contigous memory region, the hypervisor will
|
* When requesting a contigous memory region, the hypervisor will
|
||||||
* return a memory range aligned on size. This will automagically
|
* return a memory range aligned on size. This will automagically
|
||||||
|
@ -114,14 +111,21 @@ _xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary,
|
||||||
< 0) {
|
< 0) {
|
||||||
printf("xen_alloc_contig: XENMEM_decrease_reservation "
|
printf("xen_alloc_contig: XENMEM_decrease_reservation "
|
||||||
"failed!\n");
|
"failed!\n");
|
||||||
return ENOMEM;
|
xpmap_phys_to_machine_mapping[
|
||||||
|
(pa - XPMAP_OFFSET) >> PAGE_SHIFT] = mfn;
|
||||||
|
|
||||||
|
error = ENOMEM;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
|
if (HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation,
|
||||||
&mfn, 1, 0) != 1) {
|
&mfn, 1, 0) != 1) {
|
||||||
printf("xen_alloc_contig: MEMOP_decrease_reservation "
|
printf("xen_alloc_contig: MEMOP_decrease_reservation "
|
||||||
"failed!\n");
|
"failed!\n");
|
||||||
return ENOMEM;
|
xpmap_phys_to_machine_mapping[
|
||||||
|
(pa - XPMAP_OFFSET) >> PAGE_SHIFT] = mfn;
|
||||||
|
error = ENOMEM;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -135,14 +139,18 @@ _xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary,
|
||||||
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res) < 0) {
|
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res) < 0) {
|
||||||
printf("xen_alloc_contig: XENMEM_increase_reservation "
|
printf("xen_alloc_contig: XENMEM_increase_reservation "
|
||||||
"failed!\n");
|
"failed!\n");
|
||||||
return ENOMEM;
|
error = ENOMEM;
|
||||||
|
pg = NULL;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
if (HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
||||||
&mfn, 1, order) != 1) {
|
&mfn, 1, order) != 1) {
|
||||||
printf("xen_alloc_contig: MEMOP_increase_reservation "
|
printf("xen_alloc_contig: MEMOP_increase_reservation "
|
||||||
"failed!\n");
|
"failed!\n");
|
||||||
return ENOMEM;
|
error = ENOMEM;
|
||||||
|
pg = NULL;
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
s = splvm();
|
s = splvm();
|
||||||
|
@ -165,6 +173,58 @@ _xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary,
|
||||||
xpq_flush_queue();
|
xpq_flush_queue();
|
||||||
splx(s);
|
splx(s);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
/*
|
||||||
|
* Attempt to recover from a failed decrease or increase reservation:
|
||||||
|
* if decrease_reservation failed, we don't have given all pages
|
||||||
|
* back to Xen; give them back to UVM, and get the missing pages
|
||||||
|
* from Xen.
|
||||||
|
* if increase_reservation failed, we expect pg to be NULL and we just
|
||||||
|
* get back the missing pages from Xen one by one.
|
||||||
|
*/
|
||||||
|
/* give back remaining pages to UVM */
|
||||||
|
for (; pg != NULL; pg = pgnext) {
|
||||||
|
pgnext = pg->pageq.tqe_next;
|
||||||
|
TAILQ_REMOVE(mlistp, pg, pageq);
|
||||||
|
uvm_pagefree(pg);
|
||||||
|
}
|
||||||
|
/* remplace the pages that we already gave to Xen */
|
||||||
|
s = splvm();
|
||||||
|
for (pg = mlistp->tqh_first; pg != NULL; pg = pgnext) {
|
||||||
|
pgnext = pg->pageq.tqe_next;
|
||||||
|
#ifdef XEN3
|
||||||
|
res.extent_start = &mfn;
|
||||||
|
res.nr_extents = 1;
|
||||||
|
res.extent_order = 0;
|
||||||
|
res.address_bits = 31;
|
||||||
|
res.domid = DOMID_SELF;
|
||||||
|
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res)
|
||||||
|
< 0) {
|
||||||
|
printf("xen_alloc_contig: recovery "
|
||||||
|
"XENMEM_increase_reservation failed!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
|
||||||
|
&mfn, 1, 0) != 1) {
|
||||||
|
printf("xen_alloc_contig: recovery "
|
||||||
|
"MEMOP_increase_reservation failed!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pa = VM_PAGE_TO_PHYS(pg);
|
||||||
|
xpmap_phys_to_machine_mapping[
|
||||||
|
(pa - XPMAP_OFFSET) >> PAGE_SHIFT] = mfn;
|
||||||
|
xpq_queue_machphys_update((mfn) << PAGE_SHIFT, pa);
|
||||||
|
TAILQ_REMOVE(mlistp, pg, pageq);
|
||||||
|
uvm_pagefree(pg);
|
||||||
|
}
|
||||||
|
/* Flush updates through and flush the TLB */
|
||||||
|
xpq_queue_tlb_flush();
|
||||||
|
xpq_flush_queue();
|
||||||
|
splx(s);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,8 +238,7 @@ _xen_bus_dmamem_alloc_range(bus_dma_tag_t t, bus_size_t size,
|
||||||
bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
|
bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs,
|
||||||
int nsegs, int *rsegs, int flags, bus_addr_t low, bus_addr_t high)
|
int nsegs, int *rsegs, int flags, bus_addr_t low, bus_addr_t high)
|
||||||
{
|
{
|
||||||
paddr_t curaddr, lastaddr;
|
bus_addr_t curaddr, lastaddr;
|
||||||
bus_addr_t bus_curaddr, bus_lastaddr;
|
|
||||||
struct vm_page *m;
|
struct vm_page *m;
|
||||||
struct pglist mlist;
|
struct pglist mlist;
|
||||||
int curseg, error;
|
int curseg, error;
|
||||||
|
@ -210,18 +269,16 @@ again:
|
||||||
*/
|
*/
|
||||||
m = mlist.tqh_first;
|
m = mlist.tqh_first;
|
||||||
curseg = 0;
|
curseg = 0;
|
||||||
lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
|
lastaddr = segs[curseg].ds_addr = _BUS_VM_PAGE_TO_BUS(m);
|
||||||
segs[curseg].ds_len = PAGE_SIZE;
|
segs[curseg].ds_len = PAGE_SIZE;
|
||||||
m = m->pageq.tqe_next;
|
m = m->pageq.tqe_next;
|
||||||
if ((_BUS_PHYS_TO_BUS(segs[curseg].ds_addr) & (alignment - 1)) != 0)
|
if ((segs[curseg].ds_addr & (alignment - 1)) != 0)
|
||||||
goto dorealloc;
|
goto dorealloc;
|
||||||
|
|
||||||
for (; m != NULL; m = m->pageq.tqe_next) {
|
for (; m != NULL; m = m->pageq.tqe_next) {
|
||||||
curaddr = VM_PAGE_TO_PHYS(m);
|
curaddr = _BUS_VM_PAGE_TO_BUS(m);
|
||||||
bus_curaddr = _BUS_PHYS_TO_BUS(curaddr);
|
if ((lastaddr < low || lastaddr >= high) ||
|
||||||
bus_lastaddr = _BUS_PHYS_TO_BUS(lastaddr);
|
(curaddr < low || curaddr >= high)) {
|
||||||
if ((bus_lastaddr < low || bus_lastaddr >= high) ||
|
|
||||||
(bus_curaddr < low || bus_curaddr >= high)) {
|
|
||||||
/*
|
/*
|
||||||
* If machine addresses are outside the allowed
|
* If machine addresses are outside the allowed
|
||||||
* range we have to bail. Xen2 doesn't offer an
|
* range we have to bail. Xen2 doesn't offer an
|
||||||
|
@ -233,16 +290,15 @@ again:
|
||||||
uvm_pglistfree(&mlist);
|
uvm_pglistfree(&mlist);
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (bus_curaddr == (bus_lastaddr + PAGE_SIZE)) {
|
if (curaddr == (lastaddr + PAGE_SIZE)) {
|
||||||
segs[curseg].ds_len += PAGE_SIZE;
|
segs[curseg].ds_len += PAGE_SIZE;
|
||||||
if ((bus_lastaddr & boundary) !=
|
if ((lastaddr & boundary) !=
|
||||||
(bus_curaddr & boundary))
|
(curaddr & boundary))
|
||||||
goto dorealloc;
|
goto dorealloc;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
curseg++;
|
curseg++;
|
||||||
if (curseg >= nsegs ||
|
if (curseg >= nsegs ||
|
||||||
(bus_curaddr & (alignment - 1)) != 0) {
|
(curaddr & (alignment - 1)) != 0) {
|
||||||
dorealloc:
|
dorealloc:
|
||||||
if (doingrealloc == 1)
|
if (doingrealloc == 1)
|
||||||
panic("_xen_bus_dmamem_alloc_range: "
|
panic("_xen_bus_dmamem_alloc_range: "
|
||||||
|
|
Loading…
Reference in New Issue