diff mbox series

[v5,3/4] PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property

Message ID 20220412094946.27069-4-pali@kernel.org (mailing list archive)
State New, archived
Headers show
Series PCI: mvebu: Slot support | expand

Commit Message

Pali Rohár April 12, 2022, 9:49 a.m. UTC
Add function of_pci_get_slot_power_limit(), which parses the
'slot-power-limit-milliwatt' DT property, returning the value in
milliwatts and in format ready for the PCIe Slot Capabilities Register.

Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes in v4:
* Set 239 W when DT slot-power-limit-milliwatt is between 239 W and 250 W
* Fix returning power limit value
Changes in v3:
* Set 600 W when DT slot-power-limit-milliwatt > 600 W
Changes in v2:
* Added support for PCIe 6.0 slot power limit encodings
* Round down slot power limit value
---
 drivers/pci/of.c  | 70 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/pci.h | 15 ++++++++++
 2 files changed, 85 insertions(+)

Comments

Bjorn Helgaas April 13, 2022, 8:24 p.m. UTC | #1
On Tue, Apr 12, 2022 at 11:49:45AM +0200, Pali Rohár wrote:
> Add function of_pci_get_slot_power_limit(), which parses the
> 'slot-power-limit-milliwatt' DT property, returning the value in
> milliwatts and in format ready for the PCIe Slot Capabilities Register.
> 
> Signed-off-by: Pali Rohár <pali@kernel.org>
> Signed-off-by: Marek Behún <kabel@kernel.org>
> Reviewed-by: Rob Herring <robh@kernel.org>

Looks good to me!  Thank you!

Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>

> ---
> Changes in v4:
> * Set 239 W when DT slot-power-limit-milliwatt is between 239 W and 250 W
> * Fix returning power limit value
> Changes in v3:
> * Set 600 W when DT slot-power-limit-milliwatt > 600 W
> Changes in v2:
> * Added support for PCIe 6.0 slot power limit encodings
> * Round down slot power limit value
> ---
>  drivers/pci/of.c  | 70 +++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/pci/pci.h | 15 ++++++++++
>  2 files changed, 85 insertions(+)
> 
> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index cb2e8351c2cc..6c1b81304665 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -633,3 +633,73 @@ int of_pci_get_max_link_speed(struct device_node *node)
>  	return max_link_speed;
>  }
>  EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
> +
> +/**
> + * of_pci_get_slot_power_limit - Parses the "slot-power-limit-milliwatt"
> + *				 property.
> + *
> + * @node: device tree node with the slot power limit information
> + * @slot_power_limit_value: pointer where the value should be stored in PCIe
> + *			    Slot Capabilities Register format
> + * @slot_power_limit_scale: pointer where the scale should be stored in PCIe
> + *			    Slot Capabilities Register format
> + *
> + * Returns the slot power limit in milliwatts and if @slot_power_limit_value
> + * and @slot_power_limit_scale pointers are non-NULL, fills in the value and
> + * scale in format used by PCIe Slot Capabilities Register.
> + *
> + * If the property is not found or is invalid, returns 0.
> + */
> +u32 of_pci_get_slot_power_limit(struct device_node *node,
> +				u8 *slot_power_limit_value,
> +				u8 *slot_power_limit_scale)
> +{
> +	u32 slot_power_limit_mw;
> +	u8 value, scale;
> +
> +	if (of_property_read_u32(node, "slot-power-limit-milliwatt",
> +				 &slot_power_limit_mw))
> +		slot_power_limit_mw = 0;
> +
> +	/* Calculate Slot Power Limit Value and Slot Power Limit Scale */
> +	if (slot_power_limit_mw == 0) {
> +		value = 0x00;
> +		scale = 0;
> +	} else if (slot_power_limit_mw <= 255) {
> +		value = slot_power_limit_mw;
> +		scale = 3;
> +	} else if (slot_power_limit_mw <= 255*10) {
> +		value = slot_power_limit_mw / 10;
> +		scale = 2;
> +		slot_power_limit_mw = slot_power_limit_mw / 10 * 10;
> +	} else if (slot_power_limit_mw <= 255*100) {
> +		value = slot_power_limit_mw / 100;
> +		scale = 1;
> +		slot_power_limit_mw = slot_power_limit_mw / 100 * 100;
> +	} else if (slot_power_limit_mw <= 239*1000) {
> +		value = slot_power_limit_mw / 1000;
> +		scale = 0;
> +		slot_power_limit_mw = slot_power_limit_mw / 1000 * 1000;
> +	} else if (slot_power_limit_mw < 250*1000) {
> +		value = 0xEF;
> +		scale = 0;
> +		slot_power_limit_mw = 239*1000;
> +	} else if (slot_power_limit_mw <= 600*1000) {
> +		value = 0xF0 + (slot_power_limit_mw / 1000 - 250) / 25;
> +		scale = 0;
> +		slot_power_limit_mw = slot_power_limit_mw / (1000*25) * (1000*25);
> +	} else {
> +		value = 0xFE;
> +		scale = 0;
> +		slot_power_limit_mw = 600*1000;
> +	}
> +
> +	if (slot_power_limit_value)
> +		*slot_power_limit_value = value;
> +
> +	if (slot_power_limit_scale)
> +		*slot_power_limit_scale = scale;
> +
> +	return slot_power_limit_mw;
> +}
> +EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit);
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 3d60cabde1a1..e10cdec6c56e 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -627,6 +627,9 @@ struct device_node;
>  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
>  int of_get_pci_domain_nr(struct device_node *node);
>  int of_pci_get_max_link_speed(struct device_node *node);
> +u32 of_pci_get_slot_power_limit(struct device_node *node,
> +				u8 *slot_power_limit_value,
> +				u8 *slot_power_limit_scale);
>  void pci_set_of_node(struct pci_dev *dev);
>  void pci_release_of_node(struct pci_dev *dev);
>  void pci_set_bus_of_node(struct pci_bus *bus);
> @@ -653,6 +656,18 @@ of_pci_get_max_link_speed(struct device_node *node)
>  	return -EINVAL;
>  }
>  
> +static inline u32
> +of_pci_get_slot_power_limit(struct device_node *node,
> +			    u8 *slot_power_limit_value,
> +			    u8 *slot_power_limit_scale)
> +{
> +	if (slot_power_limit_value)
> +		*slot_power_limit_value = 0;
> +	if (slot_power_limit_scale)
> +		*slot_power_limit_scale = 0;
> +	return 0;
> +}
> +
>  static inline void pci_set_of_node(struct pci_dev *dev) { }
>  static inline void pci_release_of_node(struct pci_dev *dev) { }
>  static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
> -- 
> 2.20.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Pali Rohár April 21, 2022, 8:14 p.m. UTC | #2
On Wednesday 13 April 2022 15:24:33 Bjorn Helgaas wrote:
> On Tue, Apr 12, 2022 at 11:49:45AM +0200, Pali Rohár wrote:
> > Add function of_pci_get_slot_power_limit(), which parses the
> > 'slot-power-limit-milliwatt' DT property, returning the value in
> > milliwatts and in format ready for the PCIe Slot Capabilities Register.
> > 
> > Signed-off-by: Pali Rohár <pali@kernel.org>
> > Signed-off-by: Marek Behún <kabel@kernel.org>
> > Reviewed-by: Rob Herring <robh@kernel.org>
> 
> Looks good to me!  Thank you!
> 
> Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>

Perfect!

Lorenzo, is this patch series OK now for merging?

> > ---
> > Changes in v4:
> > * Set 239 W when DT slot-power-limit-milliwatt is between 239 W and 250 W
> > * Fix returning power limit value
> > Changes in v3:
> > * Set 600 W when DT slot-power-limit-milliwatt > 600 W
> > Changes in v2:
> > * Added support for PCIe 6.0 slot power limit encodings
> > * Round down slot power limit value
> > ---
> >  drivers/pci/of.c  | 70 +++++++++++++++++++++++++++++++++++++++++++++++
> >  drivers/pci/pci.h | 15 ++++++++++
> >  2 files changed, 85 insertions(+)
> > 
> > diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> > index cb2e8351c2cc..6c1b81304665 100644
> > --- a/drivers/pci/of.c
> > +++ b/drivers/pci/of.c
> > @@ -633,3 +633,73 @@ int of_pci_get_max_link_speed(struct device_node *node)
> >  	return max_link_speed;
> >  }
> >  EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
> > +
> > +/**
> > + * of_pci_get_slot_power_limit - Parses the "slot-power-limit-milliwatt"
> > + *				 property.
> > + *
> > + * @node: device tree node with the slot power limit information
> > + * @slot_power_limit_value: pointer where the value should be stored in PCIe
> > + *			    Slot Capabilities Register format
> > + * @slot_power_limit_scale: pointer where the scale should be stored in PCIe
> > + *			    Slot Capabilities Register format
> > + *
> > + * Returns the slot power limit in milliwatts and if @slot_power_limit_value
> > + * and @slot_power_limit_scale pointers are non-NULL, fills in the value and
> > + * scale in format used by PCIe Slot Capabilities Register.
> > + *
> > + * If the property is not found or is invalid, returns 0.
> > + */
> > +u32 of_pci_get_slot_power_limit(struct device_node *node,
> > +				u8 *slot_power_limit_value,
> > +				u8 *slot_power_limit_scale)
> > +{
> > +	u32 slot_power_limit_mw;
> > +	u8 value, scale;
> > +
> > +	if (of_property_read_u32(node, "slot-power-limit-milliwatt",
> > +				 &slot_power_limit_mw))
> > +		slot_power_limit_mw = 0;
> > +
> > +	/* Calculate Slot Power Limit Value and Slot Power Limit Scale */
> > +	if (slot_power_limit_mw == 0) {
> > +		value = 0x00;
> > +		scale = 0;
> > +	} else if (slot_power_limit_mw <= 255) {
> > +		value = slot_power_limit_mw;
> > +		scale = 3;
> > +	} else if (slot_power_limit_mw <= 255*10) {
> > +		value = slot_power_limit_mw / 10;
> > +		scale = 2;
> > +		slot_power_limit_mw = slot_power_limit_mw / 10 * 10;
> > +	} else if (slot_power_limit_mw <= 255*100) {
> > +		value = slot_power_limit_mw / 100;
> > +		scale = 1;
> > +		slot_power_limit_mw = slot_power_limit_mw / 100 * 100;
> > +	} else if (slot_power_limit_mw <= 239*1000) {
> > +		value = slot_power_limit_mw / 1000;
> > +		scale = 0;
> > +		slot_power_limit_mw = slot_power_limit_mw / 1000 * 1000;
> > +	} else if (slot_power_limit_mw < 250*1000) {
> > +		value = 0xEF;
> > +		scale = 0;
> > +		slot_power_limit_mw = 239*1000;
> > +	} else if (slot_power_limit_mw <= 600*1000) {
> > +		value = 0xF0 + (slot_power_limit_mw / 1000 - 250) / 25;
> > +		scale = 0;
> > +		slot_power_limit_mw = slot_power_limit_mw / (1000*25) * (1000*25);
> > +	} else {
> > +		value = 0xFE;
> > +		scale = 0;
> > +		slot_power_limit_mw = 600*1000;
> > +	}
> > +
> > +	if (slot_power_limit_value)
> > +		*slot_power_limit_value = value;
> > +
> > +	if (slot_power_limit_scale)
> > +		*slot_power_limit_scale = scale;
> > +
> > +	return slot_power_limit_mw;
> > +}
> > +EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit);
> > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> > index 3d60cabde1a1..e10cdec6c56e 100644
> > --- a/drivers/pci/pci.h
> > +++ b/drivers/pci/pci.h
> > @@ -627,6 +627,9 @@ struct device_node;
> >  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
> >  int of_get_pci_domain_nr(struct device_node *node);
> >  int of_pci_get_max_link_speed(struct device_node *node);
> > +u32 of_pci_get_slot_power_limit(struct device_node *node,
> > +				u8 *slot_power_limit_value,
> > +				u8 *slot_power_limit_scale);
> >  void pci_set_of_node(struct pci_dev *dev);
> >  void pci_release_of_node(struct pci_dev *dev);
> >  void pci_set_bus_of_node(struct pci_bus *bus);
> > @@ -653,6 +656,18 @@ of_pci_get_max_link_speed(struct device_node *node)
> >  	return -EINVAL;
> >  }
> >  
> > +static inline u32
> > +of_pci_get_slot_power_limit(struct device_node *node,
> > +			    u8 *slot_power_limit_value,
> > +			    u8 *slot_power_limit_scale)
> > +{
> > +	if (slot_power_limit_value)
> > +		*slot_power_limit_value = 0;
> > +	if (slot_power_limit_scale)
> > +		*slot_power_limit_scale = 0;
> > +	return 0;
> > +}
> > +
> >  static inline void pci_set_of_node(struct pci_dev *dev) { }
> >  static inline void pci_release_of_node(struct pci_dev *dev) { }
> >  static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
> > -- 
> > 2.20.1
> > 
> > 
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Lorenzo Pieralisi April 22, 2022, 10:06 a.m. UTC | #3
On Thu, Apr 21, 2022 at 10:14:13PM +0200, Pali Rohár wrote:
> On Wednesday 13 April 2022 15:24:33 Bjorn Helgaas wrote:
> > On Tue, Apr 12, 2022 at 11:49:45AM +0200, Pali Rohár wrote:
> > > Add function of_pci_get_slot_power_limit(), which parses the
> > > 'slot-power-limit-milliwatt' DT property, returning the value in
> > > milliwatts and in format ready for the PCIe Slot Capabilities Register.
> > > 
> > > Signed-off-by: Pali Rohár <pali@kernel.org>
> > > Signed-off-by: Marek Behún <kabel@kernel.org>
> > > Reviewed-by: Rob Herring <robh@kernel.org>
> > 
> > Looks good to me!  Thank you!
> > 
> > Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>
> 
> Perfect!
> 
> Lorenzo, is this patch series OK now for merging?

Yes it is. I have a related question (ie how to check whether a binding
has been accepted into the DT schema) but I will sort that out with
Rob.

Thanks,
Lorenzo

> > > ---
> > > Changes in v4:
> > > * Set 239 W when DT slot-power-limit-milliwatt is between 239 W and 250 W
> > > * Fix returning power limit value
> > > Changes in v3:
> > > * Set 600 W when DT slot-power-limit-milliwatt > 600 W
> > > Changes in v2:
> > > * Added support for PCIe 6.0 slot power limit encodings
> > > * Round down slot power limit value
> > > ---
> > >  drivers/pci/of.c  | 70 +++++++++++++++++++++++++++++++++++++++++++++++
> > >  drivers/pci/pci.h | 15 ++++++++++
> > >  2 files changed, 85 insertions(+)
> > > 
> > > diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> > > index cb2e8351c2cc..6c1b81304665 100644
> > > --- a/drivers/pci/of.c
> > > +++ b/drivers/pci/of.c
> > > @@ -633,3 +633,73 @@ int of_pci_get_max_link_speed(struct device_node *node)
> > >  	return max_link_speed;
> > >  }
> > >  EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
> > > +
> > > +/**
> > > + * of_pci_get_slot_power_limit - Parses the "slot-power-limit-milliwatt"
> > > + *				 property.
> > > + *
> > > + * @node: device tree node with the slot power limit information
> > > + * @slot_power_limit_value: pointer where the value should be stored in PCIe
> > > + *			    Slot Capabilities Register format
> > > + * @slot_power_limit_scale: pointer where the scale should be stored in PCIe
> > > + *			    Slot Capabilities Register format
> > > + *
> > > + * Returns the slot power limit in milliwatts and if @slot_power_limit_value
> > > + * and @slot_power_limit_scale pointers are non-NULL, fills in the value and
> > > + * scale in format used by PCIe Slot Capabilities Register.
> > > + *
> > > + * If the property is not found or is invalid, returns 0.
> > > + */
> > > +u32 of_pci_get_slot_power_limit(struct device_node *node,
> > > +				u8 *slot_power_limit_value,
> > > +				u8 *slot_power_limit_scale)
> > > +{
> > > +	u32 slot_power_limit_mw;
> > > +	u8 value, scale;
> > > +
> > > +	if (of_property_read_u32(node, "slot-power-limit-milliwatt",
> > > +				 &slot_power_limit_mw))
> > > +		slot_power_limit_mw = 0;
> > > +
> > > +	/* Calculate Slot Power Limit Value and Slot Power Limit Scale */
> > > +	if (slot_power_limit_mw == 0) {
> > > +		value = 0x00;
> > > +		scale = 0;
> > > +	} else if (slot_power_limit_mw <= 255) {
> > > +		value = slot_power_limit_mw;
> > > +		scale = 3;
> > > +	} else if (slot_power_limit_mw <= 255*10) {
> > > +		value = slot_power_limit_mw / 10;
> > > +		scale = 2;
> > > +		slot_power_limit_mw = slot_power_limit_mw / 10 * 10;
> > > +	} else if (slot_power_limit_mw <= 255*100) {
> > > +		value = slot_power_limit_mw / 100;
> > > +		scale = 1;
> > > +		slot_power_limit_mw = slot_power_limit_mw / 100 * 100;
> > > +	} else if (slot_power_limit_mw <= 239*1000) {
> > > +		value = slot_power_limit_mw / 1000;
> > > +		scale = 0;
> > > +		slot_power_limit_mw = slot_power_limit_mw / 1000 * 1000;
> > > +	} else if (slot_power_limit_mw < 250*1000) {
> > > +		value = 0xEF;
> > > +		scale = 0;
> > > +		slot_power_limit_mw = 239*1000;
> > > +	} else if (slot_power_limit_mw <= 600*1000) {
> > > +		value = 0xF0 + (slot_power_limit_mw / 1000 - 250) / 25;
> > > +		scale = 0;
> > > +		slot_power_limit_mw = slot_power_limit_mw / (1000*25) * (1000*25);
> > > +	} else {
> > > +		value = 0xFE;
> > > +		scale = 0;
> > > +		slot_power_limit_mw = 600*1000;
> > > +	}
> > > +
> > > +	if (slot_power_limit_value)
> > > +		*slot_power_limit_value = value;
> > > +
> > > +	if (slot_power_limit_scale)
> > > +		*slot_power_limit_scale = scale;
> > > +
> > > +	return slot_power_limit_mw;
> > > +}
> > > +EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit);
> > > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> > > index 3d60cabde1a1..e10cdec6c56e 100644
> > > --- a/drivers/pci/pci.h
> > > +++ b/drivers/pci/pci.h
> > > @@ -627,6 +627,9 @@ struct device_node;
> > >  int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
> > >  int of_get_pci_domain_nr(struct device_node *node);
> > >  int of_pci_get_max_link_speed(struct device_node *node);
> > > +u32 of_pci_get_slot_power_limit(struct device_node *node,
> > > +				u8 *slot_power_limit_value,
> > > +				u8 *slot_power_limit_scale);
> > >  void pci_set_of_node(struct pci_dev *dev);
> > >  void pci_release_of_node(struct pci_dev *dev);
> > >  void pci_set_bus_of_node(struct pci_bus *bus);
> > > @@ -653,6 +656,18 @@ of_pci_get_max_link_speed(struct device_node *node)
> > >  	return -EINVAL;
> > >  }
> > >  
> > > +static inline u32
> > > +of_pci_get_slot_power_limit(struct device_node *node,
> > > +			    u8 *slot_power_limit_value,
> > > +			    u8 *slot_power_limit_scale)
> > > +{
> > > +	if (slot_power_limit_value)
> > > +		*slot_power_limit_value = 0;
> > > +	if (slot_power_limit_scale)
> > > +		*slot_power_limit_scale = 0;
> > > +	return 0;
> > > +}
> > > +
> > >  static inline void pci_set_of_node(struct pci_dev *dev) { }
> > >  static inline void pci_release_of_node(struct pci_dev *dev) { }
> > >  static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
> > > -- 
> > > 2.20.1
> > > 
> > > 
> > > _______________________________________________
> > > linux-arm-kernel mailing list
> > > linux-arm-kernel@lists.infradead.org
> > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff mbox series

Patch

diff --git a/drivers/pci/of.c b/drivers/pci/of.c
index cb2e8351c2cc..6c1b81304665 100644
--- a/drivers/pci/of.c
+++ b/drivers/pci/of.c
@@ -633,3 +633,73 @@  int of_pci_get_max_link_speed(struct device_node *node)
 	return max_link_speed;
 }
 EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed);
+
+/**
+ * of_pci_get_slot_power_limit - Parses the "slot-power-limit-milliwatt"
+ *				 property.
+ *
+ * @node: device tree node with the slot power limit information
+ * @slot_power_limit_value: pointer where the value should be stored in PCIe
+ *			    Slot Capabilities Register format
+ * @slot_power_limit_scale: pointer where the scale should be stored in PCIe
+ *			    Slot Capabilities Register format
+ *
+ * Returns the slot power limit in milliwatts and if @slot_power_limit_value
+ * and @slot_power_limit_scale pointers are non-NULL, fills in the value and
+ * scale in format used by PCIe Slot Capabilities Register.
+ *
+ * If the property is not found or is invalid, returns 0.
+ */
+u32 of_pci_get_slot_power_limit(struct device_node *node,
+				u8 *slot_power_limit_value,
+				u8 *slot_power_limit_scale)
+{
+	u32 slot_power_limit_mw;
+	u8 value, scale;
+
+	if (of_property_read_u32(node, "slot-power-limit-milliwatt",
+				 &slot_power_limit_mw))
+		slot_power_limit_mw = 0;
+
+	/* Calculate Slot Power Limit Value and Slot Power Limit Scale */
+	if (slot_power_limit_mw == 0) {
+		value = 0x00;
+		scale = 0;
+	} else if (slot_power_limit_mw <= 255) {
+		value = slot_power_limit_mw;
+		scale = 3;
+	} else if (slot_power_limit_mw <= 255*10) {
+		value = slot_power_limit_mw / 10;
+		scale = 2;
+		slot_power_limit_mw = slot_power_limit_mw / 10 * 10;
+	} else if (slot_power_limit_mw <= 255*100) {
+		value = slot_power_limit_mw / 100;
+		scale = 1;
+		slot_power_limit_mw = slot_power_limit_mw / 100 * 100;
+	} else if (slot_power_limit_mw <= 239*1000) {
+		value = slot_power_limit_mw / 1000;
+		scale = 0;
+		slot_power_limit_mw = slot_power_limit_mw / 1000 * 1000;
+	} else if (slot_power_limit_mw < 250*1000) {
+		value = 0xEF;
+		scale = 0;
+		slot_power_limit_mw = 239*1000;
+	} else if (slot_power_limit_mw <= 600*1000) {
+		value = 0xF0 + (slot_power_limit_mw / 1000 - 250) / 25;
+		scale = 0;
+		slot_power_limit_mw = slot_power_limit_mw / (1000*25) * (1000*25);
+	} else {
+		value = 0xFE;
+		scale = 0;
+		slot_power_limit_mw = 600*1000;
+	}
+
+	if (slot_power_limit_value)
+		*slot_power_limit_value = value;
+
+	if (slot_power_limit_scale)
+		*slot_power_limit_scale = scale;
+
+	return slot_power_limit_mw;
+}
+EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 3d60cabde1a1..e10cdec6c56e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -627,6 +627,9 @@  struct device_node;
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 int of_get_pci_domain_nr(struct device_node *node);
 int of_pci_get_max_link_speed(struct device_node *node);
+u32 of_pci_get_slot_power_limit(struct device_node *node,
+				u8 *slot_power_limit_value,
+				u8 *slot_power_limit_scale);
 void pci_set_of_node(struct pci_dev *dev);
 void pci_release_of_node(struct pci_dev *dev);
 void pci_set_bus_of_node(struct pci_bus *bus);
@@ -653,6 +656,18 @@  of_pci_get_max_link_speed(struct device_node *node)
 	return -EINVAL;
 }
 
+static inline u32
+of_pci_get_slot_power_limit(struct device_node *node,
+			    u8 *slot_power_limit_value,
+			    u8 *slot_power_limit_scale)
+{
+	if (slot_power_limit_value)
+		*slot_power_limit_value = 0;
+	if (slot_power_limit_scale)
+		*slot_power_limit_scale = 0;
+	return 0;
+}
+
 static inline void pci_set_of_node(struct pci_dev *dev) { }
 static inline void pci_release_of_node(struct pci_dev *dev) { }
 static inline void pci_set_bus_of_node(struct pci_bus *bus) { }