On Tue, Nov 13, 2018 at 07:28:11PM +1100, Alexey Kardashevskiy wrote: > We might have memory@ nodes with "linux,usable-memory" set to zero > (for example, to replicate powernv's behaviour for GPU coherent memory) > which means that the memory needs an extra initialization but since > it can be used afterwards, the pseries platform will try mapping it > for DMA so the DMA window needs to cover those memory regions too. > > This walks through the memory nodes to find the highest RAM address to > let a huge DMA window cover that too in case this memory gets onlined > later. > > Signed-off-by: Alexey Kardashevskiy > --- > arch/powerpc/platforms/pseries/iommu.c | 43 +++++++++++++++++++++++++- > 1 file changed, 42 insertions(+), 1 deletion(-) > > diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c > index 78473ac..f818737 100644 > --- a/arch/powerpc/platforms/pseries/iommu.c > +++ b/arch/powerpc/platforms/pseries/iommu.c > @@ -967,6 +967,47 @@ struct failed_ddw_pdn { > > static LIST_HEAD(failed_ddw_pdn_list); > > +static unsigned long read_n_cells(int n, const __be32 **buf) > +{ > + unsigned long result = 0; > + > + while (n--) { > + result = (result << 32) | of_read_number(*buf, 1); > + (*buf)++; > + } > + return result; > +} Um.. this appears to be re-implementing of_read_number() in terms of of_read_number(). Wat!? > +static phys_addr_t ddw_memory_hotplug_max(void) > +{ > + phys_addr_t max_addr = memory_hotplug_max(); > + struct device_node *memory; > + > + for_each_node_by_type(memory, "memory") { > + unsigned long start, size; > + int ranges, n_mem_addr_cells, n_mem_size_cells, len; > + const __be32 *memcell_buf; > + > + memcell_buf = of_get_property(memory, "reg", &len); > + if (!memcell_buf || len <= 0) > + continue; > + > + n_mem_addr_cells = of_n_addr_cells(memory); > + n_mem_size_cells = of_n_size_cells(memory); > + > + /* ranges in cell */ > + ranges = (len >> 2) / (n_mem_addr_cells + n_mem_size_cells); > + > + /* these are order-sensitive, and modify the buffer pointer */ > + start = read_n_cells(n_mem_addr_cells, &memcell_buf); > + size = read_n_cells(n_mem_size_cells, &memcell_buf); > + > + max_addr = max_t(phys_addr_t, max_addr, start + size); > + } > + > + return max_addr; > +} Is there really no existing place we keep track of maxmimum possible memory address? > /* > * If the PE supports dynamic dma windows, and there is space for a table > * that can map all pages in a linear offset, then setup such a table, > @@ -1067,7 +1108,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn, > } > /* verify the window * number of ptes will map the partition */ > /* check largest block * page size > max memory hotplug addr */ > - max_addr = memory_hotplug_max(); > + max_addr = ddw_memory_hotplug_max(); > if (query.largest_available_block < (max_addr >> page_shift)) { > dev_dbg(&dev->dev, "can't map partition max 0x%llx with %u " > "%llu-sized pages\n", max_addr, query.largest_available_block, -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson