| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994 |
- // SPDX-License-Identifier: MIT
- /*
- * Copyright © 2022 Intel Corporation
- */
- #include <linux/hwmon.h>
- #include <linux/hwmon-sysfs.h>
- #include <linux/jiffies.h>
- #include <linux/types.h>
- #include <linux/units.h>
- #include "i915_drv.h"
- #include "i915_hwmon.h"
- #include "i915_reg.h"
- #include "intel_mchbar_regs.h"
- #include "intel_pcode.h"
- #include "gt/intel_gt.h"
- #include "gt/intel_gt_regs.h"
- /*
- * SF_* - scale factors for particular quantities according to hwmon spec.
- * - voltage - millivolts
- * - power - microwatts
- * - curr - milliamperes
- * - energy - microjoules
- * - time - milliseconds
- */
- #define SF_VOLTAGE 1000
- #define SF_POWER 1000000
- #define SF_CURR 1000
- #define SF_ENERGY 1000000
- #define SF_TIME 1000
- struct hwm_reg {
- i915_reg_t gt_perf_status;
- i915_reg_t pkg_temp;
- i915_reg_t pkg_power_sku_unit;
- i915_reg_t pkg_power_sku;
- i915_reg_t pkg_rapl_limit;
- i915_reg_t energy_status_all;
- i915_reg_t energy_status_tile;
- i915_reg_t fan_speed;
- };
- struct hwm_energy_info {
- u32 reg_val_prev;
- long accum_energy; /* Accumulated energy for energy1_input */
- };
- struct hwm_fan_info {
- u32 reg_val_prev;
- u64 time_prev;
- };
- struct hwm_drvdata {
- struct i915_hwmon *hwmon;
- struct intel_uncore *uncore;
- struct device *hwmon_dev;
- struct hwm_energy_info ei; /* Energy info for energy1_input */
- struct hwm_fan_info fi; /* Fan info for fan1_input */
- char name[12];
- int gt_n;
- bool reset_in_progress;
- wait_queue_head_t waitq;
- };
- struct i915_hwmon {
- struct hwm_drvdata ddat;
- struct hwm_drvdata ddat_gt[I915_MAX_GT];
- struct mutex hwmon_lock; /* counter overflow logic and rmw */
- struct hwm_reg rg;
- int scl_shift_power;
- int scl_shift_energy;
- int scl_shift_time;
- };
- static void
- hwm_locked_with_pm_intel_uncore_rmw(struct hwm_drvdata *ddat,
- i915_reg_t reg, u32 clear, u32 set)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- struct intel_uncore *uncore = ddat->uncore;
- intel_wakeref_t wakeref;
- with_intel_runtime_pm(uncore->rpm, wakeref) {
- mutex_lock(&hwmon->hwmon_lock);
- intel_uncore_rmw(uncore, reg, clear, set);
- mutex_unlock(&hwmon->hwmon_lock);
- }
- }
- /*
- * This function's return type of u64 allows for the case where the scaling
- * of the field taken from the 32-bit register value might cause a result to
- * exceed 32 bits.
- */
- static u64
- hwm_field_read_and_scale(struct hwm_drvdata *ddat, i915_reg_t rgadr,
- u32 field_msk, int nshift, u32 scale_factor)
- {
- struct intel_uncore *uncore = ddat->uncore;
- intel_wakeref_t wakeref;
- u32 reg_value;
- with_intel_runtime_pm(uncore->rpm, wakeref)
- reg_value = intel_uncore_read(uncore, rgadr);
- reg_value = REG_FIELD_GET(field_msk, reg_value);
- return mul_u64_u32_shr(reg_value, scale_factor, nshift);
- }
- /*
- * hwm_energy - Obtain energy value
- *
- * The underlying energy hardware register is 32-bits and is subject to
- * overflow. How long before overflow? For example, with an example
- * scaling bit shift of 14 bits (see register *PACKAGE_POWER_SKU_UNIT) and
- * a power draw of 1000 watts, the 32-bit counter will overflow in
- * approximately 4.36 minutes.
- *
- * Examples:
- * 1 watt: (2^32 >> 14) / 1 W / (60 * 60 * 24) secs/day -> 3 days
- * 1000 watts: (2^32 >> 14) / 1000 W / 60 secs/min -> 4.36 minutes
- *
- * The function significantly increases overflow duration (from 4.36
- * minutes) by accumulating the energy register into a 'long' as allowed by
- * the hwmon API. Using x86_64 128 bit arithmetic (see mul_u64_u32_shr()),
- * a 'long' of 63 bits, SF_ENERGY of 1e6 (~20 bits) and
- * hwmon->scl_shift_energy of 14 bits we have 57 (63 - 20 + 14) bits before
- * energy1_input overflows. This at 1000 W is an overflow duration of 278 years.
- */
- static void
- hwm_energy(struct hwm_drvdata *ddat, long *energy)
- {
- struct intel_uncore *uncore = ddat->uncore;
- struct i915_hwmon *hwmon = ddat->hwmon;
- struct hwm_energy_info *ei = &ddat->ei;
- intel_wakeref_t wakeref;
- i915_reg_t rgaddr;
- u32 reg_val;
- if (ddat->gt_n >= 0)
- rgaddr = hwmon->rg.energy_status_tile;
- else
- rgaddr = hwmon->rg.energy_status_all;
- with_intel_runtime_pm(uncore->rpm, wakeref) {
- mutex_lock(&hwmon->hwmon_lock);
- reg_val = intel_uncore_read(uncore, rgaddr);
- if (reg_val >= ei->reg_val_prev)
- ei->accum_energy += reg_val - ei->reg_val_prev;
- else
- ei->accum_energy += UINT_MAX - ei->reg_val_prev + reg_val;
- ei->reg_val_prev = reg_val;
- *energy = mul_u64_u32_shr(ei->accum_energy, SF_ENERGY,
- hwmon->scl_shift_energy);
- mutex_unlock(&hwmon->hwmon_lock);
- }
- }
- static ssize_t
- hwm_power1_max_interval_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct hwm_drvdata *ddat = dev_get_drvdata(dev);
- struct i915_hwmon *hwmon = ddat->hwmon;
- intel_wakeref_t wakeref;
- u32 r, x, y, x_w = 2; /* 2 bits */
- u64 tau4, out;
- with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
- r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
- x = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_X, r);
- y = REG_FIELD_GET(PKG_PWR_LIM_1_TIME_Y, r);
- /*
- * tau = 1.x * power(2,y), x = bits(23:22), y = bits(21:17)
- * = (4 | x) << (y - 2)
- * where (y - 2) ensures a 1.x fixed point representation of 1.x
- * However because y can be < 2, we compute
- * tau4 = (4 | x) << y
- * but add 2 when doing the final right shift to account for units
- */
- tau4 = (u64)((1 << x_w) | x) << y;
- /* val in hwmon interface units (millisec) */
- out = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
- return sysfs_emit(buf, "%llu\n", out);
- }
- static ssize_t
- hwm_power1_max_interval_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct hwm_drvdata *ddat = dev_get_drvdata(dev);
- struct i915_hwmon *hwmon = ddat->hwmon;
- u32 x, y, rxy, x_w = 2; /* 2 bits */
- u64 tau4, r, max_win;
- unsigned long val;
- int ret;
- ret = kstrtoul(buf, 0, &val);
- if (ret)
- return ret;
- /*
- * Max HW supported tau in '1.x * power(2,y)' format, x = 0, y = 0x12
- * The hwmon->scl_shift_time default of 0xa results in a max tau of 256 seconds
- */
- #define PKG_MAX_WIN_DEFAULT 0x12ull
- /*
- * val must be < max in hwmon interface units. The steps below are
- * explained in i915_power1_max_interval_show()
- */
- r = FIELD_PREP(PKG_MAX_WIN, PKG_MAX_WIN_DEFAULT);
- x = REG_FIELD_GET(PKG_MAX_WIN_X, r);
- y = REG_FIELD_GET(PKG_MAX_WIN_Y, r);
- tau4 = (u64)((1 << x_w) | x) << y;
- max_win = mul_u64_u32_shr(tau4, SF_TIME, hwmon->scl_shift_time + x_w);
- if (val > max_win)
- return -EINVAL;
- /* val in hw units */
- val = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_time, SF_TIME);
- /* Convert to 1.x * power(2,y) */
- if (!val) {
- /* Avoid ilog2(0) */
- y = 0;
- x = 0;
- } else {
- y = ilog2(val);
- /* x = (val - (1 << y)) >> (y - 2); */
- x = (val - (1ul << y)) << x_w >> y;
- }
- rxy = REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_X, x) | REG_FIELD_PREP(PKG_PWR_LIM_1_TIME_Y, y);
- hwm_locked_with_pm_intel_uncore_rmw(ddat, hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1_TIME, rxy);
- return count;
- }
- static SENSOR_DEVICE_ATTR(power1_max_interval, 0664,
- hwm_power1_max_interval_show,
- hwm_power1_max_interval_store, 0);
- static struct attribute *hwm_attributes[] = {
- &sensor_dev_attr_power1_max_interval.dev_attr.attr,
- NULL
- };
- static umode_t hwm_attributes_visible(struct kobject *kobj,
- struct attribute *attr, int index)
- {
- struct device *dev = kobj_to_dev(kobj);
- struct hwm_drvdata *ddat = dev_get_drvdata(dev);
- struct i915_hwmon *hwmon = ddat->hwmon;
- if (attr == &sensor_dev_attr_power1_max_interval.dev_attr.attr)
- return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? attr->mode : 0;
- return 0;
- }
- static const struct attribute_group hwm_attrgroup = {
- .attrs = hwm_attributes,
- .is_visible = hwm_attributes_visible,
- };
- static const struct attribute_group *hwm_groups[] = {
- &hwm_attrgroup,
- NULL
- };
- static const struct hwmon_channel_info * const hwm_info[] = {
- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
- HWMON_CHANNEL_INFO(in, HWMON_I_INPUT),
- HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT),
- HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
- HWMON_CHANNEL_INFO(curr, HWMON_C_CRIT),
- HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
- NULL
- };
- static const struct hwmon_channel_info * const hwm_gt_info[] = {
- HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT),
- NULL
- };
- /* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
- static int hwm_pcode_read_i1(struct drm_i915_private *i915, u32 *uval)
- {
- /* Avoid ILLEGAL_SUBCOMMAND "mailbox access failed" warning in snb_pcode_read */
- if (IS_DG1(i915) || IS_DG2(i915))
- return -ENXIO;
- return snb_pcode_read_p(&i915->uncore, PCODE_POWER_SETUP,
- POWER_SETUP_SUBCOMMAND_READ_I1, 0, uval);
- }
- static int hwm_pcode_write_i1(struct drm_i915_private *i915, u32 uval)
- {
- return snb_pcode_write_p(&i915->uncore, PCODE_POWER_SETUP,
- POWER_SETUP_SUBCOMMAND_WRITE_I1, 0, uval);
- }
- static umode_t
- hwm_temp_is_visible(const struct hwm_drvdata *ddat, u32 attr)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- if (attr == hwmon_temp_input && i915_mmio_reg_valid(hwmon->rg.pkg_temp))
- return 0444;
- return 0;
- }
- static int
- hwm_temp_read(struct hwm_drvdata *ddat, u32 attr, long *val)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- intel_wakeref_t wakeref;
- u32 reg_val;
- switch (attr) {
- case hwmon_temp_input:
- with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
- reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_temp);
- /* HW register value is in degrees Celsius, convert to millidegrees. */
- *val = REG_FIELD_GET(TEMP_MASK, reg_val) * MILLIDEGREE_PER_DEGREE;
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
- static umode_t
- hwm_in_is_visible(const struct hwm_drvdata *ddat, u32 attr)
- {
- struct drm_i915_private *i915 = ddat->uncore->i915;
- switch (attr) {
- case hwmon_in_input:
- return IS_DG1(i915) || IS_DG2(i915) ? 0444 : 0;
- default:
- return 0;
- }
- }
- static int
- hwm_in_read(struct hwm_drvdata *ddat, u32 attr, long *val)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- intel_wakeref_t wakeref;
- u32 reg_value;
- switch (attr) {
- case hwmon_in_input:
- with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
- reg_value = intel_uncore_read(ddat->uncore, hwmon->rg.gt_perf_status);
- /* HW register value in units of 2.5 millivolt */
- *val = DIV_ROUND_CLOSEST(REG_FIELD_GET(GEN12_VOLTAGE_MASK, reg_value) * 25, 10);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
- static umode_t
- hwm_power_is_visible(const struct hwm_drvdata *ddat, u32 attr, int chan)
- {
- struct drm_i915_private *i915 = ddat->uncore->i915;
- struct i915_hwmon *hwmon = ddat->hwmon;
- u32 uval;
- switch (attr) {
- case hwmon_power_max:
- return i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit) ? 0664 : 0;
- case hwmon_power_rated_max:
- return i915_mmio_reg_valid(hwmon->rg.pkg_power_sku) ? 0444 : 0;
- case hwmon_power_crit:
- return (hwm_pcode_read_i1(i915, &uval) ||
- !(uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
- default:
- return 0;
- }
- }
- #define PL1_DISABLE 0
- /*
- * HW allows arbitrary PL1 limits to be set but silently clamps these values to
- * "typical but not guaranteed" min/max values in rg.pkg_power_sku. Follow the
- * same pattern for sysfs, allow arbitrary PL1 limits to be set but display
- * clamped values when read. Write/read I1 also follows the same pattern.
- */
- static int
- hwm_power_max_read(struct hwm_drvdata *ddat, long *val)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- intel_wakeref_t wakeref;
- u64 r, min, max;
- /* Check if PL1 limit is disabled */
- with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
- r = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
- if (!(r & PKG_PWR_LIM_1_EN)) {
- *val = PL1_DISABLE;
- return 0;
- }
- *val = hwm_field_read_and_scale(ddat,
- hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1,
- hwmon->scl_shift_power,
- SF_POWER);
- with_intel_runtime_pm(ddat->uncore->rpm, wakeref)
- r = intel_uncore_read64(ddat->uncore, hwmon->rg.pkg_power_sku);
- min = REG_FIELD_GET(PKG_MIN_PWR, r);
- min = mul_u64_u32_shr(min, SF_POWER, hwmon->scl_shift_power);
- max = REG_FIELD_GET(PKG_MAX_PWR, r);
- max = mul_u64_u32_shr(max, SF_POWER, hwmon->scl_shift_power);
- if (min && max)
- *val = clamp_t(u64, *val, min, max);
- return 0;
- }
- static int
- hwm_power_max_write(struct hwm_drvdata *ddat, long val)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- intel_wakeref_t wakeref;
- DEFINE_WAIT(wait);
- int ret = 0;
- u32 nval;
- /* Block waiting for GuC reset to complete when needed */
- for (;;) {
- wakeref = intel_runtime_pm_get(ddat->uncore->rpm);
- mutex_lock(&hwmon->hwmon_lock);
- prepare_to_wait(&ddat->waitq, &wait, TASK_INTERRUPTIBLE);
- if (!hwmon->ddat.reset_in_progress)
- break;
- if (signal_pending(current)) {
- ret = -EINTR;
- break;
- }
- mutex_unlock(&hwmon->hwmon_lock);
- intel_runtime_pm_put(ddat->uncore->rpm, wakeref);
- schedule();
- }
- finish_wait(&ddat->waitq, &wait);
- if (ret)
- goto exit;
- /* Disable PL1 limit and verify, because the limit cannot be disabled on all platforms */
- if (val == PL1_DISABLE) {
- intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1_EN, 0);
- nval = intel_uncore_read(ddat->uncore, hwmon->rg.pkg_rapl_limit);
- if (nval & PKG_PWR_LIM_1_EN)
- ret = -ENODEV;
- goto exit;
- }
- /* Computation in 64-bits to avoid overflow. Round to nearest. */
- nval = DIV_ROUND_CLOSEST_ULL((u64)val << hwmon->scl_shift_power, SF_POWER);
- nval = PKG_PWR_LIM_1_EN | REG_FIELD_PREP(PKG_PWR_LIM_1, nval);
- intel_uncore_rmw(ddat->uncore, hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1_EN | PKG_PWR_LIM_1, nval);
- exit:
- mutex_unlock(&hwmon->hwmon_lock);
- intel_runtime_pm_put(ddat->uncore->rpm, wakeref);
- return ret;
- }
- static int
- hwm_power_read(struct hwm_drvdata *ddat, u32 attr, int chan, long *val)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- int ret;
- u32 uval;
- switch (attr) {
- case hwmon_power_max:
- return hwm_power_max_read(ddat, val);
- case hwmon_power_rated_max:
- *val = hwm_field_read_and_scale(ddat,
- hwmon->rg.pkg_power_sku,
- PKG_PKG_TDP,
- hwmon->scl_shift_power,
- SF_POWER);
- return 0;
- case hwmon_power_crit:
- ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
- if (ret)
- return ret;
- if (!(uval & POWER_SETUP_I1_WATTS))
- return -ENODEV;
- *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
- SF_POWER, POWER_SETUP_I1_SHIFT);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
- static int
- hwm_power_write(struct hwm_drvdata *ddat, u32 attr, int chan, long val)
- {
- u32 uval;
- switch (attr) {
- case hwmon_power_max:
- return hwm_power_max_write(ddat, val);
- case hwmon_power_crit:
- uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_POWER);
- return hwm_pcode_write_i1(ddat->uncore->i915, uval);
- default:
- return -EOPNOTSUPP;
- }
- }
- void i915_hwmon_power_max_disable(struct drm_i915_private *i915, bool *old)
- {
- struct i915_hwmon *hwmon = i915->hwmon;
- u32 r;
- if (!hwmon || !i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit))
- return;
- mutex_lock(&hwmon->hwmon_lock);
- hwmon->ddat.reset_in_progress = true;
- r = intel_uncore_rmw(hwmon->ddat.uncore, hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1_EN, 0);
- *old = !!(r & PKG_PWR_LIM_1_EN);
- mutex_unlock(&hwmon->hwmon_lock);
- }
- void i915_hwmon_power_max_restore(struct drm_i915_private *i915, bool old)
- {
- struct i915_hwmon *hwmon = i915->hwmon;
- if (!hwmon || !i915_mmio_reg_valid(hwmon->rg.pkg_rapl_limit))
- return;
- mutex_lock(&hwmon->hwmon_lock);
- intel_uncore_rmw(hwmon->ddat.uncore, hwmon->rg.pkg_rapl_limit,
- PKG_PWR_LIM_1_EN, old ? PKG_PWR_LIM_1_EN : 0);
- hwmon->ddat.reset_in_progress = false;
- wake_up_all(&hwmon->ddat.waitq);
- mutex_unlock(&hwmon->hwmon_lock);
- }
- static umode_t
- hwm_energy_is_visible(const struct hwm_drvdata *ddat, u32 attr)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- i915_reg_t rgaddr;
- switch (attr) {
- case hwmon_energy_input:
- if (ddat->gt_n >= 0)
- rgaddr = hwmon->rg.energy_status_tile;
- else
- rgaddr = hwmon->rg.energy_status_all;
- return i915_mmio_reg_valid(rgaddr) ? 0444 : 0;
- default:
- return 0;
- }
- }
- static int
- hwm_energy_read(struct hwm_drvdata *ddat, u32 attr, long *val)
- {
- switch (attr) {
- case hwmon_energy_input:
- hwm_energy(ddat, val);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
- static umode_t
- hwm_curr_is_visible(const struct hwm_drvdata *ddat, u32 attr)
- {
- struct drm_i915_private *i915 = ddat->uncore->i915;
- u32 uval;
- switch (attr) {
- case hwmon_curr_crit:
- return (hwm_pcode_read_i1(i915, &uval) ||
- (uval & POWER_SETUP_I1_WATTS)) ? 0 : 0644;
- default:
- return 0;
- }
- }
- static int
- hwm_curr_read(struct hwm_drvdata *ddat, u32 attr, long *val)
- {
- int ret;
- u32 uval;
- switch (attr) {
- case hwmon_curr_crit:
- ret = hwm_pcode_read_i1(ddat->uncore->i915, &uval);
- if (ret)
- return ret;
- if (uval & POWER_SETUP_I1_WATTS)
- return -ENODEV;
- *val = mul_u64_u32_shr(REG_FIELD_GET(POWER_SETUP_I1_DATA_MASK, uval),
- SF_CURR, POWER_SETUP_I1_SHIFT);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- }
- static int
- hwm_curr_write(struct hwm_drvdata *ddat, u32 attr, long val)
- {
- u32 uval;
- switch (attr) {
- case hwmon_curr_crit:
- uval = DIV_ROUND_CLOSEST_ULL(val << POWER_SETUP_I1_SHIFT, SF_CURR);
- return hwm_pcode_write_i1(ddat->uncore->i915, uval);
- default:
- return -EOPNOTSUPP;
- }
- }
- static umode_t
- hwm_fan_is_visible(const struct hwm_drvdata *ddat, u32 attr)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- if (attr == hwmon_fan_input && i915_mmio_reg_valid(hwmon->rg.fan_speed))
- return 0444;
- return 0;
- }
- static int
- hwm_fan_input_read(struct hwm_drvdata *ddat, long *val)
- {
- struct i915_hwmon *hwmon = ddat->hwmon;
- struct hwm_fan_info *fi = &ddat->fi;
- u64 rotations, time_now, time;
- intel_wakeref_t wakeref;
- u32 reg_val;
- int ret = 0;
- wakeref = intel_runtime_pm_get(ddat->uncore->rpm);
- mutex_lock(&hwmon->hwmon_lock);
- reg_val = intel_uncore_read(ddat->uncore, hwmon->rg.fan_speed);
- time_now = get_jiffies_64();
- /*
- * HW register value is accumulated count of pulses from
- * PWM fan with the scale of 2 pulses per rotation.
- */
- rotations = (reg_val - fi->reg_val_prev) / 2;
- time = jiffies_delta_to_msecs(time_now - fi->time_prev);
- if (unlikely(!time)) {
- ret = -EAGAIN;
- goto exit;
- }
- /*
- * Calculate fan speed in RPM by time averaging two subsequent
- * readings in minutes.
- * RPM = number of rotations * msecs per minute / time in msecs
- */
- *val = DIV_ROUND_UP_ULL(rotations * (MSEC_PER_SEC * 60), time);
- fi->reg_val_prev = reg_val;
- fi->time_prev = time_now;
- exit:
- mutex_unlock(&hwmon->hwmon_lock);
- intel_runtime_pm_put(ddat->uncore->rpm, wakeref);
- return ret;
- }
- static int
- hwm_fan_read(struct hwm_drvdata *ddat, u32 attr, long *val)
- {
- if (attr == hwmon_fan_input)
- return hwm_fan_input_read(ddat, val);
- return -EOPNOTSUPP;
- }
- static umode_t
- hwm_is_visible(const void *drvdata, enum hwmon_sensor_types type,
- u32 attr, int channel)
- {
- struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
- switch (type) {
- case hwmon_temp:
- return hwm_temp_is_visible(ddat, attr);
- case hwmon_in:
- return hwm_in_is_visible(ddat, attr);
- case hwmon_power:
- return hwm_power_is_visible(ddat, attr, channel);
- case hwmon_energy:
- return hwm_energy_is_visible(ddat, attr);
- case hwmon_curr:
- return hwm_curr_is_visible(ddat, attr);
- case hwmon_fan:
- return hwm_fan_is_visible(ddat, attr);
- default:
- return 0;
- }
- }
- static int
- hwm_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
- int channel, long *val)
- {
- struct hwm_drvdata *ddat = dev_get_drvdata(dev);
- switch (type) {
- case hwmon_temp:
- return hwm_temp_read(ddat, attr, val);
- case hwmon_in:
- return hwm_in_read(ddat, attr, val);
- case hwmon_power:
- return hwm_power_read(ddat, attr, channel, val);
- case hwmon_energy:
- return hwm_energy_read(ddat, attr, val);
- case hwmon_curr:
- return hwm_curr_read(ddat, attr, val);
- case hwmon_fan:
- return hwm_fan_read(ddat, attr, val);
- default:
- return -EOPNOTSUPP;
- }
- }
- static int
- hwm_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
- int channel, long val)
- {
- struct hwm_drvdata *ddat = dev_get_drvdata(dev);
- switch (type) {
- case hwmon_power:
- return hwm_power_write(ddat, attr, channel, val);
- case hwmon_curr:
- return hwm_curr_write(ddat, attr, val);
- default:
- return -EOPNOTSUPP;
- }
- }
- static const struct hwmon_ops hwm_ops = {
- .is_visible = hwm_is_visible,
- .read = hwm_read,
- .write = hwm_write,
- };
- static const struct hwmon_chip_info hwm_chip_info = {
- .ops = &hwm_ops,
- .info = hwm_info,
- };
- static umode_t
- hwm_gt_is_visible(const void *drvdata, enum hwmon_sensor_types type,
- u32 attr, int channel)
- {
- struct hwm_drvdata *ddat = (struct hwm_drvdata *)drvdata;
- switch (type) {
- case hwmon_energy:
- return hwm_energy_is_visible(ddat, attr);
- default:
- return 0;
- }
- }
- static int
- hwm_gt_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
- int channel, long *val)
- {
- struct hwm_drvdata *ddat = dev_get_drvdata(dev);
- switch (type) {
- case hwmon_energy:
- return hwm_energy_read(ddat, attr, val);
- default:
- return -EOPNOTSUPP;
- }
- }
- static const struct hwmon_ops hwm_gt_ops = {
- .is_visible = hwm_gt_is_visible,
- .read = hwm_gt_read,
- };
- static const struct hwmon_chip_info hwm_gt_chip_info = {
- .ops = &hwm_gt_ops,
- .info = hwm_gt_info,
- };
- static void
- hwm_get_preregistration_info(struct drm_i915_private *i915)
- {
- struct i915_hwmon *hwmon = i915->hwmon;
- struct intel_uncore *uncore = &i915->uncore;
- struct hwm_drvdata *ddat = &hwmon->ddat;
- intel_wakeref_t wakeref;
- u32 val_sku_unit = 0;
- struct intel_gt *gt;
- long energy;
- int i;
- /* Available for all Gen12+/dGfx */
- hwmon->rg.gt_perf_status = GEN12_RPSTAT1;
- if (IS_DG1(i915) || IS_DG2(i915)) {
- hwmon->rg.pkg_temp = PCU_PACKAGE_TEMPERATURE;
- hwmon->rg.pkg_power_sku_unit = PCU_PACKAGE_POWER_SKU_UNIT;
- hwmon->rg.pkg_power_sku = PCU_PACKAGE_POWER_SKU;
- hwmon->rg.pkg_rapl_limit = PCU_PACKAGE_RAPL_LIMIT;
- hwmon->rg.energy_status_all = PCU_PACKAGE_ENERGY_STATUS;
- hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
- hwmon->rg.fan_speed = PCU_PWM_FAN_SPEED;
- } else {
- hwmon->rg.pkg_temp = INVALID_MMIO_REG;
- hwmon->rg.pkg_power_sku_unit = INVALID_MMIO_REG;
- hwmon->rg.pkg_power_sku = INVALID_MMIO_REG;
- hwmon->rg.pkg_rapl_limit = INVALID_MMIO_REG;
- hwmon->rg.energy_status_all = INVALID_MMIO_REG;
- hwmon->rg.energy_status_tile = INVALID_MMIO_REG;
- hwmon->rg.fan_speed = INVALID_MMIO_REG;
- }
- with_intel_runtime_pm(uncore->rpm, wakeref) {
- /*
- * The contents of register hwmon->rg.pkg_power_sku_unit do not change,
- * so read it once and store the shift values.
- */
- if (i915_mmio_reg_valid(hwmon->rg.pkg_power_sku_unit))
- val_sku_unit = intel_uncore_read(uncore,
- hwmon->rg.pkg_power_sku_unit);
- /*
- * Store the initial fan register value, so that we can use it for
- * initial fan speed calculation.
- */
- if (i915_mmio_reg_valid(hwmon->rg.fan_speed)) {
- ddat->fi.reg_val_prev = intel_uncore_read(uncore,
- hwmon->rg.fan_speed);
- ddat->fi.time_prev = get_jiffies_64();
- }
- }
- hwmon->scl_shift_power = REG_FIELD_GET(PKG_PWR_UNIT, val_sku_unit);
- hwmon->scl_shift_energy = REG_FIELD_GET(PKG_ENERGY_UNIT, val_sku_unit);
- hwmon->scl_shift_time = REG_FIELD_GET(PKG_TIME_UNIT, val_sku_unit);
- /*
- * Initialize 'struct hwm_energy_info', i.e. set fields to the
- * first value of the energy register read
- */
- if (i915_mmio_reg_valid(hwmon->rg.energy_status_all))
- hwm_energy(ddat, &energy);
- if (i915_mmio_reg_valid(hwmon->rg.energy_status_tile)) {
- for_each_gt(gt, i915, i)
- hwm_energy(&hwmon->ddat_gt[i], &energy);
- }
- }
- void i915_hwmon_register(struct drm_i915_private *i915)
- {
- struct device *dev = i915->drm.dev;
- struct i915_hwmon *hwmon;
- struct device *hwmon_dev;
- struct hwm_drvdata *ddat;
- struct hwm_drvdata *ddat_gt;
- struct intel_gt *gt;
- int i;
- /* hwmon is available only for dGfx */
- if (!IS_DGFX(i915))
- return;
- hwmon = kzalloc_obj(*hwmon);
- if (!hwmon)
- return;
- i915->hwmon = hwmon;
- mutex_init(&hwmon->hwmon_lock);
- ddat = &hwmon->ddat;
- ddat->hwmon = hwmon;
- ddat->uncore = &i915->uncore;
- snprintf(ddat->name, sizeof(ddat->name), "i915");
- ddat->gt_n = -1;
- init_waitqueue_head(&ddat->waitq);
- for_each_gt(gt, i915, i) {
- ddat_gt = hwmon->ddat_gt + i;
- ddat_gt->hwmon = hwmon;
- ddat_gt->uncore = gt->uncore;
- snprintf(ddat_gt->name, sizeof(ddat_gt->name), "i915_gt%u", i);
- ddat_gt->gt_n = i;
- }
- hwm_get_preregistration_info(i915);
- /* hwmon_dev points to device hwmon<i> */
- hwmon_dev = hwmon_device_register_with_info(dev, ddat->name,
- ddat,
- &hwm_chip_info,
- hwm_groups);
- if (IS_ERR(hwmon_dev))
- goto err;
- ddat->hwmon_dev = hwmon_dev;
- for_each_gt(gt, i915, i) {
- ddat_gt = hwmon->ddat_gt + i;
- /*
- * Create per-gt directories only if a per-gt attribute is
- * visible. Currently this is only energy
- */
- if (!hwm_gt_is_visible(ddat_gt, hwmon_energy, hwmon_energy_input, 0))
- continue;
- hwmon_dev = hwmon_device_register_with_info(dev, ddat_gt->name,
- ddat_gt,
- &hwm_gt_chip_info,
- NULL);
- if (!IS_ERR(hwmon_dev))
- ddat_gt->hwmon_dev = hwmon_dev;
- }
- return;
- err:
- i915_hwmon_unregister(i915);
- }
- void i915_hwmon_unregister(struct drm_i915_private *i915)
- {
- struct i915_hwmon *hwmon = i915->hwmon;
- struct intel_gt *gt;
- int i;
- if (!hwmon)
- return;
- for_each_gt(gt, i915, i)
- if (hwmon->ddat_gt[i].hwmon_dev)
- hwmon_device_unregister(hwmon->ddat_gt[i].hwmon_dev);
- if (hwmon->ddat.hwmon_dev)
- hwmon_device_unregister(hwmon->ddat.hwmon_dev);
- mutex_destroy(&hwmon->hwmon_lock);
- kfree(i915->hwmon);
- i915->hwmon = NULL;
- }
|