habanalabs: enable power info via HWMON framework
authorRajaravi Krishna Katta <rkatta@habana.ai>
Wed, 18 Aug 2021 05:12:41 +0000 (08:12 +0300)
committerOded Gabbay <ogabbay@kernel.org>
Mon, 18 Oct 2021 09:05:46 +0000 (12:05 +0300)
Add support to retrieve following power info via HWMON:
- instantaneous power value
- highest value since last reset
- reset the highest place holder

Signed-off-by: Rajaravi Krishna Katta <rkatta@habana.ai>
Reviewed-by: Oded Gabbay <ogabbay@kernel.org>
Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/hwmon.c
drivers/misc/habanalabs/include/common/cpucp_if.h

index bebebcb..f8e23ca 100644 (file)
@@ -2956,6 +2956,10 @@ int hl_set_voltage(struct hl_device *hdev,
                        int sensor_index, u32 attr, long value);
 int hl_set_current(struct hl_device *hdev,
                        int sensor_index, u32 attr, long value);
+int hl_set_power(struct hl_device *hdev,
+                       int sensor_index, u32 attr, long value);
+int hl_get_power(struct hl_device *hdev,
+                       int sensor_index, u32 attr, long *value);
 void hw_sob_get(struct hl_hw_sob *hw_sob);
 void hw_sob_put(struct hl_hw_sob *hw_sob);
 void hl_encaps_handle_do_release(struct kref *ref);
index 8f12d99..e33f65b 100644 (file)
@@ -236,6 +236,23 @@ static int hl_read(struct device *dev, enum hwmon_sensor_types type,
                else
                        rc = hl_get_pwm_info(hdev, channel, attr, val);
                break;
+       case hwmon_power:
+               switch (attr) {
+               case hwmon_power_input:
+                       cpucp_attr = CPUCP_POWER_INPUT;
+                       break;
+               case hwmon_power_input_highest:
+                       cpucp_attr = CPUCP_POWER_INPUT_HIGHEST;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (use_cpucp_enum)
+                       rc = hl_get_power(hdev, channel, cpucp_attr, val);
+               else
+                       rc = hl_get_power(hdev, channel, attr, val);
+               break;
        default:
                return -EINVAL;
        }
@@ -316,6 +333,20 @@ static int hl_write(struct device *dev, enum hwmon_sensor_types type,
                else
                        hl_set_current(hdev, channel, attr, val);
                break;
+       case hwmon_power:
+               switch (attr) {
+               case hwmon_power_reset_history:
+                       cpucp_attr = CPUCP_POWER_RESET_INPUT_HISTORY;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (use_cpucp_enum)
+                       hl_set_power(hdev, channel, cpucp_attr, val);
+               else
+                       hl_set_power(hdev, channel, attr, val);
+               break;
        default:
                return -EINVAL;
        }
@@ -378,6 +409,15 @@ static umode_t hl_is_visible(const void *data, enum hwmon_sensor_types type,
                        return 0644;
                }
                break;
+       case hwmon_power:
+               switch (attr) {
+               case hwmon_power_input:
+               case hwmon_power_input_highest:
+                       return 0444;
+               case hwmon_power_reset_history:
+                       return 0200;
+               }
+               break;
        default:
                break;
        }
@@ -633,6 +673,60 @@ int hl_set_current(struct hl_device *hdev,
        return rc;
 }
 
+int hl_set_power(struct hl_device *hdev,
+                       int sensor_index, u32 attr, long value)
+{
+       struct cpucp_packet pkt;
+       int rc;
+
+       memset(&pkt, 0, sizeof(pkt));
+
+       pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET <<
+                               CPUCP_PKT_CTL_OPCODE_SHIFT);
+       pkt.sensor_index = __cpu_to_le16(sensor_index);
+       pkt.type = __cpu_to_le16(attr);
+       pkt.value = __cpu_to_le64(value);
+
+       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
+                                               0, NULL);
+
+       if (rc)
+               dev_err(hdev->dev,
+                       "Failed to set power of sensor %d, error %d\n",
+                       sensor_index, rc);
+
+       return rc;
+}
+
+int hl_get_power(struct hl_device *hdev,
+                       int sensor_index, u32 attr, long *value)
+{
+       struct cpucp_packet pkt;
+       u64 result;
+       int rc;
+
+       memset(&pkt, 0, sizeof(pkt));
+
+       pkt.ctl = cpu_to_le32(CPUCP_PACKET_POWER_GET <<
+                               CPUCP_PKT_CTL_OPCODE_SHIFT);
+       pkt.sensor_index = __cpu_to_le16(sensor_index);
+       pkt.type = __cpu_to_le16(attr);
+
+       rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt),
+                                               0, &result);
+
+       *value = (long) result;
+
+       if (rc) {
+               dev_err(hdev->dev,
+                       "Failed to get power of sensor %d, error %d\n",
+                       sensor_index, rc);
+               *value = 0;
+       }
+
+       return rc;
+}
+
 int hl_hwmon_init(struct hl_device *hdev)
 {
        struct device *dev = hdev->pdev ? &hdev->pdev->dev : hdev->dev;
index 9ff6a44..a6fa1cf 100644 (file)
@@ -598,6 +598,16 @@ enum cpucp_pll_type_attributes {
        cpucp_pll_pci,
 };
 
+/*
+ * cpucp_power_type aligns with hwmon_power_attributes
+ * defined in Linux kernel hwmon.h file
+ */
+enum cpucp_power_type {
+       CPUCP_POWER_INPUT = 8,
+       CPUCP_POWER_INPUT_HIGHEST = 9,
+       CPUCP_POWER_RESET_INPUT_HISTORY = 11
+};
+
 /*
  * MSI type enumeration table for all ASICs and future SW versions.
  * For future ASIC-LKD compatibility, we can only add new enumerations.