On Tuesday, 23 May 2023 17:32:16 CEST Paul Boddie wrote:
But the DMA domain is still not found when assigning the space. I did wonder whether I might need to create a device to hold the DMA domain resource, but my attempt to implement this failed:
for resource in hw:resources() do print("resource name=" .. resource:id()) if resource:id() == 1145130308 then device = Io.Vi.System_bus() device:add_resource(resource) bus:add_child(device) end end
Well, this proved to be the wrong track, as I imagined, but the following helped me onto the right track:
Here, Io crashes...
IO | L4Re[rm]: unhandled read page fault at 0x31 pc=0x102aba0 IO | L4Re: rom/io: Unhandled exception: PC=0x102aba0 PFA=0x30 LdrFlgs=0x0
...which is the following line in Dma_domain::add_to_group:
if (!_v_domain && !g->_set)
I imagine that I am making this harder than it should be, though.
I already suspected that I needed a DMA domain inside an actual device, as opposed to the system bus, so that the code in Io would be able to find the resource. Obviously, the attempt above did not achieve this, indicating that there is more involved in the initialisation than simply "copying" a resource into a suitable location.
I then discovered that the Hw_device_DF_dma_supported property flag would allow a search using the vbus to yield a DMA domain resource with a valid identifier and for Io to find this by itself when assigning a DMA space to a domain. Although the SoC I am using has no notion of device-specific DMA domains, conceptually it makes sense to associate DMA with the peripheral I am trying to configure, so I introduced the following to my LCD controller device:
LCD = Hw.Device(function() Property.hid = "jz4780-lcd"; -- compatible = {"mips,jz4780-lcd"}; Resource.regs = Res.mmio(0x13050000, 0x130517ff); Resource.irq = Res.irq({31, 31}, Io.Resource.Irq_type_level_high); Property.flags = Io.Hw_device_DF_dma_supported; end);
However, one counterintuitive aspect of assigning a DMA space involves the DMA domain identifier. As suggested by the nvme-driver code, although a DMA domain has a resource identifier of 0x44414d44 ("DMAD"), the assign operation actually wants the start address associated with the resource. This turns out to be zero in my case.
I still wasn't completely done, however. The map operation was failing with what tends to be described in the error messages as a "bad, unknown runtime error". Eventually, I tracked this down to the _get_ds function found in pkg/ l4re-core/moe/server/src/dma_space.cc which has some L4Re::chksys invocations. These invocations are quite unhelpful, obscuring the actual error, which was due to the received DMA space capability not having write permission.
In fact, I see that the nvme-driver code for invoking the operation uses the make_cap_rw method on a L4::Ipc::Cap instance, whereas those using the C library have to set the rights bits the old-fashioned way. I don't think I have needed to do this for anything before, so this caught me out.
In any case, with all this tidied up, I finally got hold of those physical addresses again, and thankfully the rest of my existing code still worked. I do wonder about where I might put that Hw_device_DF_dma_supported property, but I imagine that even if it were replicated on all appropriate devices, it would not matter which device such a global domain would be acquired from.
Anyway, I hope this counts as some kind of feedback about how these frameworks are experienced by outsiders such as myself. I will now aim to pick up where I left off a few weeks ago...
Thanks for the help given!
Paul