powercap: intel_rapl: Add support for lock bit per Power Limit
[linux-2.6-microblaze.git] / drivers / powercap / intel_rapl_common.c
index 7f80c35..d880083 100644 (file)
@@ -94,7 +94,6 @@ enum unit_type {
 
 #define        DOMAIN_STATE_INACTIVE           BIT(0)
 #define        DOMAIN_STATE_POWER_LIMIT_SET    BIT(1)
-#define DOMAIN_STATE_BIOS_LOCKED        BIT(2)
 
 static const char *pl_names[NR_POWER_LIMITS] = {
        [POWER_LIMIT1] = "long_term",
@@ -108,6 +107,7 @@ enum pl_prims {
        PL_LIMIT,
        PL_TIME_WINDOW,
        PL_MAX_POWER,
+       PL_LOCK,
 };
 
 static bool is_pl_valid(struct rapl_domain *rd, int pl)
@@ -117,7 +117,18 @@ static bool is_pl_valid(struct rapl_domain *rd, int pl)
        return rd->rpl[pl].name ? true : false;
 }
 
-static int get_pl_prim(int pl, enum pl_prims prim)
+static int get_pl_lock_prim(struct rapl_domain *rd, int pl)
+{
+       /*
+        * Power Limit register that supports two power limits has a different
+        * bit position for the Lock bit.
+        */
+       if (rd->rp->priv->limits[rd->id] & BIT(POWER_LIMIT2))
+               return FW_HIGH_LOCK;
+       return FW_LOCK;
+}
+
+static int get_pl_prim(struct rapl_domain *rd, int pl, enum pl_prims prim)
 {
        switch (pl) {
        case POWER_LIMIT1:
@@ -131,6 +142,8 @@ static int get_pl_prim(int pl, enum pl_prims prim)
                        return TIME_WINDOW1;
                if (prim == PL_MAX_POWER)
                        return THERMAL_SPEC_POWER;
+               if (prim == PL_LOCK)
+                       return get_pl_lock_prim(rd, pl);
                return -EINVAL;
        case POWER_LIMIT2:
                if (prim == PL_ENABLE)
@@ -143,6 +156,8 @@ static int get_pl_prim(int pl, enum pl_prims prim)
                        return TIME_WINDOW2;
                if (prim == PL_MAX_POWER)
                        return MAX_POWER;
+               if (prim == PL_LOCK)
+                       return get_pl_lock_prim(rd, pl);
                return -EINVAL;
        case POWER_LIMIT4:
                if (prim == PL_LIMIT)
@@ -314,7 +329,7 @@ static int get_domain_enable(struct powercap_zone *power_zone, bool *mode)
        u64 val;
        int ret;
 
-       if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
+       if (rd->rpl[POWER_LIMIT1].locked) {
                *mode = false;
                return 0;
        }
@@ -599,6 +614,8 @@ static struct rapl_primitive_info rpi_default[NR_RAPL_PRIMITIVES] = {
                            RAPL_DOMAIN_REG_STATUS, ENERGY_UNIT, 0),
        [FW_LOCK] = PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
                            RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+       [FW_HIGH_LOCK] = PRIMITIVE_INFO_INIT(FW_LOCK, POWER_HIGH_LOCK, 63,
+                           RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
        [PL1_ENABLE] = PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
                            RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
        [PL1_CLAMP] = PRIMITIVE_INFO_INIT(PL1_CLAMP, POWER_LIMIT1_CLAMP, 16,
@@ -719,11 +736,6 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 
        cpu = rd->rp->lead_cpu;
 
-       /* domain with 2 limits has different bit */
-       if (prim == FW_LOCK && (rd->rp->priv->limits[rd->id] & BIT(POWER_LIMIT2))) {
-               rpi->mask = POWER_HIGH_LOCK;
-               rpi->shift = 63;
-       }
        /* non-hardware data are collected by the polling thread */
        if (rpi->flag & RAPL_PRIMITIVE_DERIVED) {
                *data = rd->rdd.primitives[prim];
@@ -781,7 +793,7 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
 static int rapl_read_pl_data(struct rapl_domain *rd, int pl,
                              enum pl_prims pl_prim, bool xlate, u64 *data)
 {
-       enum rapl_primitives prim = get_pl_prim(pl, pl_prim);
+       enum rapl_primitives prim = get_pl_prim(rd, pl, pl_prim);
 
        if (!is_pl_valid(rd, pl))
                return -EINVAL;
@@ -793,12 +805,12 @@ static int rapl_write_pl_data(struct rapl_domain *rd, int pl,
                               enum pl_prims pl_prim,
                               unsigned long long value)
 {
-       enum rapl_primitives prim = get_pl_prim(pl, pl_prim);
+       enum rapl_primitives prim = get_pl_prim(rd, pl, pl_prim);
 
        if (!is_pl_valid(rd, pl))
                return -EINVAL;
 
-       if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
+       if (rd->rpl[pl].locked) {
                pr_warn("%s:%s:%s locked by BIOS\n", rd->rp->name, rd->name, pl_names[pl]);
                return -EACCES;
        }
@@ -1305,17 +1317,15 @@ static void rapl_detect_powerlimit(struct rapl_domain *rd)
        u64 val64;
        int i;
 
-       /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
-       if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
-               if (val64) {
-                       pr_info("RAPL %s domain %s locked by BIOS\n",
-                               rd->rp->name, rd->name);
-                       rd->state |= DOMAIN_STATE_BIOS_LOCKED;
+       for (i = POWER_LIMIT1; i < NR_POWER_LIMITS; i++) {
+               if (!rapl_read_pl_data(rd, i, PL_LOCK, false, &val64)) {
+                       if (val64) {
+                               rd->rpl[i].locked = true;
+                               pr_info("%s:%s:%s locked by BIOS\n",
+                                       rd->rp->name, rd->name, pl_names[i]);
+                       }
                }
-       }
 
-       /* check if power limit exists, otherwise domain is monitoring only */
-       for (i = POWER_LIMIT1; i < NR_POWER_LIMITS; i++) {
                if (rapl_read_pl_data(rd, i, PL_ENABLE, false, &val64))
                        rd->rpl[i].name = NULL;
        }