PCI: Add function for parsing 'slot-power-limit-milliwatt' DT property
authorPali Rohár <pali@kernel.org>
Tue, 12 Apr 2022 09:49:45 +0000 (11:49 +0200)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Mon, 25 Apr 2022 09:53:39 +0000 (10:53 +0100)
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.

Link: https://lore.kernel.org/r/20220412094946.27069-4-pali@kernel.org
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Marek Behún <kabel@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/of.c
drivers/pci/pci.h

index cb2e835..6c1b813 100644 (file)
@@ -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);
index 3d60cab..e10cdec 100644 (file)
@@ -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) { }