version 1.8.6.1, 2010/06/13 05:48:58 |
version 1.9, 2007/02/24 21:19:25 |
Line 69 static inline int get_order(unsigned lon |
|
Line 69 static inline int get_order(unsigned lon |
|
|
|
static int |
static int |
_xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary, |
_xen_alloc_contig(bus_size_t size, bus_size_t alignment, bus_size_t boundary, |
struct pglist *mlistp, int flags) |
struct pglist *mlistp, int flags, bus_addr_t low, bus_addr_t high) |
{ |
{ |
int order, i; |
int order, i; |
unsigned long npagesreq, npages, mfn; |
unsigned long npagesreq, npages, mfn; |
Line 106 _xen_alloc_contig(bus_size_t size, bus_s |
|
Line 106 _xen_alloc_contig(bus_size_t size, bus_s |
|
res.extent_start = &mfn; |
res.extent_start = &mfn; |
res.nr_extents = 1; |
res.nr_extents = 1; |
res.extent_order = 0; |
res.extent_order = 0; |
res.address_bits = 0; |
|
res.domid = DOMID_SELF; |
res.domid = DOMID_SELF; |
if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, &res) |
if (HYPERVISOR_memory_op(XENMEM_decrease_reservation, &res) |
< 0) { |
< 0) { |
Line 139 _xen_alloc_contig(bus_size_t size, bus_s |
|
Line 138 _xen_alloc_contig(bus_size_t size, bus_s |
|
res.extent_start = &mfn; |
res.extent_start = &mfn; |
res.nr_extents = 1; |
res.nr_extents = 1; |
res.extent_order = order; |
res.extent_order = order; |
res.address_bits = 31; |
res.address_bits = get_order(high) + PAGE_SHIFT; |
res.domid = DOMID_SELF; |
res.domid = DOMID_SELF; |
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res) < 0) { |
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res) < 0) { |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
res.extent_start = &mfn; |
res.extent_start = &mfn; |
res.nr_extents = 1; |
res.nr_extents = 1; |
res.extent_order = 0; |
res.extent_order = 0; |
res.address_bits = 31; |
res.address_bits = 32; |
res.domid = DOMID_SELF; |
res.domid = DOMID_SELF; |
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res) |
if (HYPERVISOR_memory_op(XENMEM_increase_reservation, &res) |
< 0) { |
< 0) { |
|
|
*/ |
*/ |
m = mlist.tqh_first; |
m = mlist.tqh_first; |
curseg = 0; |
curseg = 0; |
lastaddr = segs[curseg].ds_addr = _BUS_VM_PAGE_TO_BUS(m); |
curaddr = lastaddr = segs[curseg].ds_addr = _BUS_VM_PAGE_TO_BUS(m); |
|
if (curaddr < low || curaddr >= high) |
|
goto badaddr; |
segs[curseg].ds_len = PAGE_SIZE; |
segs[curseg].ds_len = PAGE_SIZE; |
m = m->pageq.tqe_next; |
m = m->pageq.tqe_next; |
if ((segs[curseg].ds_addr & (alignment - 1)) != 0) |
if ((segs[curseg].ds_addr & (alignment - 1)) != 0) |
|
|
|
|
for (; m != NULL; m = m->pageq.tqe_next) { |
for (; m != NULL; m = m->pageq.tqe_next) { |
curaddr = _BUS_VM_PAGE_TO_BUS(m); |
curaddr = _BUS_VM_PAGE_TO_BUS(m); |
if ((lastaddr < low || lastaddr >= high) || |
if (curaddr < low || curaddr >= high) |
(curaddr < low || curaddr >= high)) { |
goto badaddr; |
/* |
|
* If machine addresses are outside the allowed |
|
* range we have to bail. Xen2 doesn't offer an |
|
* interface to get memory in a specific address |
|
* range. |
|
*/ |
|
printf("_xen_bus_dmamem_alloc_range: no way to " |
|
"enforce address range\n"); |
|
uvm_pglistfree(&mlist); |
|
return EINVAL; |
|
} |
|
if (curaddr == (lastaddr + PAGE_SIZE)) { |
if (curaddr == (lastaddr + PAGE_SIZE)) { |
segs[curseg].ds_len += PAGE_SIZE; |
segs[curseg].ds_len += PAGE_SIZE; |
if ((lastaddr & boundary) != |
if ((lastaddr & boundary) != (curaddr & boundary)) |
(curaddr & boundary)) |
|
goto dorealloc; |
goto dorealloc; |
} else { |
} else { |
curseg++; |
curseg++; |
if (curseg >= nsegs || |
if (curseg >= nsegs || (curaddr & (alignment - 1)) != 0) |
(curaddr & (alignment - 1)) != 0) { |
goto dorealloc; |
dorealloc: |
|
if (doingrealloc == 1) |
|
panic("_xen_bus_dmamem_alloc_range: " |
|
"xen_alloc_contig returned " |
|
"too much segments"); |
|
doingrealloc = 1; |
|
/* |
|
* Too much segments. Free this memory and |
|
* get a contigous segment from the hypervisor. |
|
*/ |
|
uvm_pglistfree(&mlist); |
|
for (curseg = 0; curseg < nsegs; curseg++) { |
|
segs[curseg].ds_addr = 0; |
|
segs[curseg].ds_len = 0; |
|
} |
|
error = _xen_alloc_contig(size, alignment, |
|
boundary, &mlist, flags); |
|
if (error) |
|
return error; |
|
goto again; |
|
} |
|
segs[curseg].ds_addr = curaddr; |
segs[curseg].ds_addr = curaddr; |
segs[curseg].ds_len = PAGE_SIZE; |
segs[curseg].ds_len = PAGE_SIZE; |
} |
} |
|
|
} |
} |
|
|
*rsegs = curseg + 1; |
*rsegs = curseg + 1; |
|
|
return (0); |
return (0); |
|
|
|
badaddr: |
|
#ifdef XEN3 |
|
if (doingrealloc == 0) |
|
goto dorealloc; |
|
if (curaddr < low) { |
|
/* no way to enforce this */ |
|
printf("_xen_bus_dmamem_alloc_range: no way to " |
|
"enforce address range\n"); |
|
uvm_pglistfree(&mlist); |
|
return EINVAL; |
|
} |
|
printf("xen_bus_dmamem_alloc_range: " |
|
"curraddr=0x%lx > high=0x%lx\n", |
|
(u_long)curaddr, (u_long)high); |
|
panic("xen_bus_dmamem_alloc_range 1"); |
|
#else /* !XEN3 */ |
|
/* |
|
* If machine addresses are outside the allowed |
|
* range we have to bail. Xen2 doesn't offer an |
|
* interface to get memory in a specific address |
|
* range. |
|
*/ |
|
printf("_xen_bus_dmamem_alloc_range: no way to " |
|
"enforce address range\n"); |
|
uvm_pglistfree(&mlist); |
|
return EINVAL; |
|
#endif /* XEN3 */ |
|
dorealloc: |
|
if (doingrealloc == 1) |
|
panic("_xen_bus_dmamem_alloc_range: " |
|
"xen_alloc_contig returned " |
|
"too much segments"); |
|
doingrealloc = 1; |
|
/* |
|
* Too much segments, or memory doesn't fit |
|
* constraints. Free this memory and |
|
* get a contigous segment from the hypervisor. |
|
*/ |
|
uvm_pglistfree(&mlist); |
|
for (curseg = 0; curseg < nsegs; curseg++) { |
|
segs[curseg].ds_addr = 0; |
|
segs[curseg].ds_len = 0; |
|
} |
|
error = _xen_alloc_contig(size, alignment, |
|
boundary, &mlist, flags, low, high); |
|
if (error) |
|
return error; |
|
goto again; |
} |
} |