<div dir="auto">Sorry for that. I'll split the patch and I'll come again ;)</div><div class="gmail_extra"><br><div class="gmail_quote">El dia 11/04/2017 22:12, "Karol Herbst" <<a href="mailto:karolherbst@gmail.com">karolherbst@gmail.com</a>> va escriure:<br type="attribution"><blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">thanks for the work, but could you please split that patch?<br>
It looks like you are doing several things at once and it isn't really<br>
easy to review like this. And it isn't bisectable.<br>
<br>
If there are clean ups here, please do it in a seperate patch. I<br>
highly doubt that it all has to be done within one single big patch.<br>
<div class="elided-text"><br>
2017-04-11 18:54 GMT+02:00 Oscar Salvador <<a href="mailto:osalvador.vilardaga@gmail.com">osalvador.vilardaga@gmail.com</a><wbr>>:<br>
> Hi,<br>
><br>
> this patch replaces the old hwmon_device_register with the new<br>
> hwmon_device_register_with_<wbr>info.<br>
> I've tested it on my laptop with a GeForceGT 425M and it doesn't break anything.<br>
><br>
><br>
> --- linux/drivers/gpu/drm/nouveau/<wbr>nouveau_hwmon.c.orig  2017-04-11 18:27:15.477623009 +0200<br>
> +++ linux/drivers/gpu/drm/nouveau/<wbr>nouveau_hwmon.c       2017-04-11 18:45:41.918688215 +0200<br>
> @@ -1,5 +1,6 @@<br>
>  /*<br>
> - * Copyright 2010 Red Hat Inc.<br>
> + * Copyright 2010 Red Hat Inc. (Ben Skeggs)<br>
> + * Copyright 2017 Oscar Salvador<br>
>   *<br>
>   * Permission is hereby granted, free of charge, to any person obtaining a<br>
>   * copy of this software and associated documentation files (the "Software"),<br>
> @@ -19,7 +20,6 @@<br>
>   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR<br>
>   * OTHER DEALINGS IN THE SOFTWARE.<br>
>   *<br>
> - * Authors: Ben Skeggs<br>
>   */<br>
><br>
>  #ifdef CONFIG_ACPI<br>
> @@ -38,21 +38,17 @@<br>
>  #include <nvkm/subdev/volt.h><br>
><br>
>  #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))<br>
> -static ssize_t<br>
> -nouveau_hwmon_show_temp(<wbr>struct device *d, struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_show_temp(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
>         int temp = nvkm_therm_temp_get(therm);<br>
><br>
>         if (temp < 0)<br>
>                 return temp;<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000);<br>
> +       return (temp * 1000);<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_<wbr>input, S_IRUGO, nouveau_hwmon_show_temp,<br>
> -                                                 NULL, 0);<br>
><br>
>  static ssize_t<br>
>  nouveau_hwmon_show_temp1_auto_<wbr>point1_pwm(struct device *d,<br>
> @@ -60,7 +56,7 @@ nouveau_hwmon_show_temp1_auto_<wbr>point1_pwm<br>
>  {<br>
>         return snprintf(buf, PAGE_SIZE, "%d\n", 100);<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_auto_<wbr>point1_pwm, S_IRUGO,<br>
> +static SENSOR_DEVICE_ATTR(temp1_auto_<wbr>point1_pwm, 0444,<br>
>                           nouveau_hwmon_show_temp1_auto_<wbr>point1_pwm, NULL, 0);<br>
><br>
>  static ssize_t<br>
> @@ -92,7 +88,7 @@ nouveau_hwmon_set_temp1_auto_<wbr>point1_temp<br>
><br>
>         return count;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_auto_<wbr>point1_temp, S_IRUGO | S_IWUSR,<br>
> +static SENSOR_DEVICE_ATTR(temp1_auto_<wbr>point1_temp, 0644,<br>
>                           nouveau_hwmon_temp1_auto_<wbr>point1_temp,<br>
>                           nouveau_hwmon_set_temp1_auto_<wbr>point1_temp, 0);<br>
><br>
> @@ -125,319 +121,176 @@ nouveau_hwmon_set_temp1_auto_<wbr>point1_temp<br>
><br>
>         return count;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_auto_<wbr>point1_temp_hyst, S_IRUGO | S_IWUSR,<br>
> +static SENSOR_DEVICE_ATTR(temp1_auto_<wbr>point1_temp_hyst, 0644,<br>
>                           nouveau_hwmon_temp1_auto_<wbr>point1_temp_hyst,<br>
>                           nouveau_hwmon_set_temp1_auto_<wbr>point1_temp_hyst, 0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_max_temp(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n",<br>
> -              therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000);<br>
> +       return (therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000);<br>
>  }<br>
> -static ssize_t<br>
> -nouveau_hwmon_set_max_temp(<wbr>struct device *d, struct device_attribute *a,<br>
> -                                               const char *buf, size_t count)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_set_max_temp(<wbr>struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
> -<br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return count;<br>
><br>
> -       therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, value / 1000);<br>
> -<br>
> -       return count;<br>
> +       therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, val / 1000);<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,<br>
> -                                                 nouveau_hwmon_set_max_temp,<br>
> -                                                 0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_max_temp_hyst(<wbr>struct device *d, struct device_attribute *a,<br>
> -                           char *buf)<br>
> +static int<br>
> +nouveau_hwmon_max_temp_hyst(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n",<br>
> -         therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_<wbr>HYST) * 1000);<br>
> +       return (therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_<wbr>HYST)<br>
> +                                                               * 1000);<br>
>  }<br>
> -static ssize_t<br>
> -nouveau_hwmon_set_max_temp_<wbr>hyst(struct device *d, struct device_attribute *a,<br>
> -                                               const char *buf, size_t count)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_set_max_temp_<wbr>hyst(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
> -<br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return count;<br>
><br>
>         therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_<wbr>HYST,<br>
> -                       value / 1000);<br>
> -<br>
> -       return count;<br>
> +                       val / 1000);<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_max_<wbr>hyst, S_IRUGO | S_IWUSR,<br>
> -                         nouveau_hwmon_max_temp_hyst,<br>
> -                         nouveau_hwmon_set_max_temp_<wbr>hyst, 0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_critical_temp(<wbr>struct device *d, struct device_attribute *a,<br>
> -                                                       char *buf)<br>
> +static int<br>
> +nouveau_hwmon_critical_temp(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n",<br>
> -              therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000);<br>
> +       return (therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000);<br>
>  }<br>
> -static ssize_t<br>
> -nouveau_hwmon_set_critical_<wbr>temp(struct device *d, struct device_attribute *a,<br>
> -                                                           const char *buf,<br>
> -                                                               size_t count)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_set_critical_<wbr>temp(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
> -<br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return count;<br>
><br>
> -       therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, value / 1000);<br>
> +       therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, val / 1000);<br>
><br>
> -       return count;<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,<br>
> -                                               nouveau_hwmon_critical_temp,<br>
> -                                               nouveau_hwmon_set_critical_<wbr>temp,<br>
> -                                               0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_critical_temp_<wbr>hyst(struct device *d, struct device_attribute *a,<br>
> -                                                       char *buf)<br>
> +static int<br>
> +nouveau_hwmon_critical_temp_<wbr>hyst(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n",<br>
> -         therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_<wbr>HYST) * 1000);<br>
> +       return (therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_<wbr>HYST)<br>
> +                                                               * 1000);<br>
>  }<br>
> -static ssize_t<br>
> -nouveau_hwmon_set_critical_<wbr>temp_hyst(struct device *d,<br>
> -                                    struct device_attribute *a,<br>
> -                                    const char *buf,<br>
> -                                    size_t count)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_set_critical_<wbr>temp_hyst(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
> -<br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return count;<br>
><br>
>         therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_<wbr>HYST,<br>
> -                       value / 1000);<br>
> -<br>
> -       return count;<br>
> +                       val / 1000);<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_crit_<wbr>hyst, S_IRUGO | S_IWUSR,<br>
> -                         nouveau_hwmon_critical_temp_<wbr>hyst,<br>
> -                         nouveau_hwmon_set_critical_<wbr>temp_hyst, 0);<br>
> -static ssize_t<br>
> -nouveau_hwmon_emergency_temp(<wbr>struct device *d, struct device_attribute *a,<br>
> -                                                       char *buf)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_emergency_temp(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n",<br>
> -              therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000);<br>
> +       return (therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000);<br>
>  }<br>
> -static ssize_t<br>
> -nouveau_hwmon_set_emergency_<wbr>temp(struct device *d, struct device_attribute *a,<br>
> -                                                           const char *buf,<br>
> -                                                               size_t count)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_set_emergency_<wbr>temp(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
> -<br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return count;<br>
> -<br>
> -       therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, value / 1000);<br>
><br>
> -       return count;<br>
> +       therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, val / 1000);<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(temp1_<wbr>emergency, S_IRUGO | S_IWUSR,<br>
> -                                       nouveau_hwmon_emergency_temp,<br>
> -                                       nouveau_hwmon_set_emergency_<wbr>temp,<br>
> -                                       0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_emergency_temp_<wbr>hyst(struct device *d, struct device_attribute *a,<br>
> -                                                       char *buf)<br>
> +static int<br>
> +nouveau_hwmon_emergency_temp_<wbr>hyst(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n",<br>
> -         therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_<wbr>HYST) * 1000);<br>
> +       return (therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_<wbr>HYST)<br>
> +                                                               * 1000);<br>
>  }<br>
> -static ssize_t<br>
> -nouveau_hwmon_set_emergency_<wbr>temp_hyst(struct device *d,<br>
> -                                     struct device_attribute *a,<br>
> -                                     const char *buf,<br>
> -                                     size_t count)<br>
> +<br>
> +static int<br>
> +nouveau_hwmon_set_emergency_<wbr>temp_hyst(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
> -<br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return count;<br>
><br>
>         therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_<wbr>HYST,<br>
> -                       value / 1000);<br>
> -<br>
> -       return count;<br>
> -}<br>
> -static SENSOR_DEVICE_ATTR(temp1_<wbr>emergency_hyst, S_IRUGO | S_IWUSR,<br>
> -                                       nouveau_hwmon_emergency_temp_<wbr>hyst,<br>
> -                                       nouveau_hwmon_set_emergency_<wbr>temp_hyst,<br>
> -                                       0);<br>
> -<br>
> -static ssize_t nouveau_hwmon_show_name(struct device *dev,<br>
> -                                     struct device_attribute *attr,<br>
> -                                     char *buf)<br>
> -{<br>
> -       return sprintf(buf, "nouveau\n");<br>
> +                       val / 1000);<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);<br>
><br>
> -static ssize_t nouveau_hwmon_show_update_<wbr>rate(struct device *dev,<br>
> -                                     struct device_attribute *attr,<br>
> -                                     char *buf)<br>
> +static int<br>
> +nouveau_hwmon_show_update_<wbr>rate(struct nouveau_drm *drm)<br>
>  {<br>
> -       return sprintf(buf, "1000\n");<br>
> +       return 1000;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(update_<wbr>rate, S_IRUGO,<br>
> -                                               nouveau_hwmon_show_update_<wbr>rate,<br>
> -                                               NULL, 0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_show_fan1_<wbr>input(struct device *d, struct device_attribute *attr,<br>
> -                             char *buf)<br>
> +static int<br>
> +nouveau_hwmon_show_fan1_<wbr>input(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
><br>
> -       return snprintf(buf, PAGE_SIZE, "%d\n", nvkm_therm_fan_sense(therm));<br>
> +       return nvkm_therm_fan_sense(therm);<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input,<br>
> -                         NULL, 0);<br>
><br>
> - static ssize_t<br>
> -nouveau_hwmon_get_pwm1_<wbr>enable(struct device *d,<br>
> -                          struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_pwm1_<wbr>enable(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       int ret;<br>
><br>
> -       ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);<br>
> -       if (ret < 0)<br>
> -               return ret;<br>
> -<br>
> -       return sprintf(buf, "%i\n", ret);<br>
> +       return therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);<br>
>  }<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_set_pwm1_<wbr>enable(struct device *d, struct device_attribute *a,<br>
> -                          const char *buf, size_t count)<br>
> +static int<br>
> +nouveau_hwmon_set_pwm1_<wbr>enable(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       long value;<br>
>         int ret;<br>
><br>
> -       ret = kstrtol(buf, 10, &value);<br>
> +       ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, val);<br>
>         if (ret)<br>
>                 return ret;<br>
> -<br>
> -       ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, value);<br>
> -       if (ret)<br>
> -               return ret;<br>
> -       else<br>
> -               return count;<br>
> +       return val;<br>
>  }<br>
> -static SENSOR_DEVICE_ATTR(pwm1_<wbr>enable, S_IRUGO | S_IWUSR,<br>
> -                         nouveau_hwmon_get_pwm1_enable,<br>
> -                         nouveau_hwmon_set_pwm1_enable, 0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_pwm1(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       int ret;<br>
><br>
> -       ret = therm->fan_get(therm);<br>
> -       if (ret < 0)<br>
> -               return ret;<br>
> -<br>
> -       return sprintf(buf, "%i\n", ret);<br>
> +       return therm->fan_get(therm);<br>
>  }<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a,<br>
> -                      const char *buf, size_t count)<br>
> +static int<br>
> +nouveau_hwmon_set_pwm1(struct nouveau_drm *drm, long val)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
>         int ret = -ENODEV;<br>
> -       long value;<br>
><br>
> -       if (kstrtol(buf, 10, &value) == -EINVAL)<br>
> -               return -EINVAL;<br>
> -<br>
> -       ret = therm->fan_set(therm, value);<br>
> +       ret = therm->fan_set(therm, val);<br>
>         if (ret)<br>
>                 return ret;<br>
> -<br>
> -       return count;<br>
> +       return val;<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR,<br>
> -                         nouveau_hwmon_get_pwm1,<br>
> -                         nouveau_hwmon_set_pwm1, 0);<br>
> -<br>
>  static ssize_t<br>
>  nouveau_hwmon_get_pwm1_min(<wbr>struct device *d,<br>
> -                          struct device_attribute *a, char *buf)<br>
> +                               struct device_attribute *a, char *buf)<br>
>  {<br>
>         struct drm_device *dev = dev_get_drvdata(d);<br>
>         struct nouveau_drm *drm = nouveau_drm(dev);<br>
> @@ -453,7 +306,7 @@ nouveau_hwmon_get_pwm1_min(<wbr>struct device<br>
><br>
>  static ssize_t<br>
>  nouveau_hwmon_set_pwm1_min(<wbr>struct device *d, struct device_attribute *a,<br>
> -                          const char *buf, size_t count)<br>
> +                               const char *buf, size_t count)<br>
>  {<br>
>         struct drm_device *dev = dev_get_drvdata(d);<br>
>         struct nouveau_drm *drm = nouveau_drm(dev);<br>
> @@ -471,13 +324,13 @@ nouveau_hwmon_set_pwm1_min(<wbr>struct device<br>
>         return count;<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR,<br>
> -                         nouveau_hwmon_get_pwm1_min,<br>
> -                         nouveau_hwmon_set_pwm1_min, 0);<br>
> +static SENSOR_DEVICE_ATTR(pwm1_min, 0644,<br>
> +                       nouveau_hwmon_get_pwm1_min,<br>
> +                       nouveau_hwmon_set_pwm1_min, 0);<br>
><br>
>  static ssize_t<br>
>  nouveau_hwmon_get_pwm1_max(<wbr>struct device *d,<br>
> -                          struct device_attribute *a, char *buf)<br>
> +                               struct device_attribute *a, char *buf)<br>
>  {<br>
>         struct drm_device *dev = dev_get_drvdata(d);<br>
>         struct nouveau_drm *drm = nouveau_drm(dev);<br>
> @@ -493,7 +346,7 @@ nouveau_hwmon_get_pwm1_max(<wbr>struct device<br>
><br>
>  static ssize_t<br>
>  nouveau_hwmon_set_pwm1_max(<wbr>struct device *d, struct device_attribute *a,<br>
> -                          const char *buf, size_t count)<br>
> +                               const char *buf, size_t count)<br>
>  {<br>
>         struct drm_device *dev = dev_get_drvdata(d);<br>
>         struct nouveau_drm *drm = nouveau_drm(dev);<br>
> @@ -511,16 +364,13 @@ nouveau_hwmon_set_pwm1_max(<wbr>struct device<br>
>         return count;<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR,<br>
> -                         nouveau_hwmon_get_pwm1_max,<br>
> -                         nouveau_hwmon_set_pwm1_max, 0);<br>
> +static SENSOR_DEVICE_ATTR(pwm1_max, 0644,<br>
> +                       nouveau_hwmon_get_pwm1_max,<br>
> +                       nouveau_hwmon_set_pwm1_max, 0);<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_get_in0_input(<wbr>struct device *d,<br>
> -                           struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_in0_input(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_volt *volt = nvxx_volt(&drm->client.device)<wbr>;<br>
>         int ret;<br>
><br>
> @@ -528,169 +378,524 @@ nouveau_hwmon_get_in0_input(<wbr>struct devic<br>
>         if (ret < 0)<br>
>                 return ret;<br>
><br>
> -       return sprintf(buf, "%i\n", ret / 1000);<br>
> +       return (ret / 1000);<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO,<br>
> -                         nouveau_hwmon_get_in0_input, NULL, 0);<br>
> -<br>
> -static ssize_t<br>
> -nouveau_hwmon_get_in0_min(<wbr>struct device *d,<br>
> -                           struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_in0_min(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_volt *volt = nvxx_volt(&drm->client.device)<wbr>;<br>
><br>
>         if (!volt || !volt->min_uv)<br>
>                 return -ENODEV;<br>
><br>
> -       return sprintf(buf, "%i\n", volt->min_uv / 1000);<br>
> +       return (volt->min_uv / 1000);<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO,<br>
> -                         nouveau_hwmon_get_in0_min, NULL, 0);<br>
> -<br>
> -static ssize_t<br>
> -nouveau_hwmon_get_in0_max(<wbr>struct device *d,<br>
> -                           struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_in0_max(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_volt *volt = nvxx_volt(&drm->client.device)<wbr>;<br>
><br>
>         if (!volt || !volt->max_uv)<br>
>                 return -ENODEV;<br>
><br>
> -       return sprintf(buf, "%i\n", volt->max_uv / 1000);<br>
> +       return (volt->max_uv / 1000);<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO,<br>
> -                         nouveau_hwmon_get_in0_max, NULL, 0);<br>
> -<br>
> -static ssize_t<br>
> -nouveau_hwmon_get_in0_label(<wbr>struct device *d,<br>
> -                           struct device_attribute *a, char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_power1_<wbr>input(struct nouveau_drm *drm)<br>
>  {<br>
> -       return sprintf(buf, "GPU core\n");<br>
> -}<br>
> -<br>
> -static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO,<br>
> -                         nouveau_hwmon_get_in0_label, NULL, 0);<br>
> -<br>
> -static ssize_t<br>
> -nouveau_hwmon_get_power1_<wbr>input(struct device *d, struct device_attribute *a,<br>
> -                              char *buf)<br>
> -{<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.<wbr>device);<br>
>         int result = nvkm_iccsense_read_all(<wbr>iccsense);<br>
><br>
> -       if (result < 0)<br>
> -               return result;<br>
> -<br>
> -       return sprintf(buf, "%i\n", result);<br>
> +       return result;<br>
>  }<br>
><br>
> -static SENSOR_DEVICE_ATTR(power1_<wbr>input, S_IRUGO,<br>
> -                         nouveau_hwmon_get_power1_<wbr>input, NULL, 0);<br>
> -<br>
> -static ssize_t<br>
> -nouveau_hwmon_get_power1_max(<wbr>struct device *d, struct device_attribute *a,<br>
> -                            char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_power1_max(<wbr>struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.<wbr>device);<br>
> -       return sprintf(buf, "%i\n", iccsense->power_w_max);<br>
> -}<br>
><br>
> -static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO,<br>
> -                         nouveau_hwmon_get_power1_max, NULL, 0);<br>
> +       return iccsense->power_w_max;<br>
> +}<br>
><br>
> -static ssize_t<br>
> -nouveau_hwmon_get_power1_<wbr>crit(struct device *d, struct device_attribute *a,<br>
> -                             char *buf)<br>
> +static int<br>
> +nouveau_hwmon_get_power1_<wbr>crit(struct nouveau_drm *drm)<br>
>  {<br>
> -       struct drm_device *dev = dev_get_drvdata(d);<br>
> -       struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.<wbr>device);<br>
> -       return sprintf(buf, "%i\n", iccsense->power_w_crit);<br>
> -}<br>
><br>
> -static SENSOR_DEVICE_ATTR(power1_<wbr>crit, S_IRUGO,<br>
> -                         nouveau_hwmon_get_power1_crit, NULL, 0);<br>
> +       return iccsense->power_w_crit;<br>
> +}<br>
><br>
> -static struct attribute *hwmon_default_attributes[] = {<br>
> -       &sensor_dev_attr_name.dev_<wbr>attr.attr,<br>
> -       &sensor_dev_attr_update_rate.<wbr>dev_attr.attr,<br>
> +static struct attribute *pwm_fan_sensor_attrs[] = {<br>
> +       &sensor_dev_attr_pwm1_min.dev_<wbr>attr.attr,<br>
> +       &sensor_dev_attr_pwm1_max.dev_<wbr>attr.attr,<br>
>         NULL<br>
>  };<br>
> -static struct attribute *hwmon_temp_attributes[] = {<br>
> -       &sensor_dev_attr_temp1_input.<wbr>dev_attr.attr,<br>
> +ATTRIBUTE_GROUPS(pwm_fan_<wbr>sensor);<br>
> +<br>
> +static struct attribute *temp1_auto_point_sensor_<wbr>attrs[] = {<br>
>         &sensor_dev_attr_temp1_auto_<wbr>point1_pwm.dev_attr.attr,<br>
>         &sensor_dev_attr_temp1_auto_<wbr>point1_temp.dev_attr.attr,<br>
>         &sensor_dev_attr_temp1_auto_<wbr>point1_temp_hyst.dev_attr.<wbr>attr,<br>
> -       &sensor_dev_attr_temp1_max.<wbr>dev_attr.attr,<br>
> -       &sensor_dev_attr_temp1_max_<wbr>hyst.dev_attr.attr,<br>
> -       &sensor_dev_attr_temp1_crit.<wbr>dev_attr.attr,<br>
> -       &sensor_dev_attr_temp1_crit_<wbr>hyst.dev_attr.attr,<br>
> -       &sensor_dev_attr_temp1_<wbr>emergency.dev_attr.attr,<br>
> -       &sensor_dev_attr_temp1_<wbr>emergency_hyst.dev_attr.attr,<br>
>         NULL<br>
>  };<br>
> -static struct attribute *hwmon_fan_rpm_attributes[] = {<br>
> -       &sensor_dev_attr_fan1_input.<wbr>dev_attr.attr,<br>
> -       NULL<br>
> +ATTRIBUTE_GROUPS(temp1_auto_<wbr>point_sensor);<br>
> +<br>
> +#define N_ATTR_GROUPS  3<br>
> +<br>
> +static const u32 nouveau_config_chip[] = {<br>
> +       HWMON_C_UPDATE_INTERVAL,<br>
> +       0<br>
>  };<br>
> -static struct attribute *hwmon_pwm_fan_attributes[] = {<br>
> -       &sensor_dev_attr_pwm1_enable.<wbr>dev_attr.attr,<br>
> -       &sensor_dev_attr_pwm1.dev_<wbr>attr.attr,<br>
> -       &sensor_dev_attr_pwm1_min.dev_<wbr>attr.attr,<br>
> -       &sensor_dev_attr_pwm1_max.dev_<wbr>attr.attr,<br>
> -       NULL<br>
> +<br>
> +static const u32 nouveau_config_in[] = {<br>
> +       HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_LABEL,<br>
> +       0<br>
>  };<br>
><br>
> -static struct attribute *hwmon_in0_attributes[] = {<br>
> -       &sensor_dev_attr_in0_input.<wbr>dev_attr.attr,<br>
> -       &sensor_dev_attr_in0_min.dev_<wbr>attr.attr,<br>
> -       &sensor_dev_attr_in0_max.dev_<wbr>attr.attr,<br>
> -       &sensor_dev_attr_in0_label.<wbr>dev_attr.attr,<br>
> -       NULL<br>
> +static const u32 nouveau_config_temp[] = {<br>
> +       HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |<br>
> +       HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_EMERGENCY |<br>
> +       HWMON_T_EMERGENCY_HYST,<br>
> +       0<br>
>  };<br>
><br>
> -static struct attribute *hwmon_power_attributes[] = {<br>
> -       &sensor_dev_attr_power1_input.<wbr>dev_attr.attr,<br>
> -       NULL<br>
> +static const u32 nouveau_config_fan[] = {<br>
> +       HWMON_F_INPUT,<br>
> +       0<br>
>  };<br>
><br>
> -static struct attribute *hwmon_power_caps_attributes[] = {<br>
> -       &sensor_dev_attr_power1_max.<wbr>dev_attr.attr,<br>
> -       &sensor_dev_attr_power1_crit.<wbr>dev_attr.attr,<br>
> -       NULL<br>
> +static const u32 nouveau_config_pwm[] = {<br>
> +       HWMON_PWM_INPUT | HWMON_PWM_ENABLE,<br>
> +       0<br>
>  };<br>
><br>
> -static const struct attribute_group hwmon_default_attrgroup = {<br>
> -       .attrs = hwmon_default_attributes,<br>
> +static const u32 nouveau_config_power[] = {<br>
> +       HWMON_P_INPUT | HWMON_P_CAP_MAX | HWMON_P_CRIT,<br>
> +       0<br>
>  };<br>
> -static const struct attribute_group hwmon_temp_attrgroup = {<br>
> -       .attrs = hwmon_temp_attributes,<br>
> +<br>
> +static const struct hwmon_channel_info nouveau_chip = {<br>
> +       .type = hwmon_chip,<br>
> +       .config = nouveau_config_chip,<br>
>  };<br>
> -static const struct attribute_group hwmon_fan_rpm_attrgroup = {<br>
> -       .attrs = hwmon_fan_rpm_attributes,<br>
> +<br>
> +static const struct hwmon_channel_info nouveau_temp = {<br>
> +       .type = hwmon_temp,<br>
> +       .config = nouveau_config_temp,<br>
>  };<br>
> -static const struct attribute_group hwmon_pwm_fan_attrgroup = {<br>
> -       .attrs = hwmon_pwm_fan_attributes,<br>
> +<br>
> +static const struct hwmon_channel_info nouveau_fan = {<br>
> +       .type = hwmon_fan,<br>
> +       .config = nouveau_config_fan,<br>
>  };<br>
> -static const struct attribute_group hwmon_in0_attrgroup = {<br>
> -       .attrs = hwmon_in0_attributes,<br>
> +<br>
> +static const struct hwmon_channel_info nouveau_in = {<br>
> +       .type = hwmon_in,<br>
> +       .config = nouveau_config_in,<br>
> +};<br>
> +<br>
> +static const struct hwmon_channel_info nouveau_pwm = {<br>
> +       .type = hwmon_pwm,<br>
> +       .config = nouveau_config_pwm,<br>
>  };<br>
> -static const struct attribute_group hwmon_power_attrgroup = {<br>
> -       .attrs = hwmon_power_attributes,<br>
> +<br>
> +static const struct hwmon_channel_info nouveau_power = {<br>
> +       .type = hwmon_power,<br>
> +       .config = nouveau_config_power,<br>
>  };<br>
> -static const struct attribute_group hwmon_power_caps_attrgroup = {<br>
> -       .attrs = hwmon_power_caps_attributes,<br>
> +<br>
> +static const struct hwmon_channel_info *nouveau_info[] = {<br>
> +       &nouveau_chip,<br>
> +       &nouveau_temp,<br>
> +       &nouveau_fan,<br>
> +       &nouveau_in,<br>
> +       &nouveau_pwm,<br>
> +       &nouveau_power,<br>
> +       NULL<br>
> +};<br>
> +<br>
> +static umode_t<br>
> +nouveau_chip_is_visible(const void *data, u32 attr, int channel)<br>
> +{<br>
> +       switch (attr) {<br>
> +       case hwmon_chip_update_interval:<br>
> +               return 0444;<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +}<br>
> +<br>
> +static umode_t<br>
> +nouveau_power_is_visible(<wbr>const void *data, u32 attr, int channel)<br>
> +{<br>
> +       struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);<br>
> +       struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.<wbr>device);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_power_input:<br>
> +               if (iccsense && iccsense->data_valid &&<br>
> +                               !list_empty(&iccsense->rails))<br>
> +                       return 0444;<br>
> +       case hwmon_power_max:<br>
> +       case hwmon_power_crit:<br>
> +               if (iccsense->power_w_max && iccsense->power_w_crit)<br>
> +                       return 0444;<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +<br>
> +}<br>
> +<br>
> +static umode_t<br>
> +nouveau_temp_is_visible(const void *data, u32 attr, int channel)<br>
> +{<br>
> +       struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);<br>
> +       struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> +<br>
> +       if (therm && therm->attr_get && therm->attr_set)<br>
> +               if (nvkm_therm_temp_get(therm) < 0)<br>
> +                       return 0;<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_temp_input:<br>
> +               return 0444;<br>
> +       case hwmon_temp_max:<br>
> +       case hwmon_temp_max_hyst:<br>
> +       case hwmon_temp_crit:<br>
> +       case hwmon_temp_crit_hyst:<br>
> +       case hwmon_temp_emergency:<br>
> +       case hwmon_temp_emergency_hyst:<br>
> +               return 0644;<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +}<br>
> +<br>
> +static umode_t<br>
> +nouveau_pwm_is_visible(const void *data, u32 attr, int channel)<br>
> +{<br>
> +       struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);<br>
> +       struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> +<br>
> +       if (therm && therm->attr_get)<br>
> +               if (therm->fan_get && therm->fan_get(therm) < 0)<br>
> +                       return 0;<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_pwm_enable:<br>
> +       case hwmon_pwm_input:<br>
> +               return 0644;<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +}<br>
> +<br>
> +static umode_t<br>
> +nouveau_input_is_visible(<wbr>const void *data, u32 attr, int channel)<br>
> +{<br>
> +       struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);<br>
> +       struct nvkm_volt *volt = nvxx_volt(&drm->client.device)<wbr>;<br>
> +<br>
> +       if (!volt || nvkm_volt_get(volt) < 0)<br>
> +               return 0;<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_in_input:<br>
> +       case hwmon_in_label:<br>
> +       case hwmon_in_min:<br>
> +       case hwmon_in_max:<br>
> +               return 0444;<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +}<br>
> +<br>
> +static umode_t<br>
> +nouveau_fan_is_visible(const void *data, u32 attr, int channel)<br>
> +{<br>
> +       struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data);<br>
> +       struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> +<br>
> +       if (!therm || !therm->attr_get || nvkm_therm_fan_sense(therm) < 0)<br>
> +               return 0;<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_fan_input:<br>
> +               return 0444;<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_chip_read(struct device *dev, u32 attr, int channel, long *val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_chip_update_interval:<br>
> +               *val = nouveau_hwmon_show_update_<wbr>rate(drm);<br>
> +               break;<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_temp_read(struct device *dev, u32 attr, int channel, long *val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_temp_input:<br>
> +               *val = nouveau_hwmon_show_temp(drm);<br>
> +               break;<br>
> +       case hwmon_temp_max:<br>
> +               *val = nouveau_hwmon_max_temp(drm);<br>
> +               break;<br>
> +       case hwmon_temp_max_hyst:<br>
> +               *val = nouveau_hwmon_max_temp_hyst(<wbr>drm);<br>
> +               break;<br>
> +       case hwmon_temp_crit:<br>
> +               *val = nouveau_hwmon_critical_temp(<wbr>drm);<br>
> +               break;<br>
> +       case hwmon_temp_crit_hyst:<br>
> +               *val = nouveau_hwmon_critical_temp_<wbr>hyst(drm);<br>
> +               break;<br>
> +       case hwmon_temp_emergency:<br>
> +               *val = nouveau_hwmon_emergency_temp(<wbr>drm);<br>
> +               break;<br>
> +       case hwmon_temp_emergency_hyst:<br>
> +               *val = nouveau_hwmon_emergency_temp_<wbr>hyst(drm);<br>
> +               break;<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_fan_read(struct device *dev, u32 attr, int channel, long *val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_fan_input:<br>
> +               *val = nouveau_hwmon_show_fan1_input(<wbr>drm);<br>
> +               break;<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_in_read(struct device *dev, u32 attr, int channel, long *val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_in_input:<br>
> +               *val = nouveau_hwmon_get_in0_input(<wbr>drm);<br>
> +               break;<br>
> +       case hwmon_in_min:<br>
> +               *val = nouveau_hwmon_get_in0_min(drm)<wbr>;<br>
> +               break;<br>
> +       case hwmon_in_max:<br>
> +               *val = nouveau_hwmon_get_in0_max(drm)<wbr>;<br>
> +               break;<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_pwm_read(struct device *dev, u32 attr, int channel, long *val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_pwm_enable:<br>
> +               *val = nouveau_hwmon_get_pwm1_enable(<wbr>drm);<br>
> +               break;<br>
> +       case hwmon_pwm_input:<br>
> +               *val = nouveau_hwmon_get_pwm1(drm);<br>
> +               break;<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_power_read(struct device *dev, u32 attr, int channel, long *val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_power_input:<br>
> +               *val = nouveau_hwmon_get_power1_<wbr>input(drm);<br>
> +               break;<br>
> +       case hwmon_power_max:<br>
> +               *val = nouveau_hwmon_get_power1_max(<wbr>drm);<br>
> +               break;<br>
> +       case hwmon_power_crit:<br>
> +               *val = nouveau_hwmon_get_power1_crit(<wbr>drm);<br>
> +               break;<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_temp_write(struct device *dev, u32 attr, int channel, long val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_temp_max:<br>
> +               nouveau_hwmon_set_max_temp(<wbr>drm, val);<br>
> +               break;<br>
> +       case hwmon_temp_max_hyst:<br>
> +               nouveau_hwmon_set_max_temp_<wbr>hyst(drm, val);<br>
> +               break;<br>
> +       case hwmon_temp_crit:<br>
> +               nouveau_hwmon_set_critical_<wbr>temp(drm, val);<br>
> +               break;<br>
> +       case hwmon_temp_crit_hyst:<br>
> +               nouveau_hwmon_set_critical_<wbr>temp_hyst(drm, val);<br>
> +               break;<br>
> +       case hwmon_temp_emergency:<br>
> +               nouveau_hwmon_set_emergency_<wbr>temp(drm, val);<br>
> +               break;<br>
> +       case hwmon_temp_emergency_hyst:<br>
> +               nouveau_hwmon_set_emergency_<wbr>temp_hyst(drm, val);<br>
> +               break;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_pwm_write(struct device *dev, u32 attr, int channel, long val)<br>
> +{<br>
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);<br>
> +       struct nouveau_drm *drm = nouveau_drm(drm_dev);<br>
> +<br>
> +       switch (attr) {<br>
> +       case hwmon_pwm_input:<br>
> +               nouveau_hwmon_set_pwm1(drm, val);<br>
> +               break;<br>
> +       case hwmon_pwm_enable:<br>
> +               nouveau_hwmon_set_pwm1_enable(<wbr>drm, val);<br>
> +               break;<br>
> +       }<br>
> +<br>
> +       return 0;<br>
> +}<br>
> +<br>
> +static umode_t<br>
> +nouveau_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr,<br>
> +                                                               int channel)<br>
> +{<br>
> +       switch (type) {<br>
> +       case hwmon_chip:<br>
> +               return nouveau_chip_is_visible(data, attr, channel);<br>
> +       case hwmon_temp:<br>
> +               return nouveau_temp_is_visible(data, attr, channel);<br>
> +       case hwmon_fan:<br>
> +               return nouveau_fan_is_visible(data, attr, channel);<br>
> +       case hwmon_in:<br>
> +               return nouveau_input_is_visible(data, attr, channel);<br>
> +       case hwmon_pwm:<br>
> +               return nouveau_pwm_is_visible(data, attr, channel);<br>
> +       case hwmon_power:<br>
> +               return nouveau_power_is_visible(data, attr, channel);<br>
> +       default:<br>
> +               return 0;<br>
> +       }<br>
> +}<br>
> +<br>
> +<br>
> +static char *input_label = "GPU core";<br>
> +<br>
> +static int<br>
> +nouveau_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,<br>
> +                                               int channel, char **buf)<br>
> +{<br>
> +       if (type == hwmon_in && attr == hwmon_in_label) {<br>
> +               *buf = input_label;<br>
> +               return 0;<br>
> +       }<br>
> +<br>
> +       return -EOPNOTSUPP;<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,<br>
> +                                               int channel, long *val)<br>
> +{<br>
> +       switch (type) {<br>
> +       case hwmon_chip:<br>
> +               return nouveau_chip_read(dev, attr, channel, val);<br>
> +       case hwmon_temp:<br>
> +               return nouveau_temp_read(dev, attr, channel, val);<br>
> +       case hwmon_fan:<br>
> +               return nouveau_fan_read(dev, attr, channel, val);<br>
> +       case hwmon_in:<br>
> +               return nouveau_in_read(dev, attr, channel, val);<br>
> +       case hwmon_pwm:<br>
> +               return nouveau_pwm_read(dev, attr, channel, val);<br>
> +       case hwmon_power:<br>
> +               return nouveau_power_read(dev, attr, channel, val);<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +}<br>
> +<br>
> +static int<br>
> +nouveau_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,<br>
> +                                               int channel, long val)<br>
> +{<br>
> +       switch (type) {<br>
> +       case hwmon_temp:<br>
> +               return nouveau_temp_write(dev, attr, channel, val);<br>
> +       case hwmon_pwm:<br>
> +               return nouveau_pwm_write(dev, attr, channel, val);<br>
> +       default:<br>
> +               return -EOPNOTSUPP;<br>
> +       }<br>
> +}<br>
> +<br>
> +static const struct hwmon_ops nouveau_hwmon_ops = {<br>
> +       .is_visible = nouveau_is_visible,<br>
> +       .read = nouveau_read,<br>
> +       .read_string = nouveau_read_string,<br>
> +       .write = nouveau_write,<br>
> +};<br>
> +<br>
> +static const struct hwmon_chip_info nouveau_chip_info = {<br>
> +       .ops = &nouveau_hwmon_ops,<br>
> +       .info = nouveau_info,<br>
>  };<br>
>  #endif<br>
><br>
> @@ -700,90 +905,36 @@ nouveau_hwmon_init(struct drm_device *de<br>
>  #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))<br>
>         struct nouveau_drm *drm = nouveau_drm(dev);<br>
>         struct nvkm_therm *therm = nvxx_therm(&drm->client.<wbr>device);<br>
> -       struct nvkm_volt *volt = nvxx_volt(&drm->client.device)<wbr>;<br>
> -       struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.<wbr>device);<br>
>         struct nouveau_hwmon *hwmon;<br>
>         struct device *hwmon_dev;<br>
> +       const struct attribute_group *special_groups[N_ATTR_GROUPS]<wbr>;<br>
>         int ret = 0;<br>
> +       int i = 0;<br>
><br>
>         hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);<br>
>         if (!hwmon)<br>
>                 return -ENOMEM;<br>
>         hwmon->dev = dev;<br>
><br>
> -       hwmon_dev = hwmon_device_register(dev-><wbr>dev);<br>
> +       if (therm && therm->attr_get && therm->attr_set) {<br>
> +               if (nvkm_therm_temp_get(therm) >= 0)<br>
> +                       special_groups[i++] = &temp1_auto_point_sensor_<wbr>group;<br>
> +               if (therm->fan_get && therm->fan_get(therm) >= 0)<br>
> +                       special_groups[i++] = &pwm_fan_sensor_group;<br>
> +       }<br>
> +<br>
> +       special_groups[i] = 0;<br>
> +       hwmon_dev = hwmon_device_register_with_<wbr>info(dev->dev, "nouveau", dev,<br>
> +                                       &nouveau_chip_info, special_groups);<br>
> +<br>
>         if (IS_ERR(hwmon_dev)) {<br>
>                 ret = PTR_ERR(hwmon_dev);<br>
>                 NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret);<br>
>                 return ret;<br>
>         }<br>
> -       dev_set_drvdata(hwmon_dev, dev);<br>
> -<br>
> -       /* set the default attributes */<br>
> -       ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj, &hwmon_default_attrgroup);<br>
> -       if (ret)<br>
> -               goto error;<br>
> -<br>
> -       if (therm && therm->attr_get && therm->attr_set) {<br>
> -               /* if the card has a working thermal sensor */<br>
> -               if (nvkm_therm_temp_get(therm) >= 0) {<br>
> -                       ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj, &hwmon_temp_attrgroup);<br>
> -                       if (ret)<br>
> -                               goto error;<br>
> -               }<br>
> -<br>
> -               /* if the card has a pwm fan */<br>
> -               /*XXX: incorrect, need better detection for this, some boards have<br>
> -                *     the gpio entries for pwm fan control even when there's no<br>
> -                *     actual fan connected to it... therm table? */<br>
> -               if (therm->fan_get && therm->fan_get(therm) >= 0) {<br>
> -                       ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj,<br>
> -                                                &hwmon_pwm_fan_attrgroup);<br>
> -                       if (ret)<br>
> -                               goto error;<br>
> -               }<br>
> -       }<br>
> -<br>
> -       /* if the card can read the fan rpm */<br>
> -       if (therm && nvkm_therm_fan_sense(therm) >= 0) {<br>
> -               ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj,<br>
> -                                        &hwmon_fan_rpm_attrgroup);<br>
> -               if (ret)<br>
> -                       goto error;<br>
> -       }<br>
> -<br>
> -       if (volt && nvkm_volt_get(volt) >= 0) {<br>
> -               ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj,<br>
> -                                        &hwmon_in0_attrgroup);<br>
> -<br>
> -               if (ret)<br>
> -                       goto error;<br>
> -       }<br>
> -<br>
> -       if (iccsense && iccsense->data_valid && !list_empty(&iccsense->rails)) {<br>
> -               ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj,<br>
> -                                        &hwmon_power_attrgroup);<br>
> -<br>
> -               if (ret)<br>
> -                       goto error;<br>
> -<br>
> -               if (iccsense->power_w_max && iccsense->power_w_crit) {<br>
> -                       ret = sysfs_create_group(&hwmon_dev-<wbr>>kobj,<br>
> -                                                &hwmon_power_caps_attrgroup);<br>
> -                       if (ret)<br>
> -                               goto error;<br>
> -               }<br>
> -       }<br>
><br>
>         hwmon->hwmon = hwmon_dev;<br>
> -<br>
>         return 0;<br>
> -<br>
> -error:<br>
> -       NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret);<br>
> -       hwmon_device_unregister(hwmon_<wbr>dev);<br>
> -       hwmon->hwmon = NULL;<br>
> -       return ret;<br>
>  #else<br>
>         return 0;<br>
>  #endif<br>
> @@ -795,17 +946,8 @@ nouveau_hwmon_fini(struct drm_device *de<br>
>  #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))<br>
>         struct nouveau_hwmon *hwmon = nouveau_hwmon(dev);<br>
><br>
> -       if (hwmon->hwmon) {<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_default_attrgroup);<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_temp_attrgroup);<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_pwm_fan_attrgroup);<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_fan_rpm_attrgroup);<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_in0_attrgroup);<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_power_attrgroup);<br>
> -               sysfs_remove_group(&hwmon-><wbr>hwmon->kobj, &hwmon_power_caps_attrgroup);<br>
> -<br>
> +       if (hwmon->hwmon)<br>
>                 hwmon_device_unregister(hwmon-<wbr>>hwmon);<br>
> -       }<br>
><br>
>         nouveau_drm(dev)->hwmon = NULL;<br>
>         kfree(hwmon);<br>
</div>> ______________________________<wbr>_________________<br>
> Nouveau mailing list<br>
> <a href="mailto:Nouveau@lists.freedesktop.org">Nouveau@lists.freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/nouveau" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/nouveau</a><br>
</blockquote></div><br></div>