Re: [PATCH v2 2/3] media: ipu6: optimize the IPU6 MMU mapping flow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Bingbu,

On Mon, Nov 04, 2024 at 12:04:29PM +0800, Bingbu Cao wrote:
> Sakari,
> 
> On 11/1/24 9:16 PM, Sakari Ailus wrote:
> > Hi Bingbu,
> > 
> > Thanks for the update.
> > 
> > On Fri, Oct 25, 2024 at 01:52:31PM +0800, Bingbu Cao wrote:
> >> ipu6_mmu_map() operated on a per-page basis, it leads frequent
> >> spin_lock/unlock() and clflush_cache_range() for each page, it
> >> will cause inefficiencies especially when handling dma-bufs
> >> with large number of pages. However, the pages are likely concentrated
> >> pages by IOMMU DMA driver, IPU MMU driver can map the concentrated
> >> pages into less entries in l1 table.
> >>
> >> This change enhances ipu6_mmu_map() with batching process multiple
> >> contiguous pages. It significantly reduces calls for spin_lock/unlock
> >> and clflush_cache_range() and improve the performance.
> >>
> >> Signed-off-by: Bingbu Cao <bingbu.cao@xxxxxxxxx>
> >> Signed-off-by: Jianhui Dai <jianhui.j.dai@xxxxxxxxx>
> >> ---
> >>  drivers/media/pci/intel/ipu6/ipu6-mmu.c | 144 +++++++++++++++-----------------
> >>  1 file changed, 69 insertions(+), 75 deletions(-)
> >>
> >> diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
> >> index 9ea6789bca5e..e957ccb4691d 100644
> >> --- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
> >> +++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
> >> @@ -295,72 +295,90 @@ static size_t l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
> >>  static int l2_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
> >>  		  phys_addr_t paddr, size_t size)
> >>  {
> >> -	u32 l1_idx = iova >> ISP_L1PT_SHIFT;
> >> -	u32 iova_start = iova;
> >> +	struct device *dev = mmu_info->dev;
> >> +	unsigned int l2_entries;
> >>  	u32 *l2_pt, *l2_virt;
> >>  	unsigned int l2_idx;
> >>  	unsigned long flags;
> >> +	size_t mapped = 0;
> >>  	dma_addr_t dma;
> >>  	u32 l1_entry;
> >> -
> >> -	dev_dbg(mmu_info->dev,
> >> -		"mapping l2 page table for l1 index %u (iova %8.8x)\n",
> >> -		l1_idx, (u32)iova);
> >> +	u32 l1_idx;
> >> +	int err = 0;
> >>  
> >>  	spin_lock_irqsave(&mmu_info->lock, flags);
> >> -	l1_entry = mmu_info->l1_pt[l1_idx];
> >> -	if (l1_entry == mmu_info->dummy_l2_pteval) {
> >> -		l2_virt = mmu_info->l2_pts[l1_idx];
> >> -		if (likely(!l2_virt)) {
> >> -			l2_virt = alloc_l2_pt(mmu_info);
> >> -			if (!l2_virt) {
> >> -				spin_unlock_irqrestore(&mmu_info->lock, flags);
> >> -				return -ENOMEM;
> >> -			}
> >> -		}
> >> -
> >> -		dma = map_single(mmu_info, l2_virt);
> >> -		if (!dma) {
> >> -			dev_err(mmu_info->dev, "Failed to map l2pt page\n");
> >> -			free_page((unsigned long)l2_virt);
> >> -			spin_unlock_irqrestore(&mmu_info->lock, flags);
> >> -			return -EINVAL;
> >> -		}
> >> -
> >> -		l1_entry = dma >> ISP_PADDR_SHIFT;
> >> -
> >> -		dev_dbg(mmu_info->dev, "page for l1_idx %u %p allocated\n",
> >> -			l1_idx, l2_virt);
> >> -		mmu_info->l1_pt[l1_idx] = l1_entry;
> >> -		mmu_info->l2_pts[l1_idx] = l2_virt;
> >> -		clflush_cache_range((void *)&mmu_info->l1_pt[l1_idx],
> >> -				    sizeof(mmu_info->l1_pt[l1_idx]));
> >> -	}
> >> -
> >> -	l2_pt = mmu_info->l2_pts[l1_idx];
> >> -
> >> -	dev_dbg(mmu_info->dev, "l2_pt at %p with dma 0x%x\n", l2_pt, l1_entry);
> >>  
> >>  	paddr = ALIGN(paddr, ISP_PAGE_SIZE);
> >> +	for (l1_idx = iova >> ISP_L1PT_SHIFT;
> >> +	     size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) {
> >> +		dev_dbg(dev,
> >> +			"mapping l2 page table for l1 index %u (iova %8.8x)\n",
> >> +			l1_idx, (u32)iova);
> >>  
> >> -	l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
> >> +		l1_entry = mmu_info->l1_pt[l1_idx];
> >> +		if (l1_entry == mmu_info->dummy_l2_pteval) {
> >> +			l2_virt = mmu_info->l2_pts[l1_idx];
> >> +			if (likely(!l2_virt)) {
> > 
> > likely() should only be used if it's really, really uncommon on a hot path.
> > I don't think that's the case here.
> > 
> > Can it even happen l2_virt is NULL here? l1_entry has been assigned while
> > the l2 PT page has been mapped so both are either dummy / NULL or valid
> > values. The l2 pages aren't unmapped in unmap, but only in
> > ipu6_mmu_destroy(). Same goes for the map_single() if l2_virt was valid
> > already, the page has been mapped, too.
> > 
> > This seems like a pre-existing problem. If there is no actual bug here but
> > just inconsistent implementation (so it would seem), I think it's fine to
> > address this on top.
> > 
> > Can you conform this?
> 
> I would like to address this in another patch instead of this series.
> What do you think?

Works for me.

-- 
Sakari Ailus




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux