lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <a83f15e3-ac09-abf2-d8da-7b1ac86efc70@gmail.com>
Date:   Mon, 3 May 2021 17:58:53 +0200
From:   Paweł Marciniak <sunwire@...il.com>
To:     linux-hwmon@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH] Add ASRock HDD Saver support

Some of the asrock motherboards are equipped with hdd saver technology.
It is implemented via a special power connector on the motherboard and a corresponding custom made power cable with two SATA power ports.
The control is via the gpio10 pin of the nct6791d chip.
When this technology is available the module creates the hddsaver_enable file.
Reading the file returns the current status, while writing turns off or on the power of the SATA connectors.

Supported motheboards:
ASRock Z97 Extreme4 - works 100% tested.
ASRock Z97 Extreme6 - Based on boardview/schematic should works, not tested.
Other ASRock motherboards supporting this technology - status unknown.

Signed-off-by: Paweł Marciniak <sunwire@...il.com>
---
  drivers/hwmon/nct6775.c | 80 +++++++++++++++++++++++++++++++++++++++++
  1 file changed, 80 insertions(+)

diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 5bd1562..17b70f3 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -110,6 +110,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing forfan RPM signal");
  #define NCT6775_LD_ACPI		0x0a
  #define NCT6775_LD_HWM		0x0b
  #define NCT6775_LD_VID		0x0d
+#define NCT6775_LD_GPIO_DATA		0x08
  #define NCT6775_LD_12		0x12

  #define SIO_REG_LDSEL		0x07	/* Logical device select */
@@ -229,6 +230,7 @@ static const u16 NCT6775_REG_IN[] = {
  #define NCT6775_REG_FANDIV2		0x507

  #define NCT6775_REG_CR_FAN_DEBOUNCE	0xf0
+#define NCT6775_REG_CR_GPIO1_DATA	0xf1

  static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B };

@@ -1205,6 +1207,8 @@ struct nct6775_data {
  	u8 vrm;

  	bool have_vid;
+	bool have_hddsaver; /* True if hdd saver is supported */
+	bool hddsaver_status; /* True if enabled */

  	u16 have_temp;
  	u16 have_temp_fixed;
@@ -1987,6 +1991,48 @@ store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
  	return count;
  }

+static ssize_t
+show_hddsaver(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct nct6775_data *data = nct6775_update_device(dev);
+
+	return sprintf(buf, "%s\n", (data->hddsaver_status ? "On" : "Off"));
+}
+
+static ssize_t
+store_hddsaver(struct device *dev, struct device_attribute *attr, const char *buf,
+	       size_t count)
+{
+	struct nct6775_data *data = dev_get_drvdata(dev);
+	bool val;
+	int err, ret;
+	u8 tmp;
+
+	err = kstrtobool(buf, &val);
+	if (err == -EINVAL)
+		return -EINVAL;
+
+	mutex_lock(&data->update_lock);
+	ret = superio_enter(data->sioreg);
+	if (ret) {
+		count = ret;
+		goto error;
+	}
+
+	if (val != data->hddsaver_status) {
+		superio_select(data->sioreg, NCT6775_LD_GPIO_DATA); /* Logical Device 8 */
+		tmp = superio_inb(data->sioreg,
+				  NCT6775_REG_CR_GPIO1_DATA); /* GPIO1 date reg */
+		superio_outb(data->sioreg, NCT6775_REG_CR_GPIO1_DATA, tmp ^ (1<<0));
+		data->hddsaver_status = val;
+		pr_info("HDD Saver is %s\n", val ? "On" : "Off");
+	}
+	superio_exit(data->sioreg);
+error:
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
  static ssize_t
  show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
  {
@@ -3455,6 +3501,8 @@ static SENSOR_DEVICE_ATTR(intrusion1_beep, S_IWUSR | S_IRUGO, show_beep,
  			  store_beep, INTRUSION_ALARM_BASE + 1);
  static SENSOR_DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_beep,
  			  store_beep, BEEP_ENABLE_BASE);
+static SENSOR_DEVICE_ATTR(hddsaver_enable, S_IWUSR | S_IRUGO, show_hddsaver,
+			  store_hddsaver, 0);

  static umode_t nct6775_other_is_visible(struct kobject *kobj,
  					struct attribute *attr, int index)
@@ -3475,6 +3523,9 @@ static umode_t nct6775_other_is_visible(struct kobject *kobj,
  			return 0;
  	}

+	if (index == 6 && !data->have_hddsaver)
+		return 0;
+
  	return attr->mode;
  }

@@ -3490,6 +3541,7 @@ static struct attribute *nct6775_attributes_other[]= {
  	&sensor_dev_attr_intrusion0_beep.dev_attr.attr,		/* 3 */
  	&sensor_dev_attr_intrusion1_beep.dev_attr.attr,		/* 4 */
  	&sensor_dev_attr_beep_enable.dev_attr.attr,		/* 5 */
+	&sensor_dev_attr_hddsaver_enable.dev_attr.attr,		/* 6 */

  	NULL
  };
@@ -3805,6 +3857,8 @@ static int nct6775_probe(struct platform_device *pdev)
  	struct device *hwmon_dev;
  	int num_attr_groups = 0;

+	const char *board_vendor, *board_name;
+
  	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
  	if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH,
  				 DRVNAME))
@@ -4502,6 +4556,9 @@ static int nct6775_probe(struct platform_device *pdev)
  	/* Initialize the chip */
  	nct6775_init_device(data);

+	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+	board_name = dmi_get_system_info(DMI_BOARD_NAME);
+
  	err = superio_enter(sio_data->sioreg);
  	if (err)
  		return err;
@@ -4518,6 +4575,15 @@ static int nct6775_probe(struct platform_device *pdev)
  	case nct6116:
  	case nct6779:
  	case nct6791:
+		if (board_name && board_vendor &&
+		    !strcmp(board_vendor, "ASRock")) {
+            /* Z97 Extreme6 should also work (the same GPIO10 pin is used) */
+            /* but it needs testing!!! */
+			if (!strcmp(board_name, "Z97 Extreme4") || !strcmp(board_name, "Z97 Extreme6")) {
+                data->have_hddsaver = (cr2a & (1<<6));
+            }
+        }
+        break;
  	case nct6792:
  	case nct6793:
  	case nct6795:
@@ -4527,6 +4593,20 @@ static int nct6775_probe(struct platform_device *pdev)
  		break;
  	}

+	if (data->have_hddsaver) {
+		u8 tmp;
+
+		pr_notice("HDD Saver found\n");
+		superio_select(sio_data->sioreg, NCT6775_LD_GPIO_DATA); /* Logical Device 8 */
+		tmp = superio_inb(sio_data->sioreg, NCT6775_REG_CR_GPIO1_DATA); /* GPIO1 date reg */
+		data->hddsaver_status = tmp & (1<<0); /* check bit0 */
+		if (data->hddsaver_status) {
+			pr_warn("HDD Saver is disabled\n");
+		} else {
+			pr_warn("HDD Saver is enabled\n");
+		}
+	}
+
  	/*
  	 * Read VID value
  	 * We can get the VID input values directly at logical device D 0xe3.
-- 
2.31.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ