All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Barnabás Pőcze" <pobrn@protonmail.com>
To: Nitin Joshi <nitjoshi@gmail.com>
Cc: "hdegoede@redhat.com" <hdegoede@redhat.com>,
	"ibm-acpi-devel@lists.sourceforge.net" 
	<ibm-acpi-devel@lists.sourceforge.net>,
	"platform-driver-x86@vger.kernel.org" 
	<platform-driver-x86@vger.kernel.org>,
	Nitin Joshi <njoshi1@lenovo.com>,
	Mark Pearson <markpearson@lenovo.com>
Subject: Re: [PATCH 1/2] platorm/x86: thinkpad_acpi: sysfs interface to reduce wlan tx power
Date: Fri, 12 Feb 2021 08:56:28 +0000	[thread overview]
Message-ID: <E3f2ByroNWD6igc0zIeWthnZ0NztA6QT_Uvg_wgS912Bq03401uE2ieeXM-WRLezCsBNgesU0myH-69IuKVkXbmtp5jkb30Vd6Rv6E3rld8=@protonmail.com> (raw)
In-Reply-To: <20210212055856.232702-1-njoshi1@lenovo.com>

Hi


2021. február 12., péntek 6:58 keltezéssel, Nitin Joshi írta:

> Some newer Thinkpads have the WLAN antenna placed close to the WWAN
> antenna. In these cases FCC certification requires that when WWAN is
> active we reduce WLAN transmission power. A new Dynamic Power
> Reduction Control (DPRC) method is available from the BIOS on these
> platforms to reduce or restore WLAN Tx power.
>
> This patch provides a sysfs interface that userspace can use to adjust the
> WLAN power appropriately.
>
> Reviewed-by: Mark Pearson <markpearson@lenovo.com>
> Signed-off-by: Nitin Joshi <njoshi1@lenovo.com>
> ---
>  .../admin-guide/laptops/thinkpad-acpi.rst     |  18 +++
>  drivers/platform/x86/thinkpad_acpi.c          | 136 ++++++++++++++++++
>  2 files changed, 154 insertions(+)
>
> diff --git a/Documentation/admin-guide/laptops/thinkpad-acpi.rst b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
> index 5fe1ade88c17..10410811b990 100644
> --- a/Documentation/admin-guide/laptops/thinkpad-acpi.rst
> +++ b/Documentation/admin-guide/laptops/thinkpad-acpi.rst
> @@ -51,6 +51,7 @@ detailed description):
>  	- UWB enable and disable
>  	- LCD Shadow (PrivacyGuard) enable and disable
>  	- Lap mode sensor
> +	- WLAN transmission power control
>
>  A compatibility table by model and feature is maintained on the web
>  site, http://ibm-acpi.sf.net/. I appreciate any success or failure
> @@ -1447,6 +1448,23 @@ they differ between desk and lap mode.
>  The property is read-only. If the platform doesn't have support the sysfs
>  class is not created.
>
> +WLAN transmission power control
> +--------------------------------
> +
> +sysfs: wlan_tx_strength_reduce
> +
> +Some newer Thinkpads have the WLAN antenna placed close to the WWAN antenna.
> +This interface will be used by userspace to reduce the WLAN Tx power strength
> +when WWAN is active, as is required for FCC certification.
> +
> +The available commands are::
> +
> +        echo '0' > /sys/devices/platform/thinkpad_acpi/wlan_tx_strength_reduce
> +        echo '1' > /sys/devices/platform/thinkpad_acpi/wlan_tx_strength_reduce
> +
> +The first command restores the wlan transmission power and the latter one
> +reduces wlan transmission power.
> +
>  EXPERIMENTAL: UWB
>  -----------------
>
> diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
> index f3e8eca8d86d..6dbbd4a14264 100644
> --- a/drivers/platform/x86/thinkpad_acpi.c
> +++ b/drivers/platform/x86/thinkpad_acpi.c
> @@ -9983,6 +9983,138 @@ static struct ibm_struct proxsensor_driver_data = {
>  	.exit = proxsensor_exit,
>  };
>
> +/*************************************************************************
> + * DPRC(Dynamic Power Reduction Control) subdriver, for the Lenovo WWAN
> + * and WLAN feature.
> + */
> +#define DPRC_GET_WLAN_STATE             0x20000
> +#define DPRC_SET_WLAN_POWER_REDUCE      0x00030010
> +#define DPRC_SET_WLAN_POWER_FULL        0x00030100
> +static int has_wlantxreduce;

I think `bool` would be better.


> +static int wlan_txreduce;
> +
> +static int dprc_command(int command, int *output)
> +{
> +	acpi_handle dprc_handle;
> +
> +	if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DPRC", &dprc_handle))) {
> +		/* Platform doesn't support DPRC */
> +		return -ENODEV;
> +	}
> +
> +	if (!acpi_evalf(dprc_handle, output, NULL, "dd", command))
> +		return -EIO;
> +
> +	/*
> +	 * METHOD_ERR gets returned on devices where few commands are not supported
> +	 * for example WLAN power reduce command is not supported on some devices.
> +	 */
> +	if (*output & METHOD_ERR)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +
> +static int get_wlan_state(int *has_wlantxreduce, int *wlan_txreduce)
> +{
> +	int output, err;
> +
> +	/* Get current WLAN Power Transmission state */
> +	err = dprc_command(DPRC_GET_WLAN_STATE, &output);
> +	if (err)
> +		return err;
> +
> +	if (output & BIT(4))

I believe it'd be preferable to name `BIT(4)` and `BIT(8)`. E.g.:

  #define DPRC_GET_WLAN_STATE_RES_REDUCED BIT(4)
  #define DPRC_GET_WLAN_STATE_RES_FULL    BIT(8)

(or any name you like).


> +		*wlan_txreduce = 1;
> +	else if (output & BIT(8))
> +		*wlan_txreduce = 0;
> +	else
> +		*wlan_txreduce = -1;

Can you elaborate what -1 means here? Unknown/not available/invalid/error?


> +
> +	*has_wlantxreduce = 1;

Is it necessary for the getter to set this? Couldn't it be set in
`tpacpi_dprc_init()` once during initialization?


> +	return 0;
> +}
> +
> +/* sysfs wlan entry */
> +static ssize_t wlan_tx_strength_reduce_show(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)

Please align the arguments:

  ..._show(struct device *dev,
           struct device_attribute ...
           ...);


> +{
> +	int err;
> +
> +	err = get_wlan_state(&has_wlantxreduce, &wlan_txreduce);
> +	if (err)
> +		return err;
> +

Wouldn't it be better to return -ENODATA or something
similar when `wlan_txreduce` == -1?


> +	return sysfs_emit(buf, "%d\n", wlan_txreduce);
> +}
> +
> +static ssize_t wlan_tx_strength_reduce_store(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t count)

Same here.


> +{
> +	int output, err;
> +	unsigned long t;
> +
> +	if (parse_strtoul(buf, 1, &t))

Maybe `kstrtobool`?


> +		return -EINVAL;
> +
> +	tpacpi_disclose_usertask(attr->attr.name,
> +				"WLAN tx strength reduced %lu\n", t);
> +
> +	switch (t) {
> +	case 0:
> +		err = dprc_command(DPRC_SET_WLAN_POWER_FULL, &output);
> +		break;
> +	case 1:
> +		err = dprc_command(DPRC_SET_WLAN_POWER_REDUCE, &output);
> +		break;
> +	default:
> +		err = -EINVAL;
> +		dev_err(&tpacpi_pdev->dev, "Unknown operating mode. Ignoring\n");
> +		break;
> +	}
> +

If I'm not mistaken, `err` is never returned, so the write() will always seem
to succeed.


> +	sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "wlan_tx_strength_reduce");
> +	return count;
> +}
> +static DEVICE_ATTR_RW(wlan_tx_strength_reduce);
> +
> +static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
> +{
> +	int wlantx_err, err;
> +
> +	wlantx_err = get_wlan_state(&has_wlantxreduce, &wlan_txreduce);
> +	/*
> +	 * If support isn't available (ENODEV) for both devices then quit, but
> +	 * don't return an error.
> +	 */
> +	if (wlantx_err == -ENODEV)
> +		return 0;
> +	/* Otherwise, if there was an error return it */
> +	if (wlantx_err && (wlantx_err != -ENODEV))
> +		return wlantx_err;
> +
> +	if (has_wlantxreduce) {
> +		err = sysfs_create_file(&tpacpi_pdev->dev.kobj,
> +				&dev_attr_wlan_tx_strength_reduce.attr);

I believe `device_create_file()` would be better.


> +		if (err)
> +			return err;
> +	}
> +	return 0;
> +}
> +
> +static void dprc_exit(void)
> +{
> +	if (has_wlantxreduce)
> +		sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wlan_tx_strength_reduce.attr);

And similarly, `device_remove_file()`.


> +}
> +
> +static struct ibm_struct dprc_driver_data = {
> +	.name = "dprc",
> +	.exit = dprc_exit,
> +};
> +
>  /****************************************************************************
>   ****************************************************************************
>   *
> @@ -10475,6 +10607,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
>  		.init = tpacpi_proxsensor_init,
>  		.data = &proxsensor_driver_data,
>  	},
> +	{
> +		.init = tpacpi_dprc_init,
> +		.data = &dprc_driver_data,
> +	},
>  };
>
>  static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
> --
> 2.25.1


Regards,
Barnabás Pőcze

  parent reply	other threads:[~2021-02-12  8:57 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-12  5:58 [PATCH 1/2] platorm/x86: thinkpad_acpi: sysfs interface to reduce wlan tx power Nitin Joshi
2021-02-12  5:58 ` [PATCH 2/2] platorm/x86: thinkpad_acpi: sysfs interface to interface to get wwan antenna type Nitin Joshi
2021-02-13 20:43   ` Barnabás Pőcze
2021-02-15  9:07     ` [External] " Nitin Joshi1
2021-02-12  8:56 ` Barnabás Pőcze [this message]
2021-02-12 10:40   ` [External] Re: [PATCH 1/2] platorm/x86: thinkpad_acpi: sysfs interface to reduce wlan tx power Nitin Joshi1
2021-02-13 20:48     ` Barnabás Pőcze
2021-02-15  9:07       ` Nitin Joshi1
2021-02-15 14:48 ` Hans de Goede
2021-02-16  3:22   ` [External] " Nitin Joshi1
2021-03-05 16:42 ` Kevin Locke
2021-03-17  2:28   ` [External] " Nitin Joshi1

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='E3f2ByroNWD6igc0zIeWthnZ0NztA6QT_Uvg_wgS912Bq03401uE2ieeXM-WRLezCsBNgesU0myH-69IuKVkXbmtp5jkb30Vd6Rv6E3rld8=@protonmail.com' \
    --to=pobrn@protonmail.com \
    --cc=hdegoede@redhat.com \
    --cc=ibm-acpi-devel@lists.sourceforge.net \
    --cc=markpearson@lenovo.com \
    --cc=nitjoshi@gmail.com \
    --cc=njoshi1@lenovo.com \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.