Page MenuHomeFreeBSD

busdma, arm64: implement support for bus view of DMA address space
Needs ReviewPublic

Authored by mmel on Wed, Jul 8, 11:32 AM.
Tags
None
Referenced Files
Unknown Object (File)
Mon, Jul 13, 11:08 AM
Unknown Object (File)
Sun, Jul 12, 9:17 PM
Unknown Object (File)
Sat, Jul 11, 10:29 PM
Subscribers

Details

Reviewers
andrew
manu
Summary

BUS_DMA(9) explicitly states that ds_addr field of bus_dma_segment_t contains
the device visible address of the DMA segment, which is not necessarily the
same as CPU's view of memory. Add a per-tag bus_dma_mapseg_t callback
(along with bus_dma_tag_set_mapseg()) that allows to establish a mapping of
host physical address (PA) of a buffer segment to the corresponding CPU
view of memory.

This change is primarily required for the RPi 5, so it is implemented on arm64
for now. Once proven stable, it will be extended to other architectures
and the relevant updates will be added to the man pages.

MFC after: 4 weeks

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 74615
Build 71498: arc lint + arc unit

Event Timeline

mmel requested review of this revision.Wed, Jul 8, 11:32 AM

How will this work with the tags boundary, lowaddr and highaddr? We allocate memory assuming these are CPU physical addresses, but they should be bus addresses.

That's a very good and valid question.
Combining the fact that the 'dma-ranges' DT property (which this change targets) can describe multiple discontinuous ranges and that PCI(e) mappings further depend on transaction types quickly opens a very large Pandora's box. Add chained DMA tags and the IOMMU into the mix, and the problem becomes even more complex.
The honest answer is: I don't know how to handle this in full generality right now.
Today, it remains the driver's responsibility to work with CPU addresses. Modernising busdma would require a significant amount of work, and I'm not confident I have the energy or deep enough knowledge to tackle it all at once.
This minimal implementation is intended only to enable RPi5 support for now, nothing more yet.

For the IOMMU we use a separate busdma implementation. It looks like the dma-ranges property on an iommu is to translate between the translated iommu address and a cpu physical address. Because of this I don't think it's a problem there as devices behind an iommu will use a virtual address, so can allocate addresses as needed.

I haven't looked into the requirements for PCI, but for MMIO I expect we could pass a structure with device<->cpu mappings & use that to find CPU physical address space to allocate from.

At this stage, I do not want to introduce tables or hard-coded segment mappings
and/or limits for DMA memory allocation.
For flexibility, the primary interface should be based on functions. A default
implementation can always be added later if a sufficiently robust common case
is identified.

The real RPi 5 case illustrates that the situation is not trivial.

axi: axi {
	compatible = "simple-bus";
	#address-cells = <2>;

	dma-ranges = <0x00 0x00000000  0x00 0x00000000  0x10 0x00000000>,
		     <0x10 0x00000000  0x10 0x00000000  0x01 0x00000000>,
		     <0x14 0x00000000  0x14 0x00000000  0x04 0x00000000>,
		     <0x18 0x00000000  0x18 0x00000000  0x04 0x00000000>,
		     <0x1c 0x00000000  0x1c 0x00000000  0x04 0x00000000>;

	pcie0: pcie@1000100000 {
		compatible = "brcm,bcm2712-pcie";
		#address-cells = <3>;

		dma-ranges =
			/* 64GiB, 64-bit, prefetchable at PCIe 10_0000_0000 */
			<0x43000000 0x10 0x00000000 0x00 0x00000000 0x10 0x00000000>;

		pci_ep_bus: pci-ep-bus@1 {
			compatible = "simple-bus";

			dma-ranges = <0x10 0x00000000  0x43000000 0x10 0x00000000  0x10 0x00000000>;
			#address-cells = <2>;
				<... RP1 device subtreee is here...>
		}
	}
	<...2712 device subtreee is here...>
}

Regarding IOMMU: the IOMMU node itself, or any of its parent nodes, may also
contain dma-ranges. This implies that the IOMMU can be restricted in the ranges
of usable physical addresses (PA) it can target. I'm not sure if ve ready for
this.

I will attempt to handle the allocation constraints, but it is already clear
that lowaddr and highaddr alone are insufficient. The handling of alignment and
boundary requirements is still unclear to me, particularly when these
constraints are larger than page size.

I would like to take the weekend to work on the next iteration.