Patch: sym(4) "VTOBUS FAILED" panics on amd64, amd64/89550
Jan Mikkelsen
janm at transactionware.com
Thu Sep 21 21:25:39 PDT 2006
Hi,
Doug White wrote:
> On Fri, 22 Sep 2006, Jan Mikkelsen wrote:
>
> > Quick summary: sym(4) assumes on amd64 that virtual
> addresses provided by
> > bus_dmamem_alloc() have the same alignment as the physical
> addresses (in
> > this case, 2*PAGE_SIZE). They don't, and stuff breaks.
> This patch works
> > around that.
>
> Why is this? busdma supports alignment constraints; why not
> just set the
> alignment to what you need it set at? I realize sym has its own hand
> rolled DMA management craziness but alignment is something
> busdma can take
> care of easily.
sym has the alignment requirement on the virtual address because of the
buddy memory allocation algorithm; changing how sym allocates memory
internally would remove the requirement. The buddy algorithm with 2^13
bytes aligned on a 2^12 byte (but not a 2^13 byte) boundary can provide two
chunks of 2^12 bytes but nothing greater than 2^12 bytes.
The VTOBUS failure is caused by the buddy implementation making alignment
assumptions which aren't true, and then getting the virtual addresses wrong.
Perhaps I'm just doing something wrong with bus_dma. I believe I set the
alignment requirements to be 2*PAGE_SIZE, and this is what I see for the
physical address. However the virtual address seems to only be page
aligned.
I can't see any mention of virtual address alignment in the bus_dma man
page. Can it take care of virtual address alignment? If so, how?
> Also the changes to MEMO_CLUSTER_SIZE seems to be already
> compensated for
> by the code blocks that calculate it:
>
> #define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */
> #ifndef __amd64__
> #define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */
> #else
> #define MEMO_PAGE_ORDER 1 /* 2 PAGEs maximum on amd64 */
> #endif
> #if 0
> #define MEMO_FREE_UNUSED /* Free unused pages immediately */
> #endif
> #define MEMO_WARN 1
> #define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER)
> #define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT)
> #define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1)
>
> This results in 2*PAGE_SIZE clusters on amd64 and PAGE_SIZE
> clusters on
> other platforms. Since you seem to like doing
> MEMO_CLUSTER_SIZE * 2, why
> not just increase MEMO_PAGE_ORDER to 2 (and get 4*PAGE_SIZE
> clusters) ?
My fix (which I don't claim is optimal) is to allocate 2*MEMO_CLUSTER_SIZE
bytes, and then use the point within that memory with the right alignment.
The alignment is not a hardware requirement; it is a bit manipulation
requirement because of the existing allocation code.
The cost is some extra allocated pages in return for a working system.
> Oh dear, I didn't notice that the call to
> bus_dma_tag_create() has bad
> arguments. From the (RELENG_6) source:
>
> if (!bus_dma_tag_create(dev_dmat, 1,
> MEMO_CLUSTER_SIZE,
> BUS_SPACE_MAXADDR_32BIT,
> BUS_SPACE_MAXADDR_32BIT,
> NULL, NULL, MEMO_CLUSTER_SIZE, 1,
> MEMO_CLUSTER_SIZE, 0,
> busdma_lock_mutex, &Giant,
> &mp->dmat)) {
>
> As you fixed, that second BUS_SPACE_MAXADDR_32BIT should be
> BUS_SPACE_MAXADDR since its an exclusion zone. I'm suprised
> that doesn't
> fix it right there.
I tried it, didn't fix it.
> Also we generally prefer diffs in unidiff (-u) format, its a
> little easier
> to figure out exactly what changed just by looking at the
> diff. Thanks!
Thanks, I'll do that next time.
Regards,
Jan Mikkelsen.
More information about the freebsd-stable
mailing list