diff mbox

[v12,08/12] PCI: OF: Introduce helper function for retrieving PCI domain numbers

Message ID 1411498874-9864-9-git-send-email-Liviu.Dudau@arm.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Liviu Dudau Sept. 23, 2014, 7:01 p.m. UTC
Add pci_get_new_domain_nr() to allocate a new domain number
and of_get_pci_domain_nr() to retrieve the PCI domain number
of a given device from DT. Host bridge drivers or architecture
specific code can choose to implement their PCI domain number
policy using these two functions.

Using of_get_pci_domain_nr() guarantees a stable PCI domain
number on every boot provided that all host bridge controllers
are assigned a number in the device tree using "linux,pci-domain"
property. Mix use of pci_get_new_domain_nr() and of_get_pci_domain_nr()
is not recommended as it can lead to potentially conflicting
domain numbers being assigned to root busses behind different
host bridges.

Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
---
 drivers/of/of_pci.c    | 25 +++++++++++++++++++++++++
 drivers/pci/pci.c      |  9 +++++++++
 include/linux/of_pci.h |  7 +++++++
 include/linux/pci.h    |  3 +++
 4 files changed, 44 insertions(+)

Comments

Rob Herring Sept. 26, 2014, 6:20 p.m. UTC | #1
On Tue, Sep 23, 2014 at 2:01 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> Add pci_get_new_domain_nr() to allocate a new domain number
> and of_get_pci_domain_nr() to retrieve the PCI domain number
> of a given device from DT. Host bridge drivers or architecture
> specific code can choose to implement their PCI domain number
> policy using these two functions.
>
> Using of_get_pci_domain_nr() guarantees a stable PCI domain
> number on every boot provided that all host bridge controllers
> are assigned a number in the device tree using "linux,pci-domain"
> property. Mix use of pci_get_new_domain_nr() and of_get_pci_domain_nr()
> is not recommended as it can lead to potentially conflicting
> domain numbers being assigned to root busses behind different
> host bridges.
>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Grant Likely <grant.likely@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>

Looks pretty good, but a couple of comments that can be addressed as
follow-up patches.

> ---
>  drivers/of/of_pci.c    | 25 +++++++++++++++++++++++++
>  drivers/pci/pci.c      |  9 +++++++++
>  include/linux/of_pci.h |  7 +++++++
>  include/linux/pci.h    |  3 +++
>  4 files changed, 44 insertions(+)
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 8481996..82d172f 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -89,6 +89,31 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
>  }
>  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
>
> +/**
> + * This function will try to obtain the host bridge domain number by
> + * finding a property called "linux,pci-domain" of the given device node.
> + *
> + * @node: device tree node with the domain information
> + *
> + * Returns the associated domain number from DT in the range [0-0xffff], or
> + * a negative value if the required property is not found.
> + */
> +int of_get_pci_domain_nr(struct device_node *node)
> +{
> +       const __be32 *value;
> +       int len;
> +       u16 domain;
> +
> +       value = of_get_property(node, "linux,pci-domain", &len);

This needs to be documented.

> +       if (!value || len < sizeof(*value))
> +               return -EINVAL;
> +
> +       domain = (u16)be32_to_cpup(value);

of_property_read_u32 would not work here?

> +
> +       return domain;
> +}
> +EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
> +
>  #ifdef CONFIG_PCI_MSI
>
>  static LIST_HEAD(of_pci_msi_chip_list);
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index 2c9ac70..d36f35f 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -4406,6 +4406,15 @@ static void pci_no_domains(void)
>  #endif
>  }
>
> +#ifdef CONFIG_PCI_DOMAINS
> +static atomic_t __domain_nr = ATOMIC_INIT(-1);
> +
> +int pci_get_new_domain_nr(void)
> +{
> +       return atomic_inc_return(&__domain_nr);
> +}
> +#endif
> +
>  /**
>   * pci_ext_cfg_avail - can we access extended PCI config space?
>   *
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index dde3a4a..71062e9 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -15,6 +15,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
>  int of_pci_get_devfn(struct device_node *np);
>  int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
>  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
> +int of_get_pci_domain_nr(struct device_node *node);
>  #else
>  static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
>  {
> @@ -43,6 +44,12 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res)
>  {
>         return -EINVAL;
>  }
> +
> +static inline int
> +of_get_pci_domain_nr(struct device_node *node)
> +{
> +       return -1;
> +}
>  #endif
>
>  #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index a494e5d..150da2d 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1285,10 +1285,12 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
>   */
>  #ifdef CONFIG_PCI_DOMAINS
>  extern int pci_domains_supported;
> +int pci_get_new_domain_nr(void);
>  #else
>  enum { pci_domains_supported = 0 };
>  static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
>  static inline int pci_proc_domain(struct pci_bus *bus) { return 0; }
> +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
>  #endif /* CONFIG_PCI_DOMAINS */
>
>  /*
> @@ -1417,6 +1419,7 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
>
>  static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
>  static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
> +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
>
>  #define dev_is_pci(d) (false)
>  #define dev_is_pf(d) (false)
> --
> 2.1.0
>
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liviu Dudau Sept. 26, 2014, 9:20 p.m. UTC | #2
On Fri, Sep 26, 2014 at 01:20:39PM -0500, Rob Herring wrote:
> On Tue, Sep 23, 2014 at 2:01 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> > Add pci_get_new_domain_nr() to allocate a new domain number
> > and of_get_pci_domain_nr() to retrieve the PCI domain number
> > of a given device from DT. Host bridge drivers or architecture
> > specific code can choose to implement their PCI domain number
> > policy using these two functions.
> >
> > Using of_get_pci_domain_nr() guarantees a stable PCI domain
> > number on every boot provided that all host bridge controllers
> > are assigned a number in the device tree using "linux,pci-domain"
> > property. Mix use of pci_get_new_domain_nr() and of_get_pci_domain_nr()
> > is not recommended as it can lead to potentially conflicting
> > domain numbers being assigned to root busses behind different
> > host bridges.
> >
> > Cc: Bjorn Helgaas <bhelgaas@google.com>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Grant Likely <grant.likely@linaro.org>
> > Cc: Rob Herring <robh+dt@kernel.org>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> 
> Looks pretty good, but a couple of comments that can be addressed as
> follow-up patches.
> 
> > ---
> >  drivers/of/of_pci.c    | 25 +++++++++++++++++++++++++
> >  drivers/pci/pci.c      |  9 +++++++++
> >  include/linux/of_pci.h |  7 +++++++
> >  include/linux/pci.h    |  3 +++
> >  4 files changed, 44 insertions(+)
> >
> > diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> > index 8481996..82d172f 100644
> > --- a/drivers/of/of_pci.c
> > +++ b/drivers/of/of_pci.c
> > @@ -89,6 +89,31 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
> >  }
> >  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
> >
> > +/**
> > + * This function will try to obtain the host bridge domain number by
> > + * finding a property called "linux,pci-domain" of the given device node.
> > + *
> > + * @node: device tree node with the domain information
> > + *
> > + * Returns the associated domain number from DT in the range [0-0xffff], or
> > + * a negative value if the required property is not found.
> > + */
> > +int of_get_pci_domain_nr(struct device_node *node)
> > +{
> > +       const __be32 *value;
> > +       int len;
> > +       u16 domain;
> > +
> > +       value = of_get_property(node, "linux,pci-domain", &len);
> 
> This needs to be documented.

I would say needs agreed on *and* documented.

> 
> > +       if (!value || len < sizeof(*value))
> > +               return -EINVAL;
> > +
> > +       domain = (u16)be32_to_cpup(value);
> 
> of_property_read_u32 would not work here?

It should, I guess, but I want to limit the domain number range to 16 bits.

Best regards,
Liviu

> 
> > +
> > +       return domain;
> > +}
> > +EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
> > +
> >  #ifdef CONFIG_PCI_MSI
> >
> >  static LIST_HEAD(of_pci_msi_chip_list);
> > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> > index 2c9ac70..d36f35f 100644
> > --- a/drivers/pci/pci.c
> > +++ b/drivers/pci/pci.c
> > @@ -4406,6 +4406,15 @@ static void pci_no_domains(void)
> >  #endif
> >  }
> >
> > +#ifdef CONFIG_PCI_DOMAINS
> > +static atomic_t __domain_nr = ATOMIC_INIT(-1);
> > +
> > +int pci_get_new_domain_nr(void)
> > +{
> > +       return atomic_inc_return(&__domain_nr);
> > +}
> > +#endif
> > +
> >  /**
> >   * pci_ext_cfg_avail - can we access extended PCI config space?
> >   *
> > diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> > index dde3a4a..71062e9 100644
> > --- a/include/linux/of_pci.h
> > +++ b/include/linux/of_pci.h
> > @@ -15,6 +15,7 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
> >  int of_pci_get_devfn(struct device_node *np);
> >  int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
> >  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
> > +int of_get_pci_domain_nr(struct device_node *node);
> >  #else
> >  static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
> >  {
> > @@ -43,6 +44,12 @@ of_pci_parse_bus_range(struct device_node *node, struct resource *res)
> >  {
> >         return -EINVAL;
> >  }
> > +
> > +static inline int
> > +of_get_pci_domain_nr(struct device_node *node)
> > +{
> > +       return -1;
> > +}
> >  #endif
> >
> >  #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
> > diff --git a/include/linux/pci.h b/include/linux/pci.h
> > index a494e5d..150da2d 100644
> > --- a/include/linux/pci.h
> > +++ b/include/linux/pci.h
> > @@ -1285,10 +1285,12 @@ void pci_cfg_access_unlock(struct pci_dev *dev);
> >   */
> >  #ifdef CONFIG_PCI_DOMAINS
> >  extern int pci_domains_supported;
> > +int pci_get_new_domain_nr(void);
> >  #else
> >  enum { pci_domains_supported = 0 };
> >  static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
> >  static inline int pci_proc_domain(struct pci_bus *bus) { return 0; }
> > +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
> >  #endif /* CONFIG_PCI_DOMAINS */
> >
> >  /*
> > @@ -1417,6 +1419,7 @@ static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
> >
> >  static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
> >  static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
> > +static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
> >
> >  #define dev_is_pci(d) (false)
> >  #define dev_is_pf(d) (false)
> > --
> > 2.1.0
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Rob Herring Sept. 26, 2014, 9:53 p.m. UTC | #3
On Fri, Sep 26, 2014 at 4:20 PM,  <liviu@dudau.co.uk> wrote:
> On Fri, Sep 26, 2014 at 01:20:39PM -0500, Rob Herring wrote:
>> On Tue, Sep 23, 2014 at 2:01 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
>> > Add pci_get_new_domain_nr() to allocate a new domain number
>> > and of_get_pci_domain_nr() to retrieve the PCI domain number
>> > of a given device from DT. Host bridge drivers or architecture
>> > specific code can choose to implement their PCI domain number
>> > policy using these two functions.
>> >
>> > Using of_get_pci_domain_nr() guarantees a stable PCI domain
>> > number on every boot provided that all host bridge controllers
>> > are assigned a number in the device tree using "linux,pci-domain"
>> > property. Mix use of pci_get_new_domain_nr() and of_get_pci_domain_nr()
>> > is not recommended as it can lead to potentially conflicting
>> > domain numbers being assigned to root busses behind different
>> > host bridges.
>> >
>> > Cc: Bjorn Helgaas <bhelgaas@google.com>
>> > Cc: Arnd Bergmann <arnd@arndb.de>
>> > Cc: Grant Likely <grant.likely@linaro.org>
>> > Cc: Rob Herring <robh+dt@kernel.org>
>> > Cc: Catalin Marinas <catalin.marinas@arm.com>
>> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
>>
>> Looks pretty good, but a couple of comments that can be addressed as
>> follow-up patches.
>>
>> > ---
>> >  drivers/of/of_pci.c    | 25 +++++++++++++++++++++++++
>> >  drivers/pci/pci.c      |  9 +++++++++
>> >  include/linux/of_pci.h |  7 +++++++
>> >  include/linux/pci.h    |  3 +++
>> >  4 files changed, 44 insertions(+)
>> >
>> > diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
>> > index 8481996..82d172f 100644
>> > --- a/drivers/of/of_pci.c
>> > +++ b/drivers/of/of_pci.c
>> > @@ -89,6 +89,31 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
>> >  }
>> >  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
>> >
>> > +/**
>> > + * This function will try to obtain the host bridge domain number by
>> > + * finding a property called "linux,pci-domain" of the given device node.
>> > + *
>> > + * @node: device tree node with the domain information
>> > + *
>> > + * Returns the associated domain number from DT in the range [0-0xffff], or
>> > + * a negative value if the required property is not found.
>> > + */
>> > +int of_get_pci_domain_nr(struct device_node *node)
>> > +{
>> > +       const __be32 *value;
>> > +       int len;
>> > +       u16 domain;
>> > +
>> > +       value = of_get_property(node, "linux,pci-domain", &len);
>>
>> This needs to be documented.
>
> I would say needs agreed on *and* documented.

I thought Bjorn already applied the series. Who's agreement are you
waiting for specifically.

>>
>> > +       if (!value || len < sizeof(*value))
>> > +               return -EINVAL;
>> > +
>> > +       domain = (u16)be32_to_cpup(value);
>>
>> of_property_read_u32 would not work here?
>
> It should, I guess, but I want to limit the domain number range to 16 bits.

Okay, but it would still be fewer lines to use of_property_read_u32
and then cast it. You could use the u16 variant and make the property
be defined to be 16-bit in the documentation.

Rob
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Liviu Dudau Sept. 26, 2014, 10:47 p.m. UTC | #4
On Fri, Sep 26, 2014 at 10:53:26PM +0100, Rob Herring wrote:
> On Fri, Sep 26, 2014 at 4:20 PM,  <liviu@dudau.co.uk> wrote:
> > On Fri, Sep 26, 2014 at 01:20:39PM -0500, Rob Herring wrote:
> >> On Tue, Sep 23, 2014 at 2:01 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> >> > Add pci_get_new_domain_nr() to allocate a new domain number
> >> > and of_get_pci_domain_nr() to retrieve the PCI domain number
> >> > of a given device from DT. Host bridge drivers or architecture
> >> > specific code can choose to implement their PCI domain number
> >> > policy using these two functions.
> >> >
> >> > Using of_get_pci_domain_nr() guarantees a stable PCI domain
> >> > number on every boot provided that all host bridge controllers
> >> > are assigned a number in the device tree using "linux,pci-domain"
> >> > property. Mix use of pci_get_new_domain_nr() and of_get_pci_domain_nr()
> >> > is not recommended as it can lead to potentially conflicting
> >> > domain numbers being assigned to root busses behind different
> >> > host bridges.
> >> >
> >> > Cc: Bjorn Helgaas <bhelgaas@google.com>
> >> > Cc: Arnd Bergmann <arnd@arndb.de>
> >> > Cc: Grant Likely <grant.likely@linaro.org>
> >> > Cc: Rob Herring <robh+dt@kernel.org>
> >> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> >> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> >>
> >> Looks pretty good, but a couple of comments that can be addressed as
> >> follow-up patches.
> >>
> >> > ---
> >> >  drivers/of/of_pci.c    | 25 +++++++++++++++++++++++++
> >> >  drivers/pci/pci.c      |  9 +++++++++
> >> >  include/linux/of_pci.h |  7 +++++++
> >> >  include/linux/pci.h    |  3 +++
> >> >  4 files changed, 44 insertions(+)
> >> >
> >> > diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> >> > index 8481996..82d172f 100644
> >> > --- a/drivers/of/of_pci.c
> >> > +++ b/drivers/of/of_pci.c
> >> > @@ -89,6 +89,31 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
> >> >  }
> >> >  EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
> >> >
> >> > +/**
> >> > + * This function will try to obtain the host bridge domain number by
> >> > + * finding a property called "linux,pci-domain" of the given device node.
> >> > + *
> >> > + * @node: device tree node with the domain information
> >> > + *
> >> > + * Returns the associated domain number from DT in the range [0-0xffff], or
> >> > + * a negative value if the required property is not found.
> >> > + */
> >> > +int of_get_pci_domain_nr(struct device_node *node)
> >> > +{
> >> > +       const __be32 *value;
> >> > +       int len;
> >> > +       u16 domain;
> >> > +
> >> > +       value = of_get_property(node, "linux,pci-domain", &len);
> >>
> >> This needs to be documented.
> >
> > I would say needs agreed on *and* documented.
> 
> I thought Bjorn already applied the series. Who's agreement are you
> waiting for specifically.

Looks like he only applied about 60% of the series.

I'm not waiting on anyones specifig agreement, just general agreement.
Jason Gunthrope have initially suggested using pci-domain alias which
you don't like, now I'm using "linux,pci-domain" property which you've
ACKed, I wonder if I need to give people more time to catch up to the
fact?

> 
> >>
> >> > +       if (!value || len < sizeof(*value))
> >> > +               return -EINVAL;
> >> > +
> >> > +       domain = (u16)be32_to_cpup(value);
> >>
> >> of_property_read_u32 would not work here?
> >
> > It should, I guess, but I want to limit the domain number range to 16 bits.
> 
> Okay, but it would still be fewer lines to use of_property_read_u32
> and then cast it. You could use the u16 variant and make the property
> be defined to be 16-bit in the documentation.

True. Will do.

Best regards,
Liviu

> 
> Rob
>
Bjorn Helgaas Sept. 27, 2014, 8:18 p.m. UTC | #5
[+cc Yinghai]

On Fri, Sep 26, 2014 at 4:47 PM, Liviu Dudau <Liviu.Dudau@arm.com> wrote:
> On Fri, Sep 26, 2014 at 10:53:26PM +0100, Rob Herring wrote:

>> I thought Bjorn already applied the series. Who's agreement are you
>> waiting for specifically.
>
> Looks like he only applied about 60% of the series.

I applied it all but Yinghai pointed out a problem with a patch in the
middle, so I dropped that patch and everything after it because I didn't
have time to work out whether the later patches depended on anything
in the one I dropped.

Bjorn
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 8481996..82d172f 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -89,6 +89,31 @@  int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
 }
 EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
 
+/**
+ * This function will try to obtain the host bridge domain number by
+ * finding a property called "linux,pci-domain" of the given device node.
+ *
+ * @node: device tree node with the domain information
+ *
+ * Returns the associated domain number from DT in the range [0-0xffff], or
+ * a negative value if the required property is not found.
+ */
+int of_get_pci_domain_nr(struct device_node *node)
+{
+	const __be32 *value;
+	int len;
+	u16 domain;
+
+	value = of_get_property(node, "linux,pci-domain", &len);
+	if (!value || len < sizeof(*value))
+		return -EINVAL;
+
+	domain = (u16)be32_to_cpup(value);
+
+	return domain;
+}
+EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
+
 #ifdef CONFIG_PCI_MSI
 
 static LIST_HEAD(of_pci_msi_chip_list);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c9ac70..d36f35f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4406,6 +4406,15 @@  static void pci_no_domains(void)
 #endif
 }
 
+#ifdef CONFIG_PCI_DOMAINS
+static atomic_t __domain_nr = ATOMIC_INIT(-1);
+
+int pci_get_new_domain_nr(void)
+{
+	return atomic_inc_return(&__domain_nr);
+}
+#endif
+
 /**
  * pci_ext_cfg_avail - can we access extended PCI config space?
  *
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index dde3a4a..71062e9 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -15,6 +15,7 @@  struct device_node *of_pci_find_child_device(struct device_node *parent,
 int of_pci_get_devfn(struct device_node *np);
 int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
+int of_get_pci_domain_nr(struct device_node *node);
 #else
 static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
 {
@@ -43,6 +44,12 @@  of_pci_parse_bus_range(struct device_node *node, struct resource *res)
 {
 	return -EINVAL;
 }
+
+static inline int
+of_get_pci_domain_nr(struct device_node *node)
+{
+	return -1;
+}
 #endif
 
 #if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a494e5d..150da2d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1285,10 +1285,12 @@  void pci_cfg_access_unlock(struct pci_dev *dev);
  */
 #ifdef CONFIG_PCI_DOMAINS
 extern int pci_domains_supported;
+int pci_get_new_domain_nr(void);
 #else
 enum { pci_domains_supported = 0 };
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline int pci_proc_domain(struct pci_bus *bus) { return 0; }
+static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 #endif /* CONFIG_PCI_DOMAINS */
 
 /*
@@ -1417,6 +1419,7 @@  static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
 
 static inline int pci_domain_nr(struct pci_bus *bus) { return 0; }
 static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; }
+static inline int pci_get_new_domain_nr(void) { return -ENOSYS; }
 
 #define dev_is_pci(d) (false)
 #define dev_is_pf(d) (false)