All of lore.kernel.org
 help / color / mirror / Atom feed
From: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
To: Frank Li <Frank.li@nxp.com>
Cc: "Jingoo Han" <jingoohan1@gmail.com>,
	"Gustavo Pimentel" <gustavo.pimentel@synopsys.com>,
	"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
	"Krzysztof Wilczyński" <kw@linux.com>,
	"Rob Herring" <robh@kernel.org>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Kishon Vijay Abraham I" <kishon@kernel.org>,
	linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] PCI: endpoint: Migrate to Genalloc framework for outbound window memory allocation
Date: Wed, 20 Mar 2024 11:40:34 +0530	[thread overview]
Message-ID: <20240320061034.GA2525@thinkpad> (raw)
In-Reply-To: <ZfnEz9w6ICZXFZeb@lizhi-Precision-Tower-5810>

On Tue, Mar 19, 2024 at 01:01:03PM -0400, Frank Li wrote:
> On Tue, Mar 19, 2024 at 09:58:29PM +0530, Manivannan Sadhasivam wrote:
> > On Tue, Mar 19, 2024 at 11:50:50AM -0400, Frank Li wrote:
> > > On Sun, Mar 17, 2024 at 11:39:17AM +0530, Manivannan Sadhasivam wrote:
> > > > As proposed during the last year 'PCI Endpoint Subsystem Open Items
> > > > Discussion' of Linux Plumbers conference [1], let's migrate to Genalloc
> > > > framework for managing the endpoint outbound window memory allocation.
> > > > 
> > > > PCI Endpoint subsystem is using a custom memory allocator in pci-epc-mem
> > > > driver from the start for managing the memory required to map the host
> > > > address space (outbound) in endpoint. Even though it works well, it
> > > > completely defeats the purpose of the 'Genalloc framework', a general
> > > > purpose memory allocator framework created to avoid various custom memory
> > > > allocators in the kernel.
> > > > 
> > > > The migration to Genalloc framework is done is such a way that the existing
> > > > API semantics are preserved. So that the callers of the EPC mem APIs do not
> > > > need any modification (apart from the pcie-designware-epc driver that
> > > > queries page size).
> > > > 
> > > > Internally, the EPC mem driver now uses Genalloc framework's
> > > > 'gen_pool_first_fit_order_align' algorithm that aligns the allocated memory
> > > > based on the requested size as like the previous allocator. And the
> > > > page size passed during pci_epc_mem_init() API is used as the minimum order
> > > > for the memory allocations.
> > > > 
> > > > During the migration, 'struct pci_epc_mem' is removed as it is seems
> > > > redundant and the existing 'struct pci_epc_mem_window' in 'struct pci_epc'
> > > > is now used to hold the address windows of the endpoint controller.
> > > > 
> > > > [1] https://lpc.events/event/17/contributions/1419/
> > > > 
> > > > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > > ---
> > > >  drivers/pci/controller/dwc/pcie-designware-ep.c |  14 +-
> > > >  drivers/pci/endpoint/pci-epc-mem.c              | 182 +++++++++---------------
> > > >  include/linux/pci-epc.h                         |  25 +---
> > > >  3 files changed, 81 insertions(+), 140 deletions(-)
> > > > 
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > > index 5befed2dc02b..37c612282eb6 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > > @@ -482,11 +482,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
> > > >  		reg = ep_func->msi_cap + PCI_MSI_DATA_32;
> > > >  		msg_data = dw_pcie_ep_readw_dbi(ep, func_no, reg);
> > > >  	}
> > > > -	aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
> > > > +	aligned_offset = msg_addr_lower & (epc->windows[0]->page_size - 1);
> > > >  	msg_addr = ((u64)msg_addr_upper) << 32 |
> > > >  			(msg_addr_lower & ~aligned_offset);
> > > >  	ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr,
> > > > -				  epc->mem->window.page_size);
> > > > +				  epc->windows[0]->page_size);
> > > >  	if (ret)
> > > >  		return ret;
> > > >  
> > > > @@ -550,10 +550,10 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
> > > >  		return -EPERM;
> > > >  	}
> > > >  
> > > > -	aligned_offset = msg_addr & (epc->mem->window.page_size - 1);
> > > > +	aligned_offset = msg_addr & (epc->windows[0]->page_size - 1);
> > > >  	msg_addr &= ~aligned_offset;
> > > >  	ret = dw_pcie_ep_map_addr(epc, func_no, 0, ep->msi_mem_phys, msg_addr,
> > > > -				  epc->mem->window.page_size);
> > > > +				  epc->windows[0]->page_size);
> > > >  	if (ret)
> > > >  		return ret;
> > > >  
> > > > @@ -572,7 +572,7 @@ void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
> > > >  	dw_pcie_edma_remove(pci);
> > > >  
> > > >  	pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
> > > > -			      epc->mem->window.page_size);
> > > > +			      epc->windows[0]->page_size);
> > > >  
> > > >  	pci_epc_mem_exit(epc);
> > > >  
> > > > @@ -742,7 +742,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> > > >  	}
> > > >  
> > > >  	ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
> > > > -					     epc->mem->window.page_size);
> > > > +					     epc->windows[0]->page_size);
> > > >  	if (!ep->msi_mem) {
> > > >  		ret = -ENOMEM;
> > > >  		dev_err(dev, "Failed to reserve memory for MSI/MSI-X\n");
> > > > @@ -770,7 +770,7 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> > > >  
> > > >  err_free_epc_mem:
> > > >  	pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
> > > > -			      epc->mem->window.page_size);
> > > > +			      epc->windows[0]->page_size);
> > > >  
> > > >  err_exit_epc_mem:
> > > >  	pci_epc_mem_exit(epc);
> > > > diff --git a/drivers/pci/endpoint/pci-epc-mem.c b/drivers/pci/endpoint/pci-epc-mem.c
> > > > index a9c028f58da1..f9e6e1a6aeaa 100644
> > > > --- a/drivers/pci/endpoint/pci-epc-mem.c
> > > > +++ b/drivers/pci/endpoint/pci-epc-mem.c
> > > > @@ -4,37 +4,18 @@
> > > >   *
> > > >   * Copyright (C) 2017 Texas Instruments
> > > >   * Author: Kishon Vijay Abraham I <kishon@ti.com>
> > > > + *
> > > > + * Copyright (C) 2024 Linaro Ltd.
> > > > + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > >   */
> > > >  
> > > > +#include <linux/genalloc.h>
> > > >  #include <linux/io.h>
> > > >  #include <linux/module.h>
> > > >  #include <linux/slab.h>
> > > >  
> > > >  #include <linux/pci-epc.h>
> > > >  
> > > > -/**
> > > > - * pci_epc_mem_get_order() - determine the allocation order of a memory size
> > > > - * @mem: address space of the endpoint controller
> > > > - * @size: the size for which to get the order
> > > > - *
> > > > - * Reimplement get_order() for mem->page_size since the generic get_order
> > > > - * always gets order with a constant PAGE_SIZE.
> > > > - */
> > > > -static int pci_epc_mem_get_order(struct pci_epc_mem *mem, size_t size)
> > > > -{
> > > > -	int order;
> > > > -	unsigned int page_shift = ilog2(mem->window.page_size);
> > > > -
> > > > -	size--;
> > > > -	size >>= page_shift;
> > > > -#if BITS_PER_LONG == 32
> > > > -	order = fls(size);
> > > > -#else
> > > > -	order = fls64(size);
> > > > -#endif
> > > > -	return order;
> > > > -}
> > > > -
> > > >  /**
> > > >   * pci_epc_multi_mem_init() - initialize the pci_epc_mem structure
> > > >   * @epc: the EPC device that invoked pci_epc_mem_init
> > > > @@ -48,17 +29,11 @@ int pci_epc_multi_mem_init(struct pci_epc *epc,
> > > >  			   struct pci_epc_mem_window *windows,
> > > >  			   unsigned int num_windows)
> > > >  {
> > > > -	struct pci_epc_mem *mem = NULL;
> > > > -	unsigned long *bitmap = NULL;
> > > > -	unsigned int page_shift;
> > > > +	struct pci_epc_mem_window *window = NULL;
> > > >  	size_t page_size;
> > > > -	int bitmap_size;
> > > > -	int pages;
> > > >  	int ret;
> > > >  	int i;
> > > >  
> > > > -	epc->num_windows = 0;
> > > > -
> > > >  	if (!windows || !num_windows)
> > > >  		return -EINVAL;
> > > >  
> > > > @@ -70,45 +45,51 @@ int pci_epc_multi_mem_init(struct pci_epc *epc,
> > > >  		page_size = windows[i].page_size;
> > > >  		if (page_size < PAGE_SIZE)
> > > >  			page_size = PAGE_SIZE;
> > > > -		page_shift = ilog2(page_size);
> > > > -		pages = windows[i].size >> page_shift;
> > > > -		bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
> > > >  
> > > > -		mem = kzalloc(sizeof(*mem), GFP_KERNEL);
> > > > -		if (!mem) {
> > > > +		windows[i].pool = gen_pool_create(ilog2(page_size), -1);
> > > 
> > > I think it is not good to modify caller's memory. This funciton suppose
> > > pass down read-only information. And set to epc->windows[i]. I think it'd
> > > better to use epc->windows[i].pool/windows.
> > > 
> > 
> > What do you mean by modifying caller's memory? Here, the memory for epc->windows
> > is being allocated and the pool is created for each window.
> 
> windows[i].pool = gen_pool_create(ilog2(page_size), -1)
> 
> 'windows' pass down from argument pci_epc_multi_mem_init(
> ..struct pci_epc_mem_window *windows, )
> 			     ^^^^^^^
> windows[i].pool = gen_pool_create() actually change the caller's stack
> memory.
> 

Hmm, you are right. Will fix it.

> > 
> > > > +		if (!windows[i].pool) {
> > > >  			ret = -ENOMEM;
> > > > -			i--;
> > > > -			goto err_mem;
> > > > +			goto err_free_mem;
> > > > +		}
> > > > +
> > > > +		gen_pool_set_algo(windows[i].pool, gen_pool_first_fit_order_align,
> > > > +				  NULL);
> > > > +
> > > > +		windows[i].virt_base = ioremap(windows[i].phys_base, windows[i].size);
> > > > +		ret = gen_pool_add_virt(windows[i].pool, (unsigned long)windows[i].virt_base,
> > > > +					windows[i].phys_base, windows[i].size, -1);
> > > > +		if (ret) {
> > > > +			iounmap(windows[i].virt_base);
> > > > +			gen_pool_destroy(epc->windows[i]->pool);
> > > 
> > > I think move all free to err path will be easy to understand.
> > > 
> > 
> > It is not straightforward. First we need to free the memory for current
> > iteration and then all previous iterations, that too from different places.
> > Moving the code to free current iteration to the error label will look messy.
> 
> All from current iteration.
> 
> err_free_mem:
>    iounmap(windows[i].virt_base);
>    if (epc->windows[i]->pool)
> 	gen_pool_destroy(epc->windows[i]->pool)

Initially I thought it would look messy if the memory for current iteration is
freed in the error labels. But now I implemented it and it doesn't look that
bad. So will change it in next iteration.

> 
> > 
> > > > +			goto err_free_mem;
> > > >  		}
> > > >  
> > > > -		bitmap = kzalloc(bitmap_size, GFP_KERNEL);
> > > > -		if (!bitmap) {
> > > > +		window = kzalloc(sizeof(*window), GFP_KERNEL);
> > > 
> > > According to below code                                                    
> > >                                                                            
> > >         epc->windows = kcalloc(num_windows, sizeof(*epc->windows), GFP_KERNEL);
> > >         if (!epc->windows)                                                 
> > >                 return -ENOMEM;                                            
> > >                                                                            
> > > epc->windows already allocate whole num_windows * "struct pci_epc_mem_window".
> > > I think you can direct use 'window = epc->windows + i', so needn't alloc      
> > > additional memory for epc->windows[i].
> > > 
> > 
> > First we are allocating the memory for 'struct pci_epc_mem_window' _pointers_ in
> > epc->windows. Then we need to allocate memory for each pointer in epc->windows
> > to actually store data. Otherwise, we will be referencing the nulll pointer.
> 
> I think two layer pointer is totally unecessary.
> You can use one layer pointer 'struct pci_epc_mem_window       *windows;'
> 

How can you store multiple 'struct pci_epc_mem_window' with a single pointer?
Please elaborate.

- Mani

-- 
மணிவண்ணன் சதாசிவம்

  reply	other threads:[~2024-03-20  6:10 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-17  6:09 [PATCH] PCI: endpoint: Migrate to Genalloc framework for outbound window memory allocation Manivannan Sadhasivam
2024-03-18 17:08 ` Bjorn Helgaas
2024-03-19 14:35   ` Manivannan Sadhasivam
2024-03-19 15:50 ` Frank Li
2024-03-19 16:16   ` Frank Li
2024-03-19 16:28   ` Manivannan Sadhasivam
2024-03-19 17:01     ` Frank Li
2024-03-20  6:10       ` Manivannan Sadhasivam [this message]
2024-03-20 14:26         ` Frank Li
2024-03-20  9:56 ` Kishon Vijay Abraham I
2024-03-20 11:29   ` Manivannan Sadhasivam
2024-04-14 13:00     ` Manivannan Sadhasivam
2024-04-18  4:44       ` Kishon Vijay Abraham I
2024-04-18  5:24         ` Manivannan Sadhasivam
2024-04-24 14:23           ` Kishon Vijay Abraham I

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240320061034.GA2525@thinkpad \
    --to=manivannan.sadhasivam@linaro.org \
    --cc=Frank.li@nxp.com \
    --cc=bhelgaas@google.com \
    --cc=gustavo.pimentel@synopsys.com \
    --cc=jingoohan1@gmail.com \
    --cc=kishon@kernel.org \
    --cc=kw@linux.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lpieralisi@kernel.org \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.