Hi Niklas, Thank you for the patch. On Thursday 21 January 2016 15:01:33 Niklas Söderlund wrote: > Enable slave transfers to devices behind IPMMU:s by mapping the slave > addresses using the dma-mapping API. > > Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@xxxxxxxxxxxx> > --- > drivers/dma/sh/rcar-dmac.c | 59 ++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 54 insertions(+), 5 deletions(-) > > diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c > index 743873c..f3ec8a6 100644 > --- a/drivers/dma/sh/rcar-dmac.c > +++ b/drivers/dma/sh/rcar-dmac.c > @@ -1106,21 +1106,70 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, > dma_addr_t buf_addr, return desc; > } > > +static int __rcar_dmac_device_config(struct dma_chan *chan, I'd call this rcar_dmac_set_slave_addr (or something similar) to make the purpose of the function more explicit. > + struct rcar_dmac_chan_slave *slave, > + phys_addr_t addr, size_t size, > + enum dma_data_direction dir, > + struct dma_attrs *attrs) > +{ > + struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan); You can pass rchan to the function directly and avoid this cast. > + struct page *page; > + size_t offset; > + > + /* unmap old */ The drivers capitalizes the first word of each sentence in comments and ends the sentences with a full stop. Could you please use the same style for consistency. > + if (slave->slave_addr) { In theory 0 is a valid address. There's unfortunately no standard way to set an address to an invalid value that can be later checked (DMA_ERROR_CODE isn't defined on all architectures and dma_mapping_error() has no set counterpart). I would use xfer_size instead of slave_addr to check whether the page has been mapped. > + dma_unmap_page_attrs(chan->device->dev, slave->slave_addr, > + slave->xfer_size, dir, attrs); > + slave->slave_addr = 0; > + slave->xfer_size = 0; > + } > + > + /* map new */ > + if (addr) { > + /* phys_to_page not available on all platforms */ > + page = pfn_to_page(addr >> PAGE_SHIFT); > + offset = addr - page_to_phys(page); How about just offset = addr & ~PAGE_MASK; It seems simpler to me. > + slave->slave_addr = dma_map_page_attrs(chan->device->dev, page, I'm still worried about passing a page pointer computed from an address that has no associated page structure. This issue can probably be addressed separately from this series, but I'd like to see at least a comment that mentions the problem here. > + offset, size, dir, attrs); > + > + if (dma_mapping_error(chan->device->dev, slave->slave_addr)) { > + dev_err(chan->device->dev, > + "chan%u: failed to map %zx@%pap", > + rchan->index, size, &addr); > + return -EIO; > + } > + > + slave->xfer_size = size; > + } > + > + return 0; > + > +} > + > static int rcar_dmac_device_config(struct dma_chan *chan, > struct dma_slave_config *cfg) > { > struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan); > + struct dma_attrs attrs; > + int ret; > > /* > * We could lock this, but you shouldn't be configuring the > * channel, while using it... > */ > - rchan->src.slave_addr = cfg->src_addr; > - rchan->dst.slave_addr = cfg->dst_addr; > - rchan->src.xfer_size = cfg->src_addr_width; > - rchan->dst.xfer_size = cfg->dst_addr_width; > > - return 0; > + init_dma_attrs(&attrs); > + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); > + dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs); > + > + ret = __rcar_dmac_device_config(chan, &rchan->src, cfg->src_addr, You're passing a dma_addr_t while the function expects a phys_addr_t. As you mentioned in the cover letter this has been discussed before without reaching any clear conclusion, we need to come to an agreement. > + cfg->src_addr_width, DMA_FROM_DEVICE, &attrs); > + if (!ret) > + return ret; > + > + ret = __rcar_dmac_device_config(chan, &rchan->dst, cfg->dst_addr, > + cfg->dst_addr_width, DMA_TO_DEVICE, &attrs); > + return ret; > } > > static int rcar_dmac_chan_terminate_all(struct dma_chan *chan) -- Regards, Laurent Pinchart