diff mbox

[v8,6/9] pci: Introduce a domain number for pci_host_bridge.

Message ID 1404240214-9804-7-git-send-email-Liviu.Dudau@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Liviu Dudau July 1, 2014, 6:43 p.m. UTC
Make it easier to discover the domain number of a bus by storing
the number in pci_host_bridge for the root bus. Several architectures
have their own way of storing this information, so it makes sense
to try to unify the code. While at this, add a new function that
creates a root bus in a given domain and make pci_create_root_bus()
a wrapper around this function.

Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
Tested-by: Tanmay Inamdar <tinamdar@apm.com>
---
 drivers/pci/probe.c | 41 +++++++++++++++++++++++++++++++++--------
 include/linux/pci.h |  4 ++++
 2 files changed, 37 insertions(+), 8 deletions(-)

Comments

Bjorn Helgaas July 8, 2014, 12:59 a.m. UTC | #1
On Tue, Jul 01, 2014 at 07:43:31PM +0100, Liviu Dudau wrote:
> Make it easier to discover the domain number of a bus by storing
> the number in pci_host_bridge for the root bus. Several architectures
> have their own way of storing this information, so it makes sense
> to try to unify the code. While at this, add a new function that
> creates a root bus in a given domain and make pci_create_root_bus()
> a wrapper around this function.

"While at this" is always a good clue that maybe something should be
split into a separate patch :)  This is a very good example, since it
adds a new interface that deserves its own changelog.

> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> Tested-by: Tanmay Inamdar <tinamdar@apm.com>
> ---
>  drivers/pci/probe.c | 41 +++++++++++++++++++++++++++++++++--------
>  include/linux/pci.h |  4 ++++
>  2 files changed, 37 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 2c92662..abf5e82 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -1748,8 +1748,9 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
>  {
>  }
>  
> -struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> -		struct pci_ops *ops, void *sysdata, struct list_head *resources)
> +struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
> +		int domain, int bus, struct pci_ops *ops, void *sysdata,
> +		struct list_head *resources)

I don't think we should do it this way; this makes it possible to have a
host bridge where "bridge->domain_nr != pci_domain_nr(bridge->bus)".

I wonder if it would help to make a weak pci_domain_nr() function that
returns "bridge->domain_nr".  Then each arch could individually drop its
pci_domain_nr() definition as it was converted, e.g., something like this:

  - Convert every arch pci_domain_nr() from a #define to a non-inline
    function
  - Add bridge.domain_nr, initialized from pci_domain_nr()
  - Add a weak generic pci_domain_nr() that returns bridge.domain_nr
  - Add a way to create a host bridge in a specified domain, so we can
    initialize bridge.domain_nr without using pci_domain_nr()
  - Convert each arch to use the new creation mechanism and drop its
    pci_domain_nr() implementation

>  {
>  	int error;
>  	struct pci_host_bridge *bridge;
> @@ -1762,27 +1763,31 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
>  
>  	bridge = pci_alloc_host_bridge();
>  	if (!bridge)
> -		return NULL;
> +		return ERR_PTR(-ENOMEM);
>  
>  	bridge->dev.parent = parent;
>  	bridge->dev.release = pci_release_host_bridge_dev;
> +	bridge->domain_nr = domain;
>  
>  	b = pci_alloc_bus();
> -	if (!b)
> +	if (!b) {
> +		error = -ENOMEM;
>  		goto err_out;
> +	}
>  
>  	b->sysdata = sysdata;
>  	b->ops = ops;
>  	b->number = b->busn_res.start = bus;
> -	b2 = pci_find_bus(pci_domain_nr(b), bus);
> +	b2 = pci_find_bus(bridge->domain_nr, bus);
>  	if (b2) {
>  		/* If we already got to this bus through a different bridge, ignore it */
>  		dev_dbg(&b2->dev, "bus already known\n");
> +		error = -EEXIST;
>  		goto err_bus_out;
>  	}
>  
>  	bridge->bus = b;
> -	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
> +	dev_set_name(&bridge->dev, "pci%04x:%02x", bridge->domain_nr, bus);
>  	error = pcibios_root_bridge_prepare(bridge);
>  	if (error)
>  		goto err_out;
> @@ -1801,7 +1806,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
>  
>  	b->dev.class = &pcibus_class;
>  	b->dev.parent = b->bridge;
> -	dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
> +	dev_set_name(&b->dev, "%04x:%02x", bridge->domain_nr, bus);
>  	error = device_register(&b->dev);
>  	if (error)
>  		goto class_dev_reg_err;
> @@ -1851,7 +1856,27 @@ err_bus_out:
>  	kfree(b);
>  err_out:
>  	kfree(bridge);
> -	return NULL;
> +	return ERR_PTR(error);
> +}
> +
> +struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> +		struct pci_ops *ops, void *sysdata, struct list_head *resources)
> +{
> +	int domain_nr;
> +	struct pci_bus *b = pci_alloc_bus();
> +	if (!b)
> +		return NULL;
> +
> +	b->sysdata = sysdata;
> +	domain_nr = pci_domain_nr(b);
> +	kfree(b);
> +
> +	b = pci_create_root_bus_in_domain(parent, domain_nr, bus,
> +				ops, sysdata, resources);
> +	if (IS_ERR(b))
> +		return NULL;
> +
> +	return b;
>  }
>  
>  int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 466bcd1..7e7b939 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -401,6 +401,7 @@ struct pci_host_bridge_window {
>  struct pci_host_bridge {
>  	struct device dev;
>  	struct pci_bus *bus;		/* root bus */
> +	int domain_nr;
>  	struct list_head windows;	/* pci_host_bridge_windows */
>  	void (*release_fn)(struct pci_host_bridge *);
>  	void *release_data;
> @@ -769,6 +770,9 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
>  struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
>  				    struct pci_ops *ops, void *sysdata,
>  				    struct list_head *resources);
> +struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
> +			int domain, int bus, struct pci_ops *ops,
> +			void *sysdata, struct list_head *resources);
>  int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
>  int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
>  void pci_bus_release_busn_res(struct pci_bus *b);
> -- 
> 2.0.0
>
Liviu Dudau July 8, 2014, 10:46 a.m. UTC | #2
On Tue, Jul 08, 2014 at 01:59:54AM +0100, Bjorn Helgaas wrote:
> On Tue, Jul 01, 2014 at 07:43:31PM +0100, Liviu Dudau wrote:
> > Make it easier to discover the domain number of a bus by storing
> > the number in pci_host_bridge for the root bus. Several architectures
> > have their own way of storing this information, so it makes sense
> > to try to unify the code. While at this, add a new function that
> > creates a root bus in a given domain and make pci_create_root_bus()
> > a wrapper around this function.
> 
> "While at this" is always a good clue that maybe something should be
> split into a separate patch :)  This is a very good example, since it
> adds a new interface that deserves its own changelog.

Yes, I'm coming to the same conclusion. :)

> 
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > Tested-by: Tanmay Inamdar <tinamdar@apm.com>
> > ---
> >  drivers/pci/probe.c | 41 +++++++++++++++++++++++++++++++++--------
> >  include/linux/pci.h |  4 ++++
> >  2 files changed, 37 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> > index 2c92662..abf5e82 100644
> > --- a/drivers/pci/probe.c
> > +++ b/drivers/pci/probe.c
> > @@ -1748,8 +1748,9 @@ void __weak pcibios_remove_bus(struct pci_bus *bus)
> >  {
> >  }
> >  
> > -struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> > -		struct pci_ops *ops, void *sysdata, struct list_head *resources)
> > +struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
> > +		int domain, int bus, struct pci_ops *ops, void *sysdata,
> > +		struct list_head *resources)
> 
> I don't think we should do it this way; this makes it possible to have a
> host bridge where "bridge->domain_nr != pci_domain_nr(bridge->bus)".
> 
> I wonder if it would help to make a weak pci_domain_nr() function that
> returns "bridge->domain_nr".  Then each arch could individually drop its
> pci_domain_nr() definition as it was converted, e.g., something like this:
> 
>   - Convert every arch pci_domain_nr() from a #define to a non-inline
>     function
>   - Add bridge.domain_nr, initialized from pci_domain_nr()
>   - Add a weak generic pci_domain_nr() that returns bridge.domain_nr
>   - Add a way to create a host bridge in a specified domain, so we can
>     initialize bridge.domain_nr without using pci_domain_nr()
>   - Convert each arch to use the new creation mechanism and drop its
>     pci_domain_nr() implementation

I will try to propose a patch implementing this.

Best regards,
Liviu

> 
> >  {
> >  	int error;
> >  	struct pci_host_bridge *bridge;
> > @@ -1762,27 +1763,31 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> >  
> >  	bridge = pci_alloc_host_bridge();
> >  	if (!bridge)
> > -		return NULL;
> > +		return ERR_PTR(-ENOMEM);
> >  
> >  	bridge->dev.parent = parent;
> >  	bridge->dev.release = pci_release_host_bridge_dev;
> > +	bridge->domain_nr = domain;
> >  
> >  	b = pci_alloc_bus();
> > -	if (!b)
> > +	if (!b) {
> > +		error = -ENOMEM;
> >  		goto err_out;
> > +	}
> >  
> >  	b->sysdata = sysdata;
> >  	b->ops = ops;
> >  	b->number = b->busn_res.start = bus;
> > -	b2 = pci_find_bus(pci_domain_nr(b), bus);
> > +	b2 = pci_find_bus(bridge->domain_nr, bus);
> >  	if (b2) {
> >  		/* If we already got to this bus through a different bridge, ignore it */
> >  		dev_dbg(&b2->dev, "bus already known\n");
> > +		error = -EEXIST;
> >  		goto err_bus_out;
> >  	}
> >  
> >  	bridge->bus = b;
> > -	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
> > +	dev_set_name(&bridge->dev, "pci%04x:%02x", bridge->domain_nr, bus);
> >  	error = pcibios_root_bridge_prepare(bridge);
> >  	if (error)
> >  		goto err_out;
> > @@ -1801,7 +1806,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> >  
> >  	b->dev.class = &pcibus_class;
> >  	b->dev.parent = b->bridge;
> > -	dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
> > +	dev_set_name(&b->dev, "%04x:%02x", bridge->domain_nr, bus);
> >  	error = device_register(&b->dev);
> >  	if (error)
> >  		goto class_dev_reg_err;
> > @@ -1851,7 +1856,27 @@ err_bus_out:
> >  	kfree(b);
> >  err_out:
> >  	kfree(bridge);
> > -	return NULL;
> > +	return ERR_PTR(error);
> > +}
> > +
> > +struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> > +		struct pci_ops *ops, void *sysdata, struct list_head *resources)
> > +{
> > +	int domain_nr;
> > +	struct pci_bus *b = pci_alloc_bus();
> > +	if (!b)
> > +		return NULL;
> > +
> > +	b->sysdata = sysdata;
> > +	domain_nr = pci_domain_nr(b);
> > +	kfree(b);
> > +
> > +	b = pci_create_root_bus_in_domain(parent, domain_nr, bus,
> > +				ops, sysdata, resources);
> > +	if (IS_ERR(b))
> > +		return NULL;
> > +
> > +	return b;
> >  }
> >  
> >  int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
> > diff --git a/include/linux/pci.h b/include/linux/pci.h
> > index 466bcd1..7e7b939 100644
> > --- a/include/linux/pci.h
> > +++ b/include/linux/pci.h
> > @@ -401,6 +401,7 @@ struct pci_host_bridge_window {
> >  struct pci_host_bridge {
> >  	struct device dev;
> >  	struct pci_bus *bus;		/* root bus */
> > +	int domain_nr;
> >  	struct list_head windows;	/* pci_host_bridge_windows */
> >  	void (*release_fn)(struct pci_host_bridge *);
> >  	void *release_data;
> > @@ -769,6 +770,9 @@ struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
> >  struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
> >  				    struct pci_ops *ops, void *sysdata,
> >  				    struct list_head *resources);
> > +struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
> > +			int domain, int bus, struct pci_ops *ops,
> > +			void *sysdata, struct list_head *resources);
> >  int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
> >  int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
> >  void pci_bus_release_busn_res(struct pci_bus *b);
> > -- 
> > 2.0.0
> > 
>
Bjorn Helgaas July 8, 2014, 6:41 p.m. UTC | #3
On Tue, Jul 8, 2014 at 4:46 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> On Tue, Jul 08, 2014 at 01:59:54AM +0100, Bjorn Helgaas wrote:

>> I wonder if it would help to make a weak pci_domain_nr() function that
>> returns "bridge->domain_nr".  Then each arch could individually drop its
>> pci_domain_nr() definition as it was converted, e.g., something like this:
>>
>>   - Convert every arch pci_domain_nr() from a #define to a non-inline
>>     function
>>   - Add bridge.domain_nr, initialized from pci_domain_nr()
>>   - Add a weak generic pci_domain_nr() that returns bridge.domain_nr
>>   - Add a way to create a host bridge in a specified domain, so we can
>>     initialize bridge.domain_nr without using pci_domain_nr()
>>   - Convert each arch to use the new creation mechanism and drop its
>>     pci_domain_nr() implementation
>
> I will try to propose a patch implementing this.

I think this is more of an extra credit, cleanup sort of thing.  I
don't think it advances your primary goal of (I think) getting arm64
PCI support in.  So my advice is to not worry about unifying domain
handling until later.

Bjorn
Liviu Dudau July 8, 2014, 10:48 p.m. UTC | #4
On Tue, Jul 08, 2014 at 07:41:50PM +0100, Bjorn Helgaas wrote:
> On Tue, Jul 8, 2014 at 4:46 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> > On Tue, Jul 08, 2014 at 01:59:54AM +0100, Bjorn Helgaas wrote:
> 
> >> I wonder if it would help to make a weak pci_domain_nr() function that
> >> returns "bridge->domain_nr".  Then each arch could individually drop its
> >> pci_domain_nr() definition as it was converted, e.g., something like this:
> >>
> >>   - Convert every arch pci_domain_nr() from a #define to a non-inline
> >>     function
> >>   - Add bridge.domain_nr, initialized from pci_domain_nr()
> >>   - Add a weak generic pci_domain_nr() that returns bridge.domain_nr
> >>   - Add a way to create a host bridge in a specified domain, so we can
> >>     initialize bridge.domain_nr without using pci_domain_nr()
> >>   - Convert each arch to use the new creation mechanism and drop its
> >>     pci_domain_nr() implementation
> >
> > I will try to propose a patch implementing this.
> 
> I think this is more of an extra credit, cleanup sort of thing.  I
> don't think it advances your primary goal of (I think) getting arm64
> PCI support in.  So my advice is to not worry about unifying domain
> handling until later.

Getting arm64 supported *is* my main goal. But like you have stated in your
review of v7, you wanted to see another architecture converted as a guarantee
of "genericity" (for lack of a better word) for my patches. The one architecture
I've set my eyes on is microblaze, and that one uses pci_scan_root_bus()
rather than pci_create_root_bus() so I don't have any opportunity to pass the
domain number or any additional info (like the sysdata pointer that we were
talking about) to the pci_host_bridge structure unless I do this cleanup.

Best regards,
Liviu


> 
> Bjorn
>
Bjorn Helgaas July 9, 2014, 3:10 p.m. UTC | #5
On Tue, Jul 8, 2014 at 4:48 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> On Tue, Jul 08, 2014 at 07:41:50PM +0100, Bjorn Helgaas wrote:
>> On Tue, Jul 8, 2014 at 4:46 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
>> > On Tue, Jul 08, 2014 at 01:59:54AM +0100, Bjorn Helgaas wrote:
>>
>> >> I wonder if it would help to make a weak pci_domain_nr() function that
>> >> returns "bridge->domain_nr".  Then each arch could individually drop its
>> >> pci_domain_nr() definition as it was converted, e.g., something like this:
>> >>
>> >>   - Convert every arch pci_domain_nr() from a #define to a non-inline
>> >>     function
>> >>   - Add bridge.domain_nr, initialized from pci_domain_nr()
>> >>   - Add a weak generic pci_domain_nr() that returns bridge.domain_nr
>> >>   - Add a way to create a host bridge in a specified domain, so we can
>> >>     initialize bridge.domain_nr without using pci_domain_nr()
>> >>   - Convert each arch to use the new creation mechanism and drop its
>> >>     pci_domain_nr() implementation
>> >
>> > I will try to propose a patch implementing this.
>>
>> I think this is more of an extra credit, cleanup sort of thing.  I
>> don't think it advances your primary goal of (I think) getting arm64
>> PCI support in.  So my advice is to not worry about unifying domain
>> handling until later.
>
> Getting arm64 supported *is* my main goal. But like you have stated in your
> review of v7, you wanted to see another architecture converted as a guarantee
> of "genericity" (for lack of a better word) for my patches. The one architecture
> I've set my eyes on is microblaze, and that one uses pci_scan_root_bus()
> rather than pci_create_root_bus() so I don't have any opportunity to pass the
> domain number or any additional info (like the sysdata pointer that we were
> talking about) to the pci_host_bridge structure unless I do this cleanup.

I think maybe I was too harsh about that, or maybe we had different
ideas about what "conversion" involved.  My comment was in response to
"pci: Introduce pci_register_io_range() helper function", and I don't
remember why I was concerned about that; it's not even in drivers/pci,
and it doesn't have an obvious connection to putting the domain number
in struct pci_host_bridge.

The thing I'm more concerned about is adding new PCI interfaces, e.g.,
pci_create_root_bus_in_domain(), that are only used by one
architecture.  Then it's hard to be sure that it's going to be useful
for other arches.  If you can add arm64 using the existing PCI
interfaces, I don't any problem with that.

Bjorn
Liviu Dudau July 10, 2014, 9:47 a.m. UTC | #6
On Wed, Jul 09, 2014 at 04:10:04PM +0100, Bjorn Helgaas wrote:
> On Tue, Jul 8, 2014 at 4:48 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> > On Tue, Jul 08, 2014 at 07:41:50PM +0100, Bjorn Helgaas wrote:
> >> On Tue, Jul 8, 2014 at 4:46 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> >> > On Tue, Jul 08, 2014 at 01:59:54AM +0100, Bjorn Helgaas wrote:
> >>
> >> >> I wonder if it would help to make a weak pci_domain_nr() function that
> >> >> returns "bridge->domain_nr".  Then each arch could individually drop its
> >> >> pci_domain_nr() definition as it was converted, e.g., something like this:
> >> >>
> >> >>   - Convert every arch pci_domain_nr() from a #define to a non-inline
> >> >>     function
> >> >>   - Add bridge.domain_nr, initialized from pci_domain_nr()
> >> >>   - Add a weak generic pci_domain_nr() that returns bridge.domain_nr
> >> >>   - Add a way to create a host bridge in a specified domain, so we can
> >> >>     initialize bridge.domain_nr without using pci_domain_nr()
> >> >>   - Convert each arch to use the new creation mechanism and drop its
> >> >>     pci_domain_nr() implementation
> >> >
> >> > I will try to propose a patch implementing this.
> >>
> >> I think this is more of an extra credit, cleanup sort of thing.  I
> >> don't think it advances your primary goal of (I think) getting arm64
> >> PCI support in.  So my advice is to not worry about unifying domain
> >> handling until later.
> >
> > Getting arm64 supported *is* my main goal. But like you have stated in your
> > review of v7, you wanted to see another architecture converted as a guarantee
> > of "genericity" (for lack of a better word) for my patches. The one architecture
> > I've set my eyes on is microblaze, and that one uses pci_scan_root_bus()
> > rather than pci_create_root_bus() so I don't have any opportunity to pass the
> > domain number or any additional info (like the sysdata pointer that we were
> > talking about) to the pci_host_bridge structure unless I do this cleanup.
> 
> I think maybe I was too harsh about that, or maybe we had different
> ideas about what "conversion" involved.  My comment was in response to
> "pci: Introduce pci_register_io_range() helper function", and I don't
> remember why I was concerned about that; it's not even in drivers/pci,
> and it doesn't have an obvious connection to putting the domain number
> in struct pci_host_bridge.

Well, to be honest I did move some of the code (as mentioned in the Changelog) from
drivers/pci into drivers/of. It makes more sense to be in OF, as it mostly concerns
architectures that use it.

> 
> The thing I'm more concerned about is adding new PCI interfaces, e.g.,
> pci_create_root_bus_in_domain(), that are only used by one
> architecture.  Then it's hard to be sure that it's going to be useful
> for other arches.  If you can add arm64 using the existing PCI
> interfaces, I don't any problem with that.

(No blame here or reproaches, I'm just restating the situation:) I (mostly) did try
that in my v7 series but it also got NAK-ed by Arnd and Catalin as it had too much
arm64 specific code in there.

I don't see a way out of adding new PCI interfaces if we want to have support in
the PCI framework for unifying existing architectures. Of course, there is the painful
alternative of changing the existing APIs and fixing arches in one go, but like you've
said is going to be messy. I don't think I (or the people and companies wanting PCIe
on arm64) should cop out and pick a quick fix that adds sysdata structure into arm64
just to avoid new APIs, as this is not going to help anyone in long term. What I can
do is to create a set of parallel APIs for pci_{scan,create}_root_bus() that take
a pci_host_bridge pointer and start converting architectures one by one to that API
while deprecating the existing one. That way we can add arm64 easily as it would be
the first architecture to use new code without breaking things *and* we provide a
migration path.

Best regards,
Liviu

> 
> Bjorn
>
Bjorn Helgaas July 10, 2014, 10:36 p.m. UTC | #7
On Thu, Jul 10, 2014 at 3:47 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:

> I don't see a way out of adding new PCI interfaces if we want to have support in
> the PCI framework for unifying existing architectures. Of course, there is the painful
> alternative of changing the existing APIs and fixing arches in one go, but like you've
> said is going to be messy. I don't think I (or the people and companies wanting PCIe
> on arm64) should cop out and pick a quick fix that adds sysdata structure into arm64
> just to avoid new APIs, as this is not going to help anyone in long term. What I can
> do is to create a set of parallel APIs for pci_{scan,create}_root_bus() that take
> a pci_host_bridge pointer and start converting architectures one by one to that API
> while deprecating the existing one. That way we can add arm64 easily as it would be
> the first architecture to use new code without breaking things *and* we provide a
> migration path.

A lot of the v7 discussion was about pci_register_io_range().  I
apologize, because I think I really derailed things there and it was
unwarranted.  Arnd was right that migrating other arches should be a
separate effort.  I *think* I was probably thinking about the proposal
of adding pci_create_root_bus_in_domain(), and my reservations about
that got transferred to the pci_register_io_range() discussion.  In
any case, I'm completely fine with pci_register_io_range() now.

Most of the rest of the v7 discussion was about "Introduce a domain
number for pci_host_bridge."  I think we should add arm64 using the
existing pci_scan_root_bus() and keep the domain number in the arm64
sysdata structure like every other arch does.  Isn't that feasible?
We can worry about domain unification later.

I haven't followed closely enough to know what other objections people had.

Bjorn
Liviu Dudau July 11, 2014, 9:30 a.m. UTC | #8
On Thu, Jul 10, 2014 at 11:36:10PM +0100, Bjorn Helgaas wrote:
> On Thu, Jul 10, 2014 at 3:47 AM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> 
> > I don't see a way out of adding new PCI interfaces if we want to have support in
> > the PCI framework for unifying existing architectures. Of course, there is the painful
> > alternative of changing the existing APIs and fixing arches in one go, but like you've
> > said is going to be messy. I don't think I (or the people and companies wanting PCIe
> > on arm64) should cop out and pick a quick fix that adds sysdata structure into arm64
> > just to avoid new APIs, as this is not going to help anyone in long term. What I can
> > do is to create a set of parallel APIs for pci_{scan,create}_root_bus() that take
> > a pci_host_bridge pointer and start converting architectures one by one to that API
> > while deprecating the existing one. That way we can add arm64 easily as it would be
> > the first architecture to use new code without breaking things *and* we provide a
> > migration path.
> 
> A lot of the v7 discussion was about pci_register_io_range().  I
> apologize, because I think I really derailed things there and it was
> unwarranted.  Arnd was right that migrating other arches should be a
> separate effort.  I *think* I was probably thinking about the proposal
> of adding pci_create_root_bus_in_domain(), and my reservations about
> that got transferred to the pci_register_io_range() discussion.  In
> any case, I'm completely fine with pci_register_io_range() now.
> 
> Most of the rest of the v7 discussion was about "Introduce a domain
> number for pci_host_bridge."  I think we should add arm64 using the
> existing pci_scan_root_bus() and keep the domain number in the arm64
> sysdata structure like every other arch does.  Isn't that feasible?
> We can worry about domain unification later.

Thanks!

I'm really not that keen to add sysdata support in the arch code as it
requires initialisation code that I have tried to eliminate. What I'm
going to suggest for my v9 is a parallel set of APIs that arm64 will
be the first to use without changing the existing pci_{scan,create}_bus()
functions and then the conversion process will migrate arches to the new API.

Best regards,
Liviu

> 
> I haven't followed closely enough to know what other objections people had.
> 
> Bjorn
>
Catalin Marinas July 11, 2014, 2:11 p.m. UTC | #9
On Thu, Jul 10, 2014 at 11:36:10PM +0100, Bjorn Helgaas wrote:
> Most of the rest of the v7 discussion was about "Introduce a domain
> number for pci_host_bridge."  I think we should add arm64 using the
> existing pci_scan_root_bus() and keep the domain number in the arm64
> sysdata structure like every other arch does.  Isn't that feasible?
> We can worry about domain unification later.

I think that's what we were trying to avoid, adding an arm64-specific
pci_sys_data structure (and arm64-specific API). IIUC, avoiding this
would allow the host controller drivers to use the sysdata pointer for
their own private data structures.

Also since you can specify the domain number via DT (and in Liviu's
v8 patches read by of_create_pci_host_bridge), I think it would make
sense to have it stored in some generic data structures (e.g.
pci_host_bridge) rather than in an arm64 private sysdata.

(Liviu is thinking of an alternative API but maybe he could briefly
describe it here before posting a new series)
Liviu Dudau July 11, 2014, 3:08 p.m. UTC | #10
On Fri, Jul 11, 2014 at 03:11:16PM +0100, Catalin Marinas wrote:
> On Thu, Jul 10, 2014 at 11:36:10PM +0100, Bjorn Helgaas wrote:
> > Most of the rest of the v7 discussion was about "Introduce a domain
> > number for pci_host_bridge."  I think we should add arm64 using the
> > existing pci_scan_root_bus() and keep the domain number in the arm64
> > sysdata structure like every other arch does.  Isn't that feasible?
> > We can worry about domain unification later.
> 
> I think that's what we were trying to avoid, adding an arm64-specific
> pci_sys_data structure (and arm64-specific API). IIUC, avoiding this
> would allow the host controller drivers to use the sysdata pointer for
> their own private data structures.
> 
> Also since you can specify the domain number via DT (and in Liviu's
> v8 patches read by of_create_pci_host_bridge), I think it would make
> sense to have it stored in some generic data structures (e.g.
> pci_host_bridge) rather than in an arm64 private sysdata.
> 
> (Liviu is thinking of an alternative API but maybe he could briefly
> describe it here before posting a new series)
> 
> -- 
> Catalin


My plan is to keep the domain number in the pci_host_bridge and split
the creation of the pci_host_bridge out of the pci_create_root_bus().
The new function (tentatively called pci_create_new_root_bus()) will
no longer call pci_alloc_host_bridge() but will accept it as a
parameter, allowing one to be able to set the domain_nr ahead of the
root bus creation.

Best regards,
Liviu
Catalin Marinas July 11, 2014, 4:09 p.m. UTC | #11
On Fri, Jul 11, 2014 at 04:08:23PM +0100, Liviu Dudau wrote:
> On Fri, Jul 11, 2014 at 03:11:16PM +0100, Catalin Marinas wrote:
> > On Thu, Jul 10, 2014 at 11:36:10PM +0100, Bjorn Helgaas wrote:
> > > Most of the rest of the v7 discussion was about "Introduce a domain
> > > number for pci_host_bridge."  I think we should add arm64 using the
> > > existing pci_scan_root_bus() and keep the domain number in the arm64
> > > sysdata structure like every other arch does.  Isn't that feasible?
> > > We can worry about domain unification later.
> > 
> > I think that's what we were trying to avoid, adding an arm64-specific
> > pci_sys_data structure (and arm64-specific API). IIUC, avoiding this
> > would allow the host controller drivers to use the sysdata pointer for
> > their own private data structures.
> > 
> > Also since you can specify the domain number via DT (and in Liviu's
> > v8 patches read by of_create_pci_host_bridge), I think it would make
> > sense to have it stored in some generic data structures (e.g.
> > pci_host_bridge) rather than in an arm64 private sysdata.
> > 
> > (Liviu is thinking of an alternative API but maybe he could briefly
> > describe it here before posting a new series)
> 
> My plan is to keep the domain number in the pci_host_bridge and split
> the creation of the pci_host_bridge out of the pci_create_root_bus().

Wouldn't it make more sense to add domain_nr to the pci_bus structure
(well, only needed for the root bus)? It would simplify pci_domain_nr()
as well which only takes a pci_bus parameter.

> The new function (tentatively called pci_create_new_root_bus()) will
> no longer call pci_alloc_host_bridge() but will accept it as a
> parameter, allowing one to be able to set the domain_nr ahead of the
> root bus creation.

If we place domain_nr in pci_bus, this split wouldn't help but we still
need your original pci_create_root_bus_in_domain(). Are there other uses
of your proposal above?

Yet another alternative is to ignore PCI domains altogether (domain 0
always).
Bjorn Helgaas July 11, 2014, 5:02 p.m. UTC | #12
On Fri, Jul 11, 2014 at 8:11 AM, Catalin Marinas
<catalin.marinas@arm.com> wrote:
> On Thu, Jul 10, 2014 at 11:36:10PM +0100, Bjorn Helgaas wrote:
>> Most of the rest of the v7 discussion was about "Introduce a domain
>> number for pci_host_bridge."  I think we should add arm64 using the
>> existing pci_scan_root_bus() and keep the domain number in the arm64
>> sysdata structure like every other arch does.  Isn't that feasible?
>> We can worry about domain unification later.
>
> I think that's what we were trying to avoid, adding an arm64-specific
> pci_sys_data structure (and arm64-specific API). IIUC, avoiding this
> would allow the host controller drivers to use the sysdata pointer for
> their own private data structures.
>
> Also since you can specify the domain number via DT (and in Liviu's
> v8 patches read by of_create_pci_host_bridge), I think it would make
> sense to have it stored in some generic data structures (e.g.
> pci_host_bridge) rather than in an arm64 private sysdata.

It would definitely be nice to keep the domain in a generic data
structure rather than an arm64-specific one.  But every other arch
keeps it in an arch-specific structure today, and I think following
that existing pattern is the quickest way forward.

But you mentioned arm64-specific API, too.  What do you have in mind
there?  I know there will be arm64 implementations of various
pcibios_*() functions (just like for every other arch), but it sounds
like there might be something else?

Bjorn
Catalin Marinas July 11, 2014, 6:02 p.m. UTC | #13
On Fri, Jul 11, 2014 at 06:02:56PM +0100, Bjorn Helgaas wrote:
> On Fri, Jul 11, 2014 at 8:11 AM, Catalin Marinas
> <catalin.marinas@arm.com> wrote:
> > On Thu, Jul 10, 2014 at 11:36:10PM +0100, Bjorn Helgaas wrote:
> >> Most of the rest of the v7 discussion was about "Introduce a domain
> >> number for pci_host_bridge."  I think we should add arm64 using the
> >> existing pci_scan_root_bus() and keep the domain number in the arm64
> >> sysdata structure like every other arch does.  Isn't that feasible?
> >> We can worry about domain unification later.
> >
> > I think that's what we were trying to avoid, adding an arm64-specific
> > pci_sys_data structure (and arm64-specific API). IIUC, avoiding this
> > would allow the host controller drivers to use the sysdata pointer for
> > their own private data structures.
> >
> > Also since you can specify the domain number via DT (and in Liviu's
> > v8 patches read by of_create_pci_host_bridge), I think it would make
> > sense to have it stored in some generic data structures (e.g.
> > pci_host_bridge) rather than in an arm64 private sysdata.
> 
> It would definitely be nice to keep the domain in a generic data
> structure rather than an arm64-specific one.  But every other arch
> keeps it in an arch-specific structure today, and I think following
> that existing pattern is the quickest way forward.

In this case we end up with an arm64-specific struct pci_sys_data and I
assume some API that takes care of this data structure to populate the
domain nr.

In Liviu's implementation, of_create_pci_host_bridge() is called by the
host controller driver directly and reads the domain_nr from the DT. It
also gets a void *host_data which it stores as sysdata in the pci_bus
structure (but that's specific to the host controller driver rather than
arm64). Since sysdata is opaque to of_create_pci_host_bridge(), it
cannot set the domain_nr.

If we go for arm64 sysdata, the host controller driver would have to
call some arm64 pci* function (maybe with its own private data as
argument) which would have to parse the DT, assign the domain nr and
eventually call pci_create_root_bus(). But it means that significant
part of of_create_pci_host_bridge() would be moved under arch/arm64 (an
alternative is for each host driver to implement its own
of_create_pci_host_bridge()).

In addition, host drivers would retrieve their private data from the
arm64 specific sysdata structure and we were trying to make host drivers
depend only on generic data structures and API rather than arch
specific.

> But you mentioned arm64-specific API, too.  What do you have in mind
> there?  I know there will be arm64 implementations of various
> pcibios_*() functions (just like for every other arch), but it sounds
> like there might be something else?

Not much left which is arm64 specific, just some callbacks:

http://linux-arm.org/git?p=linux-ld.git;a=commitdiff;h=82ebbce34506676528b9a7ae8f8fbc84b6b6248e

AFAICT, there isn't anything that host drivers need to call directly.
Basically we want to decouple the PCI host driver model from the arch
specific data structures/API.
diff mbox

Patch

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 2c92662..abf5e82 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1748,8 +1748,9 @@  void __weak pcibios_remove_bus(struct pci_bus *bus)
 {
 }
 
-struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
-		struct pci_ops *ops, void *sysdata, struct list_head *resources)
+struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
+		int domain, int bus, struct pci_ops *ops, void *sysdata,
+		struct list_head *resources)
 {
 	int error;
 	struct pci_host_bridge *bridge;
@@ -1762,27 +1763,31 @@  struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 
 	bridge = pci_alloc_host_bridge();
 	if (!bridge)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	bridge->dev.parent = parent;
 	bridge->dev.release = pci_release_host_bridge_dev;
+	bridge->domain_nr = domain;
 
 	b = pci_alloc_bus();
-	if (!b)
+	if (!b) {
+		error = -ENOMEM;
 		goto err_out;
+	}
 
 	b->sysdata = sysdata;
 	b->ops = ops;
 	b->number = b->busn_res.start = bus;
-	b2 = pci_find_bus(pci_domain_nr(b), bus);
+	b2 = pci_find_bus(bridge->domain_nr, bus);
 	if (b2) {
 		/* If we already got to this bus through a different bridge, ignore it */
 		dev_dbg(&b2->dev, "bus already known\n");
+		error = -EEXIST;
 		goto err_bus_out;
 	}
 
 	bridge->bus = b;
-	dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+	dev_set_name(&bridge->dev, "pci%04x:%02x", bridge->domain_nr, bus);
 	error = pcibios_root_bridge_prepare(bridge);
 	if (error)
 		goto err_out;
@@ -1801,7 +1806,7 @@  struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 
 	b->dev.class = &pcibus_class;
 	b->dev.parent = b->bridge;
-	dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus);
+	dev_set_name(&b->dev, "%04x:%02x", bridge->domain_nr, bus);
 	error = device_register(&b->dev);
 	if (error)
 		goto class_dev_reg_err;
@@ -1851,7 +1856,27 @@  err_bus_out:
 	kfree(b);
 err_out:
 	kfree(bridge);
-	return NULL;
+	return ERR_PTR(error);
+}
+
+struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
+		struct pci_ops *ops, void *sysdata, struct list_head *resources)
+{
+	int domain_nr;
+	struct pci_bus *b = pci_alloc_bus();
+	if (!b)
+		return NULL;
+
+	b->sysdata = sysdata;
+	domain_nr = pci_domain_nr(b);
+	kfree(b);
+
+	b = pci_create_root_bus_in_domain(parent, domain_nr, bus,
+				ops, sysdata, resources);
+	if (IS_ERR(b))
+		return NULL;
+
+	return b;
 }
 
 int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 466bcd1..7e7b939 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -401,6 +401,7 @@  struct pci_host_bridge_window {
 struct pci_host_bridge {
 	struct device dev;
 	struct pci_bus *bus;		/* root bus */
+	int domain_nr;
 	struct list_head windows;	/* pci_host_bridge_windows */
 	void (*release_fn)(struct pci_host_bridge *);
 	void *release_data;
@@ -769,6 +770,9 @@  struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
 				    struct pci_ops *ops, void *sysdata,
 				    struct list_head *resources);
+struct pci_bus *pci_create_root_bus_in_domain(struct device *parent,
+			int domain, int bus, struct pci_ops *ops,
+			void *sysdata, struct list_head *resources);
 int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax);
 int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax);
 void pci_bus_release_busn_res(struct pci_bus *b);