On Wed, May 26, 2021 at 01:13:22PM +0100, Will Deacon wrote: > On Tue, May 18, 2021 at 02:42:14PM +0800, Claire Chang wrote: > > @@ -138,4 +160,9 @@ one for multimedia processing (named multimedia-memory@77000000, 64MiB). > > memory-region = <&multimedia_reserved>; > > /* ... */ > > }; > > + > > + pcie_device: pcie_device@0,0 { > > + memory-region = <&restricted_dma_mem_reserved>; > > + /* ... */ > > + }; > > I still don't understand how this works for individual PCIe devices -- how > is dev->of_node set to point at the node you have above? > > I tried adding the memory-region to the host controller instead, and then > I see it crop up in dmesg: > > | pci-host-generic 40000000.pci: assigned reserved memory node restricted_dma_mem_reserved > > but none of the actual PCI devices end up with 'dma_io_tlb_mem' set, and > so the restricted DMA area is not used. In fact, swiotlb isn't used at all. > > What am I missing to make this work with PCIe devices? Aha, looks like we're just missing the logic to inherit the DMA configuration. The diff below gets things working for me. Will --->8 diff --git a/drivers/of/address.c b/drivers/of/address.c index c562a9ff5f0b..bf499fdd6e93 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -1113,25 +1113,25 @@ bool of_dma_is_coherent(struct device_node *np) } EXPORT_SYMBOL_GPL(of_dma_is_coherent); -int of_dma_set_restricted_buffer(struct device *dev) +int of_dma_set_restricted_buffer(struct device *dev, struct device_node *np) { - struct device_node *node; int count, i; - if (!dev->of_node) + if (!np) return 0; - count = of_property_count_elems_of_size(dev->of_node, "memory-region", + count = of_property_count_elems_of_size(np, "memory-region", sizeof(phandle)); for (i = 0; i < count; i++) { - node = of_parse_phandle(dev->of_node, "memory-region", i); + struct device_node *node; + + node = of_parse_phandle(np, "memory-region", i); /* There might be multiple memory regions, but only one - * restriced-dma-pool region is allowed. + * restricted-dma-pool region is allowed. */ if (of_device_is_compatible(node, "restricted-dma-pool") && of_device_is_available(node)) - return of_reserved_mem_device_init_by_idx( - dev, dev->of_node, i); + return of_reserved_mem_device_init_by_idx(dev, np, i); } return 0; diff --git a/drivers/of/device.c b/drivers/of/device.c index d8d865223e51..2defdca418ec 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -166,7 +166,7 @@ int of_dma_configure_id(struct device *dev, struct device_node *np, arch_setup_dma_ops(dev, dma_start, size, iommu, coherent); if (!iommu) - return of_dma_set_restricted_buffer(dev); + return of_dma_set_restricted_buffer(dev, np); return 0; } diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 9fc874548528..8fde97565d11 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -163,14 +163,15 @@ struct bus_dma_region; #if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_HAS_DMA) int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map); -int of_dma_set_restricted_buffer(struct device *dev); +int of_dma_set_restricted_buffer(struct device *dev, struct device_node *np); #else static inline int of_dma_get_range(struct device_node *np, const struct bus_dma_region **map) { return -ENODEV; } -static inline int of_dma_set_restricted_buffer(struct device *dev) +static inline int of_dma_set_restricted_buffer(struct device *dev, + struct device_node *np) { return -ENODEV; }