From 445110941eb94709216363f9d807d2508e64abd7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 20 Jan 2023 12:45:14 +0100 Subject: [PATCH 01/80] leds: led-class: Add missing put_device() to led_put() led_put() is used to "undo" a successful of_led_get() call, of_led_get() uses class_find_device_by_of_node() which returns a reference to the device which must be free-ed with put_device() when the caller is done with it. Add a put_device() call to led_put() to free the reference returned by class_find_device_by_of_node(). And also add a put_device() in the error-exit case of try_module_get() failing. Fixes: 699a8c7c4bd3 ("leds: Add of_led_get() and led_put()") Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Hans de Goede Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230120114524.408368-2-hdegoede@redhat.com --- drivers/leds/led-class.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 6a8ea94834fa..7391d2cf1370 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -241,8 +241,10 @@ struct led_classdev *of_led_get(struct device_node *np, int index) led_cdev = dev_get_drvdata(led_dev); - if (!try_module_get(led_cdev->dev->parent->driver->owner)) + if (!try_module_get(led_cdev->dev->parent->driver->owner)) { + put_device(led_cdev->dev); return ERR_PTR(-ENODEV); + } return led_cdev; } @@ -255,6 +257,7 @@ EXPORT_SYMBOL_GPL(of_led_get); void led_put(struct led_classdev *led_cdev) { module_put(led_cdev->dev->parent->driver->owner); + put_device(led_cdev->dev); } EXPORT_SYMBOL_GPL(led_put); From fafef58ef419f08bb761714a109870b617ac0bc0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 20 Jan 2023 12:45:15 +0100 Subject: [PATCH 02/80] leds: led-class: Add led_module_get() helper Split out part of of_led_get() into a generic led_module_get() helper function. This is a preparation patch for adding a generic (non devicetree specific) led_get() function. Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Hans de Goede Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230120114524.408368-3-hdegoede@redhat.com --- drivers/leds/led-class.c | 42 +++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 7391d2cf1370..743d97b082dc 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -215,26 +215,9 @@ static int led_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume); -/** - * of_led_get() - request a LED device via the LED framework - * @np: device node to get the LED device from - * @index: the index of the LED - * - * Returns the LED device parsed from the phandle specified in the "leds" - * property of a device tree node or a negative error-code on failure. - */ -struct led_classdev *of_led_get(struct device_node *np, int index) +static struct led_classdev *led_module_get(struct device *led_dev) { - struct device *led_dev; struct led_classdev *led_cdev; - struct device_node *led_node; - - led_node = of_parse_phandle(np, "leds", index); - if (!led_node) - return ERR_PTR(-ENOENT); - - led_dev = class_find_device_by_of_node(leds_class, led_node); - of_node_put(led_node); if (!led_dev) return ERR_PTR(-EPROBE_DEFER); @@ -248,6 +231,29 @@ struct led_classdev *of_led_get(struct device_node *np, int index) return led_cdev; } + +/** + * of_led_get() - request a LED device via the LED framework + * @np: device node to get the LED device from + * @index: the index of the LED + * + * Returns the LED device parsed from the phandle specified in the "leds" + * property of a device tree node or a negative error-code on failure. + */ +struct led_classdev *of_led_get(struct device_node *np, int index) +{ + struct device *led_dev; + struct device_node *led_node; + + led_node = of_parse_phandle(np, "leds", index); + if (!led_node) + return ERR_PTR(-ENOENT); + + led_dev = class_find_device_by_of_node(leds_class, led_node); + of_node_put(led_node); + + return led_module_get(led_dev); +} EXPORT_SYMBOL_GPL(of_led_get); /** From 537bdca2a085f524b74ac2aa83822d081c585ca6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 20 Jan 2023 12:45:16 +0100 Subject: [PATCH 03/80] leds: led-class: Add __devm_led_get() helper Add a __devm_led_get() helper which registers a passed in led_classdev with devm for unregistration. This is a preparation patch for adding a generic (non devicetree specific) devm_led_get() function. Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Hans de Goede Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230120114524.408368-4-hdegoede@redhat.com --- drivers/leds/led-class.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 743d97b082dc..4904d140a560 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -274,6 +274,22 @@ static void devm_led_release(struct device *dev, void *res) led_put(*p); } +static struct led_classdev *__devm_led_get(struct device *dev, struct led_classdev *led) +{ + struct led_classdev **dr; + + dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *), GFP_KERNEL); + if (!dr) { + led_put(led); + return ERR_PTR(-ENOMEM); + } + + *dr = led; + devres_add(dev, dr); + + return led; +} + /** * devm_of_led_get - Resource-managed request of a LED device * @dev: LED consumer @@ -289,7 +305,6 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev, int index) { struct led_classdev *led; - struct led_classdev **dr; if (!dev) return ERR_PTR(-EINVAL); @@ -298,17 +313,7 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev, if (IS_ERR(led)) return led; - dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *), - GFP_KERNEL); - if (!dr) { - led_put(led); - return ERR_PTR(-ENOMEM); - } - - *dr = led; - devres_add(dev, dr); - - return led; + return __devm_led_get(dev, led); } EXPORT_SYMBOL_GPL(devm_of_led_get); From abc3100fcba6827444ef4bdb17065ac3b6619dff Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 20 Jan 2023 12:45:17 +0100 Subject: [PATCH 04/80] leds: led-class: Add generic [devm_]led_get() Add a generic [devm_]led_get() method which can be used on both devicetree and non devicetree platforms to get a LED classdev associated with a specific function on a specific device, e.g. the privacy LED associated with a specific camera sensor. Note unlike of_led_get() this takes a string describing the function rather then an index. This is done because e.g. camera sensors might have a privacy LED, or a flash LED, or both and using an index approach leaves it unclear what the function of index 0 is if there is only 1 LED. This uses a lookup-table mechanism for non devicetree platforms. This allows the platform code to map specific LED class_dev-s to a specific device,function combinations this way. For devicetree platforms getting the LED by function-name could be made to work using the standard devicetree pattern of adding a -names string array to map names to the indexes. Reviewed-by: Linus Walleij Signed-off-by: Hans de Goede Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20230120114524.408368-5-hdegoede@redhat.com --- drivers/leds/led-class.c | 84 ++++++++++++++++++++++++++++++++++++++++ include/linux/leds.h | 21 ++++++++++ 2 files changed, 105 insertions(+) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 4904d140a560..0c4b8d8d2b4f 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -23,6 +23,8 @@ #include "leds.h" static struct class *leds_class; +static DEFINE_MUTEX(leds_lookup_lock); +static LIST_HEAD(leds_lookup_list); static ssize_t brightness_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -317,6 +319,88 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev, } EXPORT_SYMBOL_GPL(devm_of_led_get); +/** + * led_get() - request a LED device via the LED framework + * @dev: device for which to get the LED device + * @con_id: name of the LED from the device's point of view + * + * @return a pointer to a LED device or ERR_PTR(errno) on failure. + */ +struct led_classdev *led_get(struct device *dev, char *con_id) +{ + struct led_lookup_data *lookup; + const char *provider = NULL; + struct device *led_dev; + + mutex_lock(&leds_lookup_lock); + list_for_each_entry(lookup, &leds_lookup_list, list) { + if (!strcmp(lookup->dev_id, dev_name(dev)) && + !strcmp(lookup->con_id, con_id)) { + provider = kstrdup_const(lookup->provider, GFP_KERNEL); + break; + } + } + mutex_unlock(&leds_lookup_lock); + + if (!provider) + return ERR_PTR(-ENOENT); + + led_dev = class_find_device_by_name(leds_class, provider); + kfree_const(provider); + + return led_module_get(led_dev); +} +EXPORT_SYMBOL_GPL(led_get); + +/** + * devm_led_get() - request a LED device via the LED framework + * @dev: device for which to get the LED device + * @con_id: name of the LED from the device's point of view + * + * The LED device returned from this function is automatically released + * on driver detach. + * + * @return a pointer to a LED device or ERR_PTR(errno) on failure. + */ +struct led_classdev *devm_led_get(struct device *dev, char *con_id) +{ + struct led_classdev *led; + + led = led_get(dev, con_id); + if (IS_ERR(led)) + return led; + + return __devm_led_get(dev, led); +} +EXPORT_SYMBOL_GPL(devm_led_get); + +/** + * led_add_lookup() - Add a LED lookup table entry + * @led_lookup: the lookup table entry to add + * + * Add a LED lookup table entry. On systems without devicetree the lookup table + * is used by led_get() to find LEDs. + */ +void led_add_lookup(struct led_lookup_data *led_lookup) +{ + mutex_lock(&leds_lookup_lock); + list_add_tail(&led_lookup->list, &leds_lookup_list); + mutex_unlock(&leds_lookup_lock); +} +EXPORT_SYMBOL_GPL(led_add_lookup); + +/** + * led_remove_lookup() - Remove a LED lookup table entry + * @led_lookup: the lookup table entry to remove + */ +void led_remove_lookup(struct led_lookup_data *led_lookup) +{ + mutex_lock(&leds_lookup_lock); + list_del(&led_lookup->list); + mutex_unlock(&leds_lookup_lock); +} +EXPORT_SYMBOL_GPL(led_remove_lookup); + static int led_classdev_next_name(const char *init_name, char *name, size_t len) { diff --git a/include/linux/leds.h b/include/linux/leds.h index ba4861ec73d3..31cb74b90ffc 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -39,6 +39,21 @@ enum led_default_state { LEDS_DEFSTATE_KEEP = 2, }; +/** + * struct led_lookup_data - represents a single LED lookup entry + * + * @list: internal list of all LED lookup entries + * @provider: name of led_classdev providing the LED + * @dev_id: name of the device associated with this LED + * @con_id: name of the LED from the device's point of view + */ +struct led_lookup_data { + struct list_head list; + const char *provider; + const char *dev_id; + const char *con_id; +}; + struct led_init_data { /* device fwnode handle */ struct fwnode_handle *fwnode; @@ -211,6 +226,12 @@ void devm_led_classdev_unregister(struct device *parent, void led_classdev_suspend(struct led_classdev *led_cdev); void led_classdev_resume(struct led_classdev *led_cdev); +void led_add_lookup(struct led_lookup_data *led_lookup); +void led_remove_lookup(struct led_lookup_data *led_lookup); + +struct led_classdev *__must_check led_get(struct device *dev, char *con_id); +struct led_classdev *__must_check devm_led_get(struct device *dev, char *con_id); + extern struct led_classdev *of_led_get(struct device_node *np, int index); extern void led_put(struct led_classdev *led_cdev); struct led_classdev *__must_check devm_of_led_get(struct device *dev, From 72d42499fba913aaf34bace576892883912da3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Dec 2022 17:23:57 +0100 Subject: [PATCH 05/80] platform/x86: acerhdf: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Acked-by: Peter Kaestle Link: https://lore.kernel.org/r/20221213162359.651529-2-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/acerhdf.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index d2c0fc38c201..ed49393d22ed 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -565,11 +565,6 @@ static int acerhdf_probe(struct platform_device *device) return 0; } -static int acerhdf_remove(struct platform_device *device) -{ - return 0; -} - static const struct dev_pm_ops acerhdf_pm_ops = { .suspend = acerhdf_suspend, .freeze = acerhdf_suspend, @@ -581,7 +576,6 @@ static struct platform_driver acerhdf_driver = { .pm = &acerhdf_pm_ops, }, .probe = acerhdf_probe, - .remove = acerhdf_remove, }; /* check hardware */ From c7304c563de8f094dca7c4d7fc84133d3db3e6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Dec 2022 17:23:58 +0100 Subject: [PATCH 06/80] platform/x86: intel: oaktrail: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221213162359.651529-3-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/oaktrail.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/platform/x86/intel/oaktrail.c b/drivers/platform/x86/intel/oaktrail.c index 7c5c623630c1..fa720967e69b 100644 --- a/drivers/platform/x86/intel/oaktrail.c +++ b/drivers/platform/x86/intel/oaktrail.c @@ -266,17 +266,11 @@ static int oaktrail_probe(struct platform_device *pdev) return 0; } -static int oaktrail_remove(struct platform_device *pdev) -{ - return 0; -} - static struct platform_driver oaktrail_driver = { .driver = { .name = DRIVER_NAME, }, .probe = oaktrail_probe, - .remove = oaktrail_remove, }; static int dmi_check_cb(const struct dmi_system_id *id) From 070b3098ddefdadcc6310878cf50ef09b380db1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Dec 2022 17:23:59 +0100 Subject: [PATCH 07/80] platform/x86: intel: punit_ipc: Drop empty platform remove function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A remove callback just returning 0 is equivalent to no remove callback at all. So drop the useless function. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221213162359.651529-4-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/punit_ipc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/platform/x86/intel/punit_ipc.c b/drivers/platform/x86/intel/punit_ipc.c index 66bb39fd0ef9..cd0ba84cc8e4 100644 --- a/drivers/platform/x86/intel/punit_ipc.c +++ b/drivers/platform/x86/intel/punit_ipc.c @@ -302,11 +302,6 @@ static int intel_punit_ipc_probe(struct platform_device *pdev) return 0; } -static int intel_punit_ipc_remove(struct platform_device *pdev) -{ - return 0; -} - static const struct acpi_device_id punit_ipc_acpi_ids[] = { { "INT34D4", 0 }, { } @@ -315,7 +310,6 @@ MODULE_DEVICE_TABLE(acpi, punit_ipc_acpi_ids); static struct platform_driver intel_punit_ipc_driver = { .probe = intel_punit_ipc_probe, - .remove = intel_punit_ipc_remove, .driver = { .name = "intel_punit_ipc", .acpi_match_table = punit_ipc_acpi_ids, From 3f88b459a729ea397aa7cec9a7054a978882370a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:20 +0100 Subject: [PATCH 08/80] platform/surface: aggregator: Improve documentation and handling of message target and source IDs The `tid_in` and `tid_out` fields of the serial hub protocol command struct (struct ssh_command) are actually source and target IDs, indicating the peer from which the message originated and the peer for which it is intended. Change the naming of those fields accordingly and improve the protocol documentation. Additionally, introduce an enum containing all currently known peers, i.e. targets and sources. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../driver-api/surface_aggregator/client.rst | 4 +- .../driver-api/surface_aggregator/ssh.rst | 34 ++++++++-------- .../platform/surface/aggregator/controller.c | 12 +++--- .../platform/surface/aggregator/ssh_msgb.h | 4 +- .../surface/aggregator/ssh_request_layer.c | 11 ++--- include/linux/surface_aggregator/controller.h | 4 +- include/linux/surface_aggregator/serial_hub.h | 40 +++++++++++++------ 7 files changed, 63 insertions(+), 46 deletions(-) diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst index 27f95abdbe99..9d7411223a84 100644 --- a/Documentation/driver-api/surface_aggregator/client.rst +++ b/Documentation/driver-api/surface_aggregator/client.rst @@ -191,7 +191,7 @@ data received from it is converted from little-endian to host endianness. * they do not correspond to an actual SAM/EC request. */ rqst.target_category = SSAM_SSH_TC_SAM; - rqst.target_id = 0x01; + rqst.target_id = SSAM_SSH_TID_SAM; rqst.command_id = 0x02; rqst.instance_id = 0x03; rqst.flags = SSAM_REQUEST_HAS_RESPONSE; @@ -241,7 +241,7 @@ one of the generator macros, for example via: SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, { .target_category = SSAM_SSH_TC_TMP, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x03, .instance_id = 0x00, }); diff --git a/Documentation/driver-api/surface_aggregator/ssh.rst b/Documentation/driver-api/surface_aggregator/ssh.rst index bf007d6c9873..18fd0f0aee84 100644 --- a/Documentation/driver-api/surface_aggregator/ssh.rst +++ b/Documentation/driver-api/surface_aggregator/ssh.rst @@ -13,6 +13,7 @@ .. |DATA_NSQ| replace:: ``DATA_NSQ`` .. |TC| replace:: ``TC`` .. |TID| replace:: ``TID`` +.. |SID| replace:: ``SID`` .. |IID| replace:: ``IID`` .. |RQID| replace:: ``RQID`` .. |CID| replace:: ``CID`` @@ -219,13 +220,13 @@ following fields, packed together and in order: - |u8| - Target category. - * - |TID| (out) + * - |TID| - |u8| - - Target ID for outgoing (host to EC) commands. + - Target ID for commands/messages. - * - |TID| (in) + * - |SID| - |u8| - - Target ID for incoming (EC to host) commands. + - Source ID for commands/messages. * - |IID| - |u8| @@ -286,19 +287,20 @@ general, however, a single target category should map to a single reserved event request ID. Furthermore, requests, responses, and events have an associated target ID -(``TID``). This target ID is split into output (host to EC) and input (EC to -host) fields, with the respecting other field (e.g. output field on incoming -messages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and -secondary (``0x02``). In general, the response to a request should have the -same ``TID`` value, however, the field (output vs. input) should be used in -accordance to the direction in which the response is sent (i.e. on the input -field, as responses are generally sent from the EC to the host). +(``TID``) and source ID (``SID``). These two fields indicate where a message +originates from (``SID``) and what the intended target of the message is +(``TID``). Note that a response to a specific request therefore has the source +and target IDs swapped when compared to the original request (i.e. the request +target is the response source and the request source is the response target). +See (:c:type:`enum ssh_request_id `) for possible values of +both. -Note that, even though requests and events should be uniquely identifiable -by target category and command ID alone, the EC may require specific -target ID and instance ID values to accept a command. A command that is -accepted for ``TID=1``, for example, may not be accepted for ``TID=2`` -and vice versa. +Note that, even though requests and events should be uniquely identifiable by +target category and command ID alone, the EC may require specific target ID and +instance ID values to accept a command. A command that is accepted for +``TID=1``, for example, may not be accepted for ``TID=2`` and vice versa. While +this may not always hold in reality, you can think of different target/source +IDs indicating different physical ECs with potentially different feature sets. Limitations and Observations diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index c6537a1b3a2e..2c99f51ccd4e 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -994,7 +994,7 @@ static void ssam_handle_event(struct ssh_rtl *rtl, item->rqid = get_unaligned_le16(&cmd->rqid); item->event.target_category = cmd->tc; - item->event.target_id = cmd->tid_in; + item->event.target_id = cmd->sid; item->event.command_id = cmd->cid; item->event.instance_id = cmd->iid; memcpy(&item->event.data[0], data->ptr, data->len); @@ -1779,35 +1779,35 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer); SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, { .target_category = SSAM_SSH_TC_SAM, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x13, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, { .target_category = SSAM_SSH_TC_SAM, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x15, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, { .target_category = SSAM_SSH_TC_SAM, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x16, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, { .target_category = SSAM_SSH_TC_SAM, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x33, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, { .target_category = SSAM_SSH_TC_SAM, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x34, .instance_id = 0x00, }); diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h index f3ecad92eefd..438873e06098 100644 --- a/drivers/platform/surface/aggregator/ssh_msgb.h +++ b/drivers/platform/surface/aggregator/ssh_msgb.h @@ -189,8 +189,8 @@ static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid, __msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */ __msgb_push_u8(msgb, rqst->target_category); /* Target category. */ - __msgb_push_u8(msgb, rqst->target_id); /* Target ID (out). */ - __msgb_push_u8(msgb, 0x00); /* Target ID (in). */ + __msgb_push_u8(msgb, rqst->target_id); /* Target ID. */ + __msgb_push_u8(msgb, SSAM_SSH_TID_HOST); /* Source ID. */ __msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */ __msgb_push_u16(msgb, rqid); /* Request ID. */ __msgb_push_u8(msgb, rqst->command_id); /* Command ID. */ diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c index 69132976d297..90634dcacabf 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.c +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c @@ -920,13 +920,14 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data) * Check if the message was intended for us. If not, drop it. * * Note: We will need to change this to handle debug messages. On newer - * generation devices, these seem to be sent to tid_out=0x03. We as - * host can still receive them as they can be forwarded via an override - * option on SAM, but doing so does not change tid_out=0x00. + * generation devices, these seem to be sent to SSAM_SSH_TID_DEBUG. We + * as host can still receive them as they can be forwarded via an + * override option on SAM, but doing so does not change the target ID + * to SSAM_SSH_TID_HOST. */ - if (command->tid_out != 0x00) { + if (command->tid != SSAM_SSH_TID_HOST) { rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n", - command->tid_out); + command->tid); return; } diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index d11a1c6e3186..8932bc0bae18 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -912,10 +912,10 @@ enum ssam_event_mask { }) #define SSAM_EVENT_REGISTRY_SAM \ - SSAM_EVENT_REGISTRY(SSAM_SSH_TC_SAM, 0x01, 0x0b, 0x0c) + SSAM_EVENT_REGISTRY(SSAM_SSH_TC_SAM, SSAM_SSH_TID_SAM, 0x0b, 0x0c) #define SSAM_EVENT_REGISTRY_KIP \ - SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, 0x02, 0x27, 0x28) + SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, SSAM_SSH_TID_KIP, 0x27, 0x28) #define SSAM_EVENT_REGISTRY_REG(tid)\ SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, tid, 0x01, 0x02) diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h index 45501b6e54e8..5c4ae1a26183 100644 --- a/include/linux/surface_aggregator/serial_hub.h +++ b/include/linux/surface_aggregator/serial_hub.h @@ -83,23 +83,21 @@ enum ssh_payload_type { /** * struct ssh_command - Payload of a command-type frame. - * @type: The type of the payload. See &enum ssh_payload_type. Should be - * SSH_PLD_TYPE_CMD for this struct. - * @tc: Command target category. - * @tid_out: Output target ID. Should be zero if this an incoming (EC to host) - * message. - * @tid_in: Input target ID. Should be zero if this is an outgoing (host to - * EC) message. - * @iid: Instance ID. - * @rqid: Request ID. Used to match requests with responses and differentiate - * between responses and events. - * @cid: Command ID. + * @type: The type of the payload. See &enum ssh_payload_type. Should be + * SSH_PLD_TYPE_CMD for this struct. + * @tc: Command target category. + * @tid: Target ID. Indicates the target of the message. + * @sid: Source ID. Indicates the source of the message. + * @iid: Instance ID. + * @rqid: Request ID. Used to match requests with responses and differentiate + * between responses and events. + * @cid: Command ID. */ struct ssh_command { u8 type; u8 tc; - u8 tid_out; - u8 tid_in; + u8 tid; + u8 sid; u8 iid; __le16 rqid; u8 cid; @@ -280,6 +278,22 @@ struct ssam_span { size_t len; }; +/** + * enum ssam_ssh_tid - Target/source IDs for Serial Hub messages. + * @SSAM_SSH_TID_HOST: We as the kernel Serial Hub driver. + * @SSAM_SSH_TID_SAM: The Surface Aggregator EC. + * @SSAM_SSH_TID_KIP: Keyboard and perihperal controller. + * @SSAM_SSH_TID_DEBUG: Debug connector. + * @SSAM_SSH_TID_SURFLINK: SurfLink connector. + */ +enum ssam_ssh_tid { + SSAM_SSH_TID_HOST = 0x00, + SSAM_SSH_TID_SAM = 0x01, + SSAM_SSH_TID_KIP = 0x02, + SSAM_SSH_TID_DEBUG = 0x03, + SSAM_SSH_TID_SURFLINK = 0x04, +}; + /* * Known SSH/EC target categories. * From 2730fc0ab4716bb5d884a8dbd3b0ac73317cfb54 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:21 +0100 Subject: [PATCH 09/80] platform/surface: aggregator: Add target and source IDs to command trace events Add command source and target IDs to trace events. Tracing support for the Surface Aggregator driver was originally implemented at a time when only two peers were known: Host and SAM. We now know that there are at least five, with three actively being used (Host, SAM, KIP; four with Debug if you want to count manually enabling that interface). So it makes sense to also explicitly name the peers involved when tracing. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/aggregator/trace.h | 73 +++++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h index 2a2c17771d01..55cc61bba1da 100644 --- a/drivers/platform/surface/aggregator/trace.h +++ b/drivers/platform/surface/aggregator/trace.h @@ -96,6 +96,7 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS); #define SSAM_SEQ_NOT_APPLICABLE ((u16)-1) #define SSAM_RQID_NOT_APPLICABLE ((u32)-1) #define SSAM_SSH_TC_NOT_APPLICABLE 0 +#define SSAM_SSH_TID_NOT_APPLICABLE ((u8)-1) #ifndef _SURFACE_AGGREGATOR_TRACE_HELPERS #define _SURFACE_AGGREGATOR_TRACE_HELPERS @@ -150,12 +151,44 @@ static inline u32 ssam_trace_get_request_id(const struct ssh_packet *p) return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(rqid)]); } +/** + * ssam_trace_get_request_tid() - Read the packet's request target ID. + * @p: The packet. + * + * Return: Returns the packet's request target ID (TID) field if the packet + * represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE + * if not (e.g. flush request, control packet). + */ +static inline u32 ssam_trace_get_request_tid(const struct ssh_packet *p) +{ + if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0)) + return SSAM_SSH_TID_NOT_APPLICABLE; + + return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(tid)]); +} + +/** + * ssam_trace_get_request_sid() - Read the packet's request source ID. + * @p: The packet. + * + * Return: Returns the packet's request source ID (SID) field if the packet + * represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE + * if not (e.g. flush request, control packet). + */ +static inline u32 ssam_trace_get_request_sid(const struct ssh_packet *p) +{ + if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0)) + return SSAM_SSH_TID_NOT_APPLICABLE; + + return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(sid)]); +} + /** * ssam_trace_get_request_tc() - Read the packet's request target category. * @p: The packet. * * Return: Returns the packet's request target category (TC) field if the - * packet represents a request with command data, or %SSAM_TC_NOT_APPLICABLE + * packet represents a request with command data, or %SSAM_SSH_TC_NOT_APPLICABLE * if not (e.g. flush request, control packet). */ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p) @@ -232,8 +265,18 @@ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p) { SSAM_RQID_NOT_APPLICABLE, "N/A" } \ ) -#define ssam_show_ssh_tc(rqid) \ - __print_symbolic(rqid, \ +#define ssam_show_ssh_tid(tid) \ + __print_symbolic(tid, \ + { SSAM_SSH_TID_NOT_APPLICABLE, "N/A" }, \ + { SSAM_SSH_TID_HOST, "Host" }, \ + { SSAM_SSH_TID_SAM, "SAM" }, \ + { SSAM_SSH_TID_KIP, "KIP" }, \ + { SSAM_SSH_TID_DEBUG, "Debug" }, \ + { SSAM_SSH_TID_SURFLINK, "SurfLink" } \ + ) + +#define ssam_show_ssh_tc(tc) \ + __print_symbolic(tc, \ { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \ { SSAM_SSH_TC_SAM, "SAM" }, \ { SSAM_SSH_TC_BAT, "BAT" }, \ @@ -313,6 +356,8 @@ DECLARE_EVENT_CLASS(ssam_command_class, TP_STRUCT__entry( __field(u16, rqid) __field(u16, len) + __field(u8, tid) + __field(u8, sid) __field(u8, tc) __field(u8, cid) __field(u8, iid) @@ -320,14 +365,18 @@ DECLARE_EVENT_CLASS(ssam_command_class, TP_fast_assign( __entry->rqid = get_unaligned_le16(&cmd->rqid); + __entry->tid = cmd->tid; + __entry->sid = cmd->sid; __entry->tc = cmd->tc; __entry->cid = cmd->cid; __entry->iid = cmd->iid; __entry->len = len; ), - TP_printk("rqid=%#06x, tc=%s, cid=%#04x, iid=%#04x, len=%u", + TP_printk("rqid=%#06x, tid=%s, sid=%s, tc=%s, cid=%#04x, iid=%#04x, len=%u", __entry->rqid, + ssam_show_ssh_tid(__entry->tid), + ssam_show_ssh_tid(__entry->sid), ssam_show_ssh_tc(__entry->tc), __entry->cid, __entry->iid, @@ -430,6 +479,8 @@ DECLARE_EVENT_CLASS(ssam_request_class, __field(u8, tc) __field(u16, cid) __field(u16, iid) + __field(u8, tid) + __field(u8, sid) ), TP_fast_assign( @@ -439,16 +490,20 @@ DECLARE_EVENT_CLASS(ssam_request_class, __entry->state = READ_ONCE(request->state); __entry->rqid = ssam_trace_get_request_id(p); ssam_trace_ptr_uid(p, __entry->uid); + __entry->tid = ssam_trace_get_request_tid(p); + __entry->sid = ssam_trace_get_request_sid(p); __entry->tc = ssam_trace_get_request_tc(p); __entry->cid = ssam_trace_get_command_field_u8(p, cid); __entry->iid = ssam_trace_get_command_field_u8(p, iid); ), - TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s", + TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s", __entry->uid, ssam_show_request_id(__entry->rqid), ssam_show_request_type(__entry->state), ssam_show_request_state(__entry->state), + ssam_show_ssh_tid(__entry->tid), + ssam_show_ssh_tid(__entry->sid), ssam_show_ssh_tc(__entry->tc), ssam_show_generic_u8_field(__entry->cid), ssam_show_generic_u8_field(__entry->iid) @@ -474,6 +529,8 @@ DECLARE_EVENT_CLASS(ssam_request_status_class, __field(u8, tc) __field(u16, cid) __field(u16, iid) + __field(u8, tid) + __field(u8, sid) ), TP_fast_assign( @@ -484,16 +541,20 @@ DECLARE_EVENT_CLASS(ssam_request_status_class, __entry->rqid = ssam_trace_get_request_id(p); __entry->status = status; ssam_trace_ptr_uid(p, __entry->uid); + __entry->tid = ssam_trace_get_request_tid(p); + __entry->sid = ssam_trace_get_request_sid(p); __entry->tc = ssam_trace_get_request_tc(p); __entry->cid = ssam_trace_get_command_field_u8(p, cid); __entry->iid = ssam_trace_get_command_field_u8(p, iid); ), - TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s, status=%d", + TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s, status=%d", __entry->uid, ssam_show_request_id(__entry->rqid), ssam_show_request_type(__entry->state), ssam_show_request_state(__entry->state), + ssam_show_ssh_tid(__entry->tid), + ssam_show_ssh_tid(__entry->sid), ssam_show_ssh_tc(__entry->tc), ssam_show_generic_u8_field(__entry->cid), ssam_show_generic_u8_field(__entry->iid), From 0a603d710c73f551f75fc1d607a1800116664ecc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:22 +0100 Subject: [PATCH 10/80] platform/surface: aggregator_hub: Use target-ID enum instead of hard-coding values Instead of hard-coding the target ID, use the respective enum ssam_ssh_tid value. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-5-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_hub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c index 43061514be38..62f27cdb6ca8 100644 --- a/drivers/platform/surface/surface_aggregator_hub.c +++ b/drivers/platform/surface/surface_aggregator_hub.c @@ -214,7 +214,7 @@ static void ssam_hub_remove(struct ssam_device *sdev) SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x0d, .instance_id = 0x00, }); @@ -292,7 +292,7 @@ static const struct ssam_hub_desc base_hub = { SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, { .target_category = SSAM_SSH_TC_KIP, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x2c, .instance_id = 0x00, }); From 36f672a40e7d82fda7cf93b35949539aee61bfea Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:23 +0100 Subject: [PATCH 11/80] platform/surface: aggregator_tabletsw: Use target-ID enum instead of hard-coding values Instead of hard-coding the target ID, use the respective enum ssam_ssh_tid value. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-6-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_tabletsw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c index 27d95a6a7851..bd8cd453c393 100644 --- a/drivers/platform/surface/surface_aggregator_tabletsw.c +++ b/drivers/platform/surface/surface_aggregator_tabletsw.c @@ -247,7 +247,7 @@ static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 s SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, { .target_category = SSAM_SSH_TC_KIP, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x1d, .instance_id = 0x00, }); @@ -371,7 +371,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour int status; rqst.target_category = SSAM_SSH_TC_POS; - rqst.target_id = 0x01; + rqst.target_id = SSAM_SSH_TID_SAM; rqst.command_id = 0x01; rqst.instance_id = 0x00; rqst.flags = SSAM_REQUEST_HAS_RESPONSE; @@ -430,7 +430,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id) SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, { .target_category = SSAM_SSH_TC_POS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x02, .instance_id = 0x00, }); From 1e6201d96ef901eb954c8ea0b16cc14bdc44e4ea Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:24 +0100 Subject: [PATCH 12/80] platform/surface: dtx: Use target-ID enum instead of hard-coding values Instead of hard-coding the target ID, use the respective enum ssam_ssh_tid value. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-7-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_dtx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c index ed36944467f9..0de76a784a35 100644 --- a/drivers/platform/surface/surface_dtx.c +++ b/drivers/platform/surface/surface_dtx.c @@ -71,63 +71,63 @@ static_assert(sizeof(struct ssam_bas_base_info) == 2); SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x06, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x07, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x08, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x09, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x0a, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x0b, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x0c, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x0d, .instance_id = 0x00, }); SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, { .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, + .target_id = SSAM_SSH_TID_SAM, .command_id = 0x11, .instance_id = 0x00, }); From ea11bf4eb59e029cc54ad294126098dce67e321a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:25 +0100 Subject: [PATCH 13/80] HID: surface-hid: Use target-ID enum instead of hard-coding values Instead of hard-coding the target ID, use the respective enum ssam_ssh_tid value. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-8-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/hid/surface-hid/surface_kbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/surface-hid/surface_kbd.c b/drivers/hid/surface-hid/surface_kbd.c index 0635341bc517..42933bf3e925 100644 --- a/drivers/hid/surface-hid/surface_kbd.c +++ b/drivers/hid/surface-hid/surface_kbd.c @@ -250,7 +250,7 @@ static int surface_kbd_probe(struct platform_device *pdev) shid->uid.domain = SSAM_DOMAIN_SERIALHUB; shid->uid.category = SSAM_SSH_TC_KBD; - shid->uid.target = 2; + shid->uid.target = SSAM_SSH_TID_KIP; shid->uid.instance = 0; shid->uid.function = 0; From 78abf1b5205534bb7deda408aa5b9b7e0bf1982e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:26 +0100 Subject: [PATCH 14/80] platform/surface: aggregator: Enforce use of target-ID enum in device ID macros Similar to the target category (TC), the target ID (TID) can be one value out of a small number of choices, given in enum ssam_ssh_tid. In the device ID macros, SSAM_SDEV() and SSAM_VDEV() we already use text expansion to, both, remove some textual clutter for the target category values and enforce that the value belongs to the known set. Now that we know the names for the target IDs, use the same trick for them as well. Also rename the SSAM_ANY_x macros to SSAM_SSH_x_ANY to better fit in. Signed-off-by: Maximilian Luz Acked-by: Sebastian Reichel Link: https://lore.kernel.org/r/20221202223327.690880-9-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/hid/surface-hid/surface_hid.c | 2 +- .../platform/surface/surface_aggregator_hub.c | 4 +- .../surface/surface_aggregator_tabletsw.c | 4 +- drivers/platform/surface/surface_dtx.c | 2 +- .../surface/surface_platform_profile.c | 2 +- drivers/power/supply/surface_battery.c | 4 +- drivers/power/supply/surface_charger.c | 2 +- include/linux/surface_aggregator/device.h | 50 +++++++++---------- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c index d4aa8c81903a..aa80d83a83d1 100644 --- a/drivers/hid/surface-hid/surface_hid.c +++ b/drivers/hid/surface-hid/surface_hid.c @@ -230,7 +230,7 @@ static void surface_hid_remove(struct ssam_device *sdev) } static const struct ssam_device_id surface_hid_match[] = { - { SSAM_SDEV(HID, SSAM_ANY_TID, SSAM_ANY_IID, 0x00) }, + { SSAM_SDEV(HID, ANY, SSAM_SSH_IID_ANY, 0x00) }, { }, }; MODULE_DEVICE_TABLE(ssam, surface_hid_match); diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c index 62f27cdb6ca8..6abd1efe2088 100644 --- a/drivers/platform/surface/surface_aggregator_hub.c +++ b/drivers/platform/surface/surface_aggregator_hub.c @@ -348,8 +348,8 @@ static const struct ssam_hub_desc kip_hub = { /* -- Driver registration. -------------------------------------------------- */ static const struct ssam_device_id ssam_hub_match[] = { - { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub }, - { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, + { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub }, + { SSAM_VDEV(HUB, KIP, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, { } }; MODULE_DEVICE_TABLE(ssam, ssam_hub_match); diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c index bd8cd453c393..6147aa887939 100644 --- a/drivers/platform/surface/surface_aggregator_tabletsw.c +++ b/drivers/platform/surface/surface_aggregator_tabletsw.c @@ -510,8 +510,8 @@ static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = { /* -- Driver registration. -------------------------------------------------- */ static const struct ssam_device_id ssam_tablet_sw_match[] = { - { SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc }, - { SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc }, + { SSAM_SDEV(KIP, SAM, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc }, + { SSAM_SDEV(POS, SAM, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc }, { }, }; MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match); diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c index 0de76a784a35..30cbde278c59 100644 --- a/drivers/platform/surface/surface_dtx.c +++ b/drivers/platform/surface/surface_dtx.c @@ -1214,7 +1214,7 @@ static void surface_dtx_ssam_remove(struct ssam_device *sdev) } static const struct ssam_device_id surface_dtx_ssam_match[] = { - { SSAM_SDEV(BAS, 0x01, 0x00, 0x00) }, + { SSAM_SDEV(BAS, SAM, 0x00, 0x00) }, { }, }; MODULE_DEVICE_TABLE(ssam, surface_dtx_ssam_match); diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c index fbf2e11fd6ce..f433a13c3689 100644 --- a/drivers/platform/surface/surface_platform_profile.c +++ b/drivers/platform/surface/surface_platform_profile.c @@ -169,7 +169,7 @@ static void surface_platform_profile_remove(struct ssam_device *sdev) } static const struct ssam_device_id ssam_platform_profile_match[] = { - { SSAM_SDEV(TMP, 0x01, 0x00, 0x01) }, + { SSAM_SDEV(TMP, SAM, 0x00, 0x01) }, { }, }; MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match); diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c index 540707882bb0..19d2f8834e56 100644 --- a/drivers/power/supply/surface_battery.c +++ b/drivers/power/supply/surface_battery.c @@ -852,8 +852,8 @@ static const struct spwr_psy_properties spwr_psy_props_bat2_sb3 = { }; static const struct ssam_device_id surface_battery_match[] = { - { SSAM_SDEV(BAT, 0x01, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1 }, - { SSAM_SDEV(BAT, 0x02, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 }, + { SSAM_SDEV(BAT, SAM, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat1 }, + { SSAM_SDEV(BAT, KIP, 0x01, 0x00), (unsigned long)&spwr_psy_props_bat2_sb3 }, { }, }; MODULE_DEVICE_TABLE(ssam, surface_battery_match); diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c index 59182d55742d..cabdd8da12d0 100644 --- a/drivers/power/supply/surface_charger.c +++ b/drivers/power/supply/surface_charger.c @@ -260,7 +260,7 @@ static const struct spwr_psy_properties spwr_psy_props_adp1 = { }; static const struct ssam_device_id surface_ac_match[] = { - { SSAM_SDEV(BAT, 0x01, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 }, + { SSAM_SDEV(BAT, SAM, 0x01, 0x01), (unsigned long)&spwr_psy_props_adp1 }, { }, }; MODULE_DEVICE_TABLE(ssam, surface_ac_match); diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 46c45d1b6368..4da20b7a0ee5 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -68,9 +68,9 @@ struct ssam_device_uid { * match_flags member of the device ID structure. Do not use them directly * with struct ssam_device_id or struct ssam_device_uid. */ -#define SSAM_ANY_TID 0xffff -#define SSAM_ANY_IID 0xffff -#define SSAM_ANY_FUN 0xffff +#define SSAM_SSH_TID_ANY 0xffff +#define SSAM_SSH_IID_ANY 0xffff +#define SSAM_SSH_FUN_ANY 0xffff /** * SSAM_DEVICE() - Initialize a &struct ssam_device_id with the given @@ -83,25 +83,25 @@ struct ssam_device_uid { * * Initializes a &struct ssam_device_id with the given parameters. See &struct * ssam_device_uid for details regarding the parameters. The special values - * %SSAM_ANY_TID, %SSAM_ANY_IID, and %SSAM_ANY_FUN can be used to specify that + * %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and %SSAM_SSH_FUN_ANY can be used to specify that * matching should ignore target ID, instance ID, and/or sub-function, * respectively. This macro initializes the ``match_flags`` field based on the * given parameters. * * Note: The parameters @d and @cat must be valid &u8 values, the parameters - * @tid, @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID, - * %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not + * @tid, @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY, + * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not * allowed. */ #define SSAM_DEVICE(d, cat, tid, iid, fun) \ - .match_flags = (((tid) != SSAM_ANY_TID) ? SSAM_MATCH_TARGET : 0) \ - | (((iid) != SSAM_ANY_IID) ? SSAM_MATCH_INSTANCE : 0) \ - | (((fun) != SSAM_ANY_FUN) ? SSAM_MATCH_FUNCTION : 0), \ + .match_flags = (((tid) != SSAM_SSH_TID_ANY) ? SSAM_MATCH_TARGET : 0) \ + | (((iid) != SSAM_SSH_IID_ANY) ? SSAM_MATCH_INSTANCE : 0) \ + | (((fun) != SSAM_SSH_FUN_ANY) ? SSAM_MATCH_FUNCTION : 0), \ .domain = d, \ .category = cat, \ - .target = __builtin_choose_expr((tid) != SSAM_ANY_TID, (tid), 0), \ - .instance = __builtin_choose_expr((iid) != SSAM_ANY_IID, (iid), 0), \ - .function = __builtin_choose_expr((fun) != SSAM_ANY_FUN, (fun), 0) + .target = __builtin_choose_expr((tid) != SSAM_SSH_TID_ANY, (tid), 0), \ + .instance = __builtin_choose_expr((iid) != SSAM_SSH_IID_ANY, (iid), 0), \ + .function = __builtin_choose_expr((fun) != SSAM_SSH_FUN_ANY, (fun), 0) /** * SSAM_VDEV() - Initialize a &struct ssam_device_id as virtual device with @@ -113,18 +113,18 @@ struct ssam_device_uid { * * Initializes a &struct ssam_device_id with the given parameters in the * virtual domain. See &struct ssam_device_uid for details regarding the - * parameters. The special values %SSAM_ANY_TID, %SSAM_ANY_IID, and - * %SSAM_ANY_FUN can be used to specify that matching should ignore target ID, + * parameters. The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and + * %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target ID, * instance ID, and/or sub-function, respectively. This macro initializes the * ``match_flags`` field based on the given parameters. * * Note: The parameter @cat must be a valid &u8 value, the parameters @tid, - * @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID, - * %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not + * @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY, + * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not * allowed. */ #define SSAM_VDEV(cat, tid, iid, fun) \ - SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, tid, iid, fun) + SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, SSAM_SSH_TID_##tid, iid, fun) /** * SSAM_SDEV() - Initialize a &struct ssam_device_id as physical SSH device @@ -136,18 +136,18 @@ struct ssam_device_uid { * * Initializes a &struct ssam_device_id with the given parameters in the SSH * domain. See &struct ssam_device_uid for details regarding the parameters. - * The special values %SSAM_ANY_TID, %SSAM_ANY_IID, and %SSAM_ANY_FUN can be - * used to specify that matching should ignore target ID, instance ID, and/or - * sub-function, respectively. This macro initializes the ``match_flags`` - * field based on the given parameters. + * The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and + * %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target + * ID, instance ID, and/or sub-function, respectively. This macro initializes + * the ``match_flags`` field based on the given parameters. * * Note: The parameter @cat must be a valid &u8 value, the parameters @tid, - * @iid, and @fun must be either valid &u8 values or %SSAM_ANY_TID, - * %SSAM_ANY_IID, or %SSAM_ANY_FUN, respectively. Other non-&u8 values are not - * allowed. + * @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY, + * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values + * are not allowed. */ #define SSAM_SDEV(cat, tid, iid, fun) \ - SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun) + SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, SSAM_SSH_TID_##tid, iid, fun) /* * enum ssam_device_flags - Flags for SSAM client devices. From 13eca7d74e331deb5924ad0555355c114a59def2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 2 Dec 2022 23:33:27 +0100 Subject: [PATCH 15/80] platform/surface: aggregator_registry: Fix target-ID of base-hub The target ID of the base hub is currently set to KIP (keyboard/ peripherals). However, even though it manages such devices with the KIP target ID, the base hub itself is actually accessed via the SAM target ID. So set it accordingly. Note that the target ID of the hub can be chosen arbitrarily and does not directly correspond to any physical or virtual component of the EC. This change is only a code improvement intended for consistency and clarity, it does not fix an actual bug. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221202223327.690880-10-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_hub.c | 2 +- drivers/platform/surface/surface_aggregator_registry.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c index 6abd1efe2088..8b8b80228c14 100644 --- a/drivers/platform/surface/surface_aggregator_hub.c +++ b/drivers/platform/surface/surface_aggregator_hub.c @@ -349,7 +349,7 @@ static const struct ssam_hub_desc kip_hub = { static const struct ssam_device_id ssam_hub_match[] = { { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub }, - { SSAM_VDEV(HUB, KIP, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, + { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, { } }; MODULE_DEVICE_TABLE(ssam, ssam_hub_match); diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 023f126121d7..296f72d52e6a 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -46,7 +46,7 @@ static const struct software_node ssam_node_hub_kip = { /* Base device hub (devices attached to Surface Book 3 base). */ static const struct software_node ssam_node_hub_base = { - .name = "ssam:00:00:02:11:00", + .name = "ssam:00:00:01:11:00", .parent = &ssam_node_root, }; From b09ee1cd59918bcf1a6793b663034b6e345b3ced Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 20 Dec 2022 18:56:08 +0100 Subject: [PATCH 16/80] platform/surface: aggregator: Rename top-level request functions to avoid ambiguities We currently have a struct ssam_request_sync and a function ssam_request_sync(). While this is valid C, there are some downsides to it. One of these is that current Sphinx versions (>= 3.0) cannot disambiguate between the two (see disucssion and pull request linked below). It instead emits a "WARNING: Duplicate C declaration" and links for the struct and function in the resulting documentation link to the same entry (i.e. both to either function or struct documentation) instead of their respective own entries. While we could just ignore that and wait for a fix, there's also a point to be made that the current naming can be somewhat confusing when searching (e.g. via grep) or trying to understand the levels of abstraction at play: We currently have struct ssam_request_sync and associated functions ssam_request_sync_[alloc|free|init|wait|...]() operating on this struct. However, function ssam_request_sync() is one abstraction level above this. Similarly, ssam_request_sync_with_buffer() is not a function operating on struct ssam_request_sync, but rather a sibling to ssam_request_sync(), both using the struct under the hood. Therefore, rename the top level request functions: ssam_request_sync() -> ssam_request_do_sync() ssam_request_sync_with_buffer() -> ssam_request_do_sync_with_buffer() ssam_request_sync_onstack() -> ssam_request_do_sync_onstack() Link: https://lore.kernel.org/all/085e0ada65c11da9303d07e70c510dc45f21315b.1656756450.git.mchehab@kernel.org/ Link: https://github.com/sphinx-doc/sphinx/pull/8313 Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20221220175608.1436273-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../driver-api/surface_aggregator/client.rst | 8 +-- drivers/hid/surface-hid/surface_hid.c | 6 +- drivers/hid/surface-hid/surface_kbd.c | 6 +- drivers/platform/surface/aggregator/bus.c | 6 +- .../platform/surface/aggregator/controller.c | 32 +++++------ .../platform/surface/surface_acpi_notify.c | 2 +- .../surface/surface_aggregator_cdev.c | 6 +- .../surface/surface_aggregator_tabletsw.c | 2 +- include/linux/surface_aggregator/controller.h | 56 +++++++++---------- include/linux/surface_aggregator/device.h | 8 +-- 10 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst index 9d7411223a84..e100ab0a24cc 100644 --- a/Documentation/driver-api/surface_aggregator/client.rst +++ b/Documentation/driver-api/surface_aggregator/client.rst @@ -19,7 +19,7 @@ .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister` .. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register` .. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister` -.. |ssam_request_sync| replace:: :c:func:`ssam_request_sync` +.. |ssam_request_do_sync| replace:: :c:func:`ssam_request_do_sync` .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask ` @@ -209,12 +209,12 @@ data received from it is converted from little-endian to host endianness. * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification * above. */ - status = ssam_request_sync(ctrl, &rqst, &resp); + status = ssam_request_do_sync(ctrl, &rqst, &resp); /* * Alternatively use * - * ssam_request_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le)); + * ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le)); * * to perform the request, allocating the message buffer directly * on the stack as opposed to allocation via kzalloc(). @@ -230,7 +230,7 @@ data received from it is converted from little-endian to host endianness. return status; } -Note that |ssam_request_sync| in its essence is a wrapper over lower-level +Note that |ssam_request_do_sync| in its essence is a wrapper over lower-level request primitives, which may also be used to perform requests. Refer to its implementation and documentation for more details. diff --git a/drivers/hid/surface-hid/surface_hid.c b/drivers/hid/surface-hid/surface_hid.c index aa80d83a83d1..61e5814b0ad7 100644 --- a/drivers/hid/surface-hid/surface_hid.c +++ b/drivers/hid/surface-hid/surface_hid.c @@ -80,7 +80,7 @@ static int ssam_hid_get_descriptor(struct surface_hid_device *shid, u8 entry, u8 rsp.length = 0; - status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, + status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(*slice)); if (status) return status; @@ -131,7 +131,7 @@ static int ssam_hid_set_raw_report(struct surface_hid_device *shid, u8 rprt_id, buf[0] = rprt_id; - return ssam_retry(ssam_request_sync, shid->ctrl, &rqst, NULL); + return ssam_retry(ssam_request_do_sync, shid->ctrl, &rqst, NULL); } static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len) @@ -151,7 +151,7 @@ static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id, rsp.length = 0; rsp.pointer = buf; - return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id)); + return ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id)); } static u32 ssam_hid_event_fn(struct ssam_event_notifier *nf, const struct ssam_event *event) diff --git a/drivers/hid/surface-hid/surface_kbd.c b/drivers/hid/surface-hid/surface_kbd.c index 42933bf3e925..4fbce201db6a 100644 --- a/drivers/hid/surface-hid/surface_kbd.c +++ b/drivers/hid/surface-hid/surface_kbd.c @@ -49,7 +49,7 @@ static int ssam_kbd_get_descriptor(struct surface_hid_device *shid, u8 entry, u8 rsp.length = 0; rsp.pointer = buf; - status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry)); + status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry)); if (status) return status; @@ -75,7 +75,7 @@ static int ssam_kbd_set_caps_led(struct surface_hid_device *shid, bool value) rqst.length = sizeof(value_u8); rqst.payload = &value_u8; - return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8)); + return ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8)); } static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf, size_t len) @@ -97,7 +97,7 @@ static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf, rsp.length = 0; rsp.pointer = buf; - status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload)); + status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload)); if (status) return status; diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index de539938896e..7004eb4a63a2 100644 --- a/drivers/platform/surface/aggregator/bus.c +++ b/drivers/platform/surface/aggregator/bus.c @@ -136,9 +136,9 @@ int ssam_device_add(struct ssam_device *sdev) * is always valid and can be used for requests as long as the client * device we add here is registered as child under it. This essentially * guarantees that the client driver can always expect the preconditions - * for functions like ssam_request_sync (controller has to be started - * and is not suspended) to hold and thus does not have to check for - * them. + * for functions like ssam_request_do_sync() (controller has to be + * started and is not suspended) to hold and thus does not have to check + * for them. * * Note that for this to work, the controller has to be a parent device. * If it is not a direct parent, care has to be taken that the device is diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index 2c99f51ccd4e..535581c0471c 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -1674,7 +1674,7 @@ int ssam_request_sync_submit(struct ssam_controller *ctrl, EXPORT_SYMBOL_GPL(ssam_request_sync_submit); /** - * ssam_request_sync() - Execute a synchronous request. + * ssam_request_do_sync() - Execute a synchronous request. * @ctrl: The controller via which the request will be submitted. * @spec: The request specification and payload. * @rsp: The response buffer. @@ -1686,9 +1686,9 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_submit); * * Return: Returns the status of the request or any failure during setup. */ -int ssam_request_sync(struct ssam_controller *ctrl, - const struct ssam_request *spec, - struct ssam_response *rsp) +int ssam_request_do_sync(struct ssam_controller *ctrl, + const struct ssam_request *spec, + struct ssam_response *rsp) { struct ssam_request_sync *rqst; struct ssam_span buf; @@ -1722,10 +1722,10 @@ int ssam_request_sync(struct ssam_controller *ctrl, ssam_request_sync_free(rqst); return status; } -EXPORT_SYMBOL_GPL(ssam_request_sync); +EXPORT_SYMBOL_GPL(ssam_request_do_sync); /** - * ssam_request_sync_with_buffer() - Execute a synchronous request with the + * ssam_request_do_sync_with_buffer() - Execute a synchronous request with the * provided buffer as back-end for the message buffer. * @ctrl: The controller via which the request will be submitted. * @spec: The request specification and payload. @@ -1738,17 +1738,17 @@ EXPORT_SYMBOL_GPL(ssam_request_sync); * SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required * message buffer size. * - * This function does essentially the same as ssam_request_sync(), but instead - * of dynamically allocating the request and message data buffer, it uses the - * provided message data buffer and stores the (small) request struct on the - * heap. + * This function does essentially the same as ssam_request_do_sync(), but + * instead of dynamically allocating the request and message data buffer, it + * uses the provided message data buffer and stores the (small) request struct + * on the heap. * * Return: Returns the status of the request or any failure during setup. */ -int ssam_request_sync_with_buffer(struct ssam_controller *ctrl, - const struct ssam_request *spec, - struct ssam_response *rsp, - struct ssam_span *buf) +int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl, + const struct ssam_request *spec, + struct ssam_response *rsp, + struct ssam_span *buf) { struct ssam_request_sync rqst; ssize_t len; @@ -1772,7 +1772,7 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl, return status; } -EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer); +EXPORT_SYMBOL_GPL(ssam_request_do_sync_with_buffer); /* -- Internal SAM requests. ------------------------------------------------ */ @@ -1864,7 +1864,7 @@ static int __ssam_ssh_event_request(struct ssam_controller *ctrl, result.length = 0; result.pointer = &buf; - status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result, + status = ssam_retry(ssam_request_do_sync_onstack, ctrl, &rqst, &result, sizeof(params)); return status < 0 ? status : buf; diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 50500e562963..897cdd9c3aae 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -590,7 +590,7 @@ static acpi_status san_rqst(struct san_data *d, struct gsb_buffer *buffer) return san_rqst_fixup_suspended(d, &rqst, buffer); } - status = __ssam_retry(ssam_request_sync_onstack, SAN_REQUEST_NUM_TRIES, + status = __ssam_retry(ssam_request_do_sync_onstack, SAN_REQUEST_NUM_TRIES, d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD); if (!status) { diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c index 492c82e69182..07f0ed658369 100644 --- a/drivers/platform/surface/surface_aggregator_cdev.c +++ b/drivers/platform/surface/surface_aggregator_cdev.c @@ -302,8 +302,8 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_ * theoretical maximum (SSH_COMMAND_MAX_PAYLOAD_SIZE) of the * underlying protocol (note that nothing remotely this size * should ever be allocated in any normal case). This size is - * validated later in ssam_request_sync(), for allocation the - * bound imposed by u16 should be enough. + * validated later in ssam_request_do_sync(), for allocation + * the bound imposed by u16 should be enough. */ spec.payload = kzalloc(spec.length, GFP_KERNEL); if (!spec.payload) { @@ -342,7 +342,7 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_ } /* Perform request. */ - status = ssam_request_sync(client->cdev->ctrl, &spec, &rsp); + status = ssam_request_do_sync(client->cdev->ctrl, &spec, &rsp); if (status) goto out; diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c index 6147aa887939..9fed800c7cc0 100644 --- a/drivers/platform/surface/surface_aggregator_tabletsw.c +++ b/drivers/platform/surface/surface_aggregator_tabletsw.c @@ -382,7 +382,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour rsp.length = 0; rsp.pointer = (u8 *)sources; - status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0); + status = ssam_retry(ssam_request_do_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0); if (status) return status; diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index 8932bc0bae18..cb7980805920 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -207,17 +207,17 @@ static inline int ssam_request_sync_wait(struct ssam_request_sync *rqst) return rqst->status; } -int ssam_request_sync(struct ssam_controller *ctrl, - const struct ssam_request *spec, - struct ssam_response *rsp); +int ssam_request_do_sync(struct ssam_controller *ctrl, + const struct ssam_request *spec, + struct ssam_response *rsp); -int ssam_request_sync_with_buffer(struct ssam_controller *ctrl, - const struct ssam_request *spec, - struct ssam_response *rsp, - struct ssam_span *buf); +int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl, + const struct ssam_request *spec, + struct ssam_response *rsp, + struct ssam_span *buf); /** - * ssam_request_sync_onstack - Execute a synchronous request on the stack. + * ssam_request_do_sync_onstack - Execute a synchronous request on the stack. * @ctrl: The controller via which the request is submitted. * @rqst: The request specification. * @rsp: The response buffer. @@ -227,7 +227,7 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl, * fully initializes it via the provided request specification, submits it, * and finally waits for its completion before returning its status. This * helper macro essentially allocates the request message buffer on the stack - * and then calls ssam_request_sync_with_buffer(). + * and then calls ssam_request_do_sync_with_buffer(). * * Note: The @payload_len parameter specifies the maximum payload length, used * for buffer allocation. The actual payload length may be smaller. @@ -235,12 +235,12 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl, * Return: Returns the status of the request or any failure during setup, i.e. * zero on success and a negative value on failure. */ -#define ssam_request_sync_onstack(ctrl, rqst, rsp, payload_len) \ +#define ssam_request_do_sync_onstack(ctrl, rqst, rsp, payload_len) \ ({ \ u8 __data[SSH_COMMAND_MESSAGE_LENGTH(payload_len)]; \ struct ssam_span __buf = { &__data[0], ARRAY_SIZE(__data) }; \ \ - ssam_request_sync_with_buffer(ctrl, rqst, rsp, &__buf); \ + ssam_request_do_sync_with_buffer(ctrl, rqst, rsp, &__buf); \ }) /** @@ -349,7 +349,7 @@ struct ssam_request_spec_md { * zero on success and negative on failure. The ``ctrl`` parameter is the * controller via which the request is being sent. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_N(name, spec...) \ @@ -366,7 +366,7 @@ struct ssam_request_spec_md { rqst.length = 0; \ rqst.payload = NULL; \ \ - return ssam_request_sync_onstack(ctrl, &rqst, NULL, 0); \ + return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, 0); \ } /** @@ -389,7 +389,7 @@ struct ssam_request_spec_md { * parameter is the controller via which the request is sent. The request * argument is specified via the ``arg`` pointer. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_W(name, atype, spec...) \ @@ -406,8 +406,8 @@ struct ssam_request_spec_md { rqst.length = sizeof(atype); \ rqst.payload = (u8 *)arg; \ \ - return ssam_request_sync_onstack(ctrl, &rqst, NULL, \ - sizeof(atype)); \ + return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, \ + sizeof(atype)); \ } /** @@ -430,7 +430,7 @@ struct ssam_request_spec_md { * the controller via which the request is sent. The request's return value is * written to the memory pointed to by the ``ret`` parameter. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_R(name, rtype, spec...) \ @@ -453,7 +453,7 @@ struct ssam_request_spec_md { rsp.length = 0; \ rsp.pointer = (u8 *)ret; \ \ - status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \ + status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, 0); \ if (status) \ return status; \ \ @@ -491,7 +491,7 @@ struct ssam_request_spec_md { * request argument is specified via the ``arg`` pointer. The request's return * value is written to the memory pointed to by the ``ret`` parameter. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_WR(name, atype, rtype, spec...) \ @@ -514,7 +514,7 @@ struct ssam_request_spec_md { rsp.length = 0; \ rsp.pointer = (u8 *)ret; \ \ - status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ + status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ if (status) \ return status; \ \ @@ -550,7 +550,7 @@ struct ssam_request_spec_md { * parameter is the controller via which the request is sent, ``tid`` the * target ID for the request, and ``iid`` the instance ID. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_N(name, spec...) \ @@ -567,7 +567,7 @@ struct ssam_request_spec_md { rqst.length = 0; \ rqst.payload = NULL; \ \ - return ssam_request_sync_onstack(ctrl, &rqst, NULL, 0); \ + return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, 0); \ } /** @@ -592,7 +592,7 @@ struct ssam_request_spec_md { * ``tid`` the target ID for the request, and ``iid`` the instance ID. The * request argument is specified via the ``arg`` pointer. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_W(name, atype, spec...) \ @@ -609,7 +609,7 @@ struct ssam_request_spec_md { rqst.length = sizeof(atype); \ rqst.payload = (u8 *)arg; \ \ - return ssam_request_sync_onstack(ctrl, &rqst, NULL, \ + return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, \ sizeof(atype)); \ } @@ -635,7 +635,7 @@ struct ssam_request_spec_md { * the target ID for the request, and ``iid`` the instance ID. The request's * return value is written to the memory pointed to by the ``ret`` parameter. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_R(name, rtype, spec...) \ @@ -658,7 +658,7 @@ struct ssam_request_spec_md { rsp.length = 0; \ rsp.pointer = (u8 *)ret; \ \ - status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, 0); \ + status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, 0); \ if (status) \ return status; \ \ @@ -698,7 +698,7 @@ struct ssam_request_spec_md { * The request argument is specified via the ``arg`` pointer. The request's * return value is written to the memory pointed to by the ``ret`` parameter. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_MD_WR(name, atype, rtype, spec...) \ @@ -722,7 +722,7 @@ struct ssam_request_spec_md { rsp.length = 0; \ rsp.pointer = (u8 *)ret; \ \ - status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ + status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ if (status) \ return status; \ \ diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 4da20b7a0ee5..1545e5567b15 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -456,7 +456,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev) * device of the request and by association the controller via which the * request is sent. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...) \ @@ -490,7 +490,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev) * which the request is sent. The request's argument is specified via the * ``arg`` pointer. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...) \ @@ -524,7 +524,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev) * the request is sent. The request's return value is written to the memory * pointed to by the ``ret`` parameter. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \ @@ -560,7 +560,7 @@ static inline int ssam_device_register_clients(struct ssam_device *sdev) * specified via the ``arg`` pointer. The request's return value is written to * the memory pointed to by the ``ret`` parameter. * - * Refer to ssam_request_sync_onstack() for more details on the behavior of + * Refer to ssam_request_do_sync_onstack() for more details on the behavior of * the generated function. */ #define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...) \ From c6d41f66d50a46ee943124f5079ad0282080cfb1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 18 Jan 2023 11:38:23 +0200 Subject: [PATCH 17/80] platform/surface: Switch to use acpi_evaluate_dsm_typed() The acpi_evaluate_dsm_typed() provides a way to check the type of the object evaluated by _DSM call. Use it instead of open coded variant. Signed-off-by: Andy Shevchenko Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20230118093823.39679-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_hotplug.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c index f004a2495201..7b6d887dccdb 100644 --- a/drivers/platform/surface/surface_hotplug.c +++ b/drivers/platform/surface/surface_hotplug.c @@ -101,18 +101,12 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type param.type = ACPI_TYPE_INTEGER; param.integer.value = value; - result = acpi_evaluate_dsm(handle, &shps_dsm_guid, SHPS_DSM_REVISION, - shps_dsm_fn_for_irq(type), ¶m); - + result = acpi_evaluate_dsm_typed(handle, &shps_dsm_guid, SHPS_DSM_REVISION, + shps_dsm_fn_for_irq(type), ¶m, ACPI_TYPE_BUFFER); if (!result) { dev_err(&pdev->dev, "IRQ notification via DSM failed (irq=%d, gpio=%d)\n", type, value); - } else if (result->type != ACPI_TYPE_BUFFER) { - dev_err(&pdev->dev, - "IRQ notification via DSM failed: unexpected result type (irq=%d, gpio=%d)\n", - type, value); - } else if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) { dev_err(&pdev->dev, "IRQ notification via DSM failed: unexpected result value (irq=%d, gpio=%d)\n", @@ -121,8 +115,7 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type mutex_unlock(&sdev->lock[type]); - if (result) - ACPI_FREE(result); + ACPI_FREE(result); } static irqreturn_t shps_handle_irq(int irq, void *data) From 6ab983187d80a10f67c8cf19a0a6640ab79a92b9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 18 Jan 2023 11:54:40 +0200 Subject: [PATCH 18/80] platform/x86: intel/pmc: Switch to use acpi_evaluate_dsm_typed() The acpi_evaluate_dsm_typed() provides a way to check the type of the object evaluated by _DSM call. Use it instead of open coded variant. Signed-off-by: Andy Shevchenko Reviewed-by: Rajneesh Bhardwaj Link: https://lore.kernel.org/r/20230118095440.41634-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/pmc/tgl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c index e3e50538465d..c245ada849d0 100644 --- a/drivers/platform/x86/intel/pmc/tgl.c +++ b/drivers/platform/x86/intel/pmc/tgl.c @@ -221,9 +221,9 @@ void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev) guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid); - out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0, - ACPI_GET_LOW_MODE_REGISTERS, NULL); - if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) { + out_obj = acpi_evaluate_dsm_typed(adev->handle, &s0ix_dsm_guid, 0, + ACPI_GET_LOW_MODE_REGISTERS, NULL, ACPI_TYPE_BUFFER); + if (out_obj) { u32 size = out_obj->buffer.length; if (size != lpm_size) { From 92e3524754dc1eb1e690cd109110929e54c76993 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2023 20:09:04 +0200 Subject: [PATCH 19/80] platform/x86: int1092: Switch to use acpi_evaluate_dsm_typed() The acpi_evaluate_dsm_typed() provides a way to check the type of the object evaluated by _DSM call. Use it instead of open coded variant. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230119180904.78446-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/int1092/intel_sar.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c index e03943e6380a..352fc4596494 100644 --- a/drivers/platform/x86/intel/int1092/intel_sar.c +++ b/drivers/platform/x86/intel/int1092/intel_sar.c @@ -131,16 +131,15 @@ static acpi_status sar_get_device_mode(struct platform_device *device) acpi_status status = AE_OK; union acpi_object *out; u32 rev = 0; - int value; - out = acpi_evaluate_dsm(context->handle, &context->guid, rev, - COMMAND_ID_DEV_MODE, NULL); - if (get_int_value(out, &value)) { + out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev, + COMMAND_ID_DEV_MODE, NULL, ACPI_TYPE_INTEGER); + if (!out) { dev_err(&device->dev, "DSM cmd:%d Failed to retrieve value\n", COMMAND_ID_DEV_MODE); status = AE_ERROR; goto dev_mode_error; } - context->sar_data.device_mode = value; + context->sar_data.device_mode = out->integer.value; update_sar_data(context); sysfs_notify(&device->dev.kobj, NULL, SYSFS_DATANAME); @@ -221,11 +220,11 @@ static void sar_get_data(int reg, struct wwan_sar_context *context) req.type = ACPI_TYPE_INTEGER; req.integer.value = reg; - out = acpi_evaluate_dsm(context->handle, &context->guid, rev, - COMMAND_ID_CONFIG_TABLE, &req); + out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev, + COMMAND_ID_CONFIG_TABLE, &req, ACPI_TYPE_PACKAGE); if (!out) return; - if (out->type == ACPI_TYPE_PACKAGE && out->package.count >= 3 && + if (out->package.count >= 3 && out->package.elements[0].type == ACPI_TYPE_INTEGER && out->package.elements[1].type == ACPI_TYPE_INTEGER && out->package.elements[2].type == ACPI_TYPE_PACKAGE && From df72690ec365394c3850b37679a3b06c582db252 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jan 2023 16:45:12 +0100 Subject: [PATCH 20/80] platform/x86: apple_gmux: Drop no longer used ACPI_VIDEO Kconfig dependency The apple_gmux code no longer uses any symbols from the ACPI_VIDEO code, so that dependency can be dropped. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230123154512.852921-1-hdegoede@redhat.com --- drivers/platform/x86/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 5692385e2d26..ec7c2b4e1721 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -214,7 +214,6 @@ config APPLE_GMUX depends on PNP depends on BACKLIGHT_CLASS_DEVICE depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE - depends on ACPI_VIDEO=n || ACPI_VIDEO help This driver provides support for the gmux device found on many Apple laptops, which controls the display mux for the hybrid From 8071b210aeb96ff047fcf55fe4fa1f7e07012e90 Mon Sep 17 00:00:00 2001 From: Rishit Bansal Date: Tue, 24 Jan 2023 03:11:50 +0530 Subject: [PATCH 21/80] platform/x86: hp-wmi: Ignore Win-Lock key events Follow up from https://lore.kernel.org/all/20230120221214.24426-1-rishitbansal0@gmail.com/ There is a "Win-Lock" key on HP Omen Laptops which supports enabling and disabling the Windows key, which trigger commands 0x21a4 and 0x121a4 respectively. Currently the hp-wmi driver throws warnings for this event. These can be ignored using KE_IGNORE as the functionality is handled by the keyboard firmware itself. Signed-off-by: Rishit Bansal Link: https://lore.kernel.org/r/20230123214150.62597-1-rishitbansal0@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/hp/hp-wmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 2ef201b625b3..873f59c3e280 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -217,6 +217,8 @@ static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x213b, { KEY_INFO } }, { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, { KE_KEY, 0x216a, { KEY_SETUP } }, + { KE_IGNORE, 0x21a4, }, /* Win Lock On */ + { KE_IGNORE, 0x121a4, }, /* Win Lock Off */ { KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */ { KE_KEY, 0x21a7, { KEY_FN_ESC } }, { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } }, From 507fa17a6c46c111f6b0d2bc483c1b3563fd16c5 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 12 Jan 2023 14:43:33 +0800 Subject: [PATCH 22/80] tools/power/x86/intel-speed-select: Remove wrong check in set_isst_id() struct isst_id *id is a pointer, comparing it with less than zero is wrong. The check is there to make sure the id->pkg and id->die is set to -1, when it is illegal or unavailable. Here comparing with MAX_PACKAGE_COUNT and MAX_DIE_PER_PACKAGE is sufficient. Hence remove the wrong check. Signed-off-by: Zhang Rui [srinivas.pandruvada@linux.intel.com: Subject and changelog edits] Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index a160bad291eb..b5822ee67cb3 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -383,11 +383,11 @@ void set_isst_id(struct isst_id *id, int cpu) id->cpu = cpu; id->pkg = get_physical_package_id(cpu); - if (id < 0 || id->pkg >= MAX_PACKAGE_COUNT) + if (id->pkg >= MAX_PACKAGE_COUNT) id->pkg = -1; id->die = get_physical_die_id(cpu); - if (id < 0 || id->die >= MAX_DIE_PER_PACKAGE) + if (id->die >= MAX_DIE_PER_PACKAGE) id->die = -1; } From b8bebc8e58d5dc8f2c528b0be4e858959c48e340 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 12 Jan 2023 14:43:34 +0800 Subject: [PATCH 23/80] tools/power/x86/intel-speed-select: Remove unused non_block flag variable 'non_block' is always 0, thus remove the variable and the handling for "non_block != 0" case. Signed-off-by: Zhang Rui Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/hfi-events.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/power/x86/intel-speed-select/hfi-events.c b/tools/power/x86/intel-speed-select/hfi-events.c index be96e90cc2a1..174b99d9f864 100644 --- a/tools/power/x86/intel-speed-select/hfi-events.c +++ b/tools/power/x86/intel-speed-select/hfi-events.c @@ -247,7 +247,6 @@ int hfi_main(void) struct nl_cb *cb; int err = 0; int mcast_id; - int no_block = 0; if (!check_hf_suport()) { fprintf(stderr, "CPU Doesn't support HFI\n"); @@ -287,9 +286,6 @@ int hfi_main(void) nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_handler, 0); nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_event, NULL); - if (no_block) - nl_socket_set_nonblocking(sock); - debug_printf("hfi is initialized\n"); while (!_hfi_exit && !err) { From 364ba3b7115087ab8960473a94cedc7336f345e2 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 12 Jan 2023 14:43:35 +0800 Subject: [PATCH 24/80] tools/power/x86/intel-speed-select: Handle open() failure case Add handling for open() failure case to make sure a valid file descriptor is passed to dup(). Signed-off-by: Zhang Rui Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-daemon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-daemon.c b/tools/power/x86/intel-speed-select/isst-daemon.c index 0699137c0901..4ad6a64f1545 100644 --- a/tools/power/x86/intel-speed-select/isst-daemon.c +++ b/tools/power/x86/intel-speed-select/isst-daemon.c @@ -174,6 +174,8 @@ static void daemonize(char *rundir, char *pidfile) close(i); i = open("/dev/null", O_RDWR); + if (i < 0) + exit(EXIT_FAILURE); ret = dup(i); if (ret == -1) exit(EXIT_FAILURE); From 8a44d27542cd84352c69e37deaafb8b8976f21a0 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 12 Jan 2023 14:43:36 +0800 Subject: [PATCH 25/80] tools/power/x86/intel-speed-select: Remove duplicate dup() Remove the duplicate dup() invocation. Signed-off-by: Zhang Rui Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-daemon.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-daemon.c b/tools/power/x86/intel-speed-select/isst-daemon.c index 4ad6a64f1545..c2290ef0e3af 100644 --- a/tools/power/x86/intel-speed-select/isst-daemon.c +++ b/tools/power/x86/intel-speed-select/isst-daemon.c @@ -176,9 +176,6 @@ static void daemonize(char *rundir, char *pidfile) i = open("/dev/null", O_RDWR); if (i < 0) exit(EXIT_FAILURE); - ret = dup(i); - if (ret == -1) - exit(EXIT_FAILURE); ret = dup(i); if (ret == -1) From 689dfc9e40036cb74f30c0700905b44b2c935846 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Thu, 12 Jan 2023 14:43:37 +0800 Subject: [PATCH 26/80] tools/power/x86/intel-speed-select: Use null-terminated string strlen() and strtok() takes null-termimated strings as input. Make sure these strings are null-terminated before using them. Signed-off-by: Zhang Rui Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index b5822ee67cb3..b549e6f0946d 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -1583,6 +1583,7 @@ static int set_cpufreq_scaling_min_max_from_cpuinfo(int cpu, int cpuinfo_max, in if (fd < 0) return fd; + min_freq[15] = '\0'; len = strlen(min_freq); ret = write(fd, min_freq, len); if (ret == -1) { @@ -2015,6 +2016,7 @@ static void set_fact_enable(int arg) if (len < 0) continue; + sibling_list[127] = '\0'; cpu_str = strtok(sibling_list, ","); while (cpu_str != NULL) { int cpu; From cf3b8e8f55e1a6c747e89599695fb8783c8a69c2 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 6 Jan 2023 17:44:26 -0800 Subject: [PATCH 27/80] tools/power/x86/intel-speed-select: cpufreq reads on offline CPUs Due to some recent kernel changes, reading cpufreq attributes like scaling_max_freq on offline CPUs returns error. So avoid reading cpufreq attributes on offline CPUs. Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- .../x86/intel-speed-select/isst-config.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index b549e6f0946d..2a737bff79cd 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -413,6 +413,33 @@ int get_topo_max_cpus(void) return topo_max_cpus; } +static unsigned int is_cpu_online(int cpu) +{ + char buffer[128]; + int fd, ret; + unsigned char online; + + snprintf(buffer, sizeof(buffer), + "/sys/devices/system/cpu/cpu%d/online", cpu); + + fd = open(buffer, O_RDONLY); + if (fd < 0) + return fd; + + ret = read(fd, &online, sizeof(online)); + close(fd); + + if (ret == -1) + return ret; + + if (online == '1') + online = 1; + else + online = 0; + + return online; +} + void set_cpu_online_offline(int cpu, int state) { char buffer[128]; @@ -1603,6 +1630,9 @@ static void set_scaling_min_to_cpuinfo_max(struct isst_id *id) if (!is_cpu_in_power_domain(i, id)) continue; + if (is_cpu_online(i) != 1) + continue; + adjust_scaling_max_from_base_freq(i); set_cpufreq_scaling_min_max_from_cpuinfo(i, 1, 0); adjust_scaling_min_from_base_freq(i); @@ -1617,6 +1647,9 @@ static void set_scaling_min_to_cpuinfo_min(struct isst_id *id) if (!is_cpu_in_power_domain(i, id)) continue; + if (is_cpu_online(i) != 1) + continue; + adjust_scaling_max_from_base_freq(i); set_cpufreq_scaling_min_max_from_cpuinfo(i, 0, 0); } From 6ed9e363157cb858bdbb8c595f04839d3f245414 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 6 Jan 2023 17:48:07 -0800 Subject: [PATCH 28/80] tools/power/x86/intel-speed-select: turbo-freq auto mode with SMT off When SMT is disabled from kernel command line, sibling CPUs still appears in the sysfs as offline CPUs. This is a problem when turbo-freq is enabled in auto mode. They are still assigned to CLOS value of 3 as they are still in the present CPU list. But they are not in the sibling list of a CPU. When the CPU is a high priority CPU, because of sibling it will be still set to CLOS to 3 as CLOS is assigned at core level not at CPU level. So, avoid setting CLOS 3 to offline CPU. Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-config.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 2a737bff79cd..5f5349faeb23 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -2066,6 +2066,9 @@ static void set_fact_enable(int arg) if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask)) continue; + if (is_cpu_online(i) != 1) + continue; + set_isst_id(&id, i); ret = set_clos_param(&id, 0, 0, 0, 0, 0xff); if (ret) From 0d5eea3527e4618ee32fce91a5d54638a7f8c411 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 9 Dec 2022 11:23:02 -0800 Subject: [PATCH 29/80] tools/power/x86/intel-speed-select: Fix display of uncore min frequency Uncore P1 is not uncore minmum frequency. This is uncore base frequency. Correct display from uncore-frequency-min(MHz) to uncore-frequency-base(Mhz). To get uncore min frequency use mailbox command CONFIG_TDP_GET_RATIO_INFO. Use this mailbox to get uncore frequency limits when present. Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- .../power/x86/intel-speed-select/isst-core.c | 23 +++++++++++++++++++ .../x86/intel-speed-select/isst-display.c | 11 +++++++-- tools/power/x86/intel-speed-select/isst.h | 4 ++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/tools/power/x86/intel-speed-select/isst-core.c b/tools/power/x86/intel-speed-select/isst-core.c index f701b45c832c..2bfc118c4b87 100644 --- a/tools/power/x86/intel-speed-select/isst-core.c +++ b/tools/power/x86/intel-speed-select/isst-core.c @@ -156,6 +156,29 @@ void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index, { unsigned int resp; int ret; + + ctdp_level->uncore_pm = 0; + ctdp_level->uncore_p0 = 0; + ctdp_level->uncore_p1 = 0; + + ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, + CONFIG_TDP_GET_RATIO_INFO, 0, + (BIT(16) | config_index), &resp); + if (ret) + goto try_uncore_mbox; + + ctdp_level->uncore_p0 = resp & GENMASK(7, 0); + ctdp_level->uncore_p1 = (resp & GENMASK(15, 8)) >> 8; + ctdp_level->uncore_pm = (resp & GENMASK(31, 24)) >> 24; + + debug_printf( + "cpu:%d ctdp:%d CONFIG_TDP_GET_RATIO_INFO resp:%x uncore p0:%d uncore p1:%d uncore pm:%d\n", + id->cpu, config_index, resp, ctdp_level->uncore_p0, ctdp_level->uncore_p1, + ctdp_level->uncore_pm); + + return; + +try_uncore_mbox: ret = isst_send_mbox_command(id->cpu, CONFIG_TDP, CONFIG_TDP_GET_UNCORE_P0_P1_INFO, 0, config_index, &resp); diff --git a/tools/power/x86/intel-speed-select/isst-display.c b/tools/power/x86/intel-speed-select/isst-display.c index b19f57d30f55..7feadac04a6f 100644 --- a/tools/power/x86/intel-speed-select/isst-display.c +++ b/tools/power/x86/intel-speed-select/isst-display.c @@ -423,10 +423,10 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level format_and_print(outf, level + 2, header, value); } - if (ctdp_level->uncore_p1) { + if (ctdp_level->uncore_pm) { snprintf(header, sizeof(header), "uncore-frequency-min(MHz)"); snprintf(value, sizeof(value), "%d", - ctdp_level->uncore_p1 * DISP_FREQ_MULTIPLIER); + ctdp_level->uncore_pm * DISP_FREQ_MULTIPLIER); format_and_print(outf, level + 2, header, value); } @@ -437,6 +437,13 @@ void isst_ctdp_display_information(struct isst_id *id, FILE *outf, int tdp_level format_and_print(outf, level + 2, header, value); } + if (ctdp_level->uncore_p1) { + snprintf(header, sizeof(header), "uncore-frequency-base(MHz)"); + snprintf(value, sizeof(value), "%d", + ctdp_level->uncore_p1 * DISP_FREQ_MULTIPLIER); + format_and_print(outf, level + 2, header, value); + } + if (ctdp_level->mem_freq) { snprintf(header, sizeof(header), "mem-frequency(MHz)"); snprintf(value, sizeof(value), "%d", diff --git a/tools/power/x86/intel-speed-select/isst.h b/tools/power/x86/intel-speed-select/isst.h index 409fcc9c8033..824876e31e23 100644 --- a/tools/power/x86/intel-speed-select/isst.h +++ b/tools/power/x86/intel-speed-select/isst.h @@ -47,6 +47,7 @@ #define CONFIG_TDP_GET_UNCORE_P0_P1_INFO 0X09 #define CONFIG_TDP_GET_P1_INFO 0x0a #define CONFIG_TDP_GET_MEM_FREQ 0x0b +#define CONFIG_TDP_GET_RATIO_INFO 0x0c #define CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES 0x10 #define CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS 0x11 @@ -144,6 +145,7 @@ struct isst_pkg_ctdp_level_info { int t_proc_hot; int uncore_p0; int uncore_p1; + int uncore_pm; int sse_p1; int avx2_p1; int avx512_p1; @@ -208,6 +210,8 @@ extern int isst_get_ctdp_control(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level); extern int isst_get_coremask_info(struct isst_id *id, int config_index, struct isst_pkg_ctdp_level_info *ctdp_level); +extern void isst_get_uncore_p0_p1_info(struct isst_id *id, int config_index, + struct isst_pkg_ctdp_level_info *ctdp_level); extern int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev); extern void isst_get_process_ctdp_complete(struct isst_id *id, From 61f9fdcdcd01f9a996b6db4e7092fcdfe8414ad5 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 24 Aug 2022 15:44:42 +0800 Subject: [PATCH 30/80] tools/power/x86/intel-speed-select: Add Emerald Rapid quirk Need memory frequency quirk as Sapphire Rapids in Emerald Rapids. So add Emerald Rapids CPU model check in is_spr_platform(). Signed-off-by: Zhang Rui [srinivas.pandruvada@linux.intel.com: Subject, changelog and code edits] Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 5f5349faeb23..9f201189a06d 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -110,7 +110,7 @@ int is_skx_based_platform(void) int is_spr_platform(void) { - if (cpu_model == 0x8F) + if (cpu_model == 0x8F || cpu_model == 0xCF) return 1; return 0; From 2612ae596129ad9792b9cd5bf5937614edca185f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 17 Jan 2023 14:34:27 -0800 Subject: [PATCH 31/80] tools/power/x86/intel-speed-select: Adjust uncore max/min frequency When perf level is changed, uncore limits can change. Set the uncore limits via Linux uncore sysfs, when user changes perf level with -o option. Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- .../x86/intel-speed-select/isst-config.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 9f201189a06d..15bee7f52044 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -1319,6 +1319,34 @@ static void dump_isst_config(int arg) isst_ctdp_display_information_end(outf); } +static int set_uncore_min_max(struct isst_id *id, int max, int freq) +{ + char buffer[128], freq_str[16]; + int fd, ret, len; + + if (max) + snprintf(buffer, sizeof(buffer), + "/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/max_freq_khz", id->pkg, id->die); + else + snprintf(buffer, sizeof(buffer), + "/sys/devices/system/cpu/intel_uncore_frequency/package_%02d_die_%02d/min_freq_khz", id->pkg, id->die); + + fd = open(buffer, O_WRONLY); + if (fd < 0) + return fd; + + snprintf(freq_str, sizeof(freq_str), "%d", freq); + len = strlen(freq_str); + ret = write(fd, freq_str, len); + if (ret == -1) { + close(fd); + return ret; + } + close(fd); + + return 0; +} + static void adjust_scaling_max_from_base_freq(int cpu); static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, void *arg3, @@ -1340,6 +1368,14 @@ static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, vo /* Wait for updated base frequencies */ usleep(2000); + /* Adjusting uncore freq */ + isst_get_uncore_p0_p1_info(id, tdp_level, &ctdp_level); + if (ctdp_level.uncore_pm) + set_uncore_min_max(id, 0, ctdp_level.uncore_pm * 100000); + + if (ctdp_level.uncore_p0) + set_uncore_min_max(id, 1, ctdp_level.uncore_p0 * 100000); + fprintf(stderr, "Option is set to online/offline\n"); ctdp_level.core_cpumask_size = alloc_cpu_set(&ctdp_level.core_cpumask); From d1fcb7493fc36a192b19fb8b046c416d05b6d6fe Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 17 Jan 2023 14:40:34 -0800 Subject: [PATCH 32/80] tools/power/x86/intel-speed-select: v1.14 release This release adds following change: - Minor fixes for coverity static analysis - Don't read cpufreq on offline CPUs - SST turbo-freq enable on auto mode when user disables SMT from kernel command line - Fix uncore frequency display - Set uncore frequency max/min limits on perf level change Signed-off-by: Srinivas Pandruvada Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c index 15bee7f52044..55d0a35df41c 100644 --- a/tools/power/x86/intel-speed-select/isst-config.c +++ b/tools/power/x86/intel-speed-select/isst-config.c @@ -15,7 +15,7 @@ struct process_cmd_struct { int arg; }; -static const char *version_str = "v1.13"; +static const char *version_str = "v1.14"; static const int supported_api_ver = 1; static struct isst_if_platform_info isst_platform_info; From 3e899fec5dfce37701d49d656954a825275bf867 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 26 Jan 2023 20:40:17 +0100 Subject: [PATCH 33/80] platform/x86: dell-ddv: Add support for interface version 3 While trying to solve a bugreport on bugzilla, i learned that some devices (for example the Dell XPS 17 9710) provide a more recent DDV WMI interface (version 3). Since the new interface version just adds an additional method, no code changes are necessary apart from whitelisting the version. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230126194021.381092-2-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-ddv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index 2bb449845d14..9cb6ae42dbdc 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -26,7 +26,8 @@ #define DRIVER_NAME "dell-wmi-ddv" -#define DELL_DDV_SUPPORTED_INTERFACE 2 +#define DELL_DDV_SUPPORTED_VERSION_MIN 2 +#define DELL_DDV_SUPPORTED_VERSION_MAX 3 #define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608" #define DELL_EPPID_LENGTH 20 @@ -49,6 +50,7 @@ enum dell_ddv_method { DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E, DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F, DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10, + DELL_DDV_BATTERY_RAW_ANALYTICS_A_BLOCK = 0x11, /* version 3 */ DELL_DDV_INTERFACE_VERSION = 0x12, @@ -340,7 +342,7 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context) return ret; dev_dbg(&wdev->dev, "WMI interface version: %d\n", version); - if (version != DELL_DDV_SUPPORTED_INTERFACE) + if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) return -ENODEV; data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); From 36d44825faf42903a0b92dd49a9620e2cbdcbe18 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 26 Jan 2023 20:40:18 +0100 Subject: [PATCH 34/80] platform/x86: dell-ddv: Return error if buffer is empty In several cases, the DDV WMI interface can return buffers with a length of zero. Return -ENODATA in such a case for proper error handling. Also replace some -EIO errors with more specialized ones. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230126194021.381092-3-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-ddv.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index 9cb6ae42dbdc..f99c4cb686fd 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -125,21 +126,27 @@ static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_meth if (ret < 0) return ret; - if (obj->package.count != 2) - goto err_free; + if (obj->package.count != 2 || + obj->package.elements[0].type != ACPI_TYPE_INTEGER || + obj->package.elements[1].type != ACPI_TYPE_BUFFER) { + ret = -ENOMSG; - if (obj->package.elements[0].type != ACPI_TYPE_INTEGER) goto err_free; + } buffer_size = obj->package.elements[0].integer.value; - if (obj->package.elements[1].type != ACPI_TYPE_BUFFER) + if (!buffer_size) { + ret = -ENODATA; + goto err_free; + } if (buffer_size > obj->package.elements[1].buffer.length) { dev_warn(&wdev->dev, FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n", buffer_size, obj->package.elements[1].buffer.length); + ret = -EMSGSIZE; goto err_free; } @@ -151,7 +158,7 @@ static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_meth err_free: kfree(obj); - return -EIO; + return ret; } static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method, From 8b52501c408b3ae5f2c5768a74e3db2fa83b4c52 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 26 Jan 2023 20:40:19 +0100 Subject: [PATCH 35/80] platform/x86: dell-ddv: Replace EIO with ENOMSG When the ACPI WMI interface returns a valid ACPI object which has the wrong type, then ENOMSG instead of EIO should be returned, since the WMI method was still successfully evaluated. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230126194021.381092-4-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-ddv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index f99c4cb686fd..58fadb74e86a 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -87,7 +87,7 @@ static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method if (obj->type != type) { kfree(obj); - return -EIO; + return -ENOMSG; } *result = obj; From cf2cc541423f51731c5844dddb0699e301616a86 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 26 Jan 2023 20:40:20 +0100 Subject: [PATCH 36/80] platform/x86: dell-ddv: Add "force" module param Until now, the dell-wmi-ddv driver needs to be manually patched and compiled to test compatibility with unknown DDV WMI interface versions. Add a module param to allow users to force loading even when a unknown interface version was detected. Since this might cause various unwanted side effects, the module param is marked as unsafe. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230126194021.381092-5-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-ddv.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index 58fadb74e86a..9695bf493ea6 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -34,6 +34,10 @@ #define DELL_EPPID_LENGTH 20 #define DELL_EPPID_EXT_LENGTH 23 +static bool force; +module_param_unsafe(force, bool, 0); +MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions"); + enum dell_ddv_method { DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01, DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02, @@ -349,8 +353,13 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context) return ret; dev_dbg(&wdev->dev, "WMI interface version: %d\n", version); - if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) - return -ENODEV; + if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) { + if (!force) + return -ENODEV; + + dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u)\n", + version); + } data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); if (!data) From bdf2ffb6be35d1ae48cb4b7785a9f0427b601017 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Fri, 27 Jan 2023 22:01:49 +0530 Subject: [PATCH 37/80] platform/x86: dell-smo8800: Use min_t() for comparison and assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify code by using min_t helper macro for logical evaluation and value assignment. Use the _t variant of min macro since the variable types are not same. This issue is identified by coccicheck using the minmax.cocci file. Signed-off-by: Deepak R Varma Acked-by: Pali Rohár Link: https://lore.kernel.org/r/Y9P8debIztOZXazW@ubun2204.myguest.virtualbox.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-smo8800.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/dell/dell-smo8800.c b/drivers/platform/x86/dell/dell-smo8800.c index 3385e852104c..8d6b7a83cf24 100644 --- a/drivers/platform/x86/dell/dell-smo8800.c +++ b/drivers/platform/x86/dell/dell-smo8800.c @@ -67,10 +67,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf, retval = 1; - if (data < 255) - byte_data = data; - else - byte_data = 255; + byte_data = min_t(u32, data, 255); if (put_user(byte_data, buf)) retval = -EFAULT; From 391bb17d71d7c93987ccc55fa303127fe6cd6775 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Sat, 28 Jan 2023 01:35:56 +0530 Subject: [PATCH 38/80] platform/x86: think-lmi: Use min_t() for comparison and assignment Simplify code by using min_t helper macro for logical evaluation and value assignment. Use the _t variant of min macro since the variable types are not same. This issue is identified by coccicheck using the minmax.cocci file. Signed-off-by: Deepak R Varma Link: https://lore.kernel.org/r/Y9QupEMPFoZpWIiM@ubun2204.myguest.virtualbox.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/think-lmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index a01a92769c1a..caa862506ed3 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -317,8 +317,8 @@ static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg) return -EIO; } - copy_size = obj->buffer.length < sizeof(struct tlmi_pwdcfg) ? - obj->buffer.length : sizeof(struct tlmi_pwdcfg); + copy_size = min_t(size_t, obj->buffer.length, sizeof(struct tlmi_pwdcfg)); + memcpy(pwdcfg, obj->buffer.pointer, copy_size); kfree(obj); From b6e10ff6c23deb7f01d342875f7a69bae067c3c8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 27 Jan 2023 21:37:25 +0100 Subject: [PATCH 39/80] media: v4l2-core: Make the v4l2-core code enable/disable the privacy LED if present Make v4l2_async_register_subdev_sensor() try to get a privacy LED associated with the sensor and extend the call_s_stream() wrapper to enable/disable the privacy LED if found. This makes the core handle privacy LED control, rather then having to duplicate this code in all the sensor drivers. Suggested-by: Sakari Ailus Acked-by: Linus Walleij Signed-off-by: Hans de Goede Acked-by: Sakari Ailus Link: https://lore.kernel.org/r/20230127203729.10205-2-hdegoede@redhat.com --- drivers/media/v4l2-core/v4l2-async.c | 4 ++ drivers/media/v4l2-core/v4l2-fwnode.c | 7 ++++ drivers/media/v4l2-core/v4l2-subdev-priv.h | 14 +++++++ drivers/media/v4l2-core/v4l2-subdev.c | 46 ++++++++++++++++++++++ include/media/v4l2-subdev.h | 4 ++ 5 files changed, 75 insertions(+) create mode 100644 drivers/media/v4l2-core/v4l2-subdev-priv.h diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 2f1b718a9189..d7e9ffc7aa23 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -24,6 +24,8 @@ #include #include +#include "v4l2-subdev-priv.h" + static int v4l2_async_nf_call_bound(struct v4l2_async_notifier *n, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -822,6 +824,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) if (!sd->async_list.next) return; + v4l2_subdev_put_privacy_led(sd); + mutex_lock(&list_lock); __v4l2_async_nf_unregister(sd->subdev_notifier); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 3d9533c1b202..049c2f2001ea 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -28,6 +28,8 @@ #include #include +#include "v4l2-subdev-priv.h" + static const struct v4l2_fwnode_bus_conv { enum v4l2_fwnode_bus_type fwnode_bus_type; enum v4l2_mbus_type mbus_type; @@ -1302,6 +1304,10 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) v4l2_async_nf_init(notifier); + ret = v4l2_subdev_get_privacy_led(sd); + if (ret < 0) + goto out_cleanup; + ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier); if (ret < 0) goto out_cleanup; @@ -1322,6 +1328,7 @@ out_unregister: v4l2_async_nf_unregister(notifier); out_cleanup: + v4l2_subdev_put_privacy_led(sd); v4l2_async_nf_cleanup(notifier); kfree(notifier); diff --git a/drivers/media/v4l2-core/v4l2-subdev-priv.h b/drivers/media/v4l2-core/v4l2-subdev-priv.h new file mode 100644 index 000000000000..52391d6d8ab7 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-subdev-priv.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * V4L2 sub-device pivate header. + * + * Copyright (C) 2023 Hans de Goede + */ + +#ifndef _V4L2_SUBDEV_PRIV_H_ +#define _V4L2_SUBDEV_PRIV_H_ + +int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd); +void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd); + +#endif diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 4988a25bd8f4..6630fb30bc7d 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -23,6 +24,8 @@ #include #include +#include "v4l2-subdev-priv.h" + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) { @@ -322,6 +325,15 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable) { int ret; +#if IS_REACHABLE(CONFIG_LEDS_CLASS) + if (!IS_ERR_OR_NULL(sd->privacy_led)) { + if (enable) + led_set_brightness(sd->privacy_led, + sd->privacy_led->max_brightness); + else + led_set_brightness(sd->privacy_led, 0); + } +#endif ret = sd->ops->video->s_stream(sd, enable); if (!enable && ret < 0) { @@ -1090,6 +1102,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) sd->grp_id = 0; sd->dev_priv = NULL; sd->host_priv = NULL; + sd->privacy_led = NULL; #if defined(CONFIG_MEDIA_CONTROLLER) sd->entity.name = sd->name; sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV; @@ -1105,3 +1118,36 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd, v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev); } EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); + +int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd) +{ +#if IS_REACHABLE(CONFIG_LEDS_CLASS) + sd->privacy_led = led_get(sd->dev, "privacy-led"); + if (IS_ERR(sd->privacy_led) && PTR_ERR(sd->privacy_led) != -ENOENT) + return dev_err_probe(sd->dev, PTR_ERR(sd->privacy_led), + "getting privacy LED\n"); + + if (!IS_ERR_OR_NULL(sd->privacy_led)) { + mutex_lock(&sd->privacy_led->led_access); + led_sysfs_disable(sd->privacy_led); + led_trigger_remove(sd->privacy_led); + led_set_brightness(sd->privacy_led, 0); + mutex_unlock(&sd->privacy_led->led_access); + } +#endif + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_get_privacy_led); + +void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd) +{ +#if IS_REACHABLE(CONFIG_LEDS_CLASS) + if (!IS_ERR_OR_NULL(sd->privacy_led)) { + mutex_lock(&sd->privacy_led->led_access); + led_sysfs_enable(sd->privacy_led); + mutex_unlock(&sd->privacy_led->led_access); + led_put(sd->privacy_led); + } +#endif +} +EXPORT_SYMBOL_GPL(v4l2_subdev_put_privacy_led); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index b15fa9930f30..f3fe9b6e26d4 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -38,6 +38,7 @@ struct v4l2_subdev; struct v4l2_subdev_fh; struct tuner_setup; struct v4l2_mbus_frame_desc; +struct led_classdev; /** * struct v4l2_decode_vbi_line - used to decode_vbi_line @@ -941,6 +942,7 @@ struct v4l2_subdev_platform_data { * @state_lock: A pointer to a lock used for all the subdev's states, set by the * driver. This is optional. If NULL, each state instance will get * a lock of its own. + * @privacy_led: Optional pointer to a LED classdev for the privacy LED for sensors. * @active_state: Active state for the subdev (NULL for subdevs tracking the * state internally). Initialized by calling * v4l2_subdev_init_finalize(). @@ -982,6 +984,8 @@ struct v4l2_subdev { * appropriate functions. */ + struct led_classdev *privacy_led; + /* * TODO: active_state should most likely be changed from a pointer to an * embedded field. For the time being it's kept as a pointer to more From 9b1785a2e2af522c2a64034a8716b7d47375ffec Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 27 Jan 2023 21:37:26 +0100 Subject: [PATCH 40/80] platform/x86: int3472/discrete: Refactor GPIO to sensor mapping Add a helper function to map the type returned by the _DSM method to a function name + the default polarity for that function. And fold the INT3472_GPIO_TYPE_RESET and INT3472_GPIO_TYPE_POWERDOWN cases into a single generic case. This is a preparation patch for further GPIO mapping changes. Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20230127203729.10205-3-hdegoede@redhat.com --- drivers/platform/x86/intel/int3472/discrete.c | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index c42c3faa2c32..708d51f9b41d 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -188,6 +188,36 @@ static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472, return 0; } +static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity) +{ + switch (type) { + case INT3472_GPIO_TYPE_RESET: + *func = "reset"; + *polarity = GPIO_ACTIVE_LOW; + break; + case INT3472_GPIO_TYPE_POWERDOWN: + *func = "powerdown"; + *polarity = GPIO_ACTIVE_LOW; + break; + case INT3472_GPIO_TYPE_CLK_ENABLE: + *func = "clk-enable"; + *polarity = GPIO_ACTIVE_HIGH; + break; + case INT3472_GPIO_TYPE_PRIVACY_LED: + *func = "privacy-led"; + *polarity = GPIO_ACTIVE_HIGH; + break; + case INT3472_GPIO_TYPE_POWER_ENABLE: + *func = "power-enable"; + *polarity = GPIO_ACTIVE_HIGH; + break; + default: + *func = "unknown"; + *polarity = GPIO_ACTIVE_HIGH; + break; + } +} + /** * skl_int3472_handle_gpio_resources: Map PMIC resources to consuming sensor * @ares: A pointer to a &struct acpi_resource @@ -227,6 +257,8 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, struct acpi_resource_gpio *agpio; union acpi_object *obj; const char *err_msg; + const char *func; + u32 polarity; int ret; u8 type; @@ -250,19 +282,14 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, type = obj->integer.value & 0xff; + int3472_get_func_and_polarity(type, &func, &polarity); + switch (type) { case INT3472_GPIO_TYPE_RESET: - ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset", - GPIO_ACTIVE_LOW); - if (ret) - err_msg = "Failed to map reset pin to sensor\n"; - - break; case INT3472_GPIO_TYPE_POWERDOWN: - ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown", - GPIO_ACTIVE_LOW); + ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, polarity); if (ret) - err_msg = "Failed to map powerdown pin to sensor\n"; + err_msg = "Failed to map GPIO pin to sensor\n"; break; case INT3472_GPIO_TYPE_CLK_ENABLE: From 5ae20a8050d08a51fef9769cd53237551f259dbe Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 27 Jan 2023 21:37:27 +0100 Subject: [PATCH 41/80] platform/x86: int3472/discrete: Create a LED class device for the privacy LED On some systems, e.g. the Lenovo ThinkPad X1 Yoga gen 7 and the ThinkPad X1 Nano gen 2 there is no clock-enable pin, triggering the: "No clk GPIO. The privacy LED won't work" warning and causing the privacy LED to not work. Fix this by modeling the privacy LED as a LED class device rather then integrating it with the registered clock. Note this relies on media subsys changes to actually turn the LED on/off when the sensor's v4l2_subdev's s_stream() operand gets called. Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20230127203729.10205-4-hdegoede@redhat.com --- drivers/platform/x86/intel/int3472/Makefile | 2 +- .../x86/intel/int3472/clk_and_regulator.c | 3 - drivers/platform/x86/intel/int3472/common.h | 15 +++- drivers/platform/x86/intel/int3472/discrete.c | 58 ++++---------- drivers/platform/x86/intel/int3472/led.c | 75 +++++++++++++++++++ 5 files changed, 106 insertions(+), 47 deletions(-) create mode 100644 drivers/platform/x86/intel/int3472/led.c diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile index cfec7784c5c9..9f16cb514397 100644 --- a/drivers/platform/x86/intel/int3472/Makefile +++ b/drivers/platform/x86/intel/int3472/Makefile @@ -1,4 +1,4 @@ obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \ intel_skl_int3472_tps68470.o -intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o common.o +intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c index 74dc2cff799e..e3b597d93388 100644 --- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c +++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c @@ -23,8 +23,6 @@ static int skl_int3472_clk_prepare(struct clk_hw *hw) struct int3472_gpio_clock *clk = to_int3472_clk(hw); gpiod_set_value_cansleep(clk->ena_gpio, 1); - gpiod_set_value_cansleep(clk->led_gpio, 1); - return 0; } @@ -33,7 +31,6 @@ static void skl_int3472_clk_unprepare(struct clk_hw *hw) struct int3472_gpio_clock *clk = to_int3472_clk(hw); gpiod_set_value_cansleep(clk->ena_gpio, 0); - gpiod_set_value_cansleep(clk->led_gpio, 0); } static int skl_int3472_clk_enable(struct clk_hw *hw) diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h index 53270d19c73a..82dc37e08882 100644 --- a/drivers/platform/x86/intel/int3472/common.h +++ b/drivers/platform/x86/intel/int3472/common.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -28,6 +29,8 @@ #define GPIO_REGULATOR_NAME_LENGTH 21 #define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9 +#define INT3472_LED_MAX_NAME_LEN 32 + #define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86 #define INT3472_REGULATOR(_name, _supply, _ops) \ @@ -96,10 +99,16 @@ struct int3472_discrete_device { struct clk_hw clk_hw; struct clk_lookup *cl; struct gpio_desc *ena_gpio; - struct gpio_desc *led_gpio; u32 frequency; } clock; + struct int3472_pled { + struct led_classdev classdev; + struct led_lookup_data lookup; + char name[INT3472_LED_MAX_NAME_LEN]; + struct gpio_desc *gpio; + } pled; + unsigned int ngpios; /* how many GPIOs have we seen */ unsigned int n_sensor_gpios; /* how many have we mapped to sensor */ struct gpiod_lookup_table gpios; @@ -119,4 +128,8 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, struct acpi_resource_gpio *agpio); void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472); +int skl_int3472_register_pled(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio, u32 polarity); +void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472); + #endif diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 708d51f9b41d..38b1372e0745 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -155,37 +155,21 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 } static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio, u8 type) + struct acpi_resource_gpio *agpio) { char *path = agpio->resource_source.string_ptr; u16 pin = agpio->pin_table[0]; struct gpio_desc *gpio; - switch (type) { - case INT3472_GPIO_TYPE_CLK_ENABLE: - gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable"); - if (IS_ERR(gpio)) - return (PTR_ERR(gpio)); + gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable"); + if (IS_ERR(gpio)) + return (PTR_ERR(gpio)); - int3472->clock.ena_gpio = gpio; - /* Ensure the pin is in output mode and non-active state */ - gpiod_direction_output(int3472->clock.ena_gpio, 0); - break; - case INT3472_GPIO_TYPE_PRIVACY_LED: - gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led"); - if (IS_ERR(gpio)) - return (PTR_ERR(gpio)); + int3472->clock.ena_gpio = gpio; + /* Ensure the pin is in output mode and non-active state */ + gpiod_direction_output(int3472->clock.ena_gpio, 0); - int3472->clock.led_gpio = gpio; - /* Ensure the pin is in output mode and non-active state */ - gpiod_direction_output(int3472->clock.led_gpio, 0); - break; - default: - dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type); - break; - } - - return 0; + return skl_int3472_register_clock(int3472); } static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity) @@ -293,11 +277,16 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_CLK_ENABLE: - case INT3472_GPIO_TYPE_PRIVACY_LED: - ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type); + ret = skl_int3472_map_gpio_to_clk(int3472, agpio); if (ret) err_msg = "Failed to map GPIO to clock\n"; + break; + case INT3472_GPIO_TYPE_PRIVACY_LED: + ret = skl_int3472_register_pled(int3472, agpio, polarity); + if (ret) + err_msg = "Failed to register LED\n"; + break; case INT3472_GPIO_TYPE_POWER_ENABLE: ret = skl_int3472_register_regulator(int3472, agpio); @@ -341,21 +330,6 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472) acpi_dev_free_resource_list(&resource_list); - /* - * If we find no clock enable GPIO pin then the privacy LED won't work. - * We've never seen that situation, but it's possible. Warn the user so - * it's clear what's happened. - */ - if (int3472->clock.ena_gpio) { - ret = skl_int3472_register_clock(int3472); - if (ret) - return ret; - } else { - if (int3472->clock.led_gpio) - dev_warn(int3472->dev, - "No clk GPIO. The privacy LED won't work\n"); - } - int3472->gpios.dev_id = int3472->sensor_name; gpiod_add_lookup_table(&int3472->gpios); @@ -372,8 +346,8 @@ static int skl_int3472_discrete_remove(struct platform_device *pdev) skl_int3472_unregister_clock(int3472); gpiod_put(int3472->clock.ena_gpio); - gpiod_put(int3472->clock.led_gpio); + skl_int3472_unregister_pled(int3472); skl_int3472_unregister_regulator(int3472); return 0; diff --git a/drivers/platform/x86/intel/int3472/led.c b/drivers/platform/x86/intel/int3472/led.c new file mode 100644 index 000000000000..bca1ce7d0d0c --- /dev/null +++ b/drivers/platform/x86/intel/int3472/led.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Author: Hans de Goede */ + +#include +#include +#include +#include "common.h" + +static int int3472_pled_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct int3472_discrete_device *int3472 = + container_of(led_cdev, struct int3472_discrete_device, pled.classdev); + + gpiod_set_value_cansleep(int3472->pled.gpio, brightness); + return 0; +} + +int skl_int3472_register_pled(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio, u32 polarity) +{ + char *p, *path = agpio->resource_source.string_ptr; + int ret; + + if (int3472->pled.classdev.dev) + return -EBUSY; + + int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0], + "int3472,privacy-led"); + if (IS_ERR(int3472->pled.gpio)) + return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio), + "getting privacy LED GPIO\n"); + + if (polarity == GPIO_ACTIVE_LOW) + gpiod_toggle_active_low(int3472->pled.gpio); + + /* Ensure the pin is in output mode and non-active state */ + gpiod_direction_output(int3472->pled.gpio, 0); + + /* Generate the name, replacing the ':' in the ACPI devname with '_' */ + snprintf(int3472->pled.name, sizeof(int3472->pled.name), + "%s::privacy_led", acpi_dev_name(int3472->sensor)); + p = strchr(int3472->pled.name, ':'); + if (p) + *p = '_'; + + int3472->pled.classdev.name = int3472->pled.name; + int3472->pled.classdev.max_brightness = 1; + int3472->pled.classdev.brightness_set_blocking = int3472_pled_set; + + ret = led_classdev_register(int3472->dev, &int3472->pled.classdev); + if (ret) + goto err_free_gpio; + + int3472->pled.lookup.provider = int3472->pled.name; + int3472->pled.lookup.dev_id = int3472->sensor_name; + int3472->pled.lookup.con_id = "privacy-led"; + led_add_lookup(&int3472->pled.lookup); + + return 0; + +err_free_gpio: + gpiod_put(int3472->pled.gpio); + return ret; +} + +void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472) +{ + if (IS_ERR_OR_NULL(int3472->pled.classdev.dev)) + return; + + led_remove_lookup(&int3472->pled.lookup); + led_classdev_unregister(&int3472->pled.classdev); + gpiod_put(int3472->pled.gpio); +} From 8cf0e541c1fd76aa9ff1ac5e77ac2ea64220eca6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 27 Jan 2023 21:37:28 +0100 Subject: [PATCH 42/80] platform/x86: int3472/discrete: Move GPIO request to skl_int3472_register_clock() Move the requesting of the clk-enable GPIO to skl_int3472_register_clock() (and move the gpiod_put to unregister). This mirrors the GPIO handling in skl_int3472_register_regulator() and allows removing skl_int3472_map_gpio_to_clk() from discrete.c. Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20230127203729.10205-5-hdegoede@redhat.com --- .../x86/intel/int3472/clk_and_regulator.c | 28 +++++++++++++++-- drivers/platform/x86/intel/int3472/common.h | 3 +- drivers/platform/x86/intel/int3472/discrete.c | 30 ++----------------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c index e3b597d93388..626e5e86f4e0 100644 --- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c +++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c @@ -86,18 +86,34 @@ static const struct clk_ops skl_int3472_clock_ops = { .recalc_rate = skl_int3472_clk_recalc_rate, }; -int skl_int3472_register_clock(struct int3472_discrete_device *int3472) +int skl_int3472_register_clock(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio) { + char *path = agpio->resource_source.string_ptr; struct clk_init_data init = { .ops = &skl_int3472_clock_ops, .flags = CLK_GET_RATE_NOCACHE, }; int ret; + if (int3472->clock.cl) + return -EBUSY; + + int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0], + "int3472,clk-enable"); + if (IS_ERR(int3472->clock.ena_gpio)) + return dev_err_probe(int3472->dev, PTR_ERR(int3472->clock.ena_gpio), + "getting clk-enable GPIO\n"); + + /* Ensure the pin is in output mode and non-active state */ + gpiod_direction_output(int3472->clock.ena_gpio, 0); + init.name = kasprintf(GFP_KERNEL, "%s-clk", acpi_dev_name(int3472->adev)); - if (!init.name) - return -ENOMEM; + if (!init.name) { + ret = -ENOMEM; + goto out_put_gpio; + } int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472); @@ -123,14 +139,20 @@ err_unregister_clk: clk_unregister(int3472->clock.clk); out_free_init_name: kfree(init.name); +out_put_gpio: + gpiod_put(int3472->clock.ena_gpio); return ret; } void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472) { + if (!int3472->clock.cl) + return; + clkdev_drop(int3472->clock.cl); clk_unregister(int3472->clock.clk); + gpiod_put(int3472->clock.ena_gpio); } int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h index 82dc37e08882..0d4fa7d00b5f 100644 --- a/drivers/platform/x86/intel/int3472/common.h +++ b/drivers/platform/x86/intel/int3472/common.h @@ -121,7 +121,8 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev, struct acpi_device **sensor_adev_ret, const char **name_ret); -int skl_int3472_register_clock(struct int3472_discrete_device *int3472); +int skl_int3472_register_clock(struct int3472_discrete_device *int3472, + struct acpi_resource_gpio *agpio); void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472); int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 38b1372e0745..b7752c2b798d 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -2,8 +2,6 @@ /* Author: Dan Scally */ #include -#include -#include #include #include #include @@ -154,24 +152,6 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347 return 0; } -static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio) -{ - char *path = agpio->resource_source.string_ptr; - u16 pin = agpio->pin_table[0]; - struct gpio_desc *gpio; - - gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable"); - if (IS_ERR(gpio)) - return (PTR_ERR(gpio)); - - int3472->clock.ena_gpio = gpio; - /* Ensure the pin is in output mode and non-active state */ - gpiod_direction_output(int3472->clock.ena_gpio, 0); - - return skl_int3472_register_clock(int3472); -} - static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity) { switch (type) { @@ -277,9 +257,9 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_CLK_ENABLE: - ret = skl_int3472_map_gpio_to_clk(int3472, agpio); + ret = skl_int3472_register_clock(int3472, agpio); if (ret) - err_msg = "Failed to map GPIO to clock\n"; + err_msg = "Failed to register clock\n"; break; case INT3472_GPIO_TYPE_PRIVACY_LED: @@ -342,11 +322,7 @@ static int skl_int3472_discrete_remove(struct platform_device *pdev) gpiod_remove_lookup_table(&int3472->gpios); - if (int3472->clock.cl) - skl_int3472_unregister_clock(int3472); - - gpiod_put(int3472->clock.ena_gpio); - + skl_int3472_unregister_clock(int3472); skl_int3472_unregister_pled(int3472); skl_int3472_unregister_regulator(int3472); From 7a88de319c8ef9a971e8b1c4004512e39b7680f2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 27 Jan 2023 21:37:29 +0100 Subject: [PATCH 43/80] platform/x86: int3472/discrete: Get the polarity from the _DSM entry According to: https://github.com/intel/ipu6-drivers/blob/master/patch/int3472-support-independent-clock-and-LED-gpios-5.17%2B.patch Bits 31-24 of the _DSM pin entry integer value codes the active-value, that is the actual physical signal (0 or 1) which needs to be output on the pin to turn the sensor chip on (to make it active). So if bits 31-24 are 0 for a reset pin, then the actual value of the reset pin needs to be 0 to take the chip out of reset. IOW in this case the reset signal is active-high rather then the default active-low. And if bits 31-24 are 0 for a clk-en pin then the actual value of the clk pin needs to be 0 to enable the clk. So in this case the clk-en signal is active-low rather then the default active-high. IOW if bits 31-24 are 0 for a pin, then the default polarity of the pin is inverted. Add a check for this and also propagate this new polarity to the clock registration. Signed-off-by: Hans de Goede Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20230127203729.10205-6-hdegoede@redhat.com --- .../platform/x86/intel/int3472/clk_and_regulator.c | 5 ++++- drivers/platform/x86/intel/int3472/common.h | 2 +- drivers/platform/x86/intel/int3472/discrete.c | 13 +++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c index 626e5e86f4e0..1086c3d83494 100644 --- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c +++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c @@ -87,7 +87,7 @@ static const struct clk_ops skl_int3472_clock_ops = { }; int skl_int3472_register_clock(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio) + struct acpi_resource_gpio *agpio, u32 polarity) { char *path = agpio->resource_source.string_ptr; struct clk_init_data init = { @@ -105,6 +105,9 @@ int skl_int3472_register_clock(struct int3472_discrete_device *int3472, return dev_err_probe(int3472->dev, PTR_ERR(int3472->clock.ena_gpio), "getting clk-enable GPIO\n"); + if (polarity == GPIO_ACTIVE_LOW) + gpiod_toggle_active_low(int3472->clock.ena_gpio); + /* Ensure the pin is in output mode and non-active state */ gpiod_direction_output(int3472->clock.ena_gpio, 0); diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h index 0d4fa7d00b5f..61688e450ce5 100644 --- a/drivers/platform/x86/intel/int3472/common.h +++ b/drivers/platform/x86/intel/int3472/common.h @@ -122,7 +122,7 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev, const char **name_ret); int skl_int3472_register_clock(struct int3472_discrete_device *int3472, - struct acpi_resource_gpio *agpio); + struct acpi_resource_gpio *agpio, u32 polarity); void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472); int skl_int3472_register_regulator(struct int3472_discrete_device *int3472, diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index b7752c2b798d..96963e30ab6c 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -220,11 +220,11 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, struct int3472_discrete_device *int3472 = data; struct acpi_resource_gpio *agpio; union acpi_object *obj; + u8 active_value, type; const char *err_msg; const char *func; u32 polarity; int ret; - u8 type; if (!acpi_gpio_get_io_resource(ares, &agpio)) return 1; @@ -248,6 +248,15 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, int3472_get_func_and_polarity(type, &func, &polarity); + /* If bits 31-24 of the _DSM entry are all 0 then the signal is inverted */ + active_value = obj->integer.value >> 24; + if (!active_value) + polarity ^= GPIO_ACTIVE_LOW; + + dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func, + agpio->resource_source.string_ptr, agpio->pin_table[0], + (polarity == GPIO_ACTIVE_HIGH) ? "high" : "low"); + switch (type) { case INT3472_GPIO_TYPE_RESET: case INT3472_GPIO_TYPE_POWERDOWN: @@ -257,7 +266,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares, break; case INT3472_GPIO_TYPE_CLK_ENABLE: - ret = skl_int3472_register_clock(int3472, agpio); + ret = skl_int3472_register_clock(int3472, agpio, polarity); if (ret) err_msg = "Failed to register clock\n"; From c00493dc467f3d57169f3b913e2c1ecb3a808ad1 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:32 -0800 Subject: [PATCH 44/80] platform/x86/intel/vsec: Add TPMI ID Add TPMI (Topology Aware Register and PM Capsule Interface) VSEC ID to create an aux device. This will allow TPMI driver to enumerate on this aux device. Signed-off-by: Srinivas Pandruvada Acked-by: David E. Box Link: https://lore.kernel.org/r/20230202010738.2186174-2-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/vsec.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index bb81b8b1f7e9..a82b2a5ed99d 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -64,6 +64,7 @@ enum intel_vsec_id { VSEC_ID_WATCHER = 3, VSEC_ID_CRASHLOG = 4, VSEC_ID_SDSI = 65, + VSEC_ID_TPMI = 66, }; static enum intel_vsec_id intel_vsec_allow_list[] = { @@ -71,6 +72,7 @@ static enum intel_vsec_id intel_vsec_allow_list[] = { VSEC_ID_WATCHER, VSEC_ID_CRASHLOG, VSEC_ID_SDSI, + VSEC_ID_TPMI, }; static const char *intel_vsec_name(enum intel_vsec_id id) @@ -88,6 +90,9 @@ static const char *intel_vsec_name(enum intel_vsec_id id) case VSEC_ID_SDSI: return "sdsi"; + case VSEC_ID_TPMI: + return "tpmi"; + default: return NULL; } From 251a41116aebdbb7ff00fbc635b1c1a0f08119e6 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:33 -0800 Subject: [PATCH 45/80] platform/x86/intel/vsec: Enhance and Export intel_vsec_add_aux() Remove static for intel_vsec_add_aux() and export this interface so that it can be used by other vsec related modules. This driver creates aux devices by parsing PCI-VSEC, which allows individual drivers to load on those devices. Those driver may further create more devices on aux bus by parsing the PCI MMIO region. For example, TPMI (Topology Aware Register and PM Capsule Interface) creates device nodes for power management features by parsing MMIO region. When TPMI driver creates devices, it can reuse existing function intel_vsec_add_aux() to create aux devices with TPMI device as the parent. Signed-off-by: Srinivas Pandruvada Acked-by: David E. Box Link: https://lore.kernel.org/r/20230202010738.2186174-3-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/vsec.c | 16 +++++++++++----- drivers/platform/x86/intel/vsec.h | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index a82b2a5ed99d..b936fc5776d7 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -138,8 +138,9 @@ static void intel_vsec_dev_release(struct device *dev) kfree(intel_vsec_dev); } -static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *intel_vsec_dev, - const char *name) +int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, + struct intel_vsec_device *intel_vsec_dev, + const char *name) { struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; int ret, id; @@ -150,9 +151,12 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in return ret; } + if (!parent) + parent = &pdev->dev; + auxdev->id = ret; auxdev->name = name; - auxdev->dev.parent = &pdev->dev; + auxdev->dev.parent = parent; auxdev->dev.release = intel_vsec_dev_release; ret = auxiliary_device_init(auxdev); @@ -169,7 +173,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in return ret; } - ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, + ret = devm_add_action_or_reset(parent, intel_vsec_remove_aux, auxdev); if (ret < 0) return ret; @@ -182,6 +186,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in return 0; } +EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC); static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, struct intel_vsec_platform_info *info) @@ -239,7 +244,8 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he else intel_vsec_dev->ida = &intel_vsec_ida; - return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id)); + return intel_vsec_add_aux(pdev, NULL, intel_vsec_dev, + intel_vsec_name(header->id)); } static bool intel_vsec_walk_header(struct pci_dev *pdev, diff --git a/drivers/platform/x86/intel/vsec.h b/drivers/platform/x86/intel/vsec.h index 3deeb05cf394..d02c340fd458 100644 --- a/drivers/platform/x86/intel/vsec.h +++ b/drivers/platform/x86/intel/vsec.h @@ -40,6 +40,10 @@ struct intel_vsec_device { int num_resources; }; +int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, + struct intel_vsec_device *intel_vsec_dev, + const char *name); + static inline struct intel_vsec_device *dev_to_ivdev(struct device *dev) { return container_of(dev, struct intel_vsec_device, auxdev.dev); From 4ec5d0231d2e4aebe41152d57c6b4f1e7ea14f08 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:34 -0800 Subject: [PATCH 46/80] platform/x86/intel/vsec: Support private data Add fields to struct intel_vsec_device, so that core module (which creates aux bus devices) can pass private data to the client drivers. For example there is one vsec device instance per CPU package. On a multi package system, this private data can be used to pass the package ID. This package id can be used by client drivers to change power settings for a specific CPU package by targeting MMIO space of the correct PCI device. Signed-off-by: Srinivas Pandruvada Acked-by: David E. Box Link: https://lore.kernel.org/r/20230202010738.2186174-4-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/vsec.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/intel/vsec.h b/drivers/platform/x86/intel/vsec.h index d02c340fd458..ae8fe92c5595 100644 --- a/drivers/platform/x86/intel/vsec.h +++ b/drivers/platform/x86/intel/vsec.h @@ -38,6 +38,8 @@ struct intel_vsec_device { struct ida *ida; struct intel_vsec_platform_info *info; int num_resources; + void *priv_data; + size_t priv_data_size; }; int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, From 47731fd2865fcbcd0b9cdbe90fcd6583c9559631 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:35 -0800 Subject: [PATCH 47/80] platform/x86/intel: Intel TPMI enumeration driver The TPMI (Topology Aware Register and PM Capsule Interface) provides a flexible, extendable and PCIe enumerable MMIO interface for PM features. For example Intel RAPL (Running Average Power Limit) provides a MMIO interface using TPMI. This has advantage over traditional MSR (Model Specific Register) interface, where a thread needs to be scheduled on the target CPU to read or write. Also the RAPL features vary between CPU models, and hence lot of model specific code. Here TPMI provides an architectural interface by providing hierarchical tables and fields, which will not need any model specific implementation. The TPMI interface uses a PCI VSEC structure to expose the location of MMIO region. This VSEC structure is present in the PCI configuration space of the Intel Out-of-Band (OOB) device, which is handled by the Intel VSEC driver. The Intel VSEC driver parses VSEC structures present in the PCI configuration space of the given device and creates an auxiliary device object for each of them. In particular, it creates an auxiliary device object representing TPMI that can be bound by an auxiliary driver. Introduce a TPMI driver that will bind to the TPMI auxiliary device object created by the Intel VSEC driver. The TPMI specification defines a PFS (PM Feature Structure) table. This table is present in the TPMI MMIO region. The starting address of PFS is derived from the tBIR (Bar Indicator Register) and "Address" field from the VSEC header. Each TPMI PM feature has one entry in the PFS with a unique TPMI ID and its access details. The TPMI driver creates device nodes for the supported PM features. The names of the devices created by the TPMI driver start with the "intel_vsec.tpmi-" prefix which is followed by a specific name of the given PM feature (for example, "intel_vsec.tpmi-rapl.0"). The device nodes are create by using interface "intel_vsec_add_aux()" provided by the Intel VSEC driver. Signed-off-by: Srinivas Pandruvada Reviewed-by: Pierre-Louis Bossart Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230202010738.2186174-5-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/Kconfig | 13 ++ drivers/platform/x86/intel/Makefile | 4 + drivers/platform/x86/intel/tpmi.c | 321 ++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 drivers/platform/x86/intel/tpmi.c diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index d5a33473e838..bbbd9e54e9ee 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -182,6 +182,19 @@ config INTEL_SMARTCONNECT This driver checks to determine whether the device has Intel Smart Connect enabled, and if so disables it. +config INTEL_TPMI + tristate "Intel Topology Aware Register and PM Capsule Interface (TPMI)" + depends on INTEL_VSEC + depends on X86_64 + help + The Intel Topology Aware Register and PM Capsule Interface (TPMI), + provides enumerable MMIO interface for power management features. + This driver creates devices, so that other PM feature driver can + be loaded for PM specific feature operation. + + To compile this driver as a module, choose M here: the module will + be called intel_vsec_tpmi. + config INTEL_TURBO_MAX_3 bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" depends on X86_64 && SCHED_MC_PRIO diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 717933dd0cfd..411df4040427 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -47,6 +47,10 @@ obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o intel_punit_ipc-y := punit_ipc.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o +# TPMI drivers +intel_vsec_tpmi-y := tpmi.o +obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o + # Intel Uncore drivers intel-rst-y := rst.o obj-$(CONFIG_INTEL_RST) += intel-rst.o diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c new file mode 100644 index 000000000000..1b87b46ba8a9 --- /dev/null +++ b/drivers/platform/x86/intel/tpmi.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * intel-tpmi : Driver to enumerate TPMI features and create devices + * + * Copyright (c) 2023, Intel Corporation. + * All Rights Reserved. + * + * The TPMI (Topology Aware Register and PM Capsule Interface) provides a + * flexible, extendable and PCIe enumerable MMIO interface for PM features. + * + * For example Intel RAPL (Running Average Power Limit) provides a MMIO + * interface using TPMI. This has advantage over traditional MSR + * (Model Specific Register) interface, where a thread needs to be scheduled + * on the target CPU to read or write. Also the RAPL features vary between + * CPU models, and hence lot of model specific code. Here TPMI provides an + * architectural interface by providing hierarchical tables and fields, + * which will not need any model specific implementation. + * + * The TPMI interface uses a PCI VSEC structure to expose the location of + * MMIO region. + * + * This VSEC structure is present in the PCI configuration space of the + * Intel Out-of-Band (OOB) device, which is handled by the Intel VSEC + * driver. The Intel VSEC driver parses VSEC structures present in the PCI + * configuration space of the given device and creates an auxiliary device + * object for each of them. In particular, it creates an auxiliary device + * object representing TPMI that can be bound by an auxiliary driver. + * + * This TPMI driver will bind to the TPMI auxiliary device object created + * by the Intel VSEC driver. + * + * The TPMI specification defines a PFS (PM Feature Structure) table. + * This table is present in the TPMI MMIO region. The starting address + * of PFS is derived from the tBIR (Bar Indicator Register) and "Address" + * field from the VSEC header. + * + * Each TPMI PM feature has one entry in the PFS with a unique TPMI + * ID and its access details. The TPMI driver creates device nodes + * for the supported PM features. + * + * The names of the devices created by the TPMI driver start with the + * "intel_vsec.tpmi-" prefix which is followed by a specific name of the + * given PM feature (for example, "intel_vsec.tpmi-rapl.0"). + * + * The device nodes are create by using interface "intel_vsec_add_aux()" + * provided by the Intel VSEC driver. + */ + +#include +#include +#include +#include + +#include "vsec.h" + +/** + * struct intel_tpmi_pfs_entry - TPMI PM Feature Structure (PFS) entry + * @tpmi_id: TPMI feature identifier (what the feature is and its data format). + * @num_entries: Number of feature interface instances present in the PFS. + * This represents the maximum number of Power domains in the SoC. + * @entry_size: Interface instance entry size in 32-bit words. + * @cap_offset: Offset from the PM_Features base address to the base of the PM VSEC + * register bank in KB. + * @attribute: Feature attribute: 0=BIOS. 1=OS. 2-3=Reserved. + * @reserved: Bits for use in the future. + * + * Represents one TPMI feature entry data in the PFS retrieved as is + * from the hardware. + */ +struct intel_tpmi_pfs_entry { + u64 tpmi_id:8; + u64 num_entries:8; + u64 entry_size:16; + u64 cap_offset:16; + u64 attribute:2; + u64 reserved:14; +} __packed; + +/** + * struct intel_tpmi_pm_feature - TPMI PM Feature information for a TPMI ID + * @pfs_header: PFS header retireved from the hardware. + * @vsec_offset: Starting MMIO address for this feature in bytes. Essentially + * this offset = "Address" from VSEC header + PFS Capability + * offset for this feature entry. + * + * Represents TPMI instance information for one TPMI ID. + */ +struct intel_tpmi_pm_feature { + struct intel_tpmi_pfs_entry pfs_header; + unsigned int vsec_offset; +}; + +/** + * struct intel_tpmi_info - TPMI information for all IDs in an instance + * @tpmi_features: Pointer to a list of TPMI feature instances + * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device + * @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features + * @pfs_start: Start of PFS offset for the TPMI instances in this device + * + * Stores the information for all TPMI devices enumerated from a single PCI device. + */ +struct intel_tpmi_info { + struct intel_tpmi_pm_feature *tpmi_features; + struct intel_vsec_device *vsec_dev; + int feature_count; + u64 pfs_start; +}; + +/* + * List of supported TMPI IDs. + * Some TMPI IDs are not used by Linux, so the numbers are not consecutive. + */ +enum intel_tpmi_id { + TPMI_ID_RAPL = 0, /* Running Average Power Limit */ + TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */ + TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */ + TPMI_ID_SST = 5, /* Speed Select Technology */ +}; + +/* Used during auxbus device creation */ +static DEFINE_IDA(intel_vsec_tpmi_ida); + +static const char *intel_tpmi_name(enum intel_tpmi_id id) +{ + switch (id) { + case TPMI_ID_RAPL: + return "rapl"; + case TPMI_ID_PEM: + return "pem"; + case TPMI_ID_UNCORE: + return "uncore"; + case TPMI_ID_SST: + return "sst"; + default: + return NULL; + } +} + +/* String Length for tpmi-"feature_name(upto 8 bytes)" */ +#define TPMI_FEATURE_NAME_LEN 14 + +static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, + struct intel_tpmi_pm_feature *pfs, + u64 pfs_start) +{ + struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev; + char feature_id_name[TPMI_FEATURE_NAME_LEN]; + struct intel_vsec_device *feature_vsec_dev; + struct resource *res, *tmp; + const char *name; + int ret, i; + + name = intel_tpmi_name(pfs->pfs_header.tpmi_id); + if (!name) + return -EOPNOTSUPP; + + feature_vsec_dev = kzalloc(sizeof(*feature_vsec_dev), GFP_KERNEL); + if (!feature_vsec_dev) + return -ENOMEM; + + res = kcalloc(pfs->pfs_header.num_entries, sizeof(*res), GFP_KERNEL); + if (!res) { + ret = -ENOMEM; + goto free_vsec; + } + + snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name); + + for (i = 0, tmp = res; i < pfs->pfs_header.num_entries; i++, tmp++) { + u64 entry_size_bytes = pfs->pfs_header.entry_size * 4; + + tmp->start = pfs->vsec_offset + entry_size_bytes * i; + tmp->end = tmp->start + entry_size_bytes - 1; + tmp->flags = IORESOURCE_MEM; + } + + feature_vsec_dev->pcidev = vsec_dev->pcidev; + feature_vsec_dev->resource = res; + feature_vsec_dev->num_resources = pfs->pfs_header.num_entries; + feature_vsec_dev->ida = &intel_vsec_tpmi_ida; + + /* + * intel_vsec_add_aux() is resource managed, no explicit + * delete is required on error or on module unload. + */ + ret = intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev, + feature_vsec_dev, feature_id_name); + if (ret) + goto free_res; + + return 0; + +free_res: + kfree(res); +free_vsec: + kfree(feature_vsec_dev); + + return ret; +} + +static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info) +{ + struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev; + int ret, i; + + for (i = 0; i < vsec_dev->num_resources; i++) { + ret = tpmi_create_device(tpmi_info, &tpmi_info->tpmi_features[i], + tpmi_info->pfs_start); + /* + * Fail, if the supported features fails to create device, + * otherwise, continue. Even if one device failed to create, + * fail the loading of driver. Since intel_vsec_add_aux() + * is resource managed, no clean up is required for the + * successfully created devices. + */ + if (ret && ret != -EOPNOTSUPP) + return ret; + } + + return 0; +} + +static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size) +{ + void __iomem *pfs_mem; + + pfs_mem = ioremap(start, size); + if (!pfs_mem) + return -ENOMEM; + + memcpy_fromio(&pfs->pfs_header, pfs_mem, sizeof(pfs->pfs_header)); + + iounmap(pfs_mem); + + return 0; +} + +static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + struct intel_tpmi_info *tpmi_info; + u64 pfs_start = 0; + int i; + + tpmi_info = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_info), GFP_KERNEL); + if (!tpmi_info) + return -ENOMEM; + + tpmi_info->vsec_dev = vsec_dev; + tpmi_info->feature_count = vsec_dev->num_resources; + + tpmi_info->tpmi_features = devm_kcalloc(&auxdev->dev, vsec_dev->num_resources, + sizeof(*tpmi_info->tpmi_features), + GFP_KERNEL); + if (!tpmi_info->tpmi_features) + return -ENOMEM; + + for (i = 0; i < vsec_dev->num_resources; i++) { + struct intel_tpmi_pm_feature *pfs; + struct resource *res; + u64 res_start; + int size, ret; + + pfs = &tpmi_info->tpmi_features[i]; + + res = &vsec_dev->resource[i]; + if (!res) + continue; + + res_start = res->start; + size = resource_size(res); + if (size < 0) + continue; + + ret = tpmi_fetch_pfs_header(pfs, res_start, size); + if (ret) + continue; + + if (!pfs_start) + pfs_start = res_start; + + pfs->pfs_header.cap_offset *= 1024; + + pfs->vsec_offset = pfs_start + pfs->pfs_header.cap_offset; + } + + tpmi_info->pfs_start = pfs_start; + + auxiliary_set_drvdata(auxdev, tpmi_info); + + return tpmi_create_devices(tpmi_info); +} + +static int tpmi_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + return intel_vsec_tpmi_init(auxdev); +} + +/* + * Remove callback is not needed currently as there is no + * cleanup required. All memory allocs are device managed. All + * devices created by this modules are also device managed. + */ + +static const struct auxiliary_device_id tpmi_id_table[] = { + { .name = "intel_vsec.tpmi" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, tpmi_id_table); + +static struct auxiliary_driver tpmi_aux_driver = { + .id_table = tpmi_id_table, + .probe = tpmi_probe, +}; + +module_auxiliary_driver(tpmi_aux_driver); + +MODULE_IMPORT_NS(INTEL_VSEC); +MODULE_DESCRIPTION("Intel TPMI enumeration module"); +MODULE_LICENSE("GPL"); From 762ed313574652ac604fb95dd601232a6e0320ef Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:36 -0800 Subject: [PATCH 48/80] platform/x86/intel/tpmi: Process CPU package mapping There is one Intel Out-of-Band (OOB) PCI device per CPU package. Since TPMI feature is exposed via OOB PCI device, there will be multiple TPMI device instances on a multi CPU package system. There are several PM features, which needs to associate APIC based CPU package ID information to a TPMI instance. For example if Intel Speed Select feature requires control of a CPU package, it needs to identify right TPMI device instance. There is one special TPMI ID (ID = 0x81) in the PFS. The MMIO region of this TPMI ID points to a mapping table: - PCI Bus ID - PCI Device ID - APIC based Package ID This mapping information can be used by any PM feature driver which requires mapping from a CPU package to a TPMI device instance. Unlike other TPMI features, device node is not created for this feature ID (0x81). Instead store the mapping information as platform data, which is part of the per PCI device TPMI instance (struct intel_tpmi_info). Later the TPMI feature drivers can get the mapping information using an interface "tpmi_get_platform_data()" Signed-off-by: Srinivas Pandruvada Reviewed-by: Pierre-Louis Bossart Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230202010738.2186174-6-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/tpmi.c | 72 +++++++++++++++++++++++++++++++ include/linux/intel_tpmi.h | 28 ++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 include/linux/intel_tpmi.h diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 1b87b46ba8a9..e612da579b29 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -47,6 +47,7 @@ */ #include +#include #include #include #include @@ -96,6 +97,7 @@ struct intel_tpmi_pm_feature { * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device * @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features * @pfs_start: Start of PFS offset for the TPMI instances in this device + * @plat_info: Stores platform info which can be used by the client drivers * * Stores the information for all TPMI devices enumerated from a single PCI device. */ @@ -104,8 +106,30 @@ struct intel_tpmi_info { struct intel_vsec_device *vsec_dev; int feature_count; u64 pfs_start; + struct intel_tpmi_plat_info plat_info; }; +/** + * struct tpmi_info_header - CPU package ID to PCI device mapping information + * @fn: PCI function number + * @dev: PCI device number + * @bus: PCI bus number + * @pkg: CPU Package id + * @reserved: Reserved for future use + * @lock: When set to 1 the register is locked and becomes read-only + * until next reset. Not for use by the OS driver. + * + * The structure to read hardware provided mapping information. + */ +struct tpmi_info_header { + u64 fn:3; + u64 dev:5; + u64 bus:8; + u64 pkg:8; + u64 reserved:39; + u64 lock:1; +} __packed; + /* * List of supported TMPI IDs. * Some TMPI IDs are not used by Linux, so the numbers are not consecutive. @@ -115,11 +139,20 @@ enum intel_tpmi_id { TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */ TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */ TPMI_ID_SST = 5, /* Speed Select Technology */ + TPMI_INFO_ID = 0x81, /* Special ID for PCI BDF and Package ID information */ }; /* Used during auxbus device creation */ static DEFINE_IDA(intel_vsec_tpmi_ida); +struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + + return vsec_dev->priv_data; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_platform_data, INTEL_TPMI); + static const char *intel_tpmi_name(enum intel_tpmi_id id) { switch (id) { @@ -177,6 +210,8 @@ static int tpmi_create_device(struct intel_tpmi_info *tpmi_info, feature_vsec_dev->pcidev = vsec_dev->pcidev; feature_vsec_dev->resource = res; feature_vsec_dev->num_resources = pfs->pfs_header.num_entries; + feature_vsec_dev->priv_data = &tpmi_info->plat_info; + feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info); feature_vsec_dev->ida = &intel_vsec_tpmi_ida; /* @@ -220,6 +255,31 @@ static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info) return 0; } +#define TPMI_INFO_BUS_INFO_OFFSET 0x08 + +static int tpmi_process_info(struct intel_tpmi_info *tpmi_info, + struct intel_tpmi_pm_feature *pfs) +{ + struct tpmi_info_header header; + void __iomem *info_mem; + + info_mem = ioremap(pfs->vsec_offset + TPMI_INFO_BUS_INFO_OFFSET, + pfs->pfs_header.entry_size * 4 - TPMI_INFO_BUS_INFO_OFFSET); + if (!info_mem) + return -ENOMEM; + + memcpy_fromio(&header, info_mem, sizeof(header)); + + tpmi_info->plat_info.package_id = header.pkg; + tpmi_info->plat_info.bus_number = header.bus; + tpmi_info->plat_info.device_number = header.dev; + tpmi_info->plat_info.function_number = header.fn; + + iounmap(info_mem); + + return 0; +} + static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size) { void __iomem *pfs_mem; @@ -238,6 +298,7 @@ static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, i static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) { struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + struct pci_dev *pci_dev = vsec_dev->pcidev; struct intel_tpmi_info *tpmi_info; u64 pfs_start = 0; int i; @@ -248,6 +309,7 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) tpmi_info->vsec_dev = vsec_dev; tpmi_info->feature_count = vsec_dev->num_resources; + tpmi_info->plat_info.bus_number = pci_dev->bus->number; tpmi_info->tpmi_features = devm_kcalloc(&auxdev->dev, vsec_dev->num_resources, sizeof(*tpmi_info->tpmi_features), @@ -282,6 +344,16 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) pfs->pfs_header.cap_offset *= 1024; pfs->vsec_offset = pfs_start + pfs->pfs_header.cap_offset; + + /* + * Process TPMI_INFO to get PCI device to CPU package ID. + * Device nodes for TPMI features are not created in this + * for loop. So, the mapping information will be available + * when actual device nodes created outside this + * loop via tpmi_create_devices(). + */ + if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) + tpmi_process_info(tpmi_info, pfs); } tpmi_info->pfs_start = pfs_start; diff --git a/include/linux/intel_tpmi.h b/include/linux/intel_tpmi.h new file mode 100644 index 000000000000..5b665320ecb4 --- /dev/null +++ b/include/linux/intel_tpmi.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * intel_tpmi.h: Intel TPMI core external interface + */ + +#ifndef _INTEL_TPMI_H_ +#define _INTEL_TPMI_H_ + +/** + * struct intel_tpmi_plat_info - Platform information for a TPMI device instance + * @package_id: CPU Package id + * @bus_number: PCI bus number + * @device_number: PCI device number + * @function_number: PCI function number + * + * Structure to store platform data for a TPMI device instance. This + * struct is used to return data via tpmi_get_platform_data(). + */ +struct intel_tpmi_plat_info { + u8 package_id; + u8 bus_number; + u8 device_number; + u8 function_number; +}; + +struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev); + +#endif From 6d957f1e1646039f51fe1f6c6060738f648c4c70 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:37 -0800 Subject: [PATCH 49/80] platform/x86/intel/tpmi: ADD tpmi external interface for tpmi feature drivers Add interface to get resources and platform data. This will avoid code duplication. These interfaces includes: - Get resource count - Get resource at an index Signed-off-by: Srinivas Pandruvada Reviewed-by: Pierre-Louis Bossart Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20230202010738.2186174-7-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/tpmi.c | 22 ++++++++++++++++++++++ include/linux/intel_tpmi.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index e612da579b29..c60733261c89 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -153,6 +153,28 @@ struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *aux } EXPORT_SYMBOL_NS_GPL(tpmi_get_platform_data, INTEL_TPMI); +int tpmi_get_resource_count(struct auxiliary_device *auxdev) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + + if (vsec_dev) + return vsec_dev->num_resources; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_count, INTEL_TPMI); + +struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index) +{ + struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev); + + if (vsec_dev && index < vsec_dev->num_resources) + return &vsec_dev->resource[index]; + + return NULL; +} +EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); + static const char *intel_tpmi_name(enum intel_tpmi_id id) { switch (id) { diff --git a/include/linux/intel_tpmi.h b/include/linux/intel_tpmi.h index 5b665320ecb4..f505788c05da 100644 --- a/include/linux/intel_tpmi.h +++ b/include/linux/intel_tpmi.h @@ -24,5 +24,7 @@ struct intel_tpmi_plat_info { }; struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev); +struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index); +int tpmi_get_resource_count(struct auxiliary_device *auxdev); #endif From 42684d44a7f211d1c1ca64737dfc00470e5fa4a3 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 1 Feb 2023 17:07:38 -0800 Subject: [PATCH 50/80] MAINTAINERS: Add entry for TPMI driver Add entry for TPMI (Topology Aware Register and PM Capsule Interface) driver. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230202010738.2186174-8-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f781f936ae35..ffd004486a8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10682,6 +10682,13 @@ S: Maintained F: arch/x86/include/asm/intel_telemetry.h F: drivers/platform/x86/intel/telemetry/ +INTEL TPMI DRIVER +M: Srinivas Pandruvada +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/intel/tpmi.c +F: include/linux/intel_tpmi.h + INTEL UNCORE FREQUENCY CONTROL M: Srinivas Pandruvada L: platform-driver-x86@vger.kernel.org From 23d18a20723b115460014a92c4e9ce631d6455c5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 4 Feb 2023 12:02:23 +0100 Subject: [PATCH 51/80] platform/x86: int3472/discrete: Drop unnecessary obj->type == string check acpi_evaluate_dsm_typed() already verifies the type is the requested type, so this error check is a no-op, drop it. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230204110223.54625-1-hdegoede@redhat.com --- drivers/platform/x86/intel/int3472/discrete.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 96963e30ab6c..f064da74f50a 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -78,14 +78,6 @@ skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472) return ERR_PTR(-ENODEV); } - if (obj->string.type != ACPI_TYPE_STRING) { - dev_err(int3472->dev, - "Sensor _DSM returned a non-string value\n"); - - ACPI_FREE(obj); - return ERR_PTR(-EINVAL); - } - for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) { if (!strcmp(int3472_sensor_configs[i].sensor_module_name, obj->string.pointer)) From b919540aeb58bc164192b07e64fd45eea4f39b91 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 8 Feb 2023 17:36:52 +0100 Subject: [PATCH 52/80] platform/x86: int3472/discrete: add LEDS_CLASS dependency int3472 now fails to link when the LED support is disabled: x86_64-linux-ld: drivers/platform/x86/intel/int3472/led.o: in function `skl_int3472_register_pled': led.c:(.text+0xf4): undefined reference to `led_classdev_register_ext' x86_64-linux-ld: led.c:(.text+0x131): undefined reference to `led_add_lookup' x86_64-linux-ld: drivers/platform/x86/intel/int3472/led.o: in function `skl_int3472_unregister_pled': led.c:(.text+0x16b): undefined reference to `led_remove_lookup' x86_64-linux-ld: led.c:(.text+0x177): undefined reference to `led_classdev_unregister' Add an explicit Kconfig dependency. Fixes: 5ae20a8050d0 ("platform/x86: int3472/discrete: Create a LED class device for the privacy LED") Signed-off-by: Arnd Bergmann Reviewed-by: Sakari Ailus Link: https://lore.kernel.org/r/20230208163658.2129009-1-arnd@kernel.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/int3472/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel/int3472/Kconfig b/drivers/platform/x86/intel/int3472/Kconfig index 62e5d4cf9ee5..17ae997f93ea 100644 --- a/drivers/platform/x86/intel/int3472/Kconfig +++ b/drivers/platform/x86/intel/int3472/Kconfig @@ -4,6 +4,7 @@ config INTEL_SKL_INT3472 depends on COMMON_CLK depends on I2C depends on GPIOLIB + depends on LEDS_CLASS depends on REGULATOR select MFD_CORE select REGMAP_I2C From 67c7debbfc3b1ccfe18e10b7e7663737f7dff0e3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Feb 2023 16:52:38 +0200 Subject: [PATCH 53/80] platform/x86: Fix header inclusion in linux/platform_data/x86/soc.h First of all, we don't use intel-family.h directly. On the other hand we actively use boolean type, that is defined in the types.h (we take top-level header for that) and x86_cpu_id, that is provided in the mod_devicetable.h. Secondly, we don't need to spread SOC_INTEL_IS_CPU() macro to the users. Hence, undefine it when it's appropriate. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230206145238.19460-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/platform_data/x86/soc.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/platform_data/x86/soc.h b/include/linux/platform_data/x86/soc.h index da05f425587a..a5705189e2ac 100644 --- a/include/linux/platform_data/x86/soc.h +++ b/include/linux/platform_data/x86/soc.h @@ -8,10 +8,13 @@ #ifndef __PLATFORM_DATA_X86_SOC_H #define __PLATFORM_DATA_X86_SOC_H +#include + #if IS_ENABLED(CONFIG_X86) +#include + #include -#include #define SOC_INTEL_IS_CPU(soc, type) \ static inline bool soc_intel_is_##soc(void) \ @@ -34,6 +37,8 @@ SOC_INTEL_IS_CPU(apl, ATOM_GOLDMONT); SOC_INTEL_IS_CPU(glk, ATOM_GOLDMONT_PLUS); SOC_INTEL_IS_CPU(cml, KABYLAKE_L); +#undef SOC_INTEL_IS_CPU + #else /* IS_ENABLED(CONFIG_X86) */ static inline bool soc_intel_is_byt(void) From 4ca26e565e1c91bb45221e15b98e4582f33375c0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Feb 2023 17:02:02 +0200 Subject: [PATCH 54/80] platform/x86: Add include/linux/platform_data/x86 to MAINTAINERS Most of the files there are being used under PDx86 subsystem or tightly related drivers (like drivers/clk/x86/). I think it makes sense to assure that PDx86 keeps an eye on the changes there. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230206150202.27892-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index ffd004486a8c..72104b2d563c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22650,6 +22650,7 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git F: drivers/platform/olpc/ F: drivers/platform/x86/ +F: include/linux/platform_data/x86/ X86 PLATFORM DRIVERS - ARCH R: Darren Hart From 1ecfd30960d4377c2d85181608936dedd35bb171 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Mon, 6 Feb 2023 20:38:52 +0530 Subject: [PATCH 55/80] platform/x86/amd: pmc: Add num_samples message id support to STB Recent PMFWs have the support for S2D_NUM_SAMPLES message ID that can tell the current number of samples present within the STB DRAM. num_samples returned would let the driver know the start of the read from the last push location. This way, the driver would emit the top most region of the STB DRAM. Co-developed-by: Sanket Goswami Signed-off-by: Sanket Goswami Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20230206150855.1938810-2-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 3cbb01ec10e3..23440f70d3df 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -114,6 +114,7 @@ enum s2d_arg { S2D_TELEMETRY_SIZE = 0x01, S2D_PHYS_ADDR_LOW, S2D_PHYS_ADDR_HIGH, + S2D_NUM_SAMPLES, }; struct amd_pmc_bit_map { @@ -246,13 +247,35 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = { static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) { struct amd_pmc_dev *dev = filp->f_inode->i_private; - u32 *buf; + u32 *buf, fsize, num_samples, stb_rdptr_offset = 0; + int ret; buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL); if (!buf) return -ENOMEM; - memcpy_fromio(buf, dev->stb_virt_addr, S2D_TELEMETRY_BYTES_MAX); + /* Spill to DRAM num_samples uses separate SMU message port */ + dev->msg_port = 1; + + /* Get the num_samples to calculate the last push location */ + ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, STB_SPILL_TO_DRAM, 1); + /* Clear msg_port for other SMU operation */ + dev->msg_port = 0; + if (ret) { + dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret); + return ret; + } + + /* Start capturing data from the last push location */ + if (num_samples > S2D_TELEMETRY_BYTES_MAX) { + fsize = S2D_TELEMETRY_BYTES_MAX; + stb_rdptr_offset = num_samples - fsize; + } else { + fsize = num_samples; + stb_rdptr_offset = 0; + } + + memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize); filp->private_data = buf; return 0; From b0d4bb973539f5e60fff37ea0f211598cac614a8 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Mon, 6 Feb 2023 20:38:53 +0530 Subject: [PATCH 56/80] platform/x86/amd: pmc: Write dummy postcode into the STB DRAM Based on the recommendation from the PMFW team in order to get the recent telemetry data present on the STB DRAM the driver is required to send one dummy write to the STB buffer, so it internally triggers the PMFW to emit the latest telemetry data in the STB DRAM region. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20230206150855.1938810-3-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 23440f70d3df..27774020597c 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -43,6 +43,7 @@ #define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001 #define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002 #define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003 +#define AMD_PMC_STB_DUMMY_PC 0xC6000007 /* STB S2D(Spill to DRAM) has different message port offset */ #define STB_SPILL_TO_DRAM 0xBE @@ -250,6 +251,11 @@ static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp) u32 *buf, fsize, num_samples, stb_rdptr_offset = 0; int ret; + /* Write dummy postcode while reading the STB buffer */ + ret = amd_pmc_write_stb(dev, AMD_PMC_STB_DUMMY_PC); + if (ret) + dev_err(dev->dev, "error writing to STB: %d\n", ret); + buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL); if (!buf) return -ENOMEM; From 1ac252a5059a77108806ce4b9160721b354bcd84 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Mon, 6 Feb 2023 20:38:54 +0530 Subject: [PATCH 57/80] platform/x86/amd: pmc: differentiate STB/SMU messaging prints Modify the dynamic debug print to differentiate between the regular and spill to DRAM usage of the SMU message port. Suggested-by: Sanket Goswami Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20230206150855.1938810-4-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 27774020597c..b99fa676d35e 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -589,13 +589,13 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) } value = amd_pmc_reg_read(dev, response); - dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value); + dev_dbg(dev->dev, "AMD_%s_REGISTER_RESPONSE:%x\n", dev->msg_port ? "S2D" : "PMC", value); value = amd_pmc_reg_read(dev, argument); - dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value); + dev_dbg(dev->dev, "AMD_%s_REGISTER_ARGUMENT:%x\n", dev->msg_port ? "S2D" : "PMC", value); value = amd_pmc_reg_read(dev, message); - dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value); + dev_dbg(dev->dev, "AMD_%s_REGISTER_MESSAGE:%x\n", dev->msg_port ? "S2D" : "PMC", value); } static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret) From be1ca8ae66851ba6a8131c15e7f9c85430315f57 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Mon, 6 Feb 2023 20:38:55 +0530 Subject: [PATCH 58/80] platform/x86/amd: pmc: Add line break for readability Add a line break for the code readability. Reviewed-by: Hans de Goede Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20230206150855.1938810-5-Shyam-sundar.S-k@amd.com Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index b99fa676d35e..ab05b9ee6655 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -105,6 +105,7 @@ #define DELAY_MIN_US 2000 #define DELAY_MAX_US 3000 #define FIFO_SIZE 4096 + enum amd_pmc_def { MSG_TEST = 0x01, MSG_OS_HINT_PCO, From 9a90ea7d378486aa358330dafc7e8c3b27de4d84 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 7 Feb 2023 04:58:21 -0800 Subject: [PATCH 59/80] platform/x86/intel/vsec: Use mutex for ida_alloc() and ida_free() ID alloc and free functions don't have in built protection for parallel invocation of ida_alloc() and ida_free(). With the current flow in the vsec driver, there is no such scenario. But add mutex protection for potential future changes. Suggested-by: Hans de Goede Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20230207125821.3837799-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/vsec.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index b936fc5776d7..f1680b7e64f5 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -129,11 +129,16 @@ static void intel_vsec_remove_aux(void *data) auxiliary_device_uninit(data); } +static DEFINE_MUTEX(vsec_ida_lock); + static void intel_vsec_dev_release(struct device *dev) { struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev); + mutex_lock(&vsec_ida_lock); ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id); + mutex_unlock(&vsec_ida_lock); + kfree(intel_vsec_dev->resource); kfree(intel_vsec_dev); } @@ -145,7 +150,9 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; int ret, id; + mutex_lock(&vsec_ida_lock); ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); + mutex_unlock(&vsec_ida_lock); if (ret < 0) { kfree(intel_vsec_dev); return ret; @@ -161,7 +168,9 @@ int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent, ret = auxiliary_device_init(auxdev); if (ret < 0) { + mutex_lock(&vsec_ida_lock); ida_free(intel_vsec_dev->ida, auxdev->id); + mutex_unlock(&vsec_ida_lock); kfree(intel_vsec_dev->resource); kfree(intel_vsec_dev); return ret; From 438688d5ae9ecb734395da09eb0aab440ff30cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 7 Feb 2023 16:40:44 +0000 Subject: [PATCH 60/80] platform/x86: dell-wmi-sysman: Make kobj_type structure constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ee6d3dd4ed48 ("driver core: make kobj_type constant.") the driver core allows the usage of const struct kobj_type. Take advantage of this to constify the structure definition to prevent modification at runtime. Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20230207-kobj_type-pdx86-v1-1-8e2c4fb83105@weissschuh.net Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-sysman/sysman.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c index 0a6411a8a104..0285b47d99d1 100644 --- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c +++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c @@ -255,7 +255,7 @@ static void attr_name_release(struct kobject *kobj) kfree(kobj); } -static struct kobj_type attr_name_ktype = { +static const struct kobj_type attr_name_ktype = { .release = attr_name_release, .sysfs_ops = &wmi_sysman_kobj_sysfs_ops, }; From 881a10355fadd10fc0bbedc729c1a32b98c37e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 7 Feb 2023 16:40:45 +0000 Subject: [PATCH 61/80] platform/x86: think-lmi: Make kobj_type structure constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ee6d3dd4ed48 ("driver core: make kobj_type constant.") the driver core allows the usage of const struct kobj_type. Take advantage of this to constify the structure definition to prevent modification at runtime. Signed-off-by: Thomas Weißschuh Reviewed-by: Mark Pearson Link: https://lore.kernel.org/r/20230207-kobj_type-pdx86-v1-2-8e2c4fb83105@weissschuh.net Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/think-lmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c index caa862506ed3..86b33b74519b 100644 --- a/drivers/platform/x86/think-lmi.c +++ b/drivers/platform/x86/think-lmi.c @@ -1089,12 +1089,12 @@ static void tlmi_pwd_setting_release(struct kobject *kobj) kfree(setting); } -static struct kobj_type tlmi_attr_setting_ktype = { +static const struct kobj_type tlmi_attr_setting_ktype = { .release = &tlmi_attr_setting_release, .sysfs_ops = &tlmi_kobj_sysfs_ops, }; -static struct kobj_type tlmi_pwd_setting_ktype = { +static const struct kobj_type tlmi_pwd_setting_ktype = { .release = &tlmi_pwd_setting_release, .sysfs_ops = &tlmi_kobj_sysfs_ops, }; From ad76d9b88c9f6065663fc2005f4b219984b3f8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 7 Feb 2023 16:40:46 +0000 Subject: [PATCH 62/80] x86/platform/uv: Make kobj_type structure constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ee6d3dd4ed48 ("driver core: make kobj_type constant.") the driver core allows the usage of const struct kobj_type. Take advantage of this to constify the structure definition to prevent modification at runtime. Signed-off-by: Thomas Weißschuh Reviewed-by: Justin Ernst Link: https://lore.kernel.org/r/20230207-kobj_type-pdx86-v1-3-8e2c4fb83105@weissschuh.net Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/uv_sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/uv_sysfs.c b/drivers/platform/x86/uv_sysfs.c index 73fc38ee7430..38d1b692d3c0 100644 --- a/drivers/platform/x86/uv_sysfs.c +++ b/drivers/platform/x86/uv_sysfs.c @@ -203,7 +203,7 @@ static const struct sysfs_ops hub_sysfs_ops = { .show = hub_type_show, }; -static struct kobj_type hub_attr_type = { +static const struct kobj_type hub_attr_type = { .release = hub_release, .sysfs_ops = &hub_sysfs_ops, .default_groups = uv_hub_groups, @@ -356,7 +356,7 @@ static const struct sysfs_ops uv_port_sysfs_ops = { .show = uv_port_type_show, }; -static struct kobj_type uv_port_attr_type = { +static const struct kobj_type uv_port_attr_type = { .release = uv_port_release, .sysfs_ops = &uv_port_sysfs_ops, .default_groups = uv_port_groups, @@ -528,7 +528,7 @@ static const struct sysfs_ops uv_pci_top_sysfs_ops = { .show = pci_top_type_show, }; -static struct kobj_type uv_pci_top_attr_type = { +static const struct kobj_type uv_pci_top_attr_type = { .release = uv_pci_top_release, .sysfs_ops = &uv_pci_top_sysfs_ops, }; From 0b8ecadc7f5bce64582024737f3c1d97b404353e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Tue, 7 Feb 2023 16:51:19 +0000 Subject: [PATCH 63/80] MAINTAINERS: dell-wmi-sysman: drop Divya Bharathi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the bounce sent by Dell's mailserver this user does not exist (anymore). Signed-off-by: Thomas Weißschuh Link: https://lore.kernel.org/r/20230207-maintainers-dell-wmi-sysman-v1-1-6594fea12f6c@weissschuh.net Signed-off-by: Hans de Goede --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 72104b2d563c..ce4cd9550bac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5926,7 +5926,6 @@ F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv F: drivers/platform/x86/dell/dell-wmi-ddv.c DELL WMI SYSMAN DRIVER -M: Divya Bharathi M: Prasanth Ksr L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org From f8dacbf7da2e02d4c0c543cf5c277c906a2bb042 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:18 +0200 Subject: [PATCH 64/80] platform: mellanox: Introduce support for rack manager switch The rack switch is designed to provide high bandwidth, low latency connectivity using optical fiber as the primary interconnect. System supports 32 OSFP ports, non-blocking switching capacity of 25.6Tbps. System equipped with: - 2 replaceable power supplies (AC) with 1+1 redundancy model. - 7 replaceable fan drawers with 6+1 redundancy model. - 2 External Root of Trust or EROT (Glacier) devices for securing ASICs firmware. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-2-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 261 ++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 2fac05a17a5c..3e4adeb20a7e 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -90,6 +90,12 @@ #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a +#define MLXPLAT_CPLD_LPC_REG_EROT_OFFSET 0x91 +#define MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET 0x92 +#define MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET 0x93 +#define MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET 0x94 +#define MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET 0x95 +#define MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET 0x96 #define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a #define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b #define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c @@ -109,6 +115,8 @@ #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 +#define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2 +#define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3 #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 #define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 @@ -214,6 +222,7 @@ #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) +#define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) @@ -243,6 +252,7 @@ #define MLXPLAT_CPLD_CH2_ETH_MODULAR 3 #define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 #define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 +#define MLXPLAT_CPLD_CH2_RACK_SWITCH 18 /* Number of LPC attached MUX platform devices */ #define MLXPLAT_CPLD_LPC_MUX_DEVS 4 @@ -280,6 +290,9 @@ /* Minimum power required for turning on Ethernet modular system (WATT) */ #define MLXPLAT_CPLD_ETH_MODULAR_PWR_MIN 50 +/* Default value for PWM control register for rack switch system */ +#define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4 + /* mlxplat_priv - platform private data * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices @@ -460,6 +473,36 @@ static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = { }, }; +/* Platform channels for rack swicth system family */ +static const int mlxplat_rack_switch_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, +}; + +/* Platform rack switch mux data */ +static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = { + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH1, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_rack_switch_channels, + .n_values = ARRAY_SIZE(mlxplat_rack_switch_channels), + }, + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH2_RACK_SWITCH, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_msn21xx_channels, + .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), + }, + +}; + /* Platform hotplug devices */ static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { { @@ -2064,6 +2107,97 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_nvlink_blade_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; +/* Platform hotplug for switch systems family data */ +static struct mlxreg_core_data mlxplat_mlxcpld_erot_ap_items_data[] = { + { + .label = "erot1_ap", + .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, + .mask = BIT(0), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "erot2_ap", + .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, + .mask = BIT(1), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_erot_error_items_data[] = { + { + .label = "erot1_error", + .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, + .mask = BIT(0), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "erot2_error", + .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, + .mask = BIT(1), + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + +static struct mlxreg_core_item mlxplat_mlxcpld_rack_switch_items[] = { + { + .data = mlxplat_mlxcpld_ext_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_EXT_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_ext_pwr_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_EXT_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, + .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_ng_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_NG_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_erot_ap_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, + .mask = MLXPLAT_CPLD_EROT_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_erot_error_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, + .mask = MLXPLAT_CPLD_EROT_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data), + .inversed = 1, + .health = false, + }, +}; + +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { + .items = mlxplat_mlxcpld_rack_switch_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_rack_switch_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, +}; + /* Platform led default data */ static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { { @@ -2947,6 +3081,44 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mask = GENMASK(7, 0) & ~BIT(2), .mode = 0200, }, + { + .label = "erot1_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "erot2_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, + { + .label = "erot1_recovery", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "erot2_recovery", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, + { + .label = "erot1_wp", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + .secured = 1, + }, + { + .label = "erot2_wp", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0644, + .secured = 1, + }, { .label = "reset_long_pb", .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, @@ -3142,6 +3314,25 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mask = GENMASK(7, 0) & ~BIT(4), .mode = 0644, }, + { + .label = "erot1_ap_reset", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "erot2_ap_reset", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "spi_chnl_select", + .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, + .mask = GENMASK(7, 0), + .bit = 1, + .mode = 0644, + }, { .label = "config1", .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, @@ -4257,6 +4448,10 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: @@ -4274,6 +4469,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: + case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: @@ -4358,6 +4554,12 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: @@ -4382,6 +4584,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: + case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: @@ -4492,6 +4696,12 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: @@ -4516,6 +4726,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: + case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET: + case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: @@ -4583,6 +4795,13 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, }; +static const struct reg_default mlxplat_mlxcpld_regmap_rack_switch[] = { + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT }, + { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, +}; + static const struct reg_default mlxplat_mlxcpld_regmap_eth_modular[] = { { MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0x61 }, { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, @@ -4676,6 +4895,20 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = { .reg_write = mlxplat_mlxcpld_reg_write, }; +static const struct regmap_config mlxplat_mlxcpld_regmap_config_rack_switch = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 255, + .cache_type = REGCACHE_FLAT, + .writeable_reg = mlxplat_mlxcpld_writeable_reg, + .readable_reg = mlxplat_mlxcpld_readable_reg, + .volatile_reg = mlxplat_mlxcpld_volatile_reg, + .reg_defaults = mlxplat_mlxcpld_regmap_rack_switch, + .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_rack_switch), + .reg_read = mlxplat_mlxcpld_reg_read, + .reg_write = mlxplat_mlxcpld_reg_write, +}; + static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = { .reg_bits = 8, .val_bits = 8, @@ -4957,6 +5190,27 @@ static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *d return 1; } +static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data); + mlxplat_mux_data = mlxplat_rack_switch_mux_data; + mlxplat_hotplug = &mlxplat_mlxcpld_rack_switch_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_ng_led_data; + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; + mlxplat_fan = &mlxplat_default_fan_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch; + + return 1; +} + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { { .callback = mlxplat_dmi_default_wc_matched, @@ -5014,6 +5268,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"), }, }, + { + .callback = mlxplat_dmi_rack_switch_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI142"), + }, + }, { .callback = mlxplat_dmi_ng400_matched, .matches = { From 488f0fca0db00257c42d44857061bc6726adaa15 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:19 +0200 Subject: [PATCH 65/80] platform: mellanox: Change "reset_pwr_converter_fail" attribute Change "reset_voltmon_upgrade_fail" attribute name to "reset_pwr_converter_fail". For systems using "mlxplat_mlxcpld_default_ng_regs_io_data", relevant CPLD 'register.bit' indicates the failure of power converter, while on older systems same 'register.bit' indicates failure of voltage monitor devices upgrade failure. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-3-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 3e4adeb20a7e..c53eca49c47f 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -3186,7 +3186,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mode = 0444, }, { - .label = "reset_voltmon_upgrade_fail", + .label = "reset_pwr_converter_fail", .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, .mask = GENMASK(7, 0) & ~BIT(0), .mode = 0444, From acc6ea304590f5ec1590e328c7ae0584f7dd77be Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:20 +0200 Subject: [PATCH 66/80] platform: mellanox: Cosmetic changes - rename to more common name Rename 'nvlink_blade' in several declaration to more common name "chassis_blade", since these names are going to be used for different kinds of blades. Fix 'swicth' to 'switch' in comment. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-4-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index c53eca49c47f..e629ec8a2a2f 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -473,7 +473,7 @@ static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = { }, }; -/* Platform channels for rack swicth system family */ +/* Platform channels for rack switch system family */ static const int mlxplat_rack_switch_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, }; @@ -2085,7 +2085,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_global_wp_items_data[] = { }, }; -static struct mlxreg_core_item mlxplat_mlxcpld_nvlink_blade_items[] = { +static struct mlxreg_core_item mlxplat_mlxcpld_chassis_blade_items[] = { { .data = mlxplat_mlxcpld_global_wp_items_data, .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, @@ -2098,9 +2098,9 @@ static struct mlxreg_core_item mlxplat_mlxcpld_nvlink_blade_items[] = { }; static -struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_nvlink_blade_data = { - .items = mlxplat_mlxcpld_nvlink_blade_items, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_items), +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_chassis_blade_data = { + .items = mlxplat_mlxcpld_chassis_blade_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_items), .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, @@ -3848,8 +3848,8 @@ static struct mlxreg_core_platform_data mlxplat_modular_regs_io_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data), }; -/* Platform register access for NVLink blade systems family data */ -static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = { +/* Platform register access for chassis blade systems family data */ +static struct mlxreg_core_data mlxplat_mlxcpld_chassis_blade_regs_io_data[] = { { .label = "cpld1_version", .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, @@ -4046,9 +4046,9 @@ static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = { }, }; -static struct mlxreg_core_platform_data mlxplat_nvlink_blade_regs_io_data = { - .data = mlxplat_mlxcpld_nvlink_blade_regs_io_data, - .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_regs_io_data), +static struct mlxreg_core_platform_data mlxplat_chassis_blade_regs_io_data = { + .data = mlxplat_mlxcpld_chassis_blade_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_regs_io_data), }; /* Platform FAN default */ @@ -5168,14 +5168,14 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) return 1; } -static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *dmi) +static int __init mlxplat_dmi_chassis_blade_matched(const struct dmi_system_id *dmi) { int i; mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); mlxplat_mux_data = mlxplat_default_mux_data; - mlxplat_hotplug = &mlxplat_mlxcpld_nvlink_blade_data; + mlxplat_hotplug = &mlxplat_mlxcpld_chassis_blade_data; mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; for (i = 0; i < mlxplat_mux_num; i++) { @@ -5183,7 +5183,7 @@ static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *d mlxplat_mux_data[i].n_values = ARRAY_SIZE(mlxplat_msn21xx_channels); } - mlxplat_regs_io = &mlxplat_nvlink_blade_regs_io_data; + mlxplat_regs_io = &mlxplat_chassis_blade_regs_io_data; mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; @@ -5288,7 +5288,7 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { }, }, { - .callback = mlxplat_dmi_nvlink_blade_matched, + .callback = mlxplat_dmi_chassis_blade_matched, .matches = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"), }, From fcf3790b9b63b27ac0269c2285021139a0798a7b Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:21 +0200 Subject: [PATCH 67/80] platform: mellanox: Introduce support for next-generation 800GB/s switch Introduce support for Nvidia next-generation 800GB/s ethernet switch SN5600. SN5600 is 51.2 Tbps Ethernet switch based on Nvidia Spectrum-4 ASIC. It can provide up to 64x800Gb/s (ETH) full bidirectional bandwidth per port using PAM-4 modulations. The system supports 64 Belly to Belly 2x4 OSFP cages. The switch was designed to fit standard 2U racks. Features: - 64 OSFP ports support 800GbE - 10GbE speed. - Additional 25GbE - 1GbE service port on the front panel. - Air-cooled with 3 + 1 redundant fan units. - 1 + 1 redundant 3000W or 3600W PSUs. - System management board is based on Intel Coffee-lake CPU E-2276 with secure-boot support. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-5-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 180 ++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index e629ec8a2a2f..cd7f6ff11b1e 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -253,6 +253,7 @@ #define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 #define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 #define MLXPLAT_CPLD_CH2_RACK_SWITCH 18 +#define MLXPLAT_CPLD_CH2_NG800 34 /* Number of LPC attached MUX platform devices */ #define MLXPLAT_CPLD_LPC_MUX_DEVS 4 @@ -503,6 +504,37 @@ static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = { }; +/* Platform channels for ng800 system family */ +static const int mlxplat_ng800_channels[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 +}; + +/* Platform ng800 mux data */ +static struct i2c_mux_reg_platform_data mlxplat_ng800_mux_data[] = { + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH1, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_ng800_channels, + .n_values = ARRAY_SIZE(mlxplat_ng800_channels), + }, + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH2_NG800, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, + .reg_size = 1, + .idle_in_use = 1, + .values = mlxplat_msn21xx_channels, + .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), + }, + +}; + /* Platform hotplug devices */ static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { { @@ -522,6 +554,15 @@ static struct i2c_board_info mlxplat_mlxcpld_ext_pwr[] = { }, }; +static struct i2c_board_info mlxplat_mlxcpld_pwr_ng800[] = { + { + I2C_BOARD_INFO("dps460", 0x59), + }, + { + I2C_BOARD_INFO("dps460", 0x5a), + }, +}; + static struct i2c_board_info mlxplat_mlxcpld_fan[] = { { I2C_BOARD_INFO("24c32", 0x50), @@ -601,6 +642,23 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_wc_items_data[] = { }, }; +static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_ng800_items_data[] = { + { + .label = "pwr1", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(0), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[0], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, + { + .label = "pwr2", + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = BIT(1), + .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[1], + .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, + }, +}; + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { { .label = "fan1", @@ -1224,6 +1282,47 @@ static struct mlxreg_core_item mlxplat_mlxcpld_ext_items[] = { } }; +static struct mlxreg_core_item mlxplat_mlxcpld_ng800_items[] = { + { + .data = mlxplat_mlxcpld_default_ng_psu_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, + .mask = MLXPLAT_CPLD_PSU_EXT_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_pwr_ng800_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, + .mask = MLXPLAT_CPLD_PWR_EXT_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_pwr_ng800_items_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_ng_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_NG_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, +}; + static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { .items = mlxplat_mlxcpld_ext_items, @@ -1234,6 +1333,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, }; +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ng800_data = { + .items = mlxplat_mlxcpld_ng800_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_ng800_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, +}; + static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = { { .label = "pwr1", @@ -3093,6 +3202,13 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mask = GENMASK(7, 0) & ~BIT(7), .mode = 0644, }, + { + .label = "clk_brd_prog_en", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0644, + .secured = 1, + }, { .label = "erot1_recovery", .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, @@ -3221,6 +3337,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mask = GENMASK(7, 0) & ~BIT(6), .mode = 0444, }, + { + .label = "reset_ac_ok_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, { .label = "psu1_on", .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, @@ -3302,6 +3424,13 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .bit = 5, .mode = 0444, }, + { + .label = "pwr_converter_prog_en", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0644, + .secured = 1, + }, { .label = "vpd_wp", .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, @@ -3326,6 +3455,30 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mask = GENMASK(7, 0) & ~BIT(1), .mode = 0444, }, + { + .label = "clk_brd1_boot_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "clk_brd2_boot_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "clk_brd_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "asic_pg_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, { .label = "spi_chnl_select", .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, @@ -5211,6 +5364,27 @@ static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dm return 1; } +static int __init mlxplat_dmi_ng800_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_ng800_mux_data); + mlxplat_mux_data = mlxplat_ng800_mux_data; + mlxplat_hotplug = &mlxplat_mlxcpld_ng800_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_ng_led_data; + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; + mlxplat_fan = &mlxplat_default_fan_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; + + return 1; +} + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { { .callback = mlxplat_dmi_default_wc_matched, @@ -5287,6 +5461,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0011"), }, }, + { + .callback = mlxplat_dmi_ng800_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0013"), + }, + }, { .callback = mlxplat_dmi_chassis_blade_matched, .matches = { From dd635e33b5c9a3ad3712abae7b845f4353da8cef Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:22 +0200 Subject: [PATCH 68/80] platform: mellanox: Introduce support of new Nvidia L1 switch Add support for new L1 switch nodes providing L1 connectivity for multi-node networking chassis. The purpose is to provide compute server with full management and IO subsystems with connections to L1 switches. System contains the following components: - COMe module based on Intel Coffee Lake CPU - Switch baseboard with two ASICs, while 24 ports of each ASICs are connected to one backplane connector 32 ports of each ASIC are connected to 8 OSFPs - Integrated 60mm dual-rotor FANs inside L1 node (N+2 redundancy) - Support 48V or 54V DC input from the external power server. Add the structures related to the new systems to allow proper activation of the all required platform driver. Add poweroff callback to support deep power cycle flow, which should include special actions against CPLD device for performing graceful operation. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-6-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 392 +++++++++++++++++++++++++++- 1 file changed, 391 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index cd7f6ff11b1e..1a07a9994f05 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #define MLX_PLAT_DEVICE_NAME "mlxplat" @@ -61,12 +62,19 @@ #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b +#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0x3c +#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0x3d +#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0x3e +#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0x3f #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 #define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42 #define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45 +#define MLXPLAT_CPLD_LPC_REG_BRD_OFFSET 0x47 +#define MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET 0x48 +#define MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET 0x49 #define MLXPLAT_CPLD_LPC_REG_GWP_OFFSET 0x4a #define MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET 0x4b #define MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET 0x4c @@ -96,6 +104,9 @@ #define MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET 0x94 #define MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET 0x95 #define MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET 0x96 +#define MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET 0x97 +#define MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET 0x98 +#define MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET 0x99 #define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a #define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b #define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c @@ -127,6 +138,7 @@ #define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1 #define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 #define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 +#define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9 #define MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET 0xde #define MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET 0xdf #define MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET 0xe0 @@ -210,6 +222,7 @@ MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 #define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2) +#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT BIT(4) #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) @@ -223,6 +236,16 @@ #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) #define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) +#define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0) +#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(5) +#define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3) +#define MLXPLAT_CPLD_THERMAL2_PDB_MASK BIT(4) +#define MLXPLAT_CPLD_INTRUSION_MASK BIT(6) +#define MLXPLAT_CPLD_PWM_PG_MASK BIT(7) +#define MLXPLAT_CPLD_L1_CHA_HEALTH_MASK (MLXPLAT_CPLD_THERMAL1_PDB_MASK | \ + MLXPLAT_CPLD_THERMAL2_PDB_MASK | \ + MLXPLAT_CPLD_INTRUSION_MASK |\ + MLXPLAT_CPLD_PWM_PG_MASK) #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) @@ -235,6 +258,8 @@ /* Masks for aggregation for modular systems */ #define MLXPLAT_CPLD_LPC_LC_MASK GENMASK(7, 0) +#define MLXPLAT_CPLD_HALT_MASK BIT(3) + /* Default I2C parent bus number */ #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 @@ -315,6 +340,8 @@ struct mlxplat_priv { void *regmap; }; +static struct platform_device *mlxplat_dev; + /* Regions for LPC I2C controller and LPC base register space */ static const struct resource mlxplat_lpc_resources[] = { [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, @@ -2307,6 +2334,156 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; +/* Callback performs graceful shutdown after notification about power button event */ +static int +mlxplat_mlxcpld_l1_switch_pwr_events_handler(void *handle, enum mlxreg_hotplug_kind kind, + u8 action) +{ + dev_info(&mlxplat_dev->dev, "System shutdown due to short press of power button"); + kernel_halt(); + return 0; +} + +static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_pwr_events_notifier = { + .user_handler = mlxplat_mlxcpld_l1_switch_pwr_events_handler, +}; + +/* Platform hotplug for l1 switch systems family data */ +static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_pwr_events_items_data[] = { + { + .label = "power_button", + .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, + .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_pwr_events_notifier, + }, +}; + +/* Callback activates latch reset flow after notification about intrusion event */ +static int +mlxplat_mlxcpld_l1_switch_intrusion_events_handler(void *handle, enum mlxreg_hotplug_kind kind, + u8 action) +{ + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + u32 regval; + int err; + + err = regmap_read(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, ®val); + if (err) + goto fail_regmap_read; + + if (action) { + dev_info(&mlxplat_dev->dev, "Detected intrusion - system latch is opened"); + err = regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + regval | MLXPLAT_CPLD_LATCH_RST_MASK); + } else { + dev_info(&mlxplat_dev->dev, "System latch is properly closed"); + err = regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + regval & ~MLXPLAT_CPLD_LATCH_RST_MASK); + } + + if (err) + goto fail_regmap_write; + + return 0; + +fail_regmap_read: +fail_regmap_write: + dev_err(&mlxplat_dev->dev, "Register access failed"); + return err; +} + +static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_intrusion_events_notifier = { + .user_handler = mlxplat_mlxcpld_l1_switch_intrusion_events_handler, +}; + +static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_health_events_items_data[] = { + { + .label = "thermal1_pdb", + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_THERMAL1_PDB_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "thermal2_pdb", + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_THERMAL2_PDB_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, + { + .label = "intrusion", + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_INTRUSION_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_intrusion_events_notifier, + }, + { + .label = "pwm_pg", + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_PWM_PG_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + +static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = { + { + .data = mlxplat_mlxcpld_default_ng_fan_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, + .mask = MLXPLAT_CPLD_FAN_NG_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_erot_ap_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, + .mask = MLXPLAT_CPLD_EROT_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_erot_error_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, + .mask = MLXPLAT_CPLD_EROT_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data), + .inversed = 1, + .health = false, + }, + { + .data = mlxplat_mlxcpld_l1_switch_pwr_events_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET, + .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_pwr_events_items_data), + .inversed = 0, + .health = false, + }, + { + .data = mlxplat_mlxcpld_l1_switch_health_events_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET, + .mask = MLXPLAT_CPLD_L1_CHA_HEALTH_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_health_events_items_data), + .inversed = 0, + .health = false, + .ind = 8, + }, +}; + +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_l1_switch_data = { + .items = mlxplat_mlxcpld_l1_switch_events_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_events_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT, +}; + /* Platform led default data */ static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { { @@ -2836,6 +3013,114 @@ static struct mlxreg_core_platform_data mlxplat_modular_led_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_led_data), }; +/* Platform led data for chassis system */ +static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_led_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, + { + .label = "fan1:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(0), + }, + { + .label = "fan1:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(0), + }, + { + .label = "fan2:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(1), + }, + { + .label = "fan2:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(1), + }, + { + .label = "fan3:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(2), + }, + { + .label = "fan3:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(2), + }, + { + .label = "fan4:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(3), + }, + { + .label = "fan4:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(3), + }, + { + .label = "fan5:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(4), + }, + { + .label = "fan5:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(4), + }, + { + .label = "fan6:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(5), + }, + { + .label = "fan6:orange", + .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET, + .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK, + .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET, + .bit = BIT(5), + }, + { + .label = "uid:blue", + .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_l1_switch_led_data = { + .data = mlxplat_mlxcpld_l1_switch_led_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_led_data), +}; + /* Platform register access default */ static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { { @@ -3367,12 +3652,48 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .mask = GENMASK(7, 0) & ~BIT(3), .mode = 0200, }, + { + .label = "deep_pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0200, + }, + { + .label = "latch_reset", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0200, + }, { .label = "jtag_enable", .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, .mask = GENMASK(7, 0) & ~BIT(4), .mode = 0644, }, + { + .label = "dbg1", + .reg = MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0644, + }, + { + .label = "dbg2", + .reg = MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0644, + }, + { + .label = "dbg3", + .reg = MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0644, + }, + { + .label = "dbg4", + .reg = MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0644, + }, { .label = "asic_health", .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, @@ -4586,11 +4907,18 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET: case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: @@ -4605,6 +4933,8 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: @@ -4633,6 +4963,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: @@ -4683,6 +5014,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: @@ -4692,6 +5027,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: @@ -4713,6 +5051,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: @@ -4749,6 +5090,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: @@ -4825,6 +5167,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET: @@ -4834,6 +5180,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: @@ -4855,6 +5204,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: @@ -4885,6 +5237,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: @@ -5080,7 +5433,6 @@ static struct resource mlxplat_mlxcpld_resources[] = { [0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"), }; -static struct platform_device *mlxplat_dev; static struct mlxreg_core_hotplug_platform_data *mlxplat_i2c; static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; static struct mlxreg_core_platform_data *mlxplat_led; @@ -5090,6 +5442,14 @@ static struct mlxreg_core_platform_data *mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS]; static const struct regmap_config *mlxplat_regmap_config; +/* Platform default poweroff function */ +static void mlxplat_poweroff(void) +{ + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + + regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, MLXPLAT_CPLD_HALT_MASK); +} + static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { int i; @@ -5385,6 +5745,28 @@ static int __init mlxplat_dmi_ng800_matched(const struct dmi_system_id *dmi) return 1; } +static int __init mlxplat_dmi_l1_switch_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data); + mlxplat_mux_data = mlxplat_rack_switch_mux_data; + mlxplat_hotplug = &mlxplat_mlxcpld_l1_switch_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_l1_switch_led_data; + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; + mlxplat_fan = &mlxplat_default_fan_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch; + pm_power_off = mlxplat_poweroff; + + return 1; +} + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { { .callback = mlxplat_dmi_default_wc_matched, @@ -5473,6 +5855,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"), }, }, + { + .callback = mlxplat_dmi_l1_switch_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0017"), + }, + }, { .callback = mlxplat_dmi_msn274x_matched, .matches = { @@ -5802,6 +6190,8 @@ static void __exit mlxplat_exit(void) struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; + if (pm_power_off) + pm_power_off = NULL; for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) platform_device_unregister(priv->pdev_wd[i]); if (priv->pdev_fan) From 0170f616f496fcaf25dde0fea042880d4af3089a Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:23 +0200 Subject: [PATCH 69/80] platform: mellanox: Split initialization procedure Split mlxplat_init() into two by adding mlxplat_pre_init(). Motivation is to prepare 'mlx-platform' driver to support systems equipped PCIe based programming logic device. Such systems are supposed to use different system resources, thus this commit separates resources allocation related code. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-7-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 78 ++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 1a07a9994f05..2d33d1e5d427 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -328,6 +328,8 @@ * @pdev_fan - FAN platform devices * @pdev_wd - array of watchdog platform devices * @regmap: device register map + * @hotplug_resources: system hotplug resources + * @hotplug_resources_size: size of system hotplug resources */ struct mlxplat_priv { struct platform_device *pdev_i2c; @@ -338,6 +340,8 @@ struct mlxplat_priv { struct platform_device *pdev_fan; struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS]; void *regmap; + struct resource *hotplug_resources; + unsigned int hotplug_resources_size; }; static struct platform_device *mlxplat_dev; @@ -6002,20 +6006,63 @@ static int mlxplat_mlxcpld_check_wd_capability(void *regmap) return 0; } +static int mlxplat_lpc_cpld_device_init(struct resource **hotplug_resources, + unsigned int *hotplug_resources_size) +{ + int err; + + mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE, + mlxplat_lpc_resources, + ARRAY_SIZE(mlxplat_lpc_resources)); + if (IS_ERR(mlxplat_dev)) + return PTR_ERR(mlxplat_dev); + + mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, + mlxplat_lpc_resources[1].start, 1); + if (!mlxplat_mlxcpld_regmap_ctx.base) { + err = -ENOMEM; + goto fail_devm_ioport_map; + } + + *hotplug_resources = mlxplat_mlxcpld_resources; + *hotplug_resources_size = ARRAY_SIZE(mlxplat_mlxcpld_resources); + + return 0; + +fail_devm_ioport_map: + platform_device_unregister(mlxplat_dev); + return err; +} + +static void mlxplat_lpc_cpld_device_exit(void) +{ + platform_device_unregister(mlxplat_dev); +} + +static int +mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size) +{ + return mlxplat_lpc_cpld_device_init(hotplug_resources, hotplug_resources_size); +} + +static void mlxplat_post_exit(void) +{ + mlxplat_lpc_cpld_device_exit(); +} + static int __init mlxplat_init(void) { + unsigned int hotplug_resources_size; + struct resource *hotplug_resources; struct mlxplat_priv *priv; int i, j, nr, err; if (!dmi_check_system(mlxplat_dmi_table)) return -ENODEV; - mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE, - mlxplat_lpc_resources, - ARRAY_SIZE(mlxplat_lpc_resources)); - - if (IS_ERR(mlxplat_dev)) - return PTR_ERR(mlxplat_dev); + err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size); + if (err) + return err; priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), GFP_KERNEL); @@ -6025,12 +6072,8 @@ static int __init mlxplat_init(void) } platform_set_drvdata(mlxplat_dev, priv); - mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev, - mlxplat_lpc_resources[1].start, 1); - if (!mlxplat_mlxcpld_regmap_ctx.base) { - err = -ENOMEM; - goto fail_alloc; - } + priv->hotplug_resources = hotplug_resources; + priv->hotplug_resources_size = hotplug_resources_size; if (!mlxplat_regmap_config) mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config; @@ -6051,8 +6094,8 @@ static int __init mlxplat_init(void) if (mlxplat_i2c) mlxplat_i2c->regmap = priv->regmap; priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", - nr, mlxplat_mlxcpld_resources, - ARRAY_SIZE(mlxplat_mlxcpld_resources), + nr, priv->hotplug_resources, + priv->hotplug_resources_size, mlxplat_i2c, sizeof(*mlxplat_i2c)); if (IS_ERR(priv->pdev_i2c)) { err = PTR_ERR(priv->pdev_i2c); @@ -6076,8 +6119,8 @@ static int __init mlxplat_init(void) priv->pdev_hotplug = platform_device_register_resndata(&mlxplat_dev->dev, "mlxreg-hotplug", PLATFORM_DEVID_NONE, - mlxplat_mlxcpld_resources, - ARRAY_SIZE(mlxplat_mlxcpld_resources), + priv->hotplug_resources, + priv->hotplug_resources_size, mlxplat_hotplug, sizeof(*mlxplat_hotplug)); if (IS_ERR(priv->pdev_hotplug)) { err = PTR_ERR(priv->pdev_hotplug); @@ -6179,7 +6222,6 @@ fail_platform_mux_register: platform_device_unregister(priv->pdev_mux[i]); platform_device_unregister(priv->pdev_i2c); fail_alloc: - platform_device_unregister(mlxplat_dev); return err; } @@ -6207,7 +6249,7 @@ static void __exit mlxplat_exit(void) platform_device_unregister(priv->pdev_mux[i]); platform_device_unregister(priv->pdev_i2c); - platform_device_unregister(mlxplat_dev); + mlxplat_post_exit(); } module_exit(mlxplat_exit); From 158cd83207768abdba86e408fed3169bb3ad3e9f Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:24 +0200 Subject: [PATCH 70/80] platform: mellanox: Split logic in init and exit flow Split logic in mlxplat_init()/mlxplat_exit() routines. Separate initialization of I2C infrastructure and others platform drivers. Motivation is to provide synchronization between I2C bus and mux drivers and other drivers using this infrastructure. I2C main bus and MUX busses are implemented in FPGA logic. On some new systems the numbers allocated for these busses could be variable depending on order of initialization of I2C native busses. Since bus numbers are passed to some other platform drivers during initialization flow, it is necessary to synchronize completion of I2C infrastructure drivers and activation of rest of drivers. Thus initialization flow will be performed in synchronized order. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-8-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 375 +++++++++++++++++----------- 1 file changed, 235 insertions(+), 140 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 2d33d1e5d427..bd94d82ecce5 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -319,6 +319,9 @@ /* Default value for PWM control register for rack switch system */ #define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4 +#define MLXPLAT_I2C_MAIN_BUS_NOTIFIED 0x01 +#define MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED 0x02 + /* mlxplat_priv - platform private data * @pdev_i2c - i2c controller platform device * @pdev_mux - array of mux platform devices @@ -330,6 +333,7 @@ * @regmap: device register map * @hotplug_resources: system hotplug resources * @hotplug_resources_size: size of system hotplug resources + * @hi2c_main_init_status: init status of I2C main bus */ struct mlxplat_priv { struct platform_device *pdev_i2c; @@ -342,9 +346,11 @@ struct mlxplat_priv { void *regmap; struct resource *hotplug_resources; unsigned int hotplug_resources_size; + u8 i2c_main_init_status; }; static struct platform_device *mlxplat_dev; +static int mlxplat_i2c_main_complition_notify(void *handle, int id); /* Regions for LPC I2C controller and LPC base register space */ static const struct resource mlxplat_lpc_resources[] = { @@ -379,6 +385,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = { .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET, .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C, + .completion_notify = mlxplat_i2c_main_complition_notify, }; /* Platform default channels */ @@ -6050,12 +6057,225 @@ static void mlxplat_post_exit(void) mlxplat_lpc_cpld_device_exit(); } +static int mlxplat_post_init(struct mlxplat_priv *priv) +{ + int i = 0, err; + + /* Add hotplug driver */ + if (mlxplat_hotplug) { + mlxplat_hotplug->regmap = priv->regmap; + priv->pdev_hotplug = + platform_device_register_resndata(&mlxplat_dev->dev, + "mlxreg-hotplug", PLATFORM_DEVID_NONE, + priv->hotplug_resources, + priv->hotplug_resources_size, + mlxplat_hotplug, sizeof(*mlxplat_hotplug)); + if (IS_ERR(priv->pdev_hotplug)) { + err = PTR_ERR(priv->pdev_hotplug); + goto fail_platform_hotplug_register; + } + } + + /* Add LED driver. */ + if (mlxplat_led) { + mlxplat_led->regmap = priv->regmap; + priv->pdev_led = + platform_device_register_resndata(&mlxplat_dev->dev, "leds-mlxreg", + PLATFORM_DEVID_NONE, NULL, 0, mlxplat_led, + sizeof(*mlxplat_led)); + if (IS_ERR(priv->pdev_led)) { + err = PTR_ERR(priv->pdev_led); + goto fail_platform_leds_register; + } + } + + /* Add registers io access driver. */ + if (mlxplat_regs_io) { + mlxplat_regs_io->regmap = priv->regmap; + priv->pdev_io_regs = platform_device_register_resndata(&mlxplat_dev->dev, + "mlxreg-io", + PLATFORM_DEVID_NONE, NULL, + 0, mlxplat_regs_io, + sizeof(*mlxplat_regs_io)); + if (IS_ERR(priv->pdev_io_regs)) { + err = PTR_ERR(priv->pdev_io_regs); + goto fail_platform_io_register; + } + } + + /* Add FAN driver. */ + if (mlxplat_fan) { + mlxplat_fan->regmap = priv->regmap; + priv->pdev_fan = platform_device_register_resndata(&mlxplat_dev->dev, "mlxreg-fan", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_fan, + sizeof(*mlxplat_fan)); + if (IS_ERR(priv->pdev_fan)) { + err = PTR_ERR(priv->pdev_fan); + goto fail_platform_fan_register; + } + } + + /* Add WD drivers. */ + err = mlxplat_mlxcpld_check_wd_capability(priv->regmap); + if (err) + goto fail_platform_wd_register; + for (i = 0; i < MLXPLAT_CPLD_WD_MAX_DEVS; i++) { + if (mlxplat_wd_data[i]) { + mlxplat_wd_data[i]->regmap = priv->regmap; + priv->pdev_wd[i] = + platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", i, + NULL, 0, mlxplat_wd_data[i], + sizeof(*mlxplat_wd_data[i])); + if (IS_ERR(priv->pdev_wd[i])) { + err = PTR_ERR(priv->pdev_wd[i]); + goto fail_platform_wd_register; + } + } + } + + return 0; + +fail_platform_wd_register: + while (--i >= 0) + platform_device_unregister(priv->pdev_wd[i]); +fail_platform_fan_register: + if (mlxplat_regs_io) + platform_device_unregister(priv->pdev_io_regs); +fail_platform_io_register: + if (mlxplat_led) + platform_device_unregister(priv->pdev_led); +fail_platform_leds_register: + if (mlxplat_hotplug) + platform_device_unregister(priv->pdev_hotplug); +fail_platform_hotplug_register: + return err; +} + +static void mlxplat_pre_exit(struct mlxplat_priv *priv) +{ + int i; + + for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_wd[i]); + if (priv->pdev_fan) + platform_device_unregister(priv->pdev_fan); + if (priv->pdev_io_regs) + platform_device_unregister(priv->pdev_io_regs); + if (priv->pdev_led) + platform_device_unregister(priv->pdev_led); + if (priv->pdev_hotplug) + platform_device_unregister(priv->pdev_hotplug); +} + +static int +mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent, + struct i2c_adapter *adapters[]) +{ + struct mlxplat_priv *priv = handle; + + return mlxplat_post_init(priv); +} + +static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv) +{ + int i, err; + + if (!priv->pdev_i2c) { + priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_NOTIFIED; + return 0; + } + + priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED; + for (i = 0; i < mlxplat_mux_num; i++) { + priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, + "i2c-mux-reg", i, NULL, 0, + &mlxplat_mux_data[i], + sizeof(mlxplat_mux_data[i])); + if (IS_ERR(priv->pdev_mux[i])) { + err = PTR_ERR(priv->pdev_mux[i]); + goto fail_platform_mux_register; + } + } + + return mlxplat_i2c_mux_complition_notify(priv, NULL, NULL); + +fail_platform_mux_register: + while (--i >= 0) + platform_device_unregister(priv->pdev_mux[i]); + return err; +} + +static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv) +{ + int i; + + for (i = mlxplat_mux_num - 1; i >= 0 ; i--) { + if (priv->pdev_mux[i]) + platform_device_unregister(priv->pdev_mux[i]); + } + + mlxplat_post_exit(); +} + +static int mlxplat_i2c_main_complition_notify(void *handle, int id) +{ + struct mlxplat_priv *priv = handle; + + return mlxplat_i2c_mux_topolgy_init(priv); +} + +static int mlxplat_i2c_main_init(struct mlxplat_priv *priv) +{ + int nr, err; + + if (!mlxplat_i2c) + return 0; + + err = mlxplat_mlxcpld_verify_bus_topology(&nr); + if (nr < 0) + goto fail_mlxplat_mlxcpld_verify_bus_topology; + + nr = (nr == mlxplat_max_adap_num) ? -1 : nr; + mlxplat_i2c->regmap = priv->regmap; + mlxplat_i2c->handle = priv; + + priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", + nr, priv->hotplug_resources, + priv->hotplug_resources_size, + mlxplat_i2c, sizeof(*mlxplat_i2c)); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); + goto fail_platform_i2c_register; + } + + if (priv->i2c_main_init_status == MLXPLAT_I2C_MAIN_BUS_NOTIFIED) { + err = mlxplat_i2c_mux_topolgy_init(priv); + if (err) + goto fail_mlxplat_i2c_mux_topolgy_init; + } + + return 0; + +fail_mlxplat_i2c_mux_topolgy_init: +fail_platform_i2c_register: +fail_mlxplat_mlxcpld_verify_bus_topology: + return err; +} + +static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv) +{ + mlxplat_i2c_mux_topolgy_exit(priv); + if (priv->pdev_i2c) + platform_device_unregister(priv->pdev_i2c); +} + static int __init mlxplat_init(void) { unsigned int hotplug_resources_size; struct resource *hotplug_resources; struct mlxplat_priv *priv; - int i, j, nr, err; + int i, err; if (!dmi_check_system(mlxplat_dmi_table)) return -ENODEV; @@ -6071,7 +6291,6 @@ static int __init mlxplat_init(void) goto fail_alloc; } platform_set_drvdata(mlxplat_dev, priv); - priv->hotplug_resources = hotplug_resources; priv->hotplug_resources_size = hotplug_resources_size; @@ -6086,142 +6305,33 @@ static int __init mlxplat_init(void) goto fail_alloc; } - err = mlxplat_mlxcpld_verify_bus_topology(&nr); - if (nr < 0) - goto fail_alloc; - - nr = (nr == mlxplat_max_adap_num) ? -1 : nr; - if (mlxplat_i2c) - mlxplat_i2c->regmap = priv->regmap; - priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", - nr, priv->hotplug_resources, - priv->hotplug_resources_size, - mlxplat_i2c, sizeof(*mlxplat_i2c)); - if (IS_ERR(priv->pdev_i2c)) { - err = PTR_ERR(priv->pdev_i2c); - goto fail_alloc; - } - - for (i = 0; i < mlxplat_mux_num; i++) { - priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, - "i2c-mux-reg", i, NULL, 0, - &mlxplat_mux_data[i], - sizeof(mlxplat_mux_data[i])); - if (IS_ERR(priv->pdev_mux[i])) { - err = PTR_ERR(priv->pdev_mux[i]); - goto fail_platform_mux_register; - } - } - - /* Add hotplug driver */ - if (mlxplat_hotplug) { - mlxplat_hotplug->regmap = priv->regmap; - priv->pdev_hotplug = - platform_device_register_resndata(&mlxplat_dev->dev, - "mlxreg-hotplug", PLATFORM_DEVID_NONE, - priv->hotplug_resources, - priv->hotplug_resources_size, - mlxplat_hotplug, sizeof(*mlxplat_hotplug)); - if (IS_ERR(priv->pdev_hotplug)) { - err = PTR_ERR(priv->pdev_hotplug); - goto fail_platform_mux_register; - } - } - /* Set default registers. */ - for (j = 0; j < mlxplat_regmap_config->num_reg_defaults; j++) { + for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) { err = regmap_write(priv->regmap, - mlxplat_regmap_config->reg_defaults[j].reg, - mlxplat_regmap_config->reg_defaults[j].def); + mlxplat_regmap_config->reg_defaults[i].reg, + mlxplat_regmap_config->reg_defaults[i].def); if (err) - goto fail_platform_mux_register; + goto fail_regmap_write; } - /* Add LED driver. */ - if (mlxplat_led) { - mlxplat_led->regmap = priv->regmap; - priv->pdev_led = - platform_device_register_resndata(&mlxplat_dev->dev, "leds-mlxreg", - PLATFORM_DEVID_NONE, NULL, 0, mlxplat_led, - sizeof(*mlxplat_led)); - if (IS_ERR(priv->pdev_led)) { - err = PTR_ERR(priv->pdev_led); - goto fail_platform_hotplug_register; - } - } - - /* Add registers io access driver. */ - if (mlxplat_regs_io) { - mlxplat_regs_io->regmap = priv->regmap; - priv->pdev_io_regs = platform_device_register_resndata(&mlxplat_dev->dev, - "mlxreg-io", - PLATFORM_DEVID_NONE, NULL, - 0, mlxplat_regs_io, - sizeof(*mlxplat_regs_io)); - if (IS_ERR(priv->pdev_io_regs)) { - err = PTR_ERR(priv->pdev_io_regs); - goto fail_platform_led_register; - } - } - - /* Add FAN driver. */ - if (mlxplat_fan) { - mlxplat_fan->regmap = priv->regmap; - priv->pdev_fan = platform_device_register_resndata(&mlxplat_dev->dev, "mlxreg-fan", - PLATFORM_DEVID_NONE, NULL, 0, - mlxplat_fan, - sizeof(*mlxplat_fan)); - if (IS_ERR(priv->pdev_fan)) { - err = PTR_ERR(priv->pdev_fan); - goto fail_platform_io_regs_register; - } - } - - /* Add WD drivers. */ - err = mlxplat_mlxcpld_check_wd_capability(priv->regmap); + err = mlxplat_i2c_main_init(priv); if (err) - goto fail_platform_wd_register; - for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { - if (mlxplat_wd_data[j]) { - mlxplat_wd_data[j]->regmap = priv->regmap; - priv->pdev_wd[j] = - platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", j, - NULL, 0, mlxplat_wd_data[j], - sizeof(*mlxplat_wd_data[j])); - if (IS_ERR(priv->pdev_wd[j])) { - err = PTR_ERR(priv->pdev_wd[j]); - goto fail_platform_wd_register; - } - } - } + goto fail_mlxplat_i2c_main_init; /* Sync registers with hardware. */ regcache_mark_dirty(priv->regmap); err = regcache_sync(priv->regmap); if (err) - goto fail_platform_wd_register; + goto fail_regcache_sync; return 0; -fail_platform_wd_register: - while (--j >= 0) - platform_device_unregister(priv->pdev_wd[j]); - if (mlxplat_fan) - platform_device_unregister(priv->pdev_fan); -fail_platform_io_regs_register: - if (mlxplat_regs_io) - platform_device_unregister(priv->pdev_io_regs); -fail_platform_led_register: - if (mlxplat_led) - platform_device_unregister(priv->pdev_led); -fail_platform_hotplug_register: - if (mlxplat_hotplug) - platform_device_unregister(priv->pdev_hotplug); -fail_platform_mux_register: - while (--i >= 0) - platform_device_unregister(priv->pdev_mux[i]); - platform_device_unregister(priv->pdev_i2c); +fail_regcache_sync: + mlxplat_pre_exit(priv); +fail_mlxplat_i2c_main_init: +fail_regmap_write: fail_alloc: + mlxplat_post_exit(); return err; } @@ -6230,26 +6340,11 @@ module_init(mlxplat_init); static void __exit mlxplat_exit(void) { struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); - int i; if (pm_power_off) pm_power_off = NULL; - for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_wd[i]); - if (priv->pdev_fan) - platform_device_unregister(priv->pdev_fan); - if (priv->pdev_io_regs) - platform_device_unregister(priv->pdev_io_regs); - if (priv->pdev_led) - platform_device_unregister(priv->pdev_led); - if (priv->pdev_hotplug) - platform_device_unregister(priv->pdev_hotplug); - - for (i = mlxplat_mux_num - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - - platform_device_unregister(priv->pdev_i2c); - mlxplat_post_exit(); + mlxplat_pre_exit(priv); + mlxplat_i2c_main_exit(priv); } module_exit(mlxplat_exit); From 233fd7e44cd7363ede8025619291b98475024c30 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:25 +0200 Subject: [PATCH 71/80] platform: mellanox: Extend all systems with I2C notification callback Motivation is to provide synchronization between I2C main bus and other platform drivers using this notification callback. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-9-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index bd94d82ecce5..e541046c9100 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -363,6 +363,11 @@ static const struct resource mlxplat_lpc_resources[] = { IORESOURCE_IO), }; +/* Platform systems default i2c data */ +static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = { + .completion_notify = mlxplat_i2c_main_complition_notify, +}; + /* Platform i2c next generation systems data */ static struct mlxreg_core_data mlxplat_mlxcpld_i2c_ng_items_data[] = { { @@ -5479,6 +5484,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_led = &mlxplat_default_led_data; mlxplat_regs_io = &mlxplat_default_regs_io_data; mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; return 1; } @@ -5501,6 +5507,7 @@ static int __init mlxplat_dmi_default_wc_matched(const struct dmi_system_id *dmi mlxplat_led = &mlxplat_default_led_wc_data; mlxplat_regs_io = &mlxplat_default_regs_io_data; mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; return 1; } @@ -5548,6 +5555,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_led = &mlxplat_msn21xx_led_data; mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; return 1; } @@ -5570,6 +5578,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) mlxplat_led = &mlxplat_default_led_data; mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; return 1; } @@ -5592,6 +5601,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) mlxplat_led = &mlxplat_msn21xx_led_data; mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; return 1; } @@ -5641,6 +5651,7 @@ static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi) mlxplat_fan = &mlxplat_default_fan_data; for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data; mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_comex; return 1; From 26e118ea98cf5ec0b53198e643d5fa8d99b73b49 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:26 +0200 Subject: [PATCH 72/80] platform/mellanox: mlxreg-hotplug: Allow more flexible hotplug events configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently hotplug configuration in logic device assumes that all items are provided with no holes. Thus, any group of hotplug events, associated with the specific status/event/mask registers is configured in those registers successively from bit zero to bit #n (#n < 8). This logic is changed int order to allow non-successive definition to support configuration with the skipped bits – for example bits 3, 5, 7 in status/event/mask registers can be associated with hotplug events, while others can be skipped. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-10-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-hotplug.c | 28 ++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index 117bc3f395fd..b7dcc64cd238 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -239,6 +239,17 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev, #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i] #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i] +static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit) +{ + int i, j; + + for (i = 0, j = -1; i <= bit; i++) { + if (mask & BIT(i)) + j++; + } + return j; +} + static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) { struct mlxreg_core_hotplug_platform_data *pdata; @@ -246,7 +257,7 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) struct mlxreg_core_data *data; unsigned long mask; u32 regval; - int num_attrs = 0, id = 0, i, j, k, ret; + int num_attrs = 0, id = 0, i, j, k, count, ret; pdata = dev_get_platdata(&priv->pdev->dev); item = pdata->items; @@ -272,7 +283,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) /* Go over all unmasked units within item. */ mask = item->mask; k = 0; - for_each_set_bit(j, &mask, item->count) { + count = item->ind ? item->ind : item->count; + for_each_set_bit(j, &mask, count) { if (data->capability) { /* * Read capability register and skip non @@ -282,16 +294,17 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv) data->capability, ®val); if (ret) return ret; + if (!(regval & data->bit)) { data++; continue; } } + PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr; PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, data->label); - if (!PRIV_ATTR(id)->name) { dev_err(priv->dev, "Memory allocation failed for attr %d.\n", id); @@ -365,9 +378,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, regval &= item->mask; asserted = item->cache ^ regval; item->cache = regval; - for_each_set_bit(bit, &asserted, 8) { - data = item->data + bit; + int pos; + + pos = mlxreg_hotplug_item_label_index_get(item->mask, bit); + if (pos < 0) + goto out; + + data = item->data + pos; if (regval & BIT(bit)) { if (item->inversed) mlxreg_hotplug_device_destroy(priv, data, item->kind); From 26917eab144c8515435ef9175fdd5dddf9f0f000 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:27 +0200 Subject: [PATCH 73/80] platform_data/mlxreg: Add field with mapped resource address Add field with PCIe remapped based address for passing it across relevant platform drivers sharing common system resources. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-11-vadimp@nvidia.com Signed-off-by: Hans de Goede --- include/linux/platform_data/mlxreg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index a6bd74e29b6b..0b9f81a6f753 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -216,6 +216,7 @@ struct mlxreg_core_platform_data { * @mask_low: low aggregation interrupt common mask; * @deferred_nr: I2C adapter number must be exist prior probing execution; * @shift_nr: I2C adapter numbers must be incremented by this value; + * @addr: mapped resource address; * @handle: handle to be passed by callback; * @completion_notify: callback to notify when platform driver probing is done; */ @@ -230,6 +231,7 @@ struct mlxreg_core_hotplug_platform_data { u32 mask_low; int deferred_nr; int shift_nr; + void __iomem *addr; void *handle; int (*completion_notify)(void *handle, int id); }; From cefdbc7815660be4d0f2d290860dcfb0f9d285e4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:28 +0200 Subject: [PATCH 74/80] platform: mellanox: mlx-platform: Add mux selection register to regmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend writeable, readable, volatile registers of the 'regmap' object with for I2C mux selector registers. The motivation is to pass this object extended with selector registers to I2C mux driver working over ‘regmap’. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-12-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index e541046c9100..60062d9f3b9b 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -139,6 +139,10 @@ #define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2 #define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3 #define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9 +#define MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET 0xdb +#define MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET 0xda +#define MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET 0xdc +#define MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET 0xdd #define MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET 0xde #define MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET 0xdf #define MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET 0xe0 @@ -172,23 +176,19 @@ #define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc #define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 -#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb -#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda -#define MLXPLAT_CPLD_LPC_I2C_CH3_OFF 0xdc -#define MLXPLAT_CPLD_LPC_I2C_CH4_OFF 0xdd #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ + MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET) | \ MLXPLAT_CPLD_LPC_PIO_OFFSET) #define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ + MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET) | \ MLXPLAT_CPLD_LPC_PIO_OFFSET) #define MLXPLAT_CPLD_LPC_REG3 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH3_OFF) | \ + MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET) | \ MLXPLAT_CPLD_LPC_PIO_OFFSET) #define MLXPLAT_CPLD_LPC_REG4 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH4_OFF) | \ + MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET) | \ MLXPLAT_CPLD_LPC_PIO_OFFSET) /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ @@ -4980,6 +4980,10 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET: @@ -5107,6 +5111,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET: case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: @@ -5254,6 +5262,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET: case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET: case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET: From 50b823fdd357ec0f2fd0a1a0b5104704916fd620 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:29 +0200 Subject: [PATCH 75/80] platform: mellanox: mlx-platform: Move bus shift assignment out of the loop Move assignment of bus shift setting out of the loop to avoid redundant operation. Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-13-vadimp@nvidia.com Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 60062d9f3b9b..7b6779cdb134 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -6008,10 +6008,11 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) shift = *nr - mlxplat_mux_data[i].parent; mlxplat_mux_data[i].parent = *nr; mlxplat_mux_data[i].base_nr += shift; - if (shift > 0) - mlxplat_hotplug->shift_nr = shift; } + if (shift > 0) + mlxplat_hotplug->shift_nr = shift; + return 0; } From e7210563432a6c6fa65a9c5c11ece2a0adbeeda2 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 8 Feb 2023 08:33:30 +0200 Subject: [PATCH 76/80] Documentation/ABI: Add new attribute for mlxreg-io sysfs interfaces Add description for new attributes added for rack manager switch and NG800 family systems. Attributes related to power converter board: - reset_pwr_converter_fail; - pwr_converter_prog_en; Attributes related to External Root of Trust (EROT) devices recovery: - erot1_ap_reset; - erot2_ap_reset; - erot1_recovery; - erot2_recovery; - erot1_reset; - erot2_reset; - erot1_wp; - erot2_wp; - spi_chnl_select; Attributes related to clock board failures and recovery: - clk_brd1_boot_fail; - clk_brd2_boot_fail; - clk_brd_fail; - clk_brd_prog_en; Attributes related to power failures: - reset_ac_ok_fail; - asic_pg_fail; Signed-off-by: Vadim Pasternak Reviewed-by: Michael Shych Link: https://lore.kernel.org/r/20230208063331.15560-14-vadimp@nvidia.com Signed-off-by: Hans de Goede --- .../ABI/stable/sysfs-driver-mlxreg-io | 122 +++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index af0cbf143c48..60953903d007 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -522,7 +522,6 @@ Description: These files allow to each of ASICs by writing 1. The files are write only. - What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/comm_chnl_ready Date: July 2022 KernelVersion: 5.20 @@ -542,3 +541,124 @@ Description: The file indicates COME module hardware configuration. The purpose is to expose some minor BOM changes for the same system SKU. The file is read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_pwr_converter_fail +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: This file shows the system reset cause due to power converter + devices failure. + Value 1 in file means this is reset cause, 0 - otherwise. + + The file is read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_ap_reset +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_ap_reset +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: These files aim to monitor the status of the External Root of Trust (EROT) + processor's RESET output to the Application Processor (AP). + By reading this file, could be determined if the EROT has invalidated or + revoked AP Firmware, at which point it will hold the AP in RESET until a + valid firmware is loaded. This protects the AP from running an + unauthorized firmware. In the normal flow, the AP reset should be released + after the EROT validates the integrity of the FW, and it should be done so + as quickly as possible so that the AP boots before the CPU starts to + communicate to each ASIC. + + The files are read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_recovery +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_recovery +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_reset +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_reset +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: These files aim to perform External Root of Trust (EROT) recovery + sequence after EROT device failure. + These EROT devices protect ASICs from unauthorized access and in normal + flow their reset should be released with system power – earliest power + up stage, so that EROTs can begin boot and authentication process before + CPU starts to communicate to ASICs. + Issuing a reset to the EROT while asserting the recovery signal will cause + the EROT Application Processor to enter recovery mode so that the EROT FW + can be updated/recovered. + For reset/recovery the related file should be toggled by 1/0. + + The files are read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_wp +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_wp +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: These files allow access to External Root of Trust (EROT) for reset + and recovery sequence after EROT device failure. + Default is 0 (programming disabled). + If the system is in locked-down mode writing this file will not be allowed. + + The files are read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/spi_chnl_select +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: This file allows SPI chip selection for External Root of Trust (EROT) + device Out-of-Band recovery. + File can be written with 0 or with 1. It selects which EROT can be accessed + through SPI device. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_pg_fail +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak vadimp@nvidia.com +Description: This file shows ASIC Power Good status. + Value 1 in file means ASIC Power Good failed, 0 - otherwise. + + The file is read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd1_boot_fail +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd2_boot_fail +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd_fail +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak vadimp@nvidia.com +Description: These files are related to clock boards status in system. + - clk_brd1_boot_fail: warning about 1-st clock board failed to boot from CI. + - clk_brd2_boot_fail: warning about 2-nd clock board failed to boot from CI. + - clk_brd_fail: error about common clock board boot failure. + + The files are read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd_prog_en +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: This file enables programming of clock boards. + Default is 0 (programming disabled). + If the system is in locked-down mode writing this file will not be allowed. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_converter_prog_en +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: This file enables programming of power converters. + Default is 0 (programming disabled). + If the system is in locked-down mode writing this file will not be allowed. + + The file is read/write. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_ac_ok_fail +Date: February 2023 +KernelVersion: 6.3 +Contact: Vadim Pasternak +Description: This file shows the system reset cause due to AC power failure. + Value 1 in file means this is reset cause, 0 - otherwise. + + The file is read only. From 3b7eeff93d291299841f943a5e9b43bb160b3992 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 9 Feb 2023 22:15:02 +0100 Subject: [PATCH 77/80] platform/x86: dell-ddv: Add hwmon support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to bugreport 216655 on bugzilla triggered by the dell-smm-hwmon driver, the contents of the sensor buffers could be almost completely decoded. Add an hwmon interface for exposing the fan and thermal sensor values. Since the WMI interface can be quite slow on some machines, the sensor buffers are cached for 1 second to lessen the performance impact. The debugfs interface remains in place to aid in reverse-engineering of unknown sensor types and the thermal buffer. Tested-by: Antonín Skala Tested-by: Gustavo Walbon Signed-off-by: Armin Wolf Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20230209211503.2739-2-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/Kconfig | 8 +- drivers/platform/x86/dell/dell-wmi-ddv.c | 490 ++++++++++++++++++++++- 2 files changed, 493 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index d319de8f2132..bdd78076b1d7 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -192,12 +192,12 @@ config DELL_WMI_DESCRIPTOR config DELL_WMI_DDV tristate "Dell WMI sensors Support" default m - depends on ACPI_BATTERY depends on ACPI_WMI + depends on ACPI_BATTERY || HWMON help - This option adds support for WMI-based sensors like - battery temperature sensors found on some Dell notebooks. - It also supports reading of the battery ePPID. + This option adds support for WMI-based fan and thermal sensors + found on some Dell notebooks. It also supports various WMI-based battery + extras like reading of the battery temperature and ePPID. To compile this drivers as a module, choose M here: the module will be called dell-wmi-ddv. diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index 9695bf493ea6..d81dc4dd93e3 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -12,19 +12,27 @@ #include #include #include +#include #include +#include #include #include +#include #include +#include #include +#include #include #include #include #include +#include #include #include +#include + #define DRIVER_NAME "dell-wmi-ddv" #define DELL_DDV_SUPPORTED_VERSION_MIN 2 @@ -63,13 +71,63 @@ enum dell_ddv_method { DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22, }; +struct fan_sensor_entry { + u8 type; + __le16 rpm; +} __packed; + +struct thermal_sensor_entry { + u8 type; + s8 now; + s8 min; + s8 max; + u8 unknown; +} __packed; + +struct combined_channel_info { + struct hwmon_channel_info info; + u32 config[]; +}; + +struct combined_chip_info { + struct hwmon_chip_info chip; + const struct hwmon_channel_info *info[]; +}; + +struct dell_wmi_ddv_sensors { + struct mutex lock; /* protect caching */ + unsigned long timestamp; + union acpi_object *obj; + u64 entries; +}; + struct dell_wmi_ddv_data { struct acpi_battery_hook hook; struct device_attribute temp_attr; struct device_attribute eppid_attr; + struct dell_wmi_ddv_sensors fans; + struct dell_wmi_ddv_sensors temps; struct wmi_device *wdev; }; +static const char * const fan_labels[] = { + "CPU Fan", + "Chassis Motherboard Fan", + "Video Fan", + "Power Supply Fan", + "Chipset Fan", + "Memory Fan", + "PCI Fan", + "HDD Fan", +}; + +static const char * const fan_dock_labels[] = { + "Docking Chassis/Motherboard Fan", + "Docking Video Fan", + "Docking Power Supply Fan", + "Docking Chipset Fan", +}; + static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg, union acpi_object **result, acpi_object_type type) { @@ -171,6 +229,410 @@ static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_meth return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING); } +/* + * Needs to be called with lock held, except during initialization. + */ +static int dell_wmi_ddv_update_sensors(struct wmi_device *wdev, enum dell_ddv_method method, + struct dell_wmi_ddv_sensors *sensors, size_t entry_size) +{ + u64 buffer_size, rem, entries; + union acpi_object *obj; + u8 *buffer; + int ret; + + if (sensors->obj) { + if (time_before(jiffies, sensors->timestamp + HZ)) + return 0; + + kfree(sensors->obj); + sensors->obj = NULL; + } + + ret = dell_wmi_ddv_query_buffer(wdev, method, 0, &obj); + if (ret < 0) + return ret; + + /* buffer format sanity check */ + buffer_size = obj->package.elements[0].integer.value; + buffer = obj->package.elements[1].buffer.pointer; + entries = div64_u64_rem(buffer_size, entry_size, &rem); + if (rem != 1 || buffer[buffer_size - 1] != 0xff) { + ret = -ENOMSG; + goto err_free; + } + + if (!entries) { + ret = -ENODATA; + goto err_free; + } + + sensors->obj = obj; + sensors->entries = entries; + sensors->timestamp = jiffies; + + return 0; + +err_free: + kfree(obj); + + return ret; +} + +static umode_t dell_wmi_ddv_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + return 0444; +} + +static int dell_wmi_ddv_fan_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel, + long *val) +{ + struct fan_sensor_entry *entry; + int ret; + + ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION, + &data->fans, sizeof(*entry)); + if (ret < 0) + return ret; + + if (channel >= data->fans.entries) + return -ENXIO; + + entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer; + switch (attr) { + case hwmon_fan_input: + *val = get_unaligned_le16(&entry[channel].rpm); + return 0; + default: + break; + } + + return -EOPNOTSUPP; +} + +static int dell_wmi_ddv_temp_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel, + long *val) +{ + struct thermal_sensor_entry *entry; + int ret; + + ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, + &data->temps, sizeof(*entry)); + if (ret < 0) + return ret; + + if (channel >= data->temps.entries) + return -ENXIO; + + entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer; + switch (attr) { + case hwmon_temp_input: + *val = entry[channel].now * 1000; + return 0; + case hwmon_temp_min: + *val = entry[channel].min * 1000; + return 0; + case hwmon_temp_max: + *val = entry[channel].max * 1000; + return 0; + default: + break; + } + + return -EOPNOTSUPP; +} + +static int dell_wmi_ddv_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + struct dell_wmi_ddv_data *data = dev_get_drvdata(dev); + int ret; + + switch (type) { + case hwmon_fan: + mutex_lock(&data->fans.lock); + ret = dell_wmi_ddv_fan_read_channel(data, attr, channel, val); + mutex_unlock(&data->fans.lock); + return ret; + case hwmon_temp: + mutex_lock(&data->temps.lock); + ret = dell_wmi_ddv_temp_read_channel(data, attr, channel, val); + mutex_unlock(&data->temps.lock); + return ret; + default: + break; + } + + return -EOPNOTSUPP; +} + +static int dell_wmi_ddv_fan_read_string(struct dell_wmi_ddv_data *data, int channel, + const char **str) +{ + struct fan_sensor_entry *entry; + int ret; + u8 type; + + ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION, + &data->fans, sizeof(*entry)); + if (ret < 0) + return ret; + + if (channel >= data->fans.entries) + return -ENXIO; + + entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer; + type = entry[channel].type; + switch (type) { + case 0x00 ... 0x07: + *str = fan_labels[type]; + break; + case 0x11 ... 0x14: + *str = fan_dock_labels[type - 0x11]; + break; + default: + *str = "Unknown Fan"; + break; + } + + return 0; +} + +static int dell_wmi_ddv_temp_read_string(struct dell_wmi_ddv_data *data, int channel, + const char **str) +{ + struct thermal_sensor_entry *entry; + int ret; + + ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, + &data->temps, sizeof(*entry)); + if (ret < 0) + return ret; + + if (channel >= data->temps.entries) + return -ENXIO; + + entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer; + switch (entry[channel].type) { + case 0x00: + *str = "CPU"; + break; + case 0x11: + *str = "Video"; + break; + case 0x22: + *str = "Memory"; /* sometimes called DIMM */ + break; + case 0x33: + *str = "Other"; + break; + case 0x44: + *str = "Ambient"; /* sometimes called SKIN */ + break; + case 0x52: + *str = "SODIMM"; + break; + case 0x55: + *str = "HDD"; + break; + case 0x62: + *str = "SODIMM 2"; + break; + case 0x73: + *str = "NB"; + break; + case 0x83: + *str = "Charger"; + break; + case 0xbb: + *str = "Memory 3"; + break; + default: + *str = "Unknown"; + break; + } + + return 0; +} + +static int dell_wmi_ddv_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, const char **str) +{ + struct dell_wmi_ddv_data *data = dev_get_drvdata(dev); + int ret; + + switch (type) { + case hwmon_fan: + switch (attr) { + case hwmon_fan_label: + mutex_lock(&data->fans.lock); + ret = dell_wmi_ddv_fan_read_string(data, channel, str); + mutex_unlock(&data->fans.lock); + return ret; + default: + break; + } + break; + case hwmon_temp: + switch (attr) { + case hwmon_temp_label: + mutex_lock(&data->temps.lock); + ret = dell_wmi_ddv_temp_read_string(data, channel, str); + mutex_unlock(&data->temps.lock); + return ret; + default: + break; + } + break; + default: + break; + } + + return -EOPNOTSUPP; +} + +static const struct hwmon_ops dell_wmi_ddv_ops = { + .is_visible = dell_wmi_ddv_is_visible, + .read = dell_wmi_ddv_read, + .read_string = dell_wmi_ddv_read_string, +}; + +static struct hwmon_channel_info *dell_wmi_ddv_channel_create(struct device *dev, u64 count, + enum hwmon_sensor_types type, + u32 config) +{ + struct combined_channel_info *cinfo; + int i; + + cinfo = devm_kzalloc(dev, struct_size(cinfo, config, count + 1), GFP_KERNEL); + if (!cinfo) + return ERR_PTR(-ENOMEM); + + cinfo->info.type = type; + cinfo->info.config = cinfo->config; + + for (i = 0; i < count; i++) + cinfo->config[i] = config; + + return &cinfo->info; +} + +static void dell_wmi_ddv_hwmon_cache_invalidate(struct dell_wmi_ddv_sensors *sensors) +{ + mutex_lock(&sensors->lock); + kfree(sensors->obj); + sensors->obj = NULL; + mutex_unlock(&sensors->lock); +} + +static void dell_wmi_ddv_hwmon_cache_destroy(void *data) +{ + struct dell_wmi_ddv_sensors *sensors = data; + + mutex_destroy(&sensors->lock); + kfree(sensors->obj); +} + +static struct hwmon_channel_info *dell_wmi_ddv_channel_init(struct wmi_device *wdev, + enum dell_ddv_method method, + struct dell_wmi_ddv_sensors *sensors, + size_t entry_size, + enum hwmon_sensor_types type, + u32 config) +{ + struct hwmon_channel_info *info; + int ret; + + ret = dell_wmi_ddv_update_sensors(wdev, method, sensors, entry_size); + if (ret < 0) + return ERR_PTR(ret); + + mutex_init(&sensors->lock); + + ret = devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors); + if (ret < 0) + return ERR_PTR(ret); + + info = dell_wmi_ddv_channel_create(&wdev->dev, sensors->entries, type, config); + if (IS_ERR(info)) + devm_release_action(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors); + + return info; +} + +static int dell_wmi_ddv_hwmon_add(struct dell_wmi_ddv_data *data) +{ + struct wmi_device *wdev = data->wdev; + struct combined_chip_info *cinfo; + struct hwmon_channel_info *info; + struct device *hdev; + int index = 0; + int ret; + + if (!devres_open_group(&wdev->dev, dell_wmi_ddv_hwmon_add, GFP_KERNEL)) + return -ENOMEM; + + cinfo = devm_kzalloc(&wdev->dev, struct_size(cinfo, info, 4), GFP_KERNEL); + if (!cinfo) { + ret = -ENOMEM; + + goto err_release; + } + + cinfo->chip.ops = &dell_wmi_ddv_ops; + cinfo->chip.info = cinfo->info; + + info = dell_wmi_ddv_channel_create(&wdev->dev, 1, hwmon_chip, HWMON_C_REGISTER_TZ); + if (IS_ERR(info)) { + ret = PTR_ERR(info); + + goto err_release; + } + + cinfo->info[index] = info; + index++; + + info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_FAN_SENSOR_INFORMATION, &data->fans, + sizeof(struct fan_sensor_entry), hwmon_fan, + (HWMON_F_INPUT | HWMON_F_LABEL)); + if (!IS_ERR(info)) { + cinfo->info[index] = info; + index++; + } + + info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, &data->temps, + sizeof(struct thermal_sensor_entry), hwmon_temp, + (HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX | + HWMON_T_LABEL)); + if (!IS_ERR(info)) { + cinfo->info[index] = info; + index++; + } + + if (index < 2) { + ret = -ENODEV; + + goto err_release; + } + + hdev = devm_hwmon_device_register_with_info(&wdev->dev, "dell_ddv", data, &cinfo->chip, + NULL); + if (IS_ERR(hdev)) { + ret = PTR_ERR(hdev); + + goto err_release; + } + + devres_close_group(&wdev->dev, dell_wmi_ddv_hwmon_add); + + return 0; + +err_release: + devres_release_group(&wdev->dev, dell_wmi_ddv_hwmon_add); + + return ret; +} + static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index) { const char *uid_str; @@ -370,9 +832,34 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context) dell_wmi_ddv_debugfs_init(wdev); - return dell_wmi_ddv_battery_add(data); + if (IS_REACHABLE(CONFIG_ACPI_BATTERY)) { + ret = dell_wmi_ddv_battery_add(data); + if (ret < 0 && ret != -ENODEV) + dev_warn(&wdev->dev, "Unable to register ACPI battery hook: %d\n", ret); + } + + if (IS_REACHABLE(CONFIG_HWMON)) { + ret = dell_wmi_ddv_hwmon_add(data); + if (ret < 0 && ret != -ENODEV) + dev_warn(&wdev->dev, "Unable to register hwmon interface: %d\n", ret); + } + + return 0; } +static int dell_wmi_ddv_resume(struct device *dev) +{ + struct dell_wmi_ddv_data *data = dev_get_drvdata(dev); + + /* Force re-reading of all sensors */ + dell_wmi_ddv_hwmon_cache_invalidate(&data->fans); + dell_wmi_ddv_hwmon_cache_invalidate(&data->temps); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(dell_wmi_ddv_dev_pm_ops, NULL, dell_wmi_ddv_resume); + static const struct wmi_device_id dell_wmi_ddv_id_table[] = { { DELL_DDV_GUID, NULL }, { } @@ -382,6 +869,7 @@ MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table); static struct wmi_driver dell_wmi_ddv_driver = { .driver = { .name = DRIVER_NAME, + .pm = pm_sleep_ptr(&dell_wmi_ddv_dev_pm_ops), }, .id_table = dell_wmi_ddv_id_table, .probe = dell_wmi_ddv_probe, From 6113bd52443f3f9035acf27d8793b0246a692e81 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Thu, 9 Feb 2023 22:15:03 +0100 Subject: [PATCH 78/80] platform/x86: dell-ddv: Prefer asynchronous probing During probe, both sensor buffers need to be queried to initialize the hwmon channels. This might be slow on some machines, causing a unnecessary delay during boot. Mark the driver with PROBE_PREFER_ASYNCHRONOUS so that it can be probed asynchronously. Signed-off-by: Armin Wolf Link: https://lore.kernel.org/r/20230209211503.2739-3-W_Armin@gmx.de Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/dell/dell-wmi-ddv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c index d81dc4dd93e3..d547c9d09725 100644 --- a/drivers/platform/x86/dell/dell-wmi-ddv.c +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -869,6 +870,7 @@ MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table); static struct wmi_driver dell_wmi_ddv_driver = { .driver = { .name = DRIVER_NAME, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = pm_sleep_ptr(&dell_wmi_ddv_dev_pm_ops), }, .id_table = dell_wmi_ddv_id_table, From 3004e8d2a0a98bbf4223ae146464fadbff68bf78 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Mon, 13 Feb 2023 17:44:57 +0530 Subject: [PATCH 79/80] platform/x86/amd/pmf: Add depends on CONFIG_POWER_SUPPLY It is reported that amd_pmf driver is missing "depends on" for CONFIG_POWER_SUPPLY causing the following build error. ld: drivers/platform/x86/amd/pmf/core.o: in function `amd_pmf_remove': core.c:(.text+0x10): undefined reference to `power_supply_unreg_notifier' ld: drivers/platform/x86/amd/pmf/core.o: in function `amd_pmf_probe': core.c:(.text+0x38f): undefined reference to `power_supply_reg_notifier' make[1]: *** [scripts/Makefile.vmlinux:34: vmlinux] Error 1 make: *** [Makefile:1248: vmlinux] Error 2 Add this to the Kconfig file. Link: https://bugzilla.kernel.org/show_bug.cgi?id=217028 Fixes: c5258d39fc4c ("platform/x86/amd/pmf: Add helper routine to update SPS thermals") Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20230213121457.1764463-1-Shyam-sundar.S-k@amd.com Cc: stable@vger.kernel.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmf/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig index c375498c4071..6d89528c3177 100644 --- a/drivers/platform/x86/amd/pmf/Kconfig +++ b/drivers/platform/x86/amd/pmf/Kconfig @@ -6,6 +6,7 @@ config AMD_PMF tristate "AMD Platform Management Framework" depends on ACPI && PCI + depends on POWER_SUPPLY select ACPI_PLATFORM_PROFILE help This driver provides support for the AMD Platform Management Framework. From 0d9bdd8a550170306c2021b8d6766c5343b870c2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 17 Feb 2023 15:42:08 +0100 Subject: [PATCH 80/80] platform/x86: nvidia-wmi-ec-backlight: Add force module parameter On some Lenovo Legion models, the backlight might be driven by either one of nvidia_wmi_ec_backlight or amdgpu_bl0 at different times. When the Nvidia WMI EC backlight interface reports the backlight is controlled by the EC, the current backlight handling only registers nvidia_wmi_ec_backlight (and registers no other backlight interfaces). This hides (never registers) the amdgpu_bl0 interface, where as prior to 6.1.4 users would have both nvidia_wmi_ec_backlight and amdgpu_bl0 and could work around things in userspace. Add a force module parameter which can be used with acpi_backlight=native to restore the old behavior as a workound (for now) by passing: "acpi_backlight=native nvidia-wmi-ec-backlight.force=1" Fixes: 8d0ca287fd8c ("platform/x86: nvidia-wmi-ec-backlight: Use acpi_video_get_backlight_type()") Link: https://bugzilla.kernel.org/show_bug.cgi?id=217026 Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Reviewed-by: Daniel Dadap Link: https://lore.kernel.org/r/20230217144208.5721-1-hdegoede@redhat.com --- drivers/platform/x86/nvidia-wmi-ec-backlight.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/nvidia-wmi-ec-backlight.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c index baccdf658538..1b572c90c76e 100644 --- a/drivers/platform/x86/nvidia-wmi-ec-backlight.c +++ b/drivers/platform/x86/nvidia-wmi-ec-backlight.c @@ -12,6 +12,10 @@ #include #include +static bool force; +module_param(force, bool, 0444); +MODULE_PARM_DESC(force, "Force loading (disable acpi_backlight=xxx checks"); + /** * wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method * @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID @@ -91,7 +95,7 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct int ret; /* drivers/acpi/video_detect.c also checks that SOURCE == EC */ - if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec) + if (!force && acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec) return -ENODEV; /*