Allocate DMA buffers in first 4GB
I tried to boot DragonFlyBSD on my AMD notebook, unfortunately it doesn't work. The problem is that on modern AMD systems, if you don't properly support AMD IOMMU, you have to allocate DMA buffers in the first 4 gigabytes of memory. That's how OpenBSD (and probably others) is doing this.
I've attached patch that fixes it in busdma_machdep.c. With this patch applied, DragonFlyBSD boots fine on my machine (and probably other modern AMD computers).
As a bonus, it simplifies code a bit, but I'm not really sure if it's a good thing. I just don't quite understand why this code wasn't using contigmalloc() all along, which seems to be more fitting for this kind of stuff.
Looks like previous code used kmalloc() when needed memory block was small enough, and then prayed for proper alignment. It retried if alignment wouldn't turn out to be OK. If requested memory block was larger, it would've used contigmalloc(). It just doesn't feel right.
I'm no expert on this stuff, so any comments are welcome!
Updated by vadaszi over 5 years ago
The attached patch should only serve as a workaround for debugging this kind of issue. Each driver needs to specify the allowed address range for DMA allocations itself (using the lowaddr and highaddr parameters in the bus_dma_tag_create() call, which specify the physical address ranges not usable for DMA).
Your issue seems like one of the drivers isn't explicitly asking for 32bit DMA memory when it should.
Yeah, it looks like the kmalloc() codepath should have some more safeguards, but when used correctly it seems to make sense as a performace optimization. Also, the kmalloc() path is only used when the driver explicitly BUS_SPACE_MAXADDR for lowaddr and highaddr in bus_dma_tag_create(), i.e. allowing the allocation to be anywhere in the physical address space.
It would be great if you post the dmesg output for your machine and maybe some information on when/how DragonFly fails to work on your system
Feel free to create a bug report for tracking your issues.
Updated by xenu over 5 years ago
Thank you for your reply, now it's a lot more clear to me! Still, it looks like its obfuscated and definitely could use more comments in code :)
So the driver itself should request 32 bit memory, and kmalloc() thing is an optimization. Got it. But I still don't fully understand the purpose of two-tries-of-kmalloc construction. It looks dodgy at best, without comments I can only assume that it either has certain, unclear assumptions on undocumented kmalloc() behavior or it just tries to get lucky twice. I can be wrong, but it just doesn't look like a very good design.
Also, I still think it's simpler to forbid allocating above 32-bits when there is no IOMMU support (just like in OpenBSD), but that's not something I'm going to argue about, as there are good reasons to not like this idea :)
I'll find offending driver when I'll have chance to boot dfly again.