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-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <9ee8eb9d-1e1c-439f-a382-c003fbd7259c@gmail.com>
Date: Fri, 9 Aug 2024 20:09:23 +0200
From: Maximilian Luz <luzmaximilian@...il.com>
To: Konrad Dybcio <konradybcio@...nel.org>, Rob Herring <robh@...nel.org>,
 Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
 Jiri Slaby <jirislaby@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
 Conor Dooley <conor+dt@...nel.org>, "Rafael J. Wysocki" <rafael@...nel.org>,
 Len Brown <lenb@...nel.org>, Hans de Goede <hdegoede@...hat.com>,
 Ilpo Järvinen <ilpo.jarvinen@...ux.intel.com>
Cc: Marijn Suijten <marijn.suijten@...ainline.org>,
 linux-serial@...r.kernel.org, linux-kernel@...r.kernel.org,
 devicetree@...r.kernel.org, linux-acpi@...r.kernel.org,
 platform-driver-x86@...r.kernel.org, Bjorn Andersson <andersson@...nel.org>,
 Konrad Dybcio <quic_kdybcio@...cinc.com>
Subject: Re: [PATCH 3/3] platform/surface: Add OF support

Hi,

Thanks for taking this up! A couple of comments below:

On 8/9/24 3:48 AM, Konrad Dybcio wrote:
> From: Konrad Dybcio <quic_kdybcio@...cinc.com>
> 
> Add basic support for registering the aggregator module on Device Tree-
> based platforms. These include at least three generations of Qualcomm
> Snapdragon-based Surface devices:
> 
> - SC8180X / SQ1 / SQ2: Pro X,
> - SC8280XP / SQ3: Devkit 2023, Pro 9
> - X Elite: Laptop 7 / Pro11
> 
> Thankfully, the aggregators on these seem to be configured in an
> identical way, which allows for using these settings as defaults and
> no DT properties need to be introduced (until that changes, anyway).
> 
> Based on the work done by Maximilian Luz, largely rewritten.
> 
> Signed-off-by: Konrad Dybcio <quic_kdybcio@...cinc.com>
> ---
>   drivers/acpi/scan.c                                |  3 +-
>   drivers/platform/surface/aggregator/bus.c          |  2 +
>   drivers/platform/surface/aggregator/controller.c   | 72 +++++++++++++++----
>   drivers/platform/surface/aggregator/core.c         | 80 ++++++++++++++++++----
>   .../platform/surface/surface_aggregator_registry.c | 44 ++++++++++--
>   5 files changed, 167 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 59771412686b..6c3cad894648 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -2444,7 +2444,8 @@ static int acpi_walk_dep_device_list(acpi_handle handle,
>    */
>   void acpi_dev_clear_dependencies(struct acpi_device *supplier)
>   {
> -	acpi_walk_dep_device_list(supplier->handle, acpi_scan_clear_dep, NULL);
> +	if (supplier)
> +		acpi_walk_dep_device_list(supplier->handle, acpi_scan_clear_dep, NULL);
>   }
>   EXPORT_SYMBOL_GPL(acpi_dev_clear_dependencies);
>   
> diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
> index af8d573aae93..d68d231e716e 100644
> --- a/drivers/platform/surface/aggregator/bus.c
> +++ b/drivers/platform/surface/aggregator/bus.c
> @@ -6,6 +6,7 @@
>    */
>   
>   #include <linux/device.h>
> +#include <linux/of.h>
>   #include <linux/property.h>
>   #include <linux/slab.h>
>   
> @@ -441,6 +442,7 @@ static int ssam_add_client_device(struct device *parent, struct ssam_controller
>   
>   	sdev->dev.parent = parent;
>   	sdev->dev.fwnode = fwnode_handle_get(node);
> +	sdev->dev.of_node = to_of_node(node);
>   
>   	status = ssam_device_add(sdev);
>   	if (status)
> diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
> index 7fc602e01487..aea10e192140 100644
> --- a/drivers/platform/surface/aggregator/controller.c
> +++ b/drivers/platform/surface/aggregator/controller.c
> @@ -1104,13 +1104,6 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
>   	u64 funcs;
>   	int status;
>   
> -	/* Set defaults. */
> -	caps->ssh_power_profile = U32_MAX;
> -	caps->screen_on_sleep_idle_timeout = U32_MAX;
> -	caps->screen_off_sleep_idle_timeout = U32_MAX;
> -	caps->d3_closes_handle = false;
> -	caps->ssh_buffer_size = U32_MAX;
> -
>   	/* Pre-load supported DSM functions. */
>   	status = ssam_dsm_get_functions(handle, &funcs);
>   	if (status)
> @@ -1149,6 +1142,57 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
>   	return 0;
>   }
>   
> +/**
> + * ssam_controller_caps_load_from_of() - Load controller capabilities from OF/DT.
> + * @device: The device from which to load the capabilities from.
> + * @caps:   Where to store the capabilities in.
> + *
> + * Return: Returns zero on success, a negative error code on failure.
> + */
> +static int ssam_controller_caps_load_from_of(struct device *dev, struct ssam_controller_caps *caps)
> +{
> +	/*
> +	 * Every device starting with Surface Pro X through Laptop 7 uses these
> +	 * identical values, which makes them good defaults.
> +	 */
> +	caps->d3_closes_handle = true;
> +	caps->screen_on_sleep_idle_timeout = 5000;
> +	caps->screen_off_sleep_idle_timeout = 30;
> +	caps->ssh_buffer_size = 48;
> +	/* TODO: figure out power profile */
> +
> +	return 0;
> +}
> +
> +/**
> + * ssam_controller_caps_load_from_acpi() - Load controller capabilities from
> + * ACPI _DSM.
> + * @handle: The handle of the ACPI controller/SSH device.
> + * @caps:   Where to store the capabilities in.
> + *
> + * Initializes the given controller capabilities with default values, then
> + * checks and, if the respective _DSM functions are available, loads the
> + * actual capabilities from the _DSM.
> + *
> + * Return: Returns zero on success, a negative error code on failure.
> + */

Doc needs updating, this is just the one copied from
ssam_controller_caps_load_acpi().

> +static int ssam_controller_caps_load(struct device *dev, struct ssam_controller_caps *caps)
> +{
> +	acpi_handle handle = ACPI_HANDLE(dev);
> +
> +	/* Set defaults. */
> +	caps->ssh_power_profile = U32_MAX;
> +	caps->screen_on_sleep_idle_timeout = U32_MAX;
> +	caps->screen_off_sleep_idle_timeout = U32_MAX;
> +	caps->d3_closes_handle = false;
> +	caps->ssh_buffer_size = U32_MAX;
> +
> +	if (handle)
> +		return ssam_controller_caps_load_from_acpi(handle, caps);
> +	else
> +		return ssam_controller_caps_load_from_of(dev, caps);
> +}
> +
>   /**
>    * ssam_controller_init() - Initialize SSAM controller.
>    * @ctrl:   The controller to initialize.
> @@ -1165,13 +1209,12 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
>   int ssam_controller_init(struct ssam_controller *ctrl,
>   			 struct serdev_device *serdev)
>   {
> -	acpi_handle handle = ACPI_HANDLE(&serdev->dev);
>   	int status;
>   
>   	init_rwsem(&ctrl->lock);
>   	kref_init(&ctrl->kref);
>   
> -	status = ssam_controller_caps_load_from_acpi(handle, &ctrl->caps);
> +	status = ssam_controller_caps_load(&serdev->dev, &ctrl->caps);
>   	if (status)
>   		return status;
>   
> @@ -2715,11 +2758,12 @@ int ssam_irq_setup(struct ssam_controller *ctrl)
>   	const int irqf = IRQF_ONESHOT | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN;
>   
>   	gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
> -	if (IS_ERR(gpiod))
> -		return PTR_ERR(gpiod);
> -
> -	irq = gpiod_to_irq(gpiod);
> -	gpiod_put(gpiod);
> +	if (IS_ERR(gpiod)) {
> +		irq = fwnode_irq_get(dev_fwnode(dev), 0);
> +	} else {
> +		irq = gpiod_to_irq(gpiod);
> +		gpiod_put(gpiod);
> +	}
>   
>   	if (irq < 0)
>   		return irq;
> diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
> index 797d0645bd77..d39e0d7ce92b 100644
> --- a/drivers/platform/surface/aggregator/core.c
> +++ b/drivers/platform/surface/aggregator/core.c
> @@ -17,9 +17,12 @@
>   #include <linux/kernel.h>
>   #include <linux/kref.h>
>   #include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
>   #include <linux/pm.h>
>   #include <linux/serdev.h>
>   #include <linux/sysfs.h>
> +#include <linux/units.h>
>   
>   #include <linux/surface_aggregator/controller.h>
>   #include <linux/surface_aggregator/device.h>
> @@ -299,7 +302,7 @@ static const struct attribute_group ssam_sam_group = {
>   };
>   
>   
> -/* -- ACPI based device setup. ---------------------------------------------- */
> +/* -- Serial device setup. ---------------------------------------------- */

Nitpick, but could we maybe keep that at 80 columns please? :)

>   
>   static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
>   						  void *ctx)
> @@ -352,13 +355,28 @@ static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
>   	return AE_CTRL_TERMINATE;
>   }
>   
> -static acpi_status ssam_serdev_setup_via_acpi(acpi_handle handle,
> -					      struct serdev_device *serdev)
> +static int ssam_serdev_setup_via_acpi(struct serdev_device *serdev, acpi_handle handle)
>   {
> -	return acpi_walk_resources(handle, METHOD_NAME__CRS,
> -				   ssam_serdev_setup_via_acpi_crs, serdev);
> +	acpi_status status;
> +
> +	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
> +				     ssam_serdev_setup_via_acpi_crs, serdev);
> +
> +	return status ? -ENXIO : 0;
>   }
>   
> +static int ssam_serdev_setup(struct acpi_device *ssh, struct serdev_device *serdev)
> +{
> +	if (ssh)
> +		return ssam_serdev_setup_via_acpi(serdev, ssh->handle);
> +
> +	/* TODO: these values may differ per board/implementation */
> +	serdev_device_set_baudrate(serdev, 4 * HZ_PER_MHZ);

Isn't this defined in the DT spec that you're adding as "current-speed"
in patch 2? Why not load it from there?

> +	serdev_device_set_flow_control(serdev, true);
> +	serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
> +
> +	return 0;
> +}
>   
>   /* -- Power management. ----------------------------------------------------- */
>   
> @@ -624,13 +642,15 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
>   	acpi_status astatus;

This can be removed, see below.

>   	int status;
>   
> -	status = gpiod_count(dev, NULL);
> -	if (status < 0)
> -		return dev_err_probe(dev, status, "no GPIO found\n");
> +	if (ssh) {
> +		status = gpiod_count(dev, NULL);
> +		if (status < 0)
> +			return dev_err_probe(dev, status, "no GPIO found\n");
>   
> -	status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios);
> -	if (status)
> -		return status;
> +		status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios);
> +		if (status)
> +			return status;
> +	}
>   
>   	/* Allocate controller. */
>   	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
> @@ -655,7 +675,7 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
>   		goto err_devopen;
>   	}
>   
> -	astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
> +	astatus = ssam_serdev_setup(ssh, serdev);>   	if (ACPI_FAILURE(astatus)) {

ssam_serdev_setup() returns an int, so this should now just use
"status".

>   		status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n");
>   		goto err_devinit;
> @@ -717,10 +737,31 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
>   	 *       For now let's thus default power/wakeup to false.
>   	 */
>   	device_set_wakeup_capable(dev, true);
> +
> +	/*
> +	 * When using DT, we have to register the platform hub driver manually,
> +	 * as it can't be matched based on top-level board compatible (like it
> +	 * does the ACPI case).
> +	 */
> +	if (!ssh) {
> +		struct platform_device *ph_pdev =
> +			platform_device_register_simple("surface_aggregator_platform_hub",
> +							0, NULL, 0);
> +		if (IS_ERR(ph_pdev))
> +			return dev_err_probe(dev, PTR_ERR(ph_pdev),
> +					     "Failed to register the platform hub driver\n");
> +	}
> +
> +	status = ssam_register_clients(&serdev->dev, ctrl);
> +	if (status)
> +		goto err_clients;

Is the ssam_register_clients() call required or is it a remnant from a
previous version? We're now not adding any children to the controller
itself but model ACPI and do all of that with the platform hub. So
unless I'm missing something, I think this should not be necessary.

> +
>   	acpi_dev_clear_dependencies(ssh);
>   
>   	return 0;
>   
> +err_clients:
> +	ssam_clear_controller();
>   err_mainref:
>   	ssam_irq_free(ctrl);
>   err_irq:
> @@ -782,18 +823,27 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev)
>   	device_set_wakeup_capable(&serdev->dev, false);
>   }
>   
> -static const struct acpi_device_id ssam_serial_hub_match[] = {
> +static const struct acpi_device_id ssam_serial_hub_acpi_match[] = {
>   	{ "MSHW0084", 0 },
>   	{ },
>   };
> -MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_match);
> +MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_acpi_match);
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id ssam_serial_hub_of_match[] = {
> +	{ .compatible = "microsoft,surface-sam", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ssam_serial_hub_of_match);
> +#endif
>   
>   static struct serdev_device_driver ssam_serial_hub = {
>   	.probe = ssam_serial_hub_probe,
>   	.remove = ssam_serial_hub_remove,
>   	.driver = {
>   		.name = "surface_serial_hub",
> -		.acpi_match_table = ssam_serial_hub_match,
> +		.acpi_match_table = ACPI_PTR(ssam_serial_hub_acpi_match),
> +		.of_match_table = of_match_ptr(ssam_serial_hub_of_match),
>   		.pm = &ssam_serial_hub_pm_ops,
>   		.shutdown = ssam_serial_hub_shutdown,
>   		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
> index 1c4d74db08c9..57787f2ff38b 100644
> --- a/drivers/platform/surface/surface_aggregator_registry.c
> +++ b/drivers/platform/surface/surface_aggregator_registry.c
> @@ -12,6 +12,7 @@
>   #include <linux/acpi.h>
>   #include <linux/kernel.h>
>   #include <linux/module.h>
> +#include <linux/of.h>
>   #include <linux/platform_device.h>
>   #include <linux/property.h>
>   #include <linux/types.h>
> @@ -273,6 +274,18 @@ static const struct software_node *ssam_node_group_sl5[] = {
>   	NULL,
>   };
>   
> +/* Devices for Surface Laptop 7. */
> +static const struct software_node *ssam_node_group_sl7[] = {
> +	&ssam_node_root,
> +	&ssam_node_bat_ac,
> +	&ssam_node_bat_main,
> +	&ssam_node_tmp_perf_profile_with_fan,
> +	&ssam_node_fan_speed,
> +	&ssam_node_hid_sam_keyboard,

Did you check if there are any other HID devices connected? In the past,
keyboard and touchpad have been split into two separate devices, so is
it a combo keyboard + touchpad device this time? Some models also had
HID-based sensor and other devices.

Would just be good to know if this can be assumed to be complete or if
we're maybe missing something here.

> +	/* TODO: evaluate thermal sensors devices when we get a driver for that */

FYI I've posted the driver at [1]. It needs a small Kbuild dependency
fix but apart from that I think it should be final, if you want to give
that a try.

[1]: https://lore.kernel.org/lkml/20240804230832.247852-1-luzmaximilian@gmail.com/T/

The rest looks fine. I'll try to find some time to update my SPX branch
this weekend and give it a spin.

Regards,
Max

> +	NULL,
> +};
> +
>   /* Devices for Surface Laptop Studio. */
>   static const struct software_node *ssam_node_group_sls[] = {
>   	&ssam_node_root,
> @@ -346,7 +359,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
>   
>   /* -- SSAM platform/meta-hub driver. ---------------------------------------- */
>   
> -static const struct acpi_device_id ssam_platform_hub_match[] = {
> +static const struct acpi_device_id ssam_platform_hub_acpi_match[] = {
>   	/* Surface Pro 4, 5, and 6 (OMBR < 0x10) */
>   	{ "MSHW0081", (unsigned long)ssam_node_group_gen5 },
>   
> @@ -402,16 +415,39 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
>   };
>   MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
>   
> +#ifdef CONFIG_OF
> +static const struct of_device_id ssam_platform_hub_of_match[] = {
> +	/* Surface Laptop 7 */
> +	{ .compatible = "microsoft,romulus13", (void *)ssam_node_group_sl7 },
> +	{ .compatible = "microsoft,romulus15", (void *)ssam_node_group_sl7 },
> +	{ },
> +};
> +#endif
> +
>   static int ssam_platform_hub_probe(struct platform_device *pdev)
>   {
>   	const struct software_node **nodes;
> +	const struct of_device_id *match;
> +	struct device_node *fdt_root;
>   	struct ssam_controller *ctrl;
>   	struct fwnode_handle *root;
>   	int status;
>   
>   	nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev);
> -	if (!nodes)
> -		return -ENODEV;
> +	if (!nodes) {
> +		fdt_root = of_find_node_by_path("/");
> +		if (!fdt_root)
> +			return -ENODEV;
> +
> +		match = of_match_node(ssam_platform_hub_of_match, fdt_root);
> +		of_node_put(fdt_root);
> +		if (!match)
> +			return -ENODEV;
> +
> +		nodes = (const struct software_node **)match->data;
> +		if (!nodes)
> +			return -ENODEV;
> +	}
>   
>   	/*
>   	 * As we're adding the SSAM client devices as children under this device
> @@ -460,7 +496,7 @@ static struct platform_driver ssam_platform_hub_driver = {
>   	.remove_new = ssam_platform_hub_remove,
>   	.driver = {
>   		.name = "surface_aggregator_platform_hub",
> -		.acpi_match_table = ssam_platform_hub_match,
> +		.acpi_match_table = ssam_platform_hub_acpi_match,
>   		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
>   	},
>   };
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ