From 8d79506120821dfa98786f2bbab86376ab16c15d Mon Sep 17 00:00:00 2001 From: Nilesh Laad Date: Tue, 28 May 2024 13:26:09 +0530 Subject: [PATCH 001/306] disp: msm: dp: parse display_type before connector initialization dp_parser is only available post connector init, so if parser is not available get display_type from devicetree itself and remove redundant code. Change-Id: I2131a257cb4795f52be1706882dce533baf94600 Signed-off-by: Nilesh Laad --- msm/dp/dp_display.c | 7 ++++++- msm/dp/dp_drm.c | 10 ++++++---- msm/dp/dp_parser.c | 11 ++++------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 99ff3c7d1c74..788c43d1da2e 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -3919,6 +3919,7 @@ static int dp_display_get_display_type(struct dp_display *dp_display, const char **display_type) { struct dp_display_private *dp; + struct device_node *of_node; if (!dp_display || !display_type) { pr_err("invalid input\n"); @@ -3928,7 +3929,11 @@ static int dp_display_get_display_type(struct dp_display *dp_display, dp = container_of(dp_display, struct dp_display_private, dp_display); if (dp->parser) *display_type = dp->parser->display_type; - + else { + of_node = dp->pdev->dev.of_node; + *display_type = of_get_property(of_node, "qcom,display-type", + NULL); + } return 0; } diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index 6af98873cb38..ad90da674401 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -471,6 +471,7 @@ int dp_connector_get_info(struct drm_connector *connector, { struct dp_display *display = data; const char *display_type = NULL; + u32 conn_disp_type = SDE_CONNECTOR_PRIMARY; if (!info || !display || !display->drm_dev) { DP_ERR("invalid params\n"); @@ -480,11 +481,11 @@ int dp_connector_get_info(struct drm_connector *connector, info->intf_type = DRM_MODE_CONNECTOR_DisplayPort; display->get_display_type(display, &display_type); - if (display_type){ + if (display_type) { if (!strcmp(display_type, "primary")) - info->display_type = SDE_CONNECTOR_PRIMARY; + conn_disp_type = SDE_CONNECTOR_PRIMARY; else if (!strcmp(display_type, "secondary")) - info->display_type = SDE_CONNECTOR_SECONDARY; + conn_disp_type = SDE_CONNECTOR_SECONDARY; } info->num_of_h_tiles = 1; @@ -495,7 +496,8 @@ int dp_connector_get_info(struct drm_connector *connector, if (display && display->is_edp) { info->intf_type = DRM_MODE_CONNECTOR_eDP; - if(display->ext_hpd_en) + info->display_type = conn_disp_type; + if (display->ext_hpd_en) info->capabilities |= MSM_DISPLAY_CAP_HOT_PLUG; else info->is_connected = true; diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index ea5546ea476c..0a138bbe4a1d 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -178,13 +178,10 @@ static int dp_parser_misc(struct dp_parser *parser) &parser->pixel_base_off[i]); } - parser->display_type = of_get_property(of_node, "qcom,display-type", NULL); - if (!parser->display_type) { - if (parser->is_edp) - parser->display_type = "primary"; - else - parser->display_type = "secondary"; - } + parser->display_type = of_get_property(of_node, "qcom,display-type", + NULL); + if (!parser->display_type) + parser->display_type = "unknown"; parser->panel_notifier_support = of_property_read_bool(of_node, "qcom,panel-notifier-support"); From 89c45623082f0fcb5ec3fc82d4d67a70d4b2f21c Mon Sep 17 00:00:00 2001 From: Shaik Jabida Date: Mon, 1 Jul 2024 14:27:21 +0530 Subject: [PATCH 002/306] dsp: q6lsm: Check size of payload before access check size of payload before access in q6lsm_mmapcallback. The payload size can be either 4 or 8 bytes. Code to verify the payload size is atleast 4 bytes is added. Change-Id: I64b07f44b66fe6793bc80bc99a09fd0521342531 Signed-off-by: Shaik Jabida (cherry picked from commit 14c551f6abb3ad841accc8af91c4a18c0a78b2fe) --- dsp/q6lsm.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/dsp/q6lsm.c b/dsp/q6lsm.c index 175c8fcb1a7e..aa4127c1ae82 100644 --- a/dsp/q6lsm.c +++ b/dsp/q6lsm.c @@ -2129,8 +2129,18 @@ static int q6lsm_mmapcallback(struct apr_client_data *data, void *priv) lsm_common.set_custom_topology = 1; return 0; } + + /* + The payload_size can be either 4 or 8 bytes. + It has to be verified whether the payload_size is + atleast 4 bytes. If it is less, returns errorcode. - if (data->payload_size < (2 * sizeof(uint32_t))) { + The opcode for 4 bytes is 0x12A80 + The opcode for 8 bytes is 0x110E8. + + */ + + if (data->payload_size < (2 * sizeof(uint16_t))) { pr_err("%s: payload has invalid size[%d]\n", __func__, data->payload_size); return -EINVAL; From ad064077b5c5157a05bb3ee4f024294138ea7643 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Wed, 5 Jun 2024 13:52:11 +0530 Subject: [PATCH 003/306] thermal: qcom: Add support to update tsens trip based on nvmem data Add support to detect higher thermal profile parts and update thermal zone trips dynamically based on nvmem cell data for tsens. Change-Id: I792c4f2736d10d68b45cc9b64c0ec08d185cf007 Signed-off-by: Manaf Meethalavalappu Pallikunhi (cherry picked from commit c360f7cb0cd4d19a3d63d79842e2cea2df99dcff) --- drivers/thermal/msm-tsens.c | 90 +++++++++++++++++++++++++++++++++++++ drivers/thermal/tsens.h | 13 ++++++ 2 files changed, 103 insertions(+) diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index c660a05761af..167d0fba08e3 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include +#include #include #include #include @@ -205,10 +207,95 @@ static int get_device_tree_data(struct platform_device *pdev, return rc; } +static void tsens_thermal_zone_trip_update(struct tsens_device *tmdev, + struct thermal_zone_device *tz, + const struct thermal_trip *trip, int trip_id) +{ + int ret = 0; + u32 trip_delta = 0; + int trip_temp; + + if (trip->type == THERMAL_TRIP_CRITICAL) + return; + + if (strnstr(tz->type, "cpu", sizeof(tz->type))) + trip_delta = TSENS_ELEVATE_CPU_DELTA; + else + trip_delta = TSENS_ELEVATE_DELTA; + + trip_temp = trip->temperature + trip_delta; + if (tz->ops->set_trip_temp) { + ret = tz->ops->set_trip_temp(tz, trip_id, trip_temp); + if (ret) { + dev_err(tmdev->dev, "%s: failed to set trip%d for %s\n", + __func__, trip_id, tz->type); + return; + } + } + thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); +} + +static int tsens_nvmem_trip_update(struct tsens_device *tmdev, + struct thermal_zone_device *tz) +{ + int i, num_trips = 0; + const struct thermal_trip *trips = NULL; + + if (strnstr(tz->type, "mdmss", sizeof(tz->type)) || + !strnstr(tz->governor->name, "step_wise", + sizeof(tz->governor->name))) + return 0; + + if (!tz->ops->set_trip_temp) { + dev_err(tmdev->dev, "%s: No set_trip_temp ops support for %s\n", + __func__, tz->type); + return -EINVAL; + } + + num_trips = of_thermal_get_ntrips(tz); + trips = of_thermal_get_trip_points(tz); + for (i = 0; i < num_trips; i++) + tsens_thermal_zone_trip_update(tmdev, tz, &trips[i], i); + + return 0; +} + +static bool tsens_is_nvmem_trip_update_needed(struct tsens_device *tmdev) +{ + int ret; + u32 chipinfo, tsens_jtag; + u8 tsens_feat_id; + + if (!of_property_read_bool(tmdev->dev->of_node, "nvmem-cells")) + return false; + + ret = nvmem_cell_read_u32(tmdev->dev, "tsens_chipinfo", &chipinfo); + if (ret) { + dev_err(tmdev->dev, + "%s: Not able to read tsens_chipinfo nvmem, ret:%d\n", + __func__, ret); + return false; + } + + tsens_jtag = chipinfo & GENMASK(19, 0); + tsens_feat_id = (chipinfo >> TSENS_FEAT_OFFSET) & GENMASK(7, 0); + dev_dbg(tmdev->dev, "chipinfo:0x%x tsens_jtag: 0x%x tsens_feat_id:0x%x", + chipinfo, tsens_jtag, tsens_feat_id); + if ((tsens_jtag == TSENS_CHIP_ID0 && tsens_feat_id == TSENS_FEAT_ID3) || + (tsens_jtag == TSENS_CHIP_ID1 && tsens_feat_id == TSENS_FEAT_ID4) || + (tsens_jtag == TSENS_CHIP_ID2 && tsens_feat_id == TSENS_FEAT_ID3) || + (tsens_jtag == TSENS_CHIP_ID3 && tsens_feat_id == TSENS_FEAT_ID2)) + return true; + + return false; +} + static int tsens_thermal_zone_register(struct tsens_device *tmdev) { int i = 0, sensor_missing = 0; + tmdev->need_trip_update = tsens_is_nvmem_trip_update_needed(tmdev); + for (i = 0; i < TSENS_MAX_SENSORS; i++) { tmdev->sensor[i].tmdev = tmdev; tmdev->sensor[i].hw_id = i; @@ -222,6 +309,9 @@ static int tsens_thermal_zone_register(struct tsens_device *tmdev) sensor_missing++; continue; } + if (tmdev->need_trip_update) + tsens_nvmem_trip_update(tmdev, + tmdev->sensor[i].tzd); } else { pr_debug("Sensor not enabled:%d\n", i); } diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h index ddb7e232aa67..c5479bcee61a 100644 --- a/drivers/thermal/tsens.h +++ b/drivers/thermal/tsens.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __QCOM_TSENS_H__ @@ -35,6 +36,17 @@ #define TSENS_DRIVER_NAME "msm-tsens" +#define TSENS_FEAT_OFFSET 20 +#define TSENS_CHIP_ID0 0x197 +#define TSENS_CHIP_ID1 0x198 +#define TSENS_CHIP_ID2 0x20e +#define TSENS_CHIP_ID3 0x20f +#define TSENS_FEAT_ID2 0x2 +#define TSENS_FEAT_ID3 0x3 +#define TSENS_FEAT_ID4 0x4 +#define TSENS_ELEVATE_DELTA 10000 +#define TSENS_ELEVATE_CPU_DELTA 5000 + enum tsens_trip_type { TSENS_TRIP_CONFIGURABLE_HI = 4, TSENS_TRIP_CONFIGURABLE_LOW @@ -218,6 +230,7 @@ struct tsens_device { int trdy_fail_ctr; struct tsens_sensor zeroc; u8 zeroc_sensor_id; + bool need_trip_update; struct workqueue_struct *tsens_reinit_work; struct work_struct therm_fwk_notify; bool tsens_reinit_wa; From b3be3854eac954ee1a805652337aa142275b8b3b Mon Sep 17 00:00:00 2001 From: Aravind Kishore Sukla Date: Mon, 6 Jun 2022 16:39:51 +0530 Subject: [PATCH 004/306] qcacld-3.0: Update wiphy max_num_akms_connect variable Update wiphy->max_num_akms_connect to wiphy->max_num_akm_suites, based on the upstream kernel change. Change-Id: I54455b1d3fc162ddea5a0f9380f66a4a06236076 CRs-Fixed: 3214543 --- core/hdd/src/wlan_hdd_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 8531cf162dc0..32ef0a23a050 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -17359,7 +17359,7 @@ wlan_hdd_update_akm_suit_info(struct wiphy *wiphy) static void wlan_hdd_update_max_connect_akm(struct wiphy *wiphy) { - wiphy->max_num_akms_connect = WLAN_CM_MAX_CONNECT_AKMS; + wiphy->max_num_akm_suites = WLAN_CM_MAX_CONNECT_AKMS; } #else static void From c6f2b88a05148d7561ef45a20f6ab5ce96f41c8d Mon Sep 17 00:00:00 2001 From: Srikanth Marepalli Date: Sat, 4 May 2024 00:42:26 +0530 Subject: [PATCH 005/306] qcacld-3.0: Enable CFG80211_MULTI_AKM_CONNECT_SUPPORT from kernelv6.0 Current code supports CFG80211_MULTI_AKM_CONNECT_SUPPORT only for v5.15 kernel. Enable this feature support from kernelv6.0 by default. Change-Id: I6fbf83df54fd898abde0546f526b193a6d8dc620 CRs-Fixed: 3806550 --- core/hdd/src/wlan_hdd_cfg80211.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index f59eccad6adf..08cdc03c2bb3 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -208,6 +208,20 @@ extern const struct nla_policy wlan_hdd_wisa_cmd_policy[ #define USE_CFG80211_DEL_STA_V2 #endif +/* + * CFG80211_MULTI_AKM_CONNECT_SUPPORT + * used to indicate the Linux kernel contains support for multi AKM connect + * support + * + * This feature was introduced in Linux Kernel 6.0 via: + * ecad3b0b99bf wifi: cfg80211: Increase akm_suites array size in + * cfg80211_crypto_settings. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) || \ + (defined CFG80211_MAX_NUM_AKM_SUITES)) +#define CFG80211_MULTI_AKM_CONNECT_SUPPORT 1 +#endif + #ifdef CFG80211_MULTI_AKM_CONNECT_SUPPORT #define WLAN_CM_MAX_CONNECT_AKMS 5 #endif From b9ce37bdc0e9fc4c9d8425606278bfbeb6d56465 Mon Sep 17 00:00:00 2001 From: Srikanth Marepalli Date: Sat, 4 May 2024 01:56:51 +0530 Subject: [PATCH 006/306] qcacld-3.0: Update connect request crypto parameters Update the connect request crypto parameters based on the new kernel changes to increase the size of the akm_suites array in connect request Change-Id: I36eb265d3dafe9d822879fdbed340ba0c6bb7225 CRs-Fixed: 3806556 --- core/hdd/src/wlan_hdd_cfg80211.c | 86 +++++++------------------------- 1 file changed, 17 insertions(+), 69 deletions(-) diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 8531cf162dc0..dce428a053ef 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -20513,7 +20513,23 @@ static bool wlan_hdd_is_akm_suite_fils(uint32_t key_mgmt) } } +static int +hdd_get_num_akm_suites(const struct cfg80211_connect_params *req) +{ + return req->crypto.n_akm_suites; +} + +static uint32_t* +hdd_get_akm_suites(const struct cfg80211_connect_params *req) +{ + return (uint32_t *)req->crypto.akm_suites; +} + #ifdef CFG80211_MULTI_AKM_CONNECT_SUPPORT +#define MAX_AKM_SUITES WLAN_CM_MAX_CONNECT_AKMS +#else +#define MAX_AKM_SUITES NL80211_MAX_NR_AKM_SUITES +#endif /** * hdd_populate_crypto_akm_type() - populate akm type for crypto * @vdev: pointed to vdev obmgr @@ -20533,64 +20549,9 @@ hdd_populate_crypto_akm_type(struct wlan_objmgr_vdev *vdev, uint32_t set_val = 0; wlan_crypto_key_mgmt akm; - if (req->crypto.n_connect_akm_suites) { - for (i = 0; i < req->crypto.n_connect_akm_suites && - i < WLAN_CM_MAX_CONNECT_AKMS; i++) { - akm = osif_nl_to_crypto_akm_type( - req->crypto.connect_akm_suites[i]); - - HDD_SET_BIT(set_val, akm); - } - - status = wlan_crypto_set_vdev_param(vdev, - WLAN_CRYPTO_PARAM_KEY_MGMT, - set_val); - if (QDF_IS_STATUS_ERROR(status)) - hdd_err("Failed to set akm type %0x to crypto", - set_val); - - status = wlan_crypto_set_vdev_param( - vdev, WLAN_CRYPTO_PARAM_ORIG_KEY_MGMT, set_val); - if (QDF_IS_STATUS_ERROR(status)) - hdd_err("Failed to set original akm type %0x to crypto", - set_val); - } else { - set_val = 0; - /* Reset to none */ - HDD_SET_BIT(set_val, WLAN_CRYPTO_KEY_MGMT_NONE); - wlan_crypto_set_vdev_param(vdev, - WLAN_CRYPTO_PARAM_KEY_MGMT, - set_val); - wlan_crypto_set_vdev_param(vdev, - WLAN_CRYPTO_PARAM_ORIG_KEY_MGMT, - set_val); - } -} - -static int -hdd_get_num_akm_suites(const struct cfg80211_connect_params *req) -{ - return req->crypto.n_connect_akm_suites; -} - -static uint32_t* -hdd_get_akm_suites(const struct cfg80211_connect_params *req) -{ - return (uint32_t *)req->crypto.connect_akm_suites; -} -#else -static void -hdd_populate_crypto_akm_type(struct wlan_objmgr_vdev *vdev, - const struct cfg80211_connect_params *req) -{ - QDF_STATUS status; - uint32_t i = 0; - uint32_t set_val = 0; - wlan_crypto_key_mgmt akm; - if (req->crypto.n_akm_suites) { for (i = 0; i < req->crypto.n_akm_suites && - i < NL80211_MAX_NR_AKM_SUITES; i++) { + i < MAX_AKM_SUITES; i++) { akm = osif_nl_to_crypto_akm_type( req->crypto.akm_suites[i]); @@ -20623,19 +20584,6 @@ hdd_populate_crypto_akm_type(struct wlan_objmgr_vdev *vdev, } } -static int -hdd_get_num_akm_suites(const struct cfg80211_connect_params *req) -{ - return req->crypto.n_akm_suites; -} - -static uint32_t* -hdd_get_akm_suites(const struct cfg80211_connect_params *req) -{ - return (uint32_t *)req->crypto.akm_suites; -} -#endif - static bool wlan_hdd_is_conn_type_fils(struct cfg80211_connect_params *req) { enum nl80211_auth_type auth_type = req->auth_type; From 0c185589bc7c4659bdcd17e060a546733eaf7b7c Mon Sep 17 00:00:00 2001 From: Srikanth Marepalli Date: Wed, 3 Jul 2024 01:47:40 +0530 Subject: [PATCH 007/306] qcacld-3.0: Fix the AKM precedence order for RSN IE When the AP is configured with multiple AKMs for eg. SuiteB and FT-SuiteB then Supplicant selects the FT-SuiteB based on its precedence order but driver was selecting SuiteB due to its incorrect AKM precedence. Due to this the RSN IE in assoc-request was filled with SuiteB AKM but all other IEs were used of FT-SuiteB as sent by the Supplicant. And this is resulting in association failure. Fix the AKM precedence in the order of more secure AKM. Change-Id: I96ff786924778d336507e3bca4a38de4d7c07ffc CRs-Fixed: 3861554 (cherry picked from commit 97b3d0426579237de9c02fdf349f781514e85e2b) --- core/sme/src/csr/csr_util.c | 76 ++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c index 0343476c116a..f8c2f48b711c 100644 --- a/core/sme/src/csr/csr_util.c +++ b/core/sme/src/csr/csr_util.c @@ -2451,6 +2451,7 @@ static void csr_update_key_mgmt_crypto_param(struct wlan_objmgr_vdev *vdev, { int32_t key_mgmt = 0; int32_t neg_akm; + uint8_t i; neg_akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); if (neg_akm < 0) { @@ -2458,69 +2459,66 @@ static void csr_update_key_mgmt_crypto_param(struct wlan_objmgr_vdev *vdev, return; } - SET_PARAM(neg_akm, - wlan_crypto_rsn_suite_to_keymgmt(ap_rsn.akm_suite[0])); + for (i = 0; i < ap_rsn.akm_suite_cnt; i++) + SET_PARAM(neg_akm, + wlan_crypto_rsn_suite_to_keymgmt(ap_rsn.akm_suite[i])); /* * As there can be multiple AKM present select the most secured AKM * present */ - if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_SAE)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE); + if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B); - else if (HAS_PARAM(neg_akm, - WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) - SET_PARAM(key_mgmt, - WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_OWE)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OWE); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_DPP)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_DPP); - else if (HAS_PARAM(neg_akm, - WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) - SET_PARAM(key_mgmt, - WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_PSK); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_DPP)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_DPP); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_SAE)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_PSK); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_PSK); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WPA_NONE)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WPA_NONE); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_OSEN)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OSEN); + else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_OWE)) + SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OWE); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_CCKM); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_OSEN)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_OSEN); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WPS)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WPS); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X); else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA)) SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_NO_WPA); - else if (HAS_PARAM(neg_akm, WLAN_CRYPTO_KEY_MGMT_WPA_NONE)) - SET_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_WPA_NONE); else /* use original if no akm match */ key_mgmt = neg_akm; @@ -2533,6 +2531,7 @@ static void csr_update_ucast_cipher_crypto_param(struct wlan_objmgr_vdev *vdev, { int32_t ucastcipherset = 0; int32_t neg_ucastcipher; + uint8_t i; neg_ucastcipher = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER); @@ -2541,8 +2540,9 @@ static void csr_update_ucast_cipher_crypto_param(struct wlan_objmgr_vdev *vdev, return; } - SET_PARAM(neg_ucastcipher, - wlan_crypto_rsn_suite_to_cipher(ap_rsn.pwise_cipher_suites[0])); + for (i = 0; i < ap_rsn.pwise_cipher_suite_count; i++) + SET_PARAM(neg_ucastcipher, + wlan_crypto_rsn_suite_to_cipher(ap_rsn.pwise_cipher_suites[i])); /* * As there can be multiple ucastcipher present select the most secured From 525fb1b48fc85dcf0855c0a415b4deed063e85b0 Mon Sep 17 00:00:00 2001 From: Srikanth Marepalli Date: Mon, 6 May 2024 18:08:26 +0530 Subject: [PATCH 008/306] wifi: cfg80211: Increase akm_suites array size in cfg80211_crypto_settings Increase akm_suites array size in struct cfg80211_crypto_settings to 10 and advertise the capability to userspace. This allows userspace to send more than two AKMs to driver in netlink commands such as NL80211_CMD_CONNECT. This capability is needed for implementing WPA3-Personal transition mode correctly with any driver that handles roaming internally. Currently, the possible AKMs for multi-AKM connect can include PSK, PSK-SHA-256, SAE, FT-PSK and FT-SAE. Since the count is already 5, increasing the akm_suites array size to 10 should be reasonable for future usecases. Signed-off-by: Veerendranath Jakkam Link: https://lore.kernel.org/r/1653312358-12321-1-git-send-email-quic_vjakkam@quicinc.com Signed-off-by: Johannes Berg Git-commit: ecad3b0b99bff7247a11f8c7cb19ac9b0cb28b09 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git. Change-Id: I4ce3de12ec85e11cf30d0b26e2324bc62ab5e73e CRs-Fixed: 3799177 Signed-off-by: Srikanth Marepalli --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 12 ++++++++---- include/net/cfg80211.h | 12 +++++++++++- include/uapi/linux/nl80211.h | 14 ++++++++++++++ net/wireless/core.c | 6 ++++++ net/wireless/nl80211.c | 7 ++++++- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 106f1a846f49..9c7f2121970d 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -222,6 +222,7 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, struct qlink_auth_encr *aen; int ret; int i; + int n; if (!qtnf_cmd_start_ap_can_fit(vif, s)) return -E2BIG; @@ -253,8 +254,9 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) aen->ciphers_pairwise[i] = cpu_to_le32(s->crypto.ciphers_pairwise[i]); - aen->n_akm_suites = cpu_to_le32(s->crypto.n_akm_suites); - for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + n = min(QLINK_MAX_NR_AKM_SUITES, s->crypto.n_akm_suites); + aen->n_akm_suites = cpu_to_le32(n); + for (i = 0; i < n; i++) aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]); aen->control_port = s->crypto.control_port; aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt; @@ -2200,6 +2202,7 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, struct qlink_auth_encr *aen; int ret; int i; + int n; u32 connect_flags = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2256,9 +2259,10 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, aen->ciphers_pairwise[i] = cpu_to_le32(sme->crypto.ciphers_pairwise[i]); - aen->n_akm_suites = cpu_to_le32(sme->crypto.n_akm_suites); + n = min(QLINK_MAX_NR_AKM_SUITES, sme->crypto.n_akm_suites); + aen->n_akm_suites = cpu_to_le32(n); - for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) + for (i = 0; i < n; i++) aen->akm_suites[i] = cpu_to_le32(sme->crypto.akm_suites[i]); aen->control_port = sme->crypto.control_port; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a076d8ab31ac..02003340baaa 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -903,6 +903,7 @@ struct survey_info { }; #define CFG80211_MAX_WEP_KEYS 4 +#define CFG80211_MAX_NUM_AKM_SUITES 10 /** * struct cfg80211_crypto_settings - Crypto settings @@ -937,7 +938,7 @@ struct cfg80211_crypto_settings { int n_ciphers_pairwise; u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; int n_akm_suites; - u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; + u32 akm_suites[CFG80211_MAX_NUM_AKM_SUITES]; bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; @@ -4682,6 +4683,13 @@ struct wiphy_iftype_akm_suites { * supported by the driver for each vif * @tid_config_support.peer: bitmap of attributes (configurations) * supported by the driver for each peer + * @max_num_akm_suites: maximum number of AKM suites allowed for + * configuration through %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and + * %NL80211_CMD_START_AP. Set to NL80211_MAX_NR_AKM_SUITES if not set by + * driver. If set by driver minimum allowed value is + * NL80211_MAX_NR_AKM_SUITES in order to avoid compatibility issues with + * legacy userspace and maximum allowed value is + * CFG80211_MAX_NUM_AKM_SUITES. */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -4833,6 +4841,8 @@ struct wiphy { u64 peer, vif; } tid_config_support; + u16 max_num_akm_suites; + char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 05e7a411cfa0..d485d9d3e574 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2465,6 +2465,13 @@ enum nl80211_commands { * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from * association request when used with NL80211_CMD_NEW_STATION). * + * @NL80211_ATTR_MAX_NUM_AKM_SUITES: U16 attribute. Indicates maximum number of + * AKM suites allowed for %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and + * %NL80211_CMD_START_AP in %NL80211_CMD_GET_WIPHY response. If this + * attribute is not present userspace shall consider maximum number of AKM + * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum + * number prior to the introduction of this attribute. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2942,6 +2949,8 @@ enum nl80211_attrs { NL80211_ATTR_HE_6GHZ_CAPABILITY, + NL80211_ATTR_MAX_NUM_AKM_SUITES = 316, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2994,6 +3003,11 @@ enum nl80211_attrs { #define NL80211_HE_MIN_CAPABILITY_LEN 16 #define NL80211_HE_MAX_CAPABILITY_LEN 54 #define NL80211_MAX_NR_CIPHER_SUITES 5 + +/* + * NL80211_MAX_NR_AKM_SUITES is obsolete when %NL80211_ATTR_MAX_NUM_AKM_SUITES + * present in %NL80211_CMD_GET_WIPHY response. + */ #define NL80211_MAX_NR_AKM_SUITES 2 #define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 diff --git a/net/wireless/core.c b/net/wireless/core.c index 3983251f2756..e558b71acdfc 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -894,6 +894,12 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; #endif + if (!wiphy->max_num_akm_suites) + wiphy->max_num_akm_suites = NL80211_MAX_NR_AKM_SUITES; + else if (wiphy->max_num_akm_suites < NL80211_MAX_NR_AKM_SUITES || + wiphy->max_num_akm_suites > CFG80211_MAX_NUM_AKM_SUITES) + return -EINVAL; + /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5041036d2523..053a1f71f74e 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -656,6 +656,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { .type = NLA_EXACT_LEN, .len = sizeof(struct ieee80211_he_6ghz_capa), }, + [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, }; /* policy for the key attributes */ @@ -2574,6 +2575,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, if (nl80211_put_tid_config_support(rdev, msg)) goto nla_put_failure; + if (nla_put_u16(msg, NL80211_ATTR_MAX_NUM_AKM_SUITES, + rdev->wiphy.max_num_akm_suites)) + goto nla_put_failure; + /* done */ state->split_start = 0; break; @@ -9377,7 +9382,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, if (len % sizeof(u32)) return -EINVAL; - if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES) + if (settings->n_akm_suites > rdev->wiphy.max_num_akm_suites) return -EINVAL; memcpy(settings->akm_suites, data, len); From 68cf8fb263d3b98200e3b3ae141115d753447229 Mon Sep 17 00:00:00 2001 From: Pranay Varma Kopanati Date: Mon, 17 Jun 2024 13:28:38 +0530 Subject: [PATCH 009/306] msm: eva: Adding kref count for cvp_get_inst_from_id Adding count for instance Change-Id: I4505feb478c1c682ecf6a790d7cb804f70e50a1c Signed-off-by: Pranay Varma Kopanati (cherry picked from commit b651124b92285fa644ca3aefe946f0d779b093e6) --- drivers/media/platform/msm/cvp/hfi_response_handler.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c index db857c210f3f..e9d61e382612 100644 --- a/drivers/media/platform/msm/cvp/hfi_response_handler.c +++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c @@ -467,7 +467,7 @@ retry: } } - inst = match ? inst : NULL; + inst = match && kref_get_unless_zero(&inst->kref) ? inst : NULL; mutex_unlock(&core->lock); } else { if (core->state == CVP_CORE_UNINIT) @@ -519,7 +519,7 @@ static int hfi_process_session_cvp_msg(u32 device_id, sess_msg = kmem_cache_alloc(cvp_driver->msg_cache, GFP_KERNEL); if (sess_msg == NULL) { dprintk(CVP_ERR, "%s runs out msg cache memory\n", __func__); - return -ENOMEM; + goto error_no_mem; } memcpy(&sess_msg->pkt, pkt, get_msg_size(pkt)); @@ -542,11 +542,14 @@ static int hfi_process_session_cvp_msg(u32 device_id, info->response_type = HAL_NO_RESP; + cvp_put_inst(inst); return 0; error_handle_msg: spin_unlock(&sq->lock); kmem_cache_free(cvp_driver->msg_cache, sess_msg); +error_no_mem: + cvp_put_inst(inst); return -ENOMEM; } From c6635960b223185ced4cc88c8ebebb12924e8d77 Mon Sep 17 00:00:00 2001 From: Santosh Sakore Date: Tue, 20 Aug 2024 12:31:31 +0530 Subject: [PATCH 010/306] adsprpc: Handle UAF scenario in put_args Currently, the DSP updates header buffers with unused DMA handle fds. In the put_args section, if any DMA handle FDs are present in the header buffer, the corresponding map is freed. However, since the header buffer is exposed to users in unsigned PD, users can update invalid FDs. If this invalid FD matches with any FD that is already in use, it could lead to a use-after-free (UAF) vulnerability. As a solution,add DMA handle references for DMA FDs, and the map for the FD will be freed only when a reference is found. Acked-by: Om Deore Change-Id: I19ae21230bf11fe89858b10c9069a5daccabc392 Signed-off-by: Santosh Sakore (cherry picked from commit c6e7698c0cf35551ab16d16ac5e21e2272644734) --- drivers/char/adsprpc.c | 71 +++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 236a22608547..c13641940079 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -584,6 +584,8 @@ struct fastrpc_mmap { struct timespec64 map_end_time; bool is_filemap; /* flag to indicate map used in process init */ unsigned int ctx_refs; /* Indicates reference count for context map */ + /* Map in use for dma handle */ + unsigned int dma_handle_refs; }; enum fastrpc_perfkeys { @@ -1213,9 +1215,14 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, int fd, uintptr_t va, return 0; } hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - /* Remove if only one reference map and no context map */ - if (map->refs == 1 && !map->ctx_refs && - map->raddr == va && map->raddr + map->len == va + len && + if ((fd < 0 || map->fd == fd) && + map->raddr == va && + map->raddr + map->len == va + len && + /* Remove if only one reference map and no context map */ + map->refs == 1 && + !map->ctx_refs && + /* Remove map only if it isn't being used by DSP */ + !map->dma_handle_refs && /* Remove map if not used in process initialization */ !map->is_filemap) { match = map; @@ -1254,8 +1261,9 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) if (map->flags == ADSP_MMAP_HEAP_ADDR || map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { spin_lock(&me->hlock); - map->refs--; - if (!map->refs && !map->is_persistent && !map->ctx_refs) + if (map->refs) + map->refs--; + if (!map->refs && !map->is_persistent) hlist_del_init(&map->hn); spin_unlock(&me->hlock); if (map->refs > 0) { @@ -1270,8 +1278,13 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) spin_unlock(&me->hlock); } } else { - map->refs--; - if (!map->refs && !map->ctx_refs) + if (map->refs) + map->refs--; + /* flags is passed as 1 during fastrpc_file_free + * (ie process exit), so that maps will be cleared + * even though references are present. + */ + if (!map->refs && !map->ctx_refs && !map->dma_handle_refs) hlist_del_init(&map->hn); if (map->refs > 0 && !flags) return; @@ -2492,12 +2505,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) FASTRPC_ATTR_NOVA, 0, 0, dmaflags, &ctx->maps[i]); if (!err && ctx->maps[i]) - ctx->maps[i]->ctx_refs++; + ctx->maps[i]->dma_handle_refs++; if (err) { for (j = bufs; j < i; j++) { - if (ctx->maps[j] && ctx->maps[j]->ctx_refs) - ctx->maps[j]->ctx_refs--; - fastrpc_mmap_free(ctx->maps[j], 0); + if (ctx->maps[j] && ctx->maps[j]->dma_handle_refs) { + ctx->maps[j]->dma_handle_refs--; + fastrpc_mmap_free(ctx->maps[j], 0); + } } mutex_unlock(&ctx->fl->map_mutex); goto bail; @@ -2635,13 +2649,33 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) rpra[i].buf.pv = buf; } PERF_END); + /* Since we are not holidng map_mutex during get args whole time + * it is possible that dma handle map may be removed by some invalid + * fd passed by DSP. Inside the lock check if the map present or not + */ + mutex_lock(&ctx->fl->map_mutex); for (i = bufs; i < bufs + handles; ++i) { - struct fastrpc_mmap *map = ctx->maps[i]; - if (map) { - pages[i].addr = map->phys; - pages[i].size = map->size; + struct fastrpc_mmap *mmap = NULL; + /* check if map was created */ + if (ctx->maps[i]) { + /* check if map still exist */ + if (!fastrpc_mmap_find(ctx->fl, ctx->fds[i], 0, 0, + 0, 0, &mmap)) { + if (mmap) { + pages[i].addr = mmap->phys; + pages[i].size = mmap->size; + } + + } else { + /* map already freed by some other call */ + mutex_unlock(&ctx->fl->map_mutex); + ADSPRPC_ERR("could not find map associated with dma handle fd %d\n", + ctx->fds[i]); + goto bail; + } } } + mutex_unlock(&ctx->fl->map_mutex); fdlist = (uint64_t *)&pages[bufs + handles]; crclist = (uint32_t *)&fdlist[M_FDLIST]; /* reset fds, crc and early wakeup hint memory */ @@ -2842,9 +2876,10 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, break; if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], 0, 0, 0, 0, &mmap)) { - if (mmap && mmap->ctx_refs) - mmap->ctx_refs--; - fastrpc_mmap_free(mmap, 0); + if (mmap && mmap->dma_handle_refs) { + mmap->dma_handle_refs = 0; + fastrpc_mmap_free(mmap, 0); + } } } mutex_unlock(&ctx->fl->map_mutex); From 762e2f518ab2ecc3c8e28f03370d57ea1c0d4073 Mon Sep 17 00:00:00 2001 From: ANANDU KRISHNAN E Date: Tue, 20 Aug 2024 17:21:05 +0530 Subject: [PATCH 011/306] msm: adsprpc: Avoid taking reference for group_info Currently, the get_current_groups API accesses group info, which increases the usage refcount. If the IOCTL using the get_current_groups API is called many times, the usage counter overflows. To avoid this, access group info without taking a reference. A reference is not required as group info is not released during the IOCTL call. Change-Id: Ib4de80cac8b36f73d8f5c6dd9824722153189285 Signed-off-by: ANANDU KRISHNAN E (cherry picked from commit de9f4fe6f82c64f7a2d06d6ecd8d1edd398bf10e) --- drivers/char/adsprpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 236a22608547..0664e70286e3 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -5806,7 +5806,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) static int fastrpc_get_process_gids(struct gid_list *gidlist) { - struct group_info *group_info = get_current_groups(); + struct group_info *group_info = current_cred()->group_info; int i = 0, err = 0, num_gids = group_info->ngroups + 1; unsigned int *gids = NULL; From 9567459a4e79f22953dbebe2c62cf54c9383d309 Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Tue, 19 Mar 2024 15:55:28 +0530 Subject: [PATCH 012/306] qcacmn: Correct RSNXE capability indexes Currently, RSNXE capability indexes are defined incorrect. It seems BIT index is misinterpreted. Correct the same as defined below in spec(IEEE Std 802.11-2020, 9.4.2.241, Table 9-780). The Extended RSN Capabilities field, except its first 4 bits, is a bit field indicating the extended RSN capabilities being advertised by the STA transmitting the element. The length of the Extended RSN Capabilities field is a variable n, in octets, as indicated by the first 4 bits in the field. Also, add a macro to check if the given akm is WPA/WPA2 i.e. legacy than WPA3. Change-Id: I3d8eee15f6734b2364628f699b7829a1edb246f0 CRs-Fixed: 3257715 (cherry picked from commit ab3c4a8142a555742094118d49c29285d80b18b5) --- .../crypto/inc/wlan_crypto_global_def.h | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h index d5f386bef272..0ba235650b4d 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h @@ -493,4 +493,24 @@ struct wlan_lmac_if_crypto_rx_ops { #define WLAN_CRYPTO_RX_OPS_SET_PEER_WEP_KEYS(crypto_rx_ops) \ (crypto_rx_ops->set_peer_wep_keys) +#define WLAN_CRYPTO_IS_WPA_WPA2(akm) \ + (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WPS) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OSEN) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384)) + #endif /* end of _WLAN_CRYPTO_GLOBAL_DEF_H_ */ From 0f39a68508e25531405b18f1ebc848459d9187e6 Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Fri, 12 Jul 2024 16:07:30 +0530 Subject: [PATCH 013/306] qcacld-3.0: Enhance the RSNXE inter-op logic Some third-party APs are not able to handle more than 1 octet in the RSNXE, even though RSNXE support is present. Therefore, to prevent this interop issue, send only 1 octet of RSNXE if the AP broadcasts only 1 octet. RSNXE handling logic summary: 1. Don't modify userspace RSNXE when caps other than SAE_H2E, SAE_PK, SECURE_LTF, SECURE_RTT, PROT_RANGE_NEGOTIOATION are set. 2. AP doesn't send RSNXE For WPA2 - Strip the RSNXE completely. For WPA3 - Retain only SAE capabilities such as H2E and PK. 3. AP supports RSNXE with length 1 For WPA2 & WPA3 - Retain only the first octet in RSNXE. 4. AP supports RSNXE with multiple octet For WPA2 & WPA3 - Use the userspace assoc ie RSNXE as it is. Change-Id: I56d1d5711b067fe5e0ff19117f6a600219cb86a0 CRs-Fixed: 3490369 (cherry picked from commit 5d837c1b79e7761e75e1e128b189fa01ec6a1a85) --- core/mac/inc/sir_mac_prot_def.h | 4 +- .../src/pe/lim/lim_process_sme_req_messages.c | 144 +++++++++++++++++- 2 files changed, 146 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h index 8927b19557e7..b31f399917c4 100644 --- a/core/mac/inc/sir_mac_prot_def.h +++ b/core/mac/inc/sir_mac_prot_def.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1872,4 +1872,6 @@ struct he_6ghz_capability_info { #define SIR_MAC_TXSTBC 1 #define SIR_MAC_RXSTBC 1 +#define SIR_MAC_RSNX_CAP_MIN_LEN 1 +#define SIR_MAC_RSNX_CAP_MAX_LEN 16 #endif /* __MAC_PROT_DEFS_H */ diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index dd4ea287d90b..49113c9529e4 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -61,6 +61,7 @@ #include #include "wlan_lmac_if_def.h" #include "wlan_reg_services_api.h" +#include /* SME REQ processing function templates */ static bool __lim_process_sme_sys_ready_ind(struct mac_context *, uint32_t *); @@ -1198,6 +1199,140 @@ lim_get_vdev_rmf_capable(struct mac_context *mac, struct pe_session *session) } #endif +/* + * lim_rebuild_rsnxe_cap() - Rebuild the RSNXE CAP for STA + * + * @rsnx_ie: RSNX IE + * @length: length of extended RSN cap field + * + * This API is used to truncate/rebuild the RSNXE based on the length + * provided. This length marks the length of the extended RSN cap field. + * + * Return: Newly constructed RSNX IE + */ +static inline uint8_t *lim_rebuild_rsnxe_cap(uint8_t *rsnx_ie, uint8_t length) +{ + const uint8_t *rsnxe_cap; + uint8_t cap_len; + uint8_t *new_rsnxe = NULL; + + if (length < SIR_MAC_RSNX_CAP_MIN_LEN || + length > SIR_MAC_RSNX_CAP_MAX_LEN) { + pe_err("Invalid length %d", length); + return NULL; + } + + rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnx_ie, &cap_len); + if (!rsnxe_cap) + return NULL; + + new_rsnxe = qdf_mem_malloc(length + 2); + if (!new_rsnxe) + return NULL; + + new_rsnxe[0] = WLAN_ELEMID_RSNXE; + new_rsnxe[1] = length; + qdf_mem_copy(&new_rsnxe[2], rsnxe_cap, length); + + /* Now update the new field length in octet 0 for the new length*/ + new_rsnxe[2] = (new_rsnxe[2] & 0xF0) | (length - 1); + + pe_debug("New RSNXE length %d", length); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + new_rsnxe, length + 2); + return new_rsnxe; +} + +static inline QDF_STATUS +lim_strip_rsnx_ie(struct mac_context *mac_ctx, + struct pe_session *session) +{ + int32_t akm; + uint8_t len = 0; + uint8_t *rsnxe = NULL, *new_rsnxe = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t *add_ie = NULL; + uint16_t add_ie_len; + + akm = wlan_crypto_get_param(session->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (akm == -1 || + !(WLAN_CRYPTO_IS_WPA_WPA2(akm) || WLAN_CRYPTO_IS_WPA3(akm))) + return status; + + add_ie = session->lim_join_req->addIEAssoc.addIEdata; + add_ie_len = session->lim_join_req->addIEAssoc.length; + + if (!wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, add_ie, add_ie_len)) + return status; + + /* + * Userspace may send RSNXE also in connect request irrespective + * of the connecting AP capabilities. This allows the driver to chose + * best candidate based on score. But the chosen candidate may + * not support the RSNXE feature and may not advertise RSNXE + * in beacon/probe response. Station is not supposed to include + * the RSNX IE in assoc request in such cases as legacy APs + * may misbahave due to the new IE. It's observed that few + * legacy APs which don't support the RSNXE reject the + * connection at EAPOL stage. + * + */ + rsnxe = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!rsnxe) + return QDF_STATUS_E_FAILURE; + + lim_strip_ie(mac_ctx, add_ie, &add_ie_len, WLAN_ELEMID_RSNXE, + ONE_BYTE, NULL, 0, rsnxe, WLAN_MAX_IE_LEN); + + session->lim_join_req->addIEAssoc.length = add_ie_len; + + if (!rsnxe[0]) + goto end; + + if (WLAN_CRYPTO_IS_WPA_WPA2(akm)) { + mlme_debug("Strip RSNXE as it is not supported by AP"); + goto end; + } + + if (WLAN_CRYPTO_IS_WPA3(akm)) { + len = 1; + goto rebuild_rsnxe; + } + + pe_err("Error in handling RSNXE. RSNXE length : %d", rsnxe[1]); + status = QDF_STATUS_E_FAILURE; + goto end; + +rebuild_rsnxe: + /* Build the new RSNXE */ + new_rsnxe = lim_rebuild_rsnxe_cap(rsnxe, len); + if (!new_rsnxe) { + status = QDF_STATUS_E_FAILURE; + goto end; + } else if (!new_rsnxe[1]) { + qdf_mem_free(new_rsnxe); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Append the new RSNXE to the assoc ie */ + if (add_ie_len + new_rsnxe[1] >= SIR_MAC_MAX_ADD_IE_LENGTH) { + pe_err("Cannot accomodate the new RSNX IE"); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(new_rsnxe); + goto end; + } + + qdf_mem_copy(&add_ie[add_ie_len], new_rsnxe, new_rsnxe[1] + 2); + add_ie_len += new_rsnxe[1] + 2; + session->lim_join_req->addIEAssoc.length = add_ie_len; + qdf_mem_free(new_rsnxe); + +end: + qdf_mem_free(rsnxe); + return status; +} + /** * __lim_process_sme_join_req() - process SME_JOIN_REQ message * @mac_ctx: Pointer to Global MAC structure @@ -1599,6 +1734,13 @@ __lim_process_sme_join_req(struct mac_context *mac_ctx, void *msg_buf) ret_code = eSIR_SME_INVALID_PARAMETERS; goto end; } + + status = lim_strip_rsnx_ie(mac_ctx, session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Error in parsing RSNX IE"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } } mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev); From 2c029ff90739a5a301203088f3110efd61072356 Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Tue, 19 Mar 2024 15:56:34 +0530 Subject: [PATCH 014/306] qcacmn: Add macro to determine WPA3 AKM Add a macro to determine if a particular AKM is WPA3-based AKM. Change-Id: I9b3f546e2e0f69281305ca9052dc109fb6812e21 CRs-Fixed: 3418837 (cherry picked from commit 389a047ba7c9e4c0f57cfd52f41fcbcf37fe85a6) --- umac/cmn_services/crypto/inc/wlan_crypto_global_def.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h index 0ba235650b4d..74d047350ac6 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h +++ b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h @@ -513,4 +513,11 @@ struct wlan_lmac_if_crypto_rx_ops { QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK_SHA384) || \ QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA384)) +#define WLAN_CRYPTO_IS_WPA3(akm) \ + (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_DPP) || \ + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) #endif /* end of _WLAN_CRYPTO_GLOBAL_DEF_H_ */ From 52c920054b2cb07d8df4b6e36e4b489ad9d6e348 Mon Sep 17 00:00:00 2001 From: Zeyuan Lu Date: Wed, 11 Sep 2024 17:56:14 +0800 Subject: [PATCH 015/306] disp: config :disable CONFIG_DSI_PARSER for kodiak Disable dsi firmware support on kodiak Change-Id: I223c5ac9c1c7f136137a115f844e5e75c01e433c Signed-off-by: Zeyuan Lu --- config/lahainadisp.conf | 2 +- config/lahainadispconf.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/config/lahainadisp.conf b/config/lahainadisp.conf index d413be39445f..953a3ef338f8 100644 --- a/config/lahainadisp.conf +++ b/config/lahainadisp.conf @@ -4,7 +4,7 @@ export CONFIG_DRM_MSM_DP=y export CONFIG_DRM_MSM_DP_MST=y export CONFIG_SYNC_FILE=y export CONFIG_DRM_MSM_DSI=y -export CONFIG_DSI_PARSER=y +export CONFIG_DSI_PARSER=n export CONFIG_DRM_SDE_WB=y export CONFIG_DRM_MSM_REGISTER_LOGGING=y export CONFIG_QCOM_MDSS_PLL=y diff --git a/config/lahainadispconf.h b/config/lahainadispconf.h index e72e0a43f1ab..379c456689c8 100644 --- a/config/lahainadispconf.h +++ b/config/lahainadispconf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, 2024 The Linux Foundation. All rights reserved. */ #define CONFIG_DRM_MSM 1 @@ -9,7 +9,6 @@ #define CONFIG_DRM_MSM_SDE 1 #define CONFIG_SYNC_FILE 1 #define CONFIG_DRM_MSM_DSI 1 -#define CONFIG_DSI_PARSER 1 #define CONFIG_DRM_SDE_WB 1 #define CONFIG_DRM_MSM_REGISTER_LOGGING 1 #define CONFIG_DRM_SDE_EVTLOG_DEBUG 1 From c8f3df8ea4a8674e41969fd0cacabcdfc2facfa1 Mon Sep 17 00:00:00 2001 From: Jinfeng Gu Date: Thu, 22 Aug 2024 15:51:37 +0800 Subject: [PATCH 016/306] disp: msm: dsi: add null pointer check in dsi_display_dev_remove This change add display null pointer check in dsi_display_dev_remove. Change-Id: Ib31756c3b22256d19cbcb508f60de4550e3834e1 Signed-off-by: Jinfeng Gu --- msm/dsi/dsi_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index b75c465340b0..6962049ee8fb 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -6131,6 +6131,10 @@ int dsi_display_dev_remove(struct platform_device *pdev) } display = platform_get_drvdata(pdev); + if (!display || !display->panel_node) { + DSI_ERR("invalid display\n"); + return -EINVAL; + } /* decrement ref count */ of_node_put(display->panel_node); From 94e81e5d2da5953d468542b58feaf0c796413f81 Mon Sep 17 00:00:00 2001 From: Vikas Reddy Pachika Date: Wed, 9 Oct 2024 17:33:19 +0530 Subject: [PATCH 017/306] disp: msm: dsi: fix error path for dsi_display init Handle dsi_display init errors with proper de-init sequence. Change-Id: I7d029980a06c8069264c3b1b2b7a6cdb781e1198 Signed-off-by: Deven Solanki Signed-off-by: Vikas Reddy Pachika --- msm/dsi/dsi_display.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 6962049ee8fb..91682051c5e2 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -5971,15 +5971,25 @@ static int dsi_display_init(struct dsi_display *display) if (rc) { DSI_ERR("[%s] failed to enable vregs, rc=%d\n", display->panel->name, rc); - return rc; + goto vreg_fail; } } rc = component_add(&pdev->dev, &dsi_display_comp_ops); - if (rc) + if (rc) { DSI_ERR("component add failed, rc=%d\n", rc); + goto comp_add_fail; + } DSI_DEBUG("component add success: %s\n", display->name); + return rc; + +comp_add_fail: + if (display->panel) + dsi_pwr_enable_regulator(&display->panel->power_info, false); +vreg_fail: + _dsi_display_dev_deinit(display); + end: return rc; } From a74ffcf33b62a7219f0cfbcf5386b236a3714411 Mon Sep 17 00:00:00 2001 From: Vikas Reddy Pachika Date: Fri, 11 Oct 2024 11:33:14 +0530 Subject: [PATCH 018/306] disp: config: fix copyright marking for lahaina config Add qcom license for lahainadispconf.h. Change-Id: I7048ca710377655c80b14213f1897256074fa2b8 Signed-off-by: Vikas Reddy Pachika --- config/lahainadispconf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/lahainadispconf.h b/config/lahainadispconf.h index 379c456689c8..3a0210956e2a 100644 --- a/config/lahainadispconf.h +++ b/config/lahainadispconf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, 2024 The Linux Foundation. All rights reserved. + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #define CONFIG_DRM_MSM 1 From d1e31dec5a9375bb595cf13a8e78a6f0d3fde329 Mon Sep 17 00:00:00 2001 From: Swami Reddy Reddy Date: Wed, 24 Jul 2024 18:53:36 +0530 Subject: [PATCH 019/306] msm: camera: sensor: TOCTOU error handling - Proper Handling in case of invalid pinctrl index - Removing dead code and unused variables - Change to dereference s_ctrl only after proper NULL Dereference Check. CRs-Fixed: 3875406 Change-Id: I8e2c717b22efff2a7d6503d38c048e30eff230da Signed-off-by: Swami Reddy Reddy --- drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c | 13 ++++++++----- .../cam_sensor_module/cam_sensor/cam_sensor_core.c | 5 +++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index 5165f6b2d1c9..146967f076a9 100644 --- a/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -379,7 +380,7 @@ static int cam_res_mgr_shared_pinctrl_select_state( cam_res->pctrl_res[idx].pstatus = PINCTRL_STATUS_SUSPEND; } - return 0; + return rc; } static int cam_res_mgr_add_device(struct device *dev, @@ -577,11 +578,9 @@ static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) bool need_free = true; int dev_num = 0; struct cam_gpio_res *gpio_res = NULL; - bool is_shared_gpio = false; bool is_shared_pctrl_gpio = false; int pctrl_idx = -1; - is_shared_gpio = cam_res_mgr_gpio_is_in_shared_gpio(gpio); is_shared_pctrl_gpio = cam_res_mgr_gpio_is_in_shared_pctrl_gpio(gpio); @@ -634,8 +633,12 @@ static void cam_res_mgr_gpio_free(struct device *dev, uint gpio) pctrl_idx = cam_res_mgr_util_get_idx_from_shared_pctrl_gpio( gpio); - cam_res_mgr_shared_pinctrl_select_state( - pctrl_idx, false); + if (pctrl_idx >= 0) { + cam_res_mgr_shared_pinctrl_select_state( + pctrl_idx, false); + } else { + CAM_ERR(CAM_RES, "invalid pinctrl idx: %d", pctrl_idx); + } } CAM_DBG(CAM_RES, "freeing gpio: %u", gpio); diff --git a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c index 999fec038324..a31023e4101c 100644 --- a/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -719,13 +719,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, { int rc = 0, pkt_opcode = 0; struct cam_control *cmd = (struct cam_control *)arg; - struct cam_sensor_power_ctrl_t *power_info = - &s_ctrl->sensordata->power_info; + struct cam_sensor_power_ctrl_t *power_info = NULL; if (!s_ctrl || !arg) { CAM_ERR(CAM_SENSOR, "s_ctrl is NULL"); return -EINVAL; } + power_info = &s_ctrl->sensordata->power_info; + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", From 5a034779fd85f258de87cad9c60421bcb680dcda Mon Sep 17 00:00:00 2001 From: Kiran Kumar Lokere Date: Mon, 9 Sep 2024 16:07:29 -0700 Subject: [PATCH 020/306] qcacld-3.0: Fix the possible OOB write in country IE unpack Fix the possible OOB write in unpacking the country IE due to the IE length check against integer division. CRs-Fixed: 3910626 Change-Id: I800290ab7285fb46ed43a46ce38967046b4881fa (cherry picked from commit 0002f9ddc9a6be3e34fe15e55f286b5794b29f08) (cherry picked from commit f33a4f5a7d5b0b54b72f6775a450575fc82a2fd8) --- core/mac/src/include/dot11f.h | 2 +- core/mac/src/sys/legacy/src/utils/src/dot11f.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/mac/src/include/dot11f.h b/core/mac/src/include/dot11f.h index 7b0afc593596..338a943facae 100644 --- a/core/mac/src/include/dot11f.h +++ b/core/mac/src/include/dot11f.h @@ -27,7 +27,7 @@ * * * This file was automatically generated by 'framesc' - * Mon May 30 20:50:39 2022 from the following file(s): + * Wed Sep 11 12:49:28 2024 from the following file(s): * * dot11f.frms * diff --git a/core/mac/src/sys/legacy/src/utils/src/dot11f.c b/core/mac/src/sys/legacy/src/utils/src/dot11f.c index ec2f7ff8be51..b44f94ea0ba8 100644 --- a/core/mac/src/sys/legacy/src/utils/src/dot11f.c +++ b/core/mac/src/sys/legacy/src/utils/src/dot11f.c @@ -25,7 +25,7 @@ * * * This file was automatically generated by 'framesc' - * Mon May 30 20:50:39 2022 from the following file(s): + * Wed Sep 11 12:49:28 2024 from the following file(s): * * dot11f.frms * @@ -134,7 +134,7 @@ typedef struct sIEDefn { #define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ do { \ if (!pSrc || IsBadReadPtr(pSrc, 4))\ - eturn DOT11F_BAD_INPUT_BUFFER; \ + return DOT11F_BAD_INPUT_BUFFER; \ if (!pBuf || IsBadWritePtr(pBuf, nBuf))\ return DOT11F_BAD_OUTPUT_BUFFER; \ if (!nBuf)\ @@ -4131,7 +4131,7 @@ uint32_t dot11f_unpack_ie_country(tpAniSirGlobal pCtx, return 0U; } else { pDst->num_more_triplets = (uint8_t)(ielen / 3); - if (ielen / 3 > 80) { + if (ielen > 80 * 3) { pDst->present = 0; return DOT11F_SKIPPED_BAD_IE; } From 2aed6fe57ad5b2d180c3ec8cc1fc56e82ae53a5d Mon Sep 17 00:00:00 2001 From: Dharmendra Tiwari Date: Tue, 3 Sep 2024 23:06:17 -0700 Subject: [PATCH 021/306] qcacld-3.0: Correcting the TSInfo structure size according to the Spec According to spec the TSinfo size should be 4 bytes. To fix this issue,TSInfo size is increased to 4bytes aligning with the current standard. CRs-Fixed: 3910625 Change-Id: I7979fa84af0295d21d4afe1b876af494a5b8fed8 (cherry picked from commit 685e5c9a53e754d4eb67211ed5ec7b4144bbfcd1) --- core/mac/src/cfg/cfgUtil/dot11f.frms | 2 +- core/mac/src/include/dot11f.h | 2 +- core/mac/src/sys/legacy/src/utils/src/dot11f.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/mac/src/cfg/cfgUtil/dot11f.frms b/core/mac/src/cfg/cfgUtil/dot11f.frms index a3bbbbbf6297..4cb16f7da0c1 100644 --- a/core/mac/src/cfg/cfgUtil/dot11f.frms +++ b/core/mac/src/cfg/cfgUtil/dot11f.frms @@ -370,7 +370,7 @@ FF SMPowerModeSet (1) //7.3.1.25 } } -FF TSInfo (3) // 7.3.2.30 +FF TSInfo (4) // 7.3.2.30 { { traffic_type: 1; diff --git a/core/mac/src/include/dot11f.h b/core/mac/src/include/dot11f.h index 338a943facae..0e2d373a0b1f 100644 --- a/core/mac/src/include/dot11f.h +++ b/core/mac/src/include/dot11f.h @@ -442,7 +442,7 @@ typedef struct sDot11fFfTSInfo { uint32_t unused:15; } tDot11fFfTSInfo; -#define DOT11F_FF_TSINFO_LEN (3) +#define DOT11F_FF_TSINFO_LEN (4) void dot11f_unpack_ff_ts_info(tpAniSirGlobal, uint8_t *, tDot11fFfTSInfo *); diff --git a/core/mac/src/sys/legacy/src/utils/src/dot11f.c b/core/mac/src/sys/legacy/src/utils/src/dot11f.c index b44f94ea0ba8..b07b8c68f94a 100644 --- a/core/mac/src/sys/legacy/src/utils/src/dot11f.c +++ b/core/mac/src/sys/legacy/src/utils/src/dot11f.c @@ -16710,7 +16710,7 @@ uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, tDot11fDelTS *pFrm, uint32_t *pnNeeded) { uint32_t status = 0; - *pnNeeded = 7; + *pnNeeded = 8; status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, IES_DelTS); return status; From 2ca80154816040f2d72ad47bc21b08d499496fab Mon Sep 17 00:00:00 2001 From: Vikas Reddy Pachika Date: Fri, 11 Oct 2024 11:33:14 +0530 Subject: [PATCH 022/306] disp: config: fix copyright marking for lahaina config Add qcom license for lahainadispconf.h. Change-Id: I7048ca710377655c80b14213f1897256074fa2b8 Signed-off-by: Vikas Reddy Pachika (cherry picked from commit a74ffcf33b62a7219f0cfbcf5386b236a3714411) --- config/lahainadispconf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/lahainadispconf.h b/config/lahainadispconf.h index 379c456689c8..3a0210956e2a 100644 --- a/config/lahainadispconf.h +++ b/config/lahainadispconf.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2020, 2024 The Linux Foundation. All rights reserved. + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #define CONFIG_DRM_MSM 1 From f1a2c1f44d585a50f2bbd3334b15c86dd3594f2e Mon Sep 17 00:00:00 2001 From: Abinath S Date: Fri, 9 Aug 2024 17:53:45 +0530 Subject: [PATCH 023/306] asoc: codec: avoid out of bound write to map array added check for port num and channel iteration are lessthan 8 to avoid out of bound write to 8x8 map array. Change-Id: I4c6fe13a5eb09be623a1c40ce16c5a5e4246e021 Signed-off-by: Abinath S (cherry picked from commit 448a545731195eae632ed5852f8c07133f8a242c) --- asoc/codecs/rouleur/rouleur.c | 5 +++++ asoc/codecs/wcd937x/wcd937x.c | 6 +++++- asoc/codecs/wcd938x/wcd938x.c | 8 +++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/asoc/codecs/rouleur/rouleur.c b/asoc/codecs/rouleur/rouleur.c index b29ba3b43a62..059ef6b015c3 100644 --- a/asoc/codecs/rouleur/rouleur.c +++ b/asoc/codecs/rouleur/rouleur.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -257,6 +258,10 @@ static int rouleur_parse_port_mapping(struct device *dev, for (i = 0; i < map_length; i++) { port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + if (port_num >= MAX_PORT || ch_iter >= MAX_CH_PER_PORT) { + dev_err(dev, "%s: Invalid port or channel number\n", __func__); + goto err_pdata_fail; + } slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index 3306130ccd78..184cb7c533ea 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -315,6 +315,10 @@ static int wcd937x_parse_port_mapping(struct device *dev, for (i = 0; i < map_length; i++) { port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + if (port_num >= MAX_PORT || ch_iter >= MAX_CH_PER_PORT) { + dev_err(dev, "%s: Invalid port or channel number\n", __func__); + goto err_pdata_fail; + } slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 3448e41f0727..8497a36b3002 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -395,6 +395,12 @@ static int wcd938x_parse_port_mapping(struct device *dev, for (i = 0; i < map_length; i++) { port_num = dt_array[NUM_SWRS_DT_PARAMS * i]; + + if (port_num >= MAX_PORT || ch_iter >= MAX_CH_PER_PORT) { + dev_err(dev, "%s: Invalid port or channel number\n", __func__); + goto err_pdata_fail; + } + slave_port_type = dt_array[NUM_SWRS_DT_PARAMS * i + 1]; ch_mask = dt_array[NUM_SWRS_DT_PARAMS * i + 2]; ch_rate = dt_array[NUM_SWRS_DT_PARAMS * i + 3]; From dbebbf294b54764127b568c9d64dbcdd98cd5831 Mon Sep 17 00:00:00 2001 From: Venkata Gopi Nagaraju Botlagunta Date: Fri, 3 Jun 2022 16:56:04 +0530 Subject: [PATCH 024/306] disp: msm: dsi: add support for hibernation Set parent to xo clock for link clocks, before we enter suspend, so that framework and hw state are in correct state, when we exit from hibernation. Change-Id: Ib0e2ca6ac57aec566171b2f72e2b6822e2d9fde2 Signed-off-by: Venkata Gopi Nagaraju Botlagunta --- msm/dsi/dsi_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index 91682051c5e2..38c478f94641 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -2716,7 +2716,7 @@ error: return rc; } -#ifdef CONFIG_DEEPSLEEP +#if defined (CONFIG_DEEPSLEEP) || defined (CONFIG_HIBERNATION) int dsi_display_unset_clk_src(struct dsi_display *display) { int rc = 0; From 48d2f3a4c01f54956a655b5749daa6b25f2dc4ad Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Fri, 29 Nov 2024 17:01:56 +0530 Subject: [PATCH 025/306] firmware: qcom_scm: do not clear dump mode from shutdown Do not overwrite download mode to NO dump mode from SCM driver, it is already being done at proper place in qcom-dload-mode driver and writing it here can clean up EDL mode written from qcom-dload-mode. Fix this issue by remove writing no dump mode from SCM driver. Change-Id: Ibfe8b8484dd69ae8386b46c9a53ef42a4a475688 Signed-off-by: Mukesh Ojha --- drivers/firmware/qcom_scm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 99593aaebacd..96b71bc4cd99 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -1248,8 +1248,6 @@ static void qcom_scm_shutdown(struct platform_device *pdev) { qcom_scm_disable_sdi(); qcom_scm_halt_spmi_pmic_arbiter(); - /* Clean shutdown, disable download mode to allow normal restart */ - qcom_scm_set_download_mode(QCOM_DOWNLOAD_NODUMP, 0); } static const struct of_device_id qcom_scm_dt_match[] = { From 6006e33112e468f3622cbb62a4cead27789f8d12 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 12 Feb 2025 06:01:36 -0800 Subject: [PATCH 026/306] fw-api: CL 28583592 - update fw common interface files Change-Id: I87ee96cf84c9476f673d7726141d81b5e6f889de CRs-Fixed: 3830439 --- fw/htt_stats.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 5a57e7f9f171..bbbfb982ac12 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -1002,6 +1002,7 @@ typedef enum { #define HTT_TX_HWQ_MAX_CMD_STALL_STATS 5 #define HTT_TX_HWQ_MAX_FES_RESULT_STATS 10 #define HTT_PDEV_STATS_PPDU_DUR_HIST_BINS 16 +#define HTT_PDEV_STATS_PPDU_DUR_HIST_EXT_BINS 6 #define HTT_PDEV_STATS_PPDU_DUR_HIST_INTERVAL_US 250 typedef enum { @@ -5913,6 +5914,8 @@ typedef struct { /** tx_ppdu_dur_hist: * Tx PPDU duration histogram, which holds the tx duration of PPDUs * under histogram bins of interval 250us + * + * Note that this histogram is extended by tx_ppdu_dur_hist_ext[] below. */ A_UINT32 tx_ppdu_dur_hist[HTT_PDEV_STATS_PPDU_DUR_HIST_BINS]; A_UINT32 tx_success_time_us_low; @@ -5926,6 +5929,11 @@ typedef struct { * OFDMA PPDUs under histogram bins of interval 250us */ A_UINT32 tx_ofdma_ppdu_dur_hist[HTT_PDEV_STATS_PPDU_DUR_HIST_BINS]; + /* tx_ppdu_dur_hist_ext: + * This array extends the PPDU duration histogram contained in the + * tx_ppdu_dur_hist[] array from 4 ms to 5.5 ms. + */ + A_UINT32 tx_ppdu_dur_hist_ext[HTT_PDEV_STATS_PPDU_DUR_HIST_EXT_BINS]; } htt_stats_tx_pdev_ppdu_dur_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_pdev_ppdu_dur_tlv htt_tx_pdev_ppdu_dur_stats_tlv; From c2f165b7e67671c98f4d8bc60017afaaee968c12 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 12 Feb 2025 06:03:39 -0800 Subject: [PATCH 027/306] fw-api: CL 28584645 - update fw common interface files Change-Id: I3d664c20c1f5000049b7b49019dfe378f677d2c4 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 8 +++++++- fw/wmi_version.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 70eaf1826cf7..23d7cc9d0d34 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -23177,7 +23177,10 @@ typedef struct { * Refer WLAN_ROAM_SCORE_MAX_BAND_INDEX for possible band_idx values. */ A_UINT32 band_idx; - /** Below RSSI/CU factor_value & factor_score param values are configured by vendor */ + /** + * The below band weight (2.4 GHz, 5 GHz, 6 GHz), RSSI, and CU factor_value + * and factor_score param values are configured by vendor. + */ A_UINT32 rssi_factor_value1; A_UINT32 rssi_factor_value2; A_UINT32 rssi_factor_value3; @@ -23192,6 +23195,9 @@ typedef struct { A_UINT32 cu_factor_value2; A_UINT32 cu_factor_score1; A_UINT32 cu_factor_score2; + A_UINT32 band_weight_2GHz; + A_UINT32 band_weight_5GHz; + A_UINT32 band_weight_6GHz; } wmi_roam_cnd_vendor_scoring_param; /** Support early stop roaming scanning when finding a strong candidate AP diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 145e8fcc2aa4..ba880aac3d5c 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1575 +#define __WMI_REVISION_ 1576 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 852c7ebf14ce08f41468c7b5de0327cdc3889b1c Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 14 Feb 2025 06:03:46 -0800 Subject: [PATCH 028/306] fw-api: CL 28602565 - update fw common interface files Change-Id: I0fc23344cd676ddf3b617eb0666e425cbd08f8c4 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 6 +++++- fw/wmi_version.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 23d7cc9d0d34..cb18938d601c 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -17050,6 +17050,8 @@ typedef struct { #define WMI_MLO_FLAGS_SET_IEEE_LINK_ID_VALID(mlo_flags, value) WMI_SET_BITS(mlo_flags, 18, 1, value) #define WMI_MLO_FLAGS_GET_IEEE_LINK_ID_VALID_PARTNER(mlo_flags) WMI_GET_BITS(mlo_flags, 19, 1) #define WMI_MLO_FLAGS_SET_IEEE_LINK_ID_VALID_PARTNER(mlo_flags, value) WMI_SET_BITS(mlo_flags, 19, 1, value) +#define WMI_MLO_FLAGS_GET_SINGLE_LINK_EMLSR_EN(mlo_flags) WMI_GET_BITS(mlo_flags, 20, 1) +#define WMI_MLO_FLAGS_SET_SINGLE_LINK_EMLSR_EN(mlo_flags, value) WMI_SET_BITS(mlo_flags, 20, 1, value) /* this structure used for passing MLO flags */ typedef struct { @@ -17081,7 +17083,8 @@ typedef struct { start_as_active:1, /* indicate link should be started in active status */ mlo_ieee_link_id_valid:1, /* indicate if the ieee_link_id in wmi_vdev_start_mlo_params is valid */ mlo_ieee_link_id_valid_partner:1, /* indicate if the ieee_link_id in wmi_partner_link_params is valid */ - unused: 12; + single_link_emlsr_en:1, /* indicate if emlsr enablement on one link is supported */ + unused: 11; }; A_UINT32 mlo_flags; }; @@ -46709,6 +46712,7 @@ typedef enum { WMI_MLO_LINK_FORCE_REASON_TDLS = 4, /* Set force specific links because of 11BE MLO TDLS setup/teardown */ WMI_MLO_LINK_FORCE_REASON_REVERT_FAILURE = 5, /* Set force specific links for revert previous failed due to host reject */ WMI_MLO_LINK_FORCE_REASON_LINK_DELETE = 6, /* Set force specific links because link is deleted from associated link set */ + WMI_MLO_LINK_FORCE_REASON_SINGLE_LINK_EMLSR_OP = 7, /* Set force specific links because single link eMLSR operation */ } WMI_MLO_LINK_FORCE_REASON; #define WMI_MLO_CONTROL_FLAGS_GET_OVERWRITE_FORCE_ACTIVE(mlo_flags) \ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index ba880aac3d5c..cbbb9e0b4e54 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1576 +#define __WMI_REVISION_ 1577 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 24f7190f10a1155ab25d749d3263f09ac5f1207b Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 16 Feb 2025 06:01:55 -0800 Subject: [PATCH 029/306] fw-api: CL 28611293 - update fw common interface files Change-Id: I0c8e6ee471af995bfb06121b43fbf0fd37cb308a CRs-Fixed: 3830439 --- fw/wmi_unified.h | 12 ++++++++++++ fw/wmi_version.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index cb18938d601c..b500c3585263 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -28469,6 +28469,12 @@ typedef enum { WMI_PEER_IND_OMI, /* operating mode indication */ } WMI_PEER_OPER_MODE_IND; + +#define WMI_EHT_PEER_PARAMS_MCS_DISABLE_GET(eht_peer_params) \ + WMI_GET_BITS(eht_peer_params, 0, 1) +#define WMI_EHT_PEER_PARAMS_MCS_DISABLE_SET(eht_peer_params, value) \ + WMI_SET_BITS(eht_peer_params, 0, 1, value) + typedef struct { /** TLV tag and len; tag equals * WMITLV_TAG_STRUC_wmi_peer_oper_mode_change */ @@ -28490,6 +28496,12 @@ typedef struct { * valid for peer_operating mode ind. OMI */ A_UINT32 new_disablemu; + /** eht_peer_params + * bit 0 - eht_mcs15_disable, refer to + * WMI_EHT_PEER_PARAMS_MCS_DISABLE_GET,SET macros + * bits 1 to 31 - reserved + */ + A_UINT32 eht_peer_params; } wmi_peer_oper_mode_change_event_fixed_param; /** FW response when tx failure count has reached threshold diff --git a/fw/wmi_version.h b/fw/wmi_version.h index cbbb9e0b4e54..5cba7be8b1ca 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1577 +#define __WMI_REVISION_ 1578 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 56040fad0f613999d64d08661ccf0155b3483edb Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 20 Feb 2025 06:01:42 -0800 Subject: [PATCH 030/306] fw-api: CL 28638758 - update fw common interface files Change-Id: I87ce14c3f75bc500871447c53ca07e2aee42c05b CRs-Fixed: 3830439 --- fw/wlan_defs.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fw/wlan_defs.h b/fw/wlan_defs.h index 2e8db1346a90..a2f7777c4c7c 100755 --- a/fw/wlan_defs.h +++ b/fw/wlan_defs.h @@ -161,6 +161,18 @@ typedef enum { MODE_11BE_EHT40_2G = 32, /* For WIN */ #endif +#if SUPPORT_11BN + MODE_11BN_UHR20 = 33, + MODE_11BN_UHR40 = 34, + MODE_11BN_UHR80 = 35, + MODE_11BN_UHR80_80 = 36, + MODE_11BN_UHR160 = 37, + MODE_11BN_UHR160_160 = 38, + MODE_11BN_UHR320 = 39, + MODE_11BN_UHR20_2G = 40, + MODE_11BN_UHR40_2G = 41, +#endif + /* * MODE_UNKNOWN should not be used within the host / target interface. * Thus, it is permissible for MODE_UNKNOWN to be conditionally-defined, From cd7a38954af6b6470c2d144c537570972598c3b4 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 21 Feb 2025 06:02:15 -0800 Subject: [PATCH 031/306] fw-api: CL 28639946 - update fw common interface files Change-Id: I39f96ad6863ad9bfbf578cb0dd76d437f6e44ea1 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 28 +++++++++++++++++++++------- fw/wmi_version.h | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index b500c3585263..2cfd13ffe269 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -49837,7 +49837,10 @@ typedef struct { } wmi_mlo_link_del_param; typedef enum { - WMI_EVENT_POWER_BOOST_START_TRAINING = 0, + WMI_EVENT_POWER_BOOST_START_INFERENCING = 0, + /* alias */ + WMI_EVENT_POWER_BOOST_START_TRAINING = + WMI_EVENT_POWER_BOOST_START_INFERENCING, WMI_EVENT_POWER_BOOST_ABORT, WMI_EVENT_POWER_BOOST_COMPLETE, @@ -49850,6 +49853,8 @@ typedef enum { WMI_PDEV_POWER_BOOST_TS_MAX } wmi_pdev_power_boost_training_stage; +typedef wmi_pdev_power_boost_training_stage + wmi_pdev_power_boost_inferencing_stage; /* alias */ typedef struct { /* WMITLV_TAG_STRUC_wmi_pdev_power_boost_event_fixed_param */ @@ -49858,11 +49863,14 @@ typedef struct { A_UINT32 pdev_id; /* enum wmi_pdev_power_boost_event_type to update the power boost status */ A_UINT32 status; - /* training_stage: - * The training stage for which the I/Q samples are updated in DDR. - * This field holds a wmi_pdev_power_boost_training_stage value. + /* inferencing_stage: + * The inferencing stage for which the I/Q samples are updated in DDR. + * This field holds a wmi_pdev_power_boost_inferencing_stage value. */ - A_UINT32 training_stage; + union { + A_UINT32 training_stage; /* deprecated name */ + A_UINT32 inferencing_stage; /* preferred name */ + }; /* MCS value for which the current DPD training has been done */ A_UINT32 mcs; /* bandwidth: @@ -49904,8 +49912,14 @@ typedef struct { A_UINT32 pdev_id; /* enum wmi_pdev_power_boost_cmd_type to update the power boost status */ A_UINT32 status; - /* wmi_pdev_power_boost_training_stage value to indicate training stage */ - A_UINT32 training_stage; + /* + * wmi_pdev_power_boost_inferencing_stage value to indicate + * inferencing stage + */ + union { + A_UINT32 training_stage; /* deprecated name */ + A_UINT32 inferencing_stage; /* preferred name */ + }; /* MCS value for which the Power Boost training has been done */ A_UINT32 mcs; /* Bandwidth in Mhz for which the Power Boost training has been done */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 5cba7be8b1ca..c1e1ef2f0385 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1578 +#define __WMI_REVISION_ 1579 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 8e2f923cfc2e91969f70493b5468a862edfae822 Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 25 Feb 2025 06:02:18 -0800 Subject: [PATCH 032/306] fw-api: CL 28676060 - update fw common interface files Change-Id: I2976f527990892e5bb7ec4feb858823eefc8d3b4 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 7 +++++++ fw/wmi_unified.h | 17 +++++++++++++++++ fw/wmi_version.h | 2 +- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index e8c306dbcb7f..c25cf1912694 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1476,6 +1476,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_sn_info, WMITLV_TAG_STRUC_wmi_vdev_vbss_config_event_fixed_param, WMITLV_TAG_STRUC_wmi_stats_ext_event_vdev_ext2_t, + WMITLV_TAG_STRUC_wmi_ndp_set_latency_tput_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2037,6 +2038,7 @@ typedef enum { OP(WMI_MLO_LINK_RECONFIG_COMPLETE_CMDID) \ OP(WMI_SAWF_EZMESH_HOP_COUNT_CMDID) \ OP(WMI_VDEV_VBSS_CONFIG_CMDID) \ + OP(WMI_NDP_SET_LATENCY_TPUT_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -4099,6 +4101,11 @@ WMITLV_CREATE_PARAM_STRUC(WMI_NDP_END_REQ_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_cmd_param, wmi_ndp_cmd_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_NDP_CMDID); +/* NDP Set Latency Tput Cmd */ +#define WMITLV_TABLE_WMI_NDP_SET_LATENCY_TPUT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_set_latency_tput_fixed_param, wmi_ndp_set_latency_tput_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_SET_LATENCY_TPUT_CMDID); + /* RCPI Info Request Cmd */ #define WMITLV_TABLE_WMI_REQUEST_RCPI_CMDID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_rcpi_cmd_fixed_param, wmi_request_rcpi_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 2cfd13ffe269..eacc47ba4efd 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -1601,6 +1601,7 @@ typedef enum { WMI_NDP_RESPONDER_REQ_CMDID, WMI_NDP_END_REQ_CMDID, WMI_NDP_CMDID, + WMI_NDP_SET_LATENCY_TPUT_CMDID, /** WMI commands related to HW data filtering **/ WMI_HW_DATA_FILTER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_HW_DATA_FILTER), @@ -29500,6 +29501,21 @@ typedef struct { #define wmi_ndp_cmd_param wmi_ndp_cmd_param_PROTOTYPE +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_set_latency_tput_fixed_param */ + A_UINT32 tlv_header; + /** NDP instance id */ + A_UINT32 ndp_instance_id; + /** NDI VDEV ID */ + A_UINT32 vdev_id; + /** latency reqirement */ + A_UINT32 latency_ms; + /** throughput requirement */ + A_UINT32 tput_mbps; +} wmi_ndp_set_latency_tput_fixed_param_PROTOTYPE; + +#define wmi_ndp_set_latency_tput_fixed_param wmi_ndp_set_latency_tput_fixed_param_PROTOTYPE + /** * NDP End request */ @@ -38726,6 +38742,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_MLO_LINK_RECONFIG_COMPLETE_CMDID); WMI_RETURN_STRING(WMI_SAWF_EZMESH_HOP_COUNT_CMDID); WMI_RETURN_STRING(WMI_VDEV_VBSS_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_NDP_SET_LATENCY_TPUT_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index c1e1ef2f0385..c3677c38d12f 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1579 +#define __WMI_REVISION_ 1580 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From b0b90ac4d856d1dcb9247c3dc41151ca948b2146 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 27 Feb 2025 06:01:52 -0800 Subject: [PATCH 033/306] fw-api: CL 28686055 - update fw common interface files Change-Id: I8ad9e55e926a44b0645d8719ab16014a46976151 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 10 +++++++--- fw/wmi_version.h | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index eacc47ba4efd..0c1741a57573 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -4959,7 +4959,10 @@ typedef struct { * So FW will start refilling the buffers. * Refer to the below definitions of WMI_RSRC_CFG_HOST_SERVICE_FLAG * OPT_DP_CTRL_REPLENISH_REFILL_RX_BUFFER_SUPPORT_GET and _SET macros. - * Bits 31:18 - Reserved + * Bit 18 + * This bit will be set by host to inform FW that VBSS feature is + * enabled. + * Bits 31:19 - Reserved */ A_UINT32 host_service_flags; @@ -50153,8 +50156,9 @@ typedef struct { } wmi_vdev_vbss_peer_sn_info; typedef enum { - WMI_VBSS_GET_PEER_CONTEXT = 0x1, - WMI_VBSS_SET_PEER_CONTEXT = 0x2, + WMI_VBSS_GET_PEER_CONTEXT = 1, + WMI_VBSS_SET_PEER_CONTEXT = 2, + WMI_VBSS_RX_SUSPEND_PEER_CONTEXT = 3, } wmi_vbss_action; #define WMI_VDEV_VBSS_GET_ACTION(action) WMI_GET_BITS(action, 0, 4) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index c3677c38d12f..22a20f1b01ce 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1580 +#define __WMI_REVISION_ 1581 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 1b6ed770d1302e62911ec5bfb5dcbec4163db437 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 28 Feb 2025 05:24:56 -0800 Subject: [PATCH 034/306] fw-api: CL 28705885 - update fw common interface files Change-Id: I9715efbcdbdceb0947101c58512106f64b81deb5 CRs-Fixed: 3830439 --- fw/wlan_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fw/wlan_defs.h b/fw/wlan_defs.h index a2f7777c4c7c..352967101d47 100755 --- a/fw/wlan_defs.h +++ b/fw/wlan_defs.h @@ -161,7 +161,7 @@ typedef enum { MODE_11BE_EHT40_2G = 32, /* For WIN */ #endif -#if SUPPORT_11BN +#if defined(SUPPORT_11BN) && SUPPORT_11BN MODE_11BN_UHR20 = 33, MODE_11BN_UHR40 = 34, MODE_11BN_UHR80 = 35, From 6bebc81e607bfa2f80969c13613b1a8940665be3 Mon Sep 17 00:00:00 2001 From: Krupali Dhanvijay Date: Fri, 21 Feb 2025 17:43:55 +0530 Subject: [PATCH 035/306] qcacld-3.0: Recalculate TX power post CSA Currently, host doesn't recalculate TX power post CSA if no change in power constraint or TPE IE, this can cause issue if local regulatory power is different for new CSA frequency. To address this issue, add support to recalculate TX power for first beacon received post CSA. Change-Id: I91f4609c552d579c24e781d382e647b6617e9315 CRs-Fixed: 3809724 --- core/mac/src/pe/include/lim_session.h | 4 +++- core/mac/src/pe/lim/lim_send_sme_rsp_messages.c | 2 ++ core/mac/src/pe/sch/sch_beacon_process.c | 5 +++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h index 5488a180a145..25f2f90143c5 100644 --- a/core/mac/src/pe/include/lim_session.h +++ b/core/mac/src/pe/include/lim_session.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -140,6 +140,7 @@ struct obss_detection_cfg { * @prev_auth_seq_num: Sequence number of previously received auth frame to * detect duplicate frames. * @prev_auth_mac_addr: mac_addr of the sta correspond to @prev_auth_seq_num + * @cal_tpc_post_csa: Recalculate tx power power csa */ struct pe_session { /* To check session table is in use or free */ @@ -580,6 +581,7 @@ struct pe_session { uint32_t dfs_regdomain; uint8_t ap_defined_power_type_6g; uint8_t best_6g_power_type; + bool cal_tpc_post_csa; }; /*------------------------------------------------------------------------- diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c index 8b6a073ea59e..639fac0c3c4f 100644 --- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c +++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1884,6 +1885,7 @@ void lim_handle_csa_offload_msg(struct mac_context *mac_ctx, err: qdf_mem_free(csa_params); + session_entry->cal_tpc_post_csa = true; } /*-------------------------------------------------------------------------- diff --git a/core/mac/src/pe/sch/sch_beacon_process.c b/core/mac/src/pe/sch/sch_beacon_process.c index 3c0914e6c71a..8ffa424d5962 100644 --- a/core/mac/src/pe/sch/sch_beacon_process.c +++ b/core/mac/src/pe/sch/sch_beacon_process.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -704,8 +704,9 @@ static void __sch_beacon_process_for_session(struct mac_context *mac_ctx, } if ((ap_constraint_change && local_constraint) || - (tpe_change && !skip_tpe)) { + (tpe_change && !skip_tpe) || session->cal_tpc_post_csa) { lim_calculate_tpc(mac_ctx, session); + session->cal_tpc_post_csa = false; if (tx_ops->set_tpc_power) tx_ops->set_tpc_power(mac_ctx->psoc, From ee56b3c1d79f335ad58c714546c6330688a0963e Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Tue, 4 Mar 2025 01:20:54 -0800 Subject: [PATCH 036/306] Release 2.0.8.35 Release 2.0.8.35 Change-Id: I2ce9028c33f0161e85772f0a7996cad2a515726a CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index c8f76c9a8572..3b4e0d649715 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "Z" -#define QWLAN_VERSION_BUILD 34 +#define QWLAN_VERSION_EXTRA "" +#define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.34Z" +#define QWLAN_VERSIONSTR "2.0.8.35" #endif /* QWLAN_VERSION_H */ From 0bfd131a4da53462b199c1f5ded68b16c4bf00ca Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 4 Mar 2025 06:01:37 -0800 Subject: [PATCH 037/306] fw-api: CL 28727084 - update fw common interface files Change-Id: Ibf9e0f097ba63bd742b857471edd34be88512656 CRs-Fixed: 3830439 --- fw/htt_stats.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index bbbfb982ac12..742adcff550e 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -8143,6 +8143,8 @@ typedef struct { A_UINT32 ru_type; /* refer to htt_stats_ru_type enum */ htt_tx_rate_stats_t per_ru[HTT_TX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS]; + + htt_tx_rate_stats_t per_tx_su_punctured_mode[HTT_TX_PDEV_STATS_NUM_PUNCTURED_MODE_COUNTERS]; } htt_stats_per_rate_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_per_rate_stats_tlv htt_tx_rate_stats_per_tlv; From c963eba2380d5fe0e98befe89e27b139b12db423 Mon Sep 17 00:00:00 2001 From: Vaibhav Vashisht Date: Sun, 2 Feb 2025 02:13:05 -0800 Subject: [PATCH 038/306] Revert "msm_ipa: Install exception rule for PPPoE-MPLS" This reverts commit 752e583b65efea2b18a10ba685cf722f8f1e4198. Reason for revert: don't install pppoe exceptions rules. This change is reverted to avoid modem crash. With this change dl rules are exceeding the sram partition range and hence modem crashes. This assert/crash introduced by q6 recently to check the dl rules boundary check. Change-Id: I9220efaaa9b0bfa306758d35603cfb2dff042714 Signed-off-by: Vaibhav Vashisht --- include/uapi/linux/msm_ipa.h | 47 ++---------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 8d2bb198379d..f63134040753 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -2,7 +2,7 @@ /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _UAPI_MSM_IPA_H_ @@ -1140,48 +1140,6 @@ static inline const char *exception_type_as_str(enum ipa_exception_type t) "???"; } -/** - * Macro ipa_exception_type_pppoe - * - * This macro is for describing which field is to be looked at for - * exception path consideration. - * - * NOTE 1: The field implies an offset into the packet under - * consideration. This offset will be calculated on behalf of - * the user of this API. - * - * NOTE 2: When exceptions are generated/sent in an ipa_exception - * structure, they will considered to be from the upload - * perspective. And when appropriate, a corresponding, and - * perhaps inverted, downlink exception will be automatically - * created on the callers behalf. As an example: If a - * FIELD_UDP_SRC_PORT is sent, an uplink exception will be - * created for udp source port, and a corresponding - * FIELD_UDP_DST_PORT will be automatically created for the - * downlink. - */ -#define FIELD_IP_PROTOCOL_PPPOE (FIELD_ETHER_TYPE + 1) -#define FIELD_TCP_SRC_PORT_PPPOE (FIELD_IP_PROTOCOL_PPPOE + 1) -#define FIELD_TCP_DST_PORT_PPPOE (FIELD_TCP_SRC_PORT_PPPOE + 1) -#define FIELD_UDP_SRC_PORT_PPPOE (FIELD_TCP_DST_PORT_PPPOE + 1) -#define FIELD_UDP_DST_PORT_PPPOE (FIELD_UDP_SRC_PORT_PPPOE + 1) -#define FIELD_ETHER_TYPE_PPPOE (FIELD_UDP_DST_PORT_PPPOE + 1) -#define FIELD_PPPOE_MAX (FIELD_ETHER_TYPE_PPPOE + 1) - -/* Function to read PPPoE exception in string format */ -static inline const char *pppoe_exception_type_as_str(uint32_t t) -{ - return - (t == FIELD_IP_PROTOCOL_PPPOE) ? "pppoe_ip_protocol" : - (t == FIELD_TCP_SRC_PORT_PPPOE) ? "pppoe_tcp_src_port" : - (t == FIELD_TCP_DST_PORT_PPPOE) ? "pppoe_tcp_dst_port" : - (t == FIELD_UDP_SRC_PORT_PPPOE) ? "pppoe_udp_src_port" : - (t == FIELD_UDP_DST_PORT_PPPOE) ? "pppoe_udp_dst_port" : - (t == FIELD_ETHER_TYPE_PPPOE) ? "pppoe_ether_type" : - (t == FIELD_PPPOE_MAX) ? "pppoe_max" : - "???"; -} - #define IP_TYPE_EXCEPTION(x) \ ((x) == FIELD_IP_PROTOCOL || \ (x) == FIELD_TCP_SRC_PORT || \ @@ -1262,7 +1220,6 @@ struct ipa_field_val_equation_gen { * @payload_length: Payload length. * @ext_attrib_mask: Extended attributes. * @l2tp_udp_next_hdr: next header in L2TP tunneling - * @p_exception : exception to enable for mpls-pppoe * @field_val_equ: for finding a value at a particular offset */ struct ipa_rule_attrib { @@ -1308,7 +1265,7 @@ struct ipa_rule_attrib { __u16 payload_length; __u32 ext_attrib_mask; __u8 l2tp_udp_next_hdr; - __u8 p_exception; + __u8 padding1; struct ipa_field_val_equation_gen fld_val_eq; }; From 0eab480551b664c5d2008dc6ce68ad91f20343af Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 6 Mar 2025 06:01:43 -0800 Subject: [PATCH 039/306] fw-api: CL 28739491 - update fw common interface files Change-Id: I0881566dbdb8f7485547e3cf1a20929bba9ec5f3 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 21 ++++++++++++++++++++- fw/wmi_version.h | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 0c1741a57573..2786461fb5de 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -4962,7 +4962,14 @@ typedef struct { * Bit 18 * This bit will be set by host to inform FW that VBSS feature is * enabled. - * Bits 31:19 - Reserved + * Bit 19 + * This bit will set by host to inform FW that the bypass approach + * for HLOS TID OVERRIDE feature not working needs to be supported, + * So FW will start handling the PPE2TCL enqueued packets with + * flow_override set. + * Refer to the below definitions of WMI_RSRC_CFG_HOST_SERVICE_FLAG + * OPT_DP_ENABLE_BYPASS_FOR_HLOS_TID_OVERRIDE_GET and _SET macros. + * Bits 31:20 - Reserved */ A_UINT32 host_service_flags; @@ -5480,6 +5487,18 @@ typedef struct { #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_VBSS_ENABLED_SET(host_service_flags, val) \ WMI_SET_BITS(host_service_flags, 18, 1, val) +/* + * This bit is to inform that we need to enable the bypass approach + * (for HLOS TID override feature not working in the target) + * to handle flowq creation from FW when flow override is set and + * frames are recvd from PPE2TCL. + * */ +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_OPT_DP_ENABLE_BYPASS_FOR_HLOS_TID_OVERRIDE_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 19, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_OPT_DP_ENABLE_BYPASS_FOR_HLOS_TID_OVERRIDE_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 19, 1, val) + + #define WMI_RSRC_CFG_CARRIER_CFG_CHARTER_ENABLE_GET(carrier_config) \ WMI_GET_BITS(carrier_config, 0, 1) #define WMI_RSRC_CFG_CARRIER_CFG_CHARTER_ENABLE_SET(carrier_config, val) \ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 22a20f1b01ce..7175ab734384 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1581 +#define __WMI_REVISION_ 1582 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From f5b3724adc02af2812eab5dfc358568c9807ad2e Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 7 Mar 2025 06:01:13 -0800 Subject: [PATCH 040/306] fw-api: CL 28748436 - update fw common interface files Change-Id: I82b61375c88f85fe8beaa2e6b6caca596c7446d9 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 13 +++++++++---- fw/wmi_version.h | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 2786461fb5de..99dff33ec961 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -21432,10 +21432,15 @@ typedef struct { #define WMI_PEER_PARAM_UL_OFDMA_RTD 0x2B /* - * Send unsolicited probe response to a connected STA. - * 0: Send immediately and stop. - * XX: Send every XX ms continuously. - * 0xFFFFFFFF: Stop sending immediately. + * Count and Interval to send unsolicited probe response to a connected STA. + * BIT 0-23 - Interval (in us) + * BIT 24-31 - Count (Number of probe response frame to send) + * + * Count : 0 - Stop sending immediately. + * Count : 1-254 - Send a probe response periodically at given interval + * until count expires. + * Count : 255 - Send a probe response periodically at given interval + * until stopped. */ #define WMI_PEER_PARAM_UNSOL_PROBE_RESP_INTVL 0x2C diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 7175ab734384..32d802c1f7da 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1582 +#define __WMI_REVISION_ 1583 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From b3a14a52cbdab8b8bf61933beb11aa87091af6c7 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 8 Mar 2025 06:01:29 -0800 Subject: [PATCH 041/306] fw-api: CL 28757294 - update fw common interface files Change-Id: I13640fafb233b52822504f80f35a0addc0e28f07 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 20 +++++++++++++++++++- fw/wmi_version.h | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 99dff33ec961..8414aac5124a 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -3564,6 +3564,21 @@ typedef struct { #define WMI_TARGET_CAP_MPDU_STATS_PER_TX_NSS_SUPPORT_SET(target_cap_flags, value)\ WMI_SET_BITS(target_cap_flags, 16, 1, value) +#define WMI_TARGET_CAP_MAX_ML_STA_BSS_NUM_GET(target_cap_flags) \ + WMI_GET_BITS(target_cap_flags, 17, 3) +#define WMI_TARGET_CAP_MAX_ML_STA_BSS_NUM_SET(target_cap_flags, value) \ + WMI_SET_BITS(target_cap_flags, 17, 3, value) + +#define WMI_TARGET_CAP_MAX_ML_SAP_BSS_NUM_GET(target_cap_flags) \ + WMI_GET_BITS(target_cap_flags, 20, 3) +#define WMI_TARGET_CAP_MAX_ML_SAP_BSS_NUM_SET(target_cap_flags, value) \ + WMI_SET_BITS(target_cap_flags, 20, 3, value) + +#define WMI_TARGET_CAP_TOTAL_ML_LINKS_NUM_GET(target_cap_flags) \ + WMI_GET_BITS(target_cap_flags, 23, 3) +#define WMI_TARGET_CAP_TOTAL_ML_LINKS_NUM_SET(target_cap_flags, value) \ + WMI_SET_BITS(target_cap_flags, 23, 3, value) + /* * wmi_htt_msdu_idx_to_htt_msdu_qtype GET/SET APIs @@ -3763,7 +3778,10 @@ typedef struct { * Bit 14 - Support for ML monitor mode * Bit 15 - Support for Qdata Tx LCE filter installation * Bit 16 - Support for MPDU stats per tx Nss capability - * Bits 31:17 - Reserved + * Bits 19:17 - max number of ML STA BSS supported, range [0-7] + * Bits 22:20 - max number of ML SAP BSS supported, range [0-7] + * Bits 25:23 - total number of ML links supported, range [0-7] + * Bits 31:26 - Reserved */ A_UINT32 target_cap_flags; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 32d802c1f7da..e12e4eedfb54 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1583 +#define __WMI_REVISION_ 1584 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From d6a623bd6ef117363dbba16d8d9ccda5ad40f529 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 15 Mar 2025 06:01:45 -0700 Subject: [PATCH 042/306] fw-api: CL 28805911 - update fw common interface files Change-Id: I4256994b4befaef82e0358413e3ee58565339fff CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_tlv_defs.h | 4 +++- fw/wmi_unified.h | 16 ++++++++++++++++ fw/wmi_version.h | 2 +- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index b82c7bd1fc45..7411d6aa6c0b 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -695,6 +695,7 @@ typedef enum { WMI_SERVICE_UMAC_MIGRATION_SUPPORT = 436, /* Indicates that FW supports UMAC migration */ WMI_SERVICE_STA_TWT_STATS_EXT = 437, /* FW supports additional info in TWT stats and ADD COMPLETION Event */ WMI_SERVICE_OPT_DP_DIAG_SUPPORT = 438, /* FW supports diag QDATA feature */ + WMI_SERVICE_MLO_ROAM_PARTNER_BRINGUP_FROM_HOST = 439, /* Indicates FW supports new design in which FW expects the host to bringup the partner link during roaming */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index c25cf1912694..a5028647b8f1 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1477,6 +1477,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_vdev_vbss_config_event_fixed_param, WMITLV_TAG_STRUC_wmi_stats_ext_event_vdev_ext2_t, WMITLV_TAG_STRUC_wmi_ndp_set_latency_tput_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_partner_link_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -6099,7 +6100,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_AGGR_STATE_TRIG_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, deauth_disassoc_frame, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_hw_mode_transition_event_fixed_param, hw_mode_transition_fixed_param, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_set_hw_mode_response_vdev_mac_entry, wmi_pdev_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_bss_info_param, bss_info_param, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_bss_info_param, bss_info_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_partner_link_param, partner_link_param, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_EVENTID); /* Roam Synch Event */ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 8414aac5124a..88c169364fb7 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -23500,6 +23500,7 @@ typedef struct { A_UINT32 no_ack_timeout; /* In msec. duration to wait before another SW retry made if no ack seen for previous frame */ A_UINT32 roam_candidate_validity_time; /* In msec. validity duration of each entry in roam cache. If the value is 0x0, this field should be disregarded. */ A_UINT32 roam_to_current_bss_disable; /* Disable roaming to current bss */ + A_UINT32 mlo_roam_partner_bringup_by_host; } wmi_roam_offload_tlv_param; @@ -23728,6 +23729,21 @@ typedef struct { wmi_mac_addr mac_addr; } wmi_roam_bss_info_param; +typedef struct { + A_UINT32 tlv_header; + /* These params are filled in the new design done for MLO roam + * optimization; only in roam abort cases Fw deletes partner links + * at the start of roam handoff itself. + * Host needs to take care of bringing up the partner link if + * roam fails based on deleted_ieee_link_id_bmap; + * deleted_ieee_link_id_bmap represents the ieee_link_id of the + * links which were deleted at the start of roam handoff. + * This is filled only for MLO and deleted_ieee_link_id_bmap = 0 + * means no link was deleted. + */ + A_UINT32 deleted_link_bmap; +} wmi_roam_partner_link_param; + /* roam_reason: bits 0-3 */ #define WMI_ROAM_REASON_INVALID 0x0 /** invalid reason. Do not interpret reason field */ #define WMI_ROAM_REASON_BETTER_AP 0x1 /** found a better AP */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index e12e4eedfb54..d44554f6f2d7 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1584 +#define __WMI_REVISION_ 1585 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From fedef6bc6438825942c0d67df07883daffbf66aa Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 16 Mar 2025 06:01:20 -0700 Subject: [PATCH 043/306] fw-api: CL 28811455 - update fw common interface files Change-Id: Ie14558a7d79c26daa984c53557ea240c3c858ebf CRs-Fixed: 3830439 --- fw/htt_stats.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 742adcff550e..ea524e6d7486 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -2017,6 +2017,22 @@ typedef htt_stats_peer_stats_cmn_tlv htt_peer_stats_cmn_tlv; #define HTT_PEER_DETAILS_SRC_INFO_M 0x00000fff #define HTT_PEER_DETAILS_SRC_INFO_S 0 +#define HTT_PEER_DETAILS_PEER_PS_ENTRY_M 0x000000ff +#define HTT_PEER_DETAILS_PEER_PS_ENTRY_S 0 +#define HTT_PEER_DETAILS_PEER_PS_EXIT_M 0x0000ff00 +#define HTT_PEER_DETAILS_PEER_PS_EXIT_S 8 +#define HTT_PEER_DETAILS_PEER_PSPOLL_TRIGGER_M 0x00ff0000 +#define HTT_PEER_DETAILS_PEER_PSPOLL_TRIGGER_S 16 +#define HTT_PEER_DETAILS_PEER_UAPSD_TRIGGER_M 0xff000000 +#define HTT_PEER_DETAILS_PEER_UAPSD_TRIGGER_S 24 + +#define HTT_PEER_DETAILS_PEER_PS_HISTOGRAM_0_M 0x000003ff +#define HTT_PEER_DETAILS_PEER_PS_HISTOGRAM_0_S 0 +#define HTT_PEER_DETAILS_PEER_PS_HISTOGRAM_1_M 0x000ffc00 +#define HTT_PEER_DETAILS_PEER_PS_HISTOGRAM_1_S 10 +#define HTT_PEER_DETAILS_PEER_PS_HISTOGRAM_2_M 0x3ff00000 +#define HTT_PEER_DETAILS_PEER_PS_HISTOGRAM_2_S 20 + #define HTT_PEER_DETAILS_SET(word, httsym, val) \ do { \ @@ -2062,6 +2078,34 @@ typedef struct { rsvd1 : 20; /* [31:12] */ }; }; + + /* Dword 10 */ + union { + A_UINT32 word__peer_ps_entry__peer_ps_exit__peer_pspoll_trigger_received__peer_uapsd_trigger_received; + struct { + A_UINT32 peer_ps_entry : 8, /* [7:0] */ + peer_ps_exit : 8, /* [15:8] */ + peer_pspoll_trigger_received : 8, /* [23:16] */ + peer_uapsd_trigger_received : 8; /* [31:24] */ + }; + }; + + /* Dword 11 */ + union { + A_UINT32 word__peer_ps_histogram_0__peer_ps_histogram_1__peer_ps_histogram_2; + struct { + /* + * This word holds 3 10-bit histograms of power-save durations: + * bits 9:0 - count of durations < 200 ms + * bits 19:10 - count of durations between 200 to 500 ms + * bits 29:20 - count of durations > 500 ms + */ + A_UINT32 peer_ps_histogram_0 : 10, /* [9:0] */ + peer_ps_histogram_1 : 10, /* [19:10] */ + peer_ps_histogram_2 : 10, /* [29:20] */ + rsvd2 : 2; /* [31:30] */ + }; + }; } htt_stats_peer_details_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_peer_details_tlv htt_peer_details_tlv; @@ -2073,6 +2117,21 @@ typedef htt_stats_peer_details_tlv htt_peer_details_tlv; #define HTT_STATS_PEER_DETAILS_SRC_INFO_GET(word) ((word >> 0) & 0xfff) +#define HTT_STATS_PEER_DETAILS_PEER_PS_ENTRY_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_PS_ENTRY) +#define HTT_STATS_PEER_DETAILS_PEER_PS_EXIT_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_PS_EXIT) +#define HTT_STATS_PEER_DETAILS_PEER_PSPOLL_TRIGGER_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_PSPOLL_TRIGGER) +#define HTT_STATS_PEER_DETAILS_PEER_UAPSD_TRIGGER_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_UAPSD_TRIGGER) +#define HTT_STATS_PEER_DETAILS_PEER_PS_HISTOGRAM_0_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_PS_HISTOGRAM_0) +#define HTT_STATS_PEER_DETAILS_PEER_PS_HISTOGRAM_1_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_PS_HISTOGRAM_1) +#define HTT_STATS_PEER_DETAILS_PEER_PS_HISTOGRAM_2_GET(word) \ + HTT_PEER_DETAILS_GET(word, PEER_PS_HISTOGRAM_2) + typedef struct { htt_tlv_hdr_t tlv_hdr; A_UINT32 sw_peer_id; From 064a6285fcf6ad94095aa60d7fcf5c9febf6e577 Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Thu, 13 Mar 2025 23:22:48 +0530 Subject: [PATCH 044/306] FROMGIT: media: venus: hfi_parser: add check to avoid out of bound access There is a possibility that init_codecs is invoked multiple times during manipulated payload from video firmware. In such case, if codecs_count can get incremented to value more than MAX_CODEC_NUM, there can be OOB access. Reset the count so that it always starts from beginning. Cc: stable@vger.kernel.org Fixes: 1a73374a04e5 ("media: venus: hfi_parser: add common capability parser") Reviewed-by: Bryan O'Donoghue CRs-Fixed: 3935643 Change-Id: I6216e773af65082e4775b415789ffd549e0bed2d Git-commit: 172bf5a9ef70a399bb227809db78442dc01d9e48 Git-repo: https://gitlab.freedesktop.org/linux-media/media-committers.git Signed-off-by: Vikash Garodia --- drivers/media/platform/qcom/venus/hfi_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index ad22b51765d4..6a8259bcf0be 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -19,6 +19,8 @@ static void init_codecs(struct venus_core *core) struct venus_caps *caps = core->caps, *cap; unsigned long bit; + core->codecs_count = 0; + if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM) return; From 45e1a910b657c514b5c3974f16db0b32c48cd7e8 Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Tue, 5 Nov 2024 14:24:56 +0530 Subject: [PATCH 045/306] FROMGIT: media: venus: hfi: add check to handle incorrect queue size qsize represents size of shared queued between driver and video firmware. Firmware can modify this value to an invalid large value. In such situation, empty_space will be bigger than the space actually available. Since new_wr_idx is not checked, so the following code will result in an OOB write. ... qsize = qhdr->q_size if (wr_idx >= rd_idx) empty_space = qsize - (wr_idx - rd_idx) .... if (new_wr_idx < qsize) { memcpy(wr_ptr, packet, dwords << 2) --> OOB write Add check to ensure qsize is within the allocated size while reading and writing packets into the queue. Cc: stable@vger.kernel.org Fixes: d96d3f30c0f2 ("[media] media: venus: hfi: add Venus HFI files") Reviewed-by: Bryan O'Donoghue CRs-Fixed: 3935673 Change-Id: Ifb907d4a4c82f853081492e06e68180476367ed5 Git-commit: 69baf245b23e20efda0079238b27fc63ecf13de1 Git-repo: https://gitlab.freedesktop.org/linux-media/media-committers.git Signed-off-by: Vikash Garodia --- drivers/media/platform/qcom/venus/hfi_venus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 306082e25943..2921486c3238 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -188,6 +188,9 @@ static int venus_write_queue(struct venus_hfi_device *hdev, /* ensure rd/wr indices's are read from memory */ rmb(); + if (qsize > IFACEQ_QUEUE_SIZE / 4) + return -EINVAL; + if (wr_idx >= rd_idx) empty_space = qsize - (wr_idx - rd_idx); else @@ -256,6 +259,9 @@ static int venus_read_queue(struct venus_hfi_device *hdev, wr_idx = qhdr->write_idx; qsize = qhdr->q_size; + if (qsize > IFACEQ_QUEUE_SIZE / 4) + return -EINVAL; + /* make sure data is valid before using it */ rmb(); From d15a6a8a95bf7b73cea1e5d7f7f8f348bbc8e22c Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Tue, 5 Nov 2024 14:24:57 +0530 Subject: [PATCH 046/306] FROMGIT: media: venus: hfi: add a check to handle OOB in sfr region sfr->buf_size is in shared memory and can be modified by malicious user. OOB write is possible when the size is made higher than actual sfr data buffer. Cap the size to allocated size for such cases. Cc: stable@vger.kernel.org Fixes: d96d3f30c0f2 ("[media] media: venus: hfi: add Venus HFI files") Reviewed-by: Bryan O'Donoghue CRs-Fixed: 3947576 Change-Id: I483a5feff3dfa35dae8f444e57601d2d1d85246f Git-commit: f4b211714bcc70effa60c34d9fa613d182e3ef1e Git-repo: https://gitlab.freedesktop.org/linux-media/media-committers.git Signed-off-by: Vikash Garodia --- drivers/media/platform/qcom/venus/hfi_venus.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 306082e25943..0b6cf86004fd 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -970,18 +970,26 @@ static void venus_sfr_print(struct venus_hfi_device *hdev) { struct device *dev = hdev->core->dev; struct hfi_sfr *sfr = hdev->sfr.kva; + u32 size; void *p; if (!sfr) return; - p = memchr(sfr->data, '\0', sfr->buf_size); + size = sfr->buf_size; + if (!size) + return; + + if (size > ALIGNED_SFR_SIZE) + size = ALIGNED_SFR_SIZE; + + p = memchr(sfr->data, '\0', size); /* * SFR isn't guaranteed to be NULL terminated since SYS_ERROR indicates * that Venus is in the process of crashing. */ if (!p) - sfr->data[sfr->buf_size - 1] = '\0'; + sfr->data[size - 1] = '\0'; dev_err_ratelimited(dev, "SFR message from FW: %s\n", sfr->data); } From c3f431c2c71092950f625e5869fa418bbe09463f Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Mon, 10 Feb 2025 17:11:38 +0530 Subject: [PATCH 047/306] dsp: q6adm: Checking array sizeof channel_type there is no check for size of num_channels is less than are equal to channel_type Change-Id: I066857d693665412c52dc579f69acdaac66d5903 Signed-off-by: Manish Kumar --- dsp/q6adm.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dsp/q6adm.c b/dsp/q6adm.c index 7455252e2f08..6000c77331e1 100644 --- a/dsp/q6adm.c +++ b/dsp/q6adm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include @@ -3910,10 +3910,14 @@ void adm_copp_mfc_cfg(int port_id, int copp_idx, int dst_sample_rate) pr_err("%s: unable to get channal map\n", __func__); goto fail_cmd; } - - for (i = 0; i < mfc_cfg.num_channels; i++) - mfc_cfg.channel_type[i] = + if (mfc_cfg.num_channels <= AUDPROC_MFC_OUT_CHANNELS_MAX) { + for (i = 0; i < mfc_cfg.num_channels; i++) + mfc_cfg.channel_type[i] = (uint16_t) open.dev_channel_mapping[i]; + } else { + pr_err("%s: size of num_channels is greater than channel type \n", __func__); + goto fail_cmd; + } atomic_set(&this_adm.copp.stat[port_idx][copp_idx], -1); From b19d4a3a8e2d7f34a57aefb386ed56327b608def Mon Sep 17 00:00:00 2001 From: Jayasri Sampath Kumaran Date: Wed, 28 Aug 2024 15:46:09 -0400 Subject: [PATCH 048/306] disp: msm: sde: fix kms NULL pointer access in encoder IRQ control A possible kms NULL pointer access is found during CPU vote for IRQ when kms isn't NULL checked before accessing structure members. So, perform kms NULL check before accessing members. Change-Id: I137759ea0723be8580e9166c983d1ba38f4eb281 Signed-off-by: Jayasri Sampath Kumaran (cherry picked from commit 393118f87846d64a10c1d5a32161bcbe012c0667) (cherry picked from commit 17513cad23c67a11431fdfd77a59d5e207352dbc) --- msm/sde/sde_encoder.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index d2c54c99ab14..5a4006468a59 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1434,6 +1434,7 @@ static int _sde_encoder_update_rsc_client( void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable) { struct sde_encoder_virt *sde_enc; + struct sde_kms *sde_kms = NULL; int i; if (!drm_enc) { @@ -1441,6 +1442,12 @@ void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable) return; } + sde_kms = sde_encoder_get_kms(drm_enc); + if (!sde_kms) { + SDE_ERROR("invalid kms\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); SDE_DEBUG_ENC(sde_enc, "enable:%d\n", enable); @@ -1450,7 +1457,7 @@ void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable) if (phys && phys->ops.irq_control) phys->ops.irq_control(phys, enable); } - sde_kms_cpu_vote_for_irq(sde_encoder_get_kms(drm_enc), enable); + sde_kms_cpu_vote_for_irq(sde_kms, enable); } From c69a241cd99da17fe666564deaaebe07bf40fefc Mon Sep 17 00:00:00 2001 From: Aditya Kodukula Date: Wed, 8 Jan 2025 11:55:23 -0800 Subject: [PATCH 049/306] qcacld-3.0: Fix potential OOB memory access Currently in the wma_stats_ext_event_handler(), the buf_ptr is not pointing correctly to the event data received from FW. This is leading to an OOB memory access during qdf_mem_copy(). So, to avoid this issue correctly point the buf_ptr to the event data sent by the FW in the TLV. Change-Id: Iffa3e96a6a36eff5899a7a9a7febe0ebb9d7878f CRs-Fixed: 4011656 --- core/wma/src/wma_utils.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index e8f10039e0ad..3f34979096b8 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -708,7 +708,6 @@ int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, } stats_ext_info = param_buf->fixed_param; - buf_ptr = (uint8_t *)stats_ext_info; alloc_len = sizeof(tSirStatsExtEvent); alloc_len += stats_ext_info->data_len; @@ -725,7 +724,7 @@ int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, if (!stats_ext_event) return -ENOMEM; - buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE; + buf_ptr = (uint8_t *)param_buf->data; stats_ext_event->vdev_id = stats_ext_info->vdev_id; stats_ext_event->event_data_len = stats_ext_info->data_len; @@ -775,7 +774,6 @@ int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, } stats_ext_info = param_buf->fixed_param; - buf_ptr = (uint8_t *)stats_ext_info; alloc_len = sizeof(tSirStatsExtEvent); alloc_len += stats_ext_info->data_len; @@ -791,7 +789,7 @@ int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, if (!stats_ext_event) return -ENOMEM; - buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE; + buf_ptr = (uint8_t *)param_buf->data; stats_ext_event->vdev_id = stats_ext_info->vdev_id; stats_ext_event->event_data_len = stats_ext_info->data_len; From b6c8048d829e93b8b045ee0cb64c8257c766c31a Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Thu, 27 Mar 2025 11:15:32 -0700 Subject: [PATCH 050/306] Release 2.0.8.35A Release 2.0.8.35A Change-Id: Ib7f525b0dbae414daa80b9e2d204943d6827aae4 CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 3b4e0d649715..5a0f26d5d2fc 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "" +#define QWLAN_VERSION_EXTRA "A" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35" +#define QWLAN_VERSIONSTR "2.0.8.35A" #endif /* QWLAN_VERSION_H */ From 2d6a1b0a8f30279bca1d48ba1cf6cb3d4a4fb19d Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 19 Mar 2025 06:09:25 -0700 Subject: [PATCH 051/306] fw-api: CL 28829747 - update fw common interface files Change-Id: I5cea8ad46033ef8aa4dd8cd4e3d495b7fc5fe4d5 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 7 +++++++ fw/wmi_unified.h | 33 ++++++++++++++++++++++++++++++--- fw/wmi_version.h | 2 +- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index a5028647b8f1..5f83c5bbaada 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1478,6 +1478,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_stats_ext_event_vdev_ext2_t, WMITLV_TAG_STRUC_wmi_ndp_set_latency_tput_fixed_param, WMITLV_TAG_STRUC_wmi_roam_partner_link_param, + WMITLV_TAG_STRUC_wmi_mlo_link_ttlm_complete_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2040,6 +2041,7 @@ typedef enum { OP(WMI_SAWF_EZMESH_HOP_COUNT_CMDID) \ OP(WMI_VDEV_VBSS_CONFIG_CMDID) \ OP(WMI_NDP_SET_LATENCY_TPUT_CMDID) \ + OP(WMI_MLO_LINK_TTLM_COMPLETE_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -5392,6 +5394,11 @@ WMITLV_CREATE_PARAM_STRUC(WMI_MLO_LINK_RECONFIG_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mlo_link_reconfig_complete_fixed_param, wmi_mlo_link_reconfig_complete_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_MLO_LINK_RECONFIG_COMPLETE_CMDID); +/** WMI cmd to notify fw completion of link TTLM negotiation */ +#define WMITLV_TABLE_WMI_MLO_LINK_TTLM_COMPLETE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mlo_link_ttlm_complete_fixed_param, wmi_mlo_link_ttlm_complete_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MLO_LINK_TTLM_COMPLETE_CMDID); + /* Mcast ipv4 address filter list cmd */ #define WMITLV_TABLE_WMI_VDEV_IGMP_OFFLOAD_CMDID(id,op,buf,len) \ WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_igmp_offload_fixed_param, wmi_igmp_offload_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 88c169364fb7..4adbf62d826e 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -1703,6 +1703,8 @@ typedef enum { WMI_MLO_LINK_RECONFIG_CMDID, /** WMI cmd to notify fw completion of link reconfig */ WMI_MLO_LINK_RECONFIG_COMPLETE_CMDID, + /** WMI cmd to notify fw completion of negotiated TID to LINK map */ + WMI_MLO_LINK_TTLM_COMPLETE_CMDID, /** WMI commands specific to Service Aware WiFi (SAWF) */ /** configure or reconfigure the parameters for a service class */ @@ -2589,6 +2591,9 @@ typedef enum { WMI_MLO_VDEV_LINK_INFO_EVENTID, /** request host to do T2LM neg to the un-disabled link */ WMI_MLO_LINK_DISABLE_REQUEST_EVENTID, + /* alias */ + WMI_MLO_LINK_TTLM_REQUEST_EVENTID = + WMI_MLO_LINK_DISABLE_REQUEST_EVENTID, /** request host to switch to new link for specified vdev */ WMI_MLO_LINK_SWITCH_REQUEST_EVENTID, /** Response event for WMI_MLO_PRIMARY_LINK_PEER_MIGRATION_CMDID */ @@ -38804,6 +38809,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_SAWF_EZMESH_HOP_COUNT_CMDID); WMI_RETURN_STRING(WMI_VDEV_VBSS_CONFIG_CMDID); WMI_RETURN_STRING(WMI_NDP_SET_LATENCY_TPUT_CMDID); + WMI_RETURN_STRING(WMI_MLO_LINK_TTLM_COMPLETE_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; @@ -41852,6 +41858,8 @@ typedef enum { WMI_ROAM_FAIL_REASON_CURR_AP_STILL_OK, /* Roam scan not happen due to current network condition is fine */ WMI_ROAM_FAIL_REASON_SCAN_CANCEL, /* Roam scan canceled */ WMI_ROAM_FAIL_REASON_MLD_EXTRA_SCAN_REQUIRED, /* Roaming is not triggered for current roam scan as extra scan is required to scan all MLD links */ + WMI_ROAM_FAIL_REASON_TTLM_REQUIRED, /* Roaming is not triggered as TTLM is required */ + WMI_ROAM_FAIL_REASON_LINKRECONFIG_REQUIRED, /* Roaming is not triggered as linkreconfig is required */ WMI_ROAM_FAIL_REASON_UNKNOWN = 255, } WMI_ROAM_FAIL_REASON_ID; @@ -47133,11 +47141,30 @@ typedef struct { /* MLD address of AP */ wmi_mac_addr mld_addr; /* any non-zero values of status indicate link reconfig failure. */ - A_UINT32 status; - /* valid only when status is non-zero. fw will do reassociation if link reconfig failure */ - A_UINT32 reassoc_if_failure; + A_UINT32 status; + /* reassoc_if_failure: + * Valid only when status is non-zero. + * FW will do reassociation if link reconfig failure. + */ + A_UINT32 reassoc_if_failure; } wmi_mlo_link_reconfig_complete_fixed_param; +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mlo_link_ttlm_complete_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* MLD address of AP */ + wmi_mac_addr mld_addr; + /* any non-zero values of status indicate link TTLM failure. */ + A_UINT32 status; + /* reassoc_if_failure: + * Valid only when status is non-zero. + * FW will do reassociation if link reconfig failure. + */ + A_UINT32 reassoc_if_failure; +} wmi_mlo_link_ttlm_complete_fixed_param; + #define WMI_TID_TO_LINK_MAP_TID_NUM_GET(_var) WMI_GET_BITS(_var, 0, 5) #define WMI_TID_TO_LINK_MAP_TID_NUM_SET(_var, _val) WMI_SET_BITS(_var, 0, 5, _val) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index d44554f6f2d7..8c2eaa3ed79f 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1585 +#define __WMI_REVISION_ 1586 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 75d3cafb4fa665446f346de008b61a0b498d319d Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 20 Mar 2025 06:04:25 -0700 Subject: [PATCH 052/306] fw-api: CL 28837244 - update fw common interface files Change-Id: Ica6e78dd65b60293236a533dcb90f6c6dc4d20f5 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 4adbf62d826e..a7777f3d18aa 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -13490,6 +13490,7 @@ typedef enum { WMI_CTRL_PATH_STATS_CAL_TYPE_PADROOP = 0x17, WMI_CTRL_PATH_STATS_CAL_TYPE_SELFCALTPC = 0x18, WMI_CTRL_PATH_STATS_CAL_TYPE_RXSPUR = 0x19, + WMI_CTRL_PATH_STATS_CAL_TYPE_PDADC = 0x1a, /* add new cal types above this line */ WMI_CTRL_PATH_STATS_CAL_TYPE_INVALID = 0xFF @@ -13589,6 +13590,7 @@ static INLINE A_UINT8 *wmi_ctrl_path_cal_type_id_to_name(A_UINT32 cal_type_id) WMI_RETURN_STRING(WMI_CTRL_PATH_STATS_CAL_TYPE_PADROOP); WMI_RETURN_STRING(WMI_CTRL_PATH_STATS_CAL_TYPE_SELFCALTPC); WMI_RETURN_STRING(WMI_CTRL_PATH_STATS_CAL_TYPE_RXSPUR); + WMI_RETURN_STRING(WMI_CTRL_PATH_STATS_CAL_TYPE_PDADC); } return (A_UINT8 *) "WMI_CTRL_PATH_STATS_CAL_TYPE_UNKNOWN"; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 8c2eaa3ed79f..a7a52290c73a 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1586 +#define __WMI_REVISION_ 1587 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 1dac7cef2e4ba8ed183a80c5a5c5c9e7b4ee3caf Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 21 Mar 2025 06:01:19 -0700 Subject: [PATCH 053/306] fw-api: CL 28843692 - update fw common interface files Change-Id: Iea151c382a79e52cfabcd969775a77a7ece3cc11 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 9 +++++++++ fw/wmi_version.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index a7777f3d18aa..201bdee54d9b 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -22681,6 +22681,15 @@ typedef struct { A_UINT32 roam_scan_period_after_inactivity; /* units = milliseconds */ /** roam full scan period value */ A_UINT32 roam_full_scan_period; /* units = milliseconds */ + /** roam_periodic_scan_interval: + * Timer value to periodically trigger the roaming process at + * set intervals during low RSSI roaming trigger. + * Low rssi trigger (Partial/full) --> + * 10s (partial) --> + * 20s (partial) --> + * 30s (partial) and so on. + */ + A_UINT32 roam_periodic_scan_interval; /* units = seconds */ } wmi_roam_scan_period_fixed_param; /** diff --git a/fw/wmi_version.h b/fw/wmi_version.h index a7a52290c73a..e24ec27599c6 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1587 +#define __WMI_REVISION_ 1588 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From b0e9177c14a0afbe6e2ef8d725353ead2da28b5e Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 22 Mar 2025 06:01:16 -0700 Subject: [PATCH 054/306] fw-api: CL 28855140 - update fw common interface files Change-Id: Ie8025f02eb197bc8110696ea213970523b9c7968 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 +- fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 201bdee54d9b..833d859d12a9 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -23757,7 +23757,7 @@ typedef struct { * This is filled only for MLO and deleted_ieee_link_id_bmap = 0 * means no link was deleted. */ - A_UINT32 deleted_link_bmap; + A_UINT32 deleted_ieee_link_id_bmap; } wmi_roam_partner_link_param; /* roam_reason: bits 0-3 */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index e24ec27599c6..bdc0aaca1fd1 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1588 +#define __WMI_REVISION_ 1589 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From ffe6aeb19c87aae2a033ed0810eed7c4e6a03608 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 22 Mar 2025 06:02:51 -0700 Subject: [PATCH 055/306] fw-api: CL 28862777 - update fw common interface files Change-Id: I6ac807713fa5e0cff9ef9f2db16405cde18127ce CRs-Fixed: 3830439 --- fw/wmi_unified.h | 23 +++++++++++++++++++++-- fw/wmi_version.h | 2 +- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 833d859d12a9..26d7bb3a044d 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -12591,8 +12591,20 @@ typedef struct { * * b'31-b'29 unused / reserved * b'28 indicate the version of rate-code (1 = RATECODE_V1) - * b'27-b'11 unused / reserved - * b'10-b'8 indicate the preamble (0 OFDM, 1 CCK, 2 HT, 3 VHT) + * b'27 unused / reserved + * b'26-b'19 indicate TX power (int8), with 0.25 dBm units + * b'15-b'14 indicate punctured mode as follows: + * 0: NO_PUNCTURE + * 1: PUNCTURED_20MHZ + * 2: PUNCTURED_40MHZ + * 3: PUNCTURED_80MHZ + * 4: PUNCTURED_120MHZ + * b'15-b'14 indicate the guard interval: + * 0: 800us, 1: 400us, 2: 1600us, 3: 3200us + * b'13-b'11 indicate the bandwidth: + * 0: 20MHz, 1: 40MHz, 2: 80MHz, 3: 160MHz, 4: 320MHz + * b'10-b'8 indicate the preamble: + * 0: OFDM, 1: CCK, 2: HT, 3: VHT, 4: HE, 5: EHT * b'7-b'5 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3, 3 - 4x4) * b'4-b'0 indicate the rate, which is indicated as follows: * OFDM : 0: OFDM 48 Mbps @@ -12615,6 +12627,9 @@ typedef struct { * 0..7: MCS0..MCS7 (HT) * 0..9: MCS0..MCS9 (11AC VHT) * 0..11: MCS0..MCS11 (11AX VHT) + * HE/EHT (pream == 4/5) + * 0..13: MCS0..MCS13 (11AX EHT) + * 14..15: MCS14..MCS15 (EHT) */ /** rate-code of the last transmission */ A_UINT32 last_tx_rate_code; @@ -17962,6 +17977,10 @@ typedef enum { #define WMI_HECAP_MAC_HTVHTTRIGRX_GET_D2(he_cap2) (0) #define WMI_HECAP_MAC_HTVHTTRIGRX_SET_D2(he_cap2, value) {;} +#define WMI_GET_HW_RATECODE_VERSION(_rcode) (((_rcode) >> 28) & 0x1) +#define WMI_SET_HW_RATECODE_VERSION_V1(_rcode) (((1) << 28) | (_rcode)) +#define WMI_GET_HW_RATECODE_GI_V1(_rcode) (((_rcode) >> 14) & 0x3) +#define WMI_GET_HW_RATECODE_BW_V1(_rcode) (((_rcode) >> 11) & 0x7) #define WMI_GET_HW_RATECODE_PREAM_V1(_rcode) (((_rcode) >> 8) & 0x7) #define WMI_GET_HW_RATECODE_NSS_V1(_rcode) (((_rcode) >> 5) & 0x7) #define WMI_GET_HW_RATECODE_RATE_V1(_rcode) (((_rcode) >> 0) & 0x1F) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index bdc0aaca1fd1..7357c932a42d 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1589 +#define __WMI_REVISION_ 1590 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From b0eaa6a4e4bb039700dd752bf8779121601dda80 Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Thu, 7 Nov 2024 11:31:17 +0530 Subject: [PATCH 056/306] msm: ep_pcie: Wake host in D3cold handling if wake is pending In below sequence where device requested for inband pme but host still proceed with #PERST assertion the ep_pcie_core_wakeup_host_internal is called to toggle wake gpio. Event Sequence: - Received a wakeup_host event in D3hot. - wakeup host internal api called -> inband pme issued - host_wake_pending set to 1 - host is in process of issuing a perst assert before the inband pme is processed - disable endpoint is called -> checks for host wake pending and and calls ep_pcie_core_wakeup_host_internal. - ep_pcie_core_wakeup_host_internal will return without doing a wakeup because of host wake pending check in it. Set the host_wake_pending flag to 0 before calling to make sure ep_pcie_core_wakeup_host_internal is executed to toggle WAKE. Change-Id: I533b7ee58ea941d9a865fc560677aa9a8daa431c Signed-off-by: Sumit Kumar --- drivers/platform/msm/ep_pcie/ep_pcie_core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/msm/ep_pcie/ep_pcie_core.c b/drivers/platform/msm/ep_pcie/ep_pcie_core.c index c8e23ac53d2f..cef10b457073 100644 --- a/drivers/platform/msm/ep_pcie/ep_pcie_core.c +++ b/drivers/platform/msm/ep_pcie/ep_pcie_core.c @@ -2179,6 +2179,11 @@ int ep_pcie_core_disable_endpoint(void) if (atomic_read(&dev->host_wake_pending)) { EP_PCIE_DBG(dev, "PCIe V%d: wake pending, init wakeup\n", dev->rev); + /* + * Clear the wake pending otherwise ep_pcie_core_wakeup_host_internal + * will return without WAKE toggle + */ + atomic_set(&dev->host_wake_pending, 0); ep_pcie_core_wakeup_host_internal(EP_PCIE_EVENT_PM_D3_COLD); } From a92f0801342cc994313500c29ffa62c0d4b49c2c Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Mon, 7 Oct 2024 11:41:50 +0530 Subject: [PATCH 057/306] msm: mhi_dev: Handle host wakeup in M3/D0 When a MHI WAKE request (that is request to bring MHI from M3 to M0) is received while device is in D0, this request is being dropped as there is no way to notify host about this event. This is leading to failure at client drivers as they unable to wakeup mhi and perform write operation. Fix the issue by waiting for D3hot in MHI before sending the wake request: - If M0 is received while waiting, exit the function. - If D3hot/D3cold is received, send the wake request. - Else return failure. Increase the timeout value of mhi_dev_write_channel() from 2s to 2.5s to accommodate the waiting time for D state transition to D3hot/D3cold. Change-Id: Idd58bb664d31bc1e5615119284c6cba924fe17b6 Signed-off-by: Sumit Kumar --- drivers/platform/msm/mhi_dev/mhi.c | 2 +- drivers/platform/msm/mhi_dev/mhi_sm.c | 34 ++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index d7d9ecad8d73..141ce1157e9c 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -39,7 +39,7 @@ /* Wait time on the device for Host to set BHI_INTVEC */ #define MHI_BHI_INTVEC_MAX_CNT 200 #define MHI_BHI_INTVEC_WAIT_MS 50 -#define MHI_WAKEUP_TIMEOUT_CNT 20 +#define MHI_WAKEUP_TIMEOUT_CNT 25 #define MHI_MASK_CH_EV_LEN 32 #define MHI_RING_CMD_ID 0 #define MHI_RING_PRIMARY_EVT_ID 1 diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index 89190bfeadfc..ba8c9a19136e 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -12,6 +12,7 @@ #include "mhi_hwio.h" #include "mhi_sm.h" #include +#include #define MHI_SM_DBG(fmt, args...) \ mhi_log(MHI_MSG_DBG, fmt, ##args) @@ -28,6 +29,8 @@ #define PCIE_EP_TIMER_US 500000000 #define MHI_IPA_DISABLE_DELAY_MS 10 #define MHI_IPA_DISABLE_COUNTER 20 +/* Maximum wait time for D state transitions to D3hot */ +#define M3_DO_WAKEUP_TIMEOUT_MS 2500 static inline const char *mhi_sm_dev_event_str(enum mhi_dev_event state) @@ -734,7 +737,7 @@ exit: * mhi_sm_wakeup_host() - wakeup MHI-host *@event: MHI state chenge event * - * Sends wekup event to MHI-host via EP-PCIe, in case MHI is in M3 state. + * Sends wakeup event to MHI-host via EP-PCIe, in case MHI is in M3 state. * * Return: 0:success * negative: failure @@ -742,6 +745,7 @@ exit: static int mhi_sm_wakeup_host(enum mhi_dev_event event) { int res = 0; + int timeout = 0; enum ep_pcie_event pcie_event; MHI_SM_FUNC_ENTRY(); @@ -753,9 +757,33 @@ static int mhi_sm_wakeup_host(enum mhi_dev_event event) MHI_SM_ERR("Failed switching to M0 state\n"); } else if (mhi_sm_ctx->mhi_state == MHI_DEV_M3_STATE) { /* - * Check and send D3_HOT to enable waking up the host - * using inband PME. + * Handle host wakeup in M3 + D0 states. + * + * When a MHI WAKE request is received while device is in D0, + * wait for D3 and wakeup the host using inband PME. + * If the MHI state changes to M0 while waiting for D3, + * exit, since both MHI and the device are in active state. */ + if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D0_STATE) { + timeout = ktime_add_ms(ktime_get(), M3_DO_WAKEUP_TIMEOUT_MS); + while (1) { + /* Received M0 */ + if (mhi_sm_ctx->mhi_state == MHI_DEV_M0_STATE) + goto exit; + /* Received D3 state */ + if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_HOT_STATE || + mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_COLD_STATE) + goto wakeup_host; + if (ktime_after(ktime_get(), timeout)) { + MHI_SM_ERR(mhi->vf_id, + "M3, D0 wakeup host is not supported %d\n", res); + goto exit; + } + usleep_range(1000, 2000); + } + } +wakeup_host: + /* Received D3hot or D3cold, send the wakeup request */ if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_HOT_STATE) pcie_event = EP_PCIE_EVENT_PM_D3_HOT; else From c0dcb8d4a30318c67f716adac73fa6f9b0cd36d1 Mon Sep 17 00:00:00 2001 From: Gururaj Pandurangi Date: Thu, 6 Feb 2025 18:27:21 -0800 Subject: [PATCH 058/306] qcacmn: Avoid OOB read in reg fill master channel API Avoid OOB read by adding sanity check for 6 GHz regulatory client type before invoking reg_fill_master_channels API. CRs-Fixed: 4046668 Change-Id: Ief959940e3470b5341d3188ac558475dc8d7fee1 --- umac/regulatory/core/src/reg_build_chan_list.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/umac/regulatory/core/src/reg_build_chan_list.c b/umac/regulatory/core/src/reg_build_chan_list.c index 6059b406d57b..40959dbe6df2 100644 --- a/umac/regulatory/core/src/reg_build_chan_list.c +++ b/umac/regulatory/core/src/reg_build_chan_list.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -2089,6 +2089,11 @@ QDF_STATUS reg_process_master_chan_list_ext( reg_store_regulatory_ext_info_to_socpriv(soc_reg, regulat_info, phy_id); + if (this_mchan_params->client_type >= REG_MAX_CLIENT_TYPE) { + reg_err("6 GHz reg client type invalid"); + return QDF_STATUS_E_FAILURE; + } + status = reg_fill_master_channels(regulat_info, &this_mchan_params->reg_rules, this_mchan_params->client_type, From bf1e9cb49c8d3c2a0c61b4780cc8488c09071da9 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 27 Mar 2025 06:01:20 -0700 Subject: [PATCH 059/306] fw-api: CL 28887056 - update fw common interface files Change-Id: I2a1c26d5c26d4d407d4588ab65c725543728b4b4 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 26d7bb3a044d..3d68dfb50873 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -48072,6 +48072,8 @@ typedef struct { * (units = ms) */ A_UINT32 delay_bound; + wmi_mac_addr mac_address; + A_UINT32 vdev_id; } wmi_sawf_ezmesh_hop_count_cmd_fixed_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 7357c932a42d..30cef9f15ed7 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1590 +#define __WMI_REVISION_ 1591 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 74c47a0d5131a22e6a132e5d089845dabc31b68d Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 28 Mar 2025 06:01:19 -0700 Subject: [PATCH 060/306] fw-api: CL 28903851 - update fw common interface files Change-Id: Ib201d1ab6a2191ac92813bdf478c67f32b5ebfa6 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 21 +++++++++++++++++++++ fw/wmi_version.h | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 7411d6aa6c0b..9007c4b601dd 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -696,6 +696,7 @@ typedef enum { WMI_SERVICE_STA_TWT_STATS_EXT = 437, /* FW supports additional info in TWT stats and ADD COMPLETION Event */ WMI_SERVICE_OPT_DP_DIAG_SUPPORT = 438, /* FW supports diag QDATA feature */ WMI_SERVICE_MLO_ROAM_PARTNER_BRINGUP_FROM_HOST = 439, /* Indicates FW supports new design in which FW expects the host to bringup the partner link during roaming */ + WMI_SERVICE_CTRL_PATH_PEER_BA_STATS = 440, /* FW supports retrieving BlockAck stats through WMI_REQUEST_CTRL_PATH_PEER_STAT */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 3d68dfb50873..bd313abfdf9a 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -14841,6 +14841,21 @@ typedef struct { A_UINT32 opaque_debug_field_2; A_UINT32 opaque_debug_field_3; A_UINT32 opaque_debug_field_4; + + /* ba_stats + * This word contains the following bitfields: + * bits 15:0 - ba_tx_neg_fail: Blockack Transmit Negotiation failure + * count for the all TIDs in peer. + * Use WMI_PEER_STATS_BA_TX_NEG_FAIL_SET,GET macros. + * bits 31:16 - reserved + */ + union { + A_UINT32 ba_stats__word; + struct { + A_UINT32 ba_tx_neg_fail: 16, + reserved: 16; + }; + }; } wmi_ctrl_path_peer_stats_struct; #define WMI_PEER_STATS_SM_MASK_SET(flag, val) \ @@ -15165,6 +15180,12 @@ typedef struct { #define WMI_PEER_STATS_RC_CHAN_FREQ_GET(flag) \ WMI_GET_BITS(flag, 16, 16) +#define WMI_PEER_STATS_PEER_BA_TX_NEG_FAIL_SET(flag, val) \ + WMI_SET_BITS(flag, 0, 16, val) +#define WMI_PEER_STATS_PEER_BA_TX_NEG_FAIL_GET(flag) \ + WMI_GET_BITS(flag, 0, 16) +/* bits 31:16 unused/reserved */ + typedef struct { /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ctrl_path_cfr_stats_struct */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 30cef9f15ed7..42ba2473b939 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1591 +#define __WMI_REVISION_ 1592 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 240a88f08035f044a4fcaca08633de6bb59aa2ea Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 30 Mar 2025 06:01:16 -0700 Subject: [PATCH 061/306] fw-api: CL 28911997 - update fw common interface files Change-Id: I6205f3dbd8c7321522400bb810c998db72159ea6 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 15 ++++++++------- fw/wmi_version.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index bd313abfdf9a..9280a364d01f 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -21717,13 +21717,14 @@ typedef struct { #define WMI_PEER_SAFEMODE_EN 0x80000000 /* Fips Mode Enabled */ /** define for peer_flags_ext */ -#define WMI_PEER_EXT_EHT 0x00000001 /* EHT enabled */ -#define WMI_PEER_EXT_320MHZ 0x00000002 /* 320Mhz enabled */ -#define WMI_PEER_EXT_DMS_CAPABLE 0x00000004 -#define WMI_PEER_EXT_HE_CAPS_6GHZ_VALID 0x00000008 /* param he_caps_6ghz is valid or not */ -#define WMI_PEER_EXT_IS_QUALCOMM_NODE 0x00000010 /* Indicates if the peer connecting is a qualcomm node */ -#define WMI_PEER_EXT_IS_MESH_NODE 0x00000020 /* Indicates if the peer connecting is a mesh node */ -#define WMI_PEER_EXT_PROTECTED_TWT 0x00000040 /* Protected TWT operation Support field in Extended RSN Capabilities element */ +#define WMI_PEER_EXT_EHT 0x00000001 /* EHT enabled */ +#define WMI_PEER_EXT_320MHZ 0x00000002 /* 320Mhz enabled */ +#define WMI_PEER_EXT_DMS_CAPABLE 0x00000004 +#define WMI_PEER_EXT_HE_CAPS_6GHZ_VALID 0x00000008 /* param he_caps_6ghz is valid or not */ +#define WMI_PEER_EXT_IS_QUALCOMM_NODE 0x00000010 /* Indicates if the peer connecting is a qualcomm node */ +#define WMI_PEER_EXT_IS_MESH_NODE 0x00000020 /* Indicates if the peer connecting is a mesh node */ +#define WMI_PEER_EXT_PROTECTED_TWT 0x00000040 /* Protected TWT operation Support field in Extended RSN Capabilities element */ +#define WMI_PEER_EXT_UHR 0x00000080 #define WMI_PEER_EXT_F_CRIT_PROTO_HINT_ENABLED 0x40000000 /** diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 42ba2473b939..94723c7947f7 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1592 +#define __WMI_REVISION_ 1593 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From a806b00e50be0299c28f3bdfcf193d6e0ca87c14 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 3 Apr 2025 06:01:28 -0700 Subject: [PATCH 062/306] fw-api: CL 28933869 - update fw common interface files Change-Id: I2d966605e82b343e87a46fa5dcd4f9041065ba38 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 3 ++- fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 9280a364d01f..9d529930df03 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -21724,7 +21724,7 @@ typedef struct { #define WMI_PEER_EXT_IS_QUALCOMM_NODE 0x00000010 /* Indicates if the peer connecting is a qualcomm node */ #define WMI_PEER_EXT_IS_MESH_NODE 0x00000020 /* Indicates if the peer connecting is a mesh node */ #define WMI_PEER_EXT_PROTECTED_TWT 0x00000040 /* Protected TWT operation Support field in Extended RSN Capabilities element */ -#define WMI_PEER_EXT_UHR 0x00000080 +#define WMI_PEER_EXT_UHR 0x00000080 /* UHR enabled */ #define WMI_PEER_EXT_F_CRIT_PROTO_HINT_ENABLED 0x40000000 /** @@ -37648,6 +37648,7 @@ typedef struct { */ typedef enum { WMI_TWT_STA_SYNC_EVENT_CAP = 1, /* STA TWT: FW internal errors reported using sync WMI_TWT_ACK_EVENTID */ + WMI_TWT_FLEXI_SUPPORT = 2, /* Add new TWT Caps above */ WMI_TWT_MAX_CAP = 32, diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 94723c7947f7..37409f2c28ee 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1593 +#define __WMI_REVISION_ 1594 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 2c229c304e7940e016e2e3581af442e748ba396d Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 4 Apr 2025 06:01:52 -0700 Subject: [PATCH 063/306] fw-api: CL 28935775 - update fw common interface files Change-Id: I9f123bd2440a2fb1960e6699daa4c05fc8d0e8e8 CRs-Fixed: 3830439 --- fw/htt.h | 1 + fw/htt_stats.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/fw/htt.h b/fw/htt.h index e9d34066ff72..300433042810 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -844,6 +844,7 @@ typedef enum { HTT_STATS_PDEV_UL_MUMIMO_DENYLIST_STATS_TAG = 209, /* htt_stats_pdev_ulmumimo_denylist_stats_tlv */ HTT_STATS_PDEV_UL_MUMIMO_SEQ_TERM_STATS_TAG = 210, /* htt_stats_pdev_ulmumimo_seq_term_stats_tlv */ HTT_STATS_PDEV_UL_MUMIMO_HIST_INELIGIBILITY_TAG = 211, /* htt_stats_pdev_ulmumimo_hist_ineligibility_tlv */ + HTT_STATS_PHY_PAPRD_PB_TAG = 212, /* htt_stats_phy_paprd_pb_tlv */ HTT_STATS_MAX_TAG, } htt_stats_tlv_tag_t; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index ea524e6d7486..0a52c1911062 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -829,6 +829,14 @@ enum htt_dbg_ext_stats_type { */ HTT_DBG_EXT_STATS_PDEV_UL_MUMIMO_ELIGIBLE = 74, + /** HTT_DBG_EXT_STATS_PAPRD_PB + * PARAMS: + * - No Params + * RESP MSG: + * - htt_stats_phy_paprd_pb_tlv + */ + HTT_DBG_EXT_STATS_PAPRD_PB = 75, + /* keep this last */ HTT_DBG_NUM_EXT_STATS = 256, @@ -10533,6 +10541,56 @@ typedef struct { } htt_vdevs_txrx_stats_t; #endif /* ATH_TARGET */ +/* PAPRD and power boost stats and counters */ +typedef struct { + htt_tlv_hdr_t tlv_hdr; + + /** current pdev_id */ + A_UINT32 pdev_id; + /** DPD and PowerBoost trigger count */ + A_UINT32 total_dpd_cal_count; + A_UINT32 chan_change_dpd_cal_count; + A_UINT32 thermal_dpd_cal_count; + A_UINT32 recovery_dpd_cal_count; + A_UINT32 pb_cal_count; + /** DPD and PowerBoost Fail Count */ + A_UINT32 total_dpd_fail_count; + A_UINT32 chan_change_dpd_fail_count; + A_UINT32 thermal_dpd_fail_count; + A_UINT32 recovery_dpd_fail_count; + A_UINT32 pb_fail_count; + + /* + * DPD and Power Boost validity status + * + * BIT 0 - DPD_CAL_STATUS + * BIT 1 - PB_CAL_STATUS + * + * CAL_STATUS can be interpreted as below + * CAL_SUCCESS = 1 + * CAL_FAIL = 0 + */ + union { + A_UINT32 dpd_pb_validity_status; + struct { + A_UINT32 is_dpd_valid:1, + is_pb_valid:1, + rsvd:30; + }; + }; + + /** Last DPD cal time in ms */ + A_UINT32 last_dpd_cal_time; + + /** Last Power Boost cal time in ms */ + A_UINT32 last_pb_cal_time; + + /** Power Boost gain per BW and MCS, in 0.25 dB units + * For example, a value of 2 represents a 0.5 dB gain. + */ + A_UINT32 power_boost_gain[HTT_TX_PDEV_STATS_NUM_BE_BW_COUNTERS][HTT_TX_PDEV_STATS_NUM_BE_MCS_COUNTERS]; +} htt_stats_phy_paprd_pb_tlv; + typedef struct { union { A_UINT32 word32; From 5837ed2916182477f611165998158b17ac93fe53 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 5 Apr 2025 06:01:26 -0700 Subject: [PATCH 064/306] fw-api: CL 28942439 - update fw common interface files Change-Id: I671008f73455301ccf03d1a706c70d1c93f5def5 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_tlv_defs.h | 4 +++- fw/wmi_unified.h | 52 +++++++++++++++++++++++++++++++++++++++++++++++ fw/wmi_version.h | 2 +- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 9007c4b601dd..e03647797902 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -697,6 +697,7 @@ typedef enum { WMI_SERVICE_OPT_DP_DIAG_SUPPORT = 438, /* FW supports diag QDATA feature */ WMI_SERVICE_MLO_ROAM_PARTNER_BRINGUP_FROM_HOST = 439, /* Indicates FW supports new design in which FW expects the host to bringup the partner link during roaming */ WMI_SERVICE_CTRL_PATH_PEER_BA_STATS = 440, /* FW supports retrieving BlockAck stats through WMI_REQUEST_CTRL_PATH_PEER_STAT */ + WMI_SERVICE_CTRL_PATH_STA_DAR_STATS_SUPPORT = 441, /* FW supports DAR stats reporting for STA mode */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 5f83c5bbaada..76012e9b04d5 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1479,6 +1479,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_ndp_set_latency_tput_fixed_param, WMITLV_TAG_STRUC_wmi_roam_partner_link_param, WMITLV_TAG_STRUC_wmi_mlo_link_ttlm_complete_fixed_param, + WMITLV_TAG_STRUC_wmi_ctrl_path_sta_dar_stats_struct, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -7273,7 +7274,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STATS_INFO_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ctrl_path_vdev_bcn_tx_stats_struct, ctrl_path_vdev_bcn_tx_stats, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ctrl_path_pdev_bcn_tx_stats_struct, ctrl_path_pdev_bcn_tx_stats, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ctrl_path_pdev_conn_stats_struct, ctrl_path_pdev_conn_stats, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ctrl_path_ml_rcfg_stats_struct, ctrl_path_ml_rcfg_stats, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ctrl_path_ml_rcfg_stats_struct, ctrl_path_ml_rcfg_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ctrl_path_sta_dar_stats_struct, ctrl_path_sta_dar_stats, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_CTRL_PATH_STATS_EVENTID); /* diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 9d529930df03..61c640efd4ea 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -16679,6 +16679,40 @@ typedef struct { A_UINT32 dot11RTSFailureCount; } wmi_ctrl_path_sta_rrm_stats_struct; +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ctrl_path_sta_dar_stats_struct */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 stats_granularity; /* Possible values are listed in wmi_ctrl_path_stats_granularity enum. */ + /* transmit_pwr: + * Units are dB w.r.t. a -20 dBm reference. + * For example, if the STA's tx power is 10 dBm, the transmit_pwr field's + * value will be 30. + */ + A_UINT32 transmit_pwr; + A_UINT32 cca_busy_cnt; + A_UINT32 cycle_cnt; + /* + * For the below 8-element arrays, in case of AC-level granularity, + * only the first 4 elements of the array are populated, and are indexed + * by wmi_traffic_ac enum values. + * Otherwise, for TID level granularity all 8 elements of the array will + * be filled by FW, and are indexed by the TID value. + */ + A_UINT32 success_mpdu_tx_cnt[8]; + A_UINT32 dropped_mpdu_tx_cnt[8]; + A_UINT32 rts_success_cnt[8]; + A_UINT32 rts_fail_cnt[8]; + A_UINT32 fcs_fail_cnt[8]; /* number of rx MPDUs whose FCS check failed */ + /* ack_fail_cnt: + * number of tx MPDUs nacked within a block ack, + * or for which no block ack was received. + */ + A_UINT32 ack_fail_cnt[8]; + A_UINT32 ba_nego_fail_cnt; + A_UINT32 beacon_loss_cnt; +} wmi_ctrl_path_sta_dar_stats_struct; + typedef struct { /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ctrl_path_vdev_bcn_stats_struct */ A_UINT32 tlv_header; @@ -36618,6 +36652,7 @@ typedef enum { WMI_REQUEST_CTRL_PATH_PDEV_BCN_TX_STAT = 20, WMI_REQUEST_CTRL_PATH_PDEV_CONN_STAT = 21, WMI_REQUEST_CTRL_PATH_ML_RECONFIG_STAT = 22, + WMI_REQUEST_CTRL_PATH_STA_DAR_STAT = 23, } wmi_ctrl_path_stats_id; typedef enum { @@ -36637,6 +36672,16 @@ typedef enum { WMI_REQUEST_CTRL_PATH_STAT_PERIODIC_PUBLISH = 5, } wmi_ctrl_path_stats_action; +typedef enum { + /* + * The following stats actions are mutually exclusive. + * A single stats request message can only specify one action. + */ + WMI_REQUEST_CTRL_PATH_STAT_DEFAULT = 0, /* unspecified granularity */ + WMI_REQUEST_CTRL_PATH_STAT_AC_LEVEL = 1, + WMI_REQUEST_CTRL_PATH_STAT_TID_LEVEL = 2, +} wmi_ctrl_path_stats_granularity; + typedef enum { WMI_HALPHY_CTRL_PATH_SU_STATS = 0, WMI_HALPHY_CTRL_PATH_SUTXBF_STATS, @@ -36673,6 +36718,13 @@ typedef struct { */ A_UINT32 stat_periodicity; + /** stats_granularity: + * Configures AC vs. TID granularity stats reporting, + * e.g. for STA_DAR_STATs. + * Possible values are listed in the wmi_ctrl_path_stats_granularity enum. + */ + A_UINT32 stats_granularity; /* refer to wmi_ctrl_path_stats_granularity */ + /** The below TLV arrays optionally follow this fixed_param TLV structure: * 1. A_UINT32 pdev_ids[]; * If this array is present and non-zero length, stats should only diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 37409f2c28ee..daf771ced9b5 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1594 +#define __WMI_REVISION_ 1595 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 0da49ec7b9a848e111f6da1f5f48a81e0ffc6ba7 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 5 Apr 2025 06:03:20 -0700 Subject: [PATCH 065/306] fw-api: CL 28944690 - update fw common interface files Change-Id: I320ebfbf2598e558700ca79045d7efb5496be5c7 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_tlv_defs.h | 6 +++++ fw/wmi_unified.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++ fw/wmi_version.h | 2 +- 4 files changed, 72 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index e03647797902..c0dc42fb9865 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -698,6 +698,7 @@ typedef enum { WMI_SERVICE_MLO_ROAM_PARTNER_BRINGUP_FROM_HOST = 439, /* Indicates FW supports new design in which FW expects the host to bringup the partner link during roaming */ WMI_SERVICE_CTRL_PATH_PEER_BA_STATS = 440, /* FW supports retrieving BlockAck stats through WMI_REQUEST_CTRL_PATH_PEER_STAT */ WMI_SERVICE_CTRL_PATH_STA_DAR_STATS_SUPPORT = 441, /* FW supports DAR stats reporting for STA mode */ + WMI_SERVICE_APF_DATA_OFFLOAD_SUPPORT_ENABLED = 442, /* Indicates FW support for APFv6 handling offloads and disable QC data offloads */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 76012e9b04d5..10f7ab407ce6 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1480,6 +1480,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_roam_partner_link_param, WMITLV_TAG_STRUC_wmi_mlo_link_ttlm_complete_fixed_param, WMITLV_TAG_STRUC_wmi_ctrl_path_sta_dar_stats_struct, + WMITLV_TAG_STRUC_wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2043,6 +2044,7 @@ typedef enum { OP(WMI_VDEV_VBSS_CONFIG_CMDID) \ OP(WMI_NDP_SET_LATENCY_TPUT_CMDID) \ OP(WMI_MLO_LINK_TTLM_COMPLETE_CMDID) \ + OP(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -5761,6 +5763,10 @@ WMITLV_CREATE_PARAM_STRUC(WMI_GET_SCAN_CACHE_RESULT_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sawf_ezmesh_hop_count_cmd_fixed_param, wmi_sawf_ezmesh_hop_count_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_SAWF_EZMESH_HOP_COUNT_CMDID); +#define WMITLV_TABLE_WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID); + /************************** TLV definitions of WMI events *******************************/ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 61c640efd4ea..f1db33bc5d5c 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -1579,6 +1579,7 @@ typedef enum { WMI_BPF_SET_VDEV_ENABLE_CMDID, WMI_BPF_SET_VDEV_WORK_MEMORY_CMDID, WMI_BPF_GET_VDEV_WORK_MEMORY_CMDID, + WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID, /** WMI commands related to monitor mode. */ WMI_MNT_FILTER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MONITOR), @@ -5109,6 +5110,27 @@ typedef struct { * BIT 6 : 31 Reserved */ A_UINT32 c2c_int_type_config; + + /** + * @brief apf_data_ofld_enable + * BIT 0 -> enable/disable offload support in apf + * @detail: This flag will indicate during init time + * based on the vendor img version if APF is supporting + * any offloads. + * BIT 1 : 31 Reserved + */ + union { + A_UINT32 apf_data_ofload_enable__word; + struct { + A_UINT32 + apf_data_ofld_enable: 1, + reserved: 31; + }; + }; + #define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_GET(word32) \ + WMI_GET_BITS(word32, 0, 1) + #define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_SET(word32, value) \ + WMI_SET_BITS(word32, 0, 1, value) } wmi_resource_config; #define WMI_MSDU_FLOW_AST_ENABLE_GET(msdu_flow_config0, ast_x) \ @@ -34076,6 +34098,47 @@ typedef struct wmi_bpf_get_vdev_work_memory_resp_evt_s { */ } wmi_bpf_get_vdev_work_memory_resp_evt_fixed_param; + +/* APF offloads supported bitmap: + * + * BIT 0: ARP OFFLOAD + * BIT 1: NS OFFLOAD + * BIT 2: IGMP OFFLOAD + * BIT 3: ICMP OFFLOAD + * BIT 4-31: reserved +*/ +#define WMI_BPF_ARP_OFFLOAD_SUPPORT_GET(param) \ + WMI_GET_BITS(param, 0, 1) +#define WMI_BPF_ARP_OFFLOAD_SUPPORT_SET(param, value) \ + WMI_SET_BITS(param, 0, 1, value) + +#define WMI_BPF_NS_OFFLOAD_SUPPORT_GET(param) \ + WMI_GET_BITS(param, 1, 1) +#define WMI_BPF_NS_OFFLOAD_SUPPORT_SET(param, value) \ + WMI_SET_BITS(param, 1, 1, value) + +#define WMI_BPF_IGMP_OFFLOAD_SUPPORT_GET(param) \ + WMI_GET_BITS(param, 2, 1) +#define WMI_BPF_IGMP_OFFLOAD_SUPPORT_SET(param, value) \ + WMI_SET_BITS(param, 2, 1, value) + +#define WMI_BPF_ICMP_OFFLOAD_SUPPORT_GET(param) \ + WMI_GET_BITS(param, 3, 1) +#define WMI_BPF_ICMP_OFFLOAD_SUPPORT_SET(param, value) \ + WMI_SET_BITS(param, 3, 1, value) + +typedef struct wmi_bpf_set_supported_offload_bitmap_cmd_s { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + /* ofld_bitmap: + * Host sends bitmap for APF supported offloads. + * Refer to the above WMI_BPF_ macros for the interpretation of the bits + * within the bitmap. + */ + A_UINT32 ofld_bitmap; +} wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param; + + #define AES_BLOCK_LEN 16 /* in bytes */ #define FIPS_KEY_LENGTH_128 16 /* in bytes */ #define FIPS_KEY_LENGTH_256 32 /* in bytes */ @@ -38915,6 +38978,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_VDEV_VBSS_CONFIG_CMDID); WMI_RETURN_STRING(WMI_NDP_SET_LATENCY_TPUT_CMDID); WMI_RETURN_STRING(WMI_MLO_LINK_TTLM_COMPLETE_CMDID); + WMI_RETURN_STRING(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index daf771ced9b5..8bb7d189c2d3 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1595 +#define __WMI_REVISION_ 1596 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 10e437e63d4d0d0caadd46ea6bf412dafcd068e8 Mon Sep 17 00:00:00 2001 From: Will Huang Date: Mon, 6 Sep 2021 17:07:50 +0800 Subject: [PATCH 066/306] qcacld-3.0: Fix mgmt tx from supplicant failed on 6 GHz chan Currently wlan_hdd_mgmt_tx path is still using legacy API to convert channel frequency to number, it is not applicable for 6 GHz channel if convert it back from number to frequency. Fix it by replace all places where using legacy API to convert channel and use channel frequency from supplicant directly. It can fix mgmt tx from supplicant on 6 GHz channel. Change-Id: I60fe37d7d716eeaceaa00f3fb59c77b629ebacac CRs-Fixed: 3024898 --- components/p2p/core/src/wlan_p2p_off_chan_tx.c | 5 +++-- components/p2p/core/src/wlan_p2p_off_chan_tx.h | 4 ++-- components/p2p/core/src/wlan_p2p_roc.c | 4 ++-- components/p2p/core/src/wlan_p2p_roc.h | 4 ++-- .../p2p/dispatcher/inc/wlan_p2p_public_struct.h | 5 +++-- core/hdd/src/wlan_hdd_p2p.c | 11 ++++++----- os_if/p2p/src/wlan_cfg80211_p2p.c | 17 ++++++++--------- 7 files changed, 26 insertions(+), 24 deletions(-) diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.c b/components/p2p/core/src/wlan_p2p_off_chan_tx.c index 1478df85dce7..2d1417271ddf 100644 --- a/components/p2p/core/src/wlan_p2p_off_chan_tx.c +++ b/components/p2p/core/src/wlan_p2p_off_chan_tx.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1076,7 +1076,8 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx, mgmt_param.vdev_id = tx_ctx->vdev_id; mgmt_param.pdata = frame; if (tx_ctx->chan) - chanfreq = (uint16_t)wlan_chan_to_freq(tx_ctx->chan); + chanfreq = tx_ctx->chan; + mgmt_param.chanfreq = chanfreq; mgmt_param.qdf_ctx = wlan_psoc_get_qdf_dev(psoc); diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.h b/components/p2p/core/src/wlan_p2p_off_chan_tx.h index 46e80fca5a33..00a7929c6484 100644 --- a/components/p2p/core/src/wlan_p2p_off_chan_tx.h +++ b/components/p2p/core/src/wlan_p2p_off_chan_tx.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -174,7 +174,7 @@ struct tx_action_context { int scan_id; uint64_t roc_cookie; int32_t id; - uint8_t chan; + qdf_freq_t chan; uint8_t *buf; int buf_len; bool off_chan; diff --git a/components/p2p/core/src/wlan_p2p_roc.c b/components/p2p/core/src/wlan_p2p_roc.c index 7146367eae62..f0c9881f3ff2 100644 --- a/components/p2p/core/src/wlan_p2p_roc.c +++ b/components/p2p/core/src/wlan_p2p_roc.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -114,7 +114,7 @@ static QDF_STATUS p2p_scan_start(struct p2p_roc_context *roc_ctx) req->scan_req.scan_type = SCAN_TYPE_P2P_LISTEN; req->scan_req.scan_req_id = p2p_soc_obj->scan_req_id; req->scan_req.chan_list.num_chan = 1; - req->scan_req.chan_list.chan[0].freq = wlan_chan_to_freq(roc_ctx->chan); + req->scan_req.chan_list.chan[0].freq = roc_ctx->chan; req->scan_req.dwell_time_passive = roc_ctx->duration; req->scan_req.dwell_time_active = 0; req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; diff --git a/components/p2p/core/src/wlan_p2p_roc.h b/components/p2p/core/src/wlan_p2p_roc.h index 143e01726a8f..f1f27364ac7b 100644 --- a/components/p2p/core/src/wlan_p2p_roc.h +++ b/components/p2p/core/src/wlan_p2p_roc.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -95,7 +95,7 @@ struct p2p_roc_context { uint32_t vdev_id; uint32_t scan_id; void *tx_ctx; - uint8_t chan; + qdf_freq_t chan; uint8_t phy_mode; uint32_t duration; enum roc_type roc_type; diff --git a/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h b/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h index 33fd71c70b40..1f09757a868b 100644 --- a/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h +++ b/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -67,7 +68,7 @@ struct p2p_ps_params { */ struct p2p_roc_req { uint32_t vdev_id; - uint32_t chan; + qdf_freq_t chan; uint32_t phy_mode; uint32_t duration; }; @@ -96,7 +97,7 @@ struct p2p_event { uint32_t vdev_id; enum p2p_roc_event roc_event; uint64_t cookie; - uint32_t chan; + qdf_freq_t chan; uint32_t duration; }; diff --git a/core/hdd/src/wlan_hdd_p2p.c b/core/hdd/src/wlan_hdd_p2p.c index 4743ce81ba2a..d8aee3c9ee21 100644 --- a/core/hdd/src/wlan_hdd_p2p.c +++ b/core/hdd/src/wlan_hdd_p2p.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -286,15 +286,16 @@ wlan_hdd_validate_and_override_offchan(struct hdd_adapter *adapter, struct ieee80211_channel *chan, bool *offchan) { - uint8_t home_ch; + qdf_freq_t home_ch_freq; if (!offchan || !chan || !(*offchan)) return; - home_ch = hdd_get_adapter_home_channel(adapter); + home_ch_freq = hdd_get_adapter_home_channel(adapter); - if (ieee80211_frequency_to_channel(chan->center_freq) == home_ch) { - hdd_debug("override offchan to 0 at home channel %d", home_ch); + if (chan->center_freq == home_ch_freq) { + hdd_debug("override offchan to 0 at home channel %d", + home_ch_freq); *offchan = false; } } diff --git a/os_if/p2p/src/wlan_cfg80211_p2p.c b/os_if/p2p/src/wlan_cfg80211_p2p.c index ddeba7bf0d51..4db1500f65fa 100644 --- a/os_if/p2p/src/wlan_cfg80211_p2p.c +++ b/os_if/p2p/src/wlan_cfg80211_p2p.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -281,8 +282,7 @@ static void wlan_p2p_event_callback(void *user_data, goto fail; } - chan = ieee80211_get_channel(wdev->wiphy, - wlan_chan_to_freq(p2p_event->chan)); + chan = ieee80211_get_channel(wdev->wiphy, p2p_event->chan); if (!chan) { osif_err("channel conversion failed"); goto fail; @@ -360,7 +360,7 @@ int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev, return -EINVAL; } - roc_req.chan = (uint32_t)wlan_freq_to_chan(chan->center_freq); + roc_req.chan = chan->center_freq; roc_req.duration = duration; roc_req.vdev_id = (uint32_t)vdev_id; @@ -409,7 +409,7 @@ int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, struct p2p_mgmt_tx mgmt_tx = {0}; struct wlan_objmgr_psoc *psoc; uint8_t vdev_id; - uint32_t channel = 0; + qdf_freq_t chan_freq = 0; if (!vdev) { osif_err("invalid vdev object"); @@ -417,7 +417,7 @@ int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, } if (chan) - channel = (uint32_t)wlan_freq_to_chan(chan->center_freq); + chan_freq = chan->center_freq; else osif_debug("NULL chan, set channel to 0"); @@ -436,8 +436,7 @@ int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, int ret; bool ok; - ret = policy_mgr_is_chan_ok_for_dnbs( - psoc, wlan_chan_to_freq(channel), &ok); + ret = policy_mgr_is_chan_ok_for_dnbs(psoc, chan_freq, &ok); if (QDF_IS_STATUS_ERROR(ret)) { osif_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d", ret); @@ -445,13 +444,13 @@ int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, } if (!ok) { osif_err("Rejecting mgmt_tx for channel:%d as DNSC is set", - channel); + chan_freq); return -EINVAL; } } mgmt_tx.vdev_id = (uint32_t)vdev_id; - mgmt_tx.chan = channel; + mgmt_tx.chan = chan_freq; mgmt_tx.wait = wait; mgmt_tx.len = len; mgmt_tx.no_cck = (uint32_t)no_cck; From fda10761df20c96ac7540fcd21f49eefeca24798 Mon Sep 17 00:00:00 2001 From: Will Huang Date: Fri, 10 Sep 2021 10:40:22 +0800 Subject: [PATCH 067/306] qcacld-3.0: Rename variables name chan to chan_freq of wlan_hdd_mgmt_tx We have fixed using channel number as internal parameter instead of chan frequency with change I60fe37d7d716eeaceaa00f3fb59c77b629ebacac, but variables name are still chan which might cause confused to reader. Rename all places where "chan" to "chan_freq", which actually channel frequency used. And alter miss APIs which still expect channel number. Change-Id: I948cbad133a17093f49384b563966d2c53b51707 CRs-Fixed: 3033951 --- .../p2p/core/src/wlan_p2p_off_chan_tx.c | 77 ++++++++-------- .../p2p/core/src/wlan_p2p_off_chan_tx.h | 4 +- components/p2p/core/src/wlan_p2p_roc.c | 88 +++++++++++-------- components/p2p/core/src/wlan_p2p_roc.h | 12 +-- .../dispatcher/inc/wlan_p2p_public_struct.h | 12 +-- .../p2p/dispatcher/src/wlan_p2p_ucfg_api.c | 20 +++-- os_if/p2p/src/wlan_cfg80211_p2p.c | 8 +- 7 files changed, 120 insertions(+), 101 deletions(-) diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.c b/components/p2p/core/src/wlan_p2p_off_chan_tx.c index 2d1417271ddf..857e619900a8 100644 --- a/components/p2p/core/src/wlan_p2p_off_chan_tx.c +++ b/components/p2p/core/src/wlan_p2p_off_chan_tx.c @@ -211,7 +211,7 @@ static QDF_STATUS p2p_check_and_update_channel(struct tx_action_context *tx_ctx) struct p2p_soc_priv_obj *p2p_soc_obj; struct p2p_roc_context *curr_roc_ctx; - if (!tx_ctx || tx_ctx->chan) { + if (!tx_ctx || tx_ctx->chan_freq) { p2p_err("NULL tx ctx or channel valid"); return QDF_STATUS_E_INVAL; } @@ -232,7 +232,7 @@ static QDF_STATUS p2p_check_and_update_channel(struct tx_action_context *tx_ctx) (mode == QDF_P2P_DEVICE_MODE || mode == QDF_P2P_CLIENT_MODE || mode == QDF_P2P_GO_MODE)) - tx_ctx->chan = curr_roc_ctx->chan; + tx_ctx->chan_freq = curr_roc_ctx->chan_freq; wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); @@ -1068,17 +1068,13 @@ static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx, void *mac_addr; uint8_t pdev_id; struct wlan_objmgr_vdev *vdev; - uint16_t chanfreq = 0; psoc = tx_ctx->p2p_soc_obj->soc; mgmt_param.tx_frame = packet; mgmt_param.frm_len = buf_len; mgmt_param.vdev_id = tx_ctx->vdev_id; mgmt_param.pdata = frame; - if (tx_ctx->chan) - chanfreq = tx_ctx->chan; - - mgmt_param.chanfreq = chanfreq; + mgmt_param.chanfreq = tx_ctx->chan_freq; mgmt_param.qdf_ctx = wlan_psoc_get_qdf_dev(psoc); if (!(mgmt_param.qdf_ctx)) { @@ -1162,7 +1158,7 @@ static QDF_STATUS p2p_roc_req_for_tx_action( p2p_soc_obj = tx_ctx->p2p_soc_obj; roc_ctx->p2p_soc_obj = p2p_soc_obj; roc_ctx->vdev_id = tx_ctx->vdev_id; - roc_ctx->chan = tx_ctx->chan; + roc_ctx->chan_freq = tx_ctx->chan_freq; roc_ctx->duration = tx_ctx->duration; roc_ctx->roc_state = ROC_STATE_IDLE; roc_ctx->roc_type = OFF_CHANNEL_TX; @@ -1805,13 +1801,15 @@ void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj) while (QDF_IS_STATUS_SUCCESS(status)) { tx_ctx = qdf_container_of(p_node, struct tx_action_context, node); - p2p_debug("p2p soc object:%pK, tx ctx:%pK, vdev_id:%d, scan_id:%d, roc_cookie:%llx, chan:%d, buf:%pK, len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", - p2p_soc_obj, tx_ctx, - tx_ctx->vdev_id, tx_ctx->scan_id, - tx_ctx->roc_cookie, tx_ctx->chan, - tx_ctx->buf, tx_ctx->buf_len, - tx_ctx->off_chan, tx_ctx->no_cck, - tx_ctx->no_ack, tx_ctx->duration); + p2p_debug("p2p soc object:%pK, tx ctx:%pK, vdev_id:%d, " + "scan_id:%d, roc_cookie:%llx, freq:%d, buf:%pK, " + "len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", + p2p_soc_obj, tx_ctx, + tx_ctx->vdev_id, tx_ctx->scan_id, + tx_ctx->roc_cookie, tx_ctx->chan_freq, + tx_ctx->buf, tx_ctx->buf_len, + tx_ctx->off_chan, tx_ctx->no_cck, + tx_ctx->no_ack, tx_ctx->duration); status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc, p_node, &p_node); @@ -1823,13 +1821,15 @@ void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj) while (QDF_IS_STATUS_SUCCESS(status)) { tx_ctx = qdf_container_of(p_node, struct tx_action_context, node); - p2p_debug("p2p soc object:%pK, tx_ctx:%pK, vdev_id:%d, scan_id:%d, roc_cookie:%llx, chan:%d, buf:%pK, len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", - p2p_soc_obj, tx_ctx, - tx_ctx->vdev_id, tx_ctx->scan_id, - tx_ctx->roc_cookie, tx_ctx->chan, - tx_ctx->buf, tx_ctx->buf_len, - tx_ctx->off_chan, tx_ctx->no_cck, - tx_ctx->no_ack, tx_ctx->duration); + p2p_debug("p2p soc object:%pK, tx_ctx:%pK, vdev_id:%d, " + "scan_id:%d, roc_cookie:%llx, freq:%d, buf:%pK, " + "len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", + p2p_soc_obj, tx_ctx, + tx_ctx->vdev_id, tx_ctx->scan_id, + tx_ctx->roc_cookie, tx_ctx->chan_freq, + tx_ctx->buf, tx_ctx->buf_len, + tx_ctx->off_chan, tx_ctx->no_cck, + tx_ctx->no_ack, tx_ctx->duration); status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack, p_node, &p_node); @@ -2919,17 +2919,17 @@ void p2p_rand_mac_tx(struct tx_action_context *tx_action) return; soc = tx_action->p2p_soc_obj->soc; - if (!tx_action->no_ack && tx_action->chan && + if (!tx_action->no_ack && tx_action->chan_freq && tx_action->buf_len > MIN_MAC_HEADER_LEN && p2p_is_vdev_support_rand_mac_by_id(soc, tx_action->vdev_id) && p2p_is_random_mac(soc, tx_action->vdev_id, &tx_action->buf[SRC_MAC_ADDR_OFFSET])) { status = p2p_request_random_mac( - soc, tx_action->vdev_id, - &tx_action->buf[SRC_MAC_ADDR_OFFSET], - wlan_chan_to_freq(tx_action->chan), - tx_action->id, - tx_action->duration); + soc, tx_action->vdev_id, + &tx_action->buf[SRC_MAC_ADDR_OFFSET], + tx_action->chan_freq, + tx_action->id, + tx_action->duration); if (status == QDF_STATUS_SUCCESS) tx_action->rand_mac_tx = true; else @@ -2999,11 +2999,13 @@ QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx) p2p_soc_obj = tx_ctx->p2p_soc_obj; - p2p_debug("soc:%pK, tx_ctx:%pK, vdev_id:%d, scan_id:%d, roc_cookie:%llx, chan:%d, buf:%pK, len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", - p2p_soc_obj->soc, tx_ctx, tx_ctx->vdev_id, - tx_ctx->scan_id, tx_ctx->roc_cookie, tx_ctx->chan, - tx_ctx->buf, tx_ctx->buf_len, tx_ctx->off_chan, - tx_ctx->no_cck, tx_ctx->no_ack, tx_ctx->duration); + p2p_debug("soc:%pK, tx_ctx:%pK, vdev_id:%d, scan_id:%d, " + "roc_cookie:%llx, freq:%d, buf:%pK, len:%d, " + "off_chan:%d, cck:%d, ack:%d, duration:%d", + p2p_soc_obj->soc, tx_ctx, tx_ctx->vdev_id, + tx_ctx->scan_id, tx_ctx->roc_cookie, tx_ctx->chan_freq, + tx_ctx->buf, tx_ctx->buf_len, tx_ctx->off_chan, + tx_ctx->no_cck, tx_ctx->no_ack, tx_ctx->duration); status = p2p_get_frame_info(tx_ctx->buf, tx_ctx->buf_len, &(tx_ctx->frame_info)); @@ -3032,8 +3034,8 @@ QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx) tx_ctx->no_ack = 1; } - if (!tx_ctx->off_chan || !tx_ctx->chan) { - if (!tx_ctx->chan) + if (!tx_ctx->off_chan || !tx_ctx->chan_freq) { + if (!tx_ctx->chan_freq) p2p_check_and_update_channel(tx_ctx); status = p2p_execute_tx_action_frame(tx_ctx); if (status != QDF_STATUS_SUCCESS) { @@ -3045,7 +3047,7 @@ QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx) /* For off channel tx case */ curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); - if (curr_roc_ctx && (curr_roc_ctx->chan == tx_ctx->chan)) { + if (curr_roc_ctx && (curr_roc_ctx->chan_freq == tx_ctx->chan_freq)) { if ((curr_roc_ctx->roc_state == ROC_STATE_REQUESTED) || (curr_roc_ctx->roc_state == ROC_STATE_STARTED)) { tx_ctx->roc_cookie = (uintptr_t)curr_roc_ctx; @@ -3076,7 +3078,8 @@ QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx) } } - curr_roc_ctx = p2p_find_roc_by_chan(p2p_soc_obj, tx_ctx->chan); + curr_roc_ctx = p2p_find_roc_by_chan_freq(p2p_soc_obj, + tx_ctx->chan_freq); if (curr_roc_ctx && (curr_roc_ctx->roc_state == ROC_STATE_IDLE)) { tx_ctx->roc_cookie = (uintptr_t)curr_roc_ctx; status = qdf_list_insert_back( diff --git a/components/p2p/core/src/wlan_p2p_off_chan_tx.h b/components/p2p/core/src/wlan_p2p_off_chan_tx.h index 00a7929c6484..5b98ccbc7066 100644 --- a/components/p2p/core/src/wlan_p2p_off_chan_tx.h +++ b/components/p2p/core/src/wlan_p2p_off_chan_tx.h @@ -157,7 +157,7 @@ struct p2p_frame_info { * @scan_id: Scan id given by scan component for this roc req * @roc_cookie: Cookie for remain on channel request * @id: Identifier of this tx context - * @chan: Chan for which this tx has been requested + * @chan_freq: Chan frequency for which this tx has been requested * @buf: tx buffer * @buf_len: Length of tx buffer * @off_chan: Is this off channel tx @@ -174,7 +174,7 @@ struct tx_action_context { int scan_id; uint64_t roc_cookie; int32_t id; - qdf_freq_t chan; + qdf_freq_t chan_freq; uint8_t *buf; int buf_len; bool off_chan; diff --git a/components/p2p/core/src/wlan_p2p_roc.c b/components/p2p/core/src/wlan_p2p_roc.c index f0c9881f3ff2..643d54a1a428 100644 --- a/components/p2p/core/src/wlan_p2p_roc.c +++ b/components/p2p/core/src/wlan_p2p_roc.c @@ -114,7 +114,7 @@ static QDF_STATUS p2p_scan_start(struct p2p_roc_context *roc_ctx) req->scan_req.scan_type = SCAN_TYPE_P2P_LISTEN; req->scan_req.scan_req_id = p2p_soc_obj->scan_req_id; req->scan_req.chan_list.num_chan = 1; - req->scan_req.chan_list.chan[0].freq = roc_ctx->chan; + req->scan_req.chan_list.chan[0].freq = roc_ctx->chan_freq; req->scan_req.dwell_time_passive = roc_ctx->duration; req->scan_req.dwell_time_active = 0; req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; @@ -278,7 +278,7 @@ static QDF_STATUS p2p_send_roc_event( p2p_evt.vdev_id = roc_ctx->vdev_id; p2p_evt.roc_event = evt; p2p_evt.cookie = (uint64_t)roc_ctx->id; - p2p_evt.chan = roc_ctx->chan; + p2p_evt.chan_freq = roc_ctx->chan_freq; p2p_evt.duration = roc_ctx->duration; p2p_debug("roc_event: %d, cookie:%llx", p2p_evt.roc_event, @@ -305,9 +305,10 @@ static QDF_STATUS p2p_destroy_roc_ctx(struct p2p_roc_context *roc_ctx, QDF_STATUS status = QDF_STATUS_SUCCESS; struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; - p2p_debug("p2p_soc_obj:%pK, roc_ctx:%pK, up_layer_event:%d, in_roc_queue:%d vdev_id:%d chan:%d duration:%d", - p2p_soc_obj, roc_ctx, up_layer_event, in_roc_queue, - roc_ctx->vdev_id, roc_ctx->chan, roc_ctx->duration); + p2p_debug("p2p_soc_obj:%pK, roc_ctx:%pK, up_layer_event:%d," + " in_roc_queue:%d vdev_id:%d freq:%d duration:%d", + p2p_soc_obj, roc_ctx, up_layer_event, in_roc_queue, + roc_ctx->vdev_id, roc_ctx->chan_freq, roc_ctx->duration); if (up_layer_event) { if (roc_ctx->roc_state < ROC_STATE_ON_CHAN) @@ -391,11 +392,13 @@ static void p2p_roc_timeout(void *pdata) return; } - p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d", - roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, - roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan, - roc_ctx->phy_mode, roc_ctx->duration, - roc_ctx->roc_type, roc_ctx->roc_state); + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d," + " tx ctx:%pK, freq:%d, phy_mode:%d, duration:%d," + " roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); if (roc_ctx->roc_state == ROC_STATE_CANCEL_IN_PROG) { p2p_err("Cancellation already in progress"); @@ -418,11 +421,13 @@ static QDF_STATUS p2p_execute_roc_req(struct p2p_roc_context *roc_ctx) QDF_STATUS status; struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; - p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d", - p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, - roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan, - roc_ctx->phy_mode, roc_ctx->duration, - roc_ctx->roc_type, roc_ctx->roc_state); + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d," + " tx ctx:%pK, freq:%d, phy_mode:%d, duration:%d," + " roc_type:%d, roc_state:%d", + p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); /* prevent runtime suspend */ qdf_runtime_pm_prevent_suspend(&p2p_soc_obj->roc_runtime_lock); @@ -645,14 +650,14 @@ struct p2p_roc_context *p2p_find_current_roc_ctx( struct p2p_roc_context, node); if (roc_ctx->roc_state != ROC_STATE_IDLE) { p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id" - ":%d, scan_id:%d, tx ctx:%pK, chan:" - "%d, phy_mode:%d, duration:%d, " - "roc_type:%d, roc_state:%d", - roc_ctx->p2p_soc_obj, roc_ctx, - roc_ctx->vdev_id, roc_ctx->scan_id, - roc_ctx->tx_ctx, roc_ctx->chan, - roc_ctx->phy_mode, roc_ctx->duration, - roc_ctx->roc_type, roc_ctx->roc_state); + ":%d, scan_id:%d, tx ctx:%pK, freq:" + "%d, phy_mode:%d, duration:%d, " + "roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, + roc_ctx->vdev_id, roc_ctx->scan_id, + roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); return roc_ctx; } @@ -685,8 +690,8 @@ struct p2p_roc_context *p2p_find_roc_by_tx_ctx( return NULL; } -struct p2p_roc_context *p2p_find_roc_by_chan( - struct p2p_soc_priv_obj *p2p_soc_obj, uint8_t chan) +struct p2p_roc_context *p2p_find_roc_by_chan_freq( + struct p2p_soc_priv_obj *p2p_soc_obj, qdf_freq_t chan_freq) { struct p2p_roc_context *roc_ctx; qdf_list_node_t *p_node; @@ -697,11 +702,14 @@ struct p2p_roc_context *p2p_find_roc_by_chan( roc_ctx = qdf_container_of(p_node, struct p2p_roc_context, node); - if (roc_ctx->chan == chan) { - p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d", + if (roc_ctx->chan_freq == chan_freq) { + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d," + " scan_id:%d, tx ctx:%pK, freq:%d," + " phy_mode:%d, duration:%d," + " roc_type:%d, roc_state:%d", roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, roc_ctx->scan_id, - roc_ctx->tx_ctx, roc_ctx->chan, + roc_ctx->tx_ctx, roc_ctx->chan_freq, roc_ctx->phy_mode, roc_ctx->duration, roc_ctx->roc_type, roc_ctx->roc_state); @@ -808,10 +816,12 @@ QDF_STATUS p2p_process_cleanup_roc_queue( roc_ctx = qdf_container_of(p_node, struct p2p_roc_context, node); - p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d", + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, " + "scan_id:%d, tx ctx:%pK, freq:%d, phy_mode:%d, " + "duration:%d, roc_type:%d, roc_state:%d", roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, roc_ctx->scan_id, - roc_ctx->tx_ctx, roc_ctx->chan, + roc_ctx->tx_ctx, roc_ctx->chan_freq, roc_ctx->phy_mode, roc_ctx->duration, roc_ctx->roc_type, roc_ctx->roc_state); status = qdf_list_peek_next(&p2p_soc_obj->roc_q, @@ -836,9 +846,11 @@ QDF_STATUS p2p_process_cleanup_roc_queue( roc_ctx = qdf_container_of(p_node, struct p2p_roc_context, node); - p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d", + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, " + "scan_id:%d, tx ctx:%pK, freq:%d, phy_mode:%d, " + "duration:%d, roc_type:%d, roc_state:%d", roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, - roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, roc_ctx->phy_mode, roc_ctx->duration, roc_ctx->roc_type, roc_ctx->roc_state); @@ -871,11 +883,13 @@ QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx) p2p_soc_obj = roc_ctx->p2p_soc_obj; - p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, tx_ctx:%pK, chan:%d, phy_mode:%d, duration:%d, roc_type:%d, roc_state:%d", - p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, - roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan, - roc_ctx->phy_mode, roc_ctx->duration, - roc_ctx->roc_type, roc_ctx->roc_state); + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, " + "tx_ctx:%pK, freq:%d, phy_mode:%d, duration:%d, " + "roc_type:%d, roc_state:%d", + p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); status = qdf_list_insert_back(&p2p_soc_obj->roc_q, &roc_ctx->node); diff --git a/components/p2p/core/src/wlan_p2p_roc.h b/components/p2p/core/src/wlan_p2p_roc.h index f1f27364ac7b..b800b20174b4 100644 --- a/components/p2p/core/src/wlan_p2p_roc.h +++ b/components/p2p/core/src/wlan_p2p_roc.h @@ -81,7 +81,7 @@ enum roc_state { * @vdev_id: Vdev id on which this request has come * @scan_id: Scan id given by scan component for this roc req * @tx_ctx: TX context if this ROC is for tx MGMT - * @chan: Chan for which this RoC has been requested + * @chan_freq: Chan frequency for which this RoC has been requested * @phy_mode: PHY mode * @duration: Duration for the RoC * @roc_type: RoC type User requested or internal @@ -95,7 +95,7 @@ struct p2p_roc_context { uint32_t vdev_id; uint32_t scan_id; void *tx_ctx; - qdf_freq_t chan; + qdf_freq_t chan_freq; uint8_t phy_mode; uint32_t duration; enum roc_type roc_type; @@ -165,9 +165,9 @@ struct p2p_roc_context *p2p_find_roc_by_tx_ctx( struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie); /** - * p2p_find_roc_by_chan() - Find out roc context by channel + * p2p_find_roc_by_chan_freq() - Find out roc context by channel * @p2p_soc_obj: p2p psoc private object - * @chan: channel of the ROC + * @chan_freq: channel frequency of the ROC * * This function finds out roc context by channel from p2p psoc * private object @@ -175,8 +175,8 @@ struct p2p_roc_context *p2p_find_roc_by_tx_ctx( * Return: Pointer to roc context - success * NULL - failure */ -struct p2p_roc_context *p2p_find_roc_by_chan( - struct p2p_soc_priv_obj *p2p_soc_obj, uint8_t chan); +struct p2p_roc_context *p2p_find_roc_by_chan_freq( + struct p2p_soc_priv_obj *p2p_soc_obj, qdf_freq_t chan_freq); /** * p2p_restart_roc_timer() - Restarts roc timer diff --git a/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h b/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h index 1f09757a868b..060f0df3ba8b 100644 --- a/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h +++ b/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h @@ -62,13 +62,13 @@ struct p2p_ps_params { /** * struct p2p_roc_req - P2P roc request * @vdev_id: Vdev id on which this request has come - * @chan: Chan for which this RoC has been requested + * @chan_freq: Chan frequency for which this RoC has been requested * @phy_mode: PHY mode * @duration: Duration for the RoC */ struct p2p_roc_req { uint32_t vdev_id; - qdf_freq_t chan; + qdf_freq_t chan_freq; uint32_t phy_mode; uint32_t duration; }; @@ -90,14 +90,14 @@ enum p2p_roc_event { * @vdev_id: Vdev id * @roc_event: RoC event * @cookie: Cookie which is given to supplicant for this roc req - * @chan: Chan for which this RoC has been requested + * @chan_freq: Chan frequency for which this RoC has been requested * @duration: Duration for the RoC */ struct p2p_event { uint32_t vdev_id; enum p2p_roc_event roc_event; uint64_t cookie; - qdf_freq_t chan; + qdf_freq_t chan_freq; uint32_t duration; }; @@ -138,7 +138,7 @@ struct p2p_tx_cnf { /** * struct p2p_mgmt_tx - p2p mgmt tx structure * @vdev_id: Vdev id - * @chan: Chan for which this RoC has been requested + * @chan_freq: Chan frequency for which this RoC has been requested * @wait: Duration for the RoC * @len: Length of tx buffer * @no_cck: Required cck or not @@ -148,7 +148,7 @@ struct p2p_tx_cnf { */ struct p2p_mgmt_tx { uint32_t vdev_id; - uint32_t chan; + qdf_freq_t chan_freq; uint32_t wait; uint32_t len; uint32_t no_cck; diff --git a/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c b/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c index 50444dc6d8e4..3b862f62d3de 100644 --- a/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c +++ b/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -118,9 +119,9 @@ QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc, QDF_STATUS status; int32_t id; - p2p_debug("soc:%pK, vdev_id:%d, chan:%d, phy_mode:%d, duration:%d", - soc, roc_req->vdev_id, roc_req->chan, - roc_req->phy_mode, roc_req->duration); + p2p_debug("soc:%pK, vdev_id:%d, chanfreq:%d, phy_mode:%d, duration:%d", + soc, roc_req->vdev_id, roc_req->chan_freq, + roc_req->phy_mode, roc_req->duration); if (!soc) { p2p_err("psoc context passed is NULL"); @@ -148,7 +149,7 @@ QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc, *cookie = (uint64_t)id; roc_ctx->p2p_soc_obj = p2p_soc_obj; roc_ctx->vdev_id = roc_req->vdev_id; - roc_ctx->chan = roc_req->chan; + roc_ctx->chan_freq = roc_req->chan_freq; roc_ctx->phy_mode = roc_req->phy_mode; roc_ctx->duration = roc_req->duration; roc_ctx->roc_state = ROC_STATE_IDLE; @@ -324,10 +325,11 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, QDF_STATUS status; int32_t id; - p2p_debug("soc:%pK, vdev_id:%d, chan:%d, wait:%d, buf_len:%d, cck:%d, no ack:%d, off chan:%d", - soc, mgmt_frm->vdev_id, mgmt_frm->chan, - mgmt_frm->wait, mgmt_frm->len, mgmt_frm->no_cck, - mgmt_frm->dont_wait_for_ack, mgmt_frm->off_chan); + p2p_debug("soc:%pK, vdev_id:%d, freq:%d, wait:%d, buf_len:%d," + " cck:%d, no ack:%d, off chan:%d", + soc, mgmt_frm->vdev_id, mgmt_frm->chan_freq, + mgmt_frm->wait, mgmt_frm->len, mgmt_frm->no_cck, + mgmt_frm->dont_wait_for_ack, mgmt_frm->off_chan); if (!soc) { p2p_err("psoc context passed is NULL"); @@ -361,7 +363,7 @@ QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, *cookie = (uint64_t)id; tx_action->p2p_soc_obj = p2p_soc_obj; tx_action->vdev_id = mgmt_frm->vdev_id; - tx_action->chan = mgmt_frm->chan; + tx_action->chan_freq = mgmt_frm->chan_freq; tx_action->duration = mgmt_frm->wait; tx_action->buf_len = mgmt_frm->len; tx_action->no_cck = mgmt_frm->no_cck; diff --git a/os_if/p2p/src/wlan_cfg80211_p2p.c b/os_if/p2p/src/wlan_cfg80211_p2p.c index 4db1500f65fa..8363fbe52a80 100644 --- a/os_if/p2p/src/wlan_cfg80211_p2p.c +++ b/os_if/p2p/src/wlan_cfg80211_p2p.c @@ -282,7 +282,7 @@ static void wlan_p2p_event_callback(void *user_data, goto fail; } - chan = ieee80211_get_channel(wdev->wiphy, p2p_event->chan); + chan = ieee80211_get_channel(wdev->wiphy, p2p_event->chan_freq); if (!chan) { osif_err("channel conversion failed"); goto fail; @@ -360,7 +360,7 @@ int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev, return -EINVAL; } - roc_req.chan = chan->center_freq; + roc_req.chan_freq = chan->center_freq; roc_req.duration = duration; roc_req.vdev_id = (uint32_t)vdev_id; @@ -372,7 +372,7 @@ int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev, } if (!ok) { - osif_err("channel%d not OK for DNBS", roc_req.chan); + osif_err("channel%d not OK for DNBS", roc_req.chan_freq); return -EINVAL; } @@ -450,7 +450,7 @@ int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, } mgmt_tx.vdev_id = (uint32_t)vdev_id; - mgmt_tx.chan = chan_freq; + mgmt_tx.chan_freq = chan_freq; mgmt_tx.wait = wait; mgmt_tx.len = len; mgmt_tx.no_cck = (uint32_t)no_cck; From d6e1ed30e5bd70090f15ccd40fcfa26e8dbb9914 Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Thu, 10 Apr 2025 01:07:24 -0700 Subject: [PATCH 068/306] Release 2.0.8.35B Release 2.0.8.35B Change-Id: Id320fd9d156ae0f075b050ba530da1bce5bb2a69 CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 5a0f26d5d2fc..d27763477199 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "A" +#define QWLAN_VERSION_EXTRA "B" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35A" +#define QWLAN_VERSIONSTR "2.0.8.35B" #endif /* QWLAN_VERSION_H */ From b587f9fca3c4be356fd2bdb248506eac7d635201 Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 8 Apr 2025 23:32:42 -0700 Subject: [PATCH 069/306] fw-api: CL 28970374 - update fw common interface files Change-Id: I7e43d146f428d9e4ba624ab1ac05666e9a9e5770 CRs-Fixed: 3830439 --- fw/wlan_module_ids.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fw/wlan_module_ids.h b/fw/wlan_module_ids.h index 981bbaef3451..a00b3e5c1924 100644 --- a/fw/wlan_module_ids.h +++ b/fw/wlan_module_ids.h @@ -196,6 +196,7 @@ typedef enum { WLAN_MODULE_C2C, /* 0x98 */ WLAN_MODULE_VBSS, /* 0x99 */ WLAN_MODULE_OPT_DATA, /* 0x9a */ + WLAN_MODULE_ASD, /* 0x9b */ WLAN_MODULE_ID_MAX, WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, From 41844e5a75f5b76e0a8bbfd2198f3eb780c57fe3 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 10 Apr 2025 06:03:26 -0700 Subject: [PATCH 070/306] fw-api: CL 28972929 - update fw common interface files Change-Id: I74d709473691bdefd22ace176ee73854f3eeae50 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 3 +++ fw/wmi_version.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index f1db33bc5d5c..95fcbb807e53 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -19455,6 +19455,9 @@ typedef enum { */ WMI_VDEV_PARAM_CONNECT_EXT_FEATURES, /* 0xC7 */ + /* Allow to tear down TWT on scan start, if corresponding INI is set */ + WMI_VDEV_PARAM_DISABLE_SCAN_START_TWT, /* 0xC8 */ + /*=== ADD NEW VDEV PARAM TYPES ABOVE THIS LINE === * The below vdev param types are used for prototyping, and are diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 8bb7d189c2d3..a6f2c51697c5 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1596 +#define __WMI_REVISION_ 1597 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 79fb39314b750fb208a84ec0db04442d4bc5803e Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 10 Apr 2025 06:01:56 -0700 Subject: [PATCH 071/306] fw-api: CL 28971130 - update fw common interface files Change-Id: I536030d3dd454e5cbfc53fe229afdedc0ce25736 CRs-Fixed: 3830439 --- fw/htt.h | 105 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 31 deletions(-) diff --git a/fw/htt.h b/fw/htt.h index 300433042810..5e43e5e8fc0e 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -266,9 +266,10 @@ * 3.136 Add htt_ext_present flag in htt_tx_tcl_global_seq_metadata. * 3.137 Add more HTT_SDWF_MSDUQ_CFG_IND_ERROR codes. * 3.138 Add T2H MLO_LATENCY_REQ, H2T _RESP msg defs. + * 3.139 Add CLASS_INFO_IDX field in MLO_R_PEER_MAP msg. */ #define HTT_CURRENT_VERSION_MAJOR 3 -#define HTT_CURRENT_VERSION_MINOR 138 +#define HTT_CURRENT_VERSION_MINOR 139 #define HTT_NUM_TX_FRAG_DESC 1024 @@ -14662,40 +14663,41 @@ PREPACK struct htt_tx_offload_deliver_ind_hdr_t * with, so that the host can use that MLO peer ID to determine which peer * transmitted the rx frame. * - * |31 |29 27|26 24|23 20|19 17|16|15 8|7 0| - * |-------------------------------------------------------------------------| - * |RSVD | PRC |NUMLINK| MLO peer ID | msg type | - * |-------------------------------------------------------------------------| - * | MAC addr 3 | MAC addr 2 | MAC addr 1 | MAC addr 0 | - * |-------------------------------------------------------------------------| - * | RSVD_16_31 | MAC addr 5 | MAC addr 4 | - * |-------------------------------------------------------------------------| - * |CACHE_SET_NUM| TIDMASK |CHIPID|V| Primary TCL AST IDX 0 | - * |-------------------------------------------------------------------------| - * |CACHE_SET_NUM| TIDMASK |CHIPID|V| Primary TCL AST IDX 1 | - * |-------------------------------------------------------------------------| - * |CACHE_SET_NUM| TIDMASK |CHIPID|V| Primary TCL AST IDX 2 | - * |-------------------------------------------------------------------------| - * |RSVD | - * |-------------------------------------------------------------------------| - * |RSVD | - * |-------------------------------------------------------------------------| - * | htt_tlv_hdr_t | - * |-------------------------------------------------------------------------| - * |RSVD_27_31 |CHIPID| VDEVID | SW peer ID | - * |-------------------------------------------------------------------------| - * | htt_tlv_hdr_t | - * |-------------------------------------------------------------------------| - * |RSVD_27_31 |CHIPID| VDEVID | SW peer ID | - * |-------------------------------------------------------------------------| - * | htt_tlv_hdr_t | - * |-------------------------------------------------------------------------| - * |RSVD_27_31 |CHIPID| VDEVID | SW peer ID | - * |-------------------------------------------------------------------------| + * |31 |29 27|26|25|24|23 20|19 17|16|15 8|7 0| + * |--------------------------------------------------------------------------| + * |RSVD | PRC | NUMLINK| MLO peer ID | msg type | + * |--------------------------------------------------------------------------| + * | MAC addr 3 | MAC addr 2 | MAC addr 1 | MAC addr 0 | + * |--------------------------------------------------------------------------| + * | RSVD_25_31 |CV| CLASS_INFO_IDX | MAC addr 5 | MAC addr 4 | + * |--------------------------------------------------------------------------| + * |CACHE_SET_NUM| TIDMASK |CHIPID|V| Primary TCL AST IDX 0 | + * |--------------------------------------------------------------------------| + * |CACHE_SET_NUM| TIDMASK |CHIPID|V| Primary TCL AST IDX 1 | + * |--------------------------------------------------------------------------| + * |CACHE_SET_NUM| TIDMASK |CHIPID|V| Primary TCL AST IDX 2 | + * |--------------------------------------------------------------------------| + * |RSVD | + * |--------------------------------------------------------------------------| + * |RSVD | + * |--------------------------------------------------------------------------| + * | htt_tlv_hdr_t | + * |--------------------------------------------------------------------------| + * |RSVD_27_31 | CHIPID | VDEVID | SW peer ID | + * |--------------------------------------------------------------------------| + * | htt_tlv_hdr_t | + * |--------------------------------------------------------------------------| + * |RSVD_27_31 | CHIPID | VDEVID | SW peer ID | + * |--------------------------------------------------------------------------| + * | htt_tlv_hdr_t | + * |--------------------------------------------------------------------------| + * |RSVD_27_31 | CHIPID | VDEVID | SW peer ID | + * |--------------------------------------------------------------------------| * * Where: * PRC - Primary REO CHIPID - 3 Bits Bit24,25,26 * NUMLINK - NUM_LOGICAL_LINKS - 3 Bits Bit27,28,29 + * CV - CLASSIFY_INFO_IDX_VALID - 1 Bit Bit24 * V (valid) - 1 Bit Bit17 * CHIPID - 3 Bits * TIDMASK - 8 Bits @@ -14735,6 +14737,16 @@ PREPACK struct htt_tx_offload_deliver_ind_hdr_t * Purpose: Identifies which peer node the peer ID is for. * Value: upper 2 bytes of peer node's MAC address * + * - CLASS_INFO_IDX + * Bits 23:16 + * Purpose: Classify info index assists TCL-L Block in certain families of + * WLAN chips to start finding the flow from the corresponding + * entry in the FLOW LOOK UP TABLE in MLO case + * - CV (CLASS_INFO_IDX_VALID) + * Bit 24 + * Purpose: if set indicates that the CLASS_INFO_IDX is valid, + * else ignore the value reported + * * - PRIMARY_TCL_AST_IDX * Bits 15:0 * Purpose: Primary TCL AST index for this peer. @@ -14806,6 +14818,11 @@ typedef enum { #define HTT_RX_MLO_PEER_MAP_MAC_ADDR_U16_M 0x0000ffff #define HTT_RX_MLO_PEER_MAP_MAC_ADDR_U16_S 0 +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_M 0x00ff0000 +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_S 16 +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_M 0x01000000 +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_S 24 + #define HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX_M 0x0000ffff #define HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX_S 0 #define HTT_RX_MLO_PEER_MAP_AST_INDEX_VALID_FLAG_M 0x00010000 @@ -14854,6 +14871,30 @@ typedef enum { #define HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_GET(word) \ (((word) & HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_M) >> HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_S) +#define HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID, value); \ + (word) |= (value) << HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_S; \ + } while (0) +#define HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_GET(word) \ + (((word) & HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_M) >> HTT_RX_MLO_PEER_PRIMARY_REO_CHIP_ID_S) + +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX, value); \ + (word) |= (value) << HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_S; \ + } while (0) +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_GET(word) \ + (((word) & HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_M) >> HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_S) + +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG, value); \ + (word) |= (value) << HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_S; \ + } while (0) +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_GET(word) \ + (((word) & HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_M) >> HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_S) + #define HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX_SET(word, value) \ do { \ HTT_CHECK_SET_VAL(HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX, value); \ @@ -14936,6 +14977,8 @@ typedef enum { #define HTT_RX_MLO_PEER_MAP_MAC_ADDR_OFFSET 4 /* bytes */ +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_OFFSET 8 /* bytes */ +#define HTT_RX_MLO_PEER_MAP_CLASSIFY_INFO_IDX_VALID_FLAG_OFFSET 8 /* bytes */ #define HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX_0_OFFSET 12 /* bytes */ #define HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX_1_OFFSET 16 /* bytes */ #define HTT_RX_MLO_PEER_MAP_PRIMARY_AST_INDEX_2_OFFSET 20 /* bytes */ From 66731738f257de083021edd22726080c515bfb9a Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Sun, 16 Feb 2025 23:56:49 +0530 Subject: [PATCH 072/306] iommu: Fix invalid access in av8l_fast_unmap_public KASAN has reported the following invalid access in av8l_fast_unmap_public. This is because while calculating pmd offset, base is subtracted from iova, in case if iova is less than base it would result in underflow, thereby resulting in an invalid access. BUG: KASAN: wild-memory-access in av8l_fast_unmap_public+0x60/0x88 [qcom_iommu_util] Write of size 8 at addr 007fffc084480000 by task syz.1.693/6987 Call trace: dump_backtrace+0x1b0/0x1e0 show_stack+0x2c/0x40 dump_stack_lvl+0xd0/0x128 print_report+0xe4/0x6f8 kasan_report+0xe8/0x148 kasan_check_range+0x250/0x294 __asan_memset+0x34/0x68 av8l_fast_unmap_public+0x60/0x88 fast_smmu_unmap_page+0x1cc/0x244 dma_unmap_page_attrs+0xa4/0x3a0 geni_i2c_xfer+0x4a24/0x6154 __i2c_transfer+0x488/0x147c i2c_transfer+0x174/0x21c i2cdev_ioctl_rdwr+0x22c/0x44c i2cdev_ioctl+0x628/0x700 __arm64_sys_ioctl+0x110/0x18c invoke_syscall+0x88/0x1cc el0_svc_common+0xe4/0x1b0 Fix this by adding a check and returning error when iova is less than base. Fixes: Ie6c23cb8e17 ("iommu/io-pgtable-fast: optimize statically allocated pages") Change-Id: I4e3a585d348d897e51888a898c8e64c51c9f46c3 Signed-off-by: Vijayanand Jitta Signed-off-by: Srinivasarao Pathipati --- drivers/iommu/dma-mapping-fast.c | 19 +++++++++++++--- drivers/iommu/io-pgtable-fast.c | 37 +++++++++++++++++++++++++++++--- include/linux/io-pgtable-fast.h | 5 +++-- 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c index 3dbaef99d89c..947ba3ca140d 100644 --- a/drivers/iommu/dma-mapping-fast.c +++ b/drivers/iommu/dma-mapping-fast.c @@ -244,8 +244,12 @@ static void fast_smmu_unmap_page(struct device *dev, dma_addr_t iova, } spin_lock_irqsave(&mapping->lock, flags); - av8l_fast_unmap_public(mapping->pgtbl_ops, iova, len); + + if (unlikely(!av8l_fast_unmap_public(mapping->pgtbl_ops, iova, len))) + goto fail; + __fast_smmu_free_iova(mapping, iova, len); +fail: spin_unlock_irqrestore(&mapping->lock, flags); trace_unmap(to_msm_iommu_domain(mapping->domain), iova - offset, len, @@ -385,7 +389,8 @@ static void fast_smmu_unmap_sg(struct device *dev, len = ALIGN(sg_dma_address(sg) + sg_dma_len(sg) - (start - offset), FAST_PAGE_SIZE); - av8l_fast_unmap_public(mapping->pgtbl_ops, start, len); + if (unlikely(!av8l_fast_unmap_public(mapping->pgtbl_ops, start, len))) + return; spin_lock_irqsave(&mapping->lock, flags); __fast_smmu_free_iova(mapping, start, len); @@ -653,7 +658,10 @@ static void fast_smmu_free(struct device *dev, size_t size, size = ALIGN(size, FAST_PAGE_SIZE); spin_lock_irqsave(&mapping->lock, flags); - av8l_fast_unmap_public(mapping->pgtbl_ops, dma_handle, size); + + if (unlikely(!av8l_fast_unmap_public(mapping->pgtbl_ops, dma_handle, size))) + goto fail; + __fast_smmu_free_iova(mapping, dma_handle, size); spin_unlock_irqrestore(&mapping->lock, flags); @@ -674,6 +682,11 @@ static void fast_smmu_free(struct device *dev, size_t size, if (page) dma_free_contiguous(dev, page, size); + + return; + +fail: + spin_unlock_irqrestore(&mapping->lock, flags); } static int fast_smmu_mmap_attrs(struct device *dev, struct vm_area_struct *vma, diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index a9159c012106..f07e93b33f05 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -127,7 +127,14 @@ #define PTE_SH_IDX(pte) (pte & AV8L_FAST_PTE_SH_MASK) -#define iopte_pmd_offset(pmds, base, iova) (pmds + ((iova - base) >> 12)) +#define iopte_pmd_offset(pmds, base, iova) \ +({ \ + typeof(iova) __iova = (iova); \ + typeof(base) __base = (base); \ + typeof(pmds) __pmds = (pmds); \ + (__iova < __base) ? ERR_PTR(-EINVAL) : \ + __pmds + ((__iova - __base) >> AV8L_FAST_PAGE_SHIFT); \ +}) static inline dma_addr_t av8l_dma_addr(void *addr) { @@ -202,6 +209,12 @@ void av8l_fast_clear_stale_ptes(struct io_pgtable_ops *ops, u64 base, struct io_pgtable *iop = iof_pgtable_ops_to_pgtable(ops); av8l_fast_iopte *pmdp = iopte_pmd_offset(data->pmds, data->base, base); + if (IS_ERR(pmdp)) { + pr_err("Invalid iova : 0x%lx, as it is less than base : 0x%llx\n", + iova, data->base); + return; + } + for (i = base >> AV8L_FAST_PAGE_SHIFT; i <= (end >> AV8L_FAST_PAGE_SHIFT); ++i) { if (!(*pmdp & AV8L_FAST_PTE_VALID)) { @@ -254,6 +267,12 @@ static int av8l_fast_map(struct io_pgtable_ops *ops, unsigned long iova, unsigned long i, nptes = size >> AV8L_FAST_PAGE_SHIFT; av8l_fast_iopte pte; + if (IS_ERR(ptep)) { + pr_err("Invalid iova : 0x%lx, as it is less than base : 0x%llx\n", + iova, data->base); + return -EINVAL; + } + pte = av8l_fast_prot_to_pte(data, prot); paddr &= AV8L_FAST_PTE_ADDR_MASK; for (i = 0; i < nptes; i++, paddr += SZ_4K) { @@ -286,6 +305,12 @@ __av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova, ptep = iopte_pmd_offset(data->pmds, data->base, iova); nptes = size >> AV8L_FAST_PAGE_SHIFT; + if (IS_ERR(ptep)) { + pr_err("Invalid iova : 0x%lx, as it is less than base : 0x%llx\n", + iova, data->base); + return 0; + } + memset(ptep, val, sizeof(*ptep) * nptes); av8l_clean_range(&iop->cfg, ptep, ptep + nptes); if (!allow_stale_tlb) @@ -295,10 +320,10 @@ __av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova, } /* caller must take care of tlb cache maintenance */ -void av8l_fast_unmap_public(struct io_pgtable_ops *ops, unsigned long iova, +size_t av8l_fast_unmap_public(struct io_pgtable_ops *ops, unsigned long iova, size_t size) { - __av8l_fast_unmap(ops, iova, size, true); + return __av8l_fast_unmap(ops, iova, size, true); } static size_t av8l_fast_unmap(struct io_pgtable_ops *ops, unsigned long iova, @@ -383,6 +408,12 @@ static bool av8l_fast_iova_coherent(struct io_pgtable_ops *ops, struct av8l_fast_io_pgtable *data = iof_pgtable_ops_to_data(ops); av8l_fast_iopte *ptep = iopte_pmd_offset(data->pmds, data->base, iova); + if (IS_ERR(ptep)) { + pr_err("Invalid iova : 0x%lx, as it is less than base : 0x%llx\n", + iova, data->base); + return false; + } + return ((PTE_MAIR_IDX(*ptep) == AV8L_FAST_MAIR_ATTR_IDX_CACHE) && ((PTE_SH_IDX(*ptep) == AV8L_FAST_PTE_SH_OS) || (PTE_SH_IDX(*ptep) == AV8L_FAST_PTE_SH_IS))); diff --git a/include/linux/io-pgtable-fast.h b/include/linux/io-pgtable-fast.h index 245f86fbbe46..95b05a85f61c 100644 --- a/include/linux/io-pgtable-fast.h +++ b/include/linux/io-pgtable-fast.h @@ -44,7 +44,7 @@ struct av8l_fast_io_pgtable { int av8l_fast_map_public(struct io_pgtable_ops *ops, unsigned long iova, phys_addr_t paddr, size_t size, int prot); -void av8l_fast_unmap_public(struct io_pgtable_ops *ops, unsigned long iova, +size_t av8l_fast_unmap_public(struct io_pgtable_ops *ops, unsigned long iova, size_t size); int av8l_fast_map_sg_public(struct io_pgtable_ops *ops, @@ -63,9 +63,10 @@ av8l_fast_map_public(struct io_pgtable_ops *ops, unsigned long iova, { return -EINVAL; } -static inline void av8l_fast_unmap_public(struct io_pgtable_ops *ops, +static inline size_t av8l_fast_unmap_public(struct io_pgtable_ops *ops, unsigned long iova, size_t size) { + return 0; } static inline int av8l_fast_map_sg_public(struct io_pgtable_ops *ops, From c24d1b2f7c4756cf0ac6592ea485ab798368404e Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 12 Apr 2025 06:01:32 -0700 Subject: [PATCH 073/306] fw-api: CL 28990820 - update fw common interface files Change-Id: Ia6f973371c3498aa5240d40035b15c475d692881 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 21 +++++++++++++++------ fw/wmi_version.h | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 95fcbb807e53..ea635f2d08b3 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -5127,11 +5127,11 @@ typedef struct { reserved: 31; }; }; - #define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_GET(word32) \ - WMI_GET_BITS(word32, 0, 1) - #define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_SET(word32, value) \ - WMI_SET_BITS(word32, 0, 1, value) } wmi_resource_config; +#define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_GET(word32) \ + WMI_GET_BITS(word32, 0, 1) +#define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_SET(word32, value) \ + WMI_SET_BITS(word32, 0, 1, value) #define WMI_MSDU_FLOW_AST_ENABLE_GET(msdu_flow_config0, ast_x) \ (((ast_x) == 0) ? 1 : ((msdu_flow_config0) & (1 << ((ast_x) - 1)))) @@ -48204,9 +48204,11 @@ typedef struct { } wmi_sawf_svc_class_disable_cmd_fixed_param; /* Used to store Hop count info for SDWF-Ezmesh scenario based on topology changes */ +#define WMI_SAWF_EZMESH_HOP_COUNT_SVC_ID_GET(svc_class_params) WMI_GET_BITS(svc_class_params, 0, 8) +#define WMI_SAWF_EZMESH_HOP_COUNT_SVC_ID_SET(svc_class_params, value) WMI_SET_BITS(svc_class_params, 0, 8, value) typedef struct { A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sawf_ezmesh_hop_count_cmd_fixed_param */ - A_UINT32 peer_id; + A_UINT32 peer_id; /* deprecated field */ A_UINT32 hop_count; /* delay_bound: * Placeholder for future functionality where delay bound will be directly @@ -48214,8 +48216,15 @@ typedef struct { * (units = ms) */ A_UINT32 delay_bound; - wmi_mac_addr mac_address; + wmi_mac_addr mac_address; /* Mac Address of next BSTA */ A_UINT32 vdev_id; + union { + struct { + A_UINT32 svc_id:8, + reserved:24; + }; + A_UINT32 svc_class_params; + }; } wmi_sawf_ezmesh_hop_count_cmd_fixed_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index a6f2c51697c5..e1e8689ac5f8 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1597 +#define __WMI_REVISION_ 1598 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From b3ce06c8af9f453745266310610bab7e51bbf652 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 13 Apr 2025 06:01:23 -0700 Subject: [PATCH 074/306] fw-api: CL 28998301 - update fw common interface files Change-Id: Ie33eaeb83df853b1d6cccef3c863466e1927a379 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index ea635f2d08b3..41055f993a30 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -24764,6 +24764,8 @@ typedef enum wake_reason_e { WOW_REASON_PF_BLOCKING_LAST_TIME, /* C2C scan report LPI AP detect or not event */ WOW_REASON_C2C_DETECT_EVENT, + /* wake up the host in case of TDLS packet reception */ + WOW_REASON_TDLS_PACKET_RX, /* add new WOW_REASON_ defs before this line */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index e1e8689ac5f8..9059a4c37355 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1598 +#define __WMI_REVISION_ 1599 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 797cb53b67843921ddfc173be1e948c27415a146 Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 14 Apr 2025 06:01:43 -0700 Subject: [PATCH 075/306] fw-api: CL 28998846 - update fw common interface files Change-Id: Ib36b895316048d638f2e07e44a1f5e076196821c CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 41055f993a30..d2e4c714b068 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -40797,6 +40797,8 @@ typedef enum _WMI_DEL_TWT_STATUS_T { WMI_DEL_TWT_STATUS_CHANGE_CONGESTION_TIMEOUT, /* Congestion timeout changed */ WMI_DEL_TWT_STATUS_P2P_GO_NOA, /* P2P GO NOA */ WMI_DEL_TWT_STATUS_UNSUPPORTED_MLMR_MODE, /* Teardown due to MLMR */ + WMI_DEL_TWT_STATUS_MLO_LINK_INACTIVE, /* Teardown due to link going to inactive */ + WMI_DEL_TWT_STATUS_2G_TWT_NOT_ENABLED, /* Teardown due to 2.4 GHz TWT not enabled */ } WMI_DEL_TWT_STATUS_T; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 9059a4c37355..457621357112 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1599 +#define __WMI_REVISION_ 1600 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From edaba15ed6637cd7e95ba7d8967c347e4ed6cdbd Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 16 Apr 2025 06:01:27 -0700 Subject: [PATCH 076/306] fw-api: CL 29007944 - update fw common interface files Change-Id: Id621154a345c04b659e0562ece0848ab76989173 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 1 + fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index d2e4c714b068..1602da16aeea 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -40799,6 +40799,7 @@ typedef enum _WMI_DEL_TWT_STATUS_T { WMI_DEL_TWT_STATUS_UNSUPPORTED_MLMR_MODE, /* Teardown due to MLMR */ WMI_DEL_TWT_STATUS_MLO_LINK_INACTIVE, /* Teardown due to link going to inactive */ WMI_DEL_TWT_STATUS_2G_TWT_NOT_ENABLED, /* Teardown due to 2.4 GHz TWT not enabled */ + WMI_DEL_TWT_STATUS_SCAN_STARTED, /* Teardown due to scan started */ } WMI_DEL_TWT_STATUS_T; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 457621357112..276f68699d88 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1600 +#define __WMI_REVISION_ 1601 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 17f7f8dcfa6fd0a13c7505f93b1d40adb487f34d Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 17 Apr 2025 06:01:38 -0700 Subject: [PATCH 077/306] fw-api: CL 29017022 - update fw common interface files Change-Id: If9992443110a31ebec92a2ea7ab5c24926cf88ff CRs-Fixed: 3830439 --- fw/wlan_defs.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fw/wlan_defs.h b/fw/wlan_defs.h index 352967101d47..823b8ec9fedf 100755 --- a/fw/wlan_defs.h +++ b/fw/wlan_defs.h @@ -274,6 +274,20 @@ typedef enum { ((mode) == MODE_11BE_EHT40_2G)) #endif /* SUPPORT_11BE */ +#if defined(SUPPORT_11BN) && SUPPORT_11BN +#define IS_MODE_UHR(mode) (((mode) == MODE_11BN_UHR20) || \ + ((mode) == MODE_11BN_UHR40) || \ + ((mode) == MODE_11BN_UHR80) || \ + ((mode) == MODE_11BN_UHR80_80) || \ + ((mode) == MODE_11BN_UHR160) || \ + ((mode) == MODE_11BN_UHR160_160)|| \ + ((mode) == MODE_11BN_UHR320) || \ + ((mode) == MODE_11BN_UHR20_2G) || \ + ((mode) == MODE_11BN_UHR40_2G)) +#define IS_MODE_UHR_2G(mode) (((mode) == MODE_11BN_UHR20_2G) || \ + ((mode) == MODE_11BN_UHR40_2G)) +#endif /* SUPPORT_11BN */ + #define IS_MODE_VHT_2G(mode) (((mode) == MODE_11AC_VHT20_2G) || \ ((mode) == MODE_11AC_VHT40_2G) || \ ((mode) == MODE_11AC_VHT80_2G)) From e1bc8251711425396d3327d4eebf297c5136e33a Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 17 Apr 2025 06:03:17 -0700 Subject: [PATCH 078/306] fw-api: CL 29018064 - update fw common interface files Change-Id: I15253402f6b7cee2602b64cd676c9f8beb5b9f8a CRs-Fixed: 3830439 --- fw/wmi_unified.h | 20 ++++++++++++-------- fw/wmi_version.h | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 1602da16aeea..25395fe7811d 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -6353,16 +6353,16 @@ typedef struct { #define WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT 0x40000 #define WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ 0x80000 #define WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ 0x100000 -/** pause home channel when scan channel is same as home channel */ -#define WMI_SCAN_FLAG_PAUSE_HOME_CHANNEL 0x200000 -/** - * report CCA busy for each possible 20Mhz subbands of the wideband scan channel - */ -#define WMI_SCAN_FLAG_REPORT_CCA_BUSY_FOREACH_20MHZ 0x400000 - /** for adaptive scan mode using 3 bits (21 - 23 bits) */ #define WMI_SCAN_DWELL_MODE_MASK 0x00E00000 #define WMI_SCAN_DWELL_MODE_SHIFT 21 +/** pause home channel when scan channel is same as home channel (bit 24) */ +#define WMI_SCAN_FLAG_PAUSE_HOME_CHANNEL 0x01000000 +/** + * report CCA busy for each possible 20MHz subband of the wideband scan channel + * (bit 25) + */ +#define WMI_SCAN_FLAG_REPORT_CCA_BUSY_FOREACH_20MHZ 0x02000000 typedef enum { WMI_SCAN_DWELL_MODE_DEFAULT = 0, @@ -6381,7 +6381,11 @@ typedef enum { #define WMI_SCAN_GET_DWELL_MODE(flag) \ (((flag) & WMI_SCAN_DWELL_MODE_MASK) >> WMI_SCAN_DWELL_MODE_SHIFT) -/** WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ +/** + * WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK + * This bitmask is used to set/get values of req_type variable in + * wmi_stop_scan_cmd_fixed_param. + */ #define WMI_SCAN_CLASS_MASK 0xFF000000 /* diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 276f68699d88..2499c5435961 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1601 +#define __WMI_REVISION_ 1602 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From b84b8d517cc810863091be4ac36d3ffbeab90bca Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 17 Apr 2025 06:05:02 -0700 Subject: [PATCH 079/306] fw-api: CL 29026260 - update fw common interface files Change-Id: I82f865e2164dc8b26e02117d61542e4a4aab5f01 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 19 +++++++++++++------ fw/wmi_version.h | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 25395fe7811d..4c36d4a0d660 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -22663,14 +22663,19 @@ typedef struct { /** * btm_config.flags * BIT 0 : Enable/Disable the BTM offload. - * BIT 1-2 : Action on non matching candidate with cache. Used WMI_ROAM_BTM_OFLD_NON_MATCHING_CND_XXX + * BIT 1-2 : Action on non matching candidate with cache. + * Used WMI_ROAM_BTM_OFLD_NON_MATCHING_CND_XXX * BIT 3-5 : Roaming handoff decisions. Use WMI_ROAM_BTM_OFLD_CNDS_MATCH_XXX * BIT 6 : Enable/Disable solicited BTM - * BIT 7 : Roam BTM candidates based on the roam score instead of BTM preferred value + * BIT 7 : Roam BTM candidates based on the roam score instead of BTM + * preferred value * BIT 8 : BTM query preference over 11k neighbor report request * BIT 9 : Send BTM query with preferred candidates list - * BIT 10 : Forward MBO BTM Request to Host if MBO ASSOC RETRY attribute is set - * BIT 11-31 : Reserved + * BIT 10 : Forward MBO BTM Request to Host if MBO ASSOC RETRY attribute + * is set + * BIT 11 : Detect the missing band from BTM request when compared to + * roam scan results and consider them as valid candidate + * BIT 12-31 : Reserved */ #define WMI_ROAM_BTM_SET_ENABLE(flags, val) WMI_SET_BITS(flags, 0, 1, val) #define WMI_ROAM_BTM_GET_ENABLE(flags) WMI_GET_BITS(flags, 0, 1) @@ -22686,8 +22691,10 @@ typedef struct { #define WMI_ROAM_BTM_GET_BTM_QUERY_PREFERENCE_OVER_11K(flags) WMI_GET_BITS(flags, 8, 1) #define WMI_ROAM_BTM_SET_BTM_QUERY_WITH_CANDIDATE_LIST(flags, val) WMI_SET_BITS(flags, 9, 1, val) #define WMI_ROAM_BTM_GET_BTM_QUERY_WITH_CANDIDATE_LIST(flags) WMI_GET_BITS(flags, 9, 1) -#define WMI_ROAM_BTM_SET_FORWARD_MBO_ASSOC_RETRY_BTM_REQUEST_TO_HOST(flags, val) WMI_SET_BITS(flags, 10, 1, val) -#define WMI_ROAM_BTM_GET_FORWARD_MBO_ASSOC_RETRY_BTM_REQUEST_TO_HOST(flags) WMI_GET_BITS(flags, 10, 1) +#define WMI_ROAM_BTM_SET_FORWARD_MBO_ASSOC_RETRY_BTM_REQUEST_TO_HOST(flags, val) WMI_SET_BITS(flags, 10, 1, val) +#define WMI_ROAM_BTM_GET_FORWARD_MBO_ASSOC_RETRY_BTM_REQUEST_TO_HOST(flags) WMI_GET_BITS(flags, 10, 1) +#define WMI_ROAM_BTM_SET_DETECT_CANDIDATE_FROM_MISSING_BAND_IN_BTM_REQUEST(flags, val) WMI_SET_BITS(flags, 11, 1, val) +#define WMI_ROAM_BTM_GET_DETECT_CANDIDATE_FROM_MISSING_BAND_IN_BTM_REQUEST(flags) WMI_GET_BITS(flags, 11, 1) /** WMI_ROAM_BTM_SET_NON_MATCHING_CNDS_ACTION definition: When BTM candidate is not matched with cache by WMI_ROAM_BTM_SET_CNDS_MATCH_CONDITION, determine what to do */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 2499c5435961..a4a073d1689c 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1602 +#define __WMI_REVISION_ 1603 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 449ce43fc908f08eccb61553fc959bdfd417cda7 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 18 Apr 2025 06:01:34 -0700 Subject: [PATCH 080/306] fw-api: CL 29035093 - update fw common interface files Change-Id: I4f071048b6d7bf27ca396d0023156588d01d58ba CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 5 +++++ fw/wmi_version.h | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index c0dc42fb9865..6286a4916a78 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -699,6 +699,7 @@ typedef enum { WMI_SERVICE_CTRL_PATH_PEER_BA_STATS = 440, /* FW supports retrieving BlockAck stats through WMI_REQUEST_CTRL_PATH_PEER_STAT */ WMI_SERVICE_CTRL_PATH_STA_DAR_STATS_SUPPORT = 441, /* FW supports DAR stats reporting for STA mode */ WMI_SERVICE_APF_DATA_OFFLOAD_SUPPORT_ENABLED = 442, /* Indicates FW support for APFv6 handling offloads and disable QC data offloads */ + WMI_SERVICE_PER_VDEV_TWT_RESP_DISABLE_SUPPORT = 443, /* FW supports vdev level TWT responder disable */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 4c36d4a0d660..b099cf732b88 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -19462,6 +19462,11 @@ typedef enum { /* Allow to tear down TWT on scan start, if corresponding INI is set */ WMI_VDEV_PARAM_DISABLE_SCAN_START_TWT, /* 0xC8 */ + /* + * value 0 | default value no opp | controlled from pdev level + * value 1 | disable responder for this vdev + */ + WMI_VDEV_PARAM_TWT_RESP_DISABLE, /* 0xC9 */ /*=== ADD NEW VDEV PARAM TYPES ABOVE THIS LINE === * The below vdev param types are used for prototyping, and are diff --git a/fw/wmi_version.h b/fw/wmi_version.h index a4a073d1689c..330e4b7c442a 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1603 +#define __WMI_REVISION_ 1604 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 8c3c623afdb7c108d01275c91d132b53f9be323e Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 20 Apr 2025 06:01:22 -0700 Subject: [PATCH 081/306] fw-api: CL 29042940 - update fw common interface files Change-Id: Ic92ae1f811726d2c3307cff22365341f43c946c4 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 8 ++++++++ fw/wmi_version.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index b099cf732b88..9dc55fc54ed7 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -50204,6 +50204,14 @@ typedef struct { * in units of KB */ A_UINT32 size_kb; + /* tx_pwr: + * TX POWER of ANN PBT INFERENCING PKT (dBm units) + */ + A_INT32 tx_pwr; + /* tx_chain_idx: + * CHAIN INDEX where WMI is sent to HOST to start inferencing + */ + A_UINT32 tx_chain_idx; } wmi_pdev_power_boost_event_fixed_param; typedef enum { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 330e4b7c442a..5b1a1745a55f 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1604 +#define __WMI_REVISION_ 1605 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 8a055950fd9a04db260d6b089d9e49b5c4a16cfb Mon Sep 17 00:00:00 2001 From: Agnimitra Sen Date: Thu, 10 Apr 2025 16:16:35 +0530 Subject: [PATCH 082/306] msm: vidc: Enable hybrid mode only for HFR usecase Dynamic properties such as IDR insertion is not supported when hybrid layers are enabled . Hybrid layers required only HFR usecase. Hence enabling hybrid only when VBR+noLTR+HFR use cases. Change-Id: I36e4ecb9c98135790cff0487a237a1a4fd33d241 --- msm/vidc/msm_venc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/msm/vidc/msm_venc.c b/msm/vidc/msm_venc.c index 25a282e5aa4a..f95639e02465 100644 --- a/msm/vidc/msm_venc.c +++ b/msm/vidc/msm_venc.c @@ -3710,6 +3710,9 @@ int msm_venc_enable_hybrid_hp(struct msm_vidc_inst *inst) if (ctrl->val) return 0; + if (msm_vidc_get_fps(inst) <= 60) + return 0; + ctrl = get_ctrl(inst, V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER); layer = get_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER); From 90f5b1c30a0a376efc5a35d816618c48fea0f9b9 Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Fri, 3 Jan 2025 17:04:10 +0530 Subject: [PATCH 083/306] msm: mhi_dev: Workqueue to handle host wakeup in M3+D0 After the change ("msm: mhi_dev: Handle host wakeup in M3/D0"), if a wakeup host request is received during M3+D0, wait for D3 hot/cold before sending the host wakeup request inside a mutex lock. Regression: In mhi_sm_dev_event_manager, the mhi_sm_ctx->mhi_state_lock mutex is held while calling mhi_sm_wakeup_host. This means waiting for mhi_sm_ctx->d_state to transition to MHI_SM_EP_PCIE_D3_HOT_STATE or MHI_SM_EP_PCIE_D3_COLD_STATE with the lock held. This prevents mhi_sm_pcie_event_manager from processing the D3 hot/cold event because it also waits for the same lock. Create a separate workqueue to wait for D3 hot/cold before waking up the host if a wakeup request is received in M3+D0. Change-Id: I1d3eff63b1968f5ded0d0c84a0fa71e893d74d45 Signed-off-by: Sumit Kumar --- drivers/platform/msm/mhi_dev/mhi_sm.c | 118 +++++++++++++++++--------- drivers/platform/msm/mhi_dev/mhi_sm.h | 1 - 2 files changed, 77 insertions(+), 42 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.c b/drivers/platform/msm/mhi_dev/mhi_sm.c index ba8c9a19136e..e8d9300c7812 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.c +++ b/drivers/platform/msm/mhi_dev/mhi_sm.c @@ -32,6 +32,8 @@ /* Maximum wait time for D state transitions to D3hot */ #define M3_DO_WAKEUP_TIMEOUT_MS 2500 +static void wait_d3_and_wakeup(struct work_struct *work); +static int mhi_dev_sm_get_mhi_pcie_states(uint32_t *mstate, uint32_t *dstate); static inline const char *mhi_sm_dev_event_str(enum mhi_dev_event state) { @@ -238,6 +240,8 @@ struct mhi_sm_dev { struct mutex mhi_state_lock; bool syserr_occurred; struct workqueue_struct *mhi_sm_wq; + struct workqueue_struct *mhi_wake_wq; + struct work_struct mhi_wake_work; atomic_t pending_device_events; atomic_t pending_pcie_events; struct mhi_sm_stats stats; @@ -742,10 +746,9 @@ exit: * Return: 0:success * negative: failure */ -static int mhi_sm_wakeup_host(enum mhi_dev_event event) +static int mhi_sm_wakeup_host(void) { int res = 0; - int timeout = 0; enum ep_pcie_event pcie_event; MHI_SM_FUNC_ENTRY(); @@ -757,33 +760,10 @@ static int mhi_sm_wakeup_host(enum mhi_dev_event event) MHI_SM_ERR("Failed switching to M0 state\n"); } else if (mhi_sm_ctx->mhi_state == MHI_DEV_M3_STATE) { /* - * Handle host wakeup in M3 + D0 states. - * - * When a MHI WAKE request is received while device is in D0, - * wait for D3 and wakeup the host using inband PME. - * If the MHI state changes to M0 while waiting for D3, - * exit, since both MHI and the device are in active state. + * Check and send D3_HOT to enable waking up the host + * using inband PME if the host is in D3_HOT state, otherwise + * send D3_COLD to wake up the host. */ - if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D0_STATE) { - timeout = ktime_add_ms(ktime_get(), M3_DO_WAKEUP_TIMEOUT_MS); - while (1) { - /* Received M0 */ - if (mhi_sm_ctx->mhi_state == MHI_DEV_M0_STATE) - goto exit; - /* Received D3 state */ - if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_HOT_STATE || - mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_COLD_STATE) - goto wakeup_host; - if (ktime_after(ktime_get(), timeout)) { - MHI_SM_ERR(mhi->vf_id, - "M3, D0 wakeup host is not supported %d\n", res); - goto exit; - } - usleep_range(1000, 2000); - } - } -wakeup_host: - /* Received D3hot or D3cold, send the wakeup request */ if (mhi_sm_ctx->d_state == MHI_SM_EP_PCIE_D3_HOT_STATE) pcie_event = EP_PCIE_EVENT_PM_D3_HOT; else @@ -934,9 +914,7 @@ static void mhi_sm_dev_event_manager(struct work_struct *work) break; case MHI_DEV_EVENT_HW_ACC_WAKEUP: case MHI_DEV_EVENT_CORE_WAKEUP: - res = mhi_sm_wakeup_host(chg_event->event); - if (res) - MHI_SM_ERR("Failed to wakeup MHI host\n"); + queue_work(mhi_sm_ctx->mhi_wake_wq, &mhi_sm_ctx->mhi_wake_work); break; case MHI_DEV_EVENT_CTRL_TRIG: case MHI_DEV_EVENT_M1_STATE: @@ -1147,9 +1125,19 @@ int mhi_dev_sm_init(struct mhi_dev *mhi_dev) if (!mhi_sm_ctx->mhi_sm_wq) { MHI_SM_ERR("Failed to create singlethread_workqueue: sm_wq\n"); res = -ENOMEM; - goto fail_init_wq; + goto fail_init_sm_wq; } + if (!mhi_sm_ctx->mhi_wake_wq) + mhi_sm_ctx->mhi_wake_wq = alloc_workqueue( + "mhi_wake_wq", WQ_HIGHPRI | WQ_UNBOUND, 1); + if (!mhi_sm_ctx->mhi_wake_wq) { + MHI_SM_ERR("Failed to create singlethread_workqueue: wake_wq\n"); + res = -ENOMEM; + goto fail_init_wake_wq; + } + INIT_WORK(&mhi_sm_ctx->mhi_wake_work, wait_d3_and_wakeup); + mutex_init(&mhi_sm_ctx->mhi_state_lock); mhi_sm_ctx->mhi_dev = mhi_dev; mhi_sm_ctx->mhi_state = MHI_DEV_RESET_STATE; @@ -1162,7 +1150,10 @@ int mhi_dev_sm_init(struct mhi_dev *mhi_dev) MHI_SM_FUNC_EXIT(); return 0; -fail_init_wq: +fail_init_wake_wq: + flush_workqueue(mhi_sm_ctx->mhi_sm_wq); + destroy_workqueue(mhi_sm_ctx->mhi_sm_wq); +fail_init_sm_wq: mhi_sm_ctx = NULL; mhi_sm_debugfs_destroy(); return res; @@ -1190,20 +1181,20 @@ int mhi_dev_sm_exit(struct mhi_dev *mhi_dev) EXPORT_SYMBOL(mhi_dev_sm_exit); /** - * mhi_dev_sm_get_mhi_state() -Get current MHI state. + * mhi_dev_sm_get_mhi_pcie_states() -Get current MHI and Pcie states. * @state: return param * - * Returns the current MHI state of the state machine. + * Returns the current MHI and PCIe states of the state machine. * * Return: 0 success * -EINVAL: invalid param * -EFAULT: state machine isn't initialized */ -int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state) +static int mhi_dev_sm_get_mhi_pcie_states(uint32_t *mstate, uint32_t *dstate) { MHI_SM_FUNC_ENTRY(); - if (!state) { + if (!mstate || !dstate) { MHI_SM_ERR("Fail: Null argument\n"); return -EINVAL; } @@ -1211,15 +1202,60 @@ int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state) MHI_SM_ERR("Fail: MHI SM is not initialized\n"); return -EFAULT; } - *state = mhi_sm_ctx->mhi_state; + mutex_lock(&mhi_sm_ctx->mhi_state_lock); + *mstate = mhi_sm_ctx->mhi_state; + *dstate = mhi_sm_ctx->d_state; + mutex_unlock(&mhi_sm_ctx->mhi_state_lock); MHI_SM_DBG("state machine states are: %s and %s\n", - mhi_sm_mstate_str(*state), - mhi_sm_dstate_str(mhi_sm_ctx->d_state)); + mhi_sm_mstate_str(*mstate), + mhi_sm_dstate_str(*dstate)); MHI_SM_FUNC_EXIT(); return 0; } -EXPORT_SYMBOL(mhi_dev_sm_get_mhi_state); + +static void wait_d3_and_wakeup(struct work_struct *work) +{ + struct mhi_sm_dev *mhi_sm_ctx = container_of(work, struct mhi_sm_dev, mhi_wake_work); + enum mhi_dev_state mstate; + enum mhi_sm_ep_pcie_state dstate; + ktime_t timeout = 0; + + if (mhi_dev_sm_get_mhi_pcie_states(&mstate, &dstate)) { + MHI_SM_ERR("Unable to read states\n"); + return; + } + /* + * Handle host wakeup in M3 + D0 states. + * When a MHI WAKE request is received while device is in D0, + * wait for D3 and wakeup the host using inband PME. + * If the MHI state changes to M0 while waiting for D3, + * exit, since both MHI and the device are in active state + */ + if (dstate == MHI_SM_EP_PCIE_D0_STATE) { + timeout = ktime_add_ms(ktime_get(), M3_DO_WAKEUP_TIMEOUT_MS); + while (1) { + mhi_dev_sm_get_mhi_pcie_states(&mstate, &dstate); + if (mstate == MHI_DEV_M0_STATE) { + MHI_SM_DBG("M0 state received\n"); + return; + } + if (dstate == MHI_SM_EP_PCIE_D3_HOT_STATE || + dstate == MHI_SM_EP_PCIE_D3_COLD_STATE) { + MHI_SM_DBG("D3 state received\n"); + goto send_host_wakeup; + } + if (ktime_after(ktime_get(), timeout)) { + MHI_SM_ERR("Neither received D3 nor M0 in stipulated time\n"); + return; + } + usleep_range(1000, 2000); + } + } +send_host_wakeup: + if (dstate == MHI_SM_EP_PCIE_D3_HOT_STATE || dstate == MHI_SM_EP_PCIE_D3_COLD_STATE) + mhi_sm_wakeup_host(); +} /** * mhi_dev_sm_set_ready() -Set MHI state to ready. diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h index 80ed0086472f..24e6daf46777 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.h +++ b/drivers/platform/msm/mhi_dev/mhi_sm.h @@ -42,7 +42,6 @@ int mhi_dev_sm_init(struct mhi_dev *dev); int mhi_dev_sm_exit(struct mhi_dev *dev); int mhi_dev_sm_set_ready(void); int mhi_dev_notify_sm_event(enum mhi_dev_event event); -int mhi_dev_sm_get_mhi_state(enum mhi_dev_state *state); int mhi_dev_sm_syserr(void); void mhi_dev_sm_pcie_handler(struct ep_pcie_notify *notify); From e860e837bd4dc2c691f1a1dc7338a241205f2ed7 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 26 Apr 2025 06:01:26 -0700 Subject: [PATCH 084/306] fw-api: CL 29072944 - update fw common interface files Change-Id: I9190e4197fa87253d183627b8cb2af7c74e29cd7 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 4 ++++ fw/wmi_version.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 9dc55fc54ed7..7e58c62dd12b 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -50212,6 +50212,8 @@ typedef struct { * CHAIN INDEX where WMI is sent to HOST to start inferencing */ A_UINT32 tx_chain_idx; + /* req_id: to distinguish pdev_power_boost event instances */ + A_UINT32 req_id; } wmi_pdev_power_boost_event_fixed_param; typedef enum { @@ -50264,6 +50266,8 @@ typedef struct { * training, in units of 1/4 (0.25dBm) steps. */ A_INT32 tx_mask_margin; + /* req_id: to distinguish pdev_power_boost cmd instances */ + A_UINT32 req_id; } wmi_pdev_power_boost_cmd_fixed_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 5b1a1745a55f..c3a9ec3d78bb 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1605 +#define __WMI_REVISION_ 1606 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 7110894453cf3a3d06c689f1503b93837753e7a3 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 1 May 2025 06:01:24 -0700 Subject: [PATCH 085/306] fw-api: CL 29115376 - update fw common interface files Change-Id: I9d8a211daaf3784946e2865934e57adf2072d505 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 7e58c62dd12b..00a83bd1f9a6 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -24782,6 +24782,8 @@ typedef enum wake_reason_e { WOW_REASON_C2C_DETECT_EVENT, /* wake up the host in case of TDLS packet reception */ WOW_REASON_TDLS_PACKET_RX, + /* wake up the host when USD is enabled */ + WOW_REASON_USD, /* add new WOW_REASON_ defs before this line */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index c3a9ec3d78bb..ac710339859e 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1606 +#define __WMI_REVISION_ 1607 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From bb7015eb285429ba62d8358d281e42fce3ec539d Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 2 May 2025 06:01:28 -0700 Subject: [PATCH 086/306] fw-api: CL 29126604 - update fw common interface files Change-Id: Ief26d2d7399a228f0bd3f729a7d86f3fa5a75319 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 12 ++++++++++++ fw/wmi_version.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 00a83bd1f9a6..8d37a6479e08 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -42802,6 +42802,18 @@ typedef enum { */ WMI_ROAM_PARAM_ROAM_LATENCY_OPTIMIZATION_BITMAP = 11, + /* + * Roam param to add RSSI penalty for non-6GHz Candidate AP + * during Roam Scan in case current connected AP is 6GHz and + * cand AP is non-6GHz. + * This RSSI penalty value (in dB units) for non-6GHz candidate AP + * will be configured via ini roam_rssi_delta_from_6ghz_to_non_6ghz. + * This configured RSSI penalty value will only be applicable for non-6GHz + * Candidate AP when the STA is connected to 6GHz Band AP and will + * not impact if STA is connected to non-6GHz Band AP + */ + WMI_ROAM_PARAM_ROAM_RSSI_PENALTY_FOR_NON_6GHZ_CAND_AP = 12, + /*=== END ROAM_PARAM_PROTOTYPE SECTION ===*/ } WMI_ROAM_PARAM; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index ac710339859e..473c9316c2a3 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1607 +#define __WMI_REVISION_ 1608 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 95cae124f2d96e55b0af317f90ff68d292490660 Mon Sep 17 00:00:00 2001 From: Prahlad Valluru Date: Thu, 8 May 2025 12:08:42 +0530 Subject: [PATCH 087/306] disp: msm: dp: handle panel_init when host is ready Currently, panel_init is getting executed even when host is already ready. Handle panel_init such that it will be called only as part of host ready. Handle continuous splash case as well. Change-Id: Id022fed099e1e1a87282c58bead839e68f502098 Signed-off-by: Nilesh Laad Signed-off-by: Prahlad Valluru --- msm/dp/dp_display.c | 9 ++++++--- msm/dp/dp_panel.c | 7 +++++-- msm/dp/dp_panel.h | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 788c43d1da2e..2655f9d236d7 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023-2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. */ @@ -1185,6 +1185,7 @@ error_ctrl: static int dp_display_panel_ready(struct dp_display_private *dp) { int rc = 0; + bool skip_op = is_skip_required(&dp->dp_display); if (dp->dp_display.is_edp) { rc = dp->power->edp_panel_set_gpio(dp->power, DP_GPIO_EDP_VCC_EN, true); @@ -1202,9 +1203,9 @@ static int dp_display_panel_ready(struct dp_display_private *dp) } return -ETIMEDOUT; } + + dp->panel->init(dp->panel, skip_op); } - if (!dp->dp_display.cont_splash_enabled) - dp->panel->init(dp->panel); return 0; } @@ -1248,6 +1249,8 @@ static int dp_display_host_ready(struct dp_display_private *dp) dp->ctrl->abort(dp->ctrl, false); dp->aux->init(dp->aux, dp->parser->aux_cfg, skip_op); + dp->panel->init(dp->panel, skip_op); + dp_display_state_add(DP_STATE_READY); /* log this as it results from user action of cable connection */ DP_INFO("[OK]\n"); diff --git a/msm/dp/dp_panel.c b/msm/dp/dp_panel.c index 8fc1b13c3e32..a9f65f1aba8c 100644 --- a/msm/dp/dp_panel.c +++ b/msm/dp/dp_panel.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ @@ -2381,7 +2381,7 @@ error: return rc; } -static int dp_panel_init_panel_info(struct dp_panel *dp_panel) +static int dp_panel_init_panel_info(struct dp_panel *dp_panel, bool skip_op) { int rc = 0; struct dp_panel_private *panel; @@ -2393,6 +2393,9 @@ static int dp_panel_init_panel_info(struct dp_panel *dp_panel) goto end; } + if (skip_op) + goto end; + panel = container_of(dp_panel, struct dp_panel_private, dp_panel); pinfo = &dp_panel->pinfo; diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index 3abb41297584..206b62dc32c7 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved. */ @@ -162,7 +162,7 @@ struct dp_panel { s64 fec_overhead_fp; - int (*init)(struct dp_panel *dp_panel); + int (*init)(struct dp_panel *dp_panel, bool skip_op); int (*deinit)(struct dp_panel *dp_panel, u32 flags); int (*hw_cfg)(struct dp_panel *dp_panel, bool enable); int (*read_sink_caps)(struct dp_panel *dp_panel, From b749468a5add48e9f20fd3913dbae9243e2bb035 Mon Sep 17 00:00:00 2001 From: Gopi Botlagunta Date: Thu, 17 Apr 2025 18:23:49 +0530 Subject: [PATCH 088/306] disp: msm: sde: get_modes from connector if not present In case of external bridges, modes are not available for setting splash_mode. Add support to get modes supported by the external bridges. Change-Id: Ib17e17bcf1ec91b582da2e0cf5d648b9c366b292 Signed-off-by: Gopi Botlagunta --- msm/sde/sde_kms.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 43c436d6ba3a..7dfad7d8d194 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -3489,11 +3489,20 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms, mutex_unlock(&dev->mode_config.mutex); return -EINVAL; } - mutex_unlock(&dev->mode_config.mutex); crtc->state->encoder_mask = (1 << drm_encoder_index(encoder)); + /* get supported modes in case of external bridge panels*/ + if (!dsi_display->panel->num_timing_nodes) { + connector->funcs->fill_modes(connector, + dev->mode_config.max_width, + dev->mode_config.max_height); + drm_mode = list_first_entry(&connector->modes, + struct drm_display_mode, head); + } + else + drm_mode = _sde_kms_get_splash_mode(sde_kms, connector, state); - drm_mode = _sde_kms_get_splash_mode(sde_kms, connector, state); + mutex_unlock(&dev->mode_config.mutex); if (!drm_mode) { SDE_ERROR("drm_mode not found; handoff_type:%d\n", sde_kms->splash_data.type); From 57c036dc583383282f4281252bfa35330e704517 Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 5 May 2025 06:01:31 -0700 Subject: [PATCH 089/306] fw-api: CL 29137988 - update fw common interface files Change-Id: I0413cfce91b98e6041a1c664eada02cb8533c56d CRs-Fixed: 3830439 --- fw/htt_stats.h | 10 +- fw/wmi_unified.h | 508 ++++++++++++++++++++++++++--------------------- fw/wmi_version.h | 2 +- 3 files changed, 293 insertions(+), 227 deletions(-) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 0a52c1911062..cde4e1d5d72f 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -1902,6 +1902,8 @@ typedef struct _htt_tx_tid_stats_v1_tlv { */ A_UINT32 head_msdu_tqm_timestamp_us; A_UINT32 head_msdu_tqm_latency_us; + A_UINT32 pause_module_id_ext; + A_UINT32 block_module_id_ext; } htt_stats_tx_tid_details_v1_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_tid_details_v1_tlv htt_tx_tid_stats_v1_tlv; @@ -1974,9 +1976,9 @@ typedef struct { A_UINT32 mpdu_cnt; /** Number of rx MSDU */ A_UINT32 msdu_cnt; - /** pause bitmap */ + /** lower 32 bits of pause bitmap */ A_UINT32 pause_bitmap; - /** block bitmap */ + /** lower 32 bits of block bitmap */ A_UINT32 block_bitmap; /** current timestamp */ A_UINT32 current_timestamp; @@ -2006,6 +2008,10 @@ typedef struct { A_UINT32 inactive_time; /** Number of MPDUs dropped after max retries */ A_UINT32 remove_mpdus_max_retries; + /** extension with upper 32 bits of pause bitmap */ + A_UINT32 pause_bitmap_ext; + /** extension with upper 32 bits of block bitmap */ + A_UINT32 block_bitmap_ext; } htt_stats_peer_stats_cmn_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_peer_stats_cmn_tlv htt_peer_stats_cmn_tlv; diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 8d37a6479e08..db6c46ef24dc 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -12779,224 +12779,240 @@ typedef struct { * number of vdev active count * (WMI_PDEV_STATS_VDEV_UP_CNT_SET,GET) */ - A_UINT32 opaque_debug_num_macs_phy_vdev_up_active; - /** refer wlan_pdev ic flags */ - A_UINT32 opaque_debug_ic_flags; - /** vdev_id that are paused per pdev */ - A_UINT32 opaque_debug_paused_ap_vdev_bitmap; - /** opaque_debug_flags: - * refer to WLAN_PS_DESC_BIN_HWM_HIT or WLAN_PS_DESC_BIN_LWM_HIT - */ - A_UINT32 opaque_debug_flags; - /** wlan_pdev fields remote_peer_cnt, max_rf_chains_2G and max_rf_chains_5G - * remote_peer_cnt_max_rf_chains_2G_5G: - * This word contains the following bitfields: - * max chains supported in the 2.4 GHz band - * (WMI_PDEV_STATS_MAX_RF_CHAIN_2G_SET,GET) - * max chains supported in the 5 GHz band, - * (WMI_PDEV_STATS_MAX_RF_CHAIN_5G_SET,GET) - * number of remote peers - * (WMI_PDEV_STATS_REMOTE_PEER_CNT_SET,GET) - */ - A_UINT32 opaque_debug_remote_peer_cnt_max_rf_chains_2G_5G; - /** wlan_pdev max HT Capability info, WMI_HT_CAP defines */ - A_UINT32 opaque_debug_max_ht_cap_info; - /** wlan_pdev max VHT capability info, WMI_VHT_CAP defines */ - A_UINT32 opaque_debug_max_vht_cap_info; - /** opaque_debug_max_vht_supp_mcs: - * wlan_pdev max VHT Supported MCS which is - * vht_supp_mcs_2G or vht_supp_mcs_5G - */ - A_UINT32 opaque_debug_max_vht_supp_mcs; - /** wlan_pdev max HE capability info, WMI_HE_CAP defines */ - A_UINT32 opaque_debug_max_he_cap_info; - A_UINT32 opaque_debug_max_he_cap_info_ext; - /** the nominal chain mask for transmit */ - A_UINT32 opaque_debug_tx_chain_mask; - /** the nominal chain mask for receive */ - A_UINT32 opaque_debug_rx_chain_mask; - /** opaque_debug_ema_flags: - * This word contains the following bitfields: - * ema_flags: ema_max_vap_cnt and ema_max_profile_period from wlan_pdev - * ema_max_vap_cnt- number of maximum EMA Tx vaps (VAPs having both - * VDEV_FLAGS_EMA_MODE and VDEV_FLAGS_TRANSMIT_AP set) - * (WMI_PDEV_STATS_EMA_MAX_VAP_CNT_SET,GET) - * ema_max_profile_period - maximum profile periodicity - * (maximum number of beacons after which VAP profiles repeat) - * for any EMA VAP on any pdev. - * (WMI_PDEV_STATS_EMA_MAX_PROFILE_PERIOD_SET,GET) - */ - A_UINT32 opaque_debug_ema_flags; - /** wlan_pdev - maximum ML peers supported */ - A_UINT32 opaque_debug_num_ml_peer_entries; - /** This word contains the following bitfields: - * wlan_pdev fields - num_max_hw_links, current_chip_id and max_num_chips - * (related to MLO) - * Max number of HW links - * (WMI_PDEV_STATS_NUM_MAX_HW_LINKS_SET,GET) - * Current Chip Id - * (WMI_PDEV_STATS_CURRENT_CHIP_ID_SET,GET) - * Max number of chips - * (WMI_PDEV_STATS_MAX_NUM_CHIPS_SET,GET) - */ - A_UINT32 opaque_debug_mlo_flags; - /** Indicate beacon size in bytes */ - A_UINT32 opaque_debug_large_bcn_size; - /** proposed by the host value of MSDUQs per each LinkView peer's TID */ - A_UINT32 opaque_debug_num_of_linkview_msduqs_per_tid; - /** bcn_filter_context variables */ - A_UINT32 opaque_debug_bcns_dropped; - A_UINT32 opaque_debug_bcns_recvd; - A_UINT32 opaque_debug_bcns_delivered; - /** Tids that are paused/unpaused based on module_id */ - A_UINT32 opaque_debug_vdev_all_tid_pause_bitmap; - /** Tids that are blocked/unblocked based on module_id */ - A_UINT32 opaque_debug_vdev_all_tid_block_bitmap; - /** wal_pdev rx filter, WAL_RX_FILTER_FLAGS defines */ - A_UINT32 opaque_debug_rx_filter; - /** This word contains the following bitfields: - * aggr_nonaggr_retry_th: - * wal_pdev fields - agg_retry_th and non_agg_retry_th - * This value holds max retry threshold up to which a Data packet - * will be retried when ack is not received. - * agg_retry_th - Threshold value used when aggregation is enabled - * (WMI_PDEV_STATS_AGG_RETRY_TH_SET,GET) - * non_agg_retry_th - Threshold value used for non-aggregation. - * (WMI_PDEV_STATS_NON_AGG_RETRY_TH_SET) - */ - A_UINT32 opaque_debug_aggr_nonaggr_retry_th; - /** This word contains the following bitfields: - * num_max_rx_ba_sessions: - * Number of rx BA session establised - * (WMI_PDEV_STATS_NUM_RX_BA_SESSIONS_SET,GET) - * Max number of rx BA session from wal_pdev - * (WMI_PDEV_STATS_MAX_RX_BA_SESSIONS_SET,GET) - */ - A_UINT32 opaque_debug_num_max_rx_ba_sessions; - /** It holds WHAL_CHANNEL_SWITCH_FLAGS values */ - A_UINT32 opaque_debug_chan_switch_flags; - /** reset_cause holds PDEV_RESET_CONSEC_FAILURE or PDEV_RESET_TXQ_TIMEOUT */ - A_UINT32 opaque_debug_consecutive_failure_reset_cause; - /** PPDU duration limit, in us */ - A_UINT32 opaque_debug_mu_ppdu_dur_limit_us; - /** pdev reset in progress */ - A_UINT32 opaque_debug_reset_in_progress; - /** wal_dev - vdev_migrate_state refer to WAL_VDEV_MIGRATE_STATE */ - A_UINT32 opaque_debug_vdev_migrate_state; - /** opaque_debug_rts_rc_flag: - * wal_pdev rts ratecode - this value reflects whatever - * WMI_PDEV_PARAM_RTS_FIXED_RATE value the host has specified for the pdev. - */ - A_UINT32 opaque_debug_rts_rc_flag; - /* Num of peer delete in progress */ - A_UINT32 opaque_debug_num_of_peer_delete_in_progress; - /** wal_pdev total number of active vdev count */ - A_UINT32 opaque_debug_total_active_vdev_cnt; - /** wal_pdev - max number of vdevs per pdev */ - A_UINT32 opaque_debug_max_vdevs; - /* NonOccupancyList(NOL) context */ - A_UINT32 opaque_debug_dfs_nol_count; - /** NOL timeout in seconds */ - A_UINT32 opaque_debug_dfs_nol_timeout; - A_UINT32 opaque_debug_dfs_use_nol; - /** channel availability check mode, refer enum WMI_ADFS_OCAC_MODE */ - A_UINT32 opaque_debug_cac_mode; - A_UINT32 opaque_debug_dyn_ppdu_dur; /* in ms */ - /** This word contains the following bitfields: - * wal_pdev home channel info - * home_chan_mhz_flags: - * primary channel frequency in mhz - * (WMI_PDEV_STATS_HOME_CHAN_MHZ_SET,GET) - * flags to specify other channel attributes - * (WMI_PDEV_STATS_HOME_CHAN_FLAGS_SET, GET) - */ - A_UINT32 opaque_debug_home_chan_mhz_flags; - /** home channel center frequency in MHz */ - A_UINT32 opaque_debug_home_band_center_freq; - /** home channel phy_mode, refer enum WLAN_PHY_MODE */ - A_UINT32 opaque_debug_home_phy_mode; - /** This word contains the following bitfields: - * wal_pdev current channel info - * cur_chan_mhz_flags: - * primary channel frequency in mhz - * (WMI_PDEV_STATS_CUR_CHAN_MHZ_SET,GET) - * flags to specify other channel attributes - * (WMI_PDEV_STATS_CUR_CHAN_FLAGS_SET,GET) - */ - A_UINT32 opaque_debug_cur_chan_mhz_flags; - /** current channel center frequency in MHz */ - A_UINT32 opaque_debug_cur_band_center_freq; - /** current channel phy_mode, refer enum WLAN_PHY_MODE */ - A_UINT32 opaque_debug_cur_phy_mode; - /* Beacon context info */ - A_UINT32 opaque_debug_bcn_q_num_bcns_queued_to_hw; - /** beacon queue AIFS */ - A_UINT32 opaque_debug_aifs; - /** beacon queue cwmin */ - A_UINT32 opaque_debug_cwmin; - /** beacon queue cwmax */ - A_UINT32 opaque_debug_cwmax; - /** FILS discovery period in TU */ - A_UINT32 opaque_debug_fils_period; - /** Beacon interval in TU */ - A_UINT32 opaque_debug_beacon_period; - A_UINT32 opaque_debug_staggered_beacon_intvl; - /** wal_pdev tx context, refer enum WAL_TX_CTXT_FLAGS */ - A_UINT32 opaque_debug_tx_ctxt_flags; - /** opaque_debug_burst_mode_pending_isr - * wal_pdev tx_ctxt fields - burst_mode refer enum WAL_TX_BURST_MODE - * and pending_isr_status count - */ - A_UINT32 opaque_debug_burst_mode_pending_isr; - /** max burst duration from ppdu duration in us */ - A_UINT32 opaque_debug_burst_dur; - /** counter for tx hw stuck */ - A_UINT32 opaque_debug_tx_hw_stuck_cnt; - /** counter for tx consecutive lifetime expiry */ - A_UINT32 opaque_debug_consecutive_lifetime_expiries; - /** wal_pdev rx context, refer enum WAL_RX_CTXT_FLAGS */ - A_UINT32 opaque_debug_rx_ctxt_flags; - /** wal_pdev fields in rx context for rx_suspend or resume count */ - A_UINT32 opaque_debug_rx_suspend_cnt; - A_UINT32 opaque_debug_rx_resume_cnt; - A_UINT32 opaque_debug_rx_pcie_suspend_cnt; - A_UINT32 opaque_debug_rx_pcie_resume_cnt; - /** This word contains the following bitfields: - * wal_pdev fields - * pdev paused - WMI_PDEV_STATS_PAUSED_SET,GET - * pdev suspend - WMI_PDEV_STATS_SUSPENDED_SET,GET - * cac_enabed - MI_PDEV_STATS_CAC_ENABLED_SET,GET - * monitor VAP present - WMI_PDEV_STATS_IS_MONITOR_TYPE_PRESENT_SET,GET - * beacon tx mode - WMI_PDEV_STATS_BCN_TX_MODE_SET,GET - * isTXsuspended - WMI_PDEV_STATS_IS_TXSUSPENDED_SET,GET - * isSCHEDsuspended - WMI_PDEV_STATS_IS_SCHEDSUSPENDED_SET,GET - * sched_algo_resume_needed - - * WMI_PDEV_STATS_SCHED_ALGO_RESUME_NEEDED_SET,GET - * abort_reason - WMI_PDEV_STATS_ABORT_REASON_SET,GET - * atf_cfg - WMI_PDEV_STATS_ATF_CONFIG_SET,GET - * Green AP TX chainmask valid - WMI_PDEV_STATS_GAP_TX_CH_MASK_VALID_SET,GET - * Green AP RX chainmask valid - WMI_PDEV_STATS_GAP_RX_CH_MASK_VALID_SET,GET - * Green AP Phy mode valid - WMI_PDEV_STATS_GAP_PHY_MODE_VALID_SET,GET - * burst_enable - WMI_PDEV_STATS_BURST_ENABLE_SET,GET - */ - A_UINT32 opaque_debug_wal_pdev_bitfield; - /** This word contains the following bitfields: - * gap_phy_mode_freq: - * When GreenAP is enabled, phy_mode (WMI_PDEV_STATS_GAP_PHY_MODE_SET,GET) - * and center freq(MHz) (WMI_PDEV_STATS_GAP_BAND_CENTER_FREQ1_SET,GET) - * in GAP context is displayed - */ - A_UINT32 opaque_debug_gap_phy_mode_freq; - /** - * The following 5 opaque_debug_reserved_field variables are provided - * purely for debugging by technicians who have outside knowledge of - * what kind of values the target has placed into these fields. - */ - A_UINT32 opaque_debug_reserved_field_1; - A_UINT32 opaque_debug_reserved_field_2; - A_UINT32 opaque_debug_reserved_field_3; - A_UINT32 opaque_debug_reserved_field_4; - A_UINT32 opaque_debug_reserved_field_5; + A_UINT32 opaque_debug_num_macs_phy_vdev_up_active; + /** refer wlan_pdev ic flags */ + A_UINT32 opaque_debug_ic_flags; + /** vdev_id that are paused per pdev */ + A_UINT32 opaque_debug_paused_ap_vdev_bitmap; + /** opaque_debug_flags: + * refer to WLAN_PS_DESC_BIN_HWM_HIT or WLAN_PS_DESC_BIN_LWM_HIT + */ + A_UINT32 opaque_debug_flags; + /** wlan_pdev fields remote_peer_cnt, max_rf_chains_2G and max_rf_chains_5G + * remote_peer_cnt_max_rf_chains_2G_5G: + * This word contains the following bitfields: + * max chains supported in the 2.4 GHz band + * (WMI_PDEV_STATS_MAX_RF_CHAIN_2G_SET,GET) + * max chains supported in the 5 GHz band, + * (WMI_PDEV_STATS_MAX_RF_CHAIN_5G_SET,GET) + * number of remote peers + * (WMI_PDEV_STATS_REMOTE_PEER_CNT_SET,GET) + */ + A_UINT32 opaque_debug_remote_peer_cnt_max_rf_chains_2G_5G; + /** wlan_pdev max HT Capability info, WMI_HT_CAP defines */ + A_UINT32 opaque_debug_max_ht_cap_info; + /** wlan_pdev max VHT capability info, WMI_VHT_CAP defines */ + A_UINT32 opaque_debug_max_vht_cap_info; + /** opaque_debug_max_vht_supp_mcs: + * wlan_pdev max VHT Supported MCS which is + * vht_supp_mcs_2G or vht_supp_mcs_5G + */ + A_UINT32 opaque_debug_max_vht_supp_mcs; + /** wlan_pdev max HE capability info, WMI_HE_CAP defines */ + A_UINT32 opaque_debug_max_he_cap_info; + A_UINT32 opaque_debug_max_he_cap_info_ext; + /** the nominal chain mask for transmit */ + A_UINT32 opaque_debug_tx_chain_mask; + /** the nominal chain mask for receive */ + A_UINT32 opaque_debug_rx_chain_mask; + /** opaque_debug_ema_flags: + * This word contains the following bitfields: + * ema_flags: ema_max_vap_cnt and ema_max_profile_period from wlan_pdev + * ema_max_vap_cnt- number of maximum EMA Tx vaps (VAPs having both + * VDEV_FLAGS_EMA_MODE and VDEV_FLAGS_TRANSMIT_AP set) + * (WMI_PDEV_STATS_EMA_MAX_VAP_CNT_SET,GET) + * ema_max_profile_period - maximum profile periodicity + * (maximum number of beacons after which VAP profiles repeat) + * for any EMA VAP on any pdev. + * (WMI_PDEV_STATS_EMA_MAX_PROFILE_PERIOD_SET,GET) + */ + A_UINT32 opaque_debug_ema_flags; + /** wlan_pdev - maximum ML peers supported */ + A_UINT32 opaque_debug_num_ml_peer_entries; + /** This word contains the following bitfields: + * wlan_pdev fields - num_max_hw_links, current_chip_id and max_num_chips + * (related to MLO) + * Max number of HW links + * (WMI_PDEV_STATS_NUM_MAX_HW_LINKS_SET,GET) + * Current Chip Id + * (WMI_PDEV_STATS_CURRENT_CHIP_ID_SET,GET) + * Max number of chips + * (WMI_PDEV_STATS_MAX_NUM_CHIPS_SET,GET) + */ + A_UINT32 opaque_debug_mlo_flags; + /** Indicate beacon size in bytes */ + A_UINT32 opaque_debug_large_bcn_size; + /** proposed by the host value of MSDUQs per each LinkView peer's TID */ + A_UINT32 opaque_debug_num_of_linkview_msduqs_per_tid; + /** bcn_filter_context variables */ + A_UINT32 opaque_debug_bcns_dropped; + A_UINT32 opaque_debug_bcns_recvd; + A_UINT32 opaque_debug_bcns_delivered; + /** + * Lower 32 bits bitmap of pause ids for TIDs that are paused/unpaused + * based on module_id. + */ + A_UINT32 opaque_debug_vdev_all_tid_pause_bitmap; + /** + * Lower 32 bits bitmap of pause ids for TIDs that are blocked/unblocked + * based on module_id. + */ + A_UINT32 opaque_debug_vdev_all_tid_block_bitmap; + /** wal_pdev rx filter, WAL_RX_FILTER_FLAGS defines */ + A_UINT32 opaque_debug_rx_filter; + /** This word contains the following bitfields: + * aggr_nonaggr_retry_th: + * wal_pdev fields - agg_retry_th and non_agg_retry_th + * This value holds max retry threshold up to which a Data packet + * will be retried when ack is not received. + * agg_retry_th - Threshold value used when aggregation is enabled + * (WMI_PDEV_STATS_AGG_RETRY_TH_SET,GET) + * non_agg_retry_th - Threshold value used for non-aggregation. + * (WMI_PDEV_STATS_NON_AGG_RETRY_TH_SET) + */ + A_UINT32 opaque_debug_aggr_nonaggr_retry_th; + /** This word contains the following bitfields: + * num_max_rx_ba_sessions: + * Number of rx BA session establised + * (WMI_PDEV_STATS_NUM_RX_BA_SESSIONS_SET,GET) + * Max number of rx BA session from wal_pdev + * (WMI_PDEV_STATS_MAX_RX_BA_SESSIONS_SET,GET) + */ + A_UINT32 opaque_debug_num_max_rx_ba_sessions; + /** It holds WHAL_CHANNEL_SWITCH_FLAGS values */ + A_UINT32 opaque_debug_chan_switch_flags; + /** reset_cause holds PDEV_RESET_CONSEC_FAILURE or PDEV_RESET_TXQ_TIMEOUT */ + A_UINT32 opaque_debug_consecutive_failure_reset_cause; + /** PPDU duration limit, in us */ + A_UINT32 opaque_debug_mu_ppdu_dur_limit_us; + /** pdev reset in progress */ + A_UINT32 opaque_debug_reset_in_progress; + /** wal_dev - vdev_migrate_state refer to WAL_VDEV_MIGRATE_STATE */ + A_UINT32 opaque_debug_vdev_migrate_state; + /** opaque_debug_rts_rc_flag: + * wal_pdev rts ratecode - this value reflects whatever + * WMI_PDEV_PARAM_RTS_FIXED_RATE value the host has specified for the pdev. + */ + A_UINT32 opaque_debug_rts_rc_flag; + /* Num of peer delete in progress */ + A_UINT32 opaque_debug_num_of_peer_delete_in_progress; + /** wal_pdev total number of active vdev count */ + A_UINT32 opaque_debug_total_active_vdev_cnt; + /** wal_pdev - max number of vdevs per pdev */ + A_UINT32 opaque_debug_max_vdevs; + /* NonOccupancyList(NOL) context */ + A_UINT32 opaque_debug_dfs_nol_count; + /** NOL timeout in seconds */ + A_UINT32 opaque_debug_dfs_nol_timeout; + A_UINT32 opaque_debug_dfs_use_nol; + /** channel availability check mode, refer enum WMI_ADFS_OCAC_MODE */ + A_UINT32 opaque_debug_cac_mode; + A_UINT32 opaque_debug_dyn_ppdu_dur; /* in ms */ + /** This word contains the following bitfields: + * wal_pdev home channel info + * home_chan_mhz_flags: + * primary channel frequency in mhz + * (WMI_PDEV_STATS_HOME_CHAN_MHZ_SET,GET) + * flags to specify other channel attributes + * (WMI_PDEV_STATS_HOME_CHAN_FLAGS_SET, GET) + */ + A_UINT32 opaque_debug_home_chan_mhz_flags; + /** home channel center frequency in MHz */ + A_UINT32 opaque_debug_home_band_center_freq; + /** home channel phy_mode, refer enum WLAN_PHY_MODE */ + A_UINT32 opaque_debug_home_phy_mode; + /** This word contains the following bitfields: + * wal_pdev current channel info + * cur_chan_mhz_flags: + * primary channel frequency in mhz + * (WMI_PDEV_STATS_CUR_CHAN_MHZ_SET,GET) + * flags to specify other channel attributes + * (WMI_PDEV_STATS_CUR_CHAN_FLAGS_SET,GET) + */ + A_UINT32 opaque_debug_cur_chan_mhz_flags; + /** current channel center frequency in MHz */ + A_UINT32 opaque_debug_cur_band_center_freq; + /** current channel phy_mode, refer enum WLAN_PHY_MODE */ + A_UINT32 opaque_debug_cur_phy_mode; + /* Beacon context info */ + A_UINT32 opaque_debug_bcn_q_num_bcns_queued_to_hw; + /** beacon queue AIFS */ + A_UINT32 opaque_debug_aifs; + /** beacon queue cwmin */ + A_UINT32 opaque_debug_cwmin; + /** beacon queue cwmax */ + A_UINT32 opaque_debug_cwmax; + /** FILS discovery period in TU */ + A_UINT32 opaque_debug_fils_period; + /** Beacon interval in TU */ + A_UINT32 opaque_debug_beacon_period; + A_UINT32 opaque_debug_staggered_beacon_intvl; + /** wal_pdev tx context, refer enum WAL_TX_CTXT_FLAGS */ + A_UINT32 opaque_debug_tx_ctxt_flags; + /** opaque_debug_burst_mode_pending_isr + * wal_pdev tx_ctxt fields - burst_mode refer enum WAL_TX_BURST_MODE + * and pending_isr_status count + */ + A_UINT32 opaque_debug_burst_mode_pending_isr; + /** max burst duration from ppdu duration in us */ + A_UINT32 opaque_debug_burst_dur; + /** counter for tx hw stuck */ + A_UINT32 opaque_debug_tx_hw_stuck_cnt; + /** counter for tx consecutive lifetime expiry */ + A_UINT32 opaque_debug_consecutive_lifetime_expiries; + /** wal_pdev rx context, refer enum WAL_RX_CTXT_FLAGS */ + A_UINT32 opaque_debug_rx_ctxt_flags; + /** wal_pdev fields in rx context for rx_suspend or resume count */ + A_UINT32 opaque_debug_rx_suspend_cnt; + A_UINT32 opaque_debug_rx_resume_cnt; + A_UINT32 opaque_debug_rx_pcie_suspend_cnt; + A_UINT32 opaque_debug_rx_pcie_resume_cnt; + /** This word contains the following bitfields: + * wal_pdev fields + * pdev paused - WMI_PDEV_STATS_PAUSED_SET,GET + * pdev suspend - WMI_PDEV_STATS_SUSPENDED_SET,GET + * cac_enabed - MI_PDEV_STATS_CAC_ENABLED_SET,GET + * monitor VAP present - WMI_PDEV_STATS_IS_MONITOR_TYPE_PRESENT_SET,GET + * beacon tx mode - WMI_PDEV_STATS_BCN_TX_MODE_SET,GET + * isTXsuspended - WMI_PDEV_STATS_IS_TXSUSPENDED_SET,GET + * isSCHEDsuspended - WMI_PDEV_STATS_IS_SCHEDSUSPENDED_SET,GET + * sched_algo_resume_needed - + * WMI_PDEV_STATS_SCHED_ALGO_RESUME_NEEDED_SET,GET + * abort_reason - WMI_PDEV_STATS_ABORT_REASON_SET,GET + * atf_cfg - WMI_PDEV_STATS_ATF_CONFIG_SET,GET + * Green AP TX chainmask valid- WMI_PDEV_STATS_GAP_TX_CH_MASK_VALID_SET,GET + * Green AP RX chainmask valid- WMI_PDEV_STATS_GAP_RX_CH_MASK_VALID_SET,GET + * Green AP Phy mode valid - WMI_PDEV_STATS_GAP_PHY_MODE_VALID_SET,GET + * burst_enable - WMI_PDEV_STATS_BURST_ENABLE_SET,GET + */ + A_UINT32 opaque_debug_wal_pdev_bitfield; + /** This word contains the following bitfields: + * gap_phy_mode_freq: + * When GreenAP is enabled, phy_mode (WMI_PDEV_STATS_GAP_PHY_MODE_SET,GET) + * and center freq(MHz) (WMI_PDEV_STATS_GAP_BAND_CENTER_FREQ1_SET,GET) + * in GAP context is displayed + */ + A_UINT32 opaque_debug_gap_phy_mode_freq; + /** + * The following 5 opaque_debug_reserved_field variables are provided + * purely for debugging by technicians who have outside knowledge of + * what kind of values the target has placed into these fields. + */ + A_UINT32 opaque_debug_reserved_field_1; + A_UINT32 opaque_debug_reserved_field_2; + A_UINT32 opaque_debug_reserved_field_3; + A_UINT32 opaque_debug_reserved_field_4; + A_UINT32 opaque_debug_reserved_field_5; + /** + * Upper 32 bits bitmap of pause ids for TIDs that are paused/unpaused + * based on module_id. + */ + A_UINT32 opaque_debug_vdev_all_tid_pause_bitmap_ext; + /** + * Upper 32 bits bitmap of pause ids for TIDs that are blocked/unblocked + * based on module_id. + */ + A_UINT32 opaque_debug_vdev_all_tid_block_bitmap_ext; } wmi_ctrl_path_pdev_stats_struct; #define WMI_PDEV_STATS_NUM_MACS_GET(flag) \ @@ -14453,28 +14469,28 @@ typedef struct { */ A_UINT32 opaque_debug_keyid0_ast_index; /* opaque_debug_all_tids_block_module_bitmap: - * Bitmap of block IDs requesting block of all TIDs, + * Lower 32 bits bitmap of block IDs requesting block of all TIDs, * part of wal_peer. * Refer to enum WLAN_PAUSE_ID. * This block/pause ID can be mapped to a WLAN_MODULE_ID module ID. */ A_UINT32 opaque_debug_all_tids_block_module_bitmap; /* opaque_debug_all_tids_pause_module_bitmap: - * Bitmap of pause IDs requesting block of all TIDs, + * Lower 32 bits bitmap of pause IDs requesting block of all TIDs, * part of wal_peer. * Refer to enum WLAN_PAUSE_ID. * This pause ID can be mapped to a WLAN_MODULE_ID module ID. */ A_UINT32 opaque_debug_all_tids_pause_module_bitmap; /* opaque_debug_data_tids_block_module_bitmap: - * Bitmap of block ids requesting block of data tids, + * Lower 32 bits bitmap of block ids requesting block of data tids, * part of wal_peer. * Refer to enum WLAN_PAUSE_ID. * This block/pause ID can be mapped to a WLAN_MODULE_ID module ID. */ A_UINT32 opaque_debug_data_tids_block_module_bitmap; /* opaque_debug_data_tids_pause_module_bitmap: - * Bitmap of pause ids requesting block of data tids, + * Lower 32 bits bitmap of pause ids requesting block of data tids, * part of wal_peer. * Refer to enum WLAN_PAUSE_ID. * This pause ID can be mapped to a WLAN_MODULE_ID module ID. @@ -14882,6 +14898,34 @@ typedef struct { reserved: 16; }; }; + /* opaque_debug_all_tids_block_module_bitmap_ext: + * Upper 32 bits bitmap of block IDs requesting block of all TIDs, + * part of wal_peer. + * Refer to enum WLAN_PAUSE_ID. + * This block/pause ID can be mapped to a WLAN_MODULE_ID module ID. + */ + A_UINT32 opaque_debug_all_tids_block_module_bitmap_ext; + /* opaque_debug_all_tids_pause_module_bitmap_ext: + * Upper 32 bits bitmap of pause IDs requesting pause of all TIDs, + * part of wal_peer. + * Refer to enum WLAN_PAUSE_ID. + * This pause ID can be mapped to a WLAN_MODULE_ID module ID. + */ + A_UINT32 opaque_debug_all_tids_pause_module_bitmap_ext; + /* opaque_debug_data_tids_block_module_bitmap_ext: + * Upper 32 bits bitmap of block ids requesting block of data tids, + * part of wal_peer. + * Refer to enum WLAN_PAUSE_ID. + * This block/pause ID can be mapped to a WLAN_MODULE_ID module ID. + */ + A_UINT32 opaque_debug_data_tids_block_module_bitmap_ext; + /* opaque_debug_data_tids_pause_module_bitmap_ext: + * Upper 32 bits bitmap of pause ids requesting pause of data tids, + * part of wal_peer. + * Refer to enum WLAN_PAUSE_ID. + * This pause ID can be mapped to a WLAN_MODULE_ID module ID. + */ + A_UINT32 opaque_debug_data_tids_pause_module_bitmap_ext; } wmi_ctrl_path_peer_stats_struct; #define WMI_PEER_STATS_SM_MASK_SET(flag, val) \ @@ -15604,9 +15648,15 @@ typedef struct { A_UINT32 opaque_debug_rx_pkt_on_channel; /* Contains the value of Target beacon transmission time offset value */ A_UINT32 opaque_debug_tbtt_offset; - /* Contains the value of tid pause bitmap of the peer from wal_vdev */ + /* + * Contains the value of lower 32 bits of tid pause bitmap of the peer + * from wal_vdev + */ A_UINT32 opaque_debug_peer_all_tid_pause_bitmap; - /* Contains the value of tid block bitmap of the peer from wal_vdev */ + /* + * Contains the value of lower 32 bits of tid block bitmap of the peer + * from wal_vdev + */ A_UINT32 opaque_debug_peer_all_tid_block_bitmap; /* Contains the value of tdls peer kickout threshold */ A_UINT32 opaque_debug_tdls_peer_kickout_th; @@ -15960,6 +16010,16 @@ typedef struct { A_UINT32 opaque_debug_field_2; A_UINT32 opaque_debug_field_3; A_UINT32 opaque_debug_field_4; + /* + * Contains the value of upper 32 bits tid pause bitmap of the peer + * from wal_vdev + */ + A_UINT32 opaque_debug_peer_all_tid_pause_bitmap_ext; + /* + * Contains the value of upper 32 bits tid block bitmap of the peer + * from wal_vdev + */ + A_UINT32 opaque_debug_peer_all_tid_block_bitmap_ext; } wmi_ctrl_path_vdev_stats_struct; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 473c9316c2a3..f45ed39751eb 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1608 +#define __WMI_REVISION_ 1609 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 37078689df3319e06e357ff67460f45a7af6d627 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 7 May 2025 06:01:35 -0700 Subject: [PATCH 090/306] fw-api: CL 29158320 - update fw common interface files Change-Id: I2c500439c96000ff4dcd5ae3c8abfb6d730fafe4 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 9 ++++++++- fw/wmi_version.h | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index db6c46ef24dc..48af06258da7 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -5617,6 +5617,7 @@ typedef enum { WMI_VENDOR1_REQ1_VERSION_4_10 = 6, WMI_VENDOR1_REQ1_VERSION_4_20 = 7, WMI_VENDOR1_REQ1_VERSION_4_40 = 8, + WMI_VENDOR1_REQ1_VERSION_4_50 = 9, } WMI_VENDOR1_REQ1_VERSION; typedef enum { @@ -5624,6 +5625,7 @@ typedef enum { WMI_VENDOR1_REQ2_VERSION_3_01 = 1, WMI_VENDOR1_REQ2_VERSION_3_20 = 2, WMI_VENDOR1_REQ2_VERSION_3_50 = 3, + WMI_VENDOR1_REQ2_VERSION_3_61 = 4, } WMI_VENDOR1_REQ2_VERSION; typedef enum { @@ -41585,6 +41587,11 @@ typedef struct { A_UINT32 vdev_id; /* 1-Enable, 0-Disable */ A_UINT32 enable; + /* self_roaming_re_enable_time: + * Allow next deauth self-roaming only when time gap is more than + * self_roaming_re_enable_time w.r.t previous deauth self-roaming. + */ + A_UINT32 self_roaming_re_enable_time; /* units = seconds */ } wmi_roam_deauth_config_cmd_fixed_param; /** IDLE roam trigger parameters */ @@ -42299,7 +42306,7 @@ typedef struct { * rssi_dbm_abs * Last known RSSI of the current BSSID at the moment when the frame * was sent and received. - * This RSSI value is valid for deauth / disassoc frame only. + * Host should ignore this field if its value is 0. * The rssi_dbm_abs value is the absolute value of the RSSI in dBm units. * For example, if the RSSI is -40 dBm, rssi_dbm_abs will be 40. */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index f45ed39751eb..179e1b8a8fcb 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1609 +#define __WMI_REVISION_ 1610 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 9c059f322eb4a1aee766bb8ebcb4e5f64d864ad8 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 10 May 2025 06:01:38 -0700 Subject: [PATCH 091/306] fw-api: CL 29182219 - update fw common interface files Change-Id: Ib22a6437ee44f649ba121c257bcc1afbafe4454b CRs-Fixed: 3830439 --- fw/wmi_unified.h | 10 ++++++++++ fw/wmi_version.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 48af06258da7..f09a162767f3 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -3885,10 +3885,18 @@ typedef struct { * WMI_HAL_REG_CAPABILITIES_EXT2 hal_reg_caps[]; * wmi_nan_capabilities nan_cap; * WMI_SCAN_RADIO_CAPABILITIES_EXT2 wmi_scan_radio_caps[]; + * wmi_twt_caps_params twt_caps[]; * wmi_htt_msdu_idx_to_htt_msdu_qtype htt_msdu_idx_to_qtype_map[]; * wmi_dbs_or_sbs_cap_ext dbs_or_sbs_cap_ext; + * wmi_cust_bdf_version_capabilities cust_bdf_version_capabilities[]; + * wmi_sw_cal_ver_cap sw_cal_ver_cap[]; * A_INT32 hw_tx_power_signed[WMI_HW_TX_POWER_CAPS_MAX]; + * WMI_COEX_FIX_CHANNEL_CAPABILITIES coex_fix_channel_caps[]; * wmi_aux_dev_capabilities aux_dev_caps[]; + * wmi_enhanced_aoa_caps_param aoa_caps_param[]; + * wmi_enhanced_aoa_per_band_caps_param + * aoa_per_band_caps_param[]; + * wmi_sar_flag_tlv_param sar_flags[]; * WMI_POWER_BOOST_CAPABILITIES power_boost_capabilities[]; * WMI_RSSI_ACCURACY_IMPROVEMENT_CAPABILITIES * rssi_accuracy_improvement_capabilities[]; @@ -22170,6 +22178,8 @@ typedef struct { A_UINT32 peer_eht_ops; wmi_ppe_threshold peer_eht_ppet; A_UINT32 assoc_flags; + /** maximum number of spatial streams supported by peer for tx */ + A_UINT32 peer_max_tx_nss; /* Following this struct are the TLV's: * A_UINT8 peer_legacy_rates[]; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 179e1b8a8fcb..14ac87fd74de 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1610 +#define __WMI_REVISION_ 1611 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 8bdc47650215af92cac52d4b1f918a269af5c56b Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 11 May 2025 06:01:32 -0700 Subject: [PATCH 092/306] fw-api: CL 29193068 - update fw common interface files Change-Id: I40ece65aa3aabdd47b1f8b227f14be466c91850b CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 +- fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index f09a162767f3..b2a81017730f 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -28038,8 +28038,8 @@ typedef struct #define LPI_IE_BITMAP_CHRE_RADIO_CHAIN 0x01000000 /* include radio chain and RSSI per chain information if this bit is set - for CHRE */ #define LPI_IE_BITMAP_CHRE_SEC_MODE_MRSNO_WIFI6 0x02000000 /* include MRSNO IE's sec_mode information for WiFi6 if this bit is set - for CHRE */ #define LPI_IE_BITMAP_CHRE_SEC_MODE_MRSNO_WIFI7 0x04000000 /* include MRSNO IE's sec_mode information for WiFi7 if this bit is set - for CHRE */ +#define LPI_IE_BITMAP_INTERWORKING_IE_VENUE_INFO 0x08000000 /* interworking IE venue info (2 bytes) will be filled when this bit is enabled */ -/* 0x08000000 is unused / available */ #define LPI_IE_BITMAP_CHRE_ESS 0x10000000 /* ESS capability info for CHRE */ #define LPI_IE_BITMAP_CHRE_SEC_MODE 0x20000000 /* Security capability info for CHRE */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 14ac87fd74de..5f5a03bf0cdf 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1611 +#define __WMI_REVISION_ 1612 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From f2ee6174bb7b14f128f779bea9e45ac5a4b9456b Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 14 May 2025 06:01:51 -0700 Subject: [PATCH 093/306] fw-api: CL 29208203 - update fw common interface files Change-Id: I08ee77feb67f147fa1dc51cca62d584c24a98369 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 7 +++++++ fw/wmi_version.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index b2a81017730f..5bbf6d2038dd 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -19703,6 +19703,13 @@ typedef enum { */ WMI_VDEV_PARAM_SET_SAP_PS_WITH_TWT, /* 0x8013 */ + /* + * Support RTT Bandwidth downgrade + * 0 - Disable RTT Bandwidth downgrade + * 1 - Enable RTT Bandwidth downgrade + */ + WMI_VDEV_PARAM_ENABLE_DISABLE_RTT_BW_DOWNGRADE, /* 0x8014 */ + /*=== END VDEV_PARAM_PROTOTYPE SECTION ===*/ } WMI_VDEV_PARAM; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 5f5a03bf0cdf..4e900407fb70 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1612 +#define __WMI_REVISION_ 1613 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 45ab41a8bdfa45fb9bc7372ab4e4b815d83ea1ad Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 14 May 2025 06:03:37 -0700 Subject: [PATCH 094/306] fw-api: CL 29217789 - update fw common interface files Change-Id: I905ac6d4b23b4c01c02a76ad4aa85f2cbe8e6362 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 37 +++++++++++++++++++++++++++++++++---- fw/wmi_version.h | 2 +- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 5bbf6d2038dd..1ad3caab84aa 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -45155,13 +45155,42 @@ typedef struct { /****** End of 11BE EHT MAC Capabilities Information field ******/ -/****** 11BE EHT OPS Information field ******/ - -/* Bit 0 is for MCS15. If bit0 is 1 then we enable mcs15 */ +/****** 11BE EHT OPS Information field - DEPRECATED ******/ +/* DEPRECATED, replaced by + * "Bit 6 is for MCS15. If bit6 is 1 then we disable mcs15" + * OLD: Bit 0 is for MCS15. If bit0 is 1 then we enable mcs15 + */ #define WMI_EHT_OPS_SUPMCS15_GET(eht_ops) WMI_GET_BITS(eht_ops, 0, 1) #define WMI_EHT_OPS_SUPMCS15_SET(eht_ops, value) WMI_SET_BITS(eht_ops, 0, 1, value) +/****** End of 11BE EHT OPS Information field - DEPRECATED ******/ +/****** 11BE EHT Operation Parameters field ******/ +/* Bit 0 EHT Operation Information Present */ +#define WMI_EHT_OPS_INFORMATION_PRESENT_GET(eht_ops) WMI_GET_BITS(eht_ops, 0, 1) +#define WMI_EHT_OPS_INFORMATION_PRESENT_SET(eht_ops, value) WMI_SET_BITS(eht_ops, 0, 1, value) + +/* Bit 1 Disabled Subchannel Bitmap Present */ +#define WMI_EHT_OPS_DISABLED_SUBCHANNEL_BITMAP_GET(eht_ops) WMI_GET_BITS(eht_ops, 1, 1) +#define WMI_EHT_OPS_DISABLED_SUBCHANNEL_BITMAP_SET(eht_ops, value) WMI_SET_BITS(eht_ops, 1, 1, value) + +/* Bit 2 EHT default PE duration */ +#define WMI_EHT_OPS_PE_DURATION_GET(eht_ops) WMI_GET_BITS(eht_ops, 2, 1) +#define WMI_EHT_OPS_PE_DURATION_SET(eht_ops, value) WMI_SET_BITS(eht_ops, 2, 1, value) + +/* Bit 3 Group Addressed BU indication limit*/ +#define WMI_EHT_OPS_GROUP_ADDRESSED_BU_INDICATION_LIMIT_GET(eht_ops) WMI_GET_BITS(eht_ops, 3, 1) +#define WMI_EHT_OPS_GROUP_ADDRESSED_BU_INDICATION_LIMIT_SET(eht_ops, value) WMI_SET_BITS(eht_ops, 3, 1, value) + +/* Bit 4~5 Group Addressed BU indication Exponent */ +#define WMI_EHT_OPS_GROUP_ADDRESSED_BU_INDICATION_EXPONENT_GET(eht_ops) WMI_GET_BITS(eht_ops, 4, 2) +#define WMI_EHT_OPS_GROUP_ADDRESSED_BU_INDICATION_EXPONENT_SET(eht_ops) WMI_SET_BITS(eht_ops, 4, 2, value) + +/* Bit 6 is for MCS15. If bit6 is 1 then we disable mcs15 */ +#define WMI_EHT_OPS_MCS15_DISABLE_GET(eht_ops) WMI_GET_BITS(eht_ops, 6, 1) +#define WMI_EHT_OPS_MCS15_DISABLE_SET(eht_ops, value) WMI_SET_BITS(eht_ops, 6, 1, value) + +/* Bit 7: reserved */ +/****** End of 11BE EHT Operation Parameters field ******/ -/****** End of 11BE EHT OPS Information field ******/ typedef struct { /** TLV tag and len; tag equals diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 4e900407fb70..c554c642e5f9 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1613 +#define __WMI_REVISION_ 1614 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From ca8db3d0f01550b87c14a3a7f3df32c7e9727a6f Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 16 May 2025 06:01:32 -0700 Subject: [PATCH 095/306] fw-api: CL 29230158 - update fw common interface files Change-Id: Ibbbacc63a3ed3df992f751ff7a2fc57768f61173 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 18 +++++++++++++++++- fw/wmi_version.h | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 6286a4916a78..c1a7fe50d9bf 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -700,6 +700,7 @@ typedef enum { WMI_SERVICE_CTRL_PATH_STA_DAR_STATS_SUPPORT = 441, /* FW supports DAR stats reporting for STA mode */ WMI_SERVICE_APF_DATA_OFFLOAD_SUPPORT_ENABLED = 442, /* Indicates FW support for APFv6 handling offloads and disable QC data offloads */ WMI_SERVICE_PER_VDEV_TWT_RESP_DISABLE_SUPPORT = 443, /* FW supports vdev level TWT responder disable */ + WMI_SERVICE_VENDOR_OUI_ACTION_V2 = 444, /* FW supports vendor OUI action version 2 */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 1ad3caab84aa..c3e42272f010 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -5001,7 +5001,13 @@ typedef struct { * flow_override set. * Refer to the below definitions of WMI_RSRC_CFG_HOST_SERVICE_FLAG * OPT_DP_ENABLE_BYPASS_FOR_HLOS_TID_OVERRIDE_GET and _SET macros. - * Bits 31:20 - Reserved + * Bit 20 + * This bit will set by host to inform FW that action OUI v2 is + * enabled by both host configuration and FW capability. + * Refer to the below definitions of + * WMI_RSRC_CFG_HOST_SERVICE_FLAG_ACTION_OUI_V2_GET and SET. + * + * Bits 31:21 - Reserved */ A_UINT32 host_service_flags; @@ -5551,6 +5557,11 @@ typedef struct { #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_OPT_DP_ENABLE_BYPASS_FOR_HLOS_TID_OVERRIDE_SET(host_service_flags, val) \ WMI_SET_BITS(host_service_flags, 19, 1, val) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_ACTION_OUI_V2_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 20, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_ACTION_OUI_V2_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 20, 1, val) + #define WMI_RSRC_CFG_CARRIER_CFG_CHARTER_ENABLE_GET(carrier_config) \ WMI_GET_BITS(carrier_config, 0, 1) @@ -26568,6 +26579,11 @@ typedef enum */ WMI_VENDOR_OUI_ACTION_AUTH_ASSOC_6MBPS_2GHZ = 17, + /* + * Disable dynamic SMPS if OUI matches + */ + WMI_VENDOR_OUI_ACTION_DISABLE_DYNAMIC_SMPS = 18, + /* Add any action before this line */ WMI_VENDOR_OUI_ACTION_MAX_ACTION_ID diff --git a/fw/wmi_version.h b/fw/wmi_version.h index c554c642e5f9..d666ef3bd39b 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1614 +#define __WMI_REVISION_ 1615 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 1227bcf0b1b2c066be7058ce091a1e0ecf2fa063 Mon Sep 17 00:00:00 2001 From: Fakruddin Vohra Date: Wed, 2 Apr 2025 10:36:06 +0530 Subject: [PATCH 096/306] mdm: ipa3: support IPoGRE new IOCTL and proc params change to support IPoGRE IOCTL for interface with QCMAP and proc context parameters. Change-Id: I13baab118eb03e18c7c53403705cbdb7611411c1 Signed-off-by: Fakruddin Vohra --- include/uapi/linux/msm_ipa.h | 125 +++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index f63134040753..5f63c7b96479 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -152,8 +152,9 @@ #define IPA_IOCTL_SET_EXT_ROUTER_MODE 95 #define IPA_IOCTL_ADD_DEL_DSCP_PCP_MAPPING 96 #define IPA_IOCTL_SEND_VLAN_MUXID_MAPPING 97 -#define IPA_IOCTL_SEND_TUNNEL_TEMPLATE_INFO 98 -#define IPA_IOCTL_QUERY_TUNNEL_FEATURE 99 +#define IPA_IOCTL_SEND_TUNNEL_TEMPLATE_INFO 98 +#define IPA_IOCTL_QUERY_TUNNEL_FEATURE 99 +#define IPA_IOCTL_ADD_IPOGRE_MAPPING 100 /** * max size of the header to be inserted */ @@ -976,8 +977,12 @@ enum ipa_eth_pdu_evt { #define IPA_ENABLE_ETH_PDU_MODE_EVENT_MAX IPA_ENABLE_ETH_PDU_MODE_EVENT_MAX }; - -#define IPA_EVENT_MAX_NUM (IPA_ENABLE_ETH_PDU_MODE_EVENT_MAX) +enum ipa_ipogre_event { + IPA_IPOGRE_NOTIFY_EVENT = IPA_ENABLE_ETH_PDU_MODE_EVENT_MAX, + IPA_IPOGRE_EVENT_MAX +#define IPA_IPOGRE_EVENT_MAX IPA_IPOGRE_EVENT_MAX +}; +#define IPA_EVENT_MAX_NUM (IPA_IPOGRE_EVENT_MAX) #define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) /** @@ -1551,9 +1556,11 @@ enum ipa_hdr_proc_type { IPA_HDR_PROC_EoGRE_HEADER_REMOVE, IPA_HDR_PROC_WWAN_TO_ETHII_EX, IPA_HDR_PROC_GRE_HEADER_ADD, - IPA_HDR_PROC_GRE_HEADER_REMOVE + IPA_HDR_PROC_GRE_HEADER_REMOVE, + IPA_HDR_PROC_IPOGRE_HEADER_ADD, + IPA_HDR_PROC_IPOGRE_HEADER_REMOVE }; -#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_GRE_HEADER_REMOVE + 1) +#define IPA_HDR_PROC_MAX (IPA_HDR_PROC_IPOGRE_HEADER_REMOVE + 1) /** * struct ipa_rt_rule - attributes of a routing rule @@ -1958,6 +1965,68 @@ struct ipa_ioc_eogre_info { struct IpaDscpVlanPcpMap_t map_info; }; +#define MAX_FLOW_PER_IPOGRE_TUNNEL 10 + +/** + * struct ipa_ipogre_info - + * @ipv4_src: Specifies source v4 address if GRE tunnel is ipv4 + * @ipv4_dst: Specifies destination v4 address if GRE tunnel is ipv4 + * @ipv6_src: Specifies source v6 address if GRE tunnel is ipv6 + * @ipv6_dst: Specifies destination v6 address if GRE tunnel is ipv6 + * @iptype: Specifies GRE tunnel's ip address type + * @tunnel_id: Specifies tunnel id + */ + +struct ipa_ipogre_tunnel_info { + uint32_t ipv4_src; + uint32_t ipv4_dst; + uint32_t ipv6_src[4]; + uint32_t ipv6_dst[4]; + enum ipa_ip_type iptype; + uint8_t tunnel_id; +} __packed; + +/** + * struct ipa_ipogre_info - + * @ipv4_src: Specifies source v4 address if GRE tunnel is ipv4 + * @ipv4_src_subnet: Specifies source v4 address subnet if GRE tunnel is ipv4 + * @ipv4_dst: Specifies destination v4 address if GRE tunnel is ipv4 + * @ipv4_dst_subnet: Specifies destination v4 address subnet if GRE tunnel is ipv4 + * @ipv6_src: Specifies source v6 address if GRE tunnel is ipv6 + * @ipv6_src_subnet: Specifies source v6 address subnet if GRE tunnel is ipv6 + * @ipv6_dst: Specifies destination v6 address if GRE tunnel is ipv6 + * @ipv6_dst_subnet: Specifies destination v6 address subnet if GRE tunnel is ipv6 + * @iptype: Specifies GRE tunnel's ip address type + * @protocol: Specifies protocol of the data traffic + */ + +struct ipa_ipogre_flow_info { + uint32_t ipv4_src; + uint32_t ipv4_src_subnet; + uint32_t ipv4_dst; + uint32_t ipv4_dst_subnet; + uint32_t ipv6_src[4]; + uint32_t ipv6_dst[4]; + uint32_t src_port; + uint32_t dst_port; + enum ipa_ip_type iptype; + uint8_t protocol; + uint8_t ipv6_src_subnet; + uint8_t ipv6_dst_subnet; +} __packed; + +/** + * struct ipa_ipogre_info - + * @ipogre_tunnel_info: Specifies tunnel information + * @ipogre_flow_info: Specifies flows to be offloaded + * @ipa_ipogre_num_flow: Specifies number of flow to be offloaded + */ + +struct ipa_ioc_ipogre_info { + struct ipa_ipogre_tunnel_info ipogre_tunnel_info; + struct ipa_ipogre_flow_info ipogre_flow_info[MAX_FLOW_PER_IPOGRE_TUNNEL]; + uint8_t ipa_ipogre_num_flow; +}; /** * struct ipa_eogre_header_add_procparams - * @eth_hdr_retained: Specifies if Ethernet header is retained or not @@ -2049,6 +2118,45 @@ struct ipa_gre_hdr_proc_ctx_params { struct ipa_gre_header_remove_procparams hdr_remove_param; }; +/** + * struct ipa_ipogre_header_add_procparams - + * @input_ip_version: Specifies if Input header is IPV4(0) or IPV6(1) + * @output_ip_version: Specifies if template header's outer IP is IPV4(0) + * or IPV6(1) + * @Tunnel_Id: Tunnel id associated with the header. + * @Mux_Id: Specifies mux id associated with the template header + */ +struct ipa_ipogre_header_add_procparams { + uint32_t input_ip_version : 1; + uint32_t output_ip_version : 1; + uint32_t tunnel_id : 4; + uint32_t mux_id : 8; + uint32_t reserved :18; +}; + +/** + * struct ipa_ipogre_header_remove_procparams - + * @hdr_len_remove: Specifies how much (in bytes) of the header needs + * to be removed + * @input_ip_version: Specifies if Input header is IPV4(0) or IPV6(1) + * @Tunnel_Id: Tunnel id associated with the header. + */ +struct ipa_ipogre_header_remove_procparams { + uint32_t hdr_len_remove : 8; + uint32_t input_ip_version : 1; + uint32_t tunnel_id : 4; + uint32_t reserved :19; +}; + +/** + * struct ipa_ipogre_hdr_proc_ctx_params - + * @hdr_add_param: parameters for header add + * @hdr_remove_param: parameters for header remove + */ +struct ipa_ipogre_hdr_proc_ctx_params { + struct ipa_ipogre_header_add_procparams hdr_add_param; + struct ipa_ipogre_header_remove_procparams hdr_remove_param; +}; /** * struct ipa_eth_II_to_eth_II_ex_procparams - * @input_ethhdr_negative_offset: Specifies where the ethernet hdr offset is @@ -2111,6 +2219,7 @@ struct ipa_hdr_proc_ctx_add { struct ipa_eth_II_to_eth_II_ex_procparams generic_params; struct ipa_wwan_to_eth_II_ex_procparams generic_params_v2; struct ipa_gre_hdr_proc_ctx_params gre_params; + struct ipa_ipogre_hdr_proc_ctx_params ipogre_params; }; #define IPA_L2TP_HDR_PROC_SUPPORT @@ -4221,6 +4330,10 @@ struct ipa_ioc_dscp_pcp_map_info { IPA_IOCTL_QUERY_TUNNEL_FEATURE, \ uint8_t) +#define IPA_IOC_ADD_IPoGRE_MAPPING _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_ADD_IPOGRE_MAPPING, \ + struct ipa_ioc_ipogre_info) + /* * unique magic number of the Tethering bridge ioctls */ From 3fedfd9225c35b50d8b48ab8ea31bbe26fd83713 Mon Sep 17 00:00:00 2001 From: Vasantha Balla Date: Fri, 28 Mar 2025 12:16:47 +0530 Subject: [PATCH 097/306] msm: vidc: Fix use after free in driver Use after free can happen in below scenario. [1] In msm_vidc_open, When instance count reaches max count or when open failed it waits for core lock before removing instance from instance list. [2] During this time backward thread can get invoked to handle firmware response for cmds, It increments reference count and gets instance. [3] If forward thread resumes after this, and frees intance, backward thread will end up using freed instance. [4] To address this, calling kref_put(&inst->kref) and freeing instance immediately if ref count is zero, if recount is not zero, backward thread frees instance memory in put_inst_helper. Change-Id: I58c81d4d9fda1523d0fa29ebdb33455db839d46f Signed-off-by: Vasantha Balla (cherry picked from commit ccddad0c4992ab7b4e3651e2c5c8df3e79bb7c43) (cherry picked from commit cc9f3cc50311796626b2c40b049daeef0a5719ea) --- msm/vidc/msm_vidc.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/msm/vidc/msm_vidc.c b/msm/vidc/msm_vidc.c index d848eb08976b..db0f6529abb8 100644 --- a/msm/vidc/msm_vidc.c +++ b/msm/vidc/msm_vidc.c @@ -1482,7 +1482,6 @@ static void close_helper(struct kref *kref) { struct msm_vidc_inst *inst = container_of(kref, struct msm_vidc_inst, kref); - msm_vidc_destroy(inst); } @@ -1497,19 +1496,19 @@ void *msm_vidc_open(int core_id, int session_type) session_type >= MSM_VIDC_MAX_DEVICES) { d_vpr_e("Invalid input, core_id = %d, session = %d\n", core_id, session_type); - goto err_invalid_core; + return NULL; } core = get_vidc_core(core_id); if (!core) { d_vpr_e("Failed to find core for core_id = %d\n", core_id); - goto err_invalid_core; + return NULL; } inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) { d_vpr_e("Failed to allocate memory\n"); rc = -ENOMEM; - goto err_invalid_core; + return NULL; } mutex_lock(&core->lock); rc = get_sid(&inst->sid, session_type); @@ -1609,14 +1608,15 @@ void *msm_vidc_open(int core_id, int session_type) s_vpr_e(inst->sid, "Failed to move video instance to init state\n"); kref_put(&inst->kref, close_helper); - inst = NULL; - goto err_invalid_core; + return NULL; } if (msm_comm_check_for_inst_overload(core)) { s_vpr_e(inst->sid, "Instance count reached Max limit, rejecting session"); - goto fail_init; + msm_comm_kill_session(inst); + kref_put(&inst->kref, close_helper); + return NULL; } msm_comm_scale_clocks_and_bus(inst, 1); @@ -1625,14 +1625,6 @@ void *msm_vidc_open(int core_id, int session_type) msm_vidc_debugfs_init_inst(inst, core->debugfs_root); return inst; -fail_init: - mutex_lock(&core->lock); - list_del(&inst->list); - mutex_unlock(&core->lock); - - v4l2_fh_del(&inst->event_handler); - v4l2_fh_exit(&inst->event_handler); - vb2_queue_release(&inst->bufq[INPUT_PORT].vb2_bufq); fail_bufq_output: vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); fail_bufq_capture: @@ -1660,7 +1652,6 @@ err_invalid_sid: put_sid(inst->sid); kfree(inst); inst = NULL; -err_invalid_core: return inst; } EXPORT_SYMBOL(msm_vidc_open); From 6a85db968b33dc9d169e1b302c3e78cfcbf32caf Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 19 May 2025 06:01:33 -0700 Subject: [PATCH 098/306] fw-api: CL 29254060 - update fw common interface files Change-Id: I811fc4f440453d374f70d87142103a90ae923bcc CRs-Fixed: 3830439 --- fw/wmi_unified.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ fw/wmi_version.h | 2 +- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index c3e42272f010..63c6b5e5568c 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -34776,6 +34776,41 @@ typedef enum { * A_INT8 ICNIRP 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-8) (Ch117~Ch149) * A_INT8 ICNIRP 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-8) (Ch117~Ch149) * A_INT8 ICNIRP 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-8) (Ch117~Ch149) + * if version == 2 or chip is col, will have NONTAS POWER LIMIT + * ====================NONTAS POWER LIMIT VALUE====================== + * A_INT8 NONTAS 2 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) + * A_INT8 NONTAS 2 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) + * A_INT8 NONTAS 2 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) + * A_INT8 NONTAS 5 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-1, Ch32 ~ Ch48) + * A_INT8 NONTAS 5 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-1, Ch32 ~ Ch48) + * A_INT8 NONTAS 5 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-1, Ch32 ~ Ch48) + * A_INT8 NONTAS 5 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-2, Ch50 ~ Ch144) + * A_INT8 NONTAS 5 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-2, Ch50 ~ Ch144) + * A_INT8 NONTAS 5 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-2, Ch50 ~ Ch144) + * A_INT8 NONTAS 5 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-3, Ch149 ~ Ch161) + * A_INT8 NONTAS 5 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-3, Ch149 ~ Ch161) + * A_INT8 NONTAS 5 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-3, Ch149 ~ Ch161) + * A_INT8 NONTAS 5 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-4, Ch163 ~ Ch177) + * A_INT8 NONTAS 5 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-4, Ch163 ~ Ch177) + * A_INT8 NONTAS 5 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-4, Ch163 ~ Ch177) + * A_INT8 NONTAS 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-5) (Ch1, Ch2 ~ Ch41) + * A_INT8 NONTAS 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-5) (Ch1, Ch2 ~ Ch41) + * A_INT8 NONTAS 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-5) (Ch1, Ch2 ~ Ch41) + * A_INT8 NONTAS 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-5) (Ch45 ~ Ch93) + * A_INT8 NONTAS 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-5) (Ch45 ~ Ch93) + * A_INT8 NONTAS 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-5) (Ch45 ~ Ch93) + * A_INT8 NONTAS 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-6) (Ch97~ Ch113) + * A_INT8 NONTAS 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-6) (Ch97~ Ch113) + * A_INT8 NONTAS 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-6) (Ch97~ Ch113) + * A_INT8 NONTAS 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-7) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-7) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-7) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-7) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-7) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-7) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz SISO (Chain0) Power Limit Value(unit: 0.25dBm) (UNII-8) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz SISO (Chain1) Power Limit Value(unit: 0.25dBm) (UNII-8) (Ch117~Ch149) + * A_INT8 NONTAS 6 GHz MIMO (Chain0 + Chain1) Power Limit Value(unit: 0.25dBm) (UNII-8) (Ch117~Ch149) */ BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER, @@ -34948,6 +34983,21 @@ typedef enum { * ============================================================== */ + BIOS_PARAM_TYPE_NON_SAR_COUNTRY_CONFIG, + /* + * BIOS_PARAM_TYPE_NON_SAR_COUNTRY_CONFIG structure contains 256 bytes as below + * + * A_UINT8 country_bitmap[NON_SAR_COUNTRY_BITMAP_COUNT];//NON_SAR_COUNTRY_BITMAP_COUNT = 256, 256BYTE. + * 0-255 stand for 256 country, each country has 8 bit for configuration. + * + * ==================each bit configuration=========================== + * BIT0: Skip TAS limit config + * BIT1: Skip SAR limit config + * BIT2: Use domain GEO table. 1: Use Country GEO table + * BIT3~5: index of domain/country used which group GEO offset table + * BIT6~7: reserved + * ==================================================================== + */ BIOS_PARAM_TYPE_MAX, } bios_param_type_e; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index d666ef3bd39b..eacac7fbc2fb 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1615 +#define __WMI_REVISION_ 1616 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 4ae3dd7d798f7a2fd63a635ddb911eec6946b8e2 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 22 May 2025 06:01:37 -0700 Subject: [PATCH 099/306] fw-api: CL 29279982 - update fw common interface files Change-Id: Icd3b8476209546f3d2898ec9a3a53b84b73752c8 CRs-Fixed: 3830439 --- fw/htt.h | 399 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 358 insertions(+), 41 deletions(-) diff --git a/fw/htt.h b/fw/htt.h index 5e43e5e8fc0e..7a879225a71f 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -267,9 +267,10 @@ * 3.137 Add more HTT_SDWF_MSDUQ_CFG_IND_ERROR codes. * 3.138 Add T2H MLO_LATENCY_REQ, H2T _RESP msg defs. * 3.139 Add CLASS_INFO_IDX field in MLO_R_PEER_MAP msg. + * 3.140 Add H2T MPDUQ_AND_MSDUQ_INFO_HDR and MPDUQ_OF_MSDUQ_INFO defs. */ #define HTT_CURRENT_VERSION_MAJOR 3 -#define HTT_CURRENT_VERSION_MINOR 139 +#define HTT_CURRENT_VERSION_MINOR 140 #define HTT_NUM_TX_FRAG_DESC 1024 @@ -880,47 +881,49 @@ typedef htt_stats_tlv_tag_t htt_tlv_tag_t; /*=== host -> target messages ===============================================*/ enum htt_h2t_msg_type { - HTT_H2T_MSG_TYPE_VERSION_REQ = 0x0, - HTT_H2T_MSG_TYPE_TX_FRM = 0x1, - HTT_H2T_MSG_TYPE_RX_RING_CFG = 0x2, - HTT_H2T_MSG_TYPE_STATS_REQ = 0x3, - HTT_H2T_MSG_TYPE_SYNC = 0x4, - HTT_H2T_MSG_TYPE_AGGR_CFG = 0x5, - HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 0x6, - DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX = 0x7, /* no longer used */ - HTT_H2T_MSG_TYPE_WDI_IPA_CFG = 0x8, - HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ = 0x9, - HTT_H2T_MSG_TYPE_AGGR_CFG_EX = 0xa, /* per vdev amsdu subfrm limit */ - HTT_H2T_MSG_TYPE_SRING_SETUP = 0xb, - HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc, - HTT_H2T_MSG_TYPE_ADD_WDS_ENTRY = 0xd, - HTT_H2T_MSG_TYPE_DELETE_WDS_ENTRY = 0xe, - HTT_H2T_MSG_TYPE_RFS_CONFIG = 0xf, - HTT_H2T_MSG_TYPE_EXT_STATS_REQ = 0x10, - HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11, - HTT_H2T_MSG_TYPE_RX_FSE_SETUP_CFG = 0x12, - HTT_H2T_MSG_TYPE_RX_FSE_OPERATION_CFG = 0x13, - HTT_H2T_MSG_TYPE_CHAN_CALDATA = 0x14, - HTT_H2T_MSG_TYPE_RX_FISA_CFG = 0x15, - HTT_H2T_MSG_TYPE_3_TUPLE_HASH_CFG = 0x16, - HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE = 0x17, - HTT_H2T_MSG_TYPE_HOST_PADDR_SIZE = 0x18, - HTT_H2T_MSG_TYPE_RXDMA_RXOLE_PPE_CFG = 0x19, - HTT_H2T_MSG_TYPE_VDEVS_TXRX_STATS_CFG = 0x1a, - HTT_H2T_MSG_TYPE_TX_MONITOR_CFG = 0x1b, - HTT_H2T_SAWF_DEF_QUEUES_MAP_REQ = 0x1c, - HTT_H2T_SAWF_DEF_QUEUES_UNMAP_REQ = 0x1d, - HTT_H2T_SAWF_DEF_QUEUES_MAP_REPORT_REQ = 0x1e, - HTT_H2T_MSG_TYPE_MSI_SETUP = 0x1f, - HTT_H2T_MSG_TYPE_STREAMING_STATS_REQ = 0x20, - HTT_H2T_MSG_TYPE_UMAC_HANG_RECOVERY_PREREQUISITE_SETUP = 0x21, + HTT_H2T_MSG_TYPE_VERSION_REQ = 0x0, + HTT_H2T_MSG_TYPE_TX_FRM = 0x1, + HTT_H2T_MSG_TYPE_RX_RING_CFG = 0x2, + HTT_H2T_MSG_TYPE_STATS_REQ = 0x3, + HTT_H2T_MSG_TYPE_SYNC = 0x4, + HTT_H2T_MSG_TYPE_AGGR_CFG = 0x5, + HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 0x6, + DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX = 0x7, /* no longer used */ + HTT_H2T_MSG_TYPE_WDI_IPA_CFG = 0x8, + HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ = 0x9, + HTT_H2T_MSG_TYPE_AGGR_CFG_EX = 0xa, /* per vdev amsdu subfrm limit */ + HTT_H2T_MSG_TYPE_SRING_SETUP = 0xb, + HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc, + HTT_H2T_MSG_TYPE_ADD_WDS_ENTRY = 0xd, + HTT_H2T_MSG_TYPE_DELETE_WDS_ENTRY = 0xe, + HTT_H2T_MSG_TYPE_RFS_CONFIG = 0xf, + HTT_H2T_MSG_TYPE_EXT_STATS_REQ = 0x10, + HTT_H2T_MSG_TYPE_PPDU_STATS_CFG = 0x11, + HTT_H2T_MSG_TYPE_RX_FSE_SETUP_CFG = 0x12, + HTT_H2T_MSG_TYPE_RX_FSE_OPERATION_CFG = 0x13, + HTT_H2T_MSG_TYPE_CHAN_CALDATA = 0x14, + HTT_H2T_MSG_TYPE_RX_FISA_CFG = 0x15, + HTT_H2T_MSG_TYPE_3_TUPLE_HASH_CFG = 0x16, + HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE = 0x17, + HTT_H2T_MSG_TYPE_HOST_PADDR_SIZE = 0x18, + HTT_H2T_MSG_TYPE_RXDMA_RXOLE_PPE_CFG = 0x19, + HTT_H2T_MSG_TYPE_VDEVS_TXRX_STATS_CFG = 0x1a, + HTT_H2T_MSG_TYPE_TX_MONITOR_CFG = 0x1b, + HTT_H2T_SAWF_DEF_QUEUES_MAP_REQ = 0x1c, + HTT_H2T_SAWF_DEF_QUEUES_UNMAP_REQ = 0x1d, + HTT_H2T_SAWF_DEF_QUEUES_MAP_REPORT_REQ = 0x1e, + HTT_H2T_MSG_TYPE_MSI_SETUP = 0x1f, + HTT_H2T_MSG_TYPE_STREAMING_STATS_REQ = 0x20, + HTT_H2T_MSG_TYPE_UMAC_HANG_RECOVERY_PREREQUISITE_SETUP = 0x21, HTT_H2T_MSG_TYPE_UMAC_HANG_RECOVERY_SOC_START_PRE_RESET = 0x22, - HTT_H2T_MSG_TYPE_RX_CCE_SUPER_RULE_SETUP = 0x23, - HTT_H2T_MSG_TYPE_PRIMARY_LINK_PEER_MIGRATE_RESP = 0x24, - HTT_H2T_MSG_TYPE_TX_LATENCY_STATS_CFG = 0x25, - HTT_H2T_MSG_TYPE_TX_LCE_SUPER_RULE_SETUP = 0x26, - HTT_H2T_MSG_TYPE_SDWF_MSDUQ_RECFG_REQ = 0x27, - HTT_H2T_MSG_TYPE_MLO_LATENCY_STATS_RESP = 0x28, + HTT_H2T_MSG_TYPE_RX_CCE_SUPER_RULE_SETUP = 0x23, + HTT_H2T_MSG_TYPE_PRIMARY_LINK_PEER_MIGRATE_RESP = 0x24, + HTT_H2T_MSG_TYPE_TX_LATENCY_STATS_CFG = 0x25, + HTT_H2T_MSG_TYPE_TX_LCE_SUPER_RULE_SETUP = 0x26, + HTT_H2T_MSG_TYPE_SDWF_MSDUQ_RECFG_REQ = 0x27, + HTT_H2T_MSG_TYPE_MLO_LATENCY_STATS_RESP = 0x28, + HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR = 0x29, + HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO = 0x2a, /* keep this last */ HTT_H2T_NUM_MSGS @@ -11586,6 +11589,320 @@ PREPACK struct htt_h2t_mlo_latency_stats { ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MLO_LATENCY_STATS_NUM_OF_TX_PKT_S)); \ } while (0) +/** + * @brief host -> target msg to provide MSDUQ or MPDUQ for new TID in a peer + * + * MSG_TYPE => HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR + * + * @details + * struct htt_h2t_mpduq_and_msduq_info_hdr: + * HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR message is sent by the host to + * target to tell how many mpduq and msduq info TLVs, in units of bytes, + * are present in the htt payload + * Example message contents: + *------------------------------------------------------------------- + *| htt_h2t_mpduq_and_msduq_info_hdr | + *------------------------------------------------------------------- + *| mpduq_info_tlv -> tid 0 , peer_id 1 | + *------------------------------------------------------------------- + *| mpduq_info_tlv -> tid 6, peer_id 1 | + *------------------------------------------------------------------- + *| msduq_info_tlv -> tid 0, peer_id 1 | + *------------------------------------------------------------------- + *| msduq_info_tlv -> tid 0, peer_id 1 | + *------------------------------------------------------------------- + *| msduq_info_tlv -> tid 6, peer_id 1 | + *------------------------------------------------------------------- + * + * As shown in the above exampple, a single htt buffer can hold multiple mpduq + * and msduq info tlvs, the info within the tlvs will indicate the peer and tid + * to which they belong. + */ + +/* HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR */ +PREPACK struct htt_h2t_mpduq_and_msduq_info_hdr { + A_UINT32 msg_type: 8, /* bits 7:0 */ + payload_size_bytes: 12, /* bits 19:8 */ + reserved_1a: 12; /* bits 31:20 */ +} POSTPACK; + +#define HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_M 0x000FFF00 +#define HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_S 8 +#define HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR_PAYLOAD_SIZE_BYTES_S)); \ + } while (0) + + +/** + * @brief host -> target message to provide mpduq for a tid in a peer + * + * MSG_TYPE => HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO + * + * @details + * struct htt_h2t_mpduq_or_msduq_info: + * HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO message is sent by the host to + * specify the configuration of new MPDUQ/MSDUQ for a tid in a peer. + * This message supports the following configuration information: + * 1. Info provided per MPDUQ: + * upper 32 bit address of 256 byte aligned physical address for mpduq + * mpduq number + * pn address space + * 2. Info provided per MSDUQ: + * upper 32 bit address of 256 byte aligned physical address for msduq + * msduq_number + * service class id + * + * The message is interpreted as follows for mpduq type: + * dword0 - b'7:0 - msg_type: Identifies msduq and mpduq info to FW + * This will be set to 0x2a + * (HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO) + * b'12:8 - msduq_mpduq_type: Indicate whether this TLV is for + * a MPDU queue or MSDU queue, and if for a MSDU queue, + * what type. + * For an MPDU queue, it will be fixed value of 30 based + * on enum HTT_H2T_TID_MSDUQ_MPDUQ_TYPE. + * dword1 - b'31:0 - mpduq_address_39_8: 256 byte aligned mpduq physical + * address, since lowest octet is zero for 256 byte aligned + * physical addresses just passing upper 32 bits of + * 40 bit address + * dword2 - b'23:0 - mpduq_number: Queue number for mpduq, encoded as follows + * [0:11] -> peer_id + * [12:16] -> tid num + * [17:21] -> mpduq_type i.e 30 + * [22:23] -> reserved + * b'31:24 - pn_addr_32_39: Upper 8 bits of 40 bit pn physical address + * dword3 - b'31:0 - pn_addr_0_31: Lower 32 bits of 40 bit pn physical address + * Additional reserved dwords for future use cases + * + * + * The message is interpreted as follows for any msduq type: + * dword0 - b'7:0 - msg_type: Identifies msduq info to fw + * This will be set to 0x2A + * (HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO) + * b'12:8 - msduq_mpduq_type : type of the msduq based on + * enum HTT_H2T_TID_MSDUQ_MPDUQ_TYPE + * dword1 - b'23:0 - tx_msduq_number: Queue number for the msduq, + * encoded as follows + * [0:11] -> peer_id + * [12:16] -> tid num + * [17:21] -> msduq_type + * [22:23] -> reserved + * b'31:24 - svc_class_id : service class id of the msduq + * dword2 - b'31:0 - msduq_address_39_8: 256 byte aligned msduq physical + * address, since lowest octet is zero for 256 byte aligned + * addresses just passing upper 32 bits of 40 bit address + * Additional reserved dwords for future use cases + */ + +/* + * Enum describes the various msduq/mpduq types, + * First 16 types correspond to the standard msduq types for data + * Next come custom flows for specific purposes + * enum 30 is reserved for mpduq type + */ +typedef enum { + HTT_H2T_TID_MSDUQ_NONUDP, /* 0 */ + HTT_H2T_TID_MSDUQ_UDP, /* 1 */ + HTT_H2T_TID_MSDUQ_CUSTOM_0, /* 2 */ + HTT_H2T_TID_MSDUQ_CUSTOM_1, /* 3 */ + HTT_H2T_TID_MSDUQ_CUSTOM_2, /* 4 */ + HTT_H2T_TID_MSDUQ_CUSTOM_3, /* 5 */ + HTT_H2T_TID_MSDUQ_CUSTOM_4, /* 6 */ + HTT_H2T_TID_MSDUQ_CUSTOM_5, /* 7 */ + HTT_H2T_TID_MSDUQ_CUSTOM_6, /* 8 */ + HTT_H2T_TID_MSDUQ_CUSTOM_7, /* 9 */ + HTT_H2T_TID_MSDUQ_CUSTOM_8, /* 10 */ + HTT_H2T_TID_MSDUQ_CUSTOM_9, /* 11 */ + HTT_H2T_TID_MSDUQ_CUSTOM_10, /* 12 */ + HTT_H2T_TID_MSDUQ_CUSTOM_11, /* 13 */ + HTT_H2T_TID_MSDUQ_CUSTOM_12, /* 14 */ + HTT_H2T_TID_MSDUQ_CUSTOM_13, /* 15 */ + + HTT_H2T_TID_MISC_MSDUQ_TYPE_START, /* 16 */ + HTT_H2T_TID_MSDUQ_HOL = HTT_H2T_TID_MISC_MSDUQ_TYPE_START, /* also 16 */ + HTT_H2T_TID_MSDUQ_MCAST, /* 17 */ + HTT_H2T_TID_MSDUQ_FAST_ROAMING, /* 18 */ + + HTT_H2T_TID_MSDUQ_DATA_TYPE_END = 29, /* 29 */ + HTT_H2T_TID_MPDUQ_TYPE, /* 30 */ + HTT_H2T_TID_MSDUQ_MPDUQ_TYPE_END, /* 31 */ +} HTT_H2T_TID_MSDUQ_MPDUQ_TYPE; + +/* + * Enum to denote tid nums that can be used + * first 8 {0 - 7} numbers correspond to data access category + * {8 - 15} are for user defined usecases + * 16 is used to denote the non-qos tid + */ +typedef enum { + HTT_H2T_DEFAULT_TID_NUM = 0, + HTT_H2T_MAX_VALID_DATA_TID_NUM = 7, + HTT_H2T_NON_QOS_TID_NUM = 16, + HTT_H2T_MAX_TID_NUM = 31, +} H2T_TX_TID; + +/* HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO */ +PREPACK struct htt_h2t_mpduq_or_msduq_info { + A_UINT32 msg_type: 8, /* bits 7:0 */ + msduq_mpduq_type: 5, /* bits 12:8 */ + reserved0: 19; /* bits 31:13 */ + + union { + struct { + A_UINT32 mpduq_address_39_8; /* bits 31:0 */ + A_UINT32 mpduq_number: 24, /* bits 23:0 */ + pn_addr_39_32: 8; /* bits 31:24 */ + A_UINT32 pn_addr_31_0; /* bits 31:0 */ + A_UINT32 reserved1a; /* bits 31:0 */ + A_UINT32 reserved1b; /* bits 31:0 */ + A_UINT32 reserved1c; /* bits 31:0 */ + A_UINT32 reserved1d; /* bits 31:0 */ + A_UINT32 reserved1e; /* bits 31:0 */ + A_UINT32 reserved1f; /* bits 31:0 */ + }; + struct { + A_UINT32 tx_msduq_number: 24, /* bits 23:0 */ + svc_class_id: 8; /* bits 31:24 */ + A_UINT32 msduq_address_39_8; /* bits 31:0 */ + A_UINT32 reserved2a; /* bits 31:0 */ + A_UINT32 reserved2b; /* bits 31:0 */ + A_UINT32 reserved2c; /* bits 31:0 */ + A_UINT32 reserved2d; /* bits 31:0 */ + A_UINT32 reserved2e; /* bits 31:0 */ + A_UINT32 reserved2f; /* bits 31:0 */ + A_UINT32 reserved2g; /* bits 31:0 */ + }; + }; +} POSTPACK; + +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_M 0x000001F0 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S 8 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_NUM_MSDUQ_MPDUQ_TYPE_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_M 0x00000FFF +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_S 0 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_M 0x0001F000 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_S 12 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_TID_NUM_S)); \ + } while (0) + + +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_M 0x003E0000 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_S 17 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_MSDUQ_MPDUQ_TYPE_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_M 0xFFFFFFFF +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_S 0 +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_ADDRESS_39_8_S)); \ + } while (0) + + +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER_M 0x00FFFFFF +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER_S 0 +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER_GET(_var) \ + (((_var) & HTT_H2T_MSG_MPDUQ_INFO_MPDUQ_NUMBER_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_INFO_MPDUQ_NUMBER_S)); \ + } while (0) + + +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_M 0xFF000000 +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_S 24 +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_39_32_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_M 0xFFFFFFFF +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_S 0 +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_INFO_PN_ADDRESS_31_0_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_M 0x00FFFFFF +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_S 0 +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_M) >> \ + HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_S) +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MSDUQ_INFO_TX_MSDUQ_NUMBER_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_M 0xFF000000 +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_S 24 +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_M) >> \ + HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_S) +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MSDUQ_INFO_SVC_CLASS_ID_S)); \ + } while (0) + +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_M 0xFFFFFFFF +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_S 0 +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_M) >> \ + HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_S) +#define HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MSDUQ_INFO_MSDUQ_ADDRESS_39_8_S)); \ + } while (0) /*=== target -> host messages ===============================================*/ From 9f650725ec4766e04026b268b76f33b03063b635 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 23 May 2025 06:01:35 -0700 Subject: [PATCH 100/306] fw-api: CL 29280684 - update fw common interface files Change-Id: I96b1742bdf575daa0f5d7e8189de942217cad3b5 CRs-Fixed: 3830439 --- fw/wmi_services.h | 2 +- fw/wmi_tlv_defs.h | 17 ++- fw/wmi_unified.h | 260 +++++++++++++++++++++++++++++++++++++++++++++- fw/wmi_version.h | 2 +- 4 files changed, 273 insertions(+), 8 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index c1a7fe50d9bf..2305cad7beee 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -701,7 +701,7 @@ typedef enum { WMI_SERVICE_APF_DATA_OFFLOAD_SUPPORT_ENABLED = 442, /* Indicates FW support for APFv6 handling offloads and disable QC data offloads */ WMI_SERVICE_PER_VDEV_TWT_RESP_DISABLE_SUPPORT = 443, /* FW supports vdev level TWT responder disable */ WMI_SERVICE_VENDOR_OUI_ACTION_V2 = 444, /* FW supports vendor OUI action version 2 */ - + WMI_SERVICE_HW_BLACKLIST_CHAN_SUPPORT = 445, /* Indicates FW support for computing and sending the HW channel blacklist for the current country and applicable power mode */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 10f7ab407ce6..80287b318db8 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1481,6 +1481,8 @@ typedef enum { WMITLV_TAG_STRUC_wmi_mlo_link_ttlm_complete_fixed_param, WMITLV_TAG_STRUC_wmi_ctrl_path_sta_dar_stats_struct, WMITLV_TAG_STRUC_wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_fixed_param, + WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_data, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2380,6 +2382,7 @@ typedef enum { OP(WMI_PDEV_WIFI_RADAR_CAPABILITIES_EVENTID) \ OP(WMI_VDEV_VBSS_CONFIG_EVENTID) \ OP(WMI_OPT_DP_DIAG_EVENTID) \ + OP(WMI_HW_BLACKLIST_CHAN_EVENTID) \ /* add new EVT_LIST elements above this line */ @@ -6977,7 +6980,9 @@ WMITLV_CREATE_PARAM_STRUC(WMI_REG_CHAN_LIST_CC_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_regulatory_chan_priority_struct, reg_chan_priority, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_regulatory_fcc_rule_struct, reg_fcc_rule, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_reg_chan_list_cc_ext_additional_params, reg_more_data, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_regulatory_rule_meta_data, reg_meta_data, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_regulatory_rule_meta_data, reg_meta_data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hw_blacklist_chan_fixed_param, hw_blacklist_chan_fixed_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hw_blacklist_chan_data, hw_blacklist_chan_data, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_REG_CHAN_LIST_CC_EXT_EVENTID); /* WMI AFC info event */ @@ -6987,9 +6992,17 @@ WMITLV_CREATE_PARAM_STRUC(WMI_REG_CHAN_LIST_CC_EXT_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_afc_power_event_param, wmi_afc_power_event_param, afc_power_event_param, WMITLV_SIZE_FIX)\ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_6g_afc_frequency_info, freq_info_array, WMITLV_SIZE_VAR)\ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_6g_afc_channel_info, channel_info_array, WMITLV_SIZE_VAR)\ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_afc_chan_eirp_power_info, chan_eirp_power_info_array, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_afc_chan_eirp_power_info, chan_eirp_power_info_array, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hw_blacklist_chan_fixed_param, hw_blacklist_chan_fixed_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hw_blacklist_chan_data, hw_blacklist_chan_data, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_AFC_EVENTID); +/* HW blacklist channels for the current country code */ +#define WMITLV_TABLE_WMI_HW_BLACKLIST_CHAN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_fixed_param, wmi_hw_blacklist_chan_fixed_param, hw_blacklist_chan_fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hw_blacklist_chan_data, hw_blacklist_chan_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_HW_BLACKLIST_CHAN_EVENTID); + /* Indicate LPI AP detect or not to Host */ #define WMITLV_TABLE_WMI_C2C_DETECT_EVENTID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_c2c_detect_event_fixed_param, wmi_c2c_detect_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 63c6b5e5568c..bee7a553655d 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -2533,6 +2533,8 @@ typedef enum { WMI_AFC_EVENTID, WMI_REG_CHAN_LIST_CC_EXT2_EVENTID, /* DEPRECATED */ WMI_C2C_DETECT_EVENTID, + /* WMI event to send the HW channel blacklist during the CTL blob update */ + WMI_HW_BLACKLIST_CHAN_EVENTID, /** Events for TWT(Target Wake Time) of STA and AP */ WMI_TWT_ENABLE_COMPLETE_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_TWT), @@ -5006,8 +5008,16 @@ typedef struct { * enabled by both host configuration and FW capability. * Refer to the below definitions of * WMI_RSRC_CFG_HOST_SERVICE_FLAG_ACTION_OUI_V2_GET and SET. + * Bit 21 + * This bit will be set by host to inform FW that HW blacklist + * channel is supported in host. Based on this flag, FW will do + * CTL generation for all the IEEE channels allowed in the VLP + * and SP power for the current county and update host in the + * below WMI Events: + * WMI_REG_CHAN_LIST_CC_EXT_EVENTID, WMI_AFC_EVENTID, and + * WMI_HW_BLACKLIST_CHAN_EVENTID * - * Bits 31:21 - Reserved + * Bits 31:22 - Reserved */ A_UINT32 host_service_flags; @@ -5562,6 +5572,12 @@ typedef struct { #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_ACTION_OUI_V2_SET(host_service_flags, val) \ WMI_SET_BITS(host_service_flags, 20, 1, val) +/* This bit is used to inform FW to send HW Blacklist channels to host */ +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_HOST_SUPPORT_HW_BLACKLIST_CHANNEL_SUPPORT_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 21, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_HOST_SUPPORT_HW_BLACKLIST_CHANNEL_SUPPORT_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 21, 1, val) + #define WMI_RSRC_CFG_CARRIER_CFG_CHARTER_ENABLE_GET(carrier_config) \ WMI_GET_BITS(carrier_config, 0, 1) @@ -39568,9 +39584,10 @@ typedef struct { A_UINT32 num_6g_reg_rules_client_lpi[WMI_REG_CLIENT_MAX]; A_UINT32 num_6g_reg_rules_client_vlp[WMI_REG_CLIENT_MAX]; /* - * NOTE: no further fields can be added into this struct, due to - * message buffer size limitations in certain targets for the - * WMI_REG_CHAN_LIST_CC_EXT_EVENT message. + * NOTE: We cannot add new parameters to the fixed param TLV though + * we have enough buffer size (WMI_SVC_MSG_SIZE) for the given WMI event. + * This is due to a crash seen in the host parsing logic of this fixed param. + * New params can be added in the same message but in other TLVs. */ /* * This fixed_param TLV is followed by the following TLVs: @@ -39586,6 +39603,10 @@ typedef struct { * - wmi_regulatory_rule_meta_data reg_meta_data[] * struct used to fill meta information specific to new reg rules * getting added(i.e. from C2C onwards). + * - wmi_hw_blacklist_chan_fixed_param hw_blacklist_chan_fixed_param[0 or 1] + * optional TLV for reporting HW channel blacklist meta-data. + * - wmi_hw_blacklist_chan_data, hw_blacklist_chan_data[] + * optional TLV for reporting HW channel blacklist information. */ } wmi_reg_chan_list_cc_event_ext_fixed_param; @@ -39738,6 +39759,10 @@ typedef struct { * This TLV array contains zero or more TLVs of channel CFI and * EIRP power values for each of the total number of channels * per global operating class. + * 6. wmi_hw_blacklist_chan_fixed_param hw_blacklist_chan_fixed_param[] + * optional meta-data for HW channel blacklist + * 7. wmi_hw_blacklist_chan_data hw_blacklist_chan_data[] + * optional HW channel blacklist information */ } wmi_afc_event_fixed_param; @@ -39830,6 +39855,233 @@ typedef struct { A_UINT32 eirp_pwr; /* maximum permissible EIRP available for above CFI in dBm, value is stored in 0.01 dBm steps */ } wmi_afc_chan_eirp_power_info; + +typedef enum { + WMI_11BE_PUNCTURE_PATTERN_80MHZ_MINUS_20MHZ_0x1 = 0, + WMI_11BE_PUNCTURE_PATTERN_80MHZ_MINUS_20MHZ_0x2 = 1, + WMI_11BE_PUNCTURE_PATTERN_80MHZ_MINUS_20MHZ_0x4 = 2, + WMI_11BE_PUNCTURE_PATTERN_80MHZ_MINUS_20MHZ_0x8 = 3, + WMI_11BE_PUNCTURE_PATTERN_80MHZ_MAX, +} WMI_11BE_PUNCTURE_PATTERNS_80MHZ; + +typedef enum { + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x1 = 0, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x2 = 1, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x4 = 2, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x8 = 3, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x10 = 4, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x20 = 5, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x40 = 6, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_20MHZ_0x80 = 7, + + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_40MHZ_0x0C = 8, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_40MHZ_0x03 = 9, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_40MHZ_0xC0 = 10, + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MINUS_40MHZ_0x30 = 11, + + WMI_11BE_PUNCTURE_PATTERN_160MHZ_MAX, +} WMI_11BE_PUNCTURE_PATTERNS_160MHZ; + +typedef enum { + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0xC = 0, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0x3 = 1, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0xC0 = 2, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0x30 = 3, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0xC00 = 4, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0x300 = 5, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0xC000 = 6, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_40MHZ_0x3000 = 7, + + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_80MHZ_0xF = 8, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_80MHZ_0xF0 = 9, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_80MHZ_0xF00 = 10, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_80MHZ_0xF000 = 11, + + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xF003 = 12, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xF00C = 13, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xF030 = 14, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xF0C0 = 15, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xF300 = 16, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xFC00 = 17, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0x003F = 18, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0x00CF = 19, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0x030F = 20, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0x0C0F = 21, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0x300F = 22, + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MINUS_120MHZ_0xC00F = 23, + + WMI_11BE_PUNCTURE_PATTERN_320MHZ_MAX, +} WMI_11BE_PUNCTURE_PATTERNS_320MHZ; + +typedef enum { + /* + * bits 16-19 of "blacklist_msg_info" in wmi_hw_blacklist_chan_fixed_param. + * This status code intimates host whether the TLV sent by + * Halphy is to update the master channel list or clear it. + */ + WMI_HW_BLACKLIST_CHAN_SP_UPDATE = 0, + WMI_HW_BLACKLIST_CHAN_VLP_UPDATE, + /* the below enums are added for future scope */ + WMI_HW_BLACKLIST_CHAN_SP_CLEAR, + WMI_HW_BLACKLIST_CHAN_VLP_CLEAR, + WMI_HW_BLACKLIST_CHAN_UPDATE_ALL, + WMI_HW_BLACKLIST_CHAN_CLEAR_ALL, + WMI_HW_BLACKLIST_CHAN_INVALID = 15, +} WMI_HW_BLACKLIST_CHAN_RESP_CMD_CODE; + +typedef enum { + /* + * bit 20, "blacklist_msg_info" flag in wmi_hw_blacklist_chan_fixed_param + * This bit field informs the host whether all the blacklist channel + * information has been sent, or if further messages will follow to + * deliver the remaining information. + */ + WMI_HW_BLACKLIST_CHAN_EVENT_DONE = 0, /* Indicates it is the last event */ + WMI_HW_BLACKLIST_CHAN_EVENT_MORE = 1, /* Indicates more evts will follow */ +} WMI_HW_BLACKLIST_CHAN_DATA_EVENT_FLAG; + +#define WMI_GET_BLACKLIST_MSG_INFO_WMI_EVT_SEQ_NUM(flag) \ + WMI_GET_BITS(flag, 0, 8) +#define WMI_SET_BLACKLIST_MSG_INFO_WMI_EVT_SEQ_NUM(flag, val) \ + WMI_SET_BITS(flag, 0, 8, val) + +#define WMI_GET_BLACKLIST_MSG_INFO_TOTAL_WMI_EVT_NUM(flag) \ + WMI_GET_BITS(flag, 8, 8) +#define WMI_SET_BLACKLIST_MSG_INFO_TOTAL_WMI_EVT_NUM(flag, val) \ + WMI_SET_BITS(flag, 8, 8, val) + +#define WMI_GET_BLACKLIST_MSG_INFO_RESP_CODE(flag) \ + WMI_GET_BITS(flag, 16, 4) +#define WMI_SET_BLACKLIST_MSG_INFO_RESP_CODE(flag, val) \ + WMI_SET_BITS(flag, 16, 4, val) + +#define WMI_GET_BLACKLIST_MSG_INFO_EVT_FLAG(flag) \ + WMI_GET_BITS(flag, 20, 1) +#define WMI_SET_BLACKLIST_MSG_INFO_EVT_FLAG(flag, val) \ + WMI_SET_BITS(flag, 20, 1, val) + +#define WMI_GET_BLACKLIST_CHANNELS_TOTAL_NUM_CHAN(flag) \ + WMI_GET_BITS(flag, 0, 16) +#define WMI_SET_BLACKLIST_CHANNELS_TOTAL_NUM_CHAN(flag, val) \ + WMI_SET_BITS(flag, 0, 16, val) + +#define WMI_GET_BLACKLIST_CHANNELS_CURRENT_NUM_CHAN(flag) \ + WMI_GET_BITS(flag, 16, 16) +#define WMI_SET_BLACKLIST_CHANNELS_CURRENT_NUM_CHAN(flag, val) \ + WMI_SET_BITS(flag, 16, 16, val) + +typedef struct { + /** TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_fixed_param*/ + A_UINT32 tlv_header; + A_UINT32 phy_id; + union { + A_UINT32 blacklist_msg_info; + /* + * bit 7 - 0 -> Current WMI event sequence number + * bit 15 - 8 -> Total number of WMI events [For debugging only] + * bit 19 - 16 -> ENUM "WMI_HW_BLACKLIST_CHAN_RESP_CMD_CODE" + * bit 20 -> ENUM "WMI_HW_BLACKLIST_CHAN_DATA_EVENT_FLAG" + * bit 31 - 21 -> Reserved + */ + struct { + A_UINT32 + blacklist_wmi_seq_num: 8, + blacklist_wmi_total_num: 8, + blacklist_resp_code: 4, + blacklist_event_flag:1, + reserved: 11; + }; + }; + /* + * bit 15 - 0 -> Total number of HW blacklist channels + * bit 31 - 16 -> number of HW blacklist channels in current WMI + */ + union { + A_UINT32 num_hw_blacklist_channels; + struct { + A_UINT32 + total_num_chan: 16, + current_num_chan: 16; + }; + }; +} wmi_hw_blacklist_chan_fixed_param; + +#define WMI_GET_FREQ_INFO_PRI20_BITMAP(flag) \ + WMI_GET_BITS(flag, 0, 16) +#define WMI_SET_FREQ_INFO_PRI20_BITMAP(flag, val) \ + WMI_SET_BITS(flag, 0, 16, val) + +#define WMI_GET_FREQ_INFO_CHAN_CENTER_FREQ(flag) \ + WMI_GET_BITS(flag, 16, 16) +#define WMI_SET_FREQ_INFO_CHAN_CENTER_FREQ(flag, val) \ + WMI_SET_BITS(flag, 16, 16, val) + +#define WMI_GET_CHAN_LIST_META_DATA_POWER_MODE(flag) \ + WMI_GET_BITS(flag, 0, 4) +#define WMI_SET_CHAN_LIST_META_DATA_POWER_MODE(flag, val) \ + WMI_SET_BITS(flag, 0, 4, val) + +#define WMI_GET_CHAN_LIST_META_DATA_MAX_BW(flag) \ + WMI_GET_BITS(flag, 4, 8) +#define WMI_SET_CHAN_LIST_META_DATA_MAX_BW(flag, val) \ + WMI_SET_BITS(flag, 4, 8, val) + +#define WMI_GET_PUNCTURE_PATTERN_BITMAP(flag) \ + WMI_GET_BITS(flag, 0, 24) +#define WMI_SET_PUNCTURE_PATTERN_BITMAP(flag, val) \ + WMI_SET_BITS(flag, 0, 24, val) + +typedef struct { + /** TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_data */ + A_UINT32 tlv_header; + /* + * bit 15 - 0 -> bitmap representing a set of 20MHz primary channels + * bit 31 - 16 -> channel center frequency in MHz for the given Max BW + * in "chan_list_meta_data" + */ + union { + A_UINT32 freq_info; + struct { + A_UINT32 + pri20_bitmap: 16, + chan_center_freq: 16; + }; + }; + /* + * bit 3 - 0 -> Power mode "WMI_6GHZ_REG_PWRMODE_TYPE" + * bit 11 - 4 -> Max BW with enum "wmi_channel_width" + * bit 31 - 12 -> reserved + */ + union { + A_UINT32 chan_list_meta_data; + struct { + A_UINT32 + power_mode: 4, + max_bw: 8, + reserved1: 20; + }; + }; + /* + * bit represents blacklisted puncture pattern based on enums + * WMI_11BE_PUNCTURE_PATTERNS_320MHZ, WMI_11BE_PUNCTURE_PATTERNS_160MHZ, + * WMI_11BE_PUNCTURE_PATTERNS_80MHZ + * bit 23 - 0 -> bitmap representing a set of puncture patterns of the + * given bandwidth. The bandwidth is represented by + * bits 8-15 of A_UINT32 chan_list_meta_data + * bit 31 - 24 -> reserved for future puncture patterns + */ + union { + A_UINT32 puncture_pattern_bitmap_info; + struct { + A_UINT32 + puncture_pattern_bitmap: 24, + reserved2: 8; + }; + }; +} wmi_hw_blacklist_chan_data; + typedef struct { A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_11d_scan_start_cmd_fixed_param */ A_UINT32 vdev_id; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index eacac7fbc2fb..a510a9740412 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1616 +#define __WMI_REVISION_ 1617 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 19977b9880cf43eee88306dd99203114385151f6 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 23 May 2025 06:03:12 -0700 Subject: [PATCH 101/306] fw-api: CL 29289444 - update fw common interface files Change-Id: I8f0f6bb38be706e781572e0cb7b1319e6d5db3c5 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 2305cad7beee..9868736ab728 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -702,6 +702,7 @@ typedef enum { WMI_SERVICE_PER_VDEV_TWT_RESP_DISABLE_SUPPORT = 443, /* FW supports vdev level TWT responder disable */ WMI_SERVICE_VENDOR_OUI_ACTION_V2 = 444, /* FW supports vendor OUI action version 2 */ WMI_SERVICE_HW_BLACKLIST_CHAN_SUPPORT = 445, /* Indicates FW support for computing and sending the HW channel blacklist for the current country and applicable power mode */ + WMI_SERVICE_NDP_DFS_CHANNEL_SUPPORT = 446, /* FW supports forming NDP on DFS channels */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_version.h b/fw/wmi_version.h index a510a9740412..e1c2a794f8ef 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1617 +#define __WMI_REVISION_ 1618 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From c157f445e58fd21e18a068a06bc1683c9d3465a9 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 23 May 2025 06:04:42 -0700 Subject: [PATCH 102/306] fw-api: CL 29289452 - update fw common interface files Change-Id: I02fd6358549ceb352efc3d55cab518fb1f934965 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 7 +++++++ fw/wmi_unified.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 80287b318db8..2d36b4b43067 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1483,6 +1483,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_fixed_param, WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_data, + WMITLV_TAG_STRUC_wmi_pdev_suspend_event_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2383,6 +2384,7 @@ typedef enum { OP(WMI_VDEV_VBSS_CONFIG_EVENTID) \ OP(WMI_OPT_DP_DIAG_EVENTID) \ OP(WMI_HW_BLACKLIST_CHAN_EVENTID) \ + OP(WMI_PDEV_SUSPEND_EVENTID) \ /* add new EVT_LIST elements above this line */ @@ -6827,6 +6829,11 @@ WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_STATS_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param, wmi_pdev_resume_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_RESUME_EVENTID); +/* pdev suspend event */ +#define WMITLV_TABLE_WMI_PDEV_SUSPEND_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_suspend_event_fixed_param, wmi_pdev_suspend_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SUSPEND_EVENTID); + /* SAP Authentication offload event */ #define WMITLV_TABLE_WMI_SAP_OFL_ADD_STA_EVENTID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param, wmi_sap_ofl_add_sta_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index bee7a553655d..8342e89591c8 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -2167,6 +2167,7 @@ typedef enum { /* send pdev resume event to host after pdev resume. */ WMI_PDEV_RESUME_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SUSPEND), + WMI_PDEV_SUSPEND_EVENTID, /** WOW wake up host event.generated in response to WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID. will cary wake reason */ @@ -31651,6 +31652,11 @@ typedef struct { A_UINT32 pdev_id; } wmi_pdev_resume_event_fixed_param; +/** WMI_PDEV_SUSPEND_EVENTID: generated in response to WMI_PDEV_SUSPEND_CMDID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_suspend_event_fixed_param */ + A_UINT32 pdev_id; +} wmi_pdev_suspend_event_fixed_param; /** value representing all modules */ From efed32fa4d6cfe5ac3c8152a3e56259bdf962e20 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 24 May 2025 06:01:33 -0700 Subject: [PATCH 103/306] fw-api: CL 29309837 - update fw common interface files Change-Id: I799781ea49334450a183b6920f280656284264d5 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 9868736ab728..8aafd2da3fa3 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -703,6 +703,7 @@ typedef enum { WMI_SERVICE_VENDOR_OUI_ACTION_V2 = 444, /* FW supports vendor OUI action version 2 */ WMI_SERVICE_HW_BLACKLIST_CHAN_SUPPORT = 445, /* Indicates FW support for computing and sending the HW channel blacklist for the current country and applicable power mode */ WMI_SERVICE_NDP_DFS_CHANNEL_SUPPORT = 446, /* FW supports forming NDP on DFS channels */ + WMI_SERVICE_WFD_R2 = 447, /* Indicates FW supports WiFi-Direct R2 */ WMI_MAX_EXT2_SERVICE From c07170c9e793b6113ebd4cd56780e0475ef40358 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 24 May 2025 06:03:15 -0700 Subject: [PATCH 104/306] fw-api: CL 29309854 - update fw common interface files Change-Id: I0c268851993df68466a1e951e147e18a1bc27579 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 6 ++++++ fw/wmi_unified.h | 36 ++++++++++++++++++++++++++++++++++++ fw/wmi_version.h | 2 +- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 2d36b4b43067..af1087cb216f 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1484,6 +1484,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_fixed_param, WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_data, WMITLV_TAG_STRUC_wmi_pdev_suspend_event_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2048,6 +2049,7 @@ typedef enum { OP(WMI_NDP_SET_LATENCY_TPUT_CMDID) \ OP(WMI_MLO_LINK_TTLM_COMPLETE_CMDID) \ OP(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID) \ + OP(WMI_BPF_SET_APF_MODE_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -5772,6 +5774,10 @@ WMITLV_CREATE_PARAM_STRUC(WMI_SAWF_EZMESH_HOP_COUNT_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID); +#define WMITLV_TABLE_WMI_BPF_SET_APF_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param, wmi_bpf_set_apf_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_APF_MODE_CMDID); + /************************** TLV definitions of WMI events *******************************/ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 8342e89591c8..14fd26ac16c2 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -1580,6 +1580,7 @@ typedef enum { WMI_BPF_SET_VDEV_WORK_MEMORY_CMDID, WMI_BPF_GET_VDEV_WORK_MEMORY_CMDID, WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID, + WMI_BPF_SET_APF_MODE_CMDID, /** WMI commands related to monitor mode. */ WMI_MNT_FILTER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MONITOR), @@ -34278,6 +34279,40 @@ typedef struct wmi_bpf_set_supported_offload_bitmap_cmd_s { A_UINT32 ofld_bitmap; } wmi_bpf_set_supported_offload_bitmap_cmd_fixed_param; +/* APF modes: */ +typedef enum { + /* Default value: 0 */ + wmi_apf_mode_default = 0, + + /* Mode 1: value 1: APF to operate only during system suspend. */ + wmi_apf_mode_system_suspend = 1, + + /* Mode 2: value 2: + * Downgrade the APF capability of the firmware to a lower version + * (from V6 to V4). + */ + wmi_apf_mode_capability_v4 = 2, + + /* Mode combination: value 3: + * Downgrade to APFv4 and enable only in system suspend. + */ + wmi_apf_mode_system_suspend_and_capability_v4 = 3, + + /* Mode 3: value 4: Turn off APF completely. */ + wmi_apf_mode_off = 4, +} wmi_apf_modes; + +typedef struct wmi_bpf_set_apf_mode_cmd_s { + A_UINT32 tlv_header; /* tag = WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param */ + A_UINT32 vdev_id; + /* apf_mode: + * Host indicates the APF mode (or combination of modes). + * Refer to the wmi_apf_modes enum for the interpretation of the + * apf_mode value. + */ + A_UINT32 apf_mode; /* holds a wmi_apf_modes value */ +} wmi_bpf_set_apf_mode_cmd_fixed_param; + #define AES_BLOCK_LEN 16 /* in bytes */ #define FIPS_KEY_LENGTH_128 16 /* in bytes */ @@ -39169,6 +39204,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_NDP_SET_LATENCY_TPUT_CMDID); WMI_RETURN_STRING(WMI_MLO_LINK_TTLM_COMPLETE_CMDID); WMI_RETURN_STRING(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID); + WMI_RETURN_STRING(WMI_BPF_SET_APF_MODE_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index e1c2a794f8ef..9f084167009b 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1618 +#define __WMI_REVISION_ 1619 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From aa70eff754550818556bbbf4f50f9271ac663e3e Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 24 May 2025 06:05:22 -0700 Subject: [PATCH 105/306] fw-api: CL 29310378 - update fw common interface files Change-Id: I19b5183523f1d114d92f9505d7dd3600d218fb3d CRs-Fixed: 3830439 --- fw/htt.h | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) diff --git a/fw/htt.h b/fw/htt.h index 7a879225a71f..f1b19434dfd4 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -268,9 +268,10 @@ * 3.138 Add T2H MLO_LATENCY_REQ, H2T _RESP msg defs. * 3.139 Add CLASS_INFO_IDX field in MLO_R_PEER_MAP msg. * 3.140 Add H2T MPDUQ_AND_MSDUQ_INFO_HDR and MPDUQ_OF_MSDUQ_INFO defs. + * 3.141 Add H2T HTT_AST_INFO for RxOLE. */ #define HTT_CURRENT_VERSION_MAJOR 3 -#define HTT_CURRENT_VERSION_MINOR 140 +#define HTT_CURRENT_VERSION_MINOR 141 #define HTT_NUM_TX_FRAG_DESC 1024 @@ -924,6 +925,7 @@ enum htt_h2t_msg_type { HTT_H2T_MSG_TYPE_MLO_LATENCY_STATS_RESP = 0x28, HTT_H2T_MSG_TYPE_MPDUQ_AND_MSDUQ_INFO_HDR = 0x29, HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO = 0x2a, + HTT_H2T_MSG_TYPE_AST_INFO = 0x2b, /* keep this last */ HTT_H2T_NUM_MSGS @@ -11905,6 +11907,178 @@ PREPACK struct htt_h2t_mpduq_or_msduq_info { } while (0) +/* + * @brief host -> target HTT_AST_INFO message + * + * MSG_TYPE => HTT_H2T_MSG_TYPE_AST_INFO + * + * The message would appear as follows: + * |31 24|23 21|20|19|18|17|16|15 8|7 0| + * |--------------+-------------------------------------+-------------------| + * |ast_max_search| ast_table_size | msg_type | + * |------------------------------------------------------------------------| + * | ast_base_addr_31_0 | + * |------------------------------------------------------------------------| + * | ase_hash_key1 | + * |------------------------------------------------------------------------| + * | ase_hash_key2 | + * |------------------------------------------------------------------------| + * | ase_hash_key3 | + * |--------------------+--+--+--+--+--+----------------+-------------------| + * | reserved |L |K |J |I |H | tmo |ast_base_addr_39_32| + * |--------------------+--+--+--+--+--+----------------+-------------------| + * + * The message is interpreted as follows: + * dword0 b'7:0 - msg_type + * 0 b'23:8 - ast table size + * b'31:24 - ast max search + * dword1 - b'31:0 - ast table base address + * dword2 - b'31:0 - ase hash key 1 + * dword3 - b'31:0 - ase hash key 2 + * dword4 - b'31:0 - ase hash key 3 + * dword5 - b'7:0 - ast_base_addr_39_32 + * b'15:8 - ast_timeout_threshold + * b'16 - H - ast cache disable knob + * b'17 - I - ast cache faluires disable knob + * b'18 - J - ast cache cmd read bypass + * Bypassing the reads from memory when an entry is not + * found in cache, in case of full cache commands, + * write back or invalidate commands. + * b'19 - K - ast cache write back fx + * If this fix is disabled, then any write back command + * for a cache line will also lead to invalidation of + * that cache line. + * b'20 - L - ast cache only entry command fix + * If enabled, a new cache entry will always be created + * for requests for which matching data was found + * neither in cache nor in memory. + */ +PREPACK struct htt_ast_info_t { + A_UINT32 msg_type: 8, + ast_table_size: 16, /* number of entries in AST */ + ast_max_search: 8; + A_UINT32 ast_base_addr; /* base address of the AST table */ + A_UINT32 ase_hash_key1; + A_UINT32 ase_hash_key2; + A_UINT32 ase_hash_key3; + A_UINT32 ast_base_addr_39_32: 8, /* 7:0 */ + ast_timeout_threshold: 8, /* 15:8 */ + ast_cache_disable: 1, /* 16 */ + ast_cache_failures_disable: 1, /* 17 */ + ast_cache_cmd_read_bypass_dis: 1, /* 18 */ + ast_cache_write_back_fix_dis: 1, /* 19 */ + ast_cache_only_entry_cmd_fix_dis: 1, /* 20 */ + reserved: 11; +} POSTPACK; + + +#define HTT_AST_INFO_SZ (sizeof(struct htt_ast_info_t)) + +/* DWORD0 */ +#define HTT_AST_INFO_AST_TABLE_SIZE_M 0x00ffff00 +#define HTT_AST_INFO_AST_TABLE_SIZE_S 8 +#define HTT_AST_INFO_AST_TABLE_SIZE_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_TABLE_SIZE_M) >> \ + HTT_AST_INFO_AST_TABLE_SIZE_S) +#define HTT_AST_INFO_AST_TABLE_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_TABLE_SIZE, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_TABLE_SIZE__S)); \ + } while (0) + +#define HTT_AST_INFO_AST_MAX_SEARCH_M 0xff000000 +#define HTT_AST_INFO_AST_MAX_SEARCH_S 24 +#define HTT_AST_INFO_AST_MAX_SEARCH_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_MAX_SEARCH_M) >> \ + HTT_AST_INFO_AST_MAX_SEARCH_S) +#define HTT_AST_INFO_AST_MAX_SEARCH_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_MAX_SEARCH, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_MAX_SEARCH_S)); \ + } while (0) + + +/* DWORD5 */ + +#define HTT_AST_INFO_AST_BASE_ADDR_39_32_M 0x000000ff +#define HTT_AST_INFO_AST_BASE_ADDR_39_32_S 0 +#define HTT_AST_INFO_AST_BASE_ADDR_39_32_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_BASE_ADDR_39_32_M) >> \ + HTT_AST_INFO_AST_BASE_ADDR_39_32_S) +#define HTT_AST_INFO_AST_BASE_ADDR_39_32_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_BASE_ADDR_39_32, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_BASE_ADDR_39_32_S)); \ + } while (0) + +#define HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_M 0x0000ff00 +#define HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_S 8 +#define HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_M) >> \ + HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_S) +#define HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_TIMEOUT_THRESHOLD, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_TIMEOUT_THRESHOLD_S)); \ + } while (0) + +#define HTT_AST_INFO_AST_CACHE_DISABLE_M 0x00010000 +#define HTT_AST_INFO_AST_CACHE_DISABLE_s 16 +#define HTT_AST_INFO_AST_CACHE_DISABLE_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_CACHE_DISABLE_M) >> \ + HTT_AST_INFO_AST_CACHE_DISABLE_s) +#define HTT_AST_INFO_AST_CACHE_DISABLE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_CACHE_DISABLE, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_CACHE_DISABLE_S)); \ + } while (0) + +#define HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_M 0x00020000 +#define HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_s 17 +#define HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_M) >> \ + HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_s) +#define HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_CACHE_FALUIRES_DISABLE_S)); \ + } while (0) + +#define HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_M 0x00040000 +#define HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_s 18 +#define HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_M) >> \ + HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_s) +#define HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_CACHE_CMD_READ_BYPASS_DIS_S)); \ + } while (0) + +#define HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_M 0x00080000 +#define HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_s 19 +#define HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_M) >> \ + HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_s) +#define HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_CACHE_WRITE_BACK_FIX_DIS_S)); \ + } while (0) + +#define HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_M 0x00100000 +#define HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_s 20 +#define HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_GET(_var) \ + (((_var) & HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_M) >> \ + HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_s) +#define HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS, _val); \ + ((_var) |= ((_val) << HTT_AST_INFO_AST_CACHE_ONLY_ENTRY_CMD_FIX_DIS_S)); \ + } while (0) + + + /*=== target -> host messages ===============================================*/ From 2771bde5d7a1f5f730d7445ccf651b7ef160ed0e Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 25 May 2025 06:01:33 -0700 Subject: [PATCH 106/306] fw-api: CL 29310832 - update fw common interface files Change-Id: I68f72ec81c2d9fbcc19fd04ad4af5955384fe719 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ fw/wmi_version.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 14fd26ac16c2..ea845f33aa15 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -6402,6 +6402,8 @@ typedef struct { * (bit 25) */ #define WMI_SCAN_FLAG_REPORT_CCA_BUSY_FOREACH_20MHZ 0x02000000 +/* Premium scan to receive higher MCS packets in scan channel */ +#define WMI_SCAN_FLAG_PREMIUM_SCAN 0x04000000 typedef enum { WMI_SCAN_DWELL_MODE_DEFAULT = 0, diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 9f084167009b..59d905a2770c 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1619 +#define __WMI_REVISION_ 1620 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From ce43dc1c773100d292b7996904519878d2764712 Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 26 May 2025 06:01:39 -0700 Subject: [PATCH 107/306] fw-api: CL 29312190 - update fw common interface files Change-Id: I2b59433fcbb9b225b5df8e5f5726d3370b83aa9d CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 8aafd2da3fa3..88f6897f8be3 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -704,6 +704,7 @@ typedef enum { WMI_SERVICE_HW_BLACKLIST_CHAN_SUPPORT = 445, /* Indicates FW support for computing and sending the HW channel blacklist for the current country and applicable power mode */ WMI_SERVICE_NDP_DFS_CHANNEL_SUPPORT = 446, /* FW supports forming NDP on DFS channels */ WMI_SERVICE_WFD_R2 = 447, /* Indicates FW supports WiFi-Direct R2 */ + WMI_SERVICE_STA_MLO_RCFG_SUPPORT = 448, /* FW supports STA ML reconfig op */ WMI_MAX_EXT2_SERVICE From 251ec89b59f1760acaf71e256895f8804a922c95 Mon Sep 17 00:00:00 2001 From: Krupali Dhanvijay Date: Wed, 19 Mar 2025 14:41:55 +0530 Subject: [PATCH 108/306] qcacld-3.0: Update PMK from firmware for FT-SAE AKM also When roaming happens with full SAE for FT-SAE AKMs host doesn't update the PMK received from firmware into its global cache. This causes stale PMK to be sent to firmware when full SAE happens when roaming to below AKM's: WLAN_CRYPTO_KEY_MGMT_FT_SAE WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY So update the PMK sent from firmware for above AKM's when auth status is connected (full SAE happens at host). CRs-Fixed: 3807689 Change-Id: I25d1a253de37481952c41f54697521285a0ccf92 --- core/sme/src/csr/csr_api_roam.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 262b4f292c30..c67bbe35827c 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -21586,11 +21586,12 @@ csr_process_roam_sync_callback(struct mac_context *mac_ctx, * eapol. So the session->psk_pmk will be stale in PMKSA cached * SAE/OWE roaming case. */ + akm_type = session->connectedProfile.AuthType; + if (roam_synch_data->authStatus == CSR_ROAM_AUTH_STATUS_AUTHENTICATED || - session->pCurRoamProfile->negotiatedAuthType == - eCSR_AUTH_TYPE_SAE || - session->pCurRoamProfile->negotiatedAuthType == - eCSR_AUTH_TYPE_OWE) { + akm_type == eCSR_AUTH_TYPE_SAE || + akm_type == eCSR_AUTH_TYPE_FT_SAE || + akm_type == eCSR_AUTH_TYPE_OWE) { csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, session_id); /* @@ -21615,8 +21616,7 @@ csr_process_roam_sync_callback(struct mac_context *mac_ctx, &session->connectedProfile.bssid); sme_debug("Trying to find PMKID for " QDF_MAC_ADDR_FMT " AKM Type:%d", QDF_MAC_ADDR_REF(pmkid_cache->BSSID.bytes), - session->pCurRoamProfile->negotiatedAuthType); - akm_type = session->connectedProfile.AuthType; + akm_type); mdie_present = session->connectedProfile.mdid.mdie_present; if (csr_lookup_pmkid_using_bssid(mac_ctx, session, @@ -21696,6 +21696,8 @@ csr_process_roam_sync_callback(struct mac_context *mac_ctx, qdf_mem_zero(pmksa, sizeof(*pmksa)); qdf_mem_free(pmksa); } + } else { + sme_debug("PMK not received from fw"); } sme_debug("pmkid found for " QDF_MAC_ADDR_FMT " len %d", QDF_MAC_ADDR_REF(pmkid_cache->BSSID.bytes), From 2db179ead0b8274d64f36ef05d0e14748fe657d5 Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Thu, 29 May 2025 01:11:39 -0700 Subject: [PATCH 109/306] Release 2.0.8.35C Release 2.0.8.35C Change-Id: I6d812e6d4eadfd09a9c6f39761446e73bf207c7f CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index d27763477199..8b118e5e2c21 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "B" +#define QWLAN_VERSION_EXTRA "C" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35B" +#define QWLAN_VERSIONSTR "2.0.8.35C" #endif /* QWLAN_VERSION_H */ From e11076b7dfe33a2056930f63dd20a6e5c189029a Mon Sep 17 00:00:00 2001 From: Zahir Shabbir Khan Date: Tue, 4 Mar 2025 12:03:30 +0530 Subject: [PATCH 110/306] dmaengine: msm_gpi: fix to avoid null pointer access A null pointer dereference is possible in gpi_prep_slave_sg. Client drivers will allocate buffer and initiate bus xfer through qup over i2c. I2c geni driver will queue the buffer address to TRE'S using scatter-gather. Clients can pass NULL buffer, so added null pointer check before accessing the TRE. This is leading to dereferencing null pointer issue. To solve this, add check for null in transfer ring. Change-Id: I3a25a7da0d38c58f725e0996c458b1fb64c0fe09 Signed-off-by: Anil Veshala Veshala Signed-off-by: Somesh Dey Signed-off-by: Zahir Shabbir Khan --- drivers/dma/qcom/gpi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 44e2e7de129e..eb9aea7851ff 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2524,6 +2525,12 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, for_each_sg(sgl, sg, sg_len, i) { tre = sg_virt(sg); + if (!tre) { + kfree(gpi_desc); + GPII_ERR(gpii, gpii_chan->chid, "TRE address is null\n"); + return NULL; + } + if (sg_len == 1) { tre_type = MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre)); From e5c4f2187cf53a997f624c311b976410de375f96 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Thu, 29 May 2025 00:23:28 +0800 Subject: [PATCH 111/306] audio-kernel: Enable hdmi in audio function for AIO bar HDMI audio using SEC_MI2S_TX. Change-Id: I0b589ffe9fac602bc62adfd228cf9a6227c9b959 Signed-off-by: Yi Zhang --- asoc/msm-pcm-routing-v2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index 7fef53cada56..0834dfa2ccb0 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -26945,6 +26945,10 @@ static const struct snd_kcontrol_new mmul17_mixer_controls[] = { MSM_BACKEND_DAI_PRI_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("INT3_MI2S_TX", SND_SOC_NOPM, MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, @@ -41375,6 +41379,7 @@ static const struct snd_soc_dapm_route intercon_mi2s[] = { {"MultiMedia29 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia30 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia17 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia18 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia19 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia28 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, From 9945f6cea301d8d3ff42bae32d25387d35e1ebba Mon Sep 17 00:00:00 2001 From: kbonga Date: Fri, 30 May 2025 15:04:16 +0530 Subject: [PATCH 112/306] qca-cmn-fw : Add extra parameter in existing rate_upper_cap command Add extra parameter in existing rate_upper_cap command Change-Id: If83cb600fe0bfc9b70406109c56bd6b743dd70ef --- fw/wmi_unified.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 9dc55fc54ed7..227c32ad79e5 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -10099,6 +10099,8 @@ typedef enum { #define WMI_PDEV_UPPER_CAP_DL_DIR_SET(_value, value) WMI_SET_BITS(_value, 18, 1, value) #define WMI_PDEV_UPPER_CAP_UL_DIR_GET(value) WMI_GET_BITS(value, 19, 1) #define WMI_PDEV_UPPER_CAP_UL_DIR_SET(_value, value) WMI_SET_BITS(_value, 19, 1, value) +#define WMI_PDEV_UPPER_CAP_DIR_GET(value) WMI_GET_BITS(value, 18, 1) +#define WMI_PDEV_UPPER_CAP_DIR_SET(_value, value) WMI_SET_BITS(_value, 18, 1, value) #define WMI_PDEV_RATE_DROP_NUM_MCS_GET(value) WMI_GET_BITS(value, 0, 8) #define WMI_PDEV_RATE_DROP_NUM_MCS_SET(_value, value) WMI_SET_BITS(_value, 0, 8, value) From d65a672130769b11823311b2264720a613c5d3f3 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 16:33:36 +0800 Subject: [PATCH 113/306] audio-kernel: Fix wcd938x DMIC unable to record Modify DMIC number to fix wcd938x DMIC can not record issue. Change-Id: I6dfb2156526b1817f6ef9ecfdf1cb670f983afbb Signed-off-by: Zhengchun Li --- asoc/codecs/wcd938x/wcd938x.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 8497a36b3002..744e8739745f 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -3381,35 +3381,35 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, ADC4, 0, adc4_switch, ARRAY_SIZE(adc4_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, DMIC1, + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, DMIC0, 0, dmic1_switch, ARRAY_SIZE(dmic1_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, DMIC2, + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, DMIC1, 0, dmic2_switch, ARRAY_SIZE(dmic2_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, DMIC3, + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, DMIC2, 0, dmic3_switch, ARRAY_SIZE(dmic3_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, DMIC4, + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, DMIC3, 0, dmic4_switch, ARRAY_SIZE(dmic4_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, DMIC5, + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, DMIC4, 0, dmic5_switch, ARRAY_SIZE(dmic5_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, DMIC6, + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, DMIC5, 0, dmic6_switch, ARRAY_SIZE(dmic6_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, DMIC7, + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, DMIC6, 0, dmic7_switch, ARRAY_SIZE(dmic7_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, DMIC8, + SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, DMIC7, 0, dmic8_switch, ARRAY_SIZE(dmic8_switch), wcd938x_tx_swr_ctrl, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), From e07673a51a06d2f53930e7a18eb9a54aa9e2edc2 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 16:24:56 +0800 Subject: [PATCH 114/306] asoc: Modification for 8ch capture Patch for 8ch audio record. This modification applies to QCM6490 platform. Change-Id: I2bcdeff53ede9ba3616bb732f54bca7e82792eab Signed-off-by: Zhengchun Li --- asoc/lahaina-port-config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asoc/lahaina-port-config.h b/asoc/lahaina-port-config.h index 62cdd512be20..12f89b0620b5 100644 --- a/asoc/lahaina-port-config.h +++ b/asoc/lahaina-port-config.h @@ -75,8 +75,8 @@ static struct port_params tx_frame_params_default[SWR_MSTR_PORT_LEN] = { /* TX UC1: TX1: 1ch, TX2: 2chs, TX3: 1ch(MBHC) */ static struct port_params tx_frame_params_shima[SWR_MSTR_PORT_LEN] = { {3, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX1 */ - {7, 5, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ - {7, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX3 */ + {7, 2, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0x00, 0x00}, /* TX2 */ + {7, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 1, 0x00, 0x00}, /* TX3 */ }; /* 4.8 MHz clock */ From 2c940fbaeb4ab9a660ecc7410c0feb270e455130 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 30 May 2025 06:01:35 -0700 Subject: [PATCH 115/306] fw-api: CL 29346863 - update fw common interface files Change-Id: I703c97fd030017ca83874a408aa67b7857e2cfad CRs-Fixed: 3830439 --- fw/htt_stats.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index cde4e1d5d72f..11852ef7f137 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -2282,6 +2282,9 @@ typedef struct _htt_tx_peer_rate_stats_tlv { A_UINT32 tx_bw_320mhz; /* MCS 14,15 */ A_UINT32 tx_mcs_ext_2[HTT_TX_PEER_STATS_NUM_EXTRA2_MCS_COUNTERS]; + A_UINT32 peer_tx_ppdu_cnt; + A_UINT32 peer_tx_mpdu_try_cnt; + A_UINT32 peer_tx_mpdu_success_cnt; } htt_stats_peer_tx_rate_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_peer_tx_rate_stats_tlv htt_tx_peer_rate_stats_tlv; @@ -2366,6 +2369,8 @@ typedef struct _htt_rx_peer_rate_stats_tlv { A_UINT32 rx_bw_320mhz; /* MCS 14,15 */ A_UINT32 rx_mcs_ext_2[HTT_RX_PEER_STATS_NUM_EXTRA2_MCS_COUNTERS]; + A_UINT32 tot_rx_ppdu_bytes; + A_UINT32 rx_mpdu_try_cnt; } htt_stats_peer_rx_rate_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_peer_rx_rate_stats_tlv htt_rx_peer_rate_stats_tlv; From 7fd586ed915d0fda019b054c250e5dce567a05e6 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 30 May 2025 06:03:10 -0700 Subject: [PATCH 116/306] fw-api: CL 29346866 - update fw common interface files Change-Id: I14d8f79cb47a859974867ad7e7f2b03601d101dc CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 88f6897f8be3..5c449ebd37b3 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -705,6 +705,7 @@ typedef enum { WMI_SERVICE_NDP_DFS_CHANNEL_SUPPORT = 446, /* FW supports forming NDP on DFS channels */ WMI_SERVICE_WFD_R2 = 447, /* Indicates FW supports WiFi-Direct R2 */ WMI_SERVICE_STA_MLO_RCFG_SUPPORT = 448, /* FW supports STA ML reconfig op */ + WMI_SERVICE_PDEV_SUSPEND_EVENT_SUPPORT = 449, /* FW supports PDEV_SUSPEND event */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 59d905a2770c..0e017473ee3a 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1620 +#define __WMI_REVISION_ 1621 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From a8506bcc9a10cd526ef47761bab7fac792f23861 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 30 May 2025 06:04:50 -0700 Subject: [PATCH 117/306] fw-api: CL 29347560 - update fw common interface files Change-Id: I96ca3f8ef53f20272d02ca9da7bb24c1bade0958 CRs-Fixed: 3830439 --- fw/htt.h | 132 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 30 deletions(-) diff --git a/fw/htt.h b/fw/htt.h index f1b19434dfd4..f359d104cfd3 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -269,9 +269,10 @@ * 3.139 Add CLASS_INFO_IDX field in MLO_R_PEER_MAP msg. * 3.140 Add H2T MPDUQ_AND_MSDUQ_INFO_HDR and MPDUQ_OF_MSDUQ_INFO defs. * 3.141 Add H2T HTT_AST_INFO for RxOLE. + * 3.142 Add T2H GLOBAL_PEER_ID_UNMAP def, update H2T MPDUQ_OR_MSDUQ_INFO def. */ #define HTT_CURRENT_VERSION_MAJOR 3 -#define HTT_CURRENT_VERSION_MINOR 141 +#define HTT_CURRENT_VERSION_MINOR 142 #define HTT_NUM_TX_FRAG_DESC 1024 @@ -11668,16 +11669,21 @@ PREPACK struct htt_h2t_mpduq_and_msduq_info_hdr { * what type. * For an MPDU queue, it will be fixed value of 30 based * on enum HTT_H2T_TID_MSDUQ_MPDUQ_TYPE. + * b'16:13 - hw_link_id: Indicates which HW link the message is for. + * This HW link ID is mainly relevant for split PHY + * usecases to identify the correct link in same SOC. * dword1 - b'31:0 - mpduq_address_39_8: 256 byte aligned mpduq physical * address, since lowest octet is zero for 256 byte aligned * physical addresses just passing upper 32 bits of * 40 bit address - * dword2 - b'23:0 - mpduq_number: Queue number for mpduq, encoded as follows - * [0:11] -> peer_id - * [12:16] -> tid num - * [17:21] -> mpduq_type i.e 30 - * [22:23] -> reserved + * dword2 - b'11:0 – peer_id + * b'16:12 – tid_num + * b'23:17 – reserved * b'31:24 - pn_addr_32_39: Upper 8 bits of 40 bit pn physical address + * Note that the mpduq_number is formed from the combination of + * peer_id (in bits 11:0) + * tid_num (in bits 16:12) + * msduq_mpduq_type (in bits 21:17) * dword3 - b'31:0 - pn_addr_0_31: Lower 32 bits of 40 bit pn physical address * Additional reserved dwords for future use cases * @@ -11686,15 +11692,20 @@ PREPACK struct htt_h2t_mpduq_and_msduq_info_hdr { * dword0 - b'7:0 - msg_type: Identifies msduq info to fw * This will be set to 0x2A * (HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO) - * b'12:8 - msduq_mpduq_type : type of the msduq based on + * b'12:8 - msduq_mpduq_type: type of the msduq based on * enum HTT_H2T_TID_MSDUQ_MPDUQ_TYPE - * dword1 - b'23:0 - tx_msduq_number: Queue number for the msduq, - * encoded as follows - * [0:11] -> peer_id - * [12:16] -> tid num - * [17:21] -> msduq_type - * [22:23] -> reserved + * b'16:13 - hw_link_id: Indicates which HW link the message is + * intended for. + * This HW link ID is mainly relevant for split PHY + * usecases to identify the correct link in same SOC. + * dword1 - b'11:0 – peer_id + * b'16:12 – tid_num + * b'23:17 – reserved * b'31:24 - svc_class_id : service class id of the msduq + * Note that the tx_msduq_number is formed from the combination of + * peer_id (in bits 11:0) + * tid_num (in bits 16:12) + * msduq_mpduq_type (in bits 21:17) * dword2 - b'31:0 - msduq_address_39_8: 256 byte aligned msduq physical * address, since lowest octet is zero for 256 byte aligned * addresses just passing upper 32 bits of 40 bit address @@ -11703,7 +11714,7 @@ PREPACK struct htt_h2t_mpduq_and_msduq_info_hdr { /* * Enum describes the various msduq/mpduq types, - * First 16 types correspond to the standard msduq types for data + * First 8 types correspond to the standard msduq types for data * Next come custom flows for specific purposes * enum 30 is reserved for mpduq type */ @@ -11716,19 +11727,11 @@ typedef enum { HTT_H2T_TID_MSDUQ_CUSTOM_3, /* 5 */ HTT_H2T_TID_MSDUQ_CUSTOM_4, /* 6 */ HTT_H2T_TID_MSDUQ_CUSTOM_5, /* 7 */ - HTT_H2T_TID_MSDUQ_CUSTOM_6, /* 8 */ - HTT_H2T_TID_MSDUQ_CUSTOM_7, /* 9 */ - HTT_H2T_TID_MSDUQ_CUSTOM_8, /* 10 */ - HTT_H2T_TID_MSDUQ_CUSTOM_9, /* 11 */ - HTT_H2T_TID_MSDUQ_CUSTOM_10, /* 12 */ - HTT_H2T_TID_MSDUQ_CUSTOM_11, /* 13 */ - HTT_H2T_TID_MSDUQ_CUSTOM_12, /* 14 */ - HTT_H2T_TID_MSDUQ_CUSTOM_13, /* 15 */ - HTT_H2T_TID_MISC_MSDUQ_TYPE_START, /* 16 */ - HTT_H2T_TID_MSDUQ_HOL = HTT_H2T_TID_MISC_MSDUQ_TYPE_START, /* also 16 */ - HTT_H2T_TID_MSDUQ_MCAST, /* 17 */ - HTT_H2T_TID_MSDUQ_FAST_ROAMING, /* 18 */ + HTT_H2T_TID_MISC_MSDUQ_TYPE_START, /* 8 */ + HTT_H2T_TID_MSDUQ_HOL = HTT_H2T_TID_MISC_MSDUQ_TYPE_START, /* also 8 */ + HTT_H2T_TID_MSDUQ_MCAST, /* 9 */ + HTT_H2T_TID_MSDUQ_FAST_ROAMING, /* 10 */ HTT_H2T_TID_MSDUQ_DATA_TYPE_END = 29, /* 29 */ HTT_H2T_TID_MPDUQ_TYPE, /* 30 */ @@ -11752,7 +11755,8 @@ typedef enum { PREPACK struct htt_h2t_mpduq_or_msduq_info { A_UINT32 msg_type: 8, /* bits 7:0 */ msduq_mpduq_type: 5, /* bits 12:8 */ - reserved0: 19; /* bits 31:13 */ + hw_link_id: 4, /* bits 16:13 */ + reserved0: 15; /* bits 31:17 */ union { struct { @@ -11782,9 +11786,9 @@ PREPACK struct htt_h2t_mpduq_or_msduq_info { }; } POSTPACK; -#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_M 0x000001F0 -#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S 8 -#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_NUM_MSDUQ_MPDUQ_TYPE_GET(_var) \ +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_M 0x00001F00 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S 8 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_GET(_var) \ (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_M) >> \ HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S) #define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_SET(_var, _val) \ @@ -11793,6 +11797,18 @@ PREPACK struct htt_h2t_mpduq_or_msduq_info { ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_MSDUQ_MPDUQ_TYPE_S)); \ } while (0) +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_M 0x0001E000 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_S 13 +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_GET(_var) \ + (((_var) & HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_M) >> \ + HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_S) +#define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID, _val); \ + ((_var) |= ((_val) << HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_INFO_HW_LINK_ID_S)); \ + } while (0) + + #define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_M 0x00000FFF #define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_S 0 #define HTT_H2T_MSG_TYPE_MPDUQ_OR_MSDUQ_NUMBER_PEER_ID_GET(_var) \ @@ -12152,6 +12168,7 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_TX_LCE_SUPER_RULE_SETUP_DONE = 0x3b, HTT_T2H_MSG_TYPE_SDWF_MSDUQ_CFG_IND = 0x3c, HTT_T2H_MSG_TYPE_MLO_LATENCY_REQ = 0x3d, + HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP = 0x3e, HTT_T2H_MSG_TYPE_TEST, @@ -23984,4 +24001,59 @@ PREPACK struct htt_t2h_mlo_latency_req_t { } while (0) +/* MSG_TYPE => HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP + * + * The following diagram shows the format of the global peer unmap message sent + * from the target to the host. This message is used to send unmap event to host + * after tid and msduq/mpduq cleanup in FW, host cleans up msduq/mpduq based on + * message. + * + * |31 24|23 20|19 8|7 0| + * |-----------------------------------------------------------------------| + * | reserved | hw_link_id | global_peer_id | msg type | + * |-----------------------------------------------------------------------| + * @details + * struct htt_t2h_global_peer_id_unmap_t: + * + * The message is interpreted as follows: + * dword0 - b'7:0 - msg_type: Identifies a request for MLO latency stats + * This will be set to 0x3e + * (HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP) + * b'19:8 - global_peer_id : global peer id assigned by host + * b'23:20 - hw_link_id : hw link id for which unmap is being sent + * + */ + + +/* HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP */ +PREPACK struct htt_t2h_global_peer_id_unmap_t { + A_UINT32 msg_type: 8, /* bits 7:0 */ + global_peer_id: 12, /* bits 19:8 */ + hw_link_id: 4, /* bits 23:20 */ + reserved: 8; /* bits 31:16 */ +} POSTPACK; + +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_M 0x000FFF00 +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_S 8 +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_GET(_var) \ + (((_var) & HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_M) >> \ + HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_S) +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_GLOBAL_PEER_ID_S)); \ + } while (0) + +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_M 0x00F00000 +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_S 20 +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_GET(_var) \ + (((_var) & HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_M) >> \ + HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_S) +#define HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID, _val); \ + ((_var) |= ((_val) << HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP_HW_LINK_ID_S)); \ + } while (0) + + #endif From 31d461c59c4df56ed2231392c326fbdc2c720192 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 31 May 2025 06:01:29 -0700 Subject: [PATCH 118/306] fw-api: CL 29370368 - update fw common interface files Change-Id: I6590fb190ee4780d7b70f376e79bb4fde07fc089 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index ea845f33aa15..28803ef1f057 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -24894,6 +24894,8 @@ typedef enum wake_reason_e { WOW_REASON_TDLS_PACKET_RX, /* wake up the host when USD is enabled */ WOW_REASON_USD, + /* wake up the host when MLO link switch happens */ + WOW_REASON_MLO_LINK_SWITCH_EVENT, /* add new WOW_REASON_ defs before this line */ From 6f5ebe81f7ba2e62ad89046ff7f5e3a736b6905d Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 31 May 2025 06:03:13 -0700 Subject: [PATCH 119/306] fw-api: CL 29370374 - update fw common interface files Change-Id: I628553fdce739abc35e1cdf704ee2f957c68c3fb CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 5c449ebd37b3..2240b7eb1417 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -706,6 +706,7 @@ typedef enum { WMI_SERVICE_WFD_R2 = 447, /* Indicates FW supports WiFi-Direct R2 */ WMI_SERVICE_STA_MLO_RCFG_SUPPORT = 448, /* FW supports STA ML reconfig op */ WMI_SERVICE_PDEV_SUSPEND_EVENT_SUPPORT = 449, /* FW supports PDEV_SUSPEND event */ + WMI_SERVICE_PCC_MODE = 450, /* Indicates FW support for PCC (P2P Connection Compatibility) Mode */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 0e017473ee3a..ce99b3c702a7 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1621 +#define __WMI_REVISION_ 1622 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 6c0406408e60e4b6c06ce54d5c53828be9fb1653 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 1 Jun 2025 06:01:22 -0700 Subject: [PATCH 120/306] fw-api: CL 29372366 - update fw common interface files Change-Id: I584a7c4da24d0b4d4451635f6ed53792f223fa6e CRs-Fixed: 3830439 --- fw/htt.h | 1 + fw/htt_stats.h | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/fw/htt.h b/fw/htt.h index f359d104cfd3..cf522cc9c9bb 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -849,6 +849,7 @@ typedef enum { HTT_STATS_PDEV_UL_MUMIMO_SEQ_TERM_STATS_TAG = 210, /* htt_stats_pdev_ulmumimo_seq_term_stats_tlv */ HTT_STATS_PDEV_UL_MUMIMO_HIST_INELIGIBILITY_TAG = 211, /* htt_stats_pdev_ulmumimo_hist_ineligibility_tlv */ HTT_STATS_PHY_PAPRD_PB_TAG = 212, /* htt_stats_phy_paprd_pb_tlv */ + HTT_STATS_HDS_PROF_STATS_TAG = 213, /* htt_stat_hds_prof_stats_tlv */ HTT_STATS_MAX_TAG, } htt_stats_tlv_tag_t; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 11852ef7f137..a35678962128 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -837,6 +837,14 @@ enum htt_dbg_ext_stats_type { */ HTT_DBG_EXT_STATS_PAPRD_PB = 75, + /** HTT_DBG_EXT_STATS_HDS_PROF + * PARAMS: + * - No Params + * RESP MSG: + * - htt_stats_hds_prof_stats_tlv + */ + HTT_DBG_EXT_STATS_HDS_PROF = 76, + /* keep this last */ HTT_DBG_NUM_EXT_STATS = 256, @@ -10602,6 +10610,73 @@ typedef struct { A_UINT32 power_boost_gain[HTT_TX_PDEV_STATS_NUM_BE_BW_COUNTERS][HTT_TX_PDEV_STATS_NUM_BE_MCS_COUNTERS]; } htt_stats_phy_paprd_pb_tlv; + +#define HTT_STATS_HDS_PROF_STATS_CIRCULAR_BUF_LEN 10 + +typedef struct { + htt_tlv_hdr_t tlv_hdr; + struct { + union { + A_UINT32 channel_info; + struct { + A_UINT32 bandwidth_mhz:16, + band_center_freq1:16; /* MHz units */ + }; + }; + + union { + A_UINT32 channel_config; + struct { + A_UINT32 phyMode:8, /* phyMode - WLAN_PHY_MODE enum type */ + txChainmask:8, + rxChainmask:8, + swProfile:8; + }; + }; + + A_UINT32 channelSwitchTime; + A_UINT32 calModuleTime; + A_UINT32 iniModuleTime; + A_UINT32 tpcModuleTime; + A_UINT32 miscModuleTime; + A_UINT32 ctlModuleTime; + A_UINT32 reserved; + } channelChange_stats[HTT_STATS_HDS_PROF_STATS_CIRCULAR_BUF_LEN]; + + A_UINT32 idx; /* shows how many channel changes have occurred */ +} htt_stats_hds_prof_stats_tlv; + +#define HTT_STATS_HDS_PROF_BANDWIDTH_MHZ_GET(word) \ + ((word) & 0x0000ffff) +#define HTT_STATS_HDS_PROF_BANDWIDTH_MHZ_SET(word, value) \ + ((word) |= ((value) & 0x0000ffff)) + +#define HTT_STATS_HDS_PROF_BAND_CENTER_FREQ1_GET(word) \ + (((word) & 0xffff0000) >> 16) +#define HTT_STATS_HDS_PROF_BAND_CENTER_FREQ1_SET(word, value) \ + ((word) |= (((value) << 16) & 0xffff0000)) + +#define HTT_STATS_HDS_PROF_PHY_MODE_GET(word) \ + (((word) & 0x000000ff) >> 0) +#define HTT_STATS_HDS_PROF_PHY_MODE_SET(word, value) \ + ((word) |= (((value) << 0) & 0x000000ff)) + +#define HTT_STATS_HDS_PROF_TX_CHAINMASK_GET(word) \ + (((word) & 0x0000ff00) >> 8) +#define HTT_STATS_HDS_PROF_TX_CHAINMASK_SET(word, value) \ + ((word) |= (((value) << 8) & 0x0000ff00)) + +#define HTT_STATS_HDS_PROF_RX_CHAINMASK_GET(word) \ + (((word) & 0x00ff0000) >> 16) +#define HTT_STATS_HDS_PROF_RX_CHAINMASK_SET(word, value) \ + ((word) |= (((value) << 16) & 0x00ff0000)) + +#define HTT_STATS_HDS_PROF_SW_PROFILE_GET(word) \ + (((word) & 0xff000000) >> 24) +#define HTT_STATS_HDS_PROF_SW_PROFILE_SET(word, value) \ + ((word) |= (((value) << 24) & 0xff000000)) + + typedef struct { union { A_UINT32 word32; From d98e80ccf48c262c05785f0644092c9cbeca3ace Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 2 Jun 2025 06:01:32 -0700 Subject: [PATCH 121/306] fw-api: CL 29372661 - update fw common interface files Change-Id: Id4b884a996761451c8fcf15117c7f4a3ccc7419d CRs-Fixed: 3830439 --- fw/wmi_unified.h | 15 ++++++++++++++- fw/wmi_version.h | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 28803ef1f057..1941b3620be8 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -5018,8 +5018,15 @@ typedef struct { * below WMI Events: * WMI_REG_CHAN_LIST_CC_EXT_EVENTID, WMI_AFC_EVENTID, and * WMI_HW_BLACKLIST_CHAN_EVENTID + * Bit 22 + * This bit will be set by host to inform FW that AFC handling + * is supported in the default cc event id. Based on this flag, + * FW will send the AFC event in the default cc event id if the + * country supports SP regulatory rules. + * Refer to the below defintions of WMI_RSRC_CFG_HOST_SERVICE_FLAG + * AFC_TRIGGER_ON_DEFAULT_CC_EVENT_GET and _SET macros. * - * Bits 31:22 - Reserved + * Bits 31:23 - Reserved */ A_UINT32 host_service_flags; @@ -5580,6 +5587,12 @@ typedef struct { #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_HOST_SUPPORT_HW_BLACKLIST_CHANNEL_SUPPORT_SET(host_service_flags, val) \ WMI_SET_BITS(host_service_flags, 21, 1, val) +/* This bit is used to inform FW to send AFC event ID in default CC event ID */ +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_AFC_TRIGGER_ON_DEFAULT_CC_EVENT_GET(host_service_flags) \ + WMI_GET_BITS(host_service_flags, 22, 1) +#define WMI_RSRC_CFG_HOST_SERVICE_FLAG_AFC_TRIGGER_ON_DEFAULT_CC_EVENT_SET(host_service_flags, val) \ + WMI_SET_BITS(host_service_flags, 22, 1, val) + #define WMI_RSRC_CFG_CARRIER_CFG_CHARTER_ENABLE_GET(carrier_config) \ WMI_GET_BITS(carrier_config, 0, 1) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index ce99b3c702a7..1be5df054b96 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1622 +#define __WMI_REVISION_ 1623 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 568fea2103684e538a8299d85837fc106bcb8373 Mon Sep 17 00:00:00 2001 From: Abhinav Parihar Date: Tue, 3 Jun 2025 13:22:30 +0530 Subject: [PATCH 122/306] msm: adsprpc: Prevent refcount increment for duplicate dmahandles When user passes same fd more than once in same remote call, it results in mapping refcount of dma handle being greater than one. Once DSP is done and passes dma handle fd in fdlist to unmap, it decrements the refcount by one and tries to delete the map. As the refcount is still greater than zero the mapping isn't deleted. This leads to stale mapping information. Avoid incrementing the map refcount when the same dmahandle is passed multiple times in a single remote call. This prevents stale mappings caused by non-zero refcounts after DSP unmaps the handle. Mapping removal should depend solely on DSP releasing all references, not on how many times the fd was passed. Change-Id: I69e98e98a6d494b5ffe0a845fd4579fe632edeeb Signed-off-by: Abhinav Parihar --- drivers/char/adsprpc.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index e8ba4bed8572..39bdf863b597 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ /* Uncomment this block to log an error on every VERIFY failure */ @@ -62,6 +62,7 @@ #define TZ_PIL_AUTH_QDSP6_PROC 1 #define FASTRPC_DMAHANDLE_NOMAP (16) +#define FASTRPC_MAP_DMA_HANDLE 0x20000 #define FASTRPC_ENOSUCH 39 #define DEBUGFS_SIZE 3072 @@ -1128,7 +1129,7 @@ static void fastrpc_mmap_add(struct fastrpc_mmap *map) } static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, - uintptr_t va, size_t len, int mflags, int refs, + uintptr_t va, size_t len, int mflags, bool refs, struct fastrpc_mmap **ppmap) { struct fastrpc_mmap *match = NULL, *map = NULL; @@ -1306,7 +1307,7 @@ static void fastrpc_mmap_free(struct fastrpc_mmap *map, uint32_t flags) dma_free_attrs(me->dev, map->size, (void *)map->va, (dma_addr_t)map->phys, (unsigned long)map->attr); } - } else if (map->flags == FASTRPC_DMAHANDLE_NOMAP) { + } else if (map->flags & FASTRPC_DMAHANDLE_NOMAP) { trace_fastrpc_dma_unmap(cid, map->phys, map->size); if (!IS_ERR_OR_NULL(map->table)) dma_buf_unmap_attachment(map->attach, map->table, @@ -1391,6 +1392,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, unsigned long flags; int err = 0, vmid, sgl_index = 0; struct scatterlist *sgl = NULL; + bool take_ref = true; if (!fl) { err = -EBADF; @@ -1404,7 +1406,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, } chan = &apps->channel[cid]; - if (!fastrpc_mmap_find(fl, fd, va, len, mflags, 1, ppmap)) + if (mflags & FASTRPC_MAP_DMA_HANDLE) + take_ref = false; + if (!fastrpc_mmap_find(fl, fd, va, len, mflags, take_ref, ppmap)) return 0; map = kzalloc(sizeof(*map), GFP_KERNEL); VERIFY(err, !IS_ERR_OR_NULL(map)); @@ -1442,7 +1446,7 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, if (err) goto bail; } - } else if (mflags == FASTRPC_DMAHANDLE_NOMAP) { + } else if (mflags & FASTRPC_DMAHANDLE_NOMAP) { VERIFY(err, !IS_ERR_OR_NULL(map->buf = dma_buf_get(fd))); if (err) { ADSPRPC_ERR("dma_buf_get failed for fd %d ret %ld\n", @@ -2496,10 +2500,10 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc); mutex_lock(&ctx->fl->map_mutex); for (i = bufs; i < bufs + handles; i++) { - int dmaflags = 0; + int dmaflags = FASTRPC_MAP_DMA_HANDLE; if (ctx->attrs && (ctx->attrs[i] & FASTRPC_ATTR_NOMAP)) - dmaflags = FASTRPC_DMAHANDLE_NOMAP; + dmaflags |= FASTRPC_DMAHANDLE_NOMAP; if (ctx->fds && (ctx->fds[i] != -1)) err = fastrpc_mmap_create(ctx->fl, ctx->fds[i], FASTRPC_ATTR_NOVA, 0, 0, dmaflags, @@ -2660,7 +2664,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (ctx->maps[i]) { /* check if map still exist */ if (!fastrpc_mmap_find(ctx->fl, ctx->fds[i], 0, 0, - 0, 0, &mmap)) { + 0, false, &mmap)) { if (mmap) { pages[i].addr = mmap->phys; pages[i].size = mmap->size; @@ -2875,7 +2879,7 @@ static int put_args(uint32_t kernel, struct smq_invoke_ctx *ctx, if (!fdlist[i]) break; if (!fastrpc_mmap_find(ctx->fl, (int)fdlist[i], 0, 0, - 0, 0, &mmap)) { + 0, false, &mmap)) { if (mmap && mmap->dma_handle_refs) { mmap->dma_handle_refs = 0; fastrpc_mmap_free(mmap, 0); @@ -4955,7 +4959,7 @@ static int fastrpc_internal_munmap_fd(struct fastrpc_file *fl, } mutex_lock(&fl->internal_map_mutex); mutex_lock(&fl->map_mutex); - err = fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, 0, &map); + err = fastrpc_mmap_find(fl, ud->fd, ud->va, ud->len, 0, false, &map); if (err) { ADSPRPC_ERR( "mapping not found to unmap fd 0x%x, va 0x%llx, len 0x%x, err %d\n", From 129840965e86526ecc2209b686513a9cee71e2ee Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 4 Jun 2025 18:01:35 -0700 Subject: [PATCH 123/306] fw-api: CL 29384929 - update fw common interface files Change-Id: I7ebcc2b2689d2581e3d8460b0718084df478ba76 CRs-Fixed: 3830439 --- fw/htt_stats.h | 218 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 4 deletions(-) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index a35678962128..cec553dd5bef 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -11081,6 +11081,26 @@ typedef struct { #define HTT_ML_PEER_EXT_DETAILS_MLD_AST_INDEX_M 0x0FFFF000 #define HTT_ML_PEER_EXT_DETAILS_MLD_AST_INDEX_S 12 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_M 0x00000007 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_S 0 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_M 0x00000038 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_S 3 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_M 0x000001C0 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_S 6 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_M 0x00000E00 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_S 9 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_M 0x00007000 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_S 12 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_M 0x00038000 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_S 15 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_M 0x001C0000 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_S 18 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_M 0x00E00000 +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_S 21 +#define HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_M 0x07000000 +#define HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_S 24 + + #define HTT_ML_PEER_EXT_DETAILS_PEER_ASSOC_IPC_RECVD_GET(_var) \ (((_var) & HTT_ML_PEER_EXT_DETAILS_PEER_ASSOC_IPC_RECVD_M) >> \ HTT_ML_PEER_EXT_DETAILS_PEER_ASSOC_IPC_RECVD_S) @@ -11123,6 +11143,97 @@ typedef struct { ((_var) |= ((_val) << HTT_ML_PEER_EXT_DETAILS_MLD_AST_INDEX_S)); \ } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID0_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID1_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID2_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID3_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID4_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID5_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID6_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_TID7_TQM_LINK_ID_S)); \ + } while (0) + +#define HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_M) >> \ + HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_S) +#define HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_EXT_DETAILS_MLO_MGMT_TID_TQM_LINK_ID_S)); \ + } while (0) + typedef struct { htt_tlv_hdr_t tlv_hdr; union { @@ -11134,6 +11245,51 @@ typedef struct { }; A_UINT32 msg_dword_1; }; + union { + struct { + A_UINT32 tid0_tqm_link0_id : 3, + tid1_tqm_link0_id : 3, + tid2_tqm_link0_id : 3, + tid3_tqm_link0_id : 3, + tid4_tqm_link0_id : 3, + tid5_tqm_link0_id : 3, + tid6_tqm_link0_id : 3, + tid7_tqm_link0_id : 3, + mlo_mgmt_tid_tqm_link0_id : 3, + reserved_tqm_link0 : 5; + }; + A_UINT32 msg_dword_tqm_link0; + }; + union { + struct { + A_UINT32 tid0_tqm_link1_id : 3, + tid1_tqm_link1_id : 3, + tid2_tqm_link1_id : 3, + tid3_tqm_link1_id : 3, + tid4_tqm_link1_id : 3, + tid5_tqm_link1_id : 3, + tid6_tqm_link1_id : 3, + tid7_tqm_link1_id : 3, + mlo_mgmt_tid_tqm_link1_id : 3, + reserved_tqm_link1 : 5; + }; + A_UINT32 msg_dword_tqm_link1; + }; + union { + struct { + A_UINT32 tid0_tqm_link2_id : 3, + tid1_tqm_link2_id : 3, + tid2_tqm_link2_id : 3, + tid3_tqm_link2_id : 3, + tid4_tqm_link2_id : 3, + tid5_tqm_link2_id : 3, + tid6_tqm_link2_id : 3, + tid7_tqm_link2_id : 3, + mlo_mgmt_tid_tqm_link2_id : 3, + reserved_tqm_link2 : 5; + }; + A_UINT32 msg_dword_tqm_link2; + }; } htt_stats_ml_peer_ext_details_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_ml_peer_ext_details_tlv htt_ml_peer_ext_details_tlv; @@ -11160,11 +11316,16 @@ typedef htt_stats_ml_peer_ext_details_tlv htt_ml_peer_ext_details_tlv; #define HTT_ML_LINK_INFO_ANCHOR_LINK_S 21 #define HTT_ML_LINK_INFO_INITIALIZED_M 0x00400000 #define HTT_ML_LINK_INFO_INITIALIZED_S 22 +#define HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_M 0x00800000 +#define HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_S 23 #define HTT_ML_LINK_INFO_SW_PEER_ID_M 0x0000ffff #define HTT_ML_LINK_INFO_SW_PEER_ID_S 0 #define HTT_ML_LINK_INFO_VDEV_ID_M 0x00ff0000 #define HTT_ML_LINK_INFO_VDEV_ID_S 16 +#define HTT_STATS_ML_LINK_INFO_PS_STATE_M 0x01000000 +#define HTT_STATS_ML_LINK_INFO_PS_STATE_S 24 + #define HTT_ML_LINK_INFO_VALID_GET(_var) \ (((_var) & HTT_ML_LINK_INFO_VALID_M) >> \ @@ -11320,6 +11481,18 @@ typedef htt_stats_ml_peer_ext_details_tlv htt_ml_peer_ext_details_tlv; ((_var) |= ((_val) << HTT_ML_LINK_INFO_INITIALIZED_S)); \ } while (0) + +#define HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_GET(_var) \ + (((_var) & HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_M) >> \ + HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_S) +#define HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_LINK_INFO_BRIDGE_PEER, _val); \ + ((_var) &= ~(HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_LINK_INFO_BRIDGE_PEER_S)); \ + } while (0) + + #define HTT_ML_LINK_INFO_SW_PEER_ID_GET(_var) \ (((_var) & HTT_ML_LINK_INFO_SW_PEER_ID_M) >> \ HTT_ML_LINK_INFO_SW_PEER_ID_S) @@ -11348,6 +11521,17 @@ typedef htt_stats_ml_peer_ext_details_tlv htt_ml_peer_ext_details_tlv; ((_var) |= ((_val) << HTT_ML_LINK_INFO_VDEV_ID_S)); \ } while (0) +#define HTT_STATS_ML_LINK_INFO_PS_STATE_GET(_var) \ + (((_var) & HTT_STATS_ML_LINK_INFO_PS_STATE_M) >> \ + HTT_STATS_ML_LINK_INFO_PS_STATE_S) +#define HTT_STATS_ML_LINK_INFO_PS_STATE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_LINK_INFO_PS_STATE, _val); \ + ((_var) &= ~(HTT_STATS_ML_LINK_INFO_PS_STATE_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_LINK_INFO_PS_STATE_S)); \ + } while (0) + + typedef struct { htt_tlv_hdr_t tlv_hdr; union { @@ -11363,7 +11547,8 @@ typedef struct { master_link : 1, anchor_link : 1, initialized : 1, - reserved : 9; + bridge_peer : 1, + reserved : 8; }; A_UINT32 msg_dword_1; }; @@ -11372,7 +11557,8 @@ typedef struct { struct { A_UINT32 sw_peer_id : 16, vdev_id : 8, - reserved1 : 8; + ps : 1, + reserved1 : 7; }; A_UINT32 msg_dword_2; }; @@ -11410,6 +11596,8 @@ typedef htt_stats_ml_link_info_details_tlv htt_ml_link_info_tlv; #define HTT_ML_PEER_DETAILS_PARTICIPATING_CHIPS_BITMAP_M 0x000000ff #define HTT_ML_PEER_DETAILS_PARTICIPATING_CHIPS_BITMAP_S 0 +#define HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_M 0x0000ff00 +#define HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_S 8 #define HTT_ML_PEER_DETAILS_NUM_LINKS_GET(_var) \ (((_var) & HTT_ML_PEER_DETAILS_NUM_LINKS_M) >> \ @@ -11595,6 +11783,17 @@ typedef htt_stats_ml_link_info_details_tlv htt_ml_link_info_tlv; ((_var) |= ((_val) << HTT_ML_PEER_DETAILS_PARTICIPATING_CHIPS_BITMAP_S)); \ } while (0) +#define HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_GET(_var) \ + (((_var) & HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_M) >> \ + HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_S) +#define HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED, _val); \ + ((_var) &= ~(HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_M)); \ + ((_var) |= ((_val) << HTT_STATS_ML_PEER_DETAILS_STATUS_REQUIRED_S)); \ + } while (0) + + typedef struct { htt_tlv_hdr_t tlv_hdr; htt_mac_addr remote_mld_mac_addr; @@ -11627,8 +11826,19 @@ typedef struct { union { struct { - A_UINT32 participating_chips_bitmap : 8, - reserved1 : 24; + A_UINT32 participating_chips_bitmap : 8, + /* status_required: + * Bitmap of status-required flags for each chip. + * Bit 0 is always the chip with the primary link. + * The remaining bits are for the other chips, + * in increasing order of chip ID, wrapping around + * to cover the chips whose IDs are smaller than the + * primary link's chip. + * Thus, bit 1 is for the chip whose ID is next after + * the primary link's chip ID, etc. + */ + status_required : 8, + reserved1 : 16; }; A_UINT32 msg_dword_2; }; From 1879db349b12c562330bd695942a1bb713d60135 Mon Sep 17 00:00:00 2001 From: Eswar Kesavalu Date: Fri, 2 May 2025 15:56:44 +0530 Subject: [PATCH 124/306] qcacld-3.0: Add ini to apply RSSI delta for 6 GHz roam Introduce a new ini parameter, to apply an RSSI penalty to non-6 GHz candidate APs during roaming from 6 GHz AP. This ensures roaming to non-6 GHz AP occurs only if it offers significantly better signal quality. Change-Id: I02482c37c56c44d3d1804282abd09deaefb8eed3 CRs-Fixed: 4141300 --- components/mlme/core/src/wlan_mlme_main.c | 3 ++ components/mlme/dispatcher/inc/cfg_mlme_lfr.h | 34 +++++++++++++ .../dispatcher/inc/wlan_mlme_public_struct.h | 8 ++- .../src/target_if_cm_roam_offload.c | 50 +++++++++++++++++++ .../core/src/wlan_cm_roam_offload.c | 8 +++ .../inc/wlan_cm_roam_public_struct.h | 12 +++++ .../dispatcher/src/wlan_cm_roam_api.c | 9 ++++ core/sme/src/csr/csr_neighbor_roam.c | 3 ++ 8 files changed, 125 insertions(+), 2 deletions(-) diff --git a/components/mlme/core/src/wlan_mlme_main.c b/components/mlme/core/src/wlan_mlme_main.c index 66f4ef140432..131518cc5cd9 100644 --- a/components/mlme/core/src/wlan_mlme_main.c +++ b/components/mlme/core/src/wlan_mlme_main.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1846,6 +1847,8 @@ static void mlme_init_lfr_cfg(struct wlan_objmgr_psoc *psoc, cfg_get(psoc, CFG_LFR3_ROAM_PREAUTH_RETRY_COUNT); lfr->roam_rssi_diff = cfg_get(psoc, CFG_LFR_ROAM_RSSI_DIFF); lfr->roam_rssi_diff_6ghz = cfg_get(psoc, CFG_LFR_ROAM_RSSI_DIFF_6GHZ); + lfr->roam_rssi_delta_6ghz_to_non_6ghz = + cfg_get(psoc, CFG_LFR_ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ); lfr->bg_rssi_threshold = cfg_get(psoc, CFG_LFR_ROAM_BG_RSSI_TH); lfr->roam_scan_offload_enabled = cfg_get(psoc, CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED); diff --git a/components/mlme/dispatcher/inc/cfg_mlme_lfr.h b/components/mlme/dispatcher/inc/cfg_mlme_lfr.h index 6ad5d7011e58..135eb7597a3c 100644 --- a/components/mlme/dispatcher/inc/cfg_mlme_lfr.h +++ b/components/mlme/dispatcher/inc/cfg_mlme_lfr.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1280,6 +1281,38 @@ CFG_VALUE_OR_DEFAULT, \ "Enable 6 GHz roam based on rssi") +/* + * + * roam_rssi_delta_from_6ghz_to_non_6ghz - Enable roam to Non 6 GHz AP based + * on rssi + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * This INI is used to decide whether to roam to Non 6 GHz AP or not based on + * RSSI. AP1 is the currently associated AP(6 GHz) and AP2(2.4 GHz / 5 GHz) is + * chosen for roaming. The Roaming will happen only if AP2 has better Signal + * Quality and it has a RSSI better than AP1. + * roam_rssi_delta_from_6ghz_to_non_6ghz is the number of dB units AP2 is + * better than AP1. + * + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ CFG_INI_UINT( \ + "roam_rssi_delta_from_6ghz_to_non_6ghz", \ + 0, \ + 100, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable 6 GHz to non 6 GHz roam based on rssi") + /* * * bg_rssi_threshold - To set RSSI Threshold for BG scan roaming @@ -2930,6 +2963,7 @@ CFG(CFG_LFR_FAST_TRANSITION_ENABLED) \ CFG(CFG_LFR_ROAM_RSSI_DIFF) \ CFG(CFG_LFR_ROAM_RSSI_DIFF_6GHZ) \ + CFG(CFG_LFR_ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ) \ CFG(CFG_LFR_ROAM_BG_RSSI_TH) \ CFG(CFG_LFR_ENABLE_WES_MODE) \ CFG(CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED) \ diff --git a/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h b/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h index ad48cd35c0cd..9ca94e78d468 100644 --- a/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h +++ b/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1680,8 +1681,10 @@ struct fw_scan_channels { * @roam_preauth_no_ack_timeout: Configure the no ack timeout period * @roam_rssi_diff: Enable roam based on rssi * @roam_rssi_diff_6ghz: RSSI diff value to be used for roaming to 6 GHz AP. - * @roam_scan_offload_enabled: Enable Roam Scan Offload - * @neighbor_scan_timer_period: Neighbor scan timer period + * @roam_rssi_delta_6ghz_to_non_6ghz: RSSI diff value to be used for + * roaming from 6 GHz to Non 6GHz AP. + * @roam_scan_offload_enabled: Enable Roam Scan Offload + * @neighbor_scan_timer_period: Neighbor scan timer period * @neighbor_scan_min_timer_period: Min neighbor scan timer period * @neighbor_lookup_rssi_threshold: Neighbor lookup rssi threshold * @opportunistic_scan_threshold_diff: Set oppurtunistic threshold diff @@ -1804,6 +1807,7 @@ struct wlan_mlme_lfr_cfg { uint32_t roam_preauth_no_ack_timeout; uint8_t roam_rssi_diff; uint8_t roam_rssi_diff_6ghz; + uint8_t roam_rssi_delta_6ghz_to_non_6ghz; uint8_t bg_rssi_threshold; bool roam_scan_offload_enabled; uint32_t neighbor_scan_timer_period; diff --git a/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c b/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c index 46e1cab26484..970d0429f1b7 100644 --- a/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c +++ b/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -264,6 +265,41 @@ target_if_cm_roam_rssi_diff_6ghz(struct wlan_objmgr_vdev *vdev, return status; } +/** + * target_if_cm_roam_rssi_delta_6ghz_to_non_6ghz() - Sends the roam RSSI + * diff value to the FW. This value is used to determine how much better + * the RSSI of the new/roamable non-6 GHz AP must be for roaming. + * + * @vdev: vdev object + * @roam_rssi_delta_6ghz_to_non_6ghz: RSSI diff value to be used for roaming to + * Non 6 GHz AP + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_rssi_delta_6ghz_to_non_6ghz(struct wlan_objmgr_vdev *vdev, + uint8_t roam_rssi_delta_6ghz_to_non_6ghz) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t vdev_id; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + vdev_id = wlan_vdev_get_id(vdev); + status = target_if_roam_set_param( + wmi_handle, vdev_id, + WMI_ROAM_PARAM_ROAM_RSSI_PENALTY_FOR_NON_6GHZ_CAND_AP, + roam_rssi_delta_6ghz_to_non_6ghz); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set WMI_ROAM_PARAM_ROAM_RSSI_PENALTY_FOR_NON_6GHZ_CAND_AP"); + + return status; +} + static QDF_STATUS target_if_cm_roam_scan_offload_rssi_thresh( wmi_unified_t wmi_handle, @@ -367,6 +403,13 @@ target_if_cm_roam_rssi_diff_6ghz(struct wlan_objmgr_vdev *vdev, return QDF_STATUS_E_NOSUPPORT; } +static QDF_STATUS +target_if_cm_roam_rssi_delta_6ghz_to_non_6ghz(struct wlan_objmgr_vdev *vdev, + uint8_t roam_rssi_diff_6ghz) +{ + return QDF_STATUS_E_NOSUPPORT; +} + static inline void target_if_check_hi_rssi_5ghz_support( wmi_unified_t wmi_handle, @@ -1276,6 +1319,9 @@ target_if_cm_roam_send_start(struct wlan_objmgr_vdev *vdev, if (req->wlan_roam_rssi_diff_6ghz) target_if_cm_roam_rssi_diff_6ghz(vdev, req->wlan_roam_rssi_diff_6ghz); + if (req->wlan_roam_rssi_delta_6ghz_to_non_6ghz) + target_if_cm_roam_rssi_delta_6ghz_to_non_6ghz( + vdev, req->wlan_roam_rssi_delta_6ghz_to_non_6ghz); /* add other wmi commands */ end: @@ -1516,6 +1562,10 @@ target_if_cm_roam_send_update_config(struct wlan_objmgr_vdev *vdev, if (req->wlan_roam_rssi_diff_6ghz) target_if_cm_roam_rssi_diff_6ghz( vdev, req->wlan_roam_rssi_diff_6ghz); + + if (req->wlan_roam_rssi_delta_6ghz_to_non_6ghz) + target_if_cm_roam_rssi_delta_6ghz_to_non_6ghz( + vdev, req->wlan_roam_rssi_delta_6ghz_to_non_6ghz); } end: return status; diff --git a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c b/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c index 647f5e0229b2..8f5e5272d77c 100644 --- a/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c +++ b/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c @@ -629,6 +629,10 @@ cm_roam_start_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_RSSI_DIFF_6GHZ, &temp); start_req->wlan_roam_rssi_diff_6ghz = temp.uint_value; + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ, &temp); + start_req->wlan_roam_rssi_delta_6ghz_to_non_6ghz = temp.uint_value; + status = wlan_cm_tgt_send_roam_start_req(psoc, vdev_id, start_req); if (QDF_IS_STATUS_ERROR(status)) mlme_debug("fail to send roam start"); @@ -691,6 +695,10 @@ cm_roam_update_config_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_RSSI_DIFF_6GHZ, &temp); update_req->wlan_roam_rssi_diff_6ghz = temp.uint_value; + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ, &temp); + update_req->wlan_roam_rssi_delta_6ghz_to_non_6ghz = temp.uint_value; + status = wlan_cm_tgt_send_roam_update_req(psoc, vdev_id, update_req); if (QDF_IS_STATUS_ERROR(status)) mlme_debug("fail to send update config"); diff --git a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h index 9a027bc6a11f..b4d17e9c04fe 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h +++ b/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -120,12 +121,14 @@ * @BEACON_RSSI_WEIGHT: Beacon Rssi weight parameter * @HI_RSSI_DELAY_BTW_SCANS: High Rssi delay between scans * @ROAM_RSSI_DIFF_6GHZ: roam rssi diff for 6 GHz AP + * @ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ: roam rssi diff for Non 6 GHz AP */ enum roam_cfg_param { RSSI_CHANGE_THRESHOLD, BEACON_RSSI_WEIGHT, HI_RSSI_DELAY_BTW_SCANS, ROAM_RSSI_DIFF_6GHZ, + ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ, }; /** @@ -1206,6 +1209,8 @@ enum roam_rt_stats_params { * scan only on prior discovery of any 6 GHz support in the environment. * @wlan_roam_rssi_diff_6ghz: This value is used as to how better the RSSI of * the new/roamable 6GHz AP should be for roaming. + * @wlan_roam_rssi_delta_6ghz_to_non_6ghz: This value is used as to how better + * the RSSI of the new/roamable non 6GHz AP should be for roaming. */ struct wlan_roam_start_config { struct wlan_roam_offload_scan_rssi_params rssi_params; @@ -1229,6 +1234,7 @@ struct wlan_roam_start_config { uint8_t wlan_exclude_rm_partial_scan_freq; uint8_t wlan_roam_full_scan_6ghz_on_disc; uint8_t wlan_roam_rssi_diff_6ghz; + uint8_t wlan_roam_rssi_delta_6ghz_to_non_6ghz; /* other wmi cmd structures */ }; @@ -1281,6 +1287,8 @@ struct wlan_roam_stop_config { * scan only on prior discovery of any 6 GHz support in the environment. * @wlan_roam_rssi_diff_6ghz: This value is used as to how better the RSSI of * the new/roamable 6GHz AP should be for roaming. + * @wlan_roam_rssi_delta_6ghz_to_non_6ghz: This value is used as to how better + * the RSSI of the new/roamable non 6GHz AP should be for roaming. */ struct wlan_roam_update_config { struct wlan_roam_beacon_miss_cnt beacon_miss_cnt; @@ -1299,6 +1307,7 @@ struct wlan_roam_update_config { uint8_t wlan_exclude_rm_partial_scan_freq; uint8_t wlan_roam_full_scan_6ghz_on_disc; uint8_t wlan_roam_rssi_diff_6ghz; + uint8_t wlan_roam_rssi_delta_6ghz_to_non_6ghz; }; #if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) @@ -1522,6 +1531,8 @@ enum roam_fail_params { * @roam_invoke_fail_reason: One of reason id from enum * wmi_roam_invoke_status_error in case of forced roam * @roam_rssi_diff_6ghz: roam rssi diff for 6 GHz AP + * @roam_rssi_delta_6ghz_to_non_6ghz: RSSI Delta value to be used for roaming + * from 6 GHz to Non 6GHz AP. */ struct wlan_cm_rso_configs { uint8_t rescan_rssi_delta; @@ -1532,6 +1543,7 @@ struct wlan_cm_rso_configs { uint32_t roam_trigger_reason; uint32_t roam_invoke_fail_reason; uint8_t roam_rssi_diff_6ghz; + uint8_t roam_rssi_delta_6ghz_to_non_6ghz; }; /** diff --git a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c index 53fce94e29c3..8ad4cef25e38 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c +++ b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -519,6 +520,10 @@ QDF_STATUS wlan_cm_roam_cfg_get_value(struct wlan_objmgr_psoc *psoc, case ROAM_RSSI_DIFF_6GHZ: dst_config->uint_value = src_config->roam_rssi_diff_6ghz; break; + case ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ: + dst_config->uint_value = + src_config->roam_rssi_delta_6ghz_to_non_6ghz; + break; default: mlme_err("Invalid roam config requested:%d", roam_cfg_type); status = QDF_STATUS_E_FAILURE; @@ -568,6 +573,10 @@ wlan_cm_roam_cfg_set_value(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, case ROAM_RSSI_DIFF_6GHZ: dst_config->roam_rssi_diff_6ghz = src_config->uint_value; break; + case ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ: + dst_config->roam_rssi_delta_6ghz_to_non_6ghz = + src_config->uint_value; + break; default: mlme_err("Invalid roam config requested:%d", roam_cfg_type); status = QDF_STATUS_E_FAILURE; diff --git a/core/sme/src/csr/csr_neighbor_roam.c b/core/sme/src/csr/csr_neighbor_roam.c index df8c0cfabee5..199c4352952f 100644 --- a/core/sme/src/csr/csr_neighbor_roam.c +++ b/core/sme/src/csr/csr_neighbor_roam.c @@ -848,6 +848,9 @@ static void csr_neighbor_roam_info_ctx_init(struct mac_context *mac, wlan_cm_roam_cfg_set_value(mac->psoc, session_id, ROAM_RSSI_DIFF_6GHZ, &src_cfg); + src_cfg.uint_value = mac->mlme_cfg->lfr.roam_rssi_delta_6ghz_to_non_6ghz; + wlan_cm_roam_cfg_set_value(mac->psoc, session_id, + ROAM_RSSI_DELTA_6GHZ_TO_NON_6GHZ, &src_cfg); /* * Now we can clear the preauthDone that * was saved as we are connected afresh From f3f95c51abbe5f02fa34e64cf96d2a79ede7dcb2 Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Thu, 5 Jun 2025 01:33:58 -0700 Subject: [PATCH 125/306] Release 2.0.8.35D Release 2.0.8.35D Change-Id: I3b0c1f0536f0ef1278181c95747928037ea12311 CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 8b118e5e2c21..0e3eaa97f81d 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "C" +#define QWLAN_VERSION_EXTRA "D" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35C" +#define QWLAN_VERSIONSTR "2.0.8.35D" #endif /* QWLAN_VERSION_H */ From 2567c2b3eb4577b9666c14b23cfe87a767874929 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 7 Jun 2025 06:01:38 -0700 Subject: [PATCH 126/306] fw-api: CL 29412107 - update fw common interface files Change-Id: I6779a596a6131f8b8027320c49304d4f10240850 CRs-Fixed: 3830439 --- fw/htt_stats.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index cec553dd5bef..7cc5dcf28b0c 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -2984,6 +2984,20 @@ typedef enum { #define HTT_MAX_NUM_SBT_INTR 4 +typedef enum { + HTT_RU_ALLOC_MODE_PF, + HTT_RU_ALLOC_MODE_QOS, + HTT_RU_ALLOC_MODE_STATIC, + HTT_RU_ALLOC_MODE_EQUAL, + HTT_RU_ALLOC_MODE_SIMPLIFIED, + + /* Reserving additional modes for future use */ + HTT_RU_ALLOC_MODE_RESERVED_1, + HTT_RU_ALLOC_MODE_RESERVED_2, + + HTT_RU_ALLOC_NUM_MODES +} HTT_RU_ALLOC_MODE; + typedef struct { htt_tlv_hdr_t tlv_hdr; @@ -3049,6 +3063,7 @@ typedef struct { * (Smart basic triggers are only used with intervals <= 40 ms.) */ A_UINT32 smart_basic_trig_sch_histogram[HTT_MAX_NUM_SBT_INTR]; + A_UINT32 ru_alloc_mode_cnt[HTT_RU_ALLOC_NUM_MODES]; } htt_stats_tx_selfgen_cmn_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_selfgen_cmn_stats_tlv htt_tx_selfgen_cmn_stats_tlv; From 4f37e589d976ba56a3dd87c06409aea7a35f2746 Mon Sep 17 00:00:00 2001 From: Vishakha Malik Date: Mon, 9 Jun 2025 15:31:59 +0530 Subject: [PATCH 127/306] crypto: qcedev - fix UAF in crypto-qti driver userspace to QCEDEV_IOCTL_MAP_BUF_REQ and QCEDEV_IOCTL_UNMAP_BUF_REQ, which can have a race condition resulting in a use-after-free (UAF). Change-Id: Iff51a098bbf9746e256e40a20fc37c5404f8aa22 Signed-off-by: Vishakha Malik --- drivers/crypto/msm/qcedev_smmu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/crypto/msm/qcedev_smmu.c b/drivers/crypto/msm/qcedev_smmu.c index 8d4844becc85..7039bce67c5c 100644 --- a/drivers/crypto/msm/qcedev_smmu.c +++ b/drivers/crypto/msm/qcedev_smmu.c @@ -329,10 +329,6 @@ int qcedev_check_and_map_buffer(void *handle, mapped_size = binfo->ion_buf.mapped_buf_size; atomic_inc(&binfo->ref_count); - /* Add buffer mapping information to regd buffer list */ - mutex_lock(&qce_hndl->registeredbufs.lock); - list_add_tail(&binfo->list, &qce_hndl->registeredbufs.list); - mutex_unlock(&qce_hndl->registeredbufs.lock); } /* Make sure the offset is within the mapped range */ @@ -344,6 +340,13 @@ int qcedev_check_and_map_buffer(void *handle, goto unmap; } + if (!found) { + /* Add buffer mapping information to regd buffer list */ + mutex_lock(&qce_hndl->registeredbufs.lock); + list_add_tail(&binfo->list, &qce_hndl->registeredbufs.list); + mutex_unlock(&qce_hndl->registeredbufs.lock); + } + /* return the mapped virtual address adjusted by offset */ *vaddr += offset; @@ -352,9 +355,6 @@ int qcedev_check_and_map_buffer(void *handle, unmap: if (!found) { qcedev_unmap_buffer(handle, mem_client, binfo); - mutex_lock(&qce_hndl->registeredbufs.lock); - list_del(&binfo->list); - mutex_unlock(&qce_hndl->registeredbufs.lock); } error: From e2fc0fc137ad0cd7b355564f32d3f145978c89c3 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 11 Jun 2025 06:01:33 -0700 Subject: [PATCH 128/306] fw-api: CL 29449355 - update fw common interface files Change-Id: Ic7352b94c01759b826b1ab9251207773abc53c07 CRs-Fixed: 3830439 --- fw/htt.h | 1 + fw/htt_stats.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/fw/htt.h b/fw/htt.h index cf522cc9c9bb..2d9bc93ce51b 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -850,6 +850,7 @@ typedef enum { HTT_STATS_PDEV_UL_MUMIMO_HIST_INELIGIBILITY_TAG = 211, /* htt_stats_pdev_ulmumimo_hist_ineligibility_tlv */ HTT_STATS_PHY_PAPRD_PB_TAG = 212, /* htt_stats_phy_paprd_pb_tlv */ HTT_STATS_HDS_PROF_STATS_TAG = 213, /* htt_stat_hds_prof_stats_tlv */ + HTT_STATS_TX_PDEV_MDSB_NUM_USERS_HISTOGRAM_TLV_TAG = 214, /* htt_stats_tx_pdev_mdsb_num_users_histogram_tlv */ HTT_STATS_MAX_TAG, } htt_stats_tlv_tag_t; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 7cc5dcf28b0c..c1f6178c2885 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -1274,6 +1274,13 @@ typedef struct { /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_pdev_flush_tlv htt_tx_pdev_stats_flush_tlv_v; +#define HTT_TX_PDEV_MDSB_MAX_NUM_USERS 8 +typedef struct { + htt_tlv_hdr_t tlv_hdr; + A_UINT32 pdev_id; + A_UINT32 mdsb_num_users_histogram[HTT_TX_PDEV_MDSB_MAX_NUM_USERS]; +} htt_stats_tx_pdev_mdsb_num_users_histogram_tlv; + #define HTT_TX_PDEV_STATS_MLO_ABORT_TLV_SZ(_num_elems) (sizeof(A_UINT32) * (_num_elems)) /* NOTE: Variable length TLV, use length spec to infer array size */ typedef struct { From 43a2892bd4757bec9cea4a99bf1da717c9fe2cf2 Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 11 Jun 2025 06:03:14 -0700 Subject: [PATCH 129/306] fw-api: CL 29449928 - update fw common interface files Change-Id: Ifc6fc413409c84216fa58b18e31b9686aabf4d82 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_tlv_defs.h | 6 +++-- fw/wmi_unified.h | 63 ++++++++++++++++++++++++++++++++++++++++++++--- fw/wmi_version.h | 2 +- 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 2240b7eb1417..913281692c32 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -707,6 +707,7 @@ typedef enum { WMI_SERVICE_STA_MLO_RCFG_SUPPORT = 448, /* FW supports STA ML reconfig op */ WMI_SERVICE_PDEV_SUSPEND_EVENT_SUPPORT = 449, /* FW supports PDEV_SUSPEND event */ WMI_SERVICE_PCC_MODE = 450, /* Indicates FW support for PCC (P2P Connection Compatibility) Mode */ + WMI_SERVICE_TDLS_NSS_CONFIRM_SUPPORT = 451, /* FW supports confirmation to host requested TDLS NSS operation */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index af1087cb216f..b985524399c2 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1484,7 +1484,8 @@ typedef enum { WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_fixed_param, WMITLV_TAG_STRUC_wmi_hw_blacklist_chan_data, WMITLV_TAG_STRUC_wmi_pdev_suspend_event_fixed_param, - WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param + WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_assoc_operating_mode_params, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2882,7 +2883,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mlo_params, mlo_params, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_eht_rate_set, peer_eht_rates, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mlo_partner_link_params, partner_link_params, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_tid_to_link_map, peer_tid_to_link_map, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_tid_to_link_map, peer_tid_to_link_map, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_operating_mode_params, operating_mode_params, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CMDID); diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 1941b3620be8..46fe2646a963 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -18241,6 +18241,8 @@ typedef struct { /* Target TSF value by which VDEV restart procedure should be completed in FW */ A_UINT32 target_tsf_us_lo; /* bits 31:0 */ A_UINT32 target_tsf_us_hi; /* bits 63:32 */ + A_UINT32 vdev_op_ul_nss; /* vdev operating uplink nss. 1 ~ n: 1ss ~ nss */ + A_UINT32 vdev_op_dl_nss; /* vdev operating downlink nss. 1 ~ n: 1ss ~ nss */ /* The TLVs follows this structure: * wmi_channel chan; <-- WMI channel @@ -22088,6 +22090,25 @@ typedef struct { wmi_mac_addr link_macaddr; } wmi_pdev_mesh_rx_filter_enable_fixed_param; +typedef struct { + A_UINT32 tlv_header; /** TLV tag (WMITLV_TAG_STRUC_wmi_peer_assoc_operating_mode_params) and len */ + /* rx_nss: + * self rx nss indicated to AP through capability IEs or operating mode IE. + * 1 ~ n: 1ss ~ nss + */ + A_UINT32 rx_nss; + /* tx_nss: + * self tx nss indicated to AP through capability IEs or operating mode IE. + * 1 ~ n: 1ss ~ nss + */ + A_UINT32 tx_nss; + /* bw: + * self BW indicated to AP through capability IEs or operating mode IE, + * refer to wmi_channel_width for definition of the values this field + * can hold. + */ + A_UINT32 bw; +} wmi_peer_assoc_operating_mode_params; /* * PEER assoc_flags for assoc complete: @@ -22231,6 +22252,11 @@ typedef struct { A_UINT32 assoc_flags; /** maximum number of spatial streams supported by peer for tx */ A_UINT32 peer_max_tx_nss; + /* max_downlink_nss: + * max downlink nss, intersected between self rx and peer tx. + * 1~N means 1ss~Nss + */ + A_UINT32 max_downlink_nss; /* Following this struct are the TLV's: * A_UINT8 peer_legacy_rates[]; @@ -22243,6 +22269,8 @@ typedef struct { * wmi_eht_rate_set peer_eht_rates; <-- EHT capabilities of the peer * wmi_peer_assoc_mlo_partner_link_params link_info[] <-- partner link info * wmi_peer_assoc_tid_to_link_map[] <-- tid to link_map info + * wmi_peer_assoc_operating_mode_params <-- operating mode param that + * host sends to AP in peer assoc req, optional TLV */ } wmi_peer_assoc_complete_cmd_fixed_param; @@ -27507,13 +27535,32 @@ typedef struct { typedef struct { /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param */ - A_UINT32 tlv_header; + A_UINT32 tlv_header; /** unique id identifying the VDEV */ - A_UINT32 vdev_id; + A_UINT32 vdev_id; /** peer MAC address */ - wmi_mac_addr peer_macaddr; + wmi_mac_addr peer_macaddr; /** new TDLS state for peer (wmi_tdls_peer_state) */ - A_UINT32 peer_state; + A_UINT32 peer_state; + /** need_nss_conf: + * only set to 1 when this TDLS peer is required to operating + * in particular HW mode NSS + */ + A_UINT32 need_nss_conf; + /* preferred_tx_nss: + * for peering state, it means advertised nss, + * for connected state, it means final negotiated nss. + * 1 ~ n: 1ss ~ nss + */ + A_UINT32 preferred_tx_nss; + /* preferred_rx_nss: + * for peering state, it means advertised nss, + * for connected state, it means final negotiated nss. + * 1 ~ n: 1ss ~ nss + */ + A_UINT32 preferred_rx_nss; + + /* The TLV for wmi_tdls_peer_capabilities will follow. * wmi_tdls_peer_capabilities peer_caps; */ @@ -27575,6 +27622,8 @@ enum wmi_tdls_peer_notification { WMI_TDLS_PEER_DISCONNECTED, /** TDLS/BT role change notification for connection tracker */ WMI_TDLS_CONNECTION_TRACKER_NOTIFICATION, + /** resp to WMI_TDLS_PEER_UPDATE_CMDID as host requested */ + WMI_TDLS_PEER_UPDATE_RESP, }; enum wmi_tdls_peer_reason { @@ -27604,6 +27653,8 @@ enum wmi_tdls_peer_reason { WMI_TDLS_SCAN_STARTED_EVENT, /** TDLS module received a scan complete event, TDLS connection tracker needs to handle this */ WMI_TDLS_SCAN_COMPLETED_EVENT, + /** TDLS max supported operating NSS in current HW mode */ + WMI_TDLS_OPERATING_NSS_CONF_EVENT, }; /* WMI_TDLS_PEER_EVENTID */ @@ -27618,6 +27669,10 @@ typedef struct { A_UINT32 peer_reason; /** unique id identifying the VDEV */ A_UINT32 vdev_id; + /** operating TX NSS 1 ~ n: 1ss ~ nss */ + A_UINT32 tx_nss; + /** operating RX NSS 1 ~ n: 1ss ~ nss */ + A_UINT32 rx_nss; } wmi_tdls_peer_event_fixed_param; /* NOTE: wmi_vdev_mcc_bcn_intvl_change_event_fixed_param would be deprecated. Please diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 1be5df054b96..b87396ef539a 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1623 +#define __WMI_REVISION_ 1624 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 02200b5f682730669a6c7d48e5a9cab29c283e45 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 18:20:15 +0800 Subject: [PATCH 130/306] asoc: Update dai link for ACM8625S AMP. ACM8625S using i2s dai quin_mi2s_rx. Add ACM8625S AMP dai on dai link. Change-Id: I0653d41b212e954e80fcf70dc4dc2bc7c0739405 Signed-off-by: Zhengchun Li --- asoc/msm_dailink.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/msm_dailink.h b/asoc/msm_dailink.h index c7353b9ae05d..ef588206d321 100644 --- a/asoc/msm_dailink.h +++ b/asoc/msm_dailink.h @@ -957,7 +957,8 @@ SND_SOC_DAILINK_DEFS(quat_mi2s_tx, SND_SOC_DAILINK_DEFS(quin_mi2s_rx, DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.8")), - DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx"), + COMP_CODEC("acm8625s_codec", "acm8625s-hifi")), DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); SND_SOC_DAILINK_DEFS(quin_mi2s_tx, From e860e2a02c871c1857a1ebf9611a47af88a2bc17 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 13 Jun 2025 06:01:53 -0700 Subject: [PATCH 131/306] fw-api: CL 29472274 - update fw common interface files Change-Id: Ieae923eaa45f1fe4a1cd149e69f41497b3d34a25 CRs-Fixed: 3830439 --- fw/htt_stats.h | 342 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 292 insertions(+), 50 deletions(-) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index c1f6178c2885..d4d41789afc9 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -1070,7 +1070,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Num PPDUs queued to HW */ A_UINT32 hw_queued; /** Num PPDUs reaped from HW */ @@ -1545,10 +1551,17 @@ typedef htt_stats_hw_wd_timeout_tlv htt_hw_stats_wd_timeout_tlv; typedef struct { htt_tlv_hdr_t tlv_hdr; - /* BIT [ 7 : 0] :- mac_id + /** + * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 tx_abort; A_UINT32 tx_abort_fail_count; A_UINT32 rx_abort; @@ -1615,10 +1628,17 @@ typedef htt_stats_hw_pdev_errs_tlv htt_hw_stats_pdev_errs_tlv; typedef struct { htt_tlv_hdr_t tlv_hdr; - /* BIT [ 7 : 0] :- mac_id + /** + * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 last_unpause_ppdu_id; A_UINT32 hwsch_unpause_wait_tqm_write; A_UINT32 hwsch_dummy_tlv_skipped; @@ -1751,7 +1771,15 @@ typedef struct _htt_msdu_flow_stats_tlv { * BIT [20 : 20] :- drop_rule * BIT [31 : 21] :- reserved */ - A_UINT32 tx_flow_no__tid_num__drop_rule; + union { + struct { + A_UINT32 tx_flow_number : 16; + A_UINT32 tid_num : 4; + A_UINT32 drop_rule : 1; + A_UINT32 reserved : 11; + }; + A_UINT32 tx_flow_no__tid_num__drop_rule; + }; A_UINT32 last_cycle_enqueue_count; A_UINT32 last_cycle_dequeue_count; A_UINT32 last_cycle_drop_count; @@ -1828,13 +1856,26 @@ typedef struct _htt_tx_tid_stats_tlv { * BIT [15 : 0] :- sw_peer_id * BIT [31 : 16] :- tid_num */ - A_UINT32 sw_peer_id__tid_num; + union { + struct { + A_UINT32 sw_peer_id : 16; + A_UINT32 tid_num : 16; + }; + A_UINT32 sw_peer_id__tid_num; + }; /** * BIT [ 7 : 0] :- num_sched_pending * BIT [15 : 8] :- num_ppdu_in_hwq * BIT [31 : 16] :- reserved */ - A_UINT32 num_sched_pending__num_ppdu_in_hwq; + union { + struct { + A_UINT32 num_sched_pending : 8; + A_UINT32 num_ppdu_in_hwq : 8; + A_UINT32 reserved : 16; + }; + A_UINT32 num_sched_pending__num_ppdu_in_hwq; + }; A_UINT32 tid_flags; /** per tid # of hw_queued ppdu */ A_UINT32 hw_queued; @@ -1864,13 +1905,26 @@ typedef struct _htt_tx_tid_stats_v1_tlv { * BIT [15 : 0] :- sw_peer_id * BIT [31 : 16] :- tid_num */ - A_UINT32 sw_peer_id__tid_num; + union { + struct { + A_UINT32 sw_peer_id : 16; + A_UINT32 tid_num : 16; + }; + A_UINT32 sw_peer_id__tid_num; + }; /** * BIT [ 7 : 0] :- num_sched_pending * BIT [15 : 8] :- num_ppdu_in_hwq * BIT [31 : 16] :- reserved */ - A_UINT32 num_sched_pending__num_ppdu_in_hwq; + union { + struct { + A_UINT32 num_sched_pending : 8; + A_UINT32 num_ppdu_in_hwq : 8; + A_UINT32 reserved : 16; + }; + A_UINT32 num_sched_pending__num_ppdu_in_hwq; + }; A_UINT32 tid_flags; /** Max qdepth in bytes reached by this tid */ A_UINT32 max_qdepth_bytes; @@ -1955,7 +2009,13 @@ typedef struct _htt_rx_tid_stats_tlv { * BIT [15 : 0] : sw_peer_id * BIT [31 : 16] : tid_num */ - A_UINT32 sw_peer_id__tid_num; + union { + struct { + A_UINT32 sw_peer_id : 16; + A_UINT32 tid_num : 16; + }; + A_UINT32 sw_peer_id__tid_num; + }; /** Stored as little endian */ A_UINT8 tid_name[MAX_HTT_TID_NAME]; /** @@ -3008,11 +3068,17 @@ typedef enum { typedef struct { htt_tlv_hdr_t tlv_hdr; - /* + /** * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** BAR sent out for SU transmission */ A_UINT32 su_bar; /** SW generated RTS frame sent */ @@ -4311,8 +4377,8 @@ typedef struct { /* NOTE: Variable length TLV, use length spec to infer array size */ typedef struct { htt_tlv_hdr_t tlv_hdr; - /** Scheduler command posted per tx_mode */ - A_UINT32 sched_cmd_posted[1/* length = num tx modes */]; + /** Scheduler command posted per tx_mode (length = num tx modes) */ + HTT_STATS_VAR_LEN_ARRAY1(A_UINT32, sched_cmd_posted); } htt_stats_sched_txq_cmd_posted_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_sched_txq_cmd_posted_tlv htt_sched_txq_cmd_posted_tlv_v; @@ -4322,8 +4388,8 @@ typedef htt_stats_sched_txq_cmd_posted_tlv htt_sched_txq_cmd_posted_tlv_v; /* NOTE: Variable length TLV, use length spec to infer array size */ typedef struct { htt_tlv_hdr_t tlv_hdr; - /** Scheduler command reaped per tx_mode */ - A_UINT32 sched_cmd_reaped[1/* length = num tx modes */]; + /** Scheduler command reaped per tx_mode (length = num tx modes) */ + HTT_STATS_VAR_LEN_ARRAY1(A_UINT32, sched_cmd_reaped); } htt_stats_sched_txq_cmd_reaped_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_sched_txq_cmd_reaped_tlv htt_sched_txq_cmd_reaped_tlv_v; @@ -4442,7 +4508,7 @@ typedef struct { * These supercycle trigger counts are not automatically reset, but * are reset upon request. */ - A_UINT32 supercycle_triggers[1/*HTT_SCHED_SUPERCYCLE_TRIGGER_MAX*/]; + HTT_STATS_VAR_LEN_ARRAY1(A_UINT32, supercycle_triggers); } htt_stats_sched_txq_supercycle_trigger_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_sched_txq_supercycle_trigger_tlv @@ -4567,7 +4633,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Current timestamp */ A_UINT32 current_timestamp; } htt_stats_tx_sched_cmn_tlv; @@ -4586,6 +4658,7 @@ typedef struct { * This structure is for documentation, and cannot be safely used directly. * Instead, use the constituent TLV structures to fill/parse. */ +#ifdef ATH_TARGET typedef struct { htt_stats_tx_sched_cmn_tlv cmn_tlv; struct { @@ -4597,6 +4670,7 @@ typedef struct { htt_stats_sched_txq_supercycle_trigger_tlv htt_sched_txq_sched_ineligibility_tlv_esched_supercycle_trigger_tlv; } txq[1]; } htt_stats_tx_sched_t; +#endif /* == TQM STATS == */ @@ -4712,7 +4786,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 max_cmdq_id; A_UINT32 list_mpdu_cnt_hist_intvl; @@ -4828,7 +4908,14 @@ typedef struct { * BIT [15 : 8] :- cmdq_id * BIT [31 : 16] :- reserved */ - A_UINT32 mac_id__cmdq_id__word; + union { + struct { + A_UINT32 mac_id : 8; + A_UINT32 cmdq_id : 8; + A_UINT32 reserved : 16; + }; + A_UINT32 mac_id__cmdq_id__word; + }; A_UINT32 sync_cmd; A_UINT32 write_cmd; A_UINT32 gen_mpdu_cmd; @@ -5064,7 +5151,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /* Global Stats */ A_UINT32 tcl2fw_entry_count; @@ -5272,23 +5365,47 @@ typedef struct { * BIT [15 : 0] :- num_elems * BIT [31 : 16] :- prefetch_tail_idx */ - A_UINT32 num_elems__prefetch_tail_idx; + union { + struct { + A_UINT32 num_elems : 16; + A_UINT32 prefetch_tail_idx : 16; + }; + A_UINT32 num_elems__prefetch_tail_idx; + }; /** * BIT [15 : 0] :- head_idx * BIT [31 : 16] :- tail_idx */ - A_UINT32 head_idx__tail_idx; + union { + struct { + A_UINT32 head_idx : 16; + A_UINT32 tail_idx : 16; + }; + A_UINT32 head_idx__tail_idx; + }; /** * BIT [15 : 0] :- shadow_head_idx * BIT [31 : 16] :- shadow_tail_idx */ - A_UINT32 shadow_head_idx__shadow_tail_idx; + union { + struct { + A_UINT32 shadow_head_idx : 16; + A_UINT32 shadow_tail_idx : 16; + }; + A_UINT32 shadow_head_idx__shadow_tail_idx; + }; A_UINT32 num_tail_incr; /** * BIT [15 : 0] :- lwm_thresh * BIT [31 : 16] :- hwm_thresh */ - A_UINT32 lwm_thresh__hwm_thresh; + union { + struct { + A_UINT32 lwm_thresh : 16; + A_UINT32 hwm_thresh : 16; + }; + A_UINT32 lwm_thresh__hwm_thresh; + }; A_UINT32 overrun_hit_count; A_UINT32 underrun_hit_count; A_UINT32 prod_blockwait_count; @@ -5319,7 +5436,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 num_records; } htt_stats_ring_if_cmn_tlv; /* preserve old name alias for new name consistent with the tag name */ @@ -5399,7 +5522,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** * Indicates the total number of 128 byte buffers in the CMEM * that are available for buffer sharing @@ -5613,7 +5742,16 @@ typedef struct { * BIT [24 : 24] :- EP 0 -consumer, 1 - producer * BIT [31 : 25] :- reserved */ - A_UINT32 mac_id__ring_id__arena__ep; + union { + struct { + A_UINT32 mac_id : 8; + A_UINT32 ring_id : 8; + A_UINT32 arena : 8; + A_UINT32 ep : 1; + A_UINT32 reserved : 7; + }; + A_UINT32 mac_id__ring_id__arena__ep; + }; /** DWORD aligned base memory address of the ring */ A_UINT32 base_addr_lsb; A_UINT32 base_addr_msb; @@ -5627,25 +5765,49 @@ typedef struct { * BIT [15 : 0] :- num_avail_words * BIT [31 : 16] :- num_valid_words */ - A_UINT32 num_avail_words__num_valid_words; + union { + struct { + A_UINT32 num_avail_words : 16; + A_UINT32 num_valid_words : 16; + }; + A_UINT32 num_avail_words__num_valid_words; + }; /** Index of head and tail * BIT [15 : 0] :- head_ptr * BIT [31 : 16] :- tail_ptr */ - A_UINT32 head_ptr__tail_ptr; + union { + struct { + A_UINT32 head_ptr : 16; + A_UINT32 tail_ptr : 16; + }; + A_UINT32 head_ptr__tail_ptr; + }; /** Empty or full counter of rings * BIT [15 : 0] :- consumer_empty * BIT [31 : 16] :- producer_full */ - A_UINT32 consumer_empty__producer_full; + union { + struct { + A_UINT32 consumer_empty : 16; + A_UINT32 producer_full : 16; + }; + A_UINT32 consumer_empty__producer_full; + }; /** Prefetch status of consumer ring * BIT [15 : 0] :- prefetch_count * BIT [31 : 16] :- internal_tail_ptr */ - A_UINT32 prefetch_count__internal_tail_ptr; + union { + struct { + A_UINT32 prefetch_count : 16; + A_UINT32 internal_tail_ptr : 16; + }; + A_UINT32 prefetch_count__internal_tail_ptr; + }; } htt_stats_sring_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_sring_stats_tlv htt_sring_stats_tlv; @@ -5778,7 +5940,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Number of tx ldpc packets */ A_UINT32 tx_ldpc; /** Number of tx rts packets */ @@ -5993,7 +6161,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** 11BE EHT DL MU OFDMA LDPC count */ A_UINT32 be_ofdma_tx_ldpc; @@ -6158,7 +6332,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 nsts; /** Number of rx ldpc packets */ @@ -6423,7 +6603,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 rx_11ax_ul_ofdma; @@ -6497,7 +6683,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 rx_11be_ul_ofdma; @@ -6650,12 +6842,18 @@ typedef struct { htt_tlv_hdr_t tlv_hdr; /** - * BIT [7:0] :- mac_id - * BIT [31:8] :- reserved + * BIT [ 7 : 0] :- mac_id + * BIT [31 : 8] :- reserved * * Refer to HTT_STATS_CMN_MAC_ID_GET/SET macros. */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Number of times UL MUMIMO RX packets received */ A_UINT32 rx_11ax_ul_mumimo; @@ -6709,12 +6907,18 @@ typedef struct { htt_tlv_hdr_t tlv_hdr; /** - * BIT [7:0] :- mac_id - * BIT [31:8] :- reserved + * BIT [ 7 : 0] :- mac_id + * BIT [31 : 8] :- reserved * * Refer to HTT_STATS_CMN_MAC_ID_GET/SET macros. */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Number of times UL MUMIMO RX packets received */ A_UINT32 rx_11be_ul_mumimo; @@ -6967,7 +7171,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Num PPDU status processed from HW */ A_UINT32 ppdu_recvd; /** Num MPDU across PPDUs with FCS ok */ @@ -7098,7 +7308,13 @@ typedef struct { * BIT [ 7 : 0] :- mac_id * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; /** Num of phy err */ A_UINT32 total_phy_err_cnt; /** Counts of different types of phy errs @@ -12166,7 +12382,13 @@ typedef struct { * read/write this bitfield. * BIT [31 : 8] :- reserved */ - A_UINT32 mac_id__word; + union { + struct { + A_UINT32 mac_id: 8, + reserved: 24; + }; + A_UINT32 mac_id__word; + }; A_UINT32 basic_trigger_across_bss; A_UINT32 basic_trigger_within_bss; A_UINT32 bsr_trigger_across_bss; @@ -12329,17 +12551,37 @@ typedef struct { * BIT [ 15 : 8] :- pri20_index * BIT [ 31 : 16] :- pri20_freq in Mhz */ - A_UINT32 mac_id__pri20_idx__freq; + union { + struct { + A_UINT32 mac_id : 8; + A_UINT32 pri20_idx : 8; + A_UINT32 pri20_freq_mhz : 16; + }; + A_UINT32 mac_id__pri20_idx__freq; + }; /* BIT [ 15 : 0] :- centre_freq1 * BIT [ 31 : 16] :- centre_freq2 */ - A_UINT32 centre_freq1__freq2; + union { + struct { + A_UINT32 centre_freq1 : 16; + A_UINT32 centre_freq2 : 16; + }; + A_UINT32 centre_freq1__freq2; + }; /* BIT [ 7 : 0] :- channel_phy_mode * BIT [ 23 : 8] :- static_pattern */ - A_UINT32 phy_mode__static_pattern; + union { + struct { + A_UINT32 phy_mode : 8; + A_UINT32 static_pattern : 16; + A_UINT32 reserved : 8; + }; + A_UINT32 phy_mode__static_pattern; + }; } htt_stats_pdev_bw_mgr_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_pdev_bw_mgr_stats_tlv htt_pdev_bw_mgr_stats_tlv; From d752352447af39d49563d157c7909d365522867b Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 13 Jun 2025 06:03:28 -0700 Subject: [PATCH 132/306] fw-api: CL 29472280 - update fw common interface files Change-Id: I3b466f9b5326dd43500d1712489423fb1536dd6d CRs-Fixed: 3830439 --- fw/htc_services.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fw/htc_services.h b/fw/htc_services.h index 50d57596a0b0..73eb52c32911 100644 --- a/fw/htc_services.h +++ b/fw/htc_services.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2012, 2014-2017, 2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved. * * Previously licensed under the ISC license by Qualcomm Atheros, Inc. * @@ -93,6 +93,11 @@ typedef enum { */ #define HTT_DATA3_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,2) +/* HTT_DATA4_MSG_SVC + * H2T channel to transfer MSDU/MPDU queue info from host to target + */ +#define HTT_DATA4_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,3) + /* raw stream service (i.e. flash, tcmd, calibration apps) */ #define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0) From ae432b7677dde23518d166504fcb274fbb6fc8ac Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 13 Jun 2025 06:05:10 -0700 Subject: [PATCH 133/306] fw-api: CL 29472287 - update fw common interface files Change-Id: I4216587effd2b89f106fd2c25bd4a830da453cb2 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 4 +++- fw/wmi_unified.h | 41 ++++++++++++++++++++++++++++++++++++++++- fw/wmi_version.h | 2 +- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index b985524399c2..e4e950374a5f 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1486,6 +1486,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_pdev_suspend_event_fixed_param, WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param, WMITLV_TAG_STRUC_wmi_peer_assoc_operating_mode_params, + WMITLV_TAG_STRUC_wmi_recv_bcn_stats, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -6401,7 +6402,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_HOST_SWFDA_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pmf_bcn_protect_stats, pmf_bcn_protect_stats, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_extd_stats, vdev_extd_stats, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_extd_stats, pdev_extd_stats, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_telemetry_stats, pdev_telemetry_stats, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_telemetry_stats, pdev_telemetry_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_recv_bcn_stats, recv_bcn_stats, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_STATS_EVENTID); /* Update PN response Event */ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 46fe2646a963..c895a500eaa8 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -4870,8 +4870,13 @@ typedef struct { * 11 -> reserved * Refer to the below WMI_RSRC_CFG_FLAGS2_OPTIMIZE_POWER_GET/SET * macros. + * Bit 25 - enable recv_bcn_stats feature + * 0 -> disable the feature + * 1 -> enable the feature + * Refer to below WMI_RSRC_CFG_FLAGS2_RECV_BCN_STATS_ENABLED_GET/SET + * macros. * - * Bits 31:25 - Reserved + * Bits 31:26 - Reserved */ A_UINT32 flags2; /** @brief host_service_flags - can be used by Host to indicate @@ -5458,6 +5463,11 @@ typedef struct { #define WMI_RSRC_CFG_FLAGS2_OPTIMIZE_POWER_SET(flags2, value) \ WMI_SET_BITS(flags2, 23, 2, value) +#define WMI_RSRC_CFG_FLAGS2_RECV_BCN_STATS_ENABLED_GET(flags2) \ + WMI_GET_BITS(flags2, 25, 1) +#define WMI_RSRC_CFG_FLAGS2_RECV_BCN_STATS_ENABLED_SET(flags2, value) \ + WMI_SET_BITS(flags2, 25, 1, value) + #define WMI_RSRC_CFG_HOST_SERVICE_FLAG_NAN_IFACE_SUPPORT_GET(host_service_flags) \ WMI_GET_BITS(host_service_flags, 0, 1) @@ -11180,6 +11190,7 @@ typedef enum { WMI_REQUEST_VDEV_EXTD_STAT = 0x10000, WMI_REQUEST_PDEV_EXTD_STAT = 0x20000, WMI_REQUEST_PDEV_TELEMETRY_STAT = 0x40000, + WMI_REQUEST_VDEV_RECV_BCN_STAT = 0x80000, } wmi_stats_id; /* @@ -11674,6 +11685,10 @@ typedef struct { * This TLV is followed by another TLV of array of bytes * num_channels * size of(struct wmi_channel_stats) */ +/* If WMI_REQUEST_VDEV_RECV_BCN_STAT is set in stats_id, then TLV + * wmi_recv_bcn_stats wmi_recv_bcn_stats[] + * follows the other TLVs + */ } wmi_radio_link_stats_event_fixed_param; /* per rate statistics */ @@ -15534,6 +15549,30 @@ typedef struct{ A_UINT32 estimated_air_time_per_ac; } wmi_pdev_telemetry_stats; + +#define WMI_MAX_BCN_HISTORY 10 /* max beacon history entry */ + +typedef struct { + /* Beacon real RSSI, non-averaged rssi, dBm units; -128 means invalid */ + A_INT32 bcn_rssi; + /* Beacon tsf, 0 means invalid */ + A_UINT32 bcn_tsf; + /* NOTE: + * Due to backwards-compatibility requirements, no new fields + * can be added to this struct. + */ +} wmi_bcn_his_info; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_recv_bcn_stats */ + A_UINT32 tlv_header; + /* Vdev id */ + A_UINT32 vdev_id; + /* Received History of last ten Beacon of the connected Bss */ + wmi_bcn_his_info bcn_history[WMI_MAX_BCN_HISTORY]; +} wmi_recv_bcn_stats; + + /** * VDEV statistics * @todo diff --git a/fw/wmi_version.h b/fw/wmi_version.h index b87396ef539a..20f1d77afbae 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1624 +#define __WMI_REVISION_ 1625 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From e7a6cd32d97a760a998ca2f86ea20134f4aec783 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 14 Jun 2025 06:01:41 -0700 Subject: [PATCH 134/306] fw-api: CL 29495802 - update fw common interface files Change-Id: I10441e94eb35209519448701ecb78027a6fd30b9 CRs-Fixed: 3830439 --- fw/wmi_unified.h | 1 + fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index c895a500eaa8..0cd7ee1c76d5 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -18481,6 +18481,7 @@ typedef enum { WMI_RATE_PREAMBLE_VHT, WMI_RATE_PREAMBLE_HE, WMI_RATE_PREAMBLE_EHT, + WMI_RATE_PREAMBLE_UHR, } WMI_RATE_PREAMBLE; /** Value to disable fixed rate setting */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 20f1d77afbae..93940d463f9e 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1625 +#define __WMI_REVISION_ 1626 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 4624e4efd2ea7a309f582a66381a21bf324e7cfc Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 14 Jun 2025 06:03:27 -0700 Subject: [PATCH 135/306] fw-api: CL 29496038 - update fw common interface files Change-Id: I955cc936adf959fd95327171b4a789c5261e15a1 CRs-Fixed: 3830439 --- fw/htt_stats.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fw/htt_stats.h b/fw/htt_stats.h index d4d41789afc9..b55bbff69ea6 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -12367,6 +12367,16 @@ typedef struct { * only for UL BSR TX mode. */ A_UINT32 running_ul_scheduler_for_bsrp_cnt[HTT_NUM_AC_WMM]; + /** + * Number of instances where we populated TX mode and candidate lists + * only for DL, due to skipping UL voluntarily. + */ + A_UINT32 running_dl_scheduler_due_to_skip_ul[HTT_NUM_AC_WMM]; + /** + * Number of instances where we populated TX mode and candidate lists + * only for UL, due to skipping DL voluntarily. + */ + A_UINT32 running_ul_scheduler_due_to_skip_dl[HTT_NUM_AC_WMM]; } htt_stats_pdev_sched_algo_ofdma_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_pdev_sched_algo_ofdma_stats_tlv From e01662d785ea3eb5f41c8b06a51dbdd706a3bf24 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 15 Jun 2025 06:01:42 -0700 Subject: [PATCH 136/306] fw-api: CL 29497269 - update fw common interface files Change-Id: Ia490ff308a2f0f97e7cb0da156a5ee95c64923df CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 7 +++++-- fw/wmi_unified.h | 42 +++++++++++++++++++++++++++++++++++++----- fw/wmi_version.h | 2 +- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index e4e950374a5f..4dcd586d8501 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1487,6 +1487,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param, WMITLV_TAG_STRUC_wmi_peer_assoc_operating_mode_params, WMITLV_TAG_STRUC_wmi_recv_bcn_stats, + WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -3661,7 +3662,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_UPDATE_MAC_ADDR_CMDID); #define WMITLV_TABLE_WMI_VDEV_VBSS_CONFIG_CMDID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_config_cmd_fixed_param, wmi_vdev_vbss_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_pn_info, vbss_peer_pn_info, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_sn_info, vbss_peer_sn_info, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_sn_info, vbss_peer_sn_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info, wmi_vdev_vbss_peer_dyn_info, vbss_peer_dyn_info, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_VBSS_CONFIG_CMDID); /* Pdev suspend Cmd */ @@ -7829,7 +7831,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VENDOR_PEER_EVENTID); #define WMITLV_TABLE_WMI_VDEV_VBSS_CONFIG_EVENTID(id,op,buf,len) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_config_event_fixed_param, wmi_vdev_vbss_config_event_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_pn_info, vbss_peer_pn_info, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_sn_info, vbss_peer_sn_info, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_sn_info, vbss_peer_sn_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info, wmi_vdev_vbss_peer_dyn_info, vbss_peer_dyn_info, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_VBSS_CONFIG_EVENTID); /* link switch event */ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 0cd7ee1c76d5..4ab9a37631a1 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -51015,8 +51015,9 @@ typedef struct { }; /* * The below TLVs follow this TLV in the WMI_VDEV_VBSS_CONFIG_CMDID msg: - * - wmi_vdev_vbss_peer_sn_info[]; * - wmi_vdev_vbss_peer_pn_info[]; + * - wmi_vdev_vbss_peer_sn_info[]; + * - wmi_vdev_vbss_peer_dyn_info; */ } wmi_vdev_vbss_config_cmd_fixed_param; @@ -51049,12 +51050,34 @@ typedef struct { ssn: 16; }; }; - /* The below TLVs follow this TLV in the WMI_VDEV_VBSS_CONFIG_EVENTID msg: - * - A_UINT32 scan_freq_list[]; - * - wmi_vdev_vbss_config_event_fixed_param[]; - */ } wmi_vdev_vbss_peer_sn_info; +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info */ + union { + A_UINT32 peer_dyn_info1_word32; + struct { + /** 15:0 omi + * 31:16 eht_omi + */ + A_UINT32 + omi: 16, + eht_omi: 16; + }; + }; + union { + A_UINT32 peer_dyn_info2_word32; + struct { + /** 1:0 pm + * 31:2 reserved + */ + A_UINT32 + pm : 1, + rsvd : 31; + }; + }; +} wmi_vdev_vbss_peer_dyn_info; + typedef enum { WMI_VBSS_GET_PEER_CONTEXT = 1, WMI_VBSS_SET_PEER_CONTEXT = 2, @@ -51073,6 +51096,15 @@ typedef enum { #define WMI_VDEV_VBSS_SN_INFO_GET_SSN(tid_num_ssn) WMI_GET_BITS(tid_num_ssn, 16, 16) #define WMI_VDEV_VBSS_SN_INFO_SET_SSN(action, value) WMI_SET_BITS(tid_num_ssn, 16, 16, value) +#define WMI_VDEV_VBSS_DYN_INFO_GET_OMI(peer_dyn_info1) WMI_GET_BITS(omi, 0, 16) +#define WMI_VDEV_VBSS_DYN_INFO_SET_OMI(peer_dyn_info1, value) WMI_SET_BITS(omi, 0, 16, value) + +#define WMI_VDEV_VBSS_DYN_INFO_GET_EHT_OMI(peer_dyn_info1) WMI_GET_BITS(eht_omi, 16, 16) +#define WMI_VDEV_VBSS_DYN_INFO_SET_EHT_OMI(peer_dyn_info1, value) WMI_SET_BITS(eht_omi, 16, 16, value) + +#define WMI_VDEV_VBSS_DYN_INFO_GET_PM(peer_dyn_info2) WMI_GET_BITS(pm, 0, 1) +#define WMI_VDEV_VBSS_DYN_INFO_SET_PM(peer_dyn_info2, value) WMI_SET_BITS(pm, 0, 1, value) + typedef struct { A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_vbss_config_event_fixed_param */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 93940d463f9e..4eec2a32e344 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1626 +#define __WMI_REVISION_ 1627 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 1f9b672143f748f42162d23fd8b0ccbcf2324d7f Mon Sep 17 00:00:00 2001 From: spuligil Date: Sun, 15 Jun 2025 06:03:06 -0700 Subject: [PATCH 137/306] fw-api: CL 29498712 - update fw common interface files Change-Id: Iec789f4373995dc0af8a306e3aa4886a93eec9d9 CRs-Fixed: 3830439 --- fw/htt.h | 4 ++ fw/htt_stats.h | 141 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 141 insertions(+), 4 deletions(-) diff --git a/fw/htt.h b/fw/htt.h index 2d9bc93ce51b..f8a35739165e 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -851,6 +851,10 @@ typedef enum { HTT_STATS_PHY_PAPRD_PB_TAG = 212, /* htt_stats_phy_paprd_pb_tlv */ HTT_STATS_HDS_PROF_STATS_TAG = 213, /* htt_stat_hds_prof_stats_tlv */ HTT_STATS_TX_PDEV_MDSB_NUM_USERS_HISTOGRAM_TLV_TAG = 214, /* htt_stats_tx_pdev_mdsb_num_users_histogram_tlv */ + HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_TAG = 215, /* htt_stats_tx_pdev_pending_seq_cnt_on_sched_post_hist_tlv */ + HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_TAG = 216, /* htt_stats_tx_pdev_pending_seq_cnt_in_hwq_hist_tlv */ + HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_TAG = 217, /* htt_stats_tx_pdev_pending_seq_cnt_in_txq_hist_tlv */ + HTT_STATS_SCHED_TXQ_EARLY_COMPL_TAG = 218, /* htt_stats_sched_txq_early_compl_tlv */ HTT_STATS_MAX_TAG, } htt_stats_tlv_tag_t; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index b55bbff69ea6..9cf849e24520 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -1020,6 +1020,10 @@ typedef enum { #define HTT_PDEV_STATS_PPDU_DUR_HIST_BINS 16 #define HTT_PDEV_STATS_PPDU_DUR_HIST_EXT_BINS 6 #define HTT_PDEV_STATS_PPDU_DUR_HIST_INTERVAL_US 250 +/* Max seq ctrl can be active in txq at a given instant */ +#define HTT_PDEV_STATS_MAX_SEQ_CTRL_HIST 4 +/* For BE max active seq_ctrl that can be in HWQ */ +#define HTT_PDEV_STATS_MAX_ACTIVE_SEQ_IN_HWQ_HIST 2 typedef enum { HTT_STATS_TX_PDEV_NO_DATA_UNDERRUN = 0, @@ -1258,6 +1262,33 @@ typedef struct { /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_pdev_cmn_tlv htt_tx_pdev_stats_cmn_tlv; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + union { + A_UINT32 pdev_id__word; + struct { + A_UINT32 + pdev_id: 8, + reserved: 24; + }; + }; + A_UINT32 pending_seq_on_sched_post_hist[HTT_PDEV_STATS_MAX_SEQ_CTRL_HIST]; +} htt_stats_tx_pdev_pending_seq_cnt_on_sched_post_hist_tlv; + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_M 0x000000ff +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_S 0 + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_GET(_var) \ + (((_var) & HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_M) >> \ + HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_S) + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_PDEV_ID_S)); \ + } while (0) + + #define HTT_TX_PDEV_STATS_URRN_TLV_SZ(_num_elems) (sizeof(A_UINT32) * (_num_elems)) /* NOTE: Variable length TLV, use length spec to infer array size */ typedef struct { @@ -1491,6 +1522,7 @@ typedef htt_stats_pdev_ctrl_path_tx_stats_tlv htt_pdev_ctrl_path_tx_stats_tlv_v; * - HTT_STATS_TX_PDEV_TRIED_MPDU_CNT_HIST_TAG * - HTT_STATS_PDEV_CTRL_PATH_TX_STATS_TAG * - HTT_STATS_MU_PPDU_DIST_TAG + * - HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_ON_SCHED_POST_HIST_TAG */ /* NOTE: * This structure is for documentation, and cannot be safely used directly. @@ -1508,6 +1540,8 @@ typedef struct _htt_tx_pdev_stats { htt_stats_tx_pdev_tried_mpdu_cnt_hist_tlv tried_mpdu_cnt_hist_tlv; htt_stats_pdev_ctrl_path_tx_stats_tlv ctrl_path_tx_tlv; htt_stats_mu_ppdu_dist_tlv mu_ppdu_dist_tlv; + htt_stats_tx_pdev_pending_seq_cnt_on_sched_post_hist_tlv + pending_seq_cnt_on_sched_post_hist_tlv; } htt_tx_pdev_stats_t; #endif /* ATH_TARGET */ @@ -2932,6 +2966,58 @@ typedef struct { typedef htt_stats_tx_hwq_txop_used_cnt_hist_tlv htt_tx_hwq_txop_used_cnt_hist_tlv_v; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + union { + A_UINT32 pdev_id__word; + struct { + A_UINT32 + pdev_id: 8, + reserved: 24; + }; + }; + A_UINT32 active_seq_in_hwq_hist[HTT_PDEV_STATS_MAX_ACTIVE_SEQ_IN_HWQ_HIST]; +} htt_stats_tx_pdev_pending_seq_cnt_in_hwq_hist_tlv; + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_M 0x000000ff +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_S 0 + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_GET(_var) \ + (((_var) & HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_M) >> \ + HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_S) + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_PDEV_ID_S)); \ + } while (0) + +typedef struct { + htt_tlv_hdr_t tlv_hdr; + union { + A_UINT32 pdev_id__word; + struct { + A_UINT32 + pdev_id: 8, + reserved: 24; + }; + }; + A_UINT32 active_seq_in_txq_hist[HTT_PDEV_STATS_MAX_SEQ_CTRL_HIST]; +} htt_stats_tx_pdev_pending_seq_cnt_in_txq_hist_tlv; + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_M 0x000000ff +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_S 0 + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_GET(_var) \ + (((_var) & HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_M) >> \ + HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_S) + +#define HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_PDEV_ID_S)); \ + } while (0) + /* STATS_TYPE : HTT_DBG_EXT_STATS_PDEV_TX_HWQ * TLV_TAGS: * - HTT_STATS_STRING_TAG @@ -2942,6 +3028,8 @@ typedef htt_stats_tx_hwq_txop_used_cnt_hist_tlv * - HTT_STATS_TX_HWQ_FES_STATUS_TAG * - HTT_STATS_TX_HWQ_TRIED_MPDU_CNT_HIST_TAG * - HTT_STATS_TX_HWQ_TXOP_USED_CNT_HIST_TAG + * - HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_TAG + * - HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_TAG */ /* NOTE: * This structure is for documentation, and cannot be safely used directly. @@ -2962,6 +3050,10 @@ typedef struct _htt_tx_hwq_stats { htt_stats_tx_hwq_fes_status_tlv fes_stats_tlv; htt_stats_tx_hwq_tried_mpdu_cnt_hist_tlv tried_mpdu_tlv; htt_stats_tx_hwq_txop_used_cnt_hist_tlv txop_used_tlv; + htt_stats_tx_pdev_pending_seq_cnt_in_hwq_hist_tlv + active_pending_seq_cnt_in_hwq_hist_tlv; + htt_stats_tx_pdev_pending_seq_cnt_in_txq_hist_tlv + active_pending_seq_cnt_in_txq_hist_tlv; } htt_tx_hwq_stats_t; #endif /* ATH_TARGET */ @@ -4514,6 +4606,44 @@ typedef struct { typedef htt_stats_sched_txq_supercycle_trigger_tlv htt_sched_txq_supercycle_triggers_tlv_v; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + union { + A_UINT32 pdev_id__word; + struct { + A_UINT32 + pdev_id: 8, + reserved: 24; + }; + }; + A_UINT32 ist_txop_end_indicated_cnt; + A_UINT32 ist_txop_end_notify_at_cmd_status_end; + A_UINT32 ist_txop_end_notify_at_isr_end; + A_UINT32 sched_cmd_post_skip_on_seq_unavail; + A_UINT32 ist_txop_end_skip_on_seq_unavail; + A_UINT32 ist_txop_end_skip_on_mpdu_ownership; + A_UINT32 skip_early_schedule_due_to_per; + A_UINT32 sched_cmd_posted_at_hw_txop_end; + A_UINT32 sched_cmd_missed_at_hw_txop_end; + A_UINT32 sched_cmd_posted_at_sched_cmd_compl; + A_UINT32 sched_cmd_missed_at_sched_cmd_compl; + A_UINT32 num_QoS_sched_runs; +} htt_stats_sched_txq_early_compl_tlv; + +#define HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_M 0x000000ff +#define HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_S 0 + +#define HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_GET(_var) \ + (((_var) & HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_M) >> \ + HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_S) + +#define HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_STATS_SCHED_TXQ_EARLY_COMPL_PDEV_ID_S)); \ + } while (0) + + #define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID_M 0x000000ff #define HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID_S 0 @@ -4653,6 +4783,7 @@ typedef struct { * - HTT_STATS_SCHED_TXQ_SCHED_ORDER_SU_TAG * - HTT_STATS_SCHED_TXQ_SCHED_INELIGIBILITY_TAG * - HTT_STATS_SCHED_TXQ_SUPERCYCLE_TRIGGER_TAG + * - HTT_STATS_SCHED_TXQ_EARLY_COMPL_TAG */ /* NOTE: * This structure is for documentation, and cannot be safely used directly. @@ -4662,12 +4793,14 @@ typedef struct { typedef struct { htt_stats_tx_sched_cmn_tlv cmn_tlv; struct { - htt_stats_tx_pdev_scheduler_txq_stats_tlv txq_tlv; - htt_stats_sched_txq_cmd_posted_tlv cmd_posted_tlv; - htt_stats_sched_txq_cmd_reaped_tlv cmd_reaped_tlv; + htt_stats_tx_pdev_scheduler_txq_stats_tlv txq_tlv; + htt_stats_sched_txq_cmd_posted_tlv cmd_posted_tlv; + htt_stats_sched_txq_cmd_reaped_tlv cmd_reaped_tlv; htt_stats_sched_txq_sched_order_su_tlv sched_order_su_tlv; htt_stats_sched_txq_sched_ineligibility_tlv sched_ineligibility_tlv; - htt_stats_sched_txq_supercycle_trigger_tlv htt_sched_txq_sched_ineligibility_tlv_esched_supercycle_trigger_tlv; + htt_stats_sched_txq_supercycle_trigger_tlv + htt_sched_txq_sched_ineligibility_tlv_esched_supercycle_trigger_tlv; + htt_stats_sched_txq_early_compl_tlv early_compl_tlv; } txq[1]; } htt_stats_tx_sched_t; #endif From 334c788a2c07903dd3953ff9d96801ca6821e64f Mon Sep 17 00:00:00 2001 From: spuligil Date: Mon, 16 Jun 2025 06:01:50 -0700 Subject: [PATCH 138/306] fw-api: CL 29499792 - update fw common interface files Change-Id: I3efe2e954c3945c86bb6c4d8020bf97fbd66d5cb CRs-Fixed: 3830439 --- fw/wmi_unified.h | 7 ++++++- fw/wmi_version.h | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 4ab9a37631a1..5f771c109acb 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -40813,7 +40813,10 @@ typedef struct { #define WLM_FLAGS_ROAM_SUPPRESS 1 #define WLM_FLAGS_ALLOW_FINAL_BMISS_ROAM 2 -/* bit 8: reserved for roaming */ +/* bit 8: Final bmiss roam will be triggered when all active links + * are final bmiss reported. + */ +#define WLM_FLAGS_ROAM_WHEN_ALL_LINKS_FBMISS 1 /* bit 9-11 of flags is used for powersave operation */ /* bit 9: WLM_FLAGS_PS_DISABLE_BMPS, disable BMPS if bit is set */ @@ -40857,6 +40860,8 @@ typedef struct { #define WLM_FLAGS_TSF_LATENCY_COMPENSATE_ENABLED_SET(flag) WMI_SET_BITS(flag, 4, 1, val) #define WLM_FLAGS_ROAM_GET_POLICY(flag) WMI_GET_BITS(flag, 6, 2) #define WLM_FLAGS_ROAM_SET_POLICY(flag, val) WMI_SET_BITS(flag, 6, 2, val) +#define WLM_FLAGS_ROAM_GET_WHEN_ALL_LINKS_FBMISS(flag) WMI_GET_BITS(flag, 8, 1) +#define WLM_FLAGS_ROAM_SET_WHEN_ALL_LINKS_FBMISS(flag, val) WMI_SET_BITS(flag, 8, 1, val) #define WLM_FLAGS_PS_IS_BMPS_DISABLED(flag) WMI_GET_BITS(flag, 9, 1) #define WLM_FLAGS_PS_IS_CSS_CLPS_DISABLED(flag) WMI_GET_BITS(flag, 10, 1) #define WLM_FLAGS_PS_SET_CSS_CLPS_DISABLE(flag, val) WMI_SET_BITS(flag, 10, 1, val) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 4eec2a32e344..b28cb730d141 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1627 +#define __WMI_REVISION_ 1628 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 695a2b9f1df15cd1f562344041700997b602a861 Mon Sep 17 00:00:00 2001 From: Bibek Kumar Patro Date: Fri, 10 Jan 2025 10:53:44 +0530 Subject: [PATCH 139/306] dma-mapping-fast: Fix PMD offset calculation for non-2M aligned start aperture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify PMD offset calculation for domains with start apertures not 2M aligned. Currently, when this happens, the PMD offset is calculated to the next PMD, and hence each IOVA is mapped as IOVA + offset, causing the IOVA to be tagged to the wrong PA. Issue occurrence - With the following sample aperture settings by a fastmap client: qcom,iommu-dma-addr-pool = <0x87f10000 0x07f00000>; qcom,iommu-geometry = <0x87f10000 0x07f00000>; The effective IOVA range is bounded to iova_base: 0x87f10000, iova_end: 0x8FE10000, which makes the IOVA base not aligned to a 2MB boundary. While calculating PTE, this adds an extra “default offset” to the PMD base (since all PMD pages’ base addresses are 2MB aligned), which further gets added on top of the actual offset obtained by (iova - base). This causes the final PMD offset to have an additional delta, causing the IOVA to be tagged to the wrong PA. ALIGN_DOWN(base, SZ_2M) helps to remove the extra “default offset,” helping to tag the IOVA to the right PA. ┌────────┐ PMD 1 base │ ├──────►┌┬──────┬┐◄── │ │ ││ ││ ALIGN_DOWN(base, SZ_2M) │PGD page├─┐ ││ old ││ │ │ │ ││offset││ │ │ │────►│└─ ││◄──── └────────┘ │wrong│ new ││ base │iova │offset─┘│◄──── │ └────────┘ right │ iova │ PMD 2 base └────►┌────────┐◄──── │ │ ALIGN_UP(base, SZ_2M) │ │ │ │ │ │ │ │ └┬───────┘ │PMD n base ┌┴───────┐ │ │ │ │ │ │ │ │ │ │ └────────┘ Change-Id: Ie320816ee91710fe06cf2337816d0fb8638ccbcb Fixes: 2e87440c3e6f ("iommu/io-pgtable-fast: optimize statically allocated pages") Signed-off-by: Bibek Kumar Patro Signed-off-by: Srinivasarao Pathipati --- drivers/iommu/io-pgtable-fast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c index f07e93b33f05..67ca5c20c521 100644 --- a/drivers/iommu/io-pgtable-fast.c +++ b/drivers/iommu/io-pgtable-fast.c @@ -133,7 +133,7 @@ typeof(base) __base = (base); \ typeof(pmds) __pmds = (pmds); \ (__iova < __base) ? ERR_PTR(-EINVAL) : \ - __pmds + ((__iova - __base) >> AV8L_FAST_PAGE_SHIFT); \ + __pmds + ((__iova - ALIGN_DOWN(__base, SZ_2M)) >> AV8L_FAST_PAGE_SHIFT); \ }) static inline dma_addr_t av8l_dma_addr(void *addr) From 5718b526ca958c746de805499348a773f3f86265 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 19 Jun 2025 06:01:52 -0700 Subject: [PATCH 140/306] fw-api: CL 29527156 - update fw common interface files Change-Id: Idfd18a33597d86627a492ea19341eb6a99448a8a CRs-Fixed: 3830439 --- fw/wlan_module_ids.h | 1 + fw/wmi_services.h | 8 ++++ fw/wmi_tlv_defs.h | 42 ++++++++++++++++ fw/wmi_unified.h | 111 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 161 insertions(+), 1 deletion(-) diff --git a/fw/wlan_module_ids.h b/fw/wlan_module_ids.h index a00b3e5c1924..6ccf2d652f95 100644 --- a/fw/wlan_module_ids.h +++ b/fw/wlan_module_ids.h @@ -197,6 +197,7 @@ typedef enum { WLAN_MODULE_VBSS, /* 0x99 */ WLAN_MODULE_OPT_DATA, /* 0x9a */ WLAN_MODULE_ASD, /* 0x9b */ + WLAN_MODULE_ENERGY_MGMT, /* 0x9c */ WLAN_MODULE_ID_MAX, WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 913281692c32..a859cabac6df 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -709,6 +709,14 @@ typedef enum { WMI_SERVICE_PCC_MODE = 450, /* Indicates FW support for PCC (P2P Connection Compatibility) Mode */ WMI_SERVICE_TDLS_NSS_CONFIRM_SUPPORT = 451, /* FW supports confirmation to host requested TDLS NSS operation */ + WMI_SERVICE_EM_PCIE_CONFIG_CBW_SUPPORT = 452, /* Indicates support for channel bandwidth based PCIe config adjustment */ + WMI_SERVICE_EM_PCIE_CONFIG_LPM_SUPPORT = 453, /* Indicates support for PCIe low power mode L0S/L1 */ + WMI_SERVICE_EM_DCVS_SUPPORT = 454, /* Indicates support for Dynamic clock and voltage scaling */ + WMI_SERVICE_EM_EDPS_SUPPORT = 455, /* Indicates support for Dynamic AP power save */ + WMI_SERVICE_EM_PUO_SUPPORT = 456, /* Indicates support for TWT based periodic unavailability operation. */ + WMI_SERVICE_EM_ECO_MODE_SUPPORT = 457, /* Indicates support for ECO mode config (LP BBF+ADC+SYNCT) */ + + WMI_MAX_EXT2_SERVICE } WMI_SERVICE; diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 4dcd586d8501..f28e569b80c6 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1488,6 +1488,12 @@ typedef enum { WMITLV_TAG_STRUC_wmi_peer_assoc_operating_mode_params, WMITLV_TAG_STRUC_wmi_recv_bcn_stats, WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info, + WMITLV_TAG_STRUC_wmi_energy_mgmt_pcie_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_energy_mgmt_pcie_lpm_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_energy_mgmt_dcvs_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_energy_mgmt_edps_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_energy_mgmt_puo_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_energy_mgmt_eco_mode_config_cmd_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2053,6 +2059,12 @@ typedef enum { OP(WMI_MLO_LINK_TTLM_COMPLETE_CMDID) \ OP(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID) \ OP(WMI_BPF_SET_APF_MODE_CMDID) \ + OP(WMI_ENERGY_MGMT_PCIE_CONFIG_CMDID) \ + OP(WMI_ENERGY_MGMT_PCIE_LPM_CMDID) \ + OP(WMI_ENERGY_MGMT_DCVS_CONFIG_CMDID) \ + OP(WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID) \ + OP(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID) \ + OP(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -5783,6 +5795,36 @@ WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_set_apf_mode_cmd_fixed_param, wmi_bpf_set_apf_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_APF_MODE_CMDID); +/* WMI cmd used to control PCIe config */ +#define WMITLV_TABLE_WMI_ENERGY_MGMT_PCIE_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_pcie_config_cmd_fixed_param, wmi_energy_mgmt_pcie_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_PCIE_CONFIG_CMDID); + +/* WMI cmd used for PCIe LPM config */ +#define WMITLV_TABLE_WMI_ENERGY_MGMT_PCIE_LPM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_pcie_lpm_cmd_fixed_param, wmi_energy_mgmt_pcie_lpm_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_PCIE_LPM_CMDID); + +/* WMI cmd used to control DCVS config */ +#define WMITLV_TABLE_WMI_ENERGY_MGMT_DCVS_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_dcvs_config_cmd_fixed_param, wmi_energy_mgmt_dcvs_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_DCVS_CONFIG_CMDID); + +/* WMI cmd used to control Dynamic AP Power Save config */ +#define WMITLV_TABLE_WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_edps_config_cmd_fixed_param, wmi_energy_mgmt_edps_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID); + +/* WMI cmd used to control Scheduled AP Power Save config */ +#define WMITLV_TABLE_WMI_ENERGY_MGMT_PUO_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_puo_config_cmd_fixed_param, wmi_energy_mgmt_puo_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID); + +/* WMI cmd used to control Un-scheduled AP Power Save config */ +#define WMITLV_TABLE_WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_eco_mode_config_cmd_fixed_param, wmi_energy_mgmt_eco_mode_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID); + /************************** TLV definitions of WMI events *******************************/ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 5f771c109acb..e18ddc622ffa 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -369,7 +369,8 @@ typedef enum { WMI_GRP_QUIET_OFL, /* 0x4a Quiet offloads */ WMI_GRP_ODD, /* 0x4b ODD */ WMI_GRP_TDMA, /* 0x4c TDMA */ - WMI_GRP_MANUAL_UL_TRIG /* 0x4d Manual UL OFDMA Trigger */ + WMI_GRP_MANUAL_UL_TRIG, /* 0x4d Manual UL OFDMA Trigger */ + WMI_GRP_ENERGY_MGMT, /* 0x4e energy management */ } WMI_GRP_ID; #define WMI_CMD_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) @@ -1728,6 +1729,21 @@ typedef enum { /** WMI Command to set Manual MU UL OFDMA trigger parameters */ WMI_VDEV_SET_ULOFDMA_MANUAL_MU_TRIG_CMDID, + + + /** WMI commands specific to Energy Management **/ + /** WMI cmd used to control PCIe config */ + WMI_ENERGY_MGMT_PCIE_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_ENERGY_MGMT), + /** WMI cmd used to control PCIe LPM */ + WMI_ENERGY_MGMT_PCIE_LPM_CMDID, + /** WMI cmd used to control Clock and Voltage config */ + WMI_ENERGY_MGMT_DCVS_CONFIG_CMDID, + /** WMI cmd used to control AP Dynamic Power Save feature */ + WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID, + /** WMI cmd used to control periodic unavailability operation */ + WMI_ENERGY_MGMT_PUO_CONFIG_CMDID, + /** WMI cmd used to control ECO mode config */ + WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID, } WMI_CMD_ID; typedef enum { @@ -39317,6 +39333,12 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_MLO_LINK_TTLM_COMPLETE_CMDID); WMI_RETURN_STRING(WMI_BPF_SET_SUPPORTED_OFFLOAD_BITMAP_CMDID); WMI_RETURN_STRING(WMI_BPF_SET_APF_MODE_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_PCIE_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_PCIE_LPM_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_DCVS_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_DPS_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; @@ -51124,6 +51146,93 @@ typedef struct { } wmi_vdev_vbss_config_event_fixed_param; +typedef enum { + /* Channel bandwidth based semi static PCIe config */ + WMI_PCIE_CONFIG_TYPE_CHANNEL_BANDWIDTH, + /* Force a specific PCIe config */ + WMI_PCIE_CONFIG_TYPE_FORCED_STATIC, +} wmi_pcie_config_type_e; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_energy_mgmt_pcie_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** enable or disable PCIe config */ + A_UINT32 enable; + /* PCIe config type (holds a wmi_pcie_config_type_e value) */ + A_UINT32 config_type; + /** pcie_gen: pcie generation to be used + * pcie_lane:pcie lane config (lane number) to be used + */ + A_UINT32 pcie_gen; + A_UINT32 pcie_lane; +} wmi_energy_mgmt_pcie_config_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_energy_mgmt_pcie_lpm_cmd_fixed_param */ + A_UINT32 tlv_header; + /** enable or disable PCIe LPM */ + A_UINT32 enable; +} wmi_energy_mgmt_pcie_lpm_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_energy_mgmt_dcvs_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** enable or disable DCVS config */ + A_UINT32 enable; +} wmi_energy_mgmt_dcvs_config_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_energy_mgmt_dps_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** enable or disable DPS config */ + A_UINT32 enable; + /** PDEV identifier */ + A_UINT32 pdev_id; + /** Channel to be used in DPS Low cap mode, freq must match the primary home chan freq */ + wmi_channel low_cap_channel; + /** Tx chainmask to be used in DPS Low cap mode */ + A_UINT32 low_cap_tx_chainmask; + /** Rx chainmask to be used in DPS Low cap mode */ + A_UINT32 low_cap_rx_chainmask; + /** Mbps throughput after which DPS will be exited and notified to Host */ + A_UINT32 exit_thpt_thrsld_mbps; + /** number of wakeups per second after which DPS will be exited and notified to Host */ + A_UINT32 exit_wakeup_thrsld_per_second; +} wmi_energy_mgmt_edps_config_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_energy_mgmt_puo_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** enable or disable DPS config */ + A_UINT32 enable; + /** PDEV identifier */ + A_UINT32 pdev_id; + /** Channel to be used in PUO Low cap mode, freq must match the primary home chan freq */ + wmi_channel low_cap_channel; + /** Tx chainmask to be used in Low cap mode */ + A_UINT32 low_cap_tx_chainmask; + /** Rx chainmask to be used in Low cap mode */ + A_UINT32 low_cap_rx_chainmask; + /** minimum duration required between SP end and SP start to trigger entering to doze state */ + A_UINT32 min_doze_thrsld_in_us; +} wmi_energy_mgmt_puo_config_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_energy_mgmt_eco_mode_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** enable or disable DPS config */ + A_UINT32 enable; + /** PDEV identifier */ + A_UINT32 pdev_id; +} wmi_energy_mgmt_eco_mode_config_cmd_fixed_param; + + /* ADD NEW DEFS HERE */ From 8b6a83bea8ec27636613a02bfb611d6f50f01cb6 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 21 Jun 2025 06:01:39 -0700 Subject: [PATCH 141/306] fw-api: CL 29563125 - update fw common interface files Change-Id: I85202ae615861e607890cbd66429eb73dbe3dd8c CRs-Fixed: 3830439 --- fw/htt.h | 11 +++- fw/htt_stats.h | 134 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 128 insertions(+), 17 deletions(-) diff --git a/fw/htt.h b/fw/htt.h index f8a35739165e..50b67b47fb3c 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -771,7 +771,10 @@ typedef enum { HTT_STATS_AST_ENTRY_TAG = 132, /* htt_ast_entry_tlv */ HTT_STATS_TX_PDEV_BE_DL_MU_OFDMA_STATS_TAG = 133, /* htt_tx_pdev_dl_be_mu_ofdma_sch_stats_tlv, TOPIC=advanced */ HTT_STATS_TX_PDEV_BE_UL_MU_OFDMA_STATS_TAG = 134, /* htt_tx_pdev_ul_be_mu_ofdma_sch_stats_tlv, TOPIC=advanced */ - HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG = 135, /* htt_tx_pdev_rate_stats_be_ofdma_tlv */ + HTT_STATS_TX_PDEV_RATE_BE_BN_OFDMA_TAG = 135, /* htt_stats_tx_pdev_rate_be_bn_ofdma_tlv */ + /* retain deprecated name as an alias */ + HTT_STATS_TX_PDEV_RATE_STATS_BE_OFDMA_TAG = + HTT_STATS_TX_PDEV_RATE_BE_BN_OFDMA_TAG, HTT_STATS_RX_PDEV_UL_MUMIMO_TRIG_BE_STATS_TAG = 136, /* htt_rx_pdev_ul_mumimo_trig_be_stats_tlv, TOPIC=advanced */ HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, /* htt_tx_selfgen_be_err_stats_tlv, TOPIC=advanced */ HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, /* htt_tx_selfgen_be_stats_tlv, TOPIC=advanced */ @@ -779,7 +782,10 @@ typedef enum { HTT_STATS_TX_PDEV_BE_UL_MU_MIMO_STATS_TAG = 140, /* htt_tx_pdev_be_ul_mu_mimo_sch_stats_tlv */ HTT_STATS_RX_PDEV_BE_UL_MIMO_USER_STATS_TAG = 141, /* htt_rx_pdev_be_ul_mimo_user_stats_tlv */ HTT_STATS_RX_RING_STATS_TAG = 142, /* htt_rx_fw_ring_stats_tlv_v */ - HTT_STATS_RX_PDEV_BE_UL_TRIG_STATS_TAG = 143, /* htt_rx_pdev_be_ul_trigger_stats_tlv, TOPIC=advanced */ + HTT_STATS_RX_PDEV_BE_BN_UL_TRIG_TAG = 143, /* htt_stats_rx_pdev_be_bn_ul_trig_tlv, TOPIC=advanced */ + /* retain deprecated name as an alias */ + HTT_STATS_RX_PDEV_BE_UL_TRIG_STATS_TAG = + HTT_STATS_RX_PDEV_BE_BN_UL_TRIG_TAG, HTT_STATS_TX_PDEV_SAWF_RATE_STATS_TAG = 144, /* htt_tx_pdev_rate_stats_sawf_tlv, TOPIC=advanced */ HTT_STATS_STRM_GEN_MPDUS_TAG = 145, /* htt_stats_strm_gen_mpdus_tlv_t */ HTT_STATS_STRM_GEN_MPDUS_DETAILS_TAG = 146, /* htt_stats_strm_gen_mpdus_details_tlv_t */ @@ -855,6 +861,7 @@ typedef enum { HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_HWQ_HIST_TAG = 216, /* htt_stats_tx_pdev_pending_seq_cnt_in_hwq_hist_tlv */ HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_TAG = 217, /* htt_stats_tx_pdev_pending_seq_cnt_in_txq_hist_tlv */ HTT_STATS_SCHED_TXQ_EARLY_COMPL_TAG = 218, /* htt_stats_sched_txq_early_compl_tlv */ + HTT_STATS_RX_PDEV_BN_UL_OFDMA_USER_TAG = 219, /* htt_stats_rx_pdev_bn_ul_ofdma_user_tlv */ HTT_STATS_MAX_TAG, } htt_stats_tlv_tag_t; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 9cf849e24520..26f867cfe9ad 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -680,16 +680,18 @@ enum htt_dbg_ext_stats_type { HTT_DBG_ODD_PDEV_BE_TX_MU_OFDMA_STATS = HTT_DBG_EXT_STATS_ODD_PDEV_BE_TX_MU_OFDMA, - /** HTT_DBG_EXT_STATS_ODD_UL_BE_OFDMA + /** HTT_DBG_EXT_STATS_ODD_UL_BE_BN_OFDMA * PARAMS: * - No Params * RESP MSG: * - htt_rx_pdev_be_ul_ofdma_user_stats_tlv */ - HTT_DBG_EXT_STATS_ODD_UL_BE_OFDMA = 60, - /* retain the deprecated name as an alias */ + HTT_DBG_EXT_STATS_ODD_UL_BE_BN_OFDMA = 60, + /* retain deprecated names as aliases */ + HTT_DBG_EXT_STATS_ODD_UL_BE_OFDMA = + HTT_DBG_EXT_STATS_ODD_UL_BE_BN_OFDMA, HTT_DBG_ODD_UL_BE_OFDMA_STATS = - HTT_DBG_EXT_STATS_ODD_UL_BE_OFDMA, + HTT_DBG_EXT_STATS_ODD_UL_BE_BN_OFDMA, /** HTT_DBG_EXT_STATS_ODD_BE_TXBF_OFDMA */ @@ -931,11 +933,14 @@ typedef enum { HTT_TX_RATE_STATS_DEFAULT, /* - * Upload 11be OFDMA TX stats + * Upload 11be and 11bn OFDMA TX stats * * TLV: htt_tx_pdev_rate_stats_be_ofdma_tlv */ - HTT_TX_RATE_STATS_UPLOAD_11BE_OFDMA, + HTT_TX_RATE_STATS_UPLOAD_11BE_11BN_OFDMA, + /* retain prior name as an alias */ + HTT_TX_RATE_STATS_UPLOAD_11BE_OFDMA = + HTT_TX_RATE_STATS_UPLOAD_11BE_11BN_OFDMA, } htt_tx_rate_stats_upload_t; /* htt_rx_ul_trigger_stats_upload_t @@ -950,11 +955,14 @@ typedef enum { HTT_RX_UL_TRIGGER_STATS_UPLOAD_11AX_OFDMA, /* - * Upload 11be UL OFDMA RX Trigger stats + * Upload 11be and 11bn UL OFDMA RX Trigger stats * * TLV: htt_rx_pdev_be_ul_trigger_stats_tlv */ - HTT_RX_UL_TRIGGER_STATS_UPLOAD_11BE_OFDMA, + HTT_RX_UL_TRIGGER_STATS_UPLOAD_11BE_11BN_OFDMA, + /* retain prior name as an alias */ + HTT_RX_UL_TRIGGER_STATS_UPLOAD_11BE_OFDMA = + HTT_RX_UL_TRIGGER_STATS_UPLOAD_11BE_11BN_OFDMA, } htt_rx_ul_trigger_stats_upload_t; /* @@ -6031,9 +6039,13 @@ typedef enum { /* 11be related updates */ #define HTT_TX_PDEV_STATS_NUM_BE_MCS_COUNTERS 16 /* 0...13,-2,-1 */ #define HTT_TX_PDEV_STATS_NUM_BE_BW_COUNTERS 5 /* 20,40,80,160,320 MHz */ +/* 11bn MCS counters: all BE MCS indices and 4 UHR iMCS */ +#define HTT_TX_PDEV_STATS_NUM_BN_MCS_COUNTERS 20 +#define HTT_TX_PDEV_STATS_NUM_BN_BW_COUNTERS 5 /* 20,40,80,160,320 MHz */ #define HTT_TX_PDEV_STATS_NUM_HE_SIG_B_MCS_COUNTERS 6 #define HTT_TX_PDEV_STATS_NUM_EHT_SIG_MCS_COUNTERS 4 +#define HTT_TX_PDEV_STATS_NUM_UHR_SIG_MCS_COUNTERS 4 typedef enum { HTT_TX_PDEV_STATS_AX_RU_SIZE_26, @@ -6066,6 +6078,9 @@ typedef enum { HTT_TX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS, } HTT_TX_PDEV_STATS_BE_RU_SIZE; +#define HTT_TX_PDEV_STATS_NUM_BN_RU_SIZE_COUNTERS \ + HTT_TX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS + typedef struct { htt_tlv_hdr_t tlv_hdr; @@ -6318,10 +6333,32 @@ typedef struct { A_UINT32 be_ofdma_tx_ru_size[HTT_TX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS]; /** 11BE EHT DL MU OFDMA EHT-SIG MCS stats */ A_UINT32 be_ofdma_eht_sig_mcs[HTT_TX_PDEV_STATS_NUM_EHT_SIG_MCS_COUNTERS]; + /** 11BE UHT DL MU OFDMA BA RU size stats */ A_UINT32 be_ofdma_ba_ru_size[HTT_TX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS]; -} htt_stats_tx_pdev_rate_stats_be_ofdma_tlv; -/* preserve old name alias for new name consistent with the tag name */ -typedef htt_stats_tx_pdev_rate_stats_be_ofdma_tlv + + /** 11BN UHR DL MU OFDMA LDPC count */ + A_UINT32 bn_ofdma_tx_ldpc; + /** 11BE UHR DL MU OFDMA TX MCS stats */ + A_UINT32 bn_ofdma_tx_mcs[HTT_TX_PDEV_STATS_NUM_BN_MCS_COUNTERS]; + /** + * 11BN UHR DL MU OFDMA TX NSS stats (Indicates NSS for individual users) + */ + A_UINT32 bn_ofdma_tx_nss[HTT_TX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + /** 11BN UHR DL MU OFDMA TX BW stats */ + A_UINT32 bn_ofdma_tx_bw[HTT_TX_PDEV_STATS_NUM_BN_BW_COUNTERS]; + /** 11BN UHR DL MU OFDMA TX guard interval stats */ + A_UINT32 bn_ofdma_tx_gi[HTT_TX_PDEV_STATS_NUM_GI_COUNTERS][HTT_TX_PDEV_STATS_NUM_BN_MCS_COUNTERS]; + /** 11BN UHR DL MU OFDMA TX RU Size stats */ + A_UINT32 bn_ofdma_tx_ru_size[HTT_TX_PDEV_STATS_NUM_BN_RU_SIZE_COUNTERS]; + /** 11BN UHR DL MU OFDMA UHR-SIG MCS stats */ + A_UINT32 bn_ofdma_uhr_sig_mcs[HTT_TX_PDEV_STATS_NUM_UHR_SIG_MCS_COUNTERS]; + /** 11BN UHR DL MU OFDMA BA RU size stats */ + A_UINT32 bn_ofdma_ba_ru_size[HTT_TX_PDEV_STATS_NUM_BN_RU_SIZE_COUNTERS]; +} htt_stats_tx_pdev_rate_be_bn_ofdma_tlv; +/* preserve old names as aliases */ +typedef htt_stats_tx_pdev_rate_be_bn_ofdma_tlv + htt_stats_tx_pdev_rate_stats_be_ofdma_tlv; +typedef htt_stats_tx_pdev_rate_be_bn_ofdma_tlv htt_tx_pdev_rate_stats_be_ofdma_tlv; typedef struct { @@ -6392,6 +6429,9 @@ typedef struct { #define HTT_RX_PDEV_STATS_RXEVM_MAX_PILOTS_PER_NSS 16 #define HTT_RX_PDEV_STATS_NUM_BE_MCS_COUNTERS 16 /* 0-13, -2, -1 */ #define HTT_RX_PDEV_STATS_NUM_BE_BW_COUNTERS 5 /* 20,40,80,160,320 MHz */ +/* 802.11BN MCS: all 16 EHT MCS indices and 4 UHR iMCS */ +#define HTT_RX_PDEV_STATS_NUM_BN_MCS_COUNTERS 20 +#define HTT_RX_PDEV_STATS_NUM_BN_BW_COUNTERS 5 /* 20,40,80,160,320 MHz */ /* HTT_RX_PDEV_STATS_NUM_RU_SIZE_COUNTERS: * RU size index 0: HTT_UL_OFDMA_V0_RU_SIZE_RU_26 @@ -6433,6 +6473,9 @@ typedef enum { HTT_RX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS, } HTT_RX_PDEV_STATS_BE_RU_SIZE; +#define HTT_RX_PDEV_STATS_NUM_BN_RU_SIZE_COUNTERS \ + HTT_RX_PDEV_STATS_NUM_BE_RU_SIZE_COUNTERS + #define HTT_RX_PDEV_RATE_STATS_MAC_ID_M 0x000000ff #define HTT_RX_PDEV_RATE_STATS_MAC_ID_S 0 @@ -6879,14 +6922,59 @@ typedef struct { A_UINT32 ul_mlo_proc_qdepth_params_count; A_UINT32 ul_mlo_proc_accepted_qdepth_params_count; A_UINT32 ul_mlo_proc_discarded_qdepth_params_count; -} htt_stats_rx_pdev_be_ul_trig_stats_tlv; -/* preserve old name alias for new name consistent with the tag name */ -typedef htt_stats_rx_pdev_be_ul_trig_stats_tlv + + A_UINT32 rx_11bn_ul_ofdma; + + A_UINT32 bn_ul_ofdma_rx_mcs[HTT_RX_PDEV_STATS_NUM_BN_MCS_COUNTERS]; + A_UINT32 bn_ul_ofdma_rx_gi[HTT_RX_PDEV_STATS_NUM_GI_COUNTERS][HTT_RX_PDEV_STATS_NUM_BN_MCS_COUNTERS]; + A_UINT32 bn_ul_ofdma_rx_nss[HTT_RX_PDEV_STATS_NUM_SPATIAL_STREAMS]; + A_UINT32 bn_ul_ofdma_rx_bw[HTT_RX_PDEV_STATS_NUM_BN_BW_COUNTERS]; + A_UINT32 bn_ul_ofdma_rx_stbc; + A_UINT32 bn_ul_ofdma_rx_ldpc; + + /* + * These are arrays to hold the number of PPDUs that we received per RU. + * E.g. PPDUs (data or non data) received in RU26 will be incremented in + * array offset 0 and similarly RU52 will be incremented in array offset 1 + */ + /** PPDU level */ + A_UINT32 bn_rx_ulofdma_data_ru_size_ppdu[HTT_RX_PDEV_STATS_NUM_BN_RU_SIZE_COUNTERS]; + /** PPDU level */ + A_UINT32 bn_rx_ulofdma_non_data_ru_size_ppdu[HTT_RX_PDEV_STATS_NUM_BN_RU_SIZE_COUNTERS]; + + /** + * STA AID array for identifying which STA the + * Target-RSSI / FD-RSSI / pwr headroom stats are for + */ + A_UINT32 bn_uplink_sta_aid[HTT_RX_UL_MAX_UPLINK_RSSI_TRACK]; + /** + * Trig Target RSSI for STA AID in same index - UNIT(dBm) + */ + A_INT32 bn_uplink_sta_target_rssi[HTT_RX_UL_MAX_UPLINK_RSSI_TRACK]; + /** + * Trig FD RSSI from STA AID in same index - UNIT(dBm) + */ + A_INT32 bn_uplink_sta_fd_rssi[HTT_RX_UL_MAX_UPLINK_RSSI_TRACK]; + /** + * Trig power headroom for STA AID in same idx - UNIT(dB) + */ + A_UINT32 bn_uplink_sta_power_headroom[HTT_RX_UL_MAX_UPLINK_RSSI_TRACK]; + + /* + * Number of UHR UL OFDMA per-user responses containing only a QoS null in + * response to basic trigger. Typically a data response is expected. + */ + A_UINT32 bn_ul_ofdma_basic_trigger_rx_qos_null_only; +} htt_stats_rx_pdev_be_bn_ul_trig_tlv; +/* preserve old names as aliases */ +typedef htt_stats_rx_pdev_be_bn_ul_trig_tlv + htt_stats_rx_pdev_be_ul_trig_stats_tlv; +typedef htt_stats_rx_pdev_be_bn_ul_trig_tlv htt_rx_pdev_be_ul_trigger_stats_tlv; /* STATS_TYPE : HTT_DBG_EXT_STATS_PDEV_UL_TRIG_STATS * TLV_TAGS: - * - HTT_STATS_RX_PDEV_BE_UL_TRIG_STATS_TAG + * - HTT_STATS_RX_PDEV_BE_BN_UL_TRIG_TAG * NOTE: * This structure is for documentation, and cannot be safely used directly. * Instead, use the constituent TLV structures to fill/parse. @@ -6935,6 +7023,22 @@ typedef struct { typedef htt_stats_rx_pdev_be_ul_ofdma_user_stats_tlv htt_rx_pdev_be_ul_ofdma_user_stats_tlv; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + + A_UINT32 user_index; + /** PPDU level */ + A_UINT32 bn_rx_ulofdma_non_data_ppdu; + /** PPDU level */ + A_UINT32 bn_rx_ulofdma_data_ppdu; + /** MPDU level */ + A_UINT32 bn_rx_ulofdma_mpdu_ok; + /** MPDU level */ + A_UINT32 bn_rx_ulofdma_mpdu_fail; + A_UINT32 bn_rx_ulofdma_non_data_nusers; + A_UINT32 bn_rx_ulofdma_data_nusers; +} htt_stats_rx_pdev_bn_ul_ofdma_user_tlv; + typedef struct { htt_tlv_hdr_t tlv_hdr; From f7a287f654dff8947ce53bf19e244d2c8800a8d6 Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 21 Jun 2025 06:03:21 -0700 Subject: [PATCH 142/306] fw-api: CL 29563157 - update fw common interface files Change-Id: I89a1bc371886805ced42afa307253f542449b0fe CRs-Fixed: 3830439 --- fw/wmi_services.h | 2 ++ fw/wmi_unified.h | 11 ++++++----- fw/wmi_version.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index a859cabac6df..55202bf9730f 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -716,6 +716,8 @@ typedef enum { WMI_SERVICE_EM_PUO_SUPPORT = 456, /* Indicates support for TWT based periodic unavailability operation. */ WMI_SERVICE_EM_ECO_MODE_SUPPORT = 457, /* Indicates support for ECO mode config (LP BBF+ADC+SYNCT) */ + WMI_SERVICE_11BN = 458, /* Indicates FW supports 802.11bn */ + WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index e18ddc622ffa..8331feb3c89f 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -11701,10 +11701,6 @@ typedef struct { * This TLV is followed by another TLV of array of bytes * num_channels * size of(struct wmi_channel_stats) */ -/* If WMI_REQUEST_VDEV_RECV_BCN_STAT is set in stats_id, then TLV - * wmi_recv_bcn_stats wmi_recv_bcn_stats[] - * follows the other TLVs - */ } wmi_radio_link_stats_event_fixed_param; /* per rate statistics */ @@ -12201,6 +12197,10 @@ typedef struct { * wmi_pdev_telemetry_stats wmi_pdev_telemetry_stats[] * follows the other TLVs */ +/* If WMI_REQUEST_VDEV_RECV_BCN_STAT is set in stats_id, then TLV + * wmi_recv_bcn_stats wmi_recv_bcn_stats[] + * follows the other TLVs + */ } wmi_stats_event_fixed_param; /* WLAN channel CCA stats bitmap */ @@ -37634,8 +37634,9 @@ typedef struct { supports_11ac:1, supports_11ax:1, supports_11be:1, + supports_11bn:1, - unused: 21, + unused: 20, max_mubfee: 4; /* max MU beamformees supported per MAC */ }; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index b28cb730d141..f0c4ba10047c 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1628 +#define __WMI_REVISION_ 1629 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From a6824ab6ea289f010303c1dc00aaeb4ce66c04bf Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 24 Jun 2025 06:01:36 -0700 Subject: [PATCH 143/306] fw-api: CL 29574189 - update fw common interface files Change-Id: I4fd0b336a81a1587925eadf4b057d25bc6b70f6e CRs-Fixed: 3830439 --- fw/wmi_unified.h | 3 +++ fw/wmi_version.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 8331feb3c89f..ecc032960b7d 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -10095,6 +10095,9 @@ typedef enum { /* To enable/disable DFS radar detection for scan radio */ WMI_PDEV_PARAM_ENABLE_SCAN_RADIO_DFS, + + /* configure CCE rules based on ethertype match */ + WMI_PDEV_PARAM_CONFIG_CUSTOM_CCE_RULE, } WMI_PDEV_PARAM; #define WMI_PDEV_ONLY_BSR_TRIG_IS_ENABLED(trig_type) WMI_GET_BITS(trig_type, 0, 1) diff --git a/fw/wmi_version.h b/fw/wmi_version.h index f0c4ba10047c..3b25bdc6dedf 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1629 +#define __WMI_REVISION_ 1630 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From f2614b0f3c9f6d0403536cc1ce88c5f71463963e Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 24 Jun 2025 21:31:13 -0700 Subject: [PATCH 144/306] fw-api: CL 29596437 - update fw common interface files Change-Id: Idffc62551252713f57cd181a8d6d1b331a436cff CRs-Fixed: 3830439 --- fw/htt.h | 122 ++++++++++++++++++++++++++++++++++++- fw/wmi_services.h | 1 + fw/wmi_unified.h | 150 +++++++++++++++++++++++++--------------------- fw/wmi_version.h | 2 +- 4 files changed, 204 insertions(+), 71 deletions(-) diff --git a/fw/htt.h b/fw/htt.h index 50b67b47fb3c..4f98bce1d7cb 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -270,9 +270,10 @@ * 3.140 Add H2T MPDUQ_AND_MSDUQ_INFO_HDR and MPDUQ_OF_MSDUQ_INFO defs. * 3.141 Add H2T HTT_AST_INFO for RxOLE. * 3.142 Add T2H GLOBAL_PEER_ID_UNMAP def, update H2T MPDUQ_OR_MSDUQ_INFO def. + * 3.143 Add T2H HAPS msg def. */ #define HTT_CURRENT_VERSION_MAJOR 3 -#define HTT_CURRENT_VERSION_MINOR 142 +#define HTT_CURRENT_VERSION_MINOR 143 #define HTT_NUM_TX_FRAG_DESC 1024 @@ -12182,6 +12183,7 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_SDWF_MSDUQ_CFG_IND = 0x3c, HTT_T2H_MSG_TYPE_MLO_LATENCY_REQ = 0x3d, HTT_T2H_MSG_TYPE_GLOBAL_PEER_ID_UNMAP = 0x3e, + HTT_T2H_MSG_TYPE_HAPS = 0x3f, HTT_T2H_MSG_TYPE_TEST, @@ -24069,4 +24071,122 @@ PREPACK struct htt_t2h_global_peer_id_unmap_t { } while (0) +/* + * @brief target -> pause/unpause host tx queues based on FW indication + * MSG_TYPE => HTT_T2H_MSG_TYPE_HAPS + * + * @details * Header fields: + * + * |31 22|21 20|19 16|15 8|7 0| + * |---------+-------------+-----------+------------------+---------------| + * | RSVD |time_type |action_code| vdev_id | msg type | + * |----------------------------------------------------------------------| + * | time_high | + * |----------------------------------------------------------------------| + * | time_low | + * |----------------------------------------------------------------------| + * + * dword0 - b'7:0 - msg_type: This will be set to + * 0x3f (HTT_T2H_MSG_TYPE_HAPS) + * b'15:8 - vdev_id + * b'19:16 - action_code (HTT_T2H_HAPS_ACTION_CODE): + * b'0000: Pause + * b'0001: Pause with One-Shot Unpause + * b'0010: Unpause + * values 3-15: reserved + * b'21:20 - time_type + * b'31:22 - rsvd + * reverse action_code at time specified below + * (units are specified by the type_type bitfield) + * dword1 - b'31:0 uint32_t time_high + * dword2 - b'31:0 uint32_t time_low + */ +typedef enum { + HTT_T2H_HAPS_ACTION_PAUSE = 0x00, + HTT_T2H_HAPS_ACTION_PAUSE_WITH_ONESHOT_UNPAUSE = 0x01, + HTT_T2H_HAPS_ACTION_UNPAUSE = 0x02, +} HTT_T2H_HAPS_ACTION_CODE; + +typedef enum { + HTT_T2H_HAPS_TIME_TYPE_HOST_QTIME = 0x00, + HTT_T2H_HAPS_TIME_TYPE_TSF = 0x01, +} HTT_T2H_HAPS_TIME_TYPE; + +PREPACK struct htt_t2h_power_state_info { + uint32_t msg_type : 8, /* [7:0] */ + vdev_id : 8, /* [15:8] */ + action_code : 4, /* [19:16] */ + time_type: 2, /* [21:20] */ + rsvd: 10; /* [31:22] */ + uint32_t time_low; + uint32_t time_high; +} POSTPACK; + +#define HTT_T2H_POWER_STATE_INFO_SIZE (sizeof(struct htt_t2h_power_state_info)) + +#define HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_M 0x0000FF00 +#define HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_S 8 + +#define HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_GET(_var) \ + (((_var) & HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_M) >> \ + HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_S) +#define HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_T2H_POWER_STATE_INFO_HTT_VDEV_ID_S));\ + } while (0) + +#define HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_M 0x000F0000 +#define HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_S 16 + +#define HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_GET(_var) \ + (((_var) & HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_M) >> \ + HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_S) +#define HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE, _val); \ + ((_var) |= ((_val) << HTT_T2H_POWER_STATE_INFO_HTT_ACTION_CODE_S));\ + } while (0) + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_M 0x00300000 +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_S 20 + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_GET(_var) \ + (((_var) & HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_M) >> \ + HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_S) + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE, _val); \ + ((_var) |= ((_val) << HTT_T2H_POWER_STATE_INFO_HTT_TIME_TYPE_S));\ + } while (0) + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_M 0xFFFFFFFF +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_S 0 + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_GET(_var) \ + (((_var) & HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_M) >> \ + HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_S) + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH, _val); \ + ((_var) |= ((_val) << HTT_T2H_POWER_STATE_INFO_HTT_TIME_HIGH_S));\ + } while (0) + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_M 0xFFFFFFFF +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_S 0 + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_GET(_var) \ + (((_var) & HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_M) >> \ + HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_S) + +#define HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW, _val); \ + ((_var) |= ((_val) << HTT_T2H_POWER_STATE_INFO_HTT_TIME_LOW_S));\ + } while (0) + + + #endif diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 55202bf9730f..ae9f2b69e5d4 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -717,6 +717,7 @@ typedef enum { WMI_SERVICE_EM_ECO_MODE_SUPPORT = 457, /* Indicates support for ECO mode config (LP BBF+ADC+SYNCT) */ WMI_SERVICE_11BN = 458, /* Indicates FW supports 802.11bn */ + WMI_SERVICE_HOST_AWARE_POWERSAVE = 459, /* FW supports indicating the powerstate of FW to host */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index ecc032960b7d..b65c95f78f0f 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -5181,6 +5181,13 @@ typedef struct { reserved: 31; }; }; + /** + * @brief HAPS flags setting for power save config + * bit 0 : Enable disable haps feature + * bit 1 : Sync and update qtime cnss timestamp + * BIT 2-31: Reserved + */ + A_UINT32 dp_haps_config; } wmi_resource_config; #define WMI_RSRC_CFG_APF_DATA_OFLD_ENABLE_GET(word32) \ WMI_GET_BITS(word32, 0, 1) @@ -20661,91 +20668,96 @@ enum wmi_sta_ps_scheme_cfg { WMI_STA_PS_OPM_CONSERVATIVE = 0, WMI_STA_PS_OPM_AGGRESSIVE = 1, WMI_STA_PS_USER_DEF = 2, + WMI_STA_PS_LATENCY_DEF = 3, }; enum wmi_sta_powersave_param { -/** - * Controls how frames are retrievd from AP while STA is sleeping - * - * (see enum wmi_sta_ps_param_rx_wake_policy) - */ -WMI_STA_PS_PARAM_RX_WAKE_POLICY = 0, + /** + * Controls how frames are retrievd from AP while STA is sleeping + * + * (see enum wmi_sta_ps_param_rx_wake_policy) + */ + WMI_STA_PS_PARAM_RX_WAKE_POLICY = 0, -/** - * The STA will go active after this many TX - * - * (see enum wmi_sta_ps_param_tx_wake_threshold) - */ -WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD = 1, + /** + * The STA will go active after this many TX + * + * (see enum wmi_sta_ps_param_tx_wake_threshold) + */ + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD = 1, -/** - * Number of PS-Poll to send before STA wakes up - * - * (see enum wmi_sta_ps_param_pspoll_count) - * - */ -WMI_STA_PS_PARAM_PSPOLL_COUNT = 2, + /** + * Number of PS-Poll to send before STA wakes up + * + * (see enum wmi_sta_ps_param_pspoll_count) + * + */ + WMI_STA_PS_PARAM_PSPOLL_COUNT = 2, -/** - * TX/RX inactivity time in msec before going to sleep. - * - * The power save SM will monitor tx/rx activity on the VDEV, if no - * activity for the specified msec of the parameter the Power save SM will - * go to sleep. - */ -WMI_STA_PS_PARAM_INACTIVITY_TIME = 3, + /** + * TX/RX inactivity time in msec before going to sleep. + * + * The power save SM will monitor tx/rx activity on the VDEV, if no + * activity for the specified msec of the parameter the Power save SM will + * go to sleep. + */ + WMI_STA_PS_PARAM_INACTIVITY_TIME = 3, -/** - * Set uapsd configuration. - * - * (see enum wmi_sta_ps_param_uapsd) - */ -WMI_STA_PS_PARAM_UAPSD = 4, + /** + * Set uapsd configuration. + * + * (see enum wmi_sta_ps_param_uapsd) + */ + WMI_STA_PS_PARAM_UAPSD = 4, -/** - * Number of PS-Poll to send before STA wakes up in QPower Mode - */ -WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT = 5, + /** + * Number of PS-Poll to send before STA wakes up in QPower Mode + */ + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT = 5, -/** - * Enable OPM - */ -WMI_STA_PS_ENABLE_QPOWER = 6, - WMI_STA_PS_ENABLE_OPM = WMI_STA_PS_ENABLE_QPOWER, /* alias */ + /** + * Enable OPM + */ + WMI_STA_PS_ENABLE_QPOWER = 6, + WMI_STA_PS_ENABLE_OPM = WMI_STA_PS_ENABLE_QPOWER, /* alias */ -/** - * Number of TX frames before the entering the Active state - */ -WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE = 7, + /** + * Number of TX frames before the entering the Active state + */ + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE = 7, -/** - * QPower SPEC PSPOLL interval - */ -WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL = 8, + /** + * QPower SPEC PSPOLL interval + */ + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL = 8, -/** - * Max SPEC PSPOLL to be sent when the PSPOLL response has - * no-data bit set - */ -WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL = 9, + /** + * Max SPEC PSPOLL to be sent when the PSPOLL response has + * no-data bit set + */ + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL = 9, -/** - * Max value of ITO reset when there is no tx-rx - * after AP has set the TIM bit - */ -WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX = 10, + /** + * Max value of ITO reset when there is no tx-rx + * after AP has set the TIM bit + */ + WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX = 10, -/** - * Flag to enable/disable Powersave Optimization - * in WOW - */ -WMI_STA_PS_PARAM_ENABLE_PS_OPT_IN_WOW = 11, + /** + * Flag to enable/disable Powersave Optimization + * in WOW + */ + WMI_STA_PS_PARAM_ENABLE_PS_OPT_IN_WOW = 11, -/** - * Speculative interval in ms - */ -WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL = 12, + /** + * Speculative interval in ms + */ + WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL = 12, + /** + * Value determines the ITO level to apply + */ + WMI_STA_PS_PARAM_ITO_LEVEL = 13, }; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 3b25bdc6dedf..9d3b7c037682 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1630 +#define __WMI_REVISION_ 1631 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 7cf61af347b71f5f0de46e8f0299b98e9bbd1856 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 26 Jun 2025 21:39:30 -0700 Subject: [PATCH 145/306] fw-api: CL 29622365 - update fw common interface files Change-Id: I8b16a6994984bfc96b972f67724cd6c417fa6260 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 8 +++- fw/wmi_unified.h | 114 +++++++++++++++++++++++++++++++++++++++++++++- fw/wmi_version.h | 2 +- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index f28e569b80c6..6d8b0fd4cdd8 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1494,6 +1494,9 @@ typedef enum { WMITLV_TAG_STRUC_wmi_energy_mgmt_edps_config_cmd_fixed_param, WMITLV_TAG_STRUC_wmi_energy_mgmt_puo_config_cmd_fixed_param, WMITLV_TAG_STRUC_wmi_energy_mgmt_eco_mode_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_mpduq_params, + WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_msduq_params, + WMITLV_TAG_STRUC_wmi_peer_assoc_hol_mdsuq_params, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2898,7 +2901,10 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_eht_rate_set, peer_eht_rates, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mlo_partner_link_params, partner_link_params, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_tid_to_link_map, peer_tid_to_link_map, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_operating_mode_params, operating_mode_params, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_operating_mode_params, operating_mode_params, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_mpduq_params, wmi_peer_assoc_mgmt_mpduq_params, mgmt_mpduq_params, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mgmt_msduq_params, mgmt_msduq_params, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_hol_mdsuq_params, wmi_peer_assoc_hol_mdsuq_params, hol_mdsuq_params, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CMDID); diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index b65c95f78f0f..64048b7e412a 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -21273,6 +21273,9 @@ typedef struct { wmi_mlo_flags mlo_flags; /* only mlo enable flag need by STA mode peer create */ } wmi_peer_create_mlo_params; +#define WMI_PEER_CREATE_GET_HW_PEER_ID_VALID(flags) WMI_GET_BITS(flags,0,1) +#define WMI_PEER_CREATE_SET_HW_PEER_ID_VALID(flags) WMI_SET_BITS(flags,0,1,value) + typedef struct { A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param */ /** unique id identifying the VDEV, generated by the caller */ @@ -21281,7 +21284,19 @@ typedef struct { wmi_mac_addr peer_macaddr; /** peer type: see enum values above */ A_UINT32 peer_type; -/* The TLVs follows this structure: + /** Peer create flags */ + union { + struct { + A_UINT32 hw_peer_id_valid :1, + reserved :31; + }; + A_UINT32 flags; + }; + /** Global sw peer id, valid only if non-zero */ + A_UINT32 sw_peer_id; + /** Global hardware id, valid only if hw_peer_id_valid is set */ + A_UINT32 hw_peer_id; +/* The TLVs follow this structure: * wmi_peer_create_mlo_params mlo_params[]; <-- MLO flags on peer_create * Optional TLV, only present for MLO peers. * If the peer is non-MLO, the array length should be 0. @@ -22181,6 +22196,101 @@ typedef struct { A_UINT32 bw; } wmi_peer_assoc_operating_mode_params; + +typedef enum { + WMI_MGMT_TID_MSDUQ_LINK_SPECIFIC,/* legacy and link peer */ + WMI_MGMT_TID_MSDUQ_LINK_AGNOSTIC, + WMI_MGMT_TID_MSDUQ_TYPE_MAX, +} WMI_MGMT_TID_MSDUQ_TYPE; + +#define WMI_MGMT_MSDUQ_GET_LINK_ID(msduq_type) WMI_GET_BITS(msduq_type,0,3) +#define WMI_MGMT_MSDUQ_SET_LINK_ID(msduq_type) WMI_SET_BITS(msduq_type,0,3,value) +#define WMI_MGMT_MSDUQ_GET_FLOW_TYPE(msduq_type) WMI_GET_BITS(msduq_type,3,5) +#define WMI_MGMT_MSDUQ_SET_FLOW_TYPE(msduq_type) WMI_SET_BITS(msduq_type,3,5,value) + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and Len. Tag: WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_msduq_params*/ + union { + struct { + A_UINT32 link_id : 3, /* HW Link ID */ + flow_type : 5, /* WMI_MGMT_TID_MSDUQ_TYPE */ + reserved : 24; + }; + A_UINT32 msduq_type; + }; + + /* 40 bit physical address, 256 bytes alligned, LSB 8 bits are zero */ + A_UINT32 mgmt_msduq_paddr_39_8; +} wmi_peer_assoc_mgmt_msduq_params; + +typedef struct { + A_UINT32 tlv_header; /* TAG_ID : WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_mpduq_params */ + /* 40 bit physical address, 256 bytes alligned, LSB 8 bits are zero */ + A_UINT32 mgmt_mpduq_paddr_39_8; + A_UINT32 pn_paddr_31_0; + A_UINT32 pn_paddr_39_32; +} wmi_peer_assoc_mgmt_mpduq_params; + +#define WMI_HOL_QUEUE_GET_PEER_ID(mpduq_msduq_number) \ + WMI_GET_BITS(mpduq_msduq_number,0,12) +#define WMI_HOL_QUEUE_SET_PEER_ID(mpduq_msduq_number) \ + WMI_SET_BITS(mpduq_msduq_number,0,12,value) +#define WMI_HOL_QUEUE_GET_TID_NUM(mpduq_msduq_number) \ + WMI_GET_BITS(mpduq_msduq_number,12,5) +#define WMI_HOL_QUEUE_SET_TID_NUM(mpduq_msduq_number) \ + WMI_SET_BITS(mpduq_msduq_number,12,5,value) +#define WMI_HOL_QUEUE_GET_MPDUQ_TYPE(mpduq_msduq_number) \ + WMI_GET_BITS(mpduq_msduq_number,17,5) +#define WMI_HOL_MSDUQ_SET_MPDUQ_TYPE(mpduq_msduq_number) \ + WMI_SET_BITS(mpduq_msduq_number,17,5,value) +#define WMI_HOL_QUEUE_GET_MSDUQ_TYPE(mpduq_msduq_number) \ + WMI_GET_BITS(mpduq_msduq_number,22,5) +#define WMI_HOL_MSDUQ_SET_MSDUQ_TYPE(mpduq_msduq_number) \ + WMI_SET_BITS(mpduq_msduq_number,22,5,value) + +typedef struct { + A_UINT32 tlv_header; /* TAG_ID : WMITLV_TAG_STRUC_wmi_peer_assoc_hol_mdsuq_params */ + + /** + * A_UINT32 + * WMI_HOL_MSDUQ_GET_PEER_ID / WMI_HOL_MSDU_SET_PEER_ID + * peer_id:12, + * + * WMI_HOL_MSDUQ_GET_TID_NUM / WMI_HOL_MSDUQ_SET_TID_NUM + * tid_num:5, + * + * WMI_HOL_MPDUQ_GET_QUEUE_TYPE / WMI_HOL_MPDUQ_SET_QUEUE_TYPE + * mpduq_type:5, + * + * WMI_HOL_MSDUQ_GET_QUEUE_TYPE / WMI_HOL_MSDUQ_SET_QUEUE_TYPE + * msduq_type:5, + * + * rsvd:5; + */ + union { + struct { + A_UINT32 peer_id : 12, + tid_num : 5, + mpduq_type : 5, + msduq_type : 5, + reserved : 5; + }; + A_UINT32 mpduq_msduq_number; + }; + + /* 40 bit address, 256 bytes alligned LSB 8 bits are zero */ + A_UINT32 mpduq_paddr_39_8; + + /* 40 bit address, 256 bytes alligned LSB 8 bits are zero */ + A_UINT32 msduq_paddr_39_8; + + /* First 32 bits for pn physical address */ + A_UINT32 pn_paddr_31_0; + + /* Upper 8 bits of 40 bit pn physical address */ + A_UINT32 pn_paddr_39_32; +} wmi_peer_assoc_hol_mdsuq_params; + /* * PEER assoc_flags for assoc complete: * Bit 0: Set for peer data flush @@ -39352,7 +39462,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_ENERGY_MGMT_PCIE_CONFIG_CMDID); WMI_RETURN_STRING(WMI_ENERGY_MGMT_PCIE_LPM_CMDID); WMI_RETURN_STRING(WMI_ENERGY_MGMT_DCVS_CONFIG_CMDID); - WMI_RETURN_STRING(WMI_ENERGY_MGMT_DPS_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID); WMI_RETURN_STRING(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID); WMI_RETURN_STRING(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID); } diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 9d3b7c037682..3c6d21ce0bf3 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1631 +#define __WMI_REVISION_ 1632 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 1ffed48e3de5975405b1ce55262068b0cfe43b3b Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 2 Jul 2025 12:01:52 -0700 Subject: [PATCH 146/306] fw-api: CL 29659315 - update fw common interface files Change-Id: I3b7187e50a42ffb24ae942c1c50a9960a5610261 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 8 ++++---- fw/wmi_version.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 6d8b0fd4cdd8..46202cf40d5b 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -2902,9 +2902,9 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mlo_partner_link_params, partner_link_params, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_tid_to_link_map, peer_tid_to_link_map, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_operating_mode_params, operating_mode_params, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_mpduq_params, wmi_peer_assoc_mgmt_mpduq_params, mgmt_mpduq_params, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mgmt_mpduq_params, mgmt_mpduq_params, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_mgmt_msduq_params, mgmt_msduq_params, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_hol_mdsuq_params, wmi_peer_assoc_hol_mdsuq_params, hol_mdsuq_params, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_assoc_hol_mdsuq_params, hol_mdsuq_params, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CMDID); @@ -3681,7 +3681,7 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_UPDATE_MAC_ADDR_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_config_cmd_fixed_param, wmi_vdev_vbss_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_pn_info, vbss_peer_pn_info, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_sn_info, vbss_peer_sn_info, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info, wmi_vdev_vbss_peer_dyn_info, vbss_peer_dyn_info, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_dyn_info, vbss_peer_dyn_info, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_VBSS_CONFIG_CMDID); /* Pdev suspend Cmd */ @@ -7880,7 +7880,7 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VENDOR_PEER_EVENTID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_config_event_fixed_param, wmi_vdev_vbss_config_event_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_pn_info, vbss_peer_pn_info, WMITLV_SIZE_VAR) \ WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_sn_info, vbss_peer_sn_info, WMITLV_SIZE_VAR) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_vbss_peer_dyn_info, wmi_vdev_vbss_peer_dyn_info, vbss_peer_dyn_info, WMITLV_SIZE_VAR) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_vbss_peer_dyn_info, vbss_peer_dyn_info, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_VBSS_CONFIG_EVENTID); /* link switch event */ diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 3c6d21ce0bf3..71bf687b5891 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1632 +#define __WMI_REVISION_ 1633 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From abe05012db9daab2affe435b0c292d88e13dda6d Mon Sep 17 00:00:00 2001 From: spuligil Date: Sat, 5 Jul 2025 06:01:52 -0700 Subject: [PATCH 147/306] fw-api: CL 29678196 - update fw common interface files Change-Id: I5812a8d5266ce44ec1e94c95f17aacbc2a463da6 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_unified.h | 21 +++++++++++++++++++++ fw/wmi_version.h | 2 +- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index ae9f2b69e5d4..7ed9332a1b20 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -718,6 +718,7 @@ typedef enum { WMI_SERVICE_11BN = 458, /* Indicates FW supports 802.11bn */ WMI_SERVICE_HOST_AWARE_POWERSAVE = 459, /* FW supports indicating the powerstate of FW to host */ + WMI_SERVICE_PDEV_DIV_STATES_REPORT = 460, /* FW supports reporting antenna diversity states */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 64048b7e412a..85accae8c459 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -10762,6 +10762,16 @@ typedef struct { */ } wmi_pdev_tpc_config_event_fixed_param; + +typedef enum { + WMI_ASD_PRIMARY_ANT = 0, + WMI_ASD_DIVERSITY_ANT = 1, + WMI_ASD_THIRD_ANT = 2, + WMI_ASD_FOURTH_ANT = 3, + + WMI_ASD_MAX_ANTTYPE = 4 +} WMI_ASD_ANT_TYPE; + typedef struct { /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_div_rssi_antid_event_fixed_param */ A_UINT32 tlv_header; @@ -10775,6 +10785,17 @@ typedef struct { wmi_mac_addr macaddr; /* EVM value for stream0 and stream1 20Mhz, dB units */ A_INT32 chain_evm[WMI_MAX_CHAINS]; + /** num_antennas_valid: + * how many elements in the WMI_ASD_MAX_ANTTYPE arrays below + * contain valid info + */ + A_UINT32 num_antennas_valid; + /** switch count on each antenna attached to each chain */ + A_UINT32 ant_cnt[WMI_MAX_CHAINS][WMI_ASD_MAX_ANTTYPE]; + /** stay duration on each antenna attached to each chain (units: ms) */ + A_UINT32 ant_dur[WMI_MAX_CHAINS][WMI_ASD_MAX_ANTTYPE]; + /** RSSI on each antenna attached to each chain in dbm */ + A_INT32 ant_rssi[WMI_MAX_CHAINS][WMI_ASD_MAX_ANTTYPE]; } wmi_pdev_div_rssi_antid_event_fixed_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 71bf687b5891..e185fece7f03 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1633 +#define __WMI_REVISION_ 1634 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 610bee83fade1c9ada339d8686716abe2ae76b9f Mon Sep 17 00:00:00 2001 From: Prasad Arepalli Date: Mon, 7 Jul 2025 15:14:17 +0530 Subject: [PATCH 148/306] msm: ipa: Avoid use-after-free scenario Introduce changes to avoid use-after-free scenarios by accessing the memory before freeing it. Change-Id: Iaa5d29b400cad593045f3644cb60a51fc09682e8 Signed-off-by: Prasad Arepalli --- drivers/platform/msm/ipa/ipa_v3/ipa_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c index c2232d59b691..0db725a54626 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -770,9 +771,9 @@ int ipa_pm_register(struct ipa_pm_register_params *params, u32 *hdl) client->skip_clk_vote = params->skip_clk_vote; client->wlock = wakeup_source_register(NULL, client->name); if (!client->wlock) { - ipa_pm_deregister(*hdl); IPA_PM_ERR("IPA wakeup source register failed %s\n", client->name); + ipa_pm_deregister(*hdl); return -ENOMEM; } From dda266c12a603c6643ec92ffa266a5c40d6c0c2f Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 9 Jul 2025 06:01:54 -0700 Subject: [PATCH 149/306] fw-api: CL 29712800 - update fw common interface files Change-Id: I57be3caf23aacb8a66905472ad72b90b2ef03999 CRs-Fixed: 3830439 --- fw/htt.h | 3 +++ fw/htt_stats.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/fw/htt.h b/fw/htt.h index 4f98bce1d7cb..6e1874396d53 100644 --- a/fw/htt.h +++ b/fw/htt.h @@ -863,6 +863,9 @@ typedef enum { HTT_STATS_TX_PDEV_PENDING_SEQ_CNT_IN_TXQ_HIST_TAG = 217, /* htt_stats_tx_pdev_pending_seq_cnt_in_txq_hist_tlv */ HTT_STATS_SCHED_TXQ_EARLY_COMPL_TAG = 218, /* htt_stats_sched_txq_early_compl_tlv */ HTT_STATS_RX_PDEV_BN_UL_OFDMA_USER_TAG = 219, /* htt_stats_rx_pdev_bn_ul_ofdma_user_tlv */ + HTT_STATS_TX_SELFGEN_BN_ERR_TAG = 220, /* htt_stats_tx_selfgen_bn_err_tlv, TOPIC=advanced */ + HTT_STATS_TX_SELFGEN_BN_TAG = 221, /* htt_stats_tx_selfgen_bn_tlv, TOPIC=advanced */ + HTT_STATS_TX_SELFGEN_BN_SCHED_STATUS_TAG = 222, /* htt_stats_tx_selfgen_bn_sched_status_tlv, TOPIC=advanced */ HTT_STATS_MAX_TAG, } htt_stats_tlv_tag_t; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 26f867cfe9ad..395dc8ca87e1 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -3417,6 +3417,35 @@ typedef struct { /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_selfgen_be_stats_tlv htt_tx_selfgen_be_stats_tlv; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + /** 11bn UHR MU Basic Trigger frame sent over the air */ + A_UINT32 bn_basic_trigger; + /** 11bn UHR MU BSRP Trigger frame sent over the air */ + A_UINT32 bn_bsr_trigger; + /** 11bn UHR MU BAR Trigger frame sent over the air */ + A_UINT32 bn_mu_bar_trigger; + /** 11bn UHR MU RTS Trigger frame sent over the air */ + A_UINT32 bn_mu_rts_trigger; + + /** 11BN UHR MU Combined Freq. BSRP Trigger frame sent over the air */ + A_UINT32 combined_bn_bsr_trigger_tried[HTT_NUM_AC_WMM]; + /** 11BN UHR MU Combined Freq. BSRP Trigger completed with error(s) */ + A_UINT32 combined_bn_bsr_trigger_err[HTT_NUM_AC_WMM]; + /** 11BN UHR MU Standalone Freq. BSRP Trigger frame sent over the air */ + A_UINT32 standalone_bn_bsr_trigger_tried[HTT_NUM_AC_WMM]; + /** 11BN UHR MU Standalone Freq. BSRP Trigger completed with error(s) */ + A_UINT32 standalone_bn_bsr_trigger_err[HTT_NUM_AC_WMM]; + /** 11BN UHR Manual Single-User UL OFDMA Trigger frame sent over the air */ + A_UINT32 manual_bn_su_ulofdma_basic_trigger[HTT_NUM_AC_WMM]; + /** 11BN UHR Manual Single-User UL OFDMA Trigger completed with error(s) */ + A_UINT32 manual_bn_su_ulofdma_basic_trigger_err[HTT_NUM_AC_WMM]; + /** 11BN UHR Manual Multi-User UL OFDMA Trigger frame sent over the air */ + A_UINT32 manual_bn_mu_ulofdma_basic_trigger[HTT_NUM_AC_WMM]; + /** 11BN UHR Manual Multi-User UL OFDMA Trigger completed with error(s) */ + A_UINT32 manual_bn_mu_ulofdma_basic_trigger_err[HTT_NUM_AC_WMM]; +} htt_stats_tx_selfgen_bn_tlv; + typedef struct { /* DEPRECATED */ htt_tlv_hdr_t tlv_hdr; /** 11AX HE OFDMA NDPA frame queued to the HW */ @@ -3998,6 +4027,29 @@ typedef struct { /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_selfgen_be_err_stats_tlv htt_tx_selfgen_be_err_stats_tlv; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + /** 11BN UHR MU Basic Trigger frame completed with error(s) */ + A_UINT32 bn_basic_trigger_err; + /** 11BN UHR MU BSRP Trigger frame completed with error(s) */ + A_UINT32 bn_bsr_trigger_err; + /** 11BN UHR MU BAR Trigger frame completed with error(s) */ + A_UINT32 bn_mu_bar_trigger_err; + /** 11BN UHR MU RTS Trigger frame completed with error(s) */ + A_UINT32 bn_mu_rts_trigger_err; + + /** 11BN UHR MU OFDMA Basic Trigger frame completed with partial user response */ + A_UINT32 bn_basic_trigger_partial_resp; + /** 11BN UHR MU BSRP Trigger frame completed with partial user response */ + A_UINT32 bn_bsr_trigger_partial_resp; + /** 11BN UHR MU BAR Trigger frame completed with partial user response */ + A_UINT32 bn_mu_bar_trigger_partial_resp; + /** 11BN UHR MU RTS Trigger frame blocked due to partner link TX/RX(eMLSR) */ + A_UINT32 bn_mu_rts_trigger_blocked; + /** 11BN UHR MU BSR Trigger frame blocked due to partner link TX/RX(eMLSR) */ + A_UINT32 bn_bsr_trigger_blocked; +} htt_stats_tx_selfgen_bn_err_tlv; + /* * Scheduler completion status reason code. * (0) HTT_TXERR_NONE - No error (Success). @@ -4129,6 +4181,19 @@ typedef struct { typedef htt_stats_tx_selfgen_be_sched_status_stats_tlv htt_tx_selfgen_be_sched_status_stats_tlv; +typedef struct { + htt_tlv_hdr_t tlv_hdr; + /** 11BN UHR MU BAR scheduler completion status reason code */ + A_UINT32 bn_mu_bar_sch_status[HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + /** 11BN UHR MU BAR scheduler error code */ + A_UINT32 bn_mu_bar_sch_flag_err[HTT_TX_SELFGEN_NUM_SCH_TSFLAG_ERROR_STATS]; + + /** 11BN UHR UL OFDMA Basic Trigger scheduler completion status reason code */ + A_UINT32 bn_basic_trig_sch_status[HTT_TX_PDEV_STATS_NUM_TX_ERR_STATUS]; + /** 11BN UHR UL OFDMA Basic Trigger scheduler error code */ + A_UINT32 bn_basic_trig_sch_flag_err[HTT_TX_SELFGEN_NUM_SCH_TSFLAG_ERROR_STATS]; +} htt_stats_tx_selfgen_bn_sched_status_tlv; + /* STATS_TYPE : HTT_DBG_EXT_STATS_TX_SELFGEN_INFO * TLV_TAGS: * - HTT_STATS_TX_SELFGEN_CMN_STATS_TAG @@ -4141,6 +4206,9 @@ typedef htt_stats_tx_selfgen_be_sched_status_stats_tlv * - HTT_STATS_TX_SELFGEN_BE_STATS_TAG * - HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG * - HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG + * - HTT_STATS_TX_SELFGEN_BN_TAG + * - HTT_STATS_TX_SELFGEN_BN_ERR_TAG + * - HTT_STATS_TX_SELFGEN_BN_SCHED_STATUS_TAG */ /* NOTE: * This structure is for documentation, and cannot be safely used directly. @@ -4158,6 +4226,9 @@ typedef struct { htt_stats_tx_selfgen_be_stats_tlv be_tlv; htt_stats_tx_selfgen_be_err_stats_tlv be_err_tlv; htt_stats_tx_selfgen_be_sched_status_stats_tlv be_sched_status_tlv; + htt_stats_tx_selfgen_bn_tlv bn_tlv; + htt_stats_tx_selfgen_bn_err_tlv bn_err_tlv; + htt_stats_tx_selfgen_bn_sched_status_tlv bn_sched_status_tlv; } htt_tx_pdev_selfgen_stats_t; #endif /* ATH_TARGET */ From 312ae55c1fe5ae849f1bdab8050dad30e08885ca Mon Sep 17 00:00:00 2001 From: Sheenam Monga Date: Wed, 21 May 2025 13:26:16 +0530 Subject: [PATCH 150/306] qcacmn: Keep counter atomicity while logging Currently, there might be a case logging counter is incremented by one thread and used by another thread which can cause issue because payload is fetched from counter. To avoid above issue keep atomicity while incrementing the counter. CRs-Fixed: 4153670 Change-Id: I417b63df8da72918a830a1f8fe7a574bab549ea8 (cherry picked from commit 0ace5b3611f7b164f61c355909a165bf716440b7) --- qdf/linux/src/qdf_trace.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index 0b3e2dbd150d..30815cb19d89 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -411,10 +411,19 @@ void qdf_mtrace_log(QDF_MODULE_ID src_module, QDF_MODULE_ID dst_module, uint16_t message_id, uint8_t vdev_id) { uint32_t trace_log, payload; - static uint16_t counter; + static __qdf_atomic_t counter; + static bool initialized = false; + + // Initialize counter only once + if (!initialized) { + qdf_atomic_init(&counter); + initialized = true; + } trace_log = (src_module << 23) | (dst_module << 15) | message_id; - payload = (vdev_id << 16) | counter++; + + qdf_atomic_add(1, &counter); + payload = ((uint32_t)vdev_id << 16) | (qdf_atomic_read(&counter) & 0xFFFF); QDF_TRACE(src_module, QDF_TRACE_LEVEL_TRACE, "%x %x", trace_log, payload); From 112e55f2b4dc682c5e74a8734bbf82068f179465 Mon Sep 17 00:00:00 2001 From: Vedang Nagar Date: Mon, 19 May 2025 12:42:22 +0530 Subject: [PATCH 151/306] FROMLIST: media: venus: Fix OOB read due to missing payload bound check Currently, The event_seq_changed() handler processes a variable number of properties sent by the firmware. The number of properties is indicated by the firmware and used to iterate over the payload. However, the payload size is not being validated against the actual message length. This can lead to out-of-bounds memory access if the firmware provides a property count that exceeds the data available in the payload. Such a condition can result in kernel crashes or potential information leaks if memory beyond the buffer is accessed. Fix this by properly validating the remaining size of the payload before each property access and updating bounds accordingly as properties are parsed. This ensures that property parsing is safely bounded within the received message buffer and protects against malformed or malicious firmware behavior. Fixes: 09c2845e8fe4 ("[media] media: venus: hfi: add Host Firmware Interface (HFI)") Change-Id: Ife789627352a3caab24d6bd32ca286161b52758f Signed-off-by: Vedang Nagar Reviewed-by: Vikash Garodia Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/linux-media/20250519-venus-fixes-v4-2-3ae91d81443d@quicinc.com/ Co-developed-by: Dikshita Agarwal Signed-off-by: Dikshita Agarwal Signed-off-by: Vasantha Balla --- drivers/media/platform/qcom/venus/hfi_msgs.c | 86 +++++++++++++++----- 1 file changed, 64 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 5694d18b43d5..990c53398b9b 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -27,8 +27,10 @@ static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, struct hfi_colour_space *colour_info; struct hfi_buffer_requirements *bufreq; struct hfi_extradata_input_crop *crop; + struct hfi_dpb_counts *dpb_count; + u32 ptype, rem_bytes; + u32 size_read = 0; u8 *data_ptr; - u32 ptype; inst->error = HFI_ERR_NONE; @@ -38,80 +40,120 @@ static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, break; default: inst->error = HFI_ERR_SESSION_INVALID_PARAMETER; - goto done; + inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); + return; } event.event_type = pkt->event_data1; num_properties_changed = pkt->event_data2; - if (!num_properties_changed) { - inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; - goto done; - } + if (!num_properties_changed) + goto error; data_ptr = (u8 *)&pkt->ext_event_data[0]; + rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt); + do { + if (rem_bytes < sizeof(u32)) + goto error; ptype = *((u32 *)data_ptr); + + data_ptr += sizeof(u32); + rem_bytes -= sizeof(u32); + switch (ptype) { case HFI_PROPERTY_PARAM_FRAME_SIZE: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_framesize)) + goto error; + frame_sz = (struct hfi_framesize *)data_ptr; event.width = frame_sz->width; event.height = frame_sz->height; - data_ptr += sizeof(*frame_sz); + size_read = sizeof(struct hfi_framesize); break; case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_profile_level)) + goto error; + profile_level = (struct hfi_profile_level *)data_ptr; event.profile = profile_level->profile; event.level = profile_level->level; - data_ptr += sizeof(*profile_level); + size_read = sizeof(struct hfi_profile_level); break; case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_bit_depth)) + goto error; + pixel_depth = (struct hfi_bit_depth *)data_ptr; event.bit_depth = pixel_depth->bit_depth; - data_ptr += sizeof(*pixel_depth); + size_read = sizeof(struct hfi_bit_depth); break; case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_pic_struct)) + goto error; + pic_struct = (struct hfi_pic_struct *)data_ptr; event.pic_struct = pic_struct->progressive_only; - data_ptr += sizeof(*pic_struct); + size_read = sizeof(struct hfi_pic_struct); break; case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_colour_space)) + goto error; + colour_info = (struct hfi_colour_space *)data_ptr; event.colour_space = colour_info->colour_space; - data_ptr += sizeof(*colour_info); + size_read = sizeof(struct hfi_colour_space); break; case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(u32)) + goto error; + event.entropy_mode = *(u32 *)data_ptr; - data_ptr += sizeof(u32); + size_read = sizeof(u32); break; case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_buffer_requirements)) + goto error; + bufreq = (struct hfi_buffer_requirements *)data_ptr; event.buf_count = HFI_BUFREQ_COUNT_MIN(bufreq, ver); data_ptr += sizeof(*bufreq); + event.buf_count = hfi_bufreq_get_count_min(bufreq, ver); + size_read = sizeof(struct hfi_buffer_requirements); break; case HFI_INDEX_EXTRADATA_INPUT_CROP: - data_ptr += sizeof(u32); + if (rem_bytes < sizeof(struct hfi_extradata_input_crop)) + goto error; + crop = (struct hfi_extradata_input_crop *)data_ptr; event.input_crop.left = crop->left; event.input_crop.top = crop->top; event.input_crop.width = crop->width; event.input_crop.height = crop->height; - data_ptr += sizeof(*crop); + size_read = sizeof(struct hfi_extradata_input_crop); + break; + case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: + if (rem_bytes < sizeof(struct hfi_dpb_counts)) + goto error; + + dpb_count = (struct hfi_dpb_counts *)data_ptr; + event.buf_count = dpb_count->fw_min_cnt; + size_read = sizeof(struct hfi_dpb_counts); break; default: + size_read = 0; break; } + data_ptr += size_read; + rem_bytes -= size_read; num_properties_changed--; } while (num_properties_changed > 0); -done: + inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); + return; + +error: + inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); } From 3a652ca6c2a0be5e121c2b86b2eed0011f818211 Mon Sep 17 00:00:00 2001 From: spuligil Date: Fri, 11 Jul 2025 06:03:12 -0700 Subject: [PATCH 152/306] fw-api: CL 29734524 - update fw common interface files Change-Id: Ic75a3f3ee0bc175c6f0b56a6951343bf72657d37 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 8 ++++++++ fw/wmi_unified.h | 21 +++++++++++++++++++++ fw/wmi_version.h | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 46202cf40d5b..8d9a1ace4801 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1497,6 +1497,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_mpduq_params, WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_msduq_params, WMITLV_TAG_STRUC_wmi_peer_assoc_hol_mdsuq_params, + WMITLV_TAG_STRUC_wmi_peer_tid_rate_custom_cmd_fixed_param, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -2068,6 +2069,7 @@ typedef enum { OP(WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID) \ OP(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID) \ OP(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID) \ + OP(WMI_PEER_TID_RATE_CUSTOM_CMDID) \ /* add new CMD_LIST elements above this line */ @@ -5831,6 +5833,12 @@ WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID); WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_energy_mgmt_eco_mode_config_cmd_fixed_param, wmi_energy_mgmt_eco_mode_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) WMITLV_CREATE_PARAM_STRUC(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID); +/* peer tid rate customization cmd */ +#define WMITLV_TABLE_WMI_PEER_TID_RATE_CUSTOM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tid_rate_custom_cmd_fixed_param, wmi_peer_tid_rate_custom_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, rate_code, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TID_RATE_CUSTOM_CMDID); + /************************** TLV definitions of WMI events *******************************/ diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 85accae8c459..3d0c3f32cd2f 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -852,6 +852,9 @@ typedef enum { /* WMI command to setup reorder queue for multiple TIDs */ WMI_PEER_MULTIPLE_REORDER_QUEUE_SETUP_CMDID, + /** Customize MCS range for specific tid */ + WMI_PEER_TID_RATE_CUSTOM_CMDID, + /* beacon/management specific commands */ /** transmit beacon by reference . used for transmitting beacon on low latency interface like pcie */ @@ -33862,6 +33865,23 @@ typedef struct { A_UINT32 tid_mask; /* bits 0 to 15 = QoS TIDs, bit 16 = non-qos TID */ } wmi_peer_reorder_queue_remove_cmd_fixed_param; +/** + * This command is sent from WLAN host driver to firmware for + * customizing MCS range & retry count for specific TID of specific peer + */ +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + wmi_mac_addr peer_macaddr; /* Peer MAC address */ + A_UINT32 tid; + /* on_off: + * Rate customization enable/disable. 1 for enable and 0 for disable. + */ + A_UINT32 on_off; + A_UINT32 bw; /* Unit MHz */ + A_UINT32 retry_count; +} wmi_peer_tid_rate_custom_cmd_fixed_param; + /* DEPRECATED - use wmi_pdev_set_mac_config_response_event_fixed_param instead */ typedef struct { @@ -39486,6 +39506,7 @@ static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) WMI_RETURN_STRING(WMI_ENERGY_MGMT_EDPS_CONFIG_CMDID); WMI_RETURN_STRING(WMI_ENERGY_MGMT_PUO_CONFIG_CMDID); WMI_RETURN_STRING(WMI_ENERGY_MGMT_ECO_MODE_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_PEER_TID_RATE_CUSTOM_CMDID); } return (A_UINT8 *) "Invalid WMI cmd"; diff --git a/fw/wmi_version.h b/fw/wmi_version.h index e185fece7f03..1437afa1b225 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1634 +#define __WMI_REVISION_ 1635 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 0d355ad3f314672e592e030d87ff065f4d39376c Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Fri, 20 Jun 2025 03:32:23 -0700 Subject: [PATCH 153/306] Add configures to enable CNSS platform driver This change adds below configures to enable CNSS platform driver. CONFIG_CNSS=m CONFIG_CNSS_CRYPTO=y CONFIG_CNSS_PCI=y CONFIG_CNSS_LOGGER=m Change-Id: Ib318b617e98db65a097794a30ddca919775e0f04 Signed-off-by: Wu Gao --- arch/arm/configs/vendor/sdxlemur.config | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/configs/vendor/sdxlemur.config b/arch/arm/configs/vendor/sdxlemur.config index 2d12580404e8..0d6a262c17ea 100644 --- a/arch/arm/configs/vendor/sdxlemur.config +++ b/arch/arm/configs/vendor/sdxlemur.config @@ -51,6 +51,10 @@ CONFIG_CNSS_ASYNC=y CONFIG_CNSS_QCA6490=y CONFIG_CNSS_UTILS=y # CONFIG_CNSS_GENL is not set +CONFIG_CNSS=m +CONFIG_CNSS_CRYPTO=y +CONFIG_CNSS_PCI=y +CONFIG_CNSS_LOGGER=m CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_PACKET=y CONFIG_UNIX=y From 8be762469ab18b40e4cea9223a1bf86fa203159d Mon Sep 17 00:00:00 2001 From: "Kaushik K.N" Date: Mon, 14 Jul 2025 21:50:31 +0530 Subject: [PATCH 154/306] qcacld-3.0: Add Validation for WMA Handle and PSOC in Wake Event Currently, the WOW wakeup event handler lacks validation for the WMA handle and the PSOC pointer within the WMA handle. This omission can lead to null pointer dereferences in the host. To address this issue, null pointer checks for both the WMA handle and the PSOC pointer have been added. CRs-Fixed: 4107000 Change-Id: Iaf22d5adc14b65b778b0e1d78108eded0cccb8c9 --- core/wma/src/wma_features.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/wma/src/wma_features.c b/core/wma/src/wma_features.c index 03a51f01fbd4..e5a234adc325 100644 --- a/core/wma/src/wma_features.c +++ b/core/wma/src/wma_features.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -2813,6 +2813,9 @@ int wma_wow_wakeup_host_event(void *handle, uint8_t *event, uint32_t len) WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *event_param; WOW_EVENT_INFO_fixed_param *wake_info; + if (!wma || !wma->psoc) + return -EINVAL; + event_param = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *)event; if (!event_param) { wma_err("Wake event data is null"); From 808c8d2af8c2a526bc793b9ed552dd1bc5b8b112 Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 15 Jul 2025 06:01:45 -0700 Subject: [PATCH 155/306] fw-api: CL 29754552 - update fw common interface files Change-Id: Ic6032c259105e7eae104f27d0468b21152fd5c9b CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + fw/wmi_version.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 7ed9332a1b20..0f79ea9e4871 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -719,6 +719,7 @@ typedef enum { WMI_SERVICE_11BN = 458, /* Indicates FW supports 802.11bn */ WMI_SERVICE_HOST_AWARE_POWERSAVE = 459, /* FW supports indicating the powerstate of FW to host */ WMI_SERVICE_PDEV_DIV_STATES_REPORT = 460, /* FW supports reporting antenna diversity states */ + WMI_SERVICE_EAPOL_OVER_RAW = 461, /* FW supports sending EAPOL frames in raw mode even when the vdev is brought up in nwifi/ethernet mode */ WMI_MAX_EXT2_SERVICE diff --git a/fw/wmi_version.h b/fw/wmi_version.h index 1437afa1b225..cffc5c2adeab 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1635 +#define __WMI_REVISION_ 1636 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From c60180a52b84a06883994b1d5d758707fe62c5e4 Mon Sep 17 00:00:00 2001 From: spuligil Date: Tue, 15 Jul 2025 06:03:38 -0700 Subject: [PATCH 156/306] fw-api: CL 29754585 - update fw common interface files Change-Id: Icbc386dc553f774e13981ee2aa645403df411777 CRs-Fixed: 3830439 --- fw/htt_ppdu_stats.h | 78 +++++++++++++++++++++++++++++++++++++-------- fw/htt_stats.h | 32 +++++++++++++++++++ 2 files changed, 97 insertions(+), 13 deletions(-) diff --git a/fw/htt_ppdu_stats.h b/fw/htt_ppdu_stats.h index d1575d7c91ba..5f7bad98cb84 100644 --- a/fw/htt_ppdu_stats.h +++ b/fw/htt_ppdu_stats.h @@ -707,6 +707,58 @@ typedef enum HTT_PPDU_STATS_SPATIAL_REUSE HTT_PPDU_STATS_SPATIAL_REUSE; (((_val) & HTT_PPDU_STATS_COMMON_TRIG_COOKIE_M) >> \ HTT_PPDU_STATS_COMMON_TRIG_COOKIE_S) +#define HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_M 0x00000001 +#define HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_S 0 + +#define HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_GET(_var) \ + (((_var) & HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_M) >> \ + HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_S) + +#define HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE, _val); \ + ((_var) |= ((_val) << HTT_PPDU_STATS_COMMON_TLV_HTT_SEQ_TYPE_S)); \ + } while (0) + +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_M 0x00000002 +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_S 1 + +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_GET(_var) \ + (((_var) & HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_M) >> \ + HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_S) + +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER, _val); \ + ((_var) |= ((_val) << HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BASIC_TRIGGER_S)); \ + } while (0) + +#define HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_M 0x00000004 +#define HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_S 2 + +#define HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_GET(_var) \ + (((_var) & HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_M) >> \ + HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_S) + +#define HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER, _val); \ + ((_var) |= ((_val) << HTT_PPDU_STATS_COMMON_TLV_IS_MANUAL_ULOFDMA_TRIGGER_S)); \ + } while (0) + +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_M 0x00000008 +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_S 3 + +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_GET(_var) \ + (((_var) & HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_M) >> \ + HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_S) + +#define HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER, _val); \ + ((_var) |= ((_val) << HTT_PPDU_STATS_COMMON_TLV_IS_COMBINED_UL_BSRP_TRIGGER_S)); \ + } while (0) + enum HTT_SEQ_TYPE { WAL_PPDU_SEQ_TYPE = 0, HTT_PPDU_SEQ_TYPE = 1, @@ -902,26 +954,26 @@ typedef struct { * HTT_PPDU_SEQ_TYPE then decoder should interpret the * seq type as HTT_PPDU_STATS_SEQ_TYPE. * htt_seq_type field will be set to HTT_PPDU_SEQ_TYPE in - * firmware versions where this field is defined. - * BIT [31: 1] - reserved + * BIT [1 : 1] - is_combined_ul_basic_trigger - Flag to indicate if a + * given UL OFDMA/MU-MIMO Basic trigger is sent combined + * as part of existing DL data sequence. + * BIT [2 : 2] - is_manual_ulofdma_trigger - Flag to indicate if a + * given UL OFDMA trigger is manually triggered from the Host. + * BIT [3 : 3] - is_combined_ul_bsrp_trigger - Flag to indicate if a + * given UL BSRP trigger is sent combined as part of + * an existing DL/UL data sequence + * BIT [31: 4] - reserved */ union { A_UINT32 reserved__htt_seq_type; struct { A_UINT32 htt_seq_type: 1, - reserved3: 31; + is_combined_ul_basic_trigger: 1, + is_manual_ulofdma_trigger: 1, + is_combined_ul_bsrp_trigger: 1, + reserved3: 28; }; }; - /* is_manual_ulofdma_trigger: - * Flag to indicate if a given UL OFDMA trigger is manually triggered - * from the Host - */ - A_UINT32 is_manual_ulofdma_trigger; - /* is_combined_ul_bsrp_trigger: - * Flag to indicate if a given UL BSRP trigger is sent combined as - * part of existing DL/UL data sequence - */ - A_UINT32 is_combined_ul_bsrp_trigger; /* Flag to indicate if the channel chosen is 320_1 / 320_2 */ A_UINT32 chan_type_320mhz; } htt_ppdu_stats_common_tlv; diff --git a/fw/htt_stats.h b/fw/htt_stats.h index 395dc8ca87e1..c0730881c023 100644 --- a/fw/htt_stats.h +++ b/fw/htt_stats.h @@ -3348,6 +3348,22 @@ typedef struct { A_UINT32 ax_mu_bar_trigger_per_ac[HTT_NUM_AC_WMM]; /** 11AX HE MU-BAR Trigger frames per AC completed with error(s) */ A_UINT32 ax_mu_bar_trigger_errors_per_ac[HTT_NUM_AC_WMM]; + /** 11AX HE MU Combined UL OFDMA Basic Trigger frame sent over the air */ + A_UINT32 combined_ax_ulofdma_trigger_tried[HTT_NUM_AC_WMM]; + /** 11AX HE MU Combined UL OFDMA Basic Trigger completed with error(s) */ + A_UINT32 combined_ax_ulofdma_trigger_err[HTT_NUM_AC_WMM]; + /** 11AX HE MU Standalone UL OFDMA Basic Trigger frame sent over the air */ + A_UINT32 standalone_ax_ulofdma_trigger_tried[HTT_NUM_AC_WMM]; + /** 11AX HE MU Standalone UL OFDMA Basic Trigger completed with error(s) */ + A_UINT32 standalone_ax_ulofdma_trigger_err[HTT_NUM_AC_WMM]; + /** 11AX HE MU Combined UL MU-MIMO Basic Trigger frame sent over the air */ + A_UINT32 combined_ax_ulmumimo_trigger_tried[HTT_NUM_AC_WMM]; + /** 11AX HE MU Combined UL MU-MIMO Basic Trigger completed with error(s) */ + A_UINT32 combined_ax_ulmumimo_trigger_err[HTT_NUM_AC_WMM]; + /** 11AX HE MU Standalone UL MU-MIMO Basic Trigger frame sent over the air*/ + A_UINT32 standalone_ax_ulmumimo_trigger_tried[HTT_NUM_AC_WMM]; + /** 11AX HE MU Standalone UL MU-MIMO Basic Trigger completed with error(s)*/ + A_UINT32 standalone_ax_ulmumimo_trigger_err[HTT_NUM_AC_WMM]; } htt_stats_tx_selfgen_ax_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_selfgen_ax_stats_tlv htt_tx_selfgen_ax_stats_tlv; @@ -3413,6 +3429,22 @@ typedef struct { A_UINT32 be_mu_bar_trigger_per_ac[HTT_NUM_AC_WMM]; /** 11BE EHT MU-BAR Trigger frames per AC completed with error(s) */ A_UINT32 be_mu_bar_trigger_errors_per_ac[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Combined UL OFDMA Basic Trigger frame sent over the air */ + A_UINT32 combined_be_ulofdma_trigger_tried[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Combined UL OFDMA Basic Trigger completed with error(s) */ + A_UINT32 combined_be_ulofdma_trigger_err[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Standalone UL OFDMA Basic Trigger frame sent over the air */ + A_UINT32 standalone_be_ulofdma_trigger_tried[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Standalone UL OFDMA Basic Trigger completed with error(s) */ + A_UINT32 standalone_be_ulofdma_trigger_err[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Combined UL MU-MIMO Basic Trigger frame sent over the air */ + A_UINT32 combined_be_ulmumimo_trigger_tried[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Combined UL MU-MIMO Basic Trigger completed with error(s) */ + A_UINT32 combined_be_ulmumimo_trigger_err[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Standalone UL MU-MIMO Basic Trigger frame sent over the air */ + A_UINT32 standalone_be_ulmumimo_trigger_tried[HTT_NUM_AC_WMM]; + /** 11BE EHT MU Standalone UL MU-MIMO Basic Trigger completed with error(s) */ + A_UINT32 standalone_be_ulmumimo_trigger_err[HTT_NUM_AC_WMM]; } htt_stats_tx_selfgen_be_stats_tlv; /* preserve old name alias for new name consistent with the tag name */ typedef htt_stats_tx_selfgen_be_stats_tlv htt_tx_selfgen_be_stats_tlv; From aa9867b1fcd45d006118fde4e6d5eba72087ac21 Mon Sep 17 00:00:00 2001 From: Vedang Nagar Date: Mon, 19 May 2025 12:42:21 +0530 Subject: [PATCH 157/306] FROMLIST: media: venus: Add a check for packet size Add a check to ensure that the packet size does not exceed the number of available words after reading the packet header from shared memory. This ensures that the size provided by the firmware is safe to process and prevent potential out-of-bounds memory access. Fixes: d96d3f30c0f2 ("[media] media: venus: hfi: add Venus HFI files") Change-Id: I561f411e0a448f8436dafdadb755deb563ce49c2 Reviewed-by: Bryan O'Donoghue Signed-off-by: Vedang Nagar Co-developed-by: Dikshita Agarwal Signed-off-by: Dikshita Agarwal Signed-off-by: Vasantha Balla --- drivers/media/platform/qcom/venus/hfi_venus.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 1b37d77bf998..33d9d50e79cd 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -240,6 +240,7 @@ static int venus_write_queue(struct venus_hfi_device *hdev, static int venus_read_queue(struct venus_hfi_device *hdev, struct iface_queue *queue, void *pkt, u32 *tx_req) { + struct hfi_pkt_hdr *pkt_hdr = NULL; struct hfi_queue_header *qhdr; u32 dwords, new_rd_idx; u32 rd_idx, wr_idx, type, qsize; @@ -305,6 +306,9 @@ static int venus_read_queue(struct venus_hfi_device *hdev, memcpy(pkt, rd_ptr, len); memcpy(pkt + len, queue->qmem.kva, new_rd_idx << 2); } + pkt_hdr = (struct hfi_pkt_hdr *)(pkt); + if ((pkt_hdr->size >> 2) != dwords) + return -EINVAL; } else { /* bad packet received, dropping */ new_rd_idx = qhdr->write_idx; From 8a31fb44f3b961f7c2ca4f53b659ec8cbacd679a Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Mon, 23 Jun 2025 03:03:28 -0700 Subject: [PATCH 158/306] cnss: Add support for building CNSS as a loadable module Add support for building CNSS as a loadable module. When CONFIG_CNSS=m is specified, CONFIG_CNSS_MODULE will be defined instead of CONFIG_CNSS. Change-Id: I367c2321836d124d30f08dae14bbe763acaf6c03 Signed-off-by: Wu Gao --- drivers/net/wireless/cnss/Makefile | 10 ++++++---- include/net/cnss.h | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/cnss/Makefile b/drivers/net/wireless/cnss/Makefile index c1ca4c3821e6..567ef214d7dd 100644 --- a/drivers/net/wireless/cnss/Makefile +++ b/drivers/net/wireless/cnss/Makefile @@ -3,7 +3,9 @@ # Makefile for CNSS platform driver # -obj-$(CONFIG_CNSS_PCI) += cnss_pci.o -obj-$(CONFIG_CNSS_SDIO) += cnss_sdio.o -obj-$(CONFIG_CNSS) += cnss_common.o -obj-$(CONFIG_CNSS_LOGGER) += logger/ +obj-$(CONFIG_CNSS) += cnss.o + +cnss-$(CONFIG_CNSS_PCI) += cnss_pci.o +cnss-$(CONFIG_CNSS_SDIO) += cnss_sdio.o +cnss-y += cnss_common.o +obj-$(CONFIG_CNSS_LOGGER) += logger/ diff --git a/include/net/cnss.h b/include/net/cnss.h index 9c99bdc2032d..77bc3157c2aa 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -10,7 +10,6 @@ #include #include -#ifdef CONFIG_CNSS #define MAX_FIRMWARE_SIZE (1 * 1024 * 1024) #define CNSS_MAX_FILE_NAME 20 #define PINCTRL_SLEEP 0 @@ -177,7 +176,6 @@ int cnss_pm_runtime_request(struct device *dev, enum cnss_runtime_request request); void cnss_set_cc_source(enum cnss_cc_src cc_source); enum cnss_cc_src cnss_get_cc_source(void); -#endif void cnss_pm_wake_lock_init(struct wakeup_source **ws, const char *name); void cnss_pm_wake_lock(struct wakeup_source *ws); From fd9deb56d1ff2a06c2a7a0ed9dce5b010d9b1bdf Mon Sep 17 00:00:00 2001 From: spuligil Date: Wed, 16 Jul 2025 06:01:42 -0700 Subject: [PATCH 159/306] fw-api: CL 29778978 - update fw common interface files Change-Id: Iecd76063e70aa0da774c4d39801d0e376b453704 CRs-Fixed: 3830439 --- fw/wmi_tlv_defs.h | 4 +++- fw/wmi_unified.h | 10 ++++++++++ fw/wmi_version.h | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/fw/wmi_tlv_defs.h b/fw/wmi_tlv_defs.h index 8d9a1ace4801..54ea736a2375 100644 --- a/fw/wmi_tlv_defs.h +++ b/fw/wmi_tlv_defs.h @@ -1498,6 +1498,7 @@ typedef enum { WMITLV_TAG_STRUC_wmi_peer_assoc_mgmt_msduq_params, WMITLV_TAG_STRUC_wmi_peer_assoc_hol_mdsuq_params, WMITLV_TAG_STRUC_wmi_peer_tid_rate_custom_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_co_located_chan_info, } WMITLV_TAG_ID; /* * IMPORTANT: Please add _ALL_ WMI Commands Here. @@ -3650,7 +3651,8 @@ WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DELETE_CMDID); /* Vdev up Cmd */ #define WMITLV_TABLE_WMI_VDEV_UP_CMDID(id,op,buf,len) \ - WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, wmi_vdev_up_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, wmi_vdev_up_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_co_located_chan_info, co_located_chan_info, WMITLV_SIZE_VAR) WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_UP_CMDID); diff --git a/fw/wmi_unified.h b/fw/wmi_unified.h index 3d0c3f32cd2f..69eb61830fb9 100644 --- a/fw/wmi_unified.h +++ b/fw/wmi_unified.h @@ -18391,6 +18391,12 @@ enum WMI_VDEV_UP_FLAGS { WMI_VDEV_UP_FLAG_VBSS_PASSIVE = 0x00000004, }; +typedef struct{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_co_located_chan_info */ + /* co-located link frequency discovered on connected ap */ + A_UINT32 link_freq; /* MHz units */ +} wmi_co_located_chan_info; + typedef struct { A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_up_cmdid_fixed_param */ /** unique id identifying the VDEV, generated by the caller */ @@ -18407,6 +18413,10 @@ typedef struct { A_UINT32 profile_num; /** flags - this is a bitwise-or combination of WMI_VDEV_UP_FLAGS values */ A_UINT32 flags; + /* The below TLVs follow this struct: + * - wmi_co_located_chan_info co_located_chan_info[]; + * Connected AP's co-located channel info + */ } wmi_vdev_up_cmd_fixed_param; typedef struct { diff --git a/fw/wmi_version.h b/fw/wmi_version.h index cffc5c2adeab..2c695cde4cda 100644 --- a/fw/wmi_version.h +++ b/fw/wmi_version.h @@ -37,7 +37,7 @@ #define __WMI_VER_MINOR_ 0 /** WMI revision number has to be incremented when there is a * change that may or may not break compatibility. */ -#define __WMI_REVISION_ 1636 +#define __WMI_REVISION_ 1637 /** The Version Namespace should not be normally changed. Only * host and firmware of the same WMI namespace will work From 024d402c850de81a4e1bda1616e00823d879dbd7 Mon Sep 17 00:00:00 2001 From: spuligil Date: Thu, 17 Jul 2025 06:02:18 -0700 Subject: [PATCH 160/306] fw-api: CL 29789367 - update fw common interface files Change-Id: I7746ab511883809be5afa3c8255391093f2bc7e1 CRs-Fixed: 3830439 --- fw/wmi_services.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fw/wmi_services.h b/fw/wmi_services.h index 0f79ea9e4871..18f2fa6085d5 100644 --- a/fw/wmi_services.h +++ b/fw/wmi_services.h @@ -720,6 +720,7 @@ typedef enum { WMI_SERVICE_HOST_AWARE_POWERSAVE = 459, /* FW supports indicating the powerstate of FW to host */ WMI_SERVICE_PDEV_DIV_STATES_REPORT = 460, /* FW supports reporting antenna diversity states */ WMI_SERVICE_EAPOL_OVER_RAW = 461, /* FW supports sending EAPOL frames in raw mode even when the vdev is brought up in nwifi/ethernet mode */ + WMI_SERVICE_MLO_SAP_LINK_REMOVAL_SUPPORT = 462, /* Indicates FW supports MLO SAP link removal operation */ WMI_MAX_EXT2_SERVICE From 83ec139d771c45f957ac336ca31910a5eeecee51 Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Mon, 23 Jun 2025 03:02:26 -0700 Subject: [PATCH 161/306] cnss: Dump stack by stack_trace_print The kernel API - show_stack isn't used after kernel updated, this function uses stack_trace_print to dump stack. Change-Id: Ib793946b3b66b271e05794bea3610ffb3684c44e Signed-off-by: Wu Gao --- drivers/net/wireless/cnss/cnss_common.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c index dbdd13e0abca..534f81f320a6 100644 --- a/drivers/net/wireless/cnss/cnss_common.c +++ b/drivers/net/wireless/cnss/cnss_common.c @@ -242,13 +242,21 @@ int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu) } EXPORT_SYMBOL(cnss_set_cpus_allowed_ptr); -/* wlan prop driver cannot invoke show_stack - * function directly, so to invoke this function it - * call wcnss_dump_stack function - */ +#define ENTRIES_COUNT 32 void cnss_dump_stack(struct task_struct *task) { - show_stack(task, NULL); + const int cnss_spaces = 4; + unsigned long cnss_entries[ENTRIES_COUNT] = {0}; + struct stack_trace cnss_trace = { + .nr_entries = 0, + .skip = 0, + .entries = &cnss_entries[0], + .max_entries = ENTRIES_COUNT, + }; + + save_stack_trace_tsk(task, &cnss_trace); + stack_trace_print(cnss_entries, cnss_trace.nr_entries, + cnss_spaces); } EXPORT_SYMBOL(cnss_dump_stack); From f4fc88f0890494d32aa0ffa9bce883e61f6fe0c7 Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Tue, 15 Jul 2025 02:53:03 -0700 Subject: [PATCH 162/306] cnss: Init reserved memory device If IOMMU is supported and enabled, it required to define IOMMU and init reversed memory device. Change-Id: I2bbd2f42333dca8a6bf7e608ce50e2c08fc0e8ba Signed-off-by: Wu Gao --- drivers/net/wireless/cnss/cnss_pci.c | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 9d588b5ed6d8..623149274fa3 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -1618,6 +1620,43 @@ static void cnss_pcie_reset_platform_ops(struct device *dev) dev->platform_data = NULL; } +#if IS_ENABLED(CONFIG_ARCH_QCOM) +/** + * cnss_pci_of_reserved_mem_device_init() - Assign reserved memory region + * to given PCI device + * @pdev: context pointer of pdev + * + * This function shall call corresponding of_reserved_mem_device* API to + * assign reserved memory region to PCI device based on where the memory is + * defined and attached to (platform device of_node or PCI device of_node) + * in device tree. + * + * Return: 0 for success, negative value for error + */ +static int cnss_pci_of_reserved_mem_device_init(struct pci_dev *pdev) +{ + struct device *dev_pci = &pdev->dev; + int ret; + + /* Use of_reserved_mem_device_init_by_idx() if reserved memory is + * attached to platform device of_node. + */ + ret = of_reserved_mem_device_init(dev_pci); + if (ret) + pr_err("Failed to init reserved mem device, err = %d\n", + ret); + if (dev_pci->cma_area) + pr_debug("CMA area is %s\n", cma_get_name(dev_pci->cma_area)); + + return ret; +} +#else +static int cnss_pci_of_reserved_mem_device_init(struct pci_dev *pdev) +{ + return 0; +} +#endif + static int cnss_wlan_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1634,6 +1673,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, atomic_set(&penv->fw_available, 0); penv->device_id = pdev->device; + cnss_pci_of_reserved_mem_device_init(pdev); if (penv->smmu_iova_len) { ret = cnss_smmu_init(&pdev->dev); if (ret) { From fed91e16d8019d54b98c0b999126456d2d172ef8 Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Thu, 28 Apr 2022 15:25:15 +0530 Subject: [PATCH 163/306] qcacld-3.0: Validate bw in lim calculate tpc Currently host driver does not validate bw in lim calculate tpc api before is it gets next higher bw, there is a possiblity that this bw becomes invalid and driver ends up with out of bound access for get higher bw array. In current scenario when host driver tries to start vdev on frequency 2472 for country IN and executes this API for frequency 2472, at the same time country is changed to US and this frequency becomes invalid. so in the execution of this API host driver gets invalid bw from reg set param and ends up with out of bound access for get higher bw array. TO address above issue, add a check to validate bw before driver acceses get higher bw array. Change-Id: Ibd6a2ff44a7928bb2fd461e6c49d4e306e4de7f7 CRs-Fixed: 3186084 --- core/mac/src/pe/lim/lim_process_sme_req_messages.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index 49113c9529e4..41842fe17ead 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -2223,7 +2223,9 @@ void lim_calculate_tpc(struct mac_context *mac, ch_params.ch_width = CH_WIDTH_20MHZ; - for (i = 0; i < num_pwr_levels; i++) { + for (i = 0; + i < num_pwr_levels && (ch_params.ch_width != CH_WIDTH_INVALID); + i++) { if (is_tpe_present) { if (is_6ghz_freq) { wlan_reg_get_client_power_for_connecting_ap( @@ -2241,8 +2243,9 @@ void lim_calculate_tpc(struct mac_context *mac, mac->pdev, oper_freq, 0, &ch_params); mlme_obj->reg_tpc_obj.frequency[i] = ch_params.mhz_freq_seg0; - ch_params.ch_width = - get_next_higher_bw[ch_params.ch_width]; + if (ch_params.ch_width != CH_WIDTH_INVALID) + ch_params.ch_width = + get_next_higher_bw[ch_params.ch_width]; } if (is_6ghz_freq) { if (LIM_IS_STA_ROLE(session)) { From ad3eca7060b622d9985ccff785d776f2883fc3c9 Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Tue, 22 Jul 2025 12:55:06 -0700 Subject: [PATCH 164/306] Release 2.0.8.35E Release 2.0.8.35E Change-Id: I831554185675089d3055c9e071c39944fe5c8f68 CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 0e3eaa97f81d..212336852d5f 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "D" +#define QWLAN_VERSION_EXTRA "E" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35D" +#define QWLAN_VERSIONSTR "2.0.8.35E" #endif /* QWLAN_VERSION_H */ From 1c5657681bfefeb006bc92b9b55aad16249218a6 Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Wed, 18 Jun 2025 12:17:24 +0530 Subject: [PATCH 165/306] qcacld-3.0: Add TPE IE EIRP power support for 6 GHz band Add TPE IE EIRP power parsing support for 6 GHz channels. 1) Currently, is_psd_power flag is derived from current channel list chan flag which returns true if corresponding channel supports PSD power. Normally, all 6 GHz channels support PSD, so this flag is usually set to 1. But, AP can transmit EIRP power in TPE IE for 6 GHz channels, thus derive this flag based on tx_power interpretation field in TPE IE for accurate value. 2) The calculated center freq is passed as argument to retrieve regulatory power from reg channel list but this logic works only for PSD. E.g. In case of EIRP, center freq can be 6125 MHz for oper freq 6115 and BW 40 MHz, and causing reg APIs to return reg power as 0. Thus, pass operating freq as argument in case of EIRP. Change-Id: If1ad3870a866592d970adad218e507c9c756f615 CRs-Fixed: 3266393 --- .../src/pe/lim/lim_process_sme_req_messages.c | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index 41842fe17ead..a48c6c707fa7 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -2059,6 +2059,7 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session, single_tpe = tpe_ies[non_psd_index]; vdev_mlme->reg_tpc_obj.eirp_power = single_tpe.tx_power[single_tpe.max_tx_pwr_count]; + vdev_mlme->reg_tpc_obj.is_psd_power = false; } } @@ -2202,7 +2203,6 @@ void lim_calculate_tpc(struct mac_context *mac, skip_tpe = wlan_mlme_skip_tpe(mac->psoc); } else { is_6ghz_freq = true; - is_psd_power = wlan_reg_is_6g_psd_power(mac->pdev); if (LIM_IS_STA_ROLE(session)) ap_power_type_6g = session->best_6g_power_type; } @@ -2210,6 +2210,7 @@ void lim_calculate_tpc(struct mac_context *mac, if (mlme_obj->reg_tpc_obj.num_pwr_levels) { is_tpe_present = true; num_pwr_levels = mlme_obj->reg_tpc_obj.num_pwr_levels; + is_psd_power = mlme_obj->reg_tpc_obj.is_psd_power; } else { num_pwr_levels = lim_get_num_pwr_levels(is_psd_power, session->ch_width); @@ -2228,10 +2229,16 @@ void lim_calculate_tpc(struct mac_context *mac, i++) { if (is_tpe_present) { if (is_6ghz_freq) { - wlan_reg_get_client_power_for_connecting_ap( - mac->pdev, ap_power_type_6g, - mlme_obj->reg_tpc_obj.frequency[i], - &is_psd_power, ®_max, &psd_power); + if (is_psd_power) { + wlan_reg_get_client_power_for_connecting_ap( + mac->pdev, ap_power_type_6g, + mlme_obj->reg_tpc_obj.frequency[i], + is_psd_power, ®_max, &psd_power); + } else { + wlan_reg_get_client_power_for_connecting_ap( + mac->pdev, ap_power_type_6g, oper_freq, + is_psd_power, ®_max, &psd_power); + } } } else { /* center frequency calculation */ @@ -2252,10 +2259,9 @@ void lim_calculate_tpc(struct mac_context *mac, wlan_reg_get_client_power_for_connecting_ap (mac->pdev, ap_power_type_6g, mlme_obj->reg_tpc_obj.frequency[i], - &is_psd_power, ®_max, &psd_power); + is_psd_power, ®_max, &psd_power); } else { - ap_power_type_6g = - wlan_reg_get_cur_6g_ap_pwr_type( + wlan_reg_get_cur_6g_ap_pwr_type( mac->pdev, &ap_power_type_6g); wlan_reg_get_6g_chan_ap_power( @@ -2321,7 +2327,6 @@ void lim_calculate_tpc(struct mac_context *mac, } mlme_obj->reg_tpc_obj.num_pwr_levels = num_pwr_levels; - mlme_obj->reg_tpc_obj.is_psd_power = is_psd_power; mlme_obj->reg_tpc_obj.eirp_power = reg_max; mlme_obj->reg_tpc_obj.power_type_6g = ap_power_type_6g; From 1eea4bab119a5e3bbb078ba4bf9d1f3a6b37a6ab Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Wed, 18 Jun 2025 12:23:26 +0530 Subject: [PATCH 166/306] qcacld-3.0: don't overwrite psd_power flag if psd_set is true When both EIRP and PSD TPE IEs are advertised by 6 GHz AP, we need to use PSD power. We need to keep the psd_power true if psd_set is true (means PSD TPE IE present) when driver processes the EIRP TPE IE. If reg rules don't support psd power, ignore PSD TPE IE. Change-Id: I96cf8f08ffd0aa143f0f0f453eed3c8b8e5d2382 CRs-Fixed: 3693350 --- .../src/pe/lim/lim_process_sme_req_messages.c | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index a48c6c707fa7..0ac96d900386 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -1903,6 +1903,8 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session, uint16_t bw_val, ch_width; qdf_freq_t curr_op_freq, curr_freq; enum reg_6g_client_type client_mobility_type; + enum reg_6g_ap_type ap_power_type_6g; + uint16_t reg_max = 0, psd_power = 0; struct ch_params ch_params = {0}; tDot11fIEtransmit_power_env single_tpe; /* @@ -1979,6 +1981,25 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session, curr_op_freq = session->curr_op_freq; bw_val = wlan_reg_get_bw_value(session->ch_width); + if (psd_set) { + if (wlan_reg_is_6ghz_chan_freq(curr_op_freq)) { + ap_power_type_6g = session->best_6g_power_type; + + wlan_reg_get_client_power_for_connecting_ap( + mac->pdev, ap_power_type_6g, + curr_op_freq, true, ®_max, &psd_power); + + /* If reg rules don't support psd power, ignore PSD + * TPE IE + */ + if (!psd_power) { + pe_debug_rl("reg rule doesn't support psd for %d ap type %d", + curr_op_freq, ap_power_type_6g); + psd_set = false; + } + } + } + if (non_psd_set && !psd_set) { single_tpe = tpe_ies[non_psd_index]; vdev_mlme->reg_tpc_obj.is_psd_power = false; @@ -2059,7 +2080,9 @@ void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session, single_tpe = tpe_ies[non_psd_index]; vdev_mlme->reg_tpc_obj.eirp_power = single_tpe.tx_power[single_tpe.max_tx_pwr_count]; - vdev_mlme->reg_tpc_obj.is_psd_power = false; + pe_debug("eirp_power %d", vdev_mlme->reg_tpc_obj.eirp_power); + if (!psd_set) + vdev_mlme->reg_tpc_obj.is_psd_power = false; } } From 7604d08f894532472b9dce5ecca083eb57b69594 Mon Sep 17 00:00:00 2001 From: Ravindra Konda Date: Tue, 22 Jul 2025 15:20:49 -0700 Subject: [PATCH 167/306] Release 2.0.8.35F Release 2.0.8.35F Change-Id: I8d4a6dabef540cd4594e32e3131bd508b4dd7ea9 CRs-Fixed: 774533 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 212336852d5f..7c707bd54fb8 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "E" +#define QWLAN_VERSION_EXTRA "F" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35E" +#define QWLAN_VERSIONSTR "2.0.8.35F" #endif /* QWLAN_VERSION_H */ From 7a8fb28e048a0b781fbaa02207977901c83676db Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Mon, 15 Aug 2022 17:47:09 -0700 Subject: [PATCH 168/306] qcacmn: Update is_psd_power logic in reg get client pwr API Currently, the reg_get_client_power_for_connecting_ap() API populates is_psd_power flag within the function and uses it as a check to further populate EIRP power. The is_psd_power flag is derived from current channel list chan flag which returns true if corresponding channel supports PSD power. Normally, all 6 GHz channels support PSD, so this flag is usually set to 1. But, AP can transmit EIRP power in TPE IE for 6 GHz channels, thus for MCC specific cases, derive this flag based on tx_power interpretation field in TPE IE for accurate value. WIN Host can still use reg_is_6g_psd_power() to retrieve the flag in the caller APIs. Hence, derive is_psd_power flag from TPE IE interpretation value beforehand and pass it as an argument to reg_get_client_power_for_connecting_ap() API. Change-Id: Iabbcbd003f441151643a087ad4908bcdaed753a5 CRs-Fixed: 3268118 --- umac/regulatory/core/src/reg_services_common.c | 7 +++---- umac/regulatory/core/src/reg_services_common.h | 9 ++++----- .../regulatory/dispatcher/inc/wlan_reg_services_api.h | 11 +++++------ .../regulatory/dispatcher/src/wlan_reg_services_api.c | 4 ++-- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/umac/regulatory/core/src/reg_services_common.c b/umac/regulatory/core/src/reg_services_common.c index 4678269ed294..877d31d91142 100644 --- a/umac/regulatory/core/src/reg_services_common.c +++ b/umac/regulatory/core/src/reg_services_common.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -5112,7 +5112,7 @@ QDF_STATUS reg_get_6g_chan_ap_power(struct wlan_objmgr_pdev *pdev, QDF_STATUS reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, enum reg_6g_ap_type ap_type, qdf_freq_t chan_freq, - bool *is_psd, + bool is_psd, uint16_t *tx_power, uint16_t *eirp_psd_power) { @@ -5135,8 +5135,7 @@ QDF_STATUS reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, reg_find_txpower_from_6g_list(chan_freq, master_chan_list, tx_power); - *is_psd = reg_is_6g_psd_power(pdev); - if (*is_psd) + if (is_psd) status = reg_get_6g_chan_psd_eirp_power(chan_freq, master_chan_list, eirp_psd_power); diff --git a/umac/regulatory/core/src/reg_services_common.h b/umac/regulatory/core/src/reg_services_common.h index c0d478ea1887..3a94a215298a 100644 --- a/umac/regulatory/core/src/reg_services_common.h +++ b/umac/regulatory/core/src/reg_services_common.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * * Permission to use, copy, modify, and/or distribute this software for @@ -1484,7 +1484,7 @@ QDF_STATUS reg_get_6g_chan_ap_power(struct wlan_objmgr_pdev *pdev, * * This function is meant to be called to find the channel frequency power * information for a client when the device is operating as a client. It will - * fill in the parameter is_psd, tx_power, and eirp_psd_power. eirp_psd_power + * fill in the parameters tx_power and eirp_psd_power. eirp_psd_power * will only be filled if the channel is PSD. * * Return: QDF_STATUS @@ -1492,7 +1492,7 @@ QDF_STATUS reg_get_6g_chan_ap_power(struct wlan_objmgr_pdev *pdev, QDF_STATUS reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, enum reg_6g_ap_type ap_type, qdf_freq_t chan_freq, - bool *is_psd, + bool is_psd, uint16_t *tx_power, uint16_t *eirp_psd_power); @@ -1582,11 +1582,10 @@ static inline QDF_STATUS reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, enum reg_6g_ap_type ap_type, qdf_freq_t chan_freq, - bool *is_psd, + bool is_psd, uint16_t *tx_power, uint16_t *eirp_psd_power) { - *is_psd = false; *tx_power = 0; *eirp_psd_power = 0; return QDF_STATUS_E_NOSUPPORT; diff --git a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h index d8c7ad95a133..c380a077abe5 100644 --- a/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h +++ b/umac/regulatory/dispatcher/inc/wlan_reg_services_api.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1869,8 +1869,8 @@ QDF_STATUS wlan_reg_get_6g_chan_ap_power(struct wlan_objmgr_pdev *pdev, * * This function is meant to be called to find the channel frequency power * information for a client when the device is operating as a client. It will - * fill in the parameter is_psd, tx_power, and eirp_psd_power. eirp_psd_power - * will only be filled if the channel is PSD. + * fill in the parameters tx_power and eirp_psd_power. eirp_psd_power will + * only be filled if the channel is PSD. * * Return: QDF_STATUS */ @@ -1878,7 +1878,7 @@ QDF_STATUS wlan_reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, enum reg_6g_ap_type ap_type, qdf_freq_t chan_freq, - bool *is_psd, uint16_t *tx_power, + bool is_psd, uint16_t *tx_power, uint16_t *eirp_psd_power); /** @@ -1985,10 +1985,9 @@ static inline QDF_STATUS wlan_reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, enum reg_6g_ap_type ap_type, qdf_freq_t chan_freq, - bool *is_psd, uint16_t *tx_power, + bool is_psd, uint16_t *tx_power, uint16_t *eirp_psd_power) { - *is_psd = false; *tx_power = 0; *eirp_psd_power = 0; return QDF_STATUS_E_NOSUPPORT; diff --git a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c index 2b720dee6ca6..7d458f0421fc 100644 --- a/umac/regulatory/dispatcher/src/wlan_reg_services_api.c +++ b/umac/regulatory/dispatcher/src/wlan_reg_services_api.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * * Permission to use, copy, modify, and/or distribute this software for @@ -1443,7 +1443,7 @@ QDF_STATUS wlan_reg_get_client_power_for_connecting_ap(struct wlan_objmgr_pdev *pdev, enum reg_6g_ap_type ap_type, qdf_freq_t chan_freq, - bool *is_psd, uint16_t *tx_power, + bool is_psd, uint16_t *tx_power, uint16_t *eirp_psd_power) { return reg_get_client_power_for_connecting_ap(pdev, ap_type, chan_freq, From 62a56196062d4c8cd71b3b9cc05fa6a72b07cc15 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Fri, 4 Jul 2025 17:54:32 +0530 Subject: [PATCH 169/306] asoc: handle heap overflow in effect driver adds a variable prev_config_param_length to track the previous configuration parameter length. This is initialized to 0 and updated after processing the EQ_CONFIG command. This allows the function to compare the current and previous configuration parameter lengths to determine if memory reallocation is necessary. Change-Id: Ib03406b862b6299c421840cc193760096e2db5d9 (cherry picked from commit f770020be262cc1470eea0ce5261e08c74685764) --- asoc/msm-audio-effects-q6-v2.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/asoc/msm-audio-effects-q6-v2.c b/asoc/msm-audio-effects-q6-v2.c index cb795f5bef45..4a7b4b32654e 100644 --- a/asoc/msm-audio-effects-q6-v2.c +++ b/asoc/msm-audio-effects-q6-v2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -1091,7 +1092,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, u32 packed_data_size = 0; u8 *eq_config_data = NULL; u32 *updt_config_data = NULL; - int config_param_length; + int config_param_length, prev_config_param_length = 0; pr_debug("%s\n", __func__); if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) { @@ -1211,7 +1212,12 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, if (!eq_config_data) eq_config_data = kzalloc(config_param_length, GFP_KERNEL); - else + else if (config_param_length != prev_config_param_length) { + if (eq_config_data) + kfree(eq_config_data); + eq_config_data = kzalloc(config_param_length, + GFP_KERNEL); + } else memset(eq_config_data, 0, config_param_length); if (!eq_config_data) { pr_err("%s, EQ_CONFIG:memory alloc failed\n", @@ -1238,6 +1244,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, *updt_config_data++ = eq->per_band_cfg[idx].band_idx; } + prev_config_param_length = config_param_length; break; case EQ_BAND_INDEX: if (length != 1 || index_offset != 0) { @@ -1320,7 +1327,8 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, pr_debug("%s: did not send pp params\n", __func__); invalid_config: kfree(params); - kfree(eq_config_data); + if (eq_config_data) + kfree(eq_config_data); return rc; } EXPORT_SYMBOL(msm_audio_effects_popless_eq_handler); From ad1e75a8ed2b8330151841b8bc322b150a9411c8 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Mon, 16 Jun 2025 19:10:01 +0530 Subject: [PATCH 170/306] asoc: compress: race condition handling in stream cmd put function protect driver data using mutex lock available to protect against race condtion due to multiple thread access. Change-Id: I7dbff3448958b1700ecca2a090fcb915d5809f30 (cherry picked from commit a9530af1782911e76fa765fd9db7c1ad20710f1d) --- asoc/msm-compress-q6-v2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c index 14f549310547..df48c414b05b 100644 --- a/asoc/msm-compress-q6-v2.c +++ b/asoc/msm-compress-q6-v2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.​ */ @@ -4219,6 +4220,7 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, return -EINVAL; } + mutex_lock(&pdata->lock); cstream = pdata->cstream[fe_id]; if (cstream == NULL) { pr_err("%s cstream is null\n", __func__); @@ -4231,7 +4233,6 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(&pdata->lock); if (prtd->audio_client == NULL) { pr_err("%s: audio_client is null\n", __func__); ret = -EINVAL; From 4117e36cb841c3a9e5751785cee84fd9a9933c2d Mon Sep 17 00:00:00 2001 From: Dharmendra Tiwari Date: Mon, 12 May 2025 08:00:40 -0700 Subject: [PATCH 171/306] qcacld-3.0: Fix underflow issue of beacon length A validation check has been added to ensure beacon length is not less than (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)), preventing underflow issues. Change-Id: I924a3ebf4a0749d5a4c56b36878765fcf46440a4 CRs-Fixed: 4166530 --- core/wma/src/wma_power.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/core/wma/src/wma_power.c b/core/wma/src/wma_power.c index 6c8004735a15..feed5a83979d 100644 --- a/core/wma/src/wma_power.c +++ b/core/wma/src/wma_power.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -1171,20 +1171,28 @@ static void wma_update_beacon_noa_ie(struct beacon_info *bcn, /* TODO: Assuming p2p noa ie is last ie in the beacon */ qdf_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len + sizeof(struct p2p_ie))); - bcn->len -= (bcn->noa_sub_ie_len + - sizeof(struct p2p_ie)); + if (bcn->len < (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie))) + bcn->len = 0; + else + bcn->len -= (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie)); bcn->noa_ie = NULL; bcn->noa_sub_ie_len = 0; } - wma_debug("No need to update NoA"); return; } if (bcn->noa_sub_ie_len && bcn->noa_ie) { + if (bcn->len < (bcn->noa_sub_ie_len + sizeof(struct p2p_ie))) + bcn->len = 0; + else + bcn->len -= (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie)); + /* NoA present in previous beacon, update it */ wma_debug("NoA present in previous beacon, update the NoA IE, bcn->len %u bcn->noa_sub_ie_len %u", - bcn->len, bcn->noa_sub_ie_len); - bcn->len -= (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)); + bcn->len, bcn->noa_sub_ie_len); qdf_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len + sizeof(struct p2p_ie))); } else { /* NoA is not present in previous beacon */ From 15ea8abee0fb0954361aad88d35b9e6c0319e411 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Reddy A E Date: Sat, 6 Sep 2025 00:37:52 -0700 Subject: [PATCH 172/306] Release 2.0.8.35G Release 2.0.8.35G Change-Id: Iaa1e456ca143d8650d715e3bdd25e00f5281b8b4 --- core/mac/inc/qwlan_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 7c707bd54fb8..500f1f71f75c 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "F" +#define QWLAN_VERSION_EXTRA "G" #define QWLAN_VERSION_BUILD 35 -#define QWLAN_VERSIONSTR "2.0.8.35F" +#define QWLAN_VERSIONSTR "2.0.8.35G" #endif /* QWLAN_VERSION_H */ From 6b26ef81599afa1718f318388f100391a4d27400 Mon Sep 17 00:00:00 2001 From: Arunteja Reddy Gopireddy Date: Tue, 2 Sep 2025 17:32:05 +0530 Subject: [PATCH 173/306] msm: cvp: Fix for kernel address exposure vulnerability to user Driver allocates an object for session structure and then passes this address to user after modifing this address a bit using hash32_ptr function. This function does not hash the address properly and user can retrieve the kernel address back from the hashed value. Change-Id: I8a91a5e67a1019a848051ce7b325be921ace967d Signed-off-by: Arunteja Reddy Gopireddy --- drivers/media/platform/msm/cvp/cvp.c | 6 +- drivers/media/platform/msm/cvp/cvp_hfi.c | 56 +++++++++++++--- .../platform/msm/cvp/hfi_packetization.c | 19 ++++-- .../platform/msm/cvp/hfi_response_handler.c | 4 +- drivers/media/platform/msm/cvp/msm_cvp.c | 66 +++++++++++++++---- drivers/media/platform/msm/cvp/msm_cvp.h | 3 + drivers/media/platform/msm/cvp/msm_cvp_buf.c | 26 ++++---- .../media/platform/msm/cvp/msm_cvp_common.c | 45 ++++++++----- drivers/media/platform/msm/cvp/msm_cvp_core.c | 5 +- .../media/platform/msm/cvp/msm_cvp_internal.h | 4 ++ drivers/media/platform/msm/cvp/msm_cvp_synx.c | 3 +- 11 files changed, 173 insertions(+), 64 deletions(-) diff --git a/drivers/media/platform/msm/cvp/cvp.c b/drivers/media/platform/msm/cvp/cvp.c index 87adb4fbd975..76f7444a43b8 100644 --- a/drivers/media/platform/msm/cvp/cvp.c +++ b/drivers/media/platform/msm/cvp/cvp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -135,6 +135,8 @@ static int msm_cvp_initialize_core(struct platform_device *pdev, INIT_LIST_HEAD(&core->instances); mutex_init(&core->lock); mutex_init(&core->clk_lock); + mutex_init(&core->idr_mtx); + idr_init(&core->sess_idr); core->state = CVP_CORE_UNINIT; for (i = SYS_MSG_INDEX(SYS_MSG_START); @@ -506,6 +508,8 @@ static int msm_cvp_remove(struct platform_device *pdev) msm_cvp_free_platform_resources(&core->resources); sysfs_remove_group(&pdev->dev.kobj, &msm_cvp_core_attr_group); dev_set_drvdata(&pdev->dev, NULL); + idr_destroy(&core->sess_idr); + mutex_destroy(&core->idr_mtx); mutex_destroy(&core->lock); mutex_destroy(&core->clk_lock); kfree(core); diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.c b/drivers/media/platform/msm/cvp/cvp_hfi.c index 22340456d275..df430d2235f7 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi.c +++ b/drivers/media/platform/msm/cvp/cvp_hfi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -29,6 +30,7 @@ #include "cvp_hfi_helper.h" #include "cvp_hfi_io.h" #include "msm_cvp_dsp.h" +#include "msm_cvp.h" #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF @@ -469,6 +471,7 @@ static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags) { int rc; struct cvp_hal_session *temp; + struct msm_cvp_inst *inst = NULL; if (msm_cvp_dsp_disable) return 0; @@ -480,9 +483,10 @@ static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags) /* don't suspend if cvp session is not paused */ if (!(temp->flags & SESSION_PAUSE)) { + inst = (struct msm_cvp_inst *)temp->session_id; dprintk(CVP_DSP, "%s: cvp session %x not paused\n", - __func__, hash32_ptr(temp)); + __func__, inst->sess_id); return -EBUSY; } } @@ -2224,12 +2228,17 @@ static void __session_clean(struct cvp_hal_session *session) { struct cvp_hal_session *temp, *next; struct iris_hfi_device *device; + struct msm_cvp_core *core = NULL; + struct msm_cvp_inst *inst = NULL; + void *tmp = NULL; if (!session || !session->device) { dprintk(CVP_WARN, "%s: invalid params\n", __func__); return; } device = session->device; + core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); + inst = (struct msm_cvp_inst *) session->session_id; dprintk(CVP_SESS, "deleted the session: %pK\n", session); /* * session might have been removed from the device list in @@ -2241,6 +2250,13 @@ static void __session_clean(struct cvp_hal_session *session) break; } } + /* Remove the IDR id assigned to this session */ + mutex_lock(&core->idr_mtx); + tmp = idr_remove(&core->sess_idr, inst->sess_id); + if (tmp != session) + dprintk(CVP_WARN, "%s: session\n", __func__); + mutex_unlock(&core->idr_mtx); + /* Poison the session handle with zeros */ *session = (struct cvp_hal_session){ {0} }; kfree(session); @@ -2278,6 +2294,9 @@ static int iris_hfi_session_init(void *device, void *session_id, struct cvp_hfi_cmd_sys_session_init_packet pkt; struct iris_hfi_device *dev; struct cvp_hal_session *s; + struct msm_cvp_core *core; + struct msm_cvp_inst *inst; + int id = 0; if (!device || !new_session) { dprintk(CVP_ERR, "%s - invalid input\n", __func__); @@ -2285,6 +2304,8 @@ static int iris_hfi_session_init(void *device, void *session_id, } dev = device; + core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); + inst = session_id; mutex_lock(&dev->lock); s = kzalloc(sizeof(*s), GFP_KERNEL); @@ -2295,15 +2316,35 @@ static int iris_hfi_session_init(void *device, void *session_id, s->session_id = session_id; s->device = dev; + + mutex_lock(&core->idr_mtx); + idr_preload(GFP_KERNEL); + + /* Need to think if we can use core->lock or dev->lock or need a + * different new lock for this? + */ + id = idr_alloc(&core->sess_idr, (void *)s, 0x7FFF0000, INT_MAX, GFP_NOWAIT); + idr_preload_end(); + mutex_unlock(&core->idr_mtx); + if (id < 0) { + dprintk(CVP_ERR, + "%s: idr allocation failed for session %pK of inst %pK\n", + __func__, s, session_id); + goto err_session_init_fail; + } + dprintk(CVP_SESS, - "%s: inst %pK, session %pK\n", __func__, session_id, s); + "%s: inst %pK, session %pK, idr_id = 0x%x\n", __func__, session_id, s, id); list_add_tail(&s->list, &dev->sess_head); __set_default_sys_properties(device); + inst->sess_id = id; + if (call_hfi_pkt_op(dev, session_init, &pkt, s)) { dprintk(CVP_ERR, "session_init: failed to create packet\n"); + inst->sess_id = 0x0000DEAD; goto err_session_init_fail; } @@ -2317,6 +2358,7 @@ static int iris_hfi_session_init(void *device, void *session_id, err_session_init_fail: if (s) __session_clean(s); + inst->sess_id = 0; *new_session = NULL; mutex_unlock(&dev->lock); return -EINVAL; @@ -2878,9 +2920,11 @@ static struct cvp_hal_session *__get_session(struct iris_hfi_device *device, u32 session_id) { struct cvp_hal_session *temp = NULL; + struct msm_cvp_inst *inst = NULL; list_for_each_entry(temp, &device->sess_head, list) { - if (session_id == hash32_ptr(temp)) + inst = (struct msm_cvp_inst *)temp->session_id; + if (session_id == inst->sess_id) return temp; } @@ -3059,6 +3103,7 @@ static int __response_handler(struct iris_hfi_device *device) /* Process the packet types that we're interested in */ process_system_msg(info, device, raw_packet); + /* This session_id is a double pointer to the idr_id of session */ session_id = get_session_id(info); /* * hfi_process_msg_packet provides a session_id that's a hashed @@ -3070,11 +3115,6 @@ static int __response_handler(struct iris_hfi_device *device) if (session_id) { struct cvp_hal_session *session = NULL; - if (upper_32_bits((uintptr_t)*session_id) != 0) { - dprintk(CVP_ERR, - "Upper 32-bits != 0 for sess_id=%pK\n", - *session_id); - } session = __get_session(device, (u32)(uintptr_t)*session_id); if (!session) { diff --git a/drivers/media/platform/msm/cvp/hfi_packetization.c b/drivers/media/platform/msm/cvp/hfi_packetization.c index 107e2d744fff..edb6caaf1d34 100644 --- a/drivers/media/platform/msm/cvp/hfi_packetization.c +++ b/drivers/media/platform/msm/cvp/hfi_packetization.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "hfi_packetization.h" @@ -208,7 +209,7 @@ inline int cvp_create_pkt_cmd_sys_session_init( pkt->size = sizeof(struct cvp_hfi_cmd_sys_session_init_packet); pkt->packet_type = HFI_CMD_SYS_SESSION_INIT; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; pkt->session_type = inst->prop.type; pkt->session_kmask = inst->prop.kernel_mask; pkt->session_prio = inst->prop.priority; @@ -266,13 +267,14 @@ int cvp_create_pkt_cmd_session_cmd(struct cvp_hal_session_cmd_pkt *pkt, int pkt_type, struct cvp_hal_session *session) { int rc = 0; + struct msm_cvp_inst *inst = session->session_id; if (!pkt) return -EINVAL; pkt->size = sizeof(struct cvp_hal_session_cmd_pkt); pkt->packet_type = pkt_type; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; return rc; } @@ -305,13 +307,14 @@ int cvp_create_pkt_cmd_session_set_buffers( { int rc = 0; struct cvp_hfi_cmd_session_set_buffers_packet *pkt; + struct msm_cvp_inst *inst = session->session_id; - if (!cmd || !session) + if (!cmd || !session || !inst) return -EINVAL; pkt = (struct cvp_hfi_cmd_session_set_buffers_packet *)cmd; pkt->packet_type = HFI_CMD_SESSION_CVP_SET_BUFFERS; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; pkt->buf_type.iova = iova; pkt->buf_type.size = size; pkt->size = sizeof(struct cvp_hfi_cmd_session_set_buffers_packet); @@ -324,13 +327,14 @@ int cvp_create_pkt_cmd_session_release_buffers( struct cvp_hal_session *session) { struct cvp_session_release_buffers_packet *pkt; + struct msm_cvp_inst *inst = session->session_id; - if (!cmd || !session) + if (!cmd || !session || !inst) return -EINVAL; pkt = (struct cvp_session_release_buffers_packet *)cmd; pkt->packet_type = HFI_CMD_SESSION_CVP_RELEASE_BUFFERS; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; pkt->num_buffers = 1; pkt->buffer_type = 0; pkt->size = sizeof(struct cvp_session_release_buffers_packet) + @@ -347,6 +351,7 @@ int cvp_create_pkt_cmd_session_send( int def_idx; struct cvp_hal_session_cmd_pkt *ptr = (struct cvp_hal_session_cmd_pkt *)in_pkt; + struct msm_cvp_inst *inst = session->session_id; if (!out_pkt || !in_pkt || !session) return -EINVAL; @@ -354,7 +359,7 @@ int cvp_create_pkt_cmd_session_send( if (ptr->size > MAX_HFI_PKT_SIZE * sizeof(unsigned int)) goto error_hfi_packet; - if (ptr->session_id != hash32_ptr(session)) + if (ptr->session_id != inst->sess_id) goto error_hfi_packet; def_idx = get_pkt_index(ptr); diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c index 311f94106534..3c58c5d90b92 100644 --- a/drivers/media/platform/msm/cvp/hfi_response_handler.c +++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -462,7 +462,7 @@ static struct msm_cvp_inst *cvp_get_inst_from_id(struct msm_cvp_core *core, retry: if (mutex_trylock(&core->lock)) { list_for_each_entry(inst, &core->instances, list) { - if (hash32_ptr(inst->session) == session_id) { + if (inst->sess_id == session_id) { match = true; break; } diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c index fefc06d6aee2..239ceb89acfa 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.c +++ b/drivers/media/platform/msm/cvp/msm_cvp.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_cvp.h" @@ -14,6 +15,47 @@ struct cvp_power_level { unsigned long bw_sum; }; +void *get_sessObj_from_idr(struct msm_cvp_inst *inst) +{ + void *sessObj = NULL; + struct msm_cvp_core *core = NULL; + + if (!inst || !inst->core) { + dprintk(CVP_ERR, "%s: invalid params\n", __func__); + return NULL; + } + + core = inst->core; + mutex_lock(&core->idr_mtx); + sessObj = idr_find(&core->sess_idr, inst->sess_id); + mutex_unlock(&core->idr_mtx); + if (!sessObj) + dprintk(CVP_ERR, "%s: Could not find the sess obj for given idr id\n", + __func__); + + return sessObj; +} + +u32 get_sessId_from_idr(void *session) +{ + void *ptr = NULL; + u32 sess_id = -1; + struct msm_cvp_core *core = NULL; + + core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); + if (!session || !core) + return -EINVAL; + mutex_lock(&core->idr_mtx); + idr_for_each_entry(&core->sess_idr, ptr, sess_id) { + if (ptr == session) { + mutex_unlock(&core->idr_mtx); + return sess_id; + } + } + mutex_unlock(&core->idr_mtx); + return sess_id; +} + static int msm_cvp_get_session_info(struct msm_cvp_inst *inst, struct cvp_kmd_session_info *session) { @@ -30,7 +72,7 @@ static int msm_cvp_get_session_info(struct msm_cvp_inst *inst, return -ECONNRESET; s->cur_cmd_type = CVP_KMD_GET_SESSION_INFO; - session->session_id = hash32_ptr(inst->session); + session->session_id = inst->sess_id; dprintk(CVP_SESS, "%s: id 0x%x\n", __func__, session->session_id); s->cur_cmd_type = 0; @@ -1227,7 +1269,7 @@ static int msm_cvp_session_stop(struct msm_cvp_inst *inst, sq->state = QUEUE_STOP; pr_info(CVP_DBG_TAG "Stop session: %pK session_id = %d\n", - "sess", inst, hash32_ptr(inst->session)); + "sess", inst, inst->sess_id); spin_unlock(&sq->lock); wake_up_all(&inst->session_queue.wq); @@ -1251,7 +1293,7 @@ int msm_cvp_session_queue_stop(struct msm_cvp_inst *inst) sq->state = QUEUE_STOP; dprintk(CVP_SESS, "Stop session queue: %pK session_id = %d\n", - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); spin_unlock(&sq->lock); wake_up_all(&inst->session_queue.wq); @@ -1551,7 +1593,7 @@ static void cvp_clean_fence_queue(struct msm_cvp_inst *inst, int synx_state) ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); dprintk(CVP_SYNX, "%s: (%#x) flush frame %llu %llu wait_list\n", - __func__, hash32_ptr(inst->session), ktid, f->frame_id); + __func__, inst->sess_id, ktid, f->frame_id); list_del_init(&f->list); msm_cvp_unmap_frame(inst, f->pkt->client_data.kdata); @@ -1564,7 +1606,7 @@ static void cvp_clean_fence_queue(struct msm_cvp_inst *inst, int synx_state) ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); dprintk(CVP_SYNX, "%s: (%#x)flush frame %llu %llu sched_list\n", - __func__, hash32_ptr(inst->session), ktid, f->frame_id); + __func__, inst->sess_id, ktid, f->frame_id); cvp_cancel_synx(inst, CVP_INPUT_SYNX, f, synx_state); } @@ -1612,14 +1654,14 @@ static int cvp_flush_all(struct msm_cvp_inst *inst) return -ECONNRESET; dprintk(CVP_SESS, "session %llx (%#x)flush all starts\n", - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); q = &inst->fence_cmd_queue; hdev = inst->core->device; cvp_clean_fence_queue(inst, SYNX_STATE_SIGNALED_CANCEL); dprintk(CVP_SESS, "%s: (%#x) send flush to fw\n", - __func__, hash32_ptr(inst->session)); + __func__, inst->sess_id); /* Send flush to FW */ rc = call_hfi_op(hdev, session_flush, (void *)inst->session); @@ -1636,7 +1678,7 @@ static int cvp_flush_all(struct msm_cvp_inst *inst) __func__, rc); dprintk(CVP_SESS, "%s: (%#x) received flush from fw\n", - __func__, hash32_ptr(inst->session)); + __func__, inst->sess_id); exit: rc = cvp_drain_fence_sched_list(inst); @@ -1859,10 +1901,10 @@ int msm_cvp_session_deinit(struct msm_cvp_inst *inst) return -EINVAL; } dprintk(CVP_SESS, "%s: inst %pK (%#x)\n", __func__, - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); - session = (struct cvp_hal_session *)inst->session; - if (!session) + session = (struct cvp_hal_session *)get_sessObj_from_idr(inst); + if (!session || session != inst->session) return rc; rc = msm_cvp_comm_try_state(inst, MSM_CVP_CLOSE_DONE); @@ -1883,7 +1925,7 @@ int msm_cvp_session_init(struct msm_cvp_inst *inst) } dprintk(CVP_SESS, "%s: inst %pK (%#x)\n", __func__, - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); /* set default frequency */ inst->clk_data.core_id = 0; diff --git a/drivers/media/platform/msm/cvp/msm_cvp.h b/drivers/media/platform/msm/cvp/msm_cvp.h index b21864b46f1c..b8ae6068de35 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.h +++ b/drivers/media/platform/msm/cvp/msm_cvp.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _MSM_CVP_H_ @@ -34,4 +35,6 @@ int msm_cvp_session_init(struct msm_cvp_inst *inst); int msm_cvp_session_deinit(struct msm_cvp_inst *inst); int msm_cvp_session_queue_stop(struct msm_cvp_inst *inst); int cvp_stop_clean_fence_queue(struct msm_cvp_inst *inst); +void *get_sessObj_from_idr(struct msm_cvp_inst *inst); +u32 get_sessId_from_idr(void *session); #endif diff --git a/drivers/media/platform/msm/cvp/msm_cvp_buf.c b/drivers/media/platform/msm/cvp/msm_cvp_buf.c index 995c111edb7d..c16eed33efd3 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_buf.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_buf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_cvp_common.h" @@ -14,7 +14,7 @@ do { \ clear_bit(idx, &inst->dma_cache.usage_bitmap); \ dprintk(CVP_MEM, "clear %x bit %d dma_cache bitmap 0x%llx\n", \ - hash32_ptr(inst->session), smem->bitmap_index, \ + inst->sess_id, smem->bitmap_index, \ inst->dma_cache.usage_bitmap); \ } while (0) @@ -22,7 +22,7 @@ do { \ set_bit(idx, &inst->dma_cache.usage_bitmap); \ dprintk(CVP_MEM, "Set %x bit %d dma_cache bitmap 0x%llx\n", \ - hash32_ptr(inst->session), idx, \ + inst->sess_id, idx, \ inst->dma_cache.usage_bitmap); \ } while (0) @@ -36,7 +36,7 @@ void print_smem(u32 tag, const char *str, struct msm_cvp_inst *inst, if (smem->dma_buf) { dprintk(tag, "%s: %x : %s size %d flags %#x iova %#x idx %d ref %d", - str, hash32_ptr(inst->session), smem->dma_buf->name, + str, inst->sess_id, smem->dma_buf->name, smem->size, smem->flags, smem->device_addr, smem->bitmap_index, smem->refcount); } @@ -51,13 +51,13 @@ static void print_internal_buffer(u32 tag, const char *str, if (cbuf->smem->dma_buf) { dprintk(tag, "%s: %x : fd %d off %d %s size %d iova %#x", - str, hash32_ptr(inst->session), cbuf->fd, + str, inst->sess_id, cbuf->fd, cbuf->offset, cbuf->smem->dma_buf->name, cbuf->size, cbuf->smem->device_addr); } else { dprintk(tag, "%s: %x : idx %2d fd %d off %d size %d iova %#x", - str, hash32_ptr(inst->session), cbuf->fd, + str, inst->sess_id, cbuf->fd, cbuf->offset, cbuf->size, cbuf->smem->device_addr); } } @@ -77,7 +77,7 @@ void print_client_buffer(u32 tag, const char *str, dprintk(tag, "%s: %x : idx %2d fd %d off %d size %d type %d flags 0x%x\n", - str, hash32_ptr(inst->session), cbuf->index, cbuf->fd, + str, inst->sess_id, cbuf->index, cbuf->fd, cbuf->offset, cbuf->size, cbuf->type, cbuf->flags); } @@ -154,7 +154,7 @@ int msm_cvp_map_buf_dsp(struct msm_cvp_inst *inst, struct cvp_kmd_buffer *buf) } if (buf->index) { - rc = cvp_dsp_register_buffer(hash32_ptr(session), buf->fd, + rc = cvp_dsp_register_buffer(inst->sess_id, buf->fd, smem->dma_buf->size, buf->size, buf->offset, buf->index, (uint32_t)smem->device_addr); if (rc) { @@ -227,7 +227,7 @@ int msm_cvp_unmap_buf_dsp(struct msm_cvp_inst *inst, struct cvp_kmd_buffer *buf) } if (buf->index) { - rc = cvp_dsp_deregister_buffer(hash32_ptr(session), buf->fd, + rc = cvp_dsp_deregister_buffer(inst->sess_id, buf->fd, cbuf->smem->dma_buf->size, buf->size, buf->offset, buf->index, (uint32_t)cbuf->smem->device_addr); if (rc) { @@ -545,7 +545,7 @@ void msm_cvp_unmap_frame(struct msm_cvp_inst *inst, u64 ktid) ktid &= (FENCE_BIT - 1); dprintk(CVP_MEM, "%s: (%#x) unmap frame %llu\n", - __func__, hash32_ptr(inst->session), ktid); + __func__, inst->sess_id, ktid); found = false; mutex_lock(&inst->frames.lock); @@ -587,7 +587,7 @@ int msm_cvp_unmap_user_persist(struct msm_cvp_inst *inst, smem = pbuf->smem; dprintk(CVP_MEM, "unmap persist: %x %d %d %#x", - hash32_ptr(inst->session), pbuf->fd, + inst->sess_id, pbuf->fd, pbuf->size, smem->device_addr); if (smem->bitmap_index >= MAX_DMABUF_NUMS) { @@ -785,7 +785,7 @@ int msm_cvp_session_deinit_buffers(struct msm_cvp_inst *inst) list_for_each_entry_safe(cbuf, dummy, &inst->cvpdspbufs.list, list) { print_internal_buffer(CVP_MEM, "remove dspbufs", inst, cbuf); - rc = cvp_dsp_deregister_buffer(hash32_ptr(session), + rc = cvp_dsp_deregister_buffer(inst->sess_id, cbuf->fd, cbuf->smem->dma_buf->size, cbuf->size, cbuf->offset, cbuf->index, (uint32_t)cbuf->smem->device_addr); @@ -955,7 +955,7 @@ int cvp_release_arp_buffers(struct msm_cvp_inst *inst) if (buf->ownership == DRIVER) { dprintk(CVP_MEM, "%s: %x : fd %d %s size %d", - "free arp", hash32_ptr(inst->session), buf->fd, + "free arp", inst->sess_id, buf->fd, smem->dma_buf->name, buf->size); msm_cvp_smem_free(smem); kmem_cache_free(cvp_driver->smem_cache, smem); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.c b/drivers/media/platform/msm/cvp/msm_cvp_common.c index 69787e51cc3d..22c8aa9441ad 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -195,23 +196,31 @@ struct msm_cvp_inst *cvp_get_inst_validate(struct msm_cvp_core *core, { int rc = 0; struct cvp_hfi_device *hdev; - struct msm_cvp_inst *s; + struct msm_cvp_inst *inst; + void *sessObj = NULL; - s = cvp_get_inst(core, session_id); - if (!s) { - dprintk(CVP_ERR, "%s session doesn't exit\n", + inst = cvp_get_inst(core, session_id); + if (!inst) { + dprintk(CVP_ERR, "%s Inst doesn't exit\n", __builtin_return_address(0)); return NULL; } - hdev = s->core->device; - rc = call_hfi_op(hdev, validate_session, s->session, __func__); - if (rc) { - cvp_put_inst(s); - s = NULL; + sessObj = get_sessObj_from_idr(inst); + if (!sessObj || sessObj != inst->session) { + dprintk(CVP_ERR, + "Either sessionObj is null or not matching with inst->session\n"); + return NULL; } - return s; + hdev = inst->core->device; + rc = call_hfi_op(hdev, validate_session, sessObj, __func__); + if (rc) { + cvp_put_inst(inst); + inst = NULL; + } + + return inst; } static void cvp_handle_session_cmd_done(enum hal_command_response cmd, @@ -486,7 +495,7 @@ static void handle_session_init_done(enum hal_command_response cmd, void *data) } dprintk(CVP_SESS, "%s: cvp session %#x\n", __func__, - hash32_ptr(inst->session)); + inst->sess_id); signal_session_msg_receipt(cmd, inst); cvp_put_inst(inst); @@ -568,7 +577,7 @@ static void handle_session_error(enum hal_command_response cmd, void *data) hdev = inst->core->device; dprintk(CVP_ERR, "Session error received for inst %pK session %x\n", - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); if (response->status == CVP_ERR_MAX_CLIENTS) { dprintk(CVP_WARN, "Too many clients, rejecting %pK", inst); @@ -901,7 +910,7 @@ static int msm_comm_session_abort(struct msm_cvp_inst *inst) abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE); dprintk(CVP_WARN, "%s: inst %pK session %x\n", __func__, - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); rc = call_hfi_op(hdev, session_abort, (void *)inst->session); if (rc) { dprintk(CVP_ERR, @@ -914,7 +923,7 @@ static int msm_comm_session_abort(struct msm_cvp_inst *inst) inst->core->resources.msm_cvp_hw_rsp_timeout)); if (!rc) { dprintk(CVP_ERR, "%s: inst %pK session %x abort timed out\n", - __func__, inst, hash32_ptr(inst->session)); + __func__, inst, inst->sess_id); call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dump_hfi_queue(hdev->hfi_device_data); msm_cvp_comm_generate_sys_error(inst); @@ -1268,7 +1277,7 @@ int msm_cvp_comm_try_state(struct msm_cvp_inst *inst, int state) } dprintk(CVP_SESS, "Trying to move inst: %pK (%#x) from: %#x to %#x\n", - inst, hash32_ptr(inst->session), inst->state, state); + inst, inst->sess_id, inst->state, state); mutex_lock(&inst->sync_lock); if (inst->state == MSM_CVP_CORE_INVALID) { @@ -1281,7 +1290,7 @@ int msm_cvp_comm_try_state(struct msm_cvp_inst *inst, int state) flipped_state = get_flipped_state(inst->state, state); dprintk(CVP_SESS, "inst: %pK (%#x) flipped_state = %#x %x\n", - inst, hash32_ptr(inst->session), flipped_state, state); + inst, inst->sess_id, flipped_state, state); switch (flipped_state) { case MSM_CVP_CORE_UNINIT_DONE: case MSM_CVP_CORE_INIT: @@ -1491,7 +1500,7 @@ int msm_cvp_comm_kill_session(struct msm_cvp_inst *inst) return 0; } dprintk(CVP_WARN, "%s: inst %pK, session %x state %d\n", __func__, - inst, hash32_ptr(inst->session), inst->state); + inst, inst->sess_id, inst->state); /* * We're internally forcibly killing the session, if fw is aware of * the session send session_abort to firmware to clean up and release @@ -1503,7 +1512,7 @@ int msm_cvp_comm_kill_session(struct msm_cvp_inst *inst) if (rc) { dprintk(CVP_ERR, "%s: inst %pK session %x abort failed\n", - __func__, inst, hash32_ptr(inst->session)); + __func__, inst, inst->sess_id); change_cvp_inst_state(inst, MSM_CVP_CORE_INVALID); } else { change_cvp_inst_state(inst, MSM_CVP_CORE_UNINIT); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_core.c b/drivers/media/platform/msm/cvp/msm_cvp_core.c index 5347eade1782..b98d43730988 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_core.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -165,7 +166,7 @@ void *msm_cvp_open(int core_id, int session_type) list_for_each_entry(inst, &core->instances, list) dprintk(CVP_ERR, "inst %pK, cmd %d id %d\n", inst, inst->cur_cmd_type, - hash32_ptr(inst->session)); + inst->sess_id); mutex_unlock(&core->lock); return NULL; @@ -369,7 +370,7 @@ int msm_cvp_destroy(struct msm_cvp_inst *inst) synx_uninitialize(inst->synx_session_id); pr_info(CVP_DBG_TAG "Closed cvp instance: %pK session_id = %d\n", - "sess", inst, hash32_ptr(inst->session)); + "sess", inst, inst->sess_id); if (inst->cur_cmd_type) dprintk(CVP_ERR, "deleted instance has pending cmd %d\n", inst->cur_cmd_type); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_internal.h b/drivers/media/platform/msm/cvp/msm_cvp_internal.h index 533e16cfce56..31495ad77d35 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_internal.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_internal.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _MSM_CVP_INTERNAL_H_ @@ -290,6 +291,8 @@ struct msm_cvp_core { unsigned long curr_freq; struct cvp_cycle_info dyn_clk; atomic64_t kernel_trans_id; + struct idr sess_idr; + struct mutex idr_mtx; }; struct msm_cvp_inst { @@ -301,6 +304,7 @@ struct msm_cvp_inst { struct cvp_session_queue session_queue_fence; struct cvp_session_event event_handler; void *session; + u32 sess_id; enum instance_state state; struct msm_cvp_list freqs; struct msm_cvp_list persistbufs; diff --git a/drivers/media/platform/msm/cvp/msm_cvp_synx.c b/drivers/media/platform/msm/cvp/msm_cvp_synx.c index f70fb4013058..4580c582174b 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_synx.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_synx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_cvp_common.h" @@ -20,7 +21,7 @@ void cvp_dump_fence_queue(struct msm_cvp_inst *inst) ssid = inst->synx_session_id; mutex_lock(&q->lock); dprintk(CVP_WARN, "inst %x fence q mode %d, ssid %d\n", - hash32_ptr(inst->session), q->mode, ssid.client_id); + inst->sess_id, q->mode, ssid.client_id); dprintk(CVP_WARN, "fence cmdq wait list:\n"); list_for_each_entry(f, &q->wait_list, list) { From a676bd5e81d78c678a77f4933d82ab095cf51aab Mon Sep 17 00:00:00 2001 From: Akshay Mohite Date: Mon, 21 Jul 2025 20:11:04 +0530 Subject: [PATCH 174/306] qcacmn: Fix out of bounds read in extract_roam_scan_ap_stats_tlv In API extract_roam_scan_ap_stats_tlv(), for loop is implemented to extract AP info from a param_buf structure and store it in a dst buffer starting from index value ap_idx. The loop iterates num_cand times, where num_cand is the number of candidate APs to be extracted. However, the issue arises when the num_cand value exceeds the remaining number of APs in the param_buf structure, starting from the ap_idx index. This can cause the loop to access memory outside the bounds of the param_buf structure. To fix this, add a check before the for loop to ensure that the num_cand value does not exceed the remaining number of APs in the param_buf structure,starting from the ap_idx index. CRs-Fixed: 4218517 Change-Id: I46504dfd17da652fddd0bcea2f3f062420b3a9ff --- wmi/src/wmi_unified_tlv.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index cd998b35ca7e..269c45b65a74 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -14208,9 +14208,14 @@ extract_roam_scan_ap_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, return QDF_STATUS_E_FAILURE; } - if (ap_idx >= param_buf->num_roam_ap_info) { - wmi_err("Invalid roam scan AP tlv ap_idx:%d total_ap:%d", - ap_idx, param_buf->num_roam_ap_info); + /* + * Check to validate that the requested number of APs do not exceed the + * remaining APs in param_buf after ap_idx to prevent out of bounds + * access. + */ + if ((ap_idx + num_cand) > param_buf->num_roam_ap_info) { + wmi_err("Invalid roam scan AP tlv ap_idx:%d, num_cand:%d, total_ap:%d", + ap_idx, num_cand, param_buf->num_roam_ap_info); return QDF_STATUS_E_FAILURE; } From 2c3bda25f8d797fe3b81218180bc8778e06b74b9 Mon Sep 17 00:00:00 2001 From: kamasali Satyanarayan Date: Mon, 29 Sep 2025 11:09:54 +0530 Subject: [PATCH 175/306] reverting enum-conversion, Handle CPU state and all USB patches 6e3e74dd047d kbuild: Move -Wenum-enum-conversion to W=2 b046ab16424e kbuild: Move -Wenum-{compare-conditional,enum-conversion} into W=1 reverting Handle CPU state 95e4f62df23f hrtimers: Handle CPU state correctly on hotplug reverting all USB patches 7a6d6b68db12 HID: usbhid: Eliminate recurrent out-of-bounds bug in usbhid_parse() b2ce37d86db3 usb: Flush altsetting 0 endpoints before reinitializating them after reset. 095cc0b5888a usb: renesas_usbhs: Reorder clock handling and power management in probe 768668e159f3 usb: usbtmc: Fix timeout value in get_stb 90da5d987601 usb: storage: Ignore UAS driver for SanDisk 3.2 Gen2 storage device 5db9d2c508ca usb: quirks: Add NO_LPM quirk for SanDisk Extreme 55AE 4f72a8dc6f67 usb: usbtmc: Fix erroneous generic_read ioctl return 85934459bc46 usb: usbtmc: Fix erroneous wait_srq ioctl return 8d9a5eaeedcd usb: usbtmc: Fix erroneous get_stb ioctl error returns 388842c35d4d USB: usbtmc: use interruptible sleep in usbtmc_read 9dda1e2a666a usb: typec: ucsi: displayport: Fix NULL pointer access 64d5ed26bff6 usb: typec: tcpm: delay SNK_TRY_WAIT_DEBOUNCE to SRC_TRYWAIT transition 30a7a793602c usb: uhci-platform: Make the clock really optional d086cca921fd usb: chipidea: ci_hdrc_imx: implement usb_phy_init() error handling b8feb22ee559 usb: chipidea: ci_hdrc_imx: use dev_err_probe() 33f2c60835a7 usb: chipidea: imx: refine the error handling for hsic 8604f111147d usb: chipidea: imx: change hsic power regulator as optional a777ccfb9ba8 usb: gadget: aspeed: Add NULL pointer check in ast_vhub_init_dev() f34551a48742 usb: host: max3421-hcd: Add missing spi_device_id table 79af6c0fa861 USB: VLI disk crashes if LPM is used 919025be9a6b usb: quirks: Add delay init quirk for SanDisk 3.2Gen1 Flash Drive ab0ffd23f312 usb: quirks: add DELAY_INIT quirk for Silicon Motion Flash Drive 015c39f38e69 usb: dwc3: gadget: check that event count does not exceed event buffer length 7109b8db9cdd USB: OHCI: Add quirk for LS7A OHCI controller (rev 0x02) eebfb64c624f usb: cdns3: Fix deadlock when using NCM gadget ec0f123f4d1a USB: serial: simple: add OWON HDS200 series oscilloscope support d75e4f33e713 USB: serial: option: add Sierra Wireless EM9291 244455a70c8a USB: serial: ftdi_sio: add support for Abacus Electrics Optical Probe 5d53a1329c80 USB: storage: quirk for ADATA Portable HDD CH94 bd4c12b86cfe usb: dwc3: support continuous runtime PM with dual role 2175d3c126c9 USB: serial: option: match on interface class for Telit FN990B f26a86f8292c USB: serial: option: fix Telit Cinterion FE990A name 57f6ae8b882f USB: serial: option: add Telit Cinterion FE990B compositions abb9f684f822 USB: serial: ftdi_sio: add support for Altera USB Blaster 3 eb00272aa51b Revert "usb: xhci: Add timeout argument in address_device USB HCD callback" 4364e0f8cfea Revert "usb: xhci: Fix NULL pointer dereference on certain command aborts" e722515dab1c xhci: pci: Fix indentation in the PCI device ID definitions 19b391884047 usb: gadget: Check bmAttributes only if configuration is valid 9af1d5c4d586 usb: gadget: Fix setting self-powered state on suspend 7367e87b6e9e usb: gadget: Set self-powered based on MaxPower and bmAttributes 094b49dec326 usb: typec: tcpci_rt1711h: Unmask alert interrupts to fix functionality b654e4c757bd usb: typec: ucsi: increase timeout for PPM reset operations dcd592ab9dd8 usb: atm: cxacru: fix a flaw in existing endpoint checks 4cd847a7b630 usb: renesas_usbhs: Flush the notify_hotplug_work a5c8be5903ec usb: quirks: Add DELAY_INIT and NO_LPM for Prolific Mass Storage Card Reader 97f8c815703e usb: renesas_usbhs: Use devm_usb_get_phy() d1968edada56 usb: renesas_usbhs: Call clk_put() 727dee085794 USB: gadget: f_midi: f_midi_complete to call queue_work 89019ab7a64f usb/gadget: f_midi: Replace tasklet with work ec42b4a0eba5 usb/gadget: f_midi: convert tasklets to use new tasklet_setup() API 19aad69c2b06 usb: dwc3: Fix timeout issue during controller enter/exit from halt state 935e842f9824 usb: dwc3: Increase DWC3 controller halt timeout 039cc7d94dc3 USB: serial: option: drop MeiG Smart defines 6621ddcdda35 USB: serial: option: fix Telit Cinterion FN990A name b95bd1248bbb USB: serial: option: add Telit Cinterion FN990B compositions 2b038768422d USB: serial: option: add MeiG Smart SLM828 7cfb70e97f09 usb: cdc-acm: Fix handling of oversized fragments a4e1ae5c0533 usb: cdc-acm: Check control transfer buffer size before access 42b30501715d USB: cdc-acm: Fill in Renesas R-Car D3 USB Download mode quirk 49f077106fa0 USB: hub: Ignore non-compliant devices with too many configs or interfaces 3a983390d14e usb: gadget: f_midi: fix MIDI Streaming descriptor lengths a0a18484cecb USB: Add USB_QUIRK_NO_LPM quirk for sony xperia xz1 smartphone a120aad69e5c USB: quirks: add USB_QUIRK_NO_LPM quirk for Teclast dist 2b8a7cfefdb2 USB: pci-quirks: Fix HCCPARAMS register error for LS7A EHCI 1c231617ac1c usb: dwc2: gadget: remove of_node reference upon udc_stop 3d921d29d48a usb: gadget: udc: renesas_usb3: Fix compiler warning 27a15815af04 usb: roles: set switch registered flag early on cc4e1d76a125 usb: gadget: f_tcm: Don't prepare BOT write request twice 54e7215ed1ab usb: gadget: f_tcm: ep_autoconfig with fullspeed endpoint 6e10b792fbf2 usb: gadget: f_tcm: Decrement command ref count on cleanup 5e051636b411 usb: gadget: f_tcm: Translate error to sense fd8bfaeba4a8 usb: xhci: Fix NULL pointer dereference on certain command aborts 7032df572eda usb: xhci: Add timeout argument in address_device USB HCD callback 7cb72dc08ed8 usb: gadget: f_tcm: Don't free command immediately 3b269db6feb2 usb: typec: tcpm: set SRC_SEND_CAPABILITIES timeout to PD_T_SENDER_RESPONSE 4b7032d01ea1 Partial revert of xhci: use pm_ptr() instead #ifdef for CONFIG_PM conditionals 1f91ebde6e35 xhci: use pm_ptr() instead of #ifdef for CONFIG_PM conditionals 76e7577bb89b Revert "usb: gadget: u_serial: Disable ep before setting port to null to fix the crash caused by port being null" fa4c7472469d USB: serial: quatech2: fix null-ptr-deref in qt2_process_read_urb() bfe60030fcd9 usb: gadget: f_fs: Remove WARN_ON in functionfs_bind b24a6afa564f usb: fix reference leak in usb_new_device() 7369c8ffc225 USB: core: Disable LPM only for non-suspended ports 01af472c23bf USB: usblp: return error when setting unsupported protocol f5f33fb57aae usb: gadget: u_serial: Disable ep before setting port to null to fix the crash caused by port being null faa0eeaf3625 USB: serial: cp210x: add Phoenix Contact UPS Device a5754f733185 usb-storage: Add max sectors quirk for Nokia 208 dffc4f7d2eca USB: serial: option: add Neoway N723-EA support f8d57de3c801 USB: serial: option: add MeiG Smart SRM815 Change-Id: Ie41f23710250fa57ccaee49aeeb96b0c3535b680 Signed-off-by: kamasali Satyanarayan --- drivers/hid/hid-hyperv.c | 5 +- drivers/hid/usbhid/hid-core.c | 25 ++++---- drivers/usb/atm/cxacru.c | 13 ++-- drivers/usb/cdns3/gadget.c | 2 - drivers/usb/chipidea/ci_hdrc_imx.c | 42 +++++++------ drivers/usb/class/cdc-acm.c | 28 +++------ drivers/usb/class/usblp.c | 7 +-- drivers/usb/class/usbtmc.c | 63 ++++++++------------ drivers/usb/core/hub.c | 33 ++-------- drivers/usb/core/port.c | 7 +-- drivers/usb/core/quirks.c | 22 ------- drivers/usb/dwc2/gadget.c | 1 - drivers/usb/dwc3/core.c | 11 +--- drivers/usb/dwc3/gadget.c | 43 +------------- drivers/usb/gadget/composite.c | 17 ++---- drivers/usb/gadget/function/f_fs.c | 2 +- drivers/usb/gadget/function/f_hid.c | 12 ++-- drivers/usb/gadget/function/f_midi.c | 22 ++++--- drivers/usb/gadget/function/f_tcm.c | 54 ++++++++++++----- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 3 - drivers/usb/gadget/udc/renesas_usb3.c | 2 +- drivers/usb/host/max3421-hcd.c | 7 --- drivers/usb/host/ohci-pci.c | 23 ------- drivers/usb/host/pci-quirks.c | 9 --- drivers/usb/host/uhci-platform.c | 2 +- drivers/usb/host/xhci-pci.c | 8 +-- drivers/usb/renesas_usbhs/common.c | 56 ++++------------- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- drivers/usb/roles/class.c | 5 +- drivers/usb/serial/cp210x.c | 1 - drivers/usb/serial/ftdi_sio.c | 16 ----- drivers/usb/serial/ftdi_sio_ids.h | 18 ------ drivers/usb/serial/option.c | 76 +++++++----------------- drivers/usb/serial/quatech2.c | 2 +- drivers/usb/serial/usb-serial-simple.c | 7 --- drivers/usb/storage/unusual_devs.h | 7 --- drivers/usb/storage/unusual_uas.h | 14 ----- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 11 ---- drivers/usb/typec/tcpm/tcpm.c | 4 +- drivers/usb/typec/ucsi/displayport.c | 2 - drivers/usb/typec/ucsi/ucsi.c | 2 +- include/linux/hid.h | 3 +- include/linux/hrtimer.h | 1 - include/linux/usb.h | 3 +- include/linux/usb/hcd.h | 2 + kernel/time/hrtimer.c | 11 +--- scripts/Makefile.extrawarn | 5 -- 47 files changed, 199 insertions(+), 512 deletions(-) diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index f9eb7ebec76f..5928e934d734 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -197,8 +197,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, if (!input_device->hid_desc) goto cleanup; - input_device->report_desc_size = le16_to_cpu( - desc->rpt_desc.wDescriptorLength); + input_device->report_desc_size = desc->desc[0].wDescriptorLength; if (input_device->report_desc_size == 0) { input_device->dev_info_status = -EINVAL; goto cleanup; @@ -214,7 +213,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, memcpy(input_device->report_desc, ((unsigned char *)desc) + desc->bLength, - le16_to_cpu(desc->rpt_desc.wDescriptorLength)); + desc->desc[0].wDescriptorLength); /* Send the ack */ memset(&ack, 0, sizeof(struct mousevsc_prt_msg)); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 6e5770b8cc4c..8537fcdb456d 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -984,11 +984,12 @@ static int usbhid_parse(struct hid_device *hid) struct usb_host_interface *interface = intf->cur_altsetting; struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; - struct hid_class_descriptor *hcdesc; u32 quirks = 0; unsigned int rsize = 0; char *rdesc; - int ret; + int ret, n; + int num_descriptors; + size_t offset = offsetof(struct hid_descriptor, desc); quirks = hid_lookup_quirk(hid); @@ -1010,19 +1011,20 @@ static int usbhid_parse(struct hid_device *hid) return -ENODEV; } - if (!hdesc->bNumDescriptors || - hdesc->bLength != sizeof(*hdesc) + - (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) { - dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n", - hdesc->bLength, hdesc->bNumDescriptors); + if (hdesc->bLength < sizeof(struct hid_descriptor)) { + dbg_hid("hid descriptor is too short\n"); return -EINVAL; } hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - if (hdesc->rpt_desc.bDescriptorType == HID_DT_REPORT) - rsize = le16_to_cpu(hdesc->rpt_desc.wDescriptorLength); + num_descriptors = min_t(int, hdesc->bNumDescriptors, + (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor)); + + for (n = 0; n < num_descriptors; n++) + if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) + rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dbg_hid("weird size of report descriptor (%u)\n", rsize); @@ -1050,11 +1052,6 @@ static int usbhid_parse(struct hid_device *hid) goto err; } - if (hdesc->bNumDescriptors > 1) - hid_warn(intf, - "%u unsupported optional hid class descriptors\n", - (int)(hdesc->bNumDescriptors - 1)); - hid->quirks |= quirks; return 0; diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index a4d863f6cda7..51d42c69fb5e 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -1135,10 +1135,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, struct cxacru_data *instance; struct usb_device *usb_dev = interface_to_usbdev(intf); struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD]; - static const u8 ep_addrs[] = { - CXACRU_EP_CMD + USB_DIR_IN, - CXACRU_EP_CMD + USB_DIR_OUT, - 0}; + struct usb_endpoint_descriptor *in, *out; int ret; /* instance init */ @@ -1186,11 +1183,13 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, } if (usb_endpoint_xfer_int(&cmd_ep->desc)) - ret = usb_check_int_endpoints(intf, ep_addrs); + ret = usb_find_common_endpoints(intf->cur_altsetting, + NULL, NULL, &in, &out); else - ret = usb_check_bulk_endpoints(intf, ep_addrs); + ret = usb_find_common_endpoints(intf->cur_altsetting, + &in, &out, NULL, NULL); - if (!ret) { + if (ret) { usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n"); ret = -ENODEV; goto fail; diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 88c3c3a1e189..61283e7e602a 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -1920,7 +1920,6 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep) "%s is already disabled\n", priv_ep->name)) return 0; - local_bh_disable(); spin_lock_irqsave(&priv_dev->lock, flags); trace_cdns3_gadget_ep_disable(priv_ep); @@ -1977,7 +1976,6 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep) priv_ep->flags &= ~EP_ENABLED; spin_unlock_irqrestore(&priv_dev->lock, flags); - local_bh_enable(); return ret; } diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index d4566b5ec348..0fe545815c5c 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -340,11 +340,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) pdata.flags |= CI_HDRC_IMX_IS_HSIC; data->usbmisc_data->hsic = 1; data->pinctrl = devm_pinctrl_get(dev); - if (PTR_ERR(data->pinctrl) == -ENODEV) - data->pinctrl = NULL; - else if (IS_ERR(data->pinctrl)) - return dev_err_probe(dev, PTR_ERR(data->pinctrl), - "pinctrl get failed\n"); + if (IS_ERR(data->pinctrl)) { + dev_err(dev, "pinctrl get failed, err=%ld\n", + PTR_ERR(data->pinctrl)); + return PTR_ERR(data->pinctrl); + } pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); if (IS_ERR(pinctrl_hsic_idle)) { @@ -369,14 +369,17 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) return PTR_ERR(data->pinctrl_hsic_active); } - data->hsic_pad_regulator = - devm_regulator_get_optional(dev, "hsic"); - if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { + data->hsic_pad_regulator = devm_regulator_get(dev, "hsic"); + if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { /* no pad regualator is needed */ data->hsic_pad_regulator = NULL; - } else if (IS_ERR(data->hsic_pad_regulator)) - return dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator), - "Get HSIC pad regulator error\n"); + } else if (IS_ERR(data->hsic_pad_regulator)) { + dev_err(dev, "Get HSIC pad regulator error: %ld\n", + PTR_ERR(data->hsic_pad_regulator)); + return PTR_ERR(data->hsic_pad_regulator); + } if (data->hsic_pad_regulator) { ret = regulator_enable(data->hsic_pad_regulator); @@ -417,11 +420,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) { pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL; data->override_phy_control = true; - ret = usb_phy_init(pdata.usb_phy); - if (ret) { - dev_err(dev, "Failed to init phy\n"); - goto err_clk; - } + usb_phy_init(pdata.usb_phy); } if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) @@ -430,7 +429,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ret = imx_usbmisc_init(data->usbmisc_data); if (ret) { dev_err(dev, "usbmisc init failed, ret=%d\n", ret); - goto phy_shutdown; + goto err_clk; } data->ci_pdev = ci_hdrc_add_device(dev, @@ -438,8 +437,10 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) &pdata); if (IS_ERR(data->ci_pdev)) { ret = PTR_ERR(data->ci_pdev); - dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n"); - goto phy_shutdown; + if (ret != -EPROBE_DEFER) + dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", + ret); + goto err_clk; } ret = imx_usbmisc_init_post(data->usbmisc_data); @@ -459,9 +460,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); -phy_shutdown: - if (data->override_phy_control) - usb_phy_shutdown(data->phy); err_clk: imx_disable_unprepare_clks(dev); disable_hsic_regulator: diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 59a354822413..8b9740142152 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -359,7 +359,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) static void acm_ctrl_irq(struct urb *urb) { struct acm *acm = urb->context; - struct usb_cdc_notification *dr; + struct usb_cdc_notification *dr = urb->transfer_buffer; unsigned int current_size = urb->actual_length; unsigned int expected_size, copy_size, alloc_size; int retval; @@ -386,25 +386,14 @@ static void acm_ctrl_irq(struct urb *urb) usb_mark_last_busy(acm->dev); - if (acm->nb_index == 0) { - /* - * The first chunk of a message must contain at least the - * notification header with the length field, otherwise we - * can't get an expected_size. - */ - if (current_size < sizeof(struct usb_cdc_notification)) { - dev_dbg(&acm->control->dev, "urb too short\n"); - goto exit; - } - dr = urb->transfer_buffer; - } else { + if (acm->nb_index) dr = (struct usb_cdc_notification *)acm->notification_buffer; - } + /* size = notification-header + (optional) data */ expected_size = sizeof(struct usb_cdc_notification) + le16_to_cpu(dr->wLength); - if (acm->nb_index != 0 || current_size < expected_size) { + if (current_size < expected_size) { /* notification is transmitted fragmented, reassemble */ if (acm->nb_size < expected_size) { u8 *new_buffer; @@ -1744,16 +1733,13 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, - { USB_DEVICE(0x045b, 0x023c), /* Renesas R-Car H3 USB Download mode */ + { USB_DEVICE(0x045b, 0x023c), /* Renesas USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, - { USB_DEVICE(0x045b, 0x0247), /* Renesas R-Car D3 USB Download mode */ + { USB_DEVICE(0x045b, 0x0248), /* Renesas USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, - { USB_DEVICE(0x045b, 0x0248), /* Renesas R-Car M3-N USB Download mode */ - .driver_info = DISABLE_ECHO, /* Don't echo banner */ - }, - { USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */ + { USB_DEVICE(0x045b, 0x024D), /* Renesas USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 759f567538e2..f27b4aecff3d 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -1337,12 +1337,11 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) return -EINVAL; - alts = usblp->protocol[protocol].alt_setting; - if (alts < 0) - return -EINVAL; - /* Don't unnecessarily set the interface if there's a single alt. */ if (usblp->intf->num_altsetting > 1) { + alts = usblp->protocol[protocol].alt_setting; + if (alts < 0) + return -EINVAL; r = usb_set_interface(usblp->dev, usblp->ifnum, alts); if (r < 0) { printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index d8ed205e6b43..00345a51f18d 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -485,8 +485,6 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, u8 tag; __u8 stb; int rv; - long wait_rv; - unsigned long expire; dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", data->iin_ep_present); @@ -529,18 +527,16 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, } if (data->iin_ep_present) { - expire = msecs_to_jiffies(file_data->timeout); - wait_rv = wait_event_interruptible_timeout( + rv = wait_event_interruptible_timeout( data->waitq, atomic_read(&data->iin_data_valid) != 0, - expire); - if (wait_rv < 0) { - dev_dbg(dev, "wait interrupted %ld\n", wait_rv); - rv = wait_rv; + file_data->timeout); + if (rv < 0) { + dev_dbg(dev, "wait interrupted %d\n", rv); goto exit; } - if (wait_rv == 0) { + if (rv == 0) { dev_dbg(dev, "wait timed out\n"); rv = -ETIMEDOUT; goto exit; @@ -560,8 +556,6 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, rv = put_user(stb, (__u8 __user *)arg); dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv); - rv = 0; - exit: /* bump interrupt bTag */ data->iin_bTag += 1; @@ -578,9 +572,9 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, { struct usbtmc_device_data *data = file_data->data; struct device *dev = &data->intf->dev; + int rv; u32 timeout; unsigned long expire; - long wait_rv; if (!data->iin_ep_present) { dev_dbg(dev, "no interrupt endpoint present\n"); @@ -594,24 +588,25 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, mutex_unlock(&data->io_mutex); - wait_rv = wait_event_interruptible_timeout( - data->waitq, - atomic_read(&file_data->srq_asserted) != 0 || - atomic_read(&file_data->closing), - expire); + rv = wait_event_interruptible_timeout( + data->waitq, + atomic_read(&file_data->srq_asserted) != 0 || + atomic_read(&file_data->closing), + expire); mutex_lock(&data->io_mutex); /* Note! disconnect or close could be called in the meantime */ if (atomic_read(&file_data->closing) || data->zombie) - return -ENODEV; + rv = -ENODEV; - if (wait_rv < 0) { - dev_dbg(dev, "%s - wait interrupted %ld\n", __func__, wait_rv); - return wait_rv; + if (rv < 0) { + /* dev can be invalid now! */ + pr_debug("%s - wait interrupted %d\n", __func__, rv); + return rv; } - if (wait_rv == 0) { + if (rv == 0) { dev_dbg(dev, "%s - wait timed out\n", __func__); return -ETIMEDOUT; } @@ -805,7 +800,6 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, unsigned long expire; int bufcount = 1; int again = 0; - long wait_rv; /* mutex already locked */ @@ -918,24 +912,19 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, if (!(flags & USBTMC_FLAG_ASYNC)) { dev_dbg(dev, "%s: before wait time %lu\n", __func__, expire); - wait_rv = wait_event_interruptible_timeout( + retval = wait_event_interruptible_timeout( file_data->wait_bulk_in, usbtmc_do_transfer(file_data), expire); - dev_dbg(dev, "%s: wait returned %ld\n", - __func__, wait_rv); + dev_dbg(dev, "%s: wait returned %d\n", + __func__, retval); - if (wait_rv < 0) { - retval = wait_rv; + if (retval <= 0) { + if (retval == 0) + retval = -ETIMEDOUT; goto error; } - - if (wait_rv == 0) { - retval = -ETIMEDOUT; - goto error; - } - } urb = usb_get_from_anchor(&file_data->in_anchor); @@ -1361,10 +1350,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, if (!buffer) return -ENOMEM; - retval = mutex_lock_interruptible(&data->io_mutex); - if (retval < 0) - goto exit_nolock; - + mutex_lock(&data->io_mutex); if (data->zombie) { retval = -ENODEV; goto exit; @@ -1487,7 +1473,6 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, exit: mutex_unlock(&data->io_mutex); -exit_nolock: kfree(buffer); return retval; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 44e7c2c39320..5dab663b7628 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1793,17 +1793,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); - /* - * The USB 2.0 spec prohibits hubs from having more than one - * configuration or interface, and we rely on this prohibition. - * Refuse to accept a device that violates it. - */ - if (hdev->descriptor.bNumConfigurations > 1 || - hdev->actconfig->desc.bNumInterfaces > 1) { - dev_err(&intf->dev, "Invalid hub with more than one config or interface\n"); - return -EINVAL; - } - /* * Set default autosuspend delay as 0 to speedup bus suspend, * based on the below considerations: @@ -2604,13 +2593,13 @@ int usb_new_device(struct usb_device *udev) err = sysfs_create_link(&udev->dev.kobj, &port_dev->dev.kobj, "port"); if (err) - goto out_del_dev; + goto fail; err = sysfs_create_link(&port_dev->dev.kobj, &udev->dev.kobj, "device"); if (err) { sysfs_remove_link(&udev->dev.kobj, "port"); - goto out_del_dev; + goto fail; } if (!test_and_set_bit(port1, hub->child_usage_bits)) @@ -2622,8 +2611,6 @@ int usb_new_device(struct usb_device *udev) pm_runtime_put_sync_autosuspend(&udev->dev); return err; -out_del_dev: - device_del(&udev->dev); fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); pm_runtime_disable(&udev->dev); @@ -5831,7 +5818,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) struct usb_hub *parent_hub; struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_device_descriptor descriptor = udev->descriptor; - struct usb_interface *intf; struct usb_host_bos *bos; int i, j, ret = 0; int port1 = udev->portnum; @@ -5893,18 +5879,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (!udev->actconfig) goto done; - /* - * Some devices can't handle setting default altsetting 0 with a - * Set-Interface request. Disable host-side endpoints of those - * interfaces here. Enable and reset them back after host has set - * its internal endpoint structures during usb_hcd_alloc_bandwith() - */ - for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { - intf = udev->actconfig->interface[i]; - if (intf->cur_altsetting->desc.bAlternateSetting == 0) - usb_disable_interface(udev, intf, true); - } - mutex_lock(hcd->bandwidth_mutex); ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL); if (ret < 0) { @@ -5936,11 +5910,12 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { struct usb_host_config *config = udev->actconfig; + struct usb_interface *intf = config->interface[i]; struct usb_interface_descriptor *desc; - intf = config->interface[i]; desc = &intf->cur_altsetting->desc; if (desc->bAlternateSetting == 0) { + usb_disable_interface(udev, intf, true); usb_enable_interface(udev, intf, true); ret = 0; } else { diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index f01b0103fe12..86e8585a5512 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -294,11 +294,10 @@ static int usb_port_runtime_suspend(struct device *dev) static void usb_port_shutdown(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); - struct usb_device *udev = port_dev->child; - if (udev && !udev->port_is_suspended) { - usb_disable_usb2_hardware_lpm(udev); - usb_unlocked_disable_lpm(udev); + if (port_dev->child) { + usb_disable_usb2_hardware_lpm(port_dev->child); + usb_unlocked_disable_lpm(port_dev->child); } } diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 98b1c457a091..a158bf40373b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -338,10 +338,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0638, 0x0a13), .driver_info = USB_QUIRK_STRING_FETCH_255 }, - /* Prolific Single-LUN Mass Storage Card Reader */ - { USB_DEVICE(0x067b, 0x2731), .driver_info = USB_QUIRK_DELAY_INIT | - USB_QUIRK_NO_LPM }, - /* Saitek Cyborg Gold Joystick */ { USB_DEVICE(0x06a3, 0x0006), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -366,12 +362,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM }, { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM }, - /* SanDisk Corp. SanDisk 3.2Gen1 */ - { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, - - /* SanDisk Extreme 55AE */ - { USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM }, - /* Realforce 87U Keyboard */ { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM }, @@ -386,9 +376,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0904, 0x6103), .driver_info = USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL }, - /* Silicon Motion Flash Drive */ - { USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT }, - /* Sound Devices USBPre2 */ { USB_DEVICE(0x0926, 0x0202), .driver_info = USB_QUIRK_ENDPOINT_BLACKLIST }, @@ -443,9 +430,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0c45, 0x7056), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, - /* Sony Xperia XZ1 Compact (lilac) smartphone in fastboot mode */ - { USB_DEVICE(0x0fce, 0x0dde), .driver_info = USB_QUIRK_NO_LPM }, - /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, @@ -536,16 +520,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* Blackmagic Design UltraStudio SDI */ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, - /* Teclast disk */ - { USB_DEVICE(0x1f75, 0x0917), .driver_info = USB_QUIRK_NO_LPM }, - /* Hauppauge HVR-950q */ { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, - /* VLI disk */ - { USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM }, - /* Raydium Touchscreen */ { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 74d2dbf9a535..abc2271799e0 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4548,7 +4548,6 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) spin_lock_irqsave(&hsotg->lock, flags); hsotg->driver = NULL; - hsotg->gadget.dev.of_node = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; hsotg->enabled = 0; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a262ccd1cf92..7caa6aacf9d4 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -122,19 +122,17 @@ static void __dwc3_set_mode(struct work_struct *work) if (dwc->dr_mode != USB_DR_MODE_OTG) return; - pm_runtime_get_sync(dwc->dev); - if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) dwc3_otg_update(dwc, 0); if (!dwc->desired_dr_role) - goto out; + return; if (dwc->desired_dr_role == dwc->current_dr_role) - goto out; + return; if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) - goto out; + return; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_HOST: @@ -198,9 +196,6 @@ static void __dwc3_set_mode(struct work_struct *work) break; } -out: - pm_runtime_mark_last_busy(dwc->dev); - pm_runtime_put_autosuspend(dwc->dev); } void dwc3_set_mode(struct dwc3 *dwc, u32 mode) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 76316205483b..6caedef5575d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1966,39 +1966,11 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) { u32 reg; - u32 timeout = 2000; - u32 saved_config = 0; + u32 timeout = 500; if (pm_runtime_suspended(dwc->dev)) return 0; - /* - * When operating in USB 2.0 speeds (HS/FS), ensure that - * GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY are cleared before starting - * or stopping the controller. This resolves timeout issues that occur - * during frequent role switches between host and device modes. - * - * Save and clear these settings, then restore them after completing the - * controller start or stop sequence. - * - * This solution was discovered through experimentation as it is not - * mentioned in the dwc3 programming guide. It has been tested on an - * Exynos platforms. - */ - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - if (reg & DWC3_GUSB2PHYCFG_SUSPHY) { - saved_config |= DWC3_GUSB2PHYCFG_SUSPHY; - reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; - } - - if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) { - saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM; - reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM; - } - - if (saved_config) - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); - reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) { if (dwc->revision <= DWC3_REVISION_187A) { @@ -2026,17 +1998,10 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend) dwc3_writel(dwc->regs, DWC3_DCTL, reg); do { - usleep_range(1000, 2000); reg = dwc3_readl(dwc->regs, DWC3_DSTS); reg &= DWC3_DSTS_DEVCTRLHLT; } while (--timeout && !(!is_on ^ !reg)); - if (saved_config) { - reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); - reg |= saved_config; - dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); - } - if (!timeout) return -ETIMEDOUT; @@ -3652,12 +3617,6 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) if (!count) return IRQ_NONE; - if (count > evt->length) { - dev_err_ratelimited(dwc->dev, "invalid count(%u) > evt->length(%u)\n", - count, evt->length); - return IRQ_NONE; - } - evt->count = count; evt->flags |= DWC3_EVENT_PENDING; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 4b2e9df97b11..3596ff37b9ef 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -915,11 +915,10 @@ static int set_config(struct usb_composite_dev *cdev, else power = min(power, 900U); done: - if (power > USB_SELF_POWER_VBUS_MAX_DRAW || - (c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER))) - usb_gadget_clear_selfpowered(gadget); - else + if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_set_selfpowered(gadget); + else + usb_gadget_clear_selfpowered(gadget); usb_gadget_vbus_draw(gadget, power); if (result >= 0 && cdev->delayed_status) @@ -2366,10 +2365,7 @@ void composite_suspend(struct usb_gadget *gadget) cdev->suspended = 1; - if (cdev->config && - cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER) - usb_gadget_set_selfpowered(gadget); - + usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, 2); } @@ -2398,11 +2394,8 @@ void composite_resume(struct usb_gadget *gadget) else maxpower = min(maxpower, 900U); - if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW || - !(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) + if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_clear_selfpowered(gadget); - else - usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, maxpower); } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 9b5f9d503ff0..53658162b148 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1875,7 +1875,7 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) ENTER(); - if ((ffs->state != FFS_ACTIVE + if (WARN_ON(ffs->state != FFS_ACTIVE || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) return -EBADFD; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 77354626252c..571560d689c8 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -114,8 +114,8 @@ static struct hid_descriptor hidg_desc = { .bcdHID = cpu_to_le16(0x0101), .bCountryCode = 0x00, .bNumDescriptors = 0x1, - /*.rpt_desc.bDescriptorType = DYNAMIC */ - /*.rpt_desc.wDescriptorLength = DYNAMIC */ + /*.desc[0].bDescriptorType = DYNAMIC */ + /*.desc[0].wDescriptorLenght = DYNAMIC */ }; /* Super-Speed Support */ @@ -730,8 +730,8 @@ static int hidg_setup(struct usb_function *f, struct hid_descriptor hidg_desc_copy = hidg_desc; VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n"); - hidg_desc_copy.rpt_desc.bDescriptorType = HID_DT_REPORT; - hidg_desc_copy.rpt_desc.wDescriptorLength = + hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT; + hidg_desc_copy.desc[0].wDescriptorLength = cpu_to_le16(hidg->report_desc_length); length = min_t(unsigned short, length, @@ -972,8 +972,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) * We can use hidg_desc struct here but we should not relay * that its content won't change after returning from this function. */ - hidg_desc.rpt_desc.bDescriptorType = HID_DT_REPORT; - hidg_desc.rpt_desc.wDescriptorLength = + hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT; + hidg_desc.desc[0].wDescriptorLength = cpu_to_le16(hidg->report_desc_length); hidg_hs_in_ep_desc.bEndpointAddress = diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index b741cdcd0128..6745919144b8 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -87,7 +87,7 @@ struct f_midi { struct snd_rawmidi_substream *out_substream[MAX_PORTS]; unsigned long out_triggered; - struct work_struct work; + struct tasklet_struct tasklet; unsigned int in_ports; unsigned int out_ports; int index; @@ -282,7 +282,7 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req) /* Our transmit completed. See if there's more to go. * f_midi_transmit eats req, don't queue it again. */ req->length = 0; - queue_work(system_highpri_wq, &midi->work); + f_midi_transmit(midi); return; } break; @@ -698,11 +698,9 @@ drop_out: f_midi_drop_out_substreams(midi); } -static void f_midi_in_work(struct work_struct *work) +static void f_midi_in_tasklet(unsigned long data) { - struct f_midi *midi; - - midi = container_of(work, struct f_midi, work); + struct f_midi *midi = (struct f_midi *) data; f_midi_transmit(midi); } @@ -739,7 +737,7 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) VDBG(midi, "%s() %d\n", __func__, up); midi->in_ports_array[substream->number].active = up; if (up) - queue_work(system_highpri_wq, &midi->work); + tasklet_hi_schedule(&midi->tasklet); } static int f_midi_out_open(struct snd_rawmidi_substream *substream) @@ -877,7 +875,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; - INIT_WORK(&midi->work, f_midi_in_work); + tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); status = f_midi_register_card(midi); if (status < 0) goto fail_register; @@ -999,11 +997,11 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) } /* configure the endpoint descriptors ... */ - ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); - ms_out_desc.bNumEmbMIDIJack = midi->out_ports; + ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); + ms_out_desc.bNumEmbMIDIJack = midi->in_ports; - ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); - ms_in_desc.bNumEmbMIDIJack = midi->in_ports; + ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); + ms_in_desc.bNumEmbMIDIJack = midi->out_ports; /* ... and add them to the list */ endpoint_descriptor_index = i; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 90fe33f9e095..41a10bcc2efc 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -245,6 +245,7 @@ static int bot_send_write_request(struct usbg_cmd *cmd) { struct f_uas *fu = cmd->fu; struct se_cmd *se_cmd = &cmd->se_cmd; + struct usb_gadget *gadget = fuas_to_gadget(fu); int ret; init_completion(&cmd->write_complete); @@ -255,6 +256,22 @@ static int bot_send_write_request(struct usbg_cmd *cmd) return -EINVAL; } + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL); + if (!cmd->data_buf) + return -ENOMEM; + + fu->bot_req_out->buf = cmd->data_buf; + } else { + fu->bot_req_out->buf = NULL; + fu->bot_req_out->num_sgs = se_cmd->t_data_nents; + fu->bot_req_out->sg = se_cmd->t_data_sg; + } + + fu->bot_req_out->complete = usbg_data_write_cmpl; + fu->bot_req_out->length = se_cmd->data_length; + fu->bot_req_out->context = cmd; + ret = usbg_prepare_w_request(cmd, fu->bot_req_out); if (ret) goto cleanup; @@ -954,7 +971,6 @@ static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req) return; cleanup: - target_put_sess_cmd(se_cmd); transport_generic_free_cmd(&cmd->se_cmd, 0); } @@ -1047,7 +1063,8 @@ static void usbg_cmd_work(struct work_struct *work) out: transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 0); + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + transport_generic_free_cmd(&cmd->se_cmd, 0); } static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, @@ -1176,7 +1193,8 @@ static void bot_cmd_work(struct work_struct *work) out: transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 0); + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + transport_generic_free_cmd(&cmd->se_cmd, 0); } static int bot_submit_command(struct f_uas *fu, @@ -1999,39 +2017,43 @@ static int tcm_bind(struct usb_configuration *c, struct usb_function *f) bot_intf_desc.bInterfaceNumber = iface; uasp_intf_desc.bInterfaceNumber = iface; fu->iface = iface; - ep = usb_ep_autoconfig(gadget, &uasp_fs_bi_desc); + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc, + &uasp_bi_ep_comp_desc); if (!ep) goto ep_fail; fu->ep_in = ep; - ep = usb_ep_autoconfig(gadget, &uasp_fs_bo_desc); + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc, + &uasp_bo_ep_comp_desc); if (!ep) goto ep_fail; fu->ep_out = ep; - ep = usb_ep_autoconfig(gadget, &uasp_fs_status_desc); + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc, + &uasp_status_in_ep_comp_desc); if (!ep) goto ep_fail; fu->ep_status = ep; - ep = usb_ep_autoconfig(gadget, &uasp_fs_cmd_desc); + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc, + &uasp_cmd_comp_desc); if (!ep) goto ep_fail; fu->ep_cmd = ep; /* Assume endpoint addresses are the same for both speeds */ - uasp_bi_desc.bEndpointAddress = uasp_fs_bi_desc.bEndpointAddress; - uasp_bo_desc.bEndpointAddress = uasp_fs_bo_desc.bEndpointAddress; + uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; + uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; uasp_status_desc.bEndpointAddress = - uasp_fs_status_desc.bEndpointAddress; - uasp_cmd_desc.bEndpointAddress = uasp_fs_cmd_desc.bEndpointAddress; + uasp_ss_status_desc.bEndpointAddress; + uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; - uasp_ss_bi_desc.bEndpointAddress = uasp_fs_bi_desc.bEndpointAddress; - uasp_ss_bo_desc.bEndpointAddress = uasp_fs_bo_desc.bEndpointAddress; - uasp_ss_status_desc.bEndpointAddress = - uasp_fs_status_desc.bEndpointAddress; - uasp_ss_cmd_desc.bEndpointAddress = uasp_fs_cmd_desc.bEndpointAddress; + uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; + uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; + uasp_fs_status_desc.bEndpointAddress = + uasp_ss_status_desc.bEndpointAddress; + uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; ret = usb_assign_descriptors(f, uasp_fs_function_desc, uasp_hs_function_desc, uasp_ss_function_desc, diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 89d7d3b24718..4008e7a51188 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -542,9 +542,6 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) d->vhub = vhub; d->index = idx; d->name = devm_kasprintf(parent, GFP_KERNEL, "port%d", idx+1); - if (!d->name) - return -ENOMEM; - d->regs = vhub->regs + 0x100 + 0x10 * idx; ast_vhub_init_ep0(vhub, &d->ep0, d); diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 2952e5feb2ee..e04acf2dfa65 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -306,7 +306,7 @@ struct renesas_usb3_request { struct list_head queue; }; -#define USB3_EP_NAME_SIZE 16 +#define USB3_EP_NAME_SIZE 8 struct renesas_usb3_ep { struct usb_ep ep; struct renesas_usb3 *usb3; diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 5a21777197e9..0a5e0e644982 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1956,12 +1956,6 @@ max3421_remove(struct spi_device *spi) return 0; } -static const struct spi_device_id max3421_spi_ids[] = { - { "max3421" }, - { }, -}; -MODULE_DEVICE_TABLE(spi, max3421_spi_ids); - static const struct of_device_id max3421_of_match_table[] = { { .compatible = "maxim,max3421", }, {}, @@ -1971,7 +1965,6 @@ MODULE_DEVICE_TABLE(of, max3421_of_match_table); static struct spi_driver max3421_driver = { .probe = max3421_probe, .remove = max3421_remove, - .id_table = max3421_spi_ids, .driver = { .name = "max3421-hcd", .of_match_table = of_match_ptr(max3421_of_match_table), diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index f9719ee5ba9e..f4e13a3fddee 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -165,25 +165,6 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) return 0; } -static int ohci_quirk_loongson(struct usb_hcd *hcd) -{ - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* - * Loongson's LS7A OHCI controller (rev 0x02) has a - * flaw. MMIO register with offset 0x60/64 is treated - * as legacy PS2-compatible keyboard/mouse interface. - * Since OHCI only use 4KB BAR resource, LS7A OHCI's - * 32KB BAR is wrapped around (the 2nd 4KB BAR space - * is the same as the 1st 4KB internally). So add 4KB - * offset (0x1000) to the OHCI registers as a quirk. - */ - if (pdev->revision == 0x2) - hcd->regs += SZ_4K; /* SZ_4K = 0x1000 */ - - return 0; -} - static int ohci_quirk_qemu(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); @@ -243,10 +224,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), .driver_data = (unsigned long)ohci_quirk_amd700, }, - { - PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a24), - .driver_data = (unsigned long)ohci_quirk_loongson, - }, { .vendor = PCI_VENDOR_ID_APPLE, .device = 0x003f, diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 7c98941d1108..f6d04491df60 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -945,15 +945,6 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) * booting from USB disk or using a usb keyboard */ hcc_params = readl(base + EHCI_HCC_PARAMS); - - /* LS7A EHCI controller doesn't have extended capabilities, the - * EECP (EHCI Extended Capabilities Pointer) field of HCCPARAMS - * register should be 0x0 but it reads as 0xa0. So clear it to - * avoid error messages on boot. - */ - if (pdev->vendor == PCI_VENDOR_ID_LOONGSON && pdev->device == 0x7a14) - hcc_params &= ~(0xffL << 8); - offset = (hcc_params >> 8) & 0xff; while (offset && --count) { pci_read_config_dword(pdev, offset, &cap); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index c0834bac4c95..be9e9db7cad1 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -122,7 +122,7 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) } /* Get and enable clock if any specified */ - uhci->clk = devm_clk_get_optional(&pdev->dev, NULL); + uhci->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(uhci->clk)) { ret = PTR_ERR(uhci->clk); goto err_rmr; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 8056be6a368a..b5ebbb9092f1 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -26,8 +26,8 @@ #define SPARSE_CNTL_ENABLE 0xC12C /* Device for a quirk */ -#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 -#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 +#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009 0x1009 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 0x1100 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 @@ -36,8 +36,8 @@ #define PCI_DEVICE_ID_EJ168 0x7023 #define PCI_DEVICE_ID_EJ188 0x7052 -#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 -#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index c395f5e23f8b..a3c30b609433 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -313,10 +313,8 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv) priv->clks[1] = of_clk_get(dev_of_node(dev), 1); if (PTR_ERR(priv->clks[1]) == -ENOENT) priv->clks[1] = NULL; - else if (IS_ERR(priv->clks[1])) { - clk_put(priv->clks[0]); + else if (IS_ERR(priv->clks[1])) return PTR_ERR(priv->clks[1]); - } return 0; } @@ -680,29 +678,10 @@ static int usbhs_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); spin_lock_init(usbhs_priv_to_lock(priv)); - /* - * Acquire clocks and enable power management (PM) early in the - * probe process, as the driver accesses registers during - * initialization. Ensure the device is active before proceeding. - */ - pm_runtime_enable(dev); - - ret = usbhsc_clk_get(dev, priv); - if (ret) - goto probe_pm_disable; - - ret = pm_runtime_resume_and_get(dev); - if (ret) - goto probe_clk_put; - - ret = usbhsc_clk_prepare_enable(priv); - if (ret) - goto probe_pm_put; - /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) - goto probe_clk_dis_unprepare; + return ret; ret = usbhs_fifo_probe(priv); if (ret < 0) @@ -719,6 +698,10 @@ static int usbhs_probe(struct platform_device *pdev) if (ret) goto probe_fail_rst; + ret = usbhsc_clk_get(dev, priv); + if (ret) + goto probe_fail_clks; + /* * deviece reset here because * USB device might be used in boot loader. @@ -734,7 +717,7 @@ static int usbhs_probe(struct platform_device *pdev) dev_warn(dev, "USB function not selected (GPIO %d)\n", priv->dparam.enable_gpio); ret = -ENOTSUPP; - goto probe_assert_rest; + goto probe_end_mod_exit; } } @@ -748,19 +731,14 @@ static int usbhs_probe(struct platform_device *pdev) ret = usbhs_platform_call(priv, hardware_init, pdev); if (ret < 0) { dev_err(dev, "platform init failed.\n"); - goto probe_assert_rest; + goto probe_end_mod_exit; } /* reset phy for connection */ usbhs_platform_call(priv, phy_reset, pdev); - /* - * Disable the clocks that were enabled earlier in the probe path, - * and let the driver handle the clocks beyond this point. - */ - usbhsc_clk_disable_unprepare(priv); - pm_runtime_put(dev); - + /* power control */ + pm_runtime_enable(dev); if (!usbhs_get_dparam(priv, runtime_pwctrl)) { usbhsc_power_ctrl(priv, 1); usbhs_mod_autonomy_mode(priv); @@ -777,7 +755,9 @@ static int usbhs_probe(struct platform_device *pdev) return ret; -probe_assert_rest: +probe_end_mod_exit: + usbhsc_clk_put(priv); +probe_fail_clks: reset_control_assert(priv->rsts); probe_fail_rst: usbhs_mod_remove(priv); @@ -785,14 +765,6 @@ probe_end_fifo_exit: usbhs_fifo_remove(priv); probe_end_pipe_exit: usbhs_pipe_remove(priv); -probe_clk_dis_unprepare: - usbhsc_clk_disable_unprepare(priv); -probe_pm_put: - pm_runtime_put(dev); -probe_clk_put: - usbhsc_clk_put(priv); -probe_pm_disable: - pm_runtime_disable(dev); dev_info(dev, "probe failed (%d)\n", ret); @@ -805,8 +777,6 @@ static int usbhs_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "usb remove\n"); - flush_delayed_work(&priv->notify_hotplug_work); - /* power off */ if (!usbhs_get_dparam(priv, runtime_pwctrl)) usbhsc_power_ctrl(priv, 0); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 5a4605bbaa8b..53489cafecc1 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1094,7 +1094,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) goto usbhs_mod_gadget_probe_err_gpriv; } - gpriv->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_UNDEFINED); + gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); dev_info(dev, "%stransceiver found\n", !IS_ERR(gpriv->transceiver) ? "" : "no "); diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 4e00a185a4b6..aa4fb7a66dce 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -317,15 +317,14 @@ usb_role_switch_register(struct device *parent, sw->dev.type = &usb_role_dev_type; dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent)); - sw->registered = true; - ret = device_register(&sw->dev); if (ret) { - sw->registered = false; put_device(&sw->dev); return ERR_PTR(ret); } + sw->registered = true; + /* TODO: Symlinks for the host port and the device controller. */ return sw; diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 39c9d1f857fc..5353fa7e5969 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -224,7 +224,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ - { USB_DEVICE(0x1B93, 0x1013) }, /* Phoenix Contact UPS Device */ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ { USB_DEVICE(0x1D6F, 0x0010) }, /* Seluxit ApS RF Dongle */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d13b8e35ce33..bfb0be4e70d5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1057,22 +1057,6 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, /* GMC devices */ { USB_DEVICE(GMC_VID, GMC_Z216C_PID) }, - /* Altera USB Blaster 3 */ - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6022_PID, 1) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6025_PID, 2) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6026_PID, 2) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6026_PID, 3) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6029_PID, 2) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602A_PID, 2) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602A_PID, 3) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602C_PID, 1) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602D_PID, 1) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602D_PID, 2) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 1) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 2) }, - { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) }, - /* Abacus Electrics */ - { USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 9c95ca876bae..b2aec1106678 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -435,11 +435,6 @@ #define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ #define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ -/* - * Abacus Electrics - */ -#define ABACUS_OPTICAL_PROBE_PID 0xf458 /* ABACUS ELECTRICS Optical Probe */ - /* * Oceanic product ids */ @@ -1610,16 +1605,3 @@ */ #define GMC_VID 0x1cd7 #define GMC_Z216C_PID 0x0217 /* GMC Z216C Adapter IR-USB */ - -/* - * Altera USB Blaster 3 (http://www.altera.com). - */ -#define ALTERA_VID 0x09fb -#define ALTERA_UB3_6022_PID 0x6022 -#define ALTERA_UB3_6025_PID 0x6025 -#define ALTERA_UB3_6026_PID 0x6026 -#define ALTERA_UB3_6029_PID 0x6029 -#define ALTERA_UB3_602A_PID 0x602a -#define ALTERA_UB3_602C_PID 0x602c -#define ALTERA_UB3_602D_PID 0x602d -#define ALTERA_UB3_602E_PID 0x602e diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 08d70256e72e..3ae4ac4d9857 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -611,7 +611,6 @@ static void option_instat_callback(struct urb *urb); /* Sierra Wireless products */ #define SIERRA_VENDOR_ID 0x1199 #define SIERRA_PRODUCT_EM9191 0x90d3 -#define SIERRA_PRODUCT_EM9291 0x90e3 /* UNISOC (Spreadtrum) products */ #define UNISOC_VENDOR_ID 0x1782 @@ -620,6 +619,15 @@ static void option_instat_callback(struct urb *urb); /* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */ #define LUAT_PRODUCT_AIR720U 0x4e00 +/* MeiG Smart Technology products */ +#define MEIGSMART_VENDOR_ID 0x2dee +/* MeiG Smart SRM825L based on Qualcomm 315 */ +#define MEIGSMART_PRODUCT_SRM825L 0x4d22 +/* MeiG Smart SLM320 based on UNISOC UIS8910 */ +#define MEIGSMART_PRODUCT_SLM320 0x4d41 +/* MeiG Smart SLM770A based on ASR1803 */ +#define MEIGSMART_PRODUCT_SLM770A 0x4d57 + /* Device flags */ /* Highest interface number which can be used with NCTRL() and RSVD() */ @@ -1359,23 +1367,23 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(2) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1063, 0xff), /* Telit LN920 (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1070, 0xff), /* Telit FN990A (rmnet) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1070, 0xff), /* Telit FN990 (rmnet) */ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1071, 0xff), /* Telit FN990A (MBIM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1071, 0xff), /* Telit FN990 (MBIM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1072, 0xff), /* Telit FN990A (RNDIS) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1072, 0xff), /* Telit FN990 (RNDIS) */ .driver_info = NCTRL(2) | RSVD(3) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff), /* Telit FN990A (ECM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff), /* Telit FN990 (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990A (PCIe) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990 (PCIe) */ .driver_info = RSVD(0) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990A (rmnet) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990 (rmnet) */ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990A (MBIM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990 (MBIM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1082, 0xff), /* Telit FE990A (RNDIS) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1082, 0xff), /* Telit FE990 (RNDIS) */ .driver_info = NCTRL(2) | RSVD(3) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1083, 0xff), /* Telit FE990A (ECM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1083, 0xff), /* Telit FE990 (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a0, 0xff), /* Telit FN20C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, @@ -1389,44 +1397,12 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x30), /* Telit FE990B (rmnet) */ - .driver_info = NCTRL(5) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b1, 0xff, 0xff, 0x30), /* Telit FE990B (MBIM) */ - .driver_info = NCTRL(6) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b1, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b1, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b2, 0xff, 0xff, 0x30), /* Telit FE990B (RNDIS) */ - .driver_info = NCTRL(6) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b2, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b2, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x30), /* Telit FE990B (ECM) */ - .driver_info = NCTRL(6) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x60) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c0, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c4, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c8, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x30), /* Telit FN990B (rmnet) */ - .driver_info = NCTRL(5) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x30), /* Telit FN990B (MBIM) */ - .driver_info = NCTRL(6) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d2, 0xff, 0xff, 0x30), /* Telit FN990B (RNDIS) */ - .driver_info = NCTRL(6) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d2, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d2, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d3, 0xff, 0xff, 0x30), /* Telit FN990B (ECM) */ - .driver_info = NCTRL(6) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d3, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d3, 0xff, 0xff, 0x60) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), @@ -2371,14 +2347,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a05, 0xff) }, /* Fibocom FM650-CN (NCM mode) */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a06, 0xff) }, /* Fibocom FM650-CN (RNDIS mode) */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a07, 0xff) }, /* Fibocom FM650-CN (MBIM mode) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d41, 0xff, 0, 0) }, /* MeiG Smart SLM320 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57, 0xff, 0, 0) }, /* MeiG Smart SLM770A */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0, 0) }, /* MeiG Smart SRM815 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0x10, 0x02) }, /* MeiG Smart SLM828 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0x10, 0x03) }, /* MeiG Smart SLM828 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM815 and SRM825L */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825L */ - { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825L */ { USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */ @@ -2433,15 +2401,17 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x30) }, - { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM770A, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x60) }, { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff), /* TCL IK512 MBIM */ .driver_info = NCTRL(1) }, { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0640, 0xff), /* TCL IK512 ECM */ .driver_info = NCTRL(3) }, - { USB_DEVICE_INTERFACE_CLASS(0x2949, 0x8700, 0xff) }, /* Neoway N723-EA */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 5501898dfcfb..d172e8642d4a 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -555,7 +555,7 @@ static void qt2_process_read_urb(struct urb *urb) newport = *(ch + 3); - if (newport >= serial->num_ports) { + if (newport > serial->num_ports) { dev_err(&port->dev, "%s - port change to invalid port: %i\n", __func__, newport); diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index bac5ab6377ae..24b8772a345e 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -101,11 +101,6 @@ DEVICE(nokia, NOKIA_IDS); { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ DEVICE_N(novatel_gps, NOVATEL_IDS, 3); -/* OWON electronic test and measurement equipment driver */ -#define OWON_IDS() \ - { USB_DEVICE(0x5345, 0x1234) } /* HDS200 oscilloscopes and others */ -DEVICE(owon, OWON_IDS); - /* Siemens USB/MPI adapter */ #define SIEMENS_IDS() \ { USB_DEVICE(0x908, 0x0004) } @@ -140,7 +135,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &motorola_tetra_device, &nokia_device, &novatel_gps_device, - &owon_device, &siemens_mpi_device, &suunto_device, &vivopay_device, @@ -160,7 +154,6 @@ static const struct usb_device_id id_table[] = { MOTOROLA_TETRA_IDS(), NOKIA_IDS(), NOVATEL_IDS(), - OWON_IDS(), SIEMENS_IDS(), SUUNTO_IDS(), VIVOPAY_IDS(), diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index a6dc2faae85d..606a68bd8059 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -255,13 +255,6 @@ UNUSUAL_DEV( 0x0421, 0x06aa, 0x1110, 0x1110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), -/* Added by Lubomir Rintel , a very fine chap */ -UNUSUAL_DEV( 0x0421, 0x06c2, 0x0000, 0x0406, - "Nokia", - "Nokia 208", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_MAX_SECTORS_64 ), - #ifdef NO_SDDR09 UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index ff296434d601..a4513dd931b2 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -52,13 +52,6 @@ UNUSUAL_DEV(0x059f, 0x1061, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_OPCODES | US_FL_NO_SAME), -/* Reported-by: Zhihong Zhou */ -UNUSUAL_DEV(0x0781, 0x55e8, 0x0000, 0x9999, - "SanDisk", - "", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_UAS), - /* Reported-by: Hongling Zeng */ UNUSUAL_DEV(0x090c, 0x2000, 0x0000, 0x9999, "Hiksemi", @@ -90,13 +83,6 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_LUNS), -/* Reported-by: Oliver Neukum */ -UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, - "ADATA", - "Portable HDD CH94", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_NO_ATA_1X), - /* Reported-by: Benjamin Tissoires */ UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, "Initio Corporation", diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index 76ab5eb6d7f2..b56a0880a044 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -217,11 +217,6 @@ static int rt1711h_probe(struct i2c_client *client, { int ret; struct rt1711h_chip *chip; - const u16 alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | - TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST | - TCPC_ALERT_RX_STATUS | TCPC_ALERT_POWER_STATUS | - TCPC_ALERT_CC_STATUS | TCPC_ALERT_RX_BUF_OVF | - TCPC_ALERT_FAULT; ret = rt1711h_check_revision(client); if (ret < 0) { @@ -263,12 +258,6 @@ static int rt1711h_probe(struct i2c_client *client, dev_name(chip->dev), chip); if (ret < 0) return ret; - - /* Enable alert interrupts */ - ret = rt1711h_write16(chip, TCPC_ALERT_MASK, alert_mask); - if (ret < 0) - return ret; - enable_irq_wake(client->irq); return 0; diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index ae2d03c3ec1e..446d09d89860 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -3009,7 +3009,7 @@ static void run_state_machine(struct tcpm_port *port) port->caps_count = 0; port->pd_capable = true; tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT, - PD_T_SENDER_RESPONSE); + PD_T_SEND_SOURCE_CAP); } break; case SRC_SEND_CAPABILITIES_TIMEOUT: @@ -3761,7 +3761,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, case SNK_TRY_WAIT_DEBOUNCE: if (!tcpm_port_is_sink(port)) { port->max_wait = 0; - tcpm_set_state(port, SRC_TRYWAIT, PD_T_PD_DEBOUNCE); + tcpm_set_state(port, SRC_TRYWAIT, 0); } break; case SRC_TRY_WAIT: diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index 79692b13a873..f67c5a304155 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -272,8 +272,6 @@ void ucsi_displayport_remove_partner(struct typec_altmode *alt) if (!dp) return; - cancel_work_sync(&dp->work); - dp->data.conf = 0; dp->data.status = 0; dp->initialized = false; diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index fa2860a1bcf7..6da0ce066785 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -25,7 +25,7 @@ * difficult to estimate the time it takes for the system to process the command * before it is actually passed to the PPM. */ -#define UCSI_TIMEOUT_MS 10000 +#define UCSI_TIMEOUT_MS 5000 /* * UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests diff --git a/include/linux/hid.h b/include/linux/hid.h index ec0efababc79..115224aefa94 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -671,9 +671,8 @@ struct hid_descriptor { __le16 bcdHID; __u8 bCountryCode; __u8 bNumDescriptors; - struct hid_class_descriptor rpt_desc; - struct hid_class_descriptor opt_descs[]; + struct hid_class_descriptor desc[1]; } __attribute__ ((packed)); #define HID_DEVICE(b, g, ven, prod) \ diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 14b4c6c2e8dc..1bb58485b2e2 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -528,7 +528,6 @@ extern void __init hrtimers_init(void); extern void sysrq_timer_list_show(void); int hrtimers_prepare_cpu(unsigned int cpu); -int hrtimers_cpu_starting(unsigned int cpu); #ifdef CONFIG_HOTPLUG_CPU int hrtimers_dead_cpu(unsigned int cpu); #else diff --git a/include/linux/usb.h b/include/linux/usb.h index 32d43a9ab817..484608d419f5 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -713,12 +713,13 @@ struct usb_device { unsigned long active_duration; +#ifdef CONFIG_PM unsigned long connect_time; unsigned do_remote_wakeup:1; unsigned reset_resume:1; unsigned port_is_suspended:1; - +#endif struct wusb_dev *wusb_dev; int slot_id; enum usb_device_removable removable; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 91e9db289303..ca8ec43770a9 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -498,7 +498,9 @@ extern void usb_hcd_pci_shutdown(struct pci_dev *dev); extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); +#ifdef CONFIG_PM extern const struct dev_pm_ops usb_hcd_pci_pm_ops; +#endif #endif /* CONFIG_USB_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index f2296351f294..d03a8e81deb9 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -2066,15 +2066,6 @@ int hrtimers_prepare_cpu(unsigned int cpu) } cpu_base->cpu = cpu; - hrtimer_cpu_base_init_expiry_lock(cpu_base); - return 0; -} - -int hrtimers_cpu_starting(unsigned int cpu) -{ - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - - /* Clear out any left over state from a CPU down operation */ cpu_base->active_bases = 0; cpu_base->hres_active = 0; cpu_base->hang_detected = 0; @@ -2082,6 +2073,7 @@ int hrtimers_cpu_starting(unsigned int cpu) cpu_base->softirq_next_timer = NULL; cpu_base->expires_next = KTIME_MAX; cpu_base->softirq_expires_next = KTIME_MAX; + hrtimer_cpu_base_init_expiry_lock(cpu_base); return 0; } @@ -2167,7 +2159,6 @@ int hrtimers_dead_cpu(unsigned int scpu) void __init hrtimers_init(void) { hrtimers_prepare_cpu(smp_processor_id()); - hrtimers_cpu_starting(smp_processor_id()); open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq); } diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index c85fd32b70da..6a78afc6f13b 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -36,10 +36,6 @@ KBUILD_CFLAGS += $(call cc-option, -Wstringop-truncation) KBUILD_CFLAGS += -Wno-missing-field-initializers KBUILD_CFLAGS += -Wno-sign-compare -ifdef CONFIG_CC_IS_CLANG -KBUILD_CFLAGS += -Wno-enum-enum-conversion -endif - KBUILD_CPPFLAGS += -DKBUILD_EXTRA_WARN1 else @@ -55,7 +51,6 @@ KBUILD_CFLAGS += -Wno-format-zero-length KBUILD_CFLAGS += $(call cc-disable-warning, pointer-to-enum-cast) KBUILD_CFLAGS += $(call cc-disable-warning, unaligned-access) KBUILD_CFLAGS += $(call cc-disable-warning, cast-function-type-strict) -KBUILD_CFLAGS += -Wno-enum-compare-conditional endif endif From 40b465c13e9d2e2e0fa91637031535f321e81458 Mon Sep 17 00:00:00 2001 From: Akash Kumar Date: Wed, 10 Sep 2025 10:08:06 +0530 Subject: [PATCH 176/306] usb: gadget: uvc: Modify UVC_NUM_REQUESTS Modify UVC_NUM_REQUESTS to resolve uvc drop frame problem. Increase UVC_NUM_REQUESTS to 64 from 4 to prevent uvc drop frame problem caused by unavailability of free UVC buffers, ensuring smoother video playback. Change-Id: I0babb3eca4c62140205bd549ef7904b7e893e7bd Signed-off-by: Akash Kumar --- drivers/usb/gadget/function/uvc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 1473d25ff17a..9961d7d04546 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -65,7 +65,7 @@ extern unsigned int uvc_gadget_trace_param; * Driver specific constants */ -#define UVC_NUM_REQUESTS 4 +#define UVC_NUM_REQUESTS 64 #define UVC_MAX_REQUEST_SIZE 64 #define UVC_MAX_EVENTS 4 From 158551277b6a006d567e0f5a19dfa2d11cac6f46 Mon Sep 17 00:00:00 2001 From: Ruixuan Gu Date: Mon, 29 Sep 2025 14:43:35 +0800 Subject: [PATCH 177/306] netfilter: fix NATTYPE refresh timeout issue nattype timer is refreshed with wrong expires value Change-Id: I07473c0b21ac966c190b24b76bc93423680c2866 Signed-off-by: Ruixuan Gu --- net/ipv4/netfilter/ipt_NATTYPE.c | 15 +++++++++------ net/netfilter/nf_conntrack_core.c | 8 ++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/net/ipv4/netfilter/ipt_NATTYPE.c b/net/ipv4/netfilter/ipt_NATTYPE.c index fae7cad3f89f..484c0c111e4a 100644 --- a/net/ipv4/netfilter/ipt_NATTYPE.c +++ b/net/ipv4/netfilter/ipt_NATTYPE.c @@ -53,8 +53,8 @@ static void nattype_nte_debug_print(const struct ipt_nattype *nte, &nte->range.min_addr.ip, ntohs(nte->range.min_proto.all), ntohs(nte->nat_port), &nte->dest_addr, ntohs(nte->dest_port)); - DEBUGP("Timeout[%lx], Expires[%lx]\n", nte->timeout_value, - nte->timeout.expires); + DEBUGP("Timeout[%lx], Expires[%lx], Current[%lx]\n", nte->timeout_value, + nte->timeout.expires, jiffies); } /* netfilter NATTYPE nattype_free() @@ -80,8 +80,9 @@ bool nattype_refresh_timer_impl(unsigned long nat_type, spin_unlock_bh(&nattype_lock); return false; } + DEBUGP("%s: timeout_value=%lx, jiffies=%lx", __func__, timeout_value, jiffies); if (del_timer(&nte->timeout)) { - nte->timeout.expires = timeout_value; + nte->timeout.expires = timeout_value + jiffies - nfct_time_stamp; add_timer(&nte->timeout); spin_unlock_bh(&nattype_lock); nattype_nte_debug_print(nte, "refresh"); @@ -293,7 +294,7 @@ static unsigned int nattype_nat(struct sk_buff *skb, * found the entry. */ if (!nattype_refresh_timer((unsigned long)nte, - jiffies + nte->timeout_value)) + nfct_time_stamp + nte->timeout_value)) break; /* netfilter @@ -326,6 +327,7 @@ static unsigned int nattype_forward(struct sk_buff *skb, const struct ipt_nattype_info *info = par->targinfo; u16 nat_port; enum ip_conntrack_dir dir; + unsigned long timeout_value; if (xt_hooknum(par) != NF_INET_POST_ROUTING) return XT_CONTINUE; @@ -358,7 +360,7 @@ static unsigned int nattype_forward(struct sk_buff *skb, * found the entry. */ if (!nattype_refresh_timer((unsigned long)nte, - ct->timeout)) + ct->timeout)) break; /* netfilter NATTYPE @@ -431,7 +433,8 @@ static unsigned int nattype_forward(struct sk_buff *skb, * entry as this one is timed out and will be removed * from the list shortly. */ - if (!nattype_refresh_timer((unsigned long)nte2, jiffies + nte2->timeout_value)) + timeout_value = nfct_time_stamp + nte2->timeout_value; + if (!nattype_refresh_timer((unsigned long)nte2, timeout_value)) break; /* netfilter NATTYPE diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index e999b6d8da11..effa09102d3c 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1853,8 +1853,12 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, /* Refresh the NAT type entry. */ #if defined(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) nattype_ref_timer = rcu_dereference(nattype_refresh_timer); - if (nattype_ref_timer) - nattype_ref_timer(ct->nattype_entry, ct->timeout); + if (nattype_ref_timer) { + if (nf_ct_is_confirmed(ct)) + nattype_ref_timer(ct->nattype_entry, ct->timeout); + else + nattype_ref_timer(ct->nattype_entry, extra_jiffies + nfct_time_stamp); + } #endif acct: From 537b2272231efe4e739220bf4333eacc2bcf6ad6 Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Wed, 10 Sep 2025 14:52:27 +0530 Subject: [PATCH 178/306] UPSTREAM: usb: dwc3: Wait for EndXfer command completion DWC3 programming guide mentions that when operating in USB2.0 speeds, if GUSB2PHYCFG[6] or GUSB2PHYCFG[8] is set, it must be cleared prior to issuing commands and may be set again after the command completes. But currently while issuing EndXfer command without CmdIOC set, we wait for 1ms after GUSB2PHYCFG is restored. This results in cases where EndXfer command doesn't get completed and causes SMMU faults since requests are unmapped afterwards. Hence restore GUSB2PHYCFG after waiting for EndXfer command completion. Cc: stable@vger.kernel.org Fixes: 1d26ba0944d3 ("usb: dwc3: Wait unconditionally after issuing EndXfer command") Acked-by: Thinh Nguyen Link: https://lore.kernel.org/r/20240924093208.2524531-1-quic_prashk@quicinc.com Signed-off-by: Prashanth K Signed-off-by: Greg Kroah-Hartman Git-commit: c96e31252110a84dcc44412e8a7b456b33c3e298 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git. Change-Id: I4015b2190d984ffa10e89348cd375ab355e28531 Signed-off-by: Prashanth K Signed-off-by: Akash Kumar --- drivers/usb/dwc3/gadget.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2a92adf569c8..ff1072ce09ac 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -491,6 +491,10 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, dwc3_gadget_ep_get_transfer_index(dep); } + if (DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER && + !(cmd & DWC3_DEPCMD_CMDIOC)) + mdelay(1); + if (saved_config) { reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); reg |= saved_config; @@ -3705,9 +3709,6 @@ int dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt) else dep->flags |= DWC3_EP_END_TRANSFER_PENDING; - if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) - udelay(100); - return ret; } EXPORT_SYMBOL(dwc3_stop_active_transfer); From 43caee68715247ac5a44c967381a12a94f64d1d3 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Thu, 18 Sep 2025 18:25:47 +0530 Subject: [PATCH 179/306] mtd: msm_qpic_nand: check for page_erased bit along with op_err Due to a hardware bug in ECC-Engine, ECC-Engine couldn't able to set OP_ERR bit in flash_status regesiter whenever an erased page encounters bitflips. Due to this, ECC-Engine is trying to correct the bitflips on an erased page and leading to data corruption. So, a check for PAGE_ERASED bit is added prior to OP_ERR bit for an erased page detection logic. Change-Id: I570625123fe828450dade06570f782ebe93d39f1 Signed-off-by: Pradeep P V K Signed-off-by: Pradeep P V K Signed-off-by: Ram Kumar Dwivedi --- drivers/mtd/devices/msm_qpic_nand.c | 64 ++++++++++++++++++++++++++--- drivers/mtd/devices/msm_qpic_nand.h | 6 ++- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index 329e7ebbd191..0b7a478bb612 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2007 Google, Inc. * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_qpic_nand.h" @@ -1944,7 +1944,7 @@ free_dma: if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > 4) { + if (num_zero_bits > MAX_ECC_BIT_FLIPS) { *erased_page = false; goto free_mem; } @@ -1956,7 +1956,7 @@ free_dma: ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= 4)) + if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) *erased_page = true; free_mem: kfree(ecc); @@ -2163,6 +2163,33 @@ static int msm_nand_read_pagescope(struct mtd_info *mtd, loff_t from, goto free_dma; /* Check for flash status errors */ pageerr = rawerr = 0; + + /* + * PAGE_ERASED bit will set only if all + * CODEWORD_ERASED bit of all codewords + * of the page is set. + * + * PAGE_ERASED bit is a 'logical and' of all + * CODEWORD_ERASED bit of all codewords i.e. + * even if one codeword is detected as not + * an erased codeword, PAGE_ERASED bit will unset. + */ + for (n = rw_params.start_sector; n < cwperpage; n++) { + if ((dma_buffer->result[n].erased_cw_status & + (1 << PAGE_ERASED)) && + (dma_buffer->result[n].buffer_status & + NUM_ERRORS)) { + err = msm_nand_is_erased_page_ps(mtd, + from, ops, + &rw_params, + &erased_page); + if (err) + goto free_dma; + if (erased_page) + rawerr = -EIO; + break; + } + } for (n = rw_params.start_sector; n < cwperpage; n++) { if (dma_buffer->result[n].flash_status & (FS_OP_ERR | FS_MPU_ERR)) { @@ -2554,7 +2581,7 @@ free_dma: if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > 4) { + if (num_zero_bits > MAX_ECC_BIT_FLIPS) { *erased_page = false; goto free_mem; } @@ -2566,7 +2593,7 @@ free_dma: ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= 4)) + if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) *erased_page = true; free_mem: kfree(ecc); @@ -2760,6 +2787,33 @@ static int msm_nand_read_oob(struct mtd_info *mtd, loff_t from, goto free_dma; /* Check for flash status errors */ pageerr = rawerr = 0; + + /* + * PAGE_ERASED bit will set only if all + * CODEWORD_ERASED bit of all codewords + * of the page is set. + * + * PAGE_ERASED bit is a 'logical and' of all + * CODEWORD_ERASED bit of all codewords i.e. + * even if one codeword is detected as not + * an erased codeword, PAGE_ERASED bit will unset. + */ + for (n = rw_params.start_sector; n < cwperpage; n++) { + if ((dma_buffer->result[n].erased_cw_status & + (1 << PAGE_ERASED)) && + (dma_buffer->result[n].buffer_status & + NUM_ERRORS)) { + err = msm_nand_is_erased_page(mtd, + from, ops, + &rw_params, + &erased_page); + if (err) + goto free_dma; + if (erased_page) + rawerr = -EIO; + break; + } + } for (n = rw_params.start_sector; n < cwperpage; n++) { if (dma_buffer->result[n].flash_status & (FS_OP_ERR | FS_MPU_ERR)) { diff --git a/drivers/mtd/devices/msm_qpic_nand.h b/drivers/mtd/devices/msm_qpic_nand.h index cc1df16f5b3d..0297ad9697c4 100644 --- a/drivers/mtd/devices/msm_qpic_nand.h +++ b/drivers/mtd/devices/msm_qpic_nand.h @@ -154,7 +154,10 @@ #define RESET_ERASED_DET (1 << AUTO_DETECT_RES) #define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES) #define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC) -#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC) +#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC | SET_N_MAX_ZEROS) +#define N_MAX_ZEROS 2 +#define MAX_ECC_BIT_FLIPS 4 +#define SET_N_MAX_ZEROS (MAX_ECC_BIT_FLIPS << N_MAX_ZEROS) #define MSM_NAND_ERASED_CW_DETECT_STATUS(info) MSM_NAND_REG(info, 0x300EC) #define PAGE_ALL_ERASED 7 @@ -163,6 +166,7 @@ #define CODEWORD_ERASED 4 #define ERASED_PAGE ((1 << PAGE_ALL_ERASED) | (1 << PAGE_ERASED)) #define ERASED_CW ((1 << CODEWORD_ALL_ERASED) | (1 << CODEWORD_ERASED)) +#define NUM_ERRORS 0x1f #define MSM_NAND_CTRL(info) MSM_NAND_REG(info, 0x30F00) #define BAM_MODE_EN 0 From 96f3098bef83a0a81d5abca00df27cc043073fa6 Mon Sep 17 00:00:00 2001 From: Pradeep P V K Date: Fri, 5 Jun 2020 18:38:21 +0530 Subject: [PATCH 180/306] mtd: msm_qpic_nand: Use flash device ECC capability for erase page Page codeword's ECC data is used to determine if the page is actually erased or not. On an erased page, this data is all 0xFF. The acceptable bitflips on this ECC data is flash device dependent. So, always check against flash device ECC capability value for erase page determination. Change-Id: Ib3889f91c871b5f131fe8bc960ffa68ac11e0633 Signed-off-by: Pradeep P V K Signed-off-by: Pradeep P V K Signed-off-by: Ram Kumar Dwivedi --- drivers/mtd/devices/msm_qpic_nand.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/devices/msm_qpic_nand.c b/drivers/mtd/devices/msm_qpic_nand.c index 0b7a478bb612..eb45e4908968 100644 --- a/drivers/mtd/devices/msm_qpic_nand.c +++ b/drivers/mtd/devices/msm_qpic_nand.c @@ -1944,7 +1944,7 @@ free_dma: if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > MAX_ECC_BIT_FLIPS) { + if (num_zero_bits > info->flash_dev.ecc_capability) { *erased_page = false; goto free_mem; } @@ -1955,8 +1955,8 @@ free_dma: num_zero_bits = last_pos = next_pos = 0; ecc_temp += chip->ecc_parity_bytes; } - - if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) + if ((n == cwperpage) && + (num_zero_bits <= info->flash_dev.ecc_capability)) *erased_page = true; free_mem: kfree(ecc); @@ -2581,7 +2581,7 @@ free_dma: if (last_pos < ecc_bytes_percw_in_bits) num_zero_bits++; - if (num_zero_bits > MAX_ECC_BIT_FLIPS) { + if (num_zero_bits > info->flash_dev.ecc_capability) { *erased_page = false; goto free_mem; } @@ -2593,7 +2593,8 @@ free_dma: ecc_temp += chip->ecc_parity_bytes; } - if ((n == cwperpage) && (num_zero_bits <= MAX_ECC_BIT_FLIPS)) + if ((n == cwperpage) && + (num_zero_bits <= info->flash_dev.ecc_capability)) *erased_page = true; free_mem: kfree(ecc); From 0308b8b14b58779a0ad4f1b12e6fea36200d0944 Mon Sep 17 00:00:00 2001 From: Akash Kumar Date: Mon, 13 Oct 2025 15:54:38 +0530 Subject: [PATCH 181/306] usb: gadget: uvc: Add grey and I420 YUV UVC format support uvc_formats[] needs to be updated with bitsperpixel,fcc tuple so that these formats can be passed by user space to S_FMT ioctl. user space must use streaming/uncompressed/u/guidFormat to specify the guid. user space must use streaming/uncompressed/u/bBitsPerPixel to set the bitsperpixel. In this case they are 8 and 12 respectively for grey and yuv420. GUID for these formats taken from drivers/media/usb/uvc/uvc_driver.c V4L2_PIX_FMT_GREY: { 'Y', '8', ' ', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} (bitsperpixel) : 8 V4L2_PIX_FMT_YUV420: { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} (bitsperpixel) : 12 Change-Id: I6c164e4d77d4af03223f16a088ee743fbf0878b9 Signed-off-by: Akash Kumar --- drivers/usb/gadget/function/uvc_v4l2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 495f0ec663ea..93d0d0d2f75f 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -58,6 +58,8 @@ struct uvc_format { static struct uvc_format uvc_formats[] = { { 16, V4L2_PIX_FMT_YUYV }, { 0, V4L2_PIX_FMT_MJPEG }, + { 12, V4L2_PIX_FMT_YUV420 }, + { 8, V4L2_PIX_FMT_GREY }, }; static int From bf2e9f51c58f437dcfed7a607dd7e89280d09c57 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Thu, 5 Jun 2025 18:01:42 +0530 Subject: [PATCH 182/306] asoc: lsm: thread safety issue while accessing substream data Added mutex protection while accessing substream data to avoid potential race conditions when accessing this resource from multiple threads. Change-Id: I92e368a73ec2c683c7fcbb4579a19214cc60d1d2 --- asoc/msm-lsm-client.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index bd9b73571263..b18a558848d2 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -42,6 +42,11 @@ #define LSM_IS_LAST_STAGE(client, stage_idx) \ (client->num_stages == (stage_idx + 1)) +struct lsm_char_dev { + /* Protects access to LSM client sessions and shared resources */ + struct mutex lock; +}; + static struct snd_pcm_hardware msm_pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -3106,9 +3111,11 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) { unsigned long flags; struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd; struct msm_pcm_stream_app_type_cfg cfg_data = {0}; + struct lsm_char_dev *lsm_dev; + struct snd_soc_component *component = NULL; int ret = 0; int be_id = 0; int fe_id = 0; @@ -3117,12 +3124,29 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) pr_err("%s: Invalid private_data", __func__); return -EINVAL; } - if (!prtd || !prtd->lsm_client) { - pr_err("%s: No LSM session active\n", __func__); + if (!component || !component->dev) { + pr_err("%s: Invalid component\n", __func__); return -EINVAL; } rtd = substream->private_data; + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } dev_dbg(rtd->dev, "%s\n", __func__); if (prtd->lsm_client->started) { if (prtd->lsm_client->lab_enable) { @@ -3232,6 +3256,7 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) mutex_destroy(&prtd->lsm_api_lock); kfree(prtd); runtime->private_data = NULL; + mutex_unlock(&lsm_dev->lock); return 0; } @@ -3629,6 +3654,14 @@ static struct snd_soc_component_driver msm_soc_component = { static int msm_lsm_probe(struct platform_device *pdev) { + struct lsm_char_dev *lsm_dev; + + lsm_dev = devm_kzalloc(&pdev->dev, sizeof(*lsm_dev), GFP_KERNEL); + if (!lsm_dev) + return -ENOMEM; + + mutex_init(&lsm_dev->lock); + dev_set_drvdata(&pdev->dev, lsm_dev); return snd_soc_register_component(&pdev->dev, &msm_soc_component, NULL, 0); @@ -3636,6 +3669,10 @@ static int msm_lsm_probe(struct platform_device *pdev) static int msm_lsm_remove(struct platform_device *pdev) { + struct lsm_char_dev *lsm_dev; + lsm_dev = dev_get_drvdata(&pdev->dev); + mutex_destroy(&lsm_dev->lock); + snd_soc_unregister_component(&pdev->dev); return 0; From 5fceb1d45f380d709de958a5c45c167708e027b3 Mon Sep 17 00:00:00 2001 From: Akshaya Chirikonda Date: Fri, 13 Jun 2025 12:54:00 +0530 Subject: [PATCH 183/306] asoc: lsm: Race condition protection in confidence levels handling Added mutex protection around freeing confidence_levels to prevent potential race conditions when accessing this memory. Change-Id: I38ec13791a0e99f3ea5f3b2aaf983a1860e7aeeb --- asoc/msm-lsm-client.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index b18a558848d2..85566e51dd76 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include @@ -688,15 +688,47 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, struct lsm_params_info_v2 *p_info) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd = substream->private_data; int rc = 0; + struct lsm_char_dev *lsm_dev; + struct snd_soc_component *component = NULL; + + if (!rtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -EINVAL; + } + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } if (p_info->param_type == LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS) { if (p_info->param_size > MAX_KEYWORDS_SUPPORTED) { dev_err(rtd->dev, "%s: invalid number of snd_model keywords %d, the max is %d\n", __func__, p_info->param_size, MAX_KEYWORDS_SUPPORTED); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -707,6 +739,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: get_conf_levels failed for snd_model %d, err = %d\n", __func__, p_info->model_id, rc); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -727,6 +760,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: invalid confidence levels %d\n", __func__, p_info->param_size); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -738,6 +772,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: get_conf_levels failed, err = %d\n", __func__, rc); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -754,6 +789,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, prtd->lsm_client->confidence_levels = NULL; } } + mutex_unlock(&lsm_dev->lock); return rc; } From 86664f1bbf83f1dc16f77cd8ffab6ce3a3eb35bd Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Fri, 13 Jun 2025 12:59:44 +0530 Subject: [PATCH 184/306] asoc: lsm: thread safety issue in hw params management Added mutex protection while accessing lsm client hw params to avoid potential race conditions when accessing this resource from multiple threads. Change-Id: Ib2cbb954cb145a7a194e8af753cdaf434835b245 --- asoc/msm-lsm-client.c | 67 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index 85566e51dd76..7d69b97ca7c6 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1030,23 +1030,63 @@ static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substrea u32 enable, struct lsm_params_info_v2 *p_info) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct lsm_hw_params *out_hw_params = &prtd->lsm_client->out_hw_params; + struct lsm_hw_params *out_hw_params = NULL; + struct snd_soc_component *component = NULL; + struct lsm_char_dev *lsm_dev = NULL; u8 *chmap = NULL; u32 ch_idx; int rc = 0, stage_idx = p_info->stage_idx; + if (!rtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -EINVAL; + } + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + out_hw_params = &prtd->lsm_client->out_hw_params; + if (!out_hw_params) { + pr_err("%s: Invalid hw params\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + if (prtd->lsm_client->stage_cfg[stage_idx].lab_enable == enable) { dev_dbg(rtd->dev, "%s: Lab for session %d, stage %d already %s\n", __func__, prtd->lsm_client->session, stage_idx, enable ? "enabled" : "disabled"); + mutex_unlock(&lsm_dev->lock); return rc; } chmap = kzalloc(out_hw_params->num_chs, GFP_KERNEL); - if (!chmap) + if (!chmap) { + mutex_unlock(&lsm_dev->lock); return -ENOMEM; + } rc = q6lsm_lab_control(prtd->lsm_client, enable, p_info); if (rc) { @@ -1087,6 +1127,7 @@ static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substrea fail: kfree(chmap); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -3301,21 +3342,36 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct lsm_hw_params *out_hw_params = NULL; struct lsm_hw_params *in_hw_params = NULL; struct snd_soc_pcm_runtime *rtd; + struct lsm_char_dev *lsm_dev = NULL; + struct snd_soc_component *component = NULL; if (!substream->private_data) { pr_err("%s: Invalid private_data", __func__); return -EINVAL; } rtd = substream->private_data; + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: Invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&lsm_dev->lock); + prtd = runtime->private_data; if (!prtd || !params) { dev_err(rtd->dev, "%s: invalid params prtd %pK params %pK", __func__, prtd, params); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } in_hw_params = &prtd->lsm_client->in_hw_params; @@ -3330,6 +3386,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, "%s: Invalid Params sample rate %d period count %d\n", __func__, out_hw_params->sample_rate, out_hw_params->period_count); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -3340,6 +3397,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, } else { dev_err(rtd->dev, "%s: Invalid Format 0x%x\n", __func__, params_format(params)); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -3360,6 +3418,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, */ memcpy(in_hw_params, out_hw_params, sizeof(struct lsm_hw_params)); + mutex_unlock(&lsm_dev->lock); return 0; } From 47c8aa7cad489faf1bdb65fe878a31384a0d017a Mon Sep 17 00:00:00 2001 From: amaindol Date: Tue, 22 Jul 2025 15:51:46 +0530 Subject: [PATCH 185/306] qcacmn: Validate vdev count before pdev CSA switch count update The num of vdevs parameter of the pdev csa switch count TLV is a tainted value and is not checked before use. Invalid values can cause a slab out of bound error, which results in a crash. Add a check for the num of vdevs while extracting pdev csa switch count TLV. Compare the number of vdevs with the num of vdev ids parameter of the csa switch count firmware event. Drop the event if the check fails. CRs-Fixed: 4217096 Change-Id: I88401984437186a1a6e077c274d0011fa93e8704 --- wmi/src/wmi_unified_tlv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 269c45b65a74..b9359e099ce6 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -14729,6 +14729,12 @@ static QDF_STATUS extract_pdev_csa_switch_count_status_tlv( wmi_handle, csa_status->pdev_id); param->current_switch_count = csa_status->current_switch_count; + + if (param_buf->num_vdev_ids != csa_status->num_vdevs) { + wmi_err("Invalid number of vdevs: received = %d, expected = %d", + csa_status->num_vdevs, param_buf->num_vdev_ids); + return QDF_STATUS_E_INVAL; + } param->num_vdevs = csa_status->num_vdevs; param->vdev_ids = param_buf->vdev_ids; From c8edf34ac9cfb69a3e4ee9be4e4d12ce57a20a93 Mon Sep 17 00:00:00 2001 From: Sivakanth Vaka Date: Mon, 4 Mar 2024 16:59:59 +0530 Subject: [PATCH 186/306] ipa: Added changes to move the hdr entry to free list Added changes to move the hdr free offset list after deteting the hdrs from the hdr table if delted hdr is pointing to the some proc ctx. Signed-off-by: Sivakanth Vaka Signed-off-by: Avinash Kumar Change-Id: Ic1f20fc8070ae7a45c2d7a5abd5b9c56a96c49cf --- drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index a3f090def566..28285a6eed57 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -710,7 +710,10 @@ static int __ipa3_del_hdr_proc_ctx(u32 proc_ctx_hdl, return 0; } - if (release_hdr) + if (entry->hdr && entry == entry->hdr->proc_ctx) + entry->hdr->proc_ctx = NULL; + + if (entry->hdr && release_hdr) __ipa3_del_hdr(entry->hdr->id, false); /* move the offset entry to appropriate free list */ @@ -774,17 +777,19 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user) return 0; } + if (entry->proc_ctx && entry == entry->proc_ctx->hdr) + entry->proc_ctx->hdr = NULL; + if (entry->is_hdr_proc_ctx || entry->proc_ctx) { dma_unmap_single(ipa3_ctx->pdev, entry->phys_base, entry->hdr_len, DMA_TO_DEVICE); __ipa3_del_hdr_proc_ctx(entry->proc_ctx->id, false, false); - } else { - /* move the offset entry to appropriate free list */ - list_move(&entry->offset_entry->link, - &htbl->head_free_offset_list[entry->offset_entry->bin]); } + /* move the offset entry to appropriate free list */ + list_move(&entry->offset_entry->link, + &htbl->head_free_offset_list[entry->offset_entry->bin]); list_del(&entry->link); htbl->hdr_cnt--; entry->cookie = 0; From e5fdc7822ba1274a16742d727e47b14d8c56d835 Mon Sep 17 00:00:00 2001 From: Vishnu Saini Date: Thu, 16 Oct 2025 11:56:23 +0530 Subject: [PATCH 187/306] disp: msm: sde: fix splash resource cleanup for edp Currently, splash_display->encoder is invalid for edp so _sde_kms_release_splash_resource is not releasing the resources. ea245e79821 ("disp: msm: sde: Remove pm vote at time of handoff") partially addressing the issue, but _sde_kms_free_splash_display_data is not called, resulting in smmu mapping not freed. Since iommu framework is not aware of this direct mapping through smmu so any allocations to this iova will fail due to this existing mapping, resulting in mapping and commit failures. Populate splash_display for edp so that cleanup of splash region is proper and revert ea245e79821, which is no longer needed. Change-Id: I5bd2b0d5996f0f91e4b0cf1e4f78e03feee4afe4 Signed-off-by: Vishnu Saini --- msm/sde/sde_kms.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 7dfad7d8d194..5dd01e54989d 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -1255,16 +1255,6 @@ static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms, SDE_EVT32(DRMID(crtc), crtc->state->active, sde_kms->splash_data.num_splash_displays); - /*remove all votes if eDP displays are done with splash*/ - if (dp_display_get_num_of_boot_displays()) { - for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) - sde_power_data_bus_set_quota(phandle, i, - SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, - phandle->ib_quota[i]); - pm_runtime_put_sync(sde_kms->dev->dev); - sde_kms->splash_data.num_splash_displays--; - } - for (i = 0; i < MAX_DSI_DISPLAYS; i++) { splash_display = &sde_kms->splash_data.splash_display[i]; if (splash_display->encoder && @@ -3385,7 +3375,7 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms, struct msm_display_info info; struct drm_encoder *encoder = NULL; struct drm_crtc *crtc = NULL; - int i, rc = 0; + int i, rc = 0, splash_index = 0; struct drm_display_mode *drm_mode = NULL; struct drm_device *dev; struct msm_drm_private *priv; @@ -3423,7 +3413,7 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms, DRM_INFO("cont_splash enabled in %d of %d display(s)\n", sde_kms->splash_data.num_splash_displays, - sde_kms->dsi_display_count); + sde_kms->dsi_display_count + sde_kms->dp_display_count); /* dsi */ for (i = 0; i < sde_kms->dsi_display_count; ++i) { @@ -3559,6 +3549,19 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms, break; } + splash_display = &sde_kms->splash_data.splash_display[splash_index]; + if (splash_display->cont_splash_enabled) { + priv = sde_kms->dev->dev_private; + encoder->crtc = priv->crtcs[splash_index]; + splash_display->encoder = encoder; + + SDE_DEBUG("dp-display:%d splash_index:%d crtc id[%d]:%d enc id[%d]:%d\n", + i, splash_index, encoder->crtc->index, encoder->crtc->base.id, + encoder->index, encoder->base.id); + + splash_index++; + } + mutex_lock(&dev->mode_config.mutex); drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { From 40c990ed3d9987d281009a1256c5664614ec1138 Mon Sep 17 00:00:00 2001 From: Surya Prakash Sivaraj Date: Fri, 16 May 2025 12:51:50 +0530 Subject: [PATCH 188/306] qcacld-3.0: Populate MBSSID cap in Ext CAP IE The MBSSID cap in the extended capability IE is populated properly in the Probe and Assoc request of the initial connection. But, this cap is missing in the reassoc request during roaming. Host driver fills this cap based on the service cap of MBSSID support only during the probe/assoc req generation. This cap is not passed to the firmware via SET IE or via assoc IEs in the RSO START. Since the service cap would not change in runtime, override the MBSSID cap in the assoc IEs received from the userspace itself. This sets the cap in both SET IE as well as RSO START. Change-Id: I69476e503a369df6533de9c215efc4c39d9e251c CRs-Fixed: 4117861 --- core/mac/src/pe/lim/lim_process_sme_req_messages.c | 3 +++ core/sme/src/csr/csr_api_roam.c | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index 0ac96d900386..0f57abe3c224 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -6520,6 +6520,9 @@ static void lim_process_set_ie_req(struct mac_context *mac_ctx, uint32_t *msg_bu if (p_ext_cap->interworking_service) p_ext_cap->qos_map = 1; + if (wma_is_mbssid_enabled()) + p_ext_cap->multi_bssid = 1; + extra_ext_cap.num_bytes = lim_compute_ext_cap_ie_length(&extra_ext_cap); send_ie: diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index c67bbe35827c..4484ed3c5ce8 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -17422,6 +17422,8 @@ static void csr_cm_update_driver_assoc_ies( MIN_TX_PWR_CAP, MAX_TX_PWR_CAP}; uint8_t max_tx_pwr_cap = 0; uint8_t supp_chan_ie[DOT11F_IE_SUPPCHANNELS_MAX_LEN], supp_chan_ie_len; + struct s_ext_cap *extcap; + uint8_t *ext_cap_ie; static const uint8_t qcn_ie[] = {0x8C, 0xFD, 0xF0, 0x1, QCN_IE_VERSION_SUBATTR_ID, QCN_IE_VERSION_SUBATTR_DATA_LEN, @@ -17433,6 +17435,14 @@ static void csr_cm_update_driver_assoc_ies( qdf_mem_copy(rso_mode_cfg->assoc_ie, session->pAddIEAssoc, rso_mode_cfg->assoc_ie_length); + ext_cap_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_XCAPS, + rso_mode_cfg->assoc_ie, + rso_mode_cfg->assoc_ie_length); + if (ext_cap_ie && wma_is_mbssid_enabled()) { + extcap = (struct s_ext_cap *)&ext_cap_ie[2]; + extcap->multi_bssid = 1; + } + if (session->pConnectBssDesc) max_tx_pwr_cap = csr_get_cfg_max_tx_power( mac_ctx, From c5a324ce0b79d0f5c6770c902852693ff72ab3b8 Mon Sep 17 00:00:00 2001 From: Kaushik Yalla Date: Thu, 9 Oct 2025 02:28:35 -0700 Subject: [PATCH 189/306] kgsl: Add buffer overflow check for perfcounter dynamic list Add buffer overflow check to ensure dynamic list updates do not exceed allocated buffer size, returning an error if overflow would occur. Change-Id: I5ef8ff91fda3879250cb848761fa01674fc59cf7 Signed-off-by: Shiv Kumar Signed-off-by: Kaushik Yalla Signed-off-by: Chandra Vamsi Yekkaluri --- drivers/gpu/msm/adreno_a6xx.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 048e33de599c..93bebbdb24fc 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -2523,6 +2524,7 @@ int a6xx_perfcounter_update(struct adreno_device *adreno_dev, struct cpu_gpu_lock *lock = ptr; u32 *data = ptr + sizeof(*lock); int i, offset = 0; + u32 pending_pairs = 2; /* No of pairs to add: and */ if (cpu_gpu_lock(lock)) { cpu_gpu_unlock(lock); @@ -2546,6 +2548,13 @@ int a6xx_perfcounter_update(struct adreno_device *adreno_dev, offset += 2; } + /* Ensure there is enough space in the reglist buffer for new pairs */ + if ((offset + (pending_pairs * 2)) >= + (adreno_dev->pwrup_reglist->size / sizeof(u32))) { + cpu_gpu_unlock(lock); + return -ENOSPC; + } + /* * For all targets A6XX_RBBM_PERFCTR_CNTL needs to be the last entry, * so overwrite the existing A6XX_RBBM_PERFCNTL_CTRL and add it back to From 5cef717354325b214141c9c5b4a0f88d90589cf4 Mon Sep 17 00:00:00 2001 From: Akash Kumar Date: Thu, 30 Oct 2025 16:07:18 +0530 Subject: [PATCH 190/306] UPSTREAM: usb: gadget: configfs: Add frame-based frame format support Add support for frame-based frame format, which can be used to support multiple formats like H264 or H265, in addition to MJPEG and YUV frames. The frame-based format is set to H264 by default, but it can be updated to other formats by modifying the GUID through the guid configfs attribute. Different structures are used for all three formats, as H264 has a different structure compared to MJPEG and uncompressed formats. These structures will be passed to the frame make function based on the active format, using a common frame structure with additional parameters needed only for frame-based formats. These parameters are handled at runtime in the UVC driver. Signed-off-by: Akash Kumar Link: https://lore.kernel.org/r/20240927152138.31416-1-quic_akakum@quicinc.com Signed-off-by: Greg Kroah-Hartman Git-commit: 7b5a58952fc3b51905c2963647485565df1e5e26 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git. Change-Id: Iffef14deba1f7e22c74b89b72a252f23802549d4 Signed-off-by: Akash Kumar --- .../ABI/testing/configfs-usb-gadget-uvc | 65 ++++ drivers/usb/gadget/function/f_uvc.c | 10 +- drivers/usb/gadget/function/uvc_configfs.c | 349 +++++++++++++++++- drivers/usb/gadget/function/uvc_v4l2.c | 1 + include/uapi/linux/usb/video.h | 58 +++ 5 files changed, 469 insertions(+), 14 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 809765bd9573..5d4180aaf18e 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -265,6 +265,71 @@ Description: Specific uncompressed frame descriptors bmCapabilities - still image support, fixed frame-rate support +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased +Date: Oct 2025 +KernelVersion: 5.4 +Description: Framebased format descriptors + +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name +Date: Oct 2025 +KernelVersion: 5.4 +Description: Specific framebased format descriptors + + ================== ======================================= + bFormatIndex unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only + bmaControls this format's data for bmaControls in + the streaming header + bmInterlaceFlags specifies interlace information, + read-only + bAspectRatioY the X dimension of the picture aspect + ratio, read-only + bAspectRatioX the Y dimension of the picture aspect + ratio, read-only + bDefaultFrameIndex optimum frame index for this stream + bBitsPerPixel number of bits per pixel used to + specify color in the decoded video + frame + guidFormat globally unique id used to identify + stream-encoding format + ================== ======================================= + +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name/name +Date: Sept 2024 +KernelVersion: 5.15 +Description: Specific framebased frame descriptors + + ========================= ===================================== + bFrameIndex unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only + dwFrameInterval indicates how frame interval can be + programmed; a number of values + separated by newline can be specified + dwDefaultFrameInterval the frame interval the device would + like to use as default + dwBytesPerLine Specifies the number of bytes per line + + of video for packed fixed frame size + formats, allowing the receiver to + perform stride alignment of the video. + If the bVariableSize value (above) is + TRUE (1), or if the format does not + permit such alignment, this value shall + be set to zero (0). + dwMaxBitRate the maximum bit rate at the shortest + frame interval in bps + dwMinBitRate the minimum bit rate at the longest + frame interval in bps + wHeight height of decoded bitmap frame in px + wWidth width of decoded bitmam frame in px + bmCapabilities still image support, fixed frame-rate + support + ========================= ===================================== + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header Date: Dec 2014 KernelVersion: 4.0 diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 094a88ff9a67..b4c08b4ed602 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -808,9 +808,9 @@ static struct usb_function_instance *uvc_alloc_inst(void) cd->wObjectiveFocalLengthMax = cpu_to_le16(0); cd->wOcularFocalLength = cpu_to_le16(0); cd->bControlSize = 3; - cd->bmControls[0] = 2; - cd->bmControls[1] = 0; - cd->bmControls[2] = 0; + cd->bmControls[0] = 62; + cd->bmControls[1] = 126; + cd->bmControls[2] = 10; pd = &opts->uvc_processing; pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2); @@ -820,8 +820,8 @@ static struct usb_function_instance *uvc_alloc_inst(void) pd->bSourceID = 1; pd->wMaxMultiplier = cpu_to_le16(16*1024); pd->bControlSize = 2; - pd->bmControls[0] = 1; - pd->bmControls[1] = 0; + pd->bmControls[0] = 91; + pd->bmControls[1] = 23; pd->iProcessing = 0; pd->bmVideoStandards = 0; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 00fb58e50a15..5480a2988fe4 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -762,16 +762,19 @@ static const struct uvcg_config_group_type uvcg_control_grp_type = { /* ----------------------------------------------------------------------------- * streaming/uncompressed * streaming/mjpeg + * streaming/framebased */ static const char * const uvcg_format_names[] = { "uncompressed", "mjpeg", + "framebased" }; enum uvcg_format_type { UVCG_UNCOMPRESSED = 0, UVCG_MJPEG, + UVCG_FRAMEBASED, }; struct uvcg_format { @@ -1080,6 +1083,7 @@ struct uvcg_frame { u32 dw_max_video_frame_buffer_size; u32 dw_default_frame_interval; u8 b_frame_interval_type; + u32 dw_bytes_perline; } __attribute__((packed)) frame; u32 *dw_frame_interval; }; @@ -1190,6 +1194,7 @@ UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32); UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32); UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32); UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32); +UVCG_FRAME_ATTR(dw_bytes_perline, dwBytesPerLine, 32); #undef UVCG_FRAME_ATTR @@ -1324,7 +1329,7 @@ end: UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); -static struct configfs_attribute *uvcg_frame_attrs[] = { +static struct configfs_attribute *uvcg_frame_attrs1[] = { &uvcg_frame_attr_b_frame_index, &uvcg_frame_attr_bm_capabilities, &uvcg_frame_attr_w_width, @@ -1337,12 +1342,32 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { NULL, }; -static const struct config_item_type uvcg_frame_type = { +static struct configfs_attribute *uvcg_frame_attrs2[] = { + &uvcg_frame_attr_b_frame_index, + &uvcg_frame_attr_bm_capabilities, + &uvcg_frame_attr_w_width, + &uvcg_frame_attr_w_height, + &uvcg_frame_attr_dw_min_bit_rate, + &uvcg_frame_attr_dw_max_bit_rate, + &uvcg_frame_attr_dw_max_video_frame_buffer_size, + &uvcg_frame_attr_dw_default_frame_interval, + &uvcg_frame_attr_dw_frame_interval, + &uvcg_frame_attr_dw_bytes_perline, + NULL, +}; + +static const struct config_item_type uvcg_frame_type1 = { .ct_item_ops = &uvcg_config_item_ops, - .ct_attrs = uvcg_frame_attrs, + .ct_attrs = uvcg_frame_attrs1, .ct_owner = THIS_MODULE, }; +static const struct config_item_type uvcg_frame_type2 = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_frame_attrs2, + .ct_owner = THIS_MODULE, +}; + static struct config_item *uvcg_frame_make(struct config_group *group, const char *name) { @@ -1363,6 +1388,7 @@ static struct config_item *uvcg_frame_make(struct config_group *group, h->frame.dw_max_bit_rate = 55296000; h->frame.dw_max_video_frame_buffer_size = 460800; h->frame.dw_default_frame_interval = 666666; + h->frame.dw_bytes_perline = 0; opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); @@ -1375,6 +1401,9 @@ static struct config_item *uvcg_frame_make(struct config_group *group, } else if (fmt->type == UVCG_MJPEG) { h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG; h->fmt_type = UVCG_MJPEG; + } else if (fmt->type == UVCG_FRAMEBASED) { + h->frame.b_descriptor_subtype = UVC_VS_FRAME_FRAME_BASED; + h->fmt_type = UVCG_FRAMEBASED; } else { mutex_unlock(&opts->lock); kfree(h); @@ -1383,7 +1412,10 @@ static struct config_item *uvcg_frame_make(struct config_group *group, ++fmt->num_frames; mutex_unlock(&opts->lock); - config_item_init_type_name(&h->item, name, &uvcg_frame_type); + if (fmt->type == UVCG_FRAMEBASED) + config_item_init_type_name(&h->item, name, &uvcg_frame_type2); + else + config_item_init_type_name(&h->item, name, &uvcg_frame_type1); return &h->item; } @@ -1413,9 +1445,6 @@ static void uvcg_format_set_indices(struct config_group *fmt) list_for_each_entry(ci, &fmt->cg_children, ci_entry) { struct uvcg_frame *frm; - if (ci->ci_type != &uvcg_frame_type) - continue; - frm = to_uvcg_frame(ci); frm->frame.b_frame_index = i++; } @@ -1856,6 +1885,260 @@ static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { .name = "mjpeg", }; +/* ----------------------------------------------------------------------------- + * streaming/framebased/ + */ + +struct uvcg_framebased { + struct uvcg_format fmt; + struct uvc_format_framebased desc; +}; + +static inline struct uvcg_framebased *to_uvcg_framebased(struct config_item *item) +{ + return container_of(to_uvcg_format(item), struct uvcg_framebased, fmt); +} + +static struct configfs_group_operations uvcg_framebased_group_ops = { + .make_item = uvcg_frame_make, + .drop_item = uvcg_frame_drop, +}; + +#define UVCG_FRAMEBASED_ATTR_RO(cname, aname, bits) \ + static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ + char *page) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int result; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; \ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + result = scnprintf(page, PAGE_SIZE, "%u\n", le##bits##_to_cpu(u->desc.aname));\ + mutex_unlock(&opts->lock); \ + \ + mutex_unlock(su_mutex); \ + return result; \ +} \ + \ +UVC_ATTR_RO(uvcg_framebased_, cname, aname) + +#define UVCG_FRAMEBASED_ATTR(cname, aname, bits) \ + static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ + char *page) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int result; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + result = scnprintf(page, PAGE_SIZE, "%u\n", le##bits##_to_cpu(u->desc.aname));\ + mutex_unlock(&opts->lock); \ + \ + mutex_unlock(su_mutex); \ + return result; \ +} \ + \ +static ssize_t \ +uvcg_framebased_##cname##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int ret; \ + u8 num; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + if (u->fmt.linked || opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou8(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (num > 255) { \ + ret = -EINVAL; \ + goto end; \ + } \ + u->desc.aname = num; \ + ret = len; \ +end: \ + mutex_unlock(&opts->lock); \ + mutex_unlock(su_mutex); \ + return ret; \ +} \ + \ +UVC_ATTR(uvcg_framebased_, cname, aname) + +UVCG_FRAMEBASED_ATTR_RO(b_format_index, bFormatIndex, 8); +UVCG_FRAMEBASED_ATTR_RO(b_bits_per_pixel, bBitsPerPixel, 8); +UVCG_FRAMEBASED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); +UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); +UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); +UVCG_FRAMEBASED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); + +#undef UVCG_FRAMEBASED_ATTR +#undef UVCG_FRAMEBASED_ATTR_RO + +static ssize_t uvcg_framebased_guid_format_show(struct config_item *item, + char *page) +{ + struct uvcg_framebased *ch = to_uvcg_framebased(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat)); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return sizeof(ch->desc.guidFormat); +} + +static ssize_t uvcg_framebased_guid_format_store(struct config_item *item, + const char *page, size_t len) +{ + struct uvcg_framebased *ch = to_uvcg_framebased(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + int ret; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + if (ch->fmt.linked || opts->refcnt) { + ret = -EBUSY; + goto end; + } + + memcpy(ch->desc.guidFormat, page, + min(sizeof(ch->desc.guidFormat), len)); + ret = sizeof(ch->desc.guidFormat); + +end: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + +UVC_ATTR(uvcg_framebased_, guid_format, guidFormat); + + static inline ssize_t +uvcg_framebased_bma_controls_show(struct config_item *item, char *page) +{ + struct uvcg_framebased *u = to_uvcg_framebased(item); + + return uvcg_format_bma_controls_show(&u->fmt, page); +} + + static inline ssize_t +uvcg_framebased_bma_controls_store(struct config_item *item, + const char *page, size_t len) +{ + struct uvcg_framebased *u = to_uvcg_framebased(item); + + return uvcg_format_bma_controls_store(&u->fmt, page, len); +} + +UVC_ATTR(uvcg_framebased_, bma_controls, bmaControls); + +static struct configfs_attribute *uvcg_framebased_attrs[] = { + &uvcg_framebased_attr_b_format_index, + &uvcg_framebased_attr_b_default_frame_index, + &uvcg_framebased_attr_b_bits_per_pixel, + &uvcg_framebased_attr_b_aspect_ratio_x, + &uvcg_framebased_attr_b_aspect_ratio_y, + &uvcg_framebased_attr_bm_interface_flags, + &uvcg_framebased_attr_bma_controls, + &uvcg_framebased_attr_guid_format, + NULL, +}; + +static const struct config_item_type uvcg_framebased_type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_framebased_group_ops, + .ct_attrs = uvcg_framebased_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *uvcg_framebased_make(struct config_group *group, + const char *name) +{ + static char guid[] = { /*Declear frame based as H264 format*/ + 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + }; + struct uvcg_framebased *h; + + h = kzalloc(sizeof(*h), GFP_KERNEL); + if (!h) + return ERR_PTR(-ENOMEM); + + h->desc.bLength = UVC_DT_FORMAT_FRAMEBASED_SIZE; + h->desc.bDescriptorType = USB_DT_CS_INTERFACE; + h->desc.bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED; + memcpy(h->desc.guidFormat, guid, sizeof(guid)); + h->desc.bBitsPerPixel = 0; + h->desc.bDefaultFrameIndex = 1; + h->desc.bAspectRatioX = 0; + h->desc.bAspectRatioY = 0; + h->desc.bmInterfaceFlags = 0; + h->desc.bCopyProtect = 0; + h->desc.bVariableSize = 1; + + h->fmt.type = UVCG_FRAMEBASED; + config_group_init_type_name(&h->fmt.group, name, + &uvcg_framebased_type); + + return &h->fmt.group; +} + +static struct configfs_group_operations uvcg_framebased_grp_ops = { + .make_group = uvcg_framebased_make, +}; + +static const struct uvcg_config_group_type uvcg_framebased_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_framebased_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "framebased", +}; + /* ----------------------------------------------------------------------------- * streaming/color_matching/default */ @@ -2001,6 +2284,7 @@ static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h, if (ret) return ret; grp = &f->fmt->group; + j = 0; list_for_each_entry(item, &grp->cg_children, ci_entry) { frm = to_uvcg_frame(item); ret = fun(frm, priv2, priv3, j++, UVCG_FRAME); @@ -2049,6 +2333,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, container_of(fmt, struct uvcg_mjpeg, fmt); *size += sizeof(m->desc); + } else if (fmt->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *f = + container_of(fmt, struct uvcg_framebased, fmt); + + *size += sizeof(f->desc); } else { return -EINVAL; } @@ -2059,6 +2348,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, int sz = sizeof(frm->dw_frame_interval); *size += sizeof(frm->frame); + /* + * framebased has duplicate member with uncompressed and + * mjpeg, so minus it + */ + *size -= sizeof(u32); *size += frm->frame.b_frame_interval_type * sz; } break; @@ -2069,6 +2363,27 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, return 0; } +static int __uvcg_copy_framebased_desc(void *dest, struct uvcg_frame *frm, + int sz) +{ + struct uvc_frame_framebased *desc = dest; + + desc->bLength = frm->frame.b_length; + desc->bDescriptorType = frm->frame.b_descriptor_type; + desc->bDescriptorSubType = frm->frame.b_descriptor_subtype; + desc->bFrameIndex = frm->frame.b_frame_index; + desc->bmCapabilities = frm->frame.bm_capabilities; + desc->wWidth = frm->frame.w_width; + desc->wHeight = frm->frame.w_height; + desc->dwMinBitRate = frm->frame.dw_min_bit_rate; + desc->dwMaxBitRate = frm->frame.dw_max_bit_rate; + desc->dwDefaultFrameInterval = frm->frame.dw_default_frame_interval; + desc->bFrameIntervalType = frm->frame.b_frame_interval_type; + desc->dwBytesPerLine = frm->frame.dw_bytes_perline; + + return 0; +} + /* * Fill an array of streaming descriptors. * @@ -2123,6 +2438,15 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, m->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &m->desc, sizeof(m->desc)); *dest += sizeof(m->desc); + } else if (fmt->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *f = + container_of(fmt, struct uvcg_framebased, + fmt); + + f->desc.bFormatIndex = n + 1; + f->desc.bNumFrameDescriptors = fmt->num_frames; + memcpy(*dest, &f->desc, sizeof(f->desc)); + *dest += sizeof(f->desc); } else { return -EINVAL; } @@ -2132,8 +2456,11 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, struct uvcg_frame *frm = priv1; struct uvc_descriptor_header *h = *dest; - sz = sizeof(frm->frame); - memcpy(*dest, &frm->frame, sz); + sz = sizeof(frm->frame) - 4; + if (frm->fmt_type != UVCG_FRAMEBASED) + memcpy(*dest, &frm->frame, sz); + else + __uvcg_copy_framebased_desc(*dest, frm, sz); *dest += sz; sz = frm->frame.b_frame_interval_type * sizeof(*frm->dw_frame_interval); @@ -2145,6 +2472,9 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, else if (frm->fmt_type == UVCG_MJPEG) h->bLength = UVC_DT_FRAME_MJPEG_SIZE( frm->frame.b_frame_interval_type); + else if (frm->fmt_type == UVCG_FRAMEBASED) + h->bLength = UVC_DT_FRAME_FRAMEBASED_SIZE( + frm->frame.b_frame_interval_type); } break; } @@ -2357,6 +2687,7 @@ static const struct uvcg_config_group_type uvcg_streaming_grp_type = { &uvcg_streaming_header_grp_type, &uvcg_uncompressed_grp_type, &uvcg_mjpeg_grp_type, + &uvcg_framebased_grp_type, &uvcg_color_matching_grp_type, &uvcg_streaming_class_grp_type, NULL, diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 93d0d0d2f75f..49f1f2ad134e 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -58,6 +58,7 @@ struct uvc_format { static struct uvc_format uvc_formats[] = { { 16, V4L2_PIX_FMT_YUYV }, { 0, V4L2_PIX_FMT_MJPEG }, + { 0, V4L2_PIX_FMT_H264 }, { 12, V4L2_PIX_FMT_YUV420 }, { 8, V4L2_PIX_FMT_GREY }, }; diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h index c58854fb7d94..c79b6049d9d7 100644 --- a/include/uapi/linux/usb/video.h +++ b/include/uapi/linux/usb/video.h @@ -597,5 +597,63 @@ struct UVC_FRAME_MJPEG(n) { \ __le32 dwFrameInterval[n]; \ } __attribute__ ((packed)) +/* Frame Based Payload - 3.1.1. Frame Based Video Format Descriptor */ +struct uvc_format_framebased { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFormatIndex; + __u8 bNumFrameDescriptors; + __u8 guidFormat[16]; + __u8 bBitsPerPixel; + __u8 bDefaultFrameIndex; + __u8 bAspectRatioX; + __u8 bAspectRatioY; + __u8 bmInterfaceFlags; + __u8 bCopyProtect; + __u8 bVariableSize; +} __attribute__((__packed__)); + +#define UVC_DT_FORMAT_FRAMEBASED_SIZE 28 + +/* Frame Based Payload - 3.1.2. Frame Based Video Frame Descriptor */ +struct uvc_frame_framebased { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFrameIndex; + __u8 bmCapabilities; + __u16 wWidth; + __u16 wHeight; + __u32 dwMinBitRate; + __u32 dwMaxBitRate; + __u32 dwDefaultFrameInterval; + __u8 bFrameIntervalType; + __u32 dwBytesPerLine; + __u32 dwFrameInterval[]; +} __attribute__((__packed__)); + +#define UVC_DT_FRAME_FRAMEBASED_SIZE(n) (26+4*(n)) + +#define UVC_FRAME_FRAMEBASED(n) \ + uvc_frame_framebased_##n + +#define DECLARE_UVC_FRAME_FRAMEBASED(n) \ + struct UVC_FRAME_FRAMEBASED(n) { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bFrameIndex; \ + __u8 bmCapabilities; \ + __u16 wWidth; \ + __u16 wHeight; \ + __u32 dwMinBitRate; \ + __u32 dwMaxBitRate; \ + __u32 dwDefaultFrameInterval; \ + __u8 bFrameIntervalType; \ + __u32 dwBytesPerLine; \ + __u32 dwFrameInterval[n]; \ + } __attribute__ ((packed)) + #endif /* __LINUX_USB_VIDEO_H */ From 6bbef66ce393adf4515b9ce14f0c63568d54526c Mon Sep 17 00:00:00 2001 From: yadwan Date: Tue, 29 Jul 2025 11:04:00 +0800 Subject: [PATCH 191/306] disp: msm: sde: Add change to fix slab out of bounds Non null terminated string from user space can cause out of bound access issue. Hence added a NULL character explicitly in name when received from user space. Change-Id: I6d498f16a59ec2832ddc0951952101859666eacf Signed-off-by: yadwan (cherry picked from commit 7eb70ce3648b8eb8e5340b0bf3c5bb3a7605d811) --- msm/sde/sde_wb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msm/sde/sde_wb.c b/msm/sde/sde_wb.c index dcb308fabf84..d6648ad7e2fc 100644 --- a/msm/sde/sde_wb.c +++ b/msm/sde/sde_wb.c @@ -204,6 +204,8 @@ int sde_wb_connector_set_modes(struct sde_wb_device *wb_dev, memset(&dispmode, 0, sizeof(dispmode)); ret = drm_mode_convert_umode(wb_dev->drm_dev, &dispmode, &modeinfo[i]); + /* null terminate the string */ + modeinfo[i].name[DRM_DISPLAY_MODE_LEN - 1] = '\0'; if (ret) { SDE_ERROR( "failed to convert mode %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x status:%d rc:%d\n", From df717747fdf18d12fa0606b64d77b1d8db9c1d08 Mon Sep 17 00:00:00 2001 From: Harini Manikumar Date: Thu, 4 Sep 2025 17:27:06 +0530 Subject: [PATCH 192/306] msm: smmu: Unregister SMMU fault handler before cleanup IOMMU fault handler can be invoked post SMMU destroy which can lead to use-after-free issue. Unregister the SMMU fault handler before freeing SMMU context and unregistering the platform device. Change-Id: I1cddd4a381f16d650258850a3d012d380fbe5ef8 Signed-off-by: Harini Manikumar Signed-off-by: Karthik Veeranki --- msm/msm_smmu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/msm/msm_smmu.c b/msm/msm_smmu.c index 53f5f926560a..af9ba0ba87f5 100644 --- a/msm/msm_smmu.c +++ b/msm/msm_smmu.c @@ -1,4 +1,5 @@ /* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -211,6 +212,10 @@ static void msm_smmu_destroy(struct msm_mmu *mmu) { struct msm_smmu *smmu = to_msm_smmu(mmu); struct platform_device *pdev = to_platform_device(smmu->client_dev); + struct iommu_domain *domain = iommu_get_domain_for_dev(smmu->client_dev); + + if (domain) + iommu_set_fault_handler(domain, NULL, NULL); if (smmu->client_dev) platform_device_unregister(pdev); From a3e616cc0d3d7a59818c35acfa7f8829def160b0 Mon Sep 17 00:00:00 2001 From: Desireddy Suresh Kumar Reddy Date: Fri, 9 Feb 2024 16:49:34 +0530 Subject: [PATCH 193/306] net: bridge: Fix for co-located mode Issue point: 1.qca-hyfi-bridge calls the HyFi-hooks for enabling the co-located mode. a. hyfi_bridge_get_dst and br_get_dst_hook functions are passed as arguments in a rcu_assign_pointer function. b. br_get_dst_hook implementations should be available in the br_dev_xmit kernel function. But currently br_get_dst_hook implementations are missing in br_dev_xmit. Fix: 1. For enabling co-located-agent-mode and ieee1905-packet-transfer this HyFi-hook (br_get_dst_hook) are made available in br_dev_xmit function. a. Added the br_get_dst_hook and get_dst_hook in the required files(net/bridge/br_input.c & net/bridge/br_device.c) Change-Id: Iac43ea347c83276971816029a940818e99752710 Signed-off-by: Desireddy Suresh Kumar Reddy --- include/linux/if_bridge.h | 4 ++++ net/bridge/br_device.c | 27 ++++++++++++++++++++++++--- net/bridge/br_input.c | 19 ++++++++++++++++++- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 9e2ad3b81690..e06623fa5b80 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -162,5 +162,9 @@ extern br_notify_hook_t __rcu *br_notify_hook; typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src, struct sk_buff *skb); extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook; +typedef struct net_bridge_port *br_get_dst_hook_t( + const struct net_bridge_port *src, + struct sk_buff **skb); +extern br_get_dst_hook_t __rcu *br_get_dst_hook; #endif #endif diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 00438505c175..ec4dee64357b 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -34,6 +34,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) const struct nf_br_ops *nf_ops; const unsigned char *dest; u16 vid = 0; +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + struct net_bridge_port *pdst; + br_get_dst_hook_t *get_dst_hook; +#endif if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) { kfree_skb(skb); @@ -82,6 +86,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) br_do_suppress_nd(skb, br, vid, NULL, msg); } +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + get_dst_hook = rcu_dereference(br_get_dst_hook); +#endif + dest = eth_hdr(skb)->h_dest; if (is_broadcast_ether_addr(dest)) { br_flood(br, skb, BR_PKT_BROADCAST, false, true); @@ -107,11 +115,24 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) br_multicast_flood(mdst, skb, false, true); else br_flood(br, skb, BR_PKT_MULTICAST, false, true); - } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { - br_forward(dst->dst, skb, false, true); } else { - br_flood(br, skb, BR_PKT_UNICAST, false, true); +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + pdst = __br_get(get_dst_hook, NULL, NULL, &skb); + if (pdst) { + if (!skb) + goto out; + br_forward(pdst, skb, false, true); + } else +#endif + { + dst = br_fdb_find_rcu(br, dest, vid); + if (dst) + br_forward(dst->dst, skb, false, true); + else + br_flood(br, skb, BR_PKT_UNICAST, false, true); + } } + out: rcu_read_unlock(); return NETDEV_TX_OK; diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index ace461e94830..02dbaf13f591 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -33,6 +33,11 @@ br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb) /* Hook for external Multicast handler */ br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly; EXPORT_SYMBOL(br_multicast_handle_hook); + +/* Hook for external forwarding logic */ +br_get_dst_hook_t __rcu *br_get_dst_hook __read_mostly; +EXPORT_SYMBOL_GPL(br_get_dst_hook); + #endif int br_pass_frame_up(struct sk_buff *skb) @@ -94,6 +99,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb struct net_bridge *br; #ifdef CONFIG_HYFI_BRIDGE_HOOKS br_multicast_handle_hook_t *multicast_handle_hook; + struct net_bridge_port *pdst = NULL; + br_get_dst_hook_t *get_dst_hook = rcu_dereference(br_get_dst_hook); #endif u16 vid = 0; @@ -168,7 +175,17 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb } break; case BR_PKT_UNICAST: - dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + pdst = __br_get(get_dst_hook, NULL, p, &skb); + if (pdst) { + if (!skb) + goto out; + } else +#endif + { + dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); + } + break; default: break; } From 3a1ebfc377d01f5123dd9509ba774666b38c7e0a Mon Sep 17 00:00:00 2001 From: Manoj Sekar Date: Mon, 26 Jun 2023 22:26:28 +0530 Subject: [PATCH 194/306] bridge: port structure members from 5.4 kernel port bridge related structure members from 5.4 kernel to 5.15 kernel required for EasyMesh Kernel modules. Change-Id: I74c934a0a6c96782f4e6c4ff99e26ab1b8b39168 Signed-off-by: Manoj Sekar --- net/bridge/br_private.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c7130fff57a0..023ecc1f4494 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -195,6 +195,9 @@ struct net_bridge_fdb_entry { struct net_bridge_fdb_key key; struct hlist_node fdb_node; + unsigned char is_local:1, + is_static:1; + unsigned long flags; unsigned char offloaded:1; From 895cfcbb7afc51c581db9fb91146e95f8fd5d676 Mon Sep 17 00:00:00 2001 From: Manoj Sekar Date: Mon, 26 Jun 2023 20:31:54 +0530 Subject: [PATCH 195/306] net: Add netdevice notification for bridge activity This modification allows programs to get notified whenever a device is added to or removed from a bridge. This will be used by NSS Qdisc for updating bridge shaper configuration. Change-Id: I70e63c5b219d7ab022400741b2dc789cfef71ead Signed-off-by: Manoj Sekar --- include/linux/netdevice.h | 2 ++ net/bridge/br_if.c | 3 +++ net/core/dev.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7d048d775eff..04fde5ea195b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2554,6 +2554,8 @@ enum netdev_cmd { NETDEV_CVLAN_FILTER_DROP_INFO, NETDEV_SVLAN_FILTER_PUSH_INFO, NETDEV_SVLAN_FILTER_DROP_INFO, + NETDEV_BR_JOIN, + NETDEV_BR_LEAVE, }; const char *netdev_cmd_to_name(enum netdev_cmd cmd); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index ea0ddd513cc1..a5565b7dfb06 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -695,6 +695,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, br_set_gso_limits(br); kobject_uevent(&p->kobj, KOBJ_ADD); + call_netdevice_notifiers(NETDEV_BR_JOIN, dev); return 0; @@ -732,6 +733,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) if (!p || p->br != br) return -EINVAL; + call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); + /* Since more than one interface can be attached to a bridge, * there still maybe an alternate path for netconsole to use; * therefore there is no reason for a NETDEV_RELEASE event. diff --git a/net/core/dev.c b/net/core/dev.c index aad29ac5ac15..d4d84160b795 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1521,7 +1521,7 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd) N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN) N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO) N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO) - N(PRE_CHANGEADDR) + N(PRE_CHANGEADDR) N(BR_JOIN) N(BR_LEAVE) } #undef N return "UNKNOWN_NETDEV_EVENT"; From 491b8e69beb7e7813819d801a01a694bb95c3432 Mon Sep 17 00:00:00 2001 From: Shiv Kumar Date: Wed, 10 Sep 2025 21:55:15 +0530 Subject: [PATCH 196/306] kgsl: gmu: Use num_vma for safe GMU VMAs array access Use num_vma to bound GMU VMAs array access instead of GMU_MEM_TYPE_MAX, preventing out-of-bounds reads when the array size is less than the enum maximum. Change-Id: Iffb587e5eb3fa70356872eb0f56d065d1b58f27c Signed-off-by: Shiv Kumar Signed-off-by: Sushmita Gollena Signed-off-by: Nagababu Pamarthi --- drivers/gpu/msm/adreno_a6xx_gmu.c | 9 ++++++--- drivers/gpu/msm/adreno_a6xx_gmu.h | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.c b/drivers/gpu/msm/adreno_a6xx_gmu.c index 8a4ea1752b24..07b1e1d24f45 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.c +++ b/drivers/gpu/msm/adreno_a6xx_gmu.c @@ -593,7 +593,7 @@ static int find_vma_block(struct a6xx_gmu_device *gmu, u32 addr, u32 size) { int i; - for (i = 0; i < GMU_MEM_TYPE_MAX; i++) { + for (i = 0; i < gmu->num_vmas; i++) { struct gmu_vma_entry *vma = &gmu->vma[i]; if ((addr >= vma->start) && @@ -2685,10 +2685,13 @@ int a6xx_gmu_probe(struct kgsl_device *device, if (ret) goto error; - if (adreno_is_a650_family(adreno_dev)) + if (adreno_is_a650_family(adreno_dev)) { gmu->vma = a6xx_gmu_vma; - else + gmu->num_vmas = ARRAY_SIZE(a6xx_gmu_vma); + } else { gmu->vma = a6xx_gmu_vma_legacy; + gmu->num_vmas = ARRAY_SIZE(a6xx_gmu_vma_legacy); + } /* Map and reserve GMU CSRs registers */ ret = a6xx_gmu_reg_probe(adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx_gmu.h b/drivers/gpu/msm/adreno_a6xx_gmu.h index d39597683ec9..b671771c46b4 100644 --- a/drivers/gpu/msm/adreno_a6xx_gmu.h +++ b/drivers/gpu/msm/adreno_a6xx_gmu.h @@ -187,6 +187,8 @@ struct a6xx_gmu_device { /** @global_entries: To keep track of number of gmu buffers */ u32 global_entries; struct gmu_vma_entry *vma; + /** @num_vmas: Number of entries in the @vma array */ + u32 num_vmas; unsigned int log_wptr_retention; /** @cm3_fault: whether gmu received a cm3 fault interrupt */ atomic_t cm3_fault; From 1d2451ca457a90a44a73618195247bdadee66381 Mon Sep 17 00:00:00 2001 From: Pulkit Singh Tak Date: Tue, 30 Dec 2025 11:39:53 +0530 Subject: [PATCH 197/306] msm: eva: OOB write issue in fence processing Added check for number of fences from user in kernel space before fence processing. Change-Id: I58f7899a811245a33357f19678557cb35b6a3736 Signed-off-by: Pulkit Singh Tak --- drivers/media/platform/msm/cvp/msm_cvp.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c index 239ceb89acfa..346f21641519 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.c +++ b/drivers/media/platform/msm/cvp/msm_cvp.c @@ -741,6 +741,13 @@ static int msm_cvp_session_process_hfi_fence(struct msm_cvp_inst *inst, f->output_index = kfc->output_index; } + if (f->num_fences >= (MAX_HFI_FENCE_SIZE / 2)) { + dprintk(CVP_ERR, "%s: Max number of fences exceeded! Max number supported: %d", + __func__, (MAX_HFI_FENCE_SIZE / 2)); + cvp_free_fence_data(f); + msm_cvp_unmap_frame(inst, pkt->client_data.kdata); + goto exit; + } dprintk(CVP_SYNX, "%s: frameID %llu ktid %llu\n", __func__, f->frame_id, pkt->client_data.kdata); From 13fa1e24012c0d7e1c98874aa3abe8908c67714d Mon Sep 17 00:00:00 2001 From: Arpit Saini Date: Fri, 10 Oct 2025 16:44:16 +0530 Subject: [PATCH 198/306] disp: msm: dsi: Fix potential data race in ctrl isr Use atomic operations for shared variables to ensure safe concurrent access from both ISR and task context. Change-Id: I72a235007f0b36553f436a900a3e9a91afcd75a4 Signed-off-by: Arpit Saini --- msm/dsi/dsi_ctrl.c | 21 ++++++++++++++------- msm/dsi/dsi_ctrl.h | 8 ++++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 278e3dcbe921..122fb10c18a5 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -229,10 +229,10 @@ static ssize_t debugfs_line_count_read(struct file *file, dsi_ctrl->cmd_trigger_frame); len += scnprintf((buf + len), max_len - len, "Command successful at line: %04x\n", - dsi_ctrl->cmd_success_line); + atomic_read(&dsi_ctrl->cmd_success_line)); len += scnprintf((buf + len), max_len - len, "Command successful at frame: %04x\n", - dsi_ctrl->cmd_success_frame); + atomic_read(&dsi_ctrl->cmd_success_frame)); mutex_unlock(&dsi_ctrl->ctrl_lock); @@ -2889,14 +2889,20 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) if (status & DSI_CMD_MODE_DMA_DONE) { if (dsi_ctrl->enable_cmd_dma_stats) { - u32 reg = dsi_ctrl->hw.ops.log_line_count(&dsi_ctrl->hw, - dsi_ctrl->cmd_mode); - dsi_ctrl->cmd_success_line = (reg & 0xFFFF); - dsi_ctrl->cmd_success_frame = ((reg >> 16) & 0xFFFF); + if (dsi_ctrl->hw.ops.log_line_count[dsi_ctrl->disp_op]) + reg = + dsi_ctrl->hw.ops.log_line_count[dsi_ctrl->disp_op](&dsi_ctrl->hw, + dsi_ctrl->cmd_mode); + else + reg = 0; + atomic_set(&dsi_ctrl->cmd_success_line, (reg & 0xFFFF)); + atomic_set(&dsi_ctrl->cmd_success_frame, ((reg >> 16) & 0xFFFF)); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_success_line, dsi_ctrl->cmd_success_frame); } + + atomic64_set(&dsi_ctrl->cmd_success_ts, ktime_get()); atomic_set(&dsi_ctrl->dma_irq_trig, 1); dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE); @@ -3481,6 +3487,7 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, rc); } + cmd->ts = atomic64_read(&dsi_ctrl->cmd_success_ts); dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_TX, 0x0); error: diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index a3290750520b..f66be7fb6b70 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ @@ -309,8 +310,11 @@ struct dsi_ctrl { bool cmd_mode; u32 cmd_trigger_line; u32 cmd_trigger_frame; - u32 cmd_success_line; - u32 cmd_success_frame; + atomic_t cmd_success_line; + atomic_t cmd_success_frame; + u32 cmd_engine_refcount; + u32 pending_cmd_flags; + atomic64_t cmd_success_ts; }; /** From df582cc15abb460d6fa57c0f183488b3db673afe Mon Sep 17 00:00:00 2001 From: Gopi Botlagunta Date: Wed, 7 Jan 2026 15:37:06 +0530 Subject: [PATCH 199/306] disp: msm: dsi: Fix potential data race in ctrl isr Use atomic operations for shared variables to ensure safe concurrent access from both ISR and task context. Change-Id: I02d4bde88692d0be7027b158648a3ab8a5704b2d Signed-off-by: Gopi Botlagunta --- msm/dsi/dsi_ctrl.c | 10 +++++----- msm/dsi/dsi_ctrl.h | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 278e3dcbe921..5dc027912f13 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -229,10 +229,10 @@ static ssize_t debugfs_line_count_read(struct file *file, dsi_ctrl->cmd_trigger_frame); len += scnprintf((buf + len), max_len - len, "Command successful at line: %04x\n", - dsi_ctrl->cmd_success_line); + atomic_read(&dsi_ctrl->cmd_success_line)); len += scnprintf((buf + len), max_len - len, "Command successful at frame: %04x\n", - dsi_ctrl->cmd_success_frame); + atomic_read(&dsi_ctrl->cmd_success_frame)); mutex_unlock(&dsi_ctrl->ctrl_lock); @@ -2891,8 +2891,8 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) if (dsi_ctrl->enable_cmd_dma_stats) { u32 reg = dsi_ctrl->hw.ops.log_line_count(&dsi_ctrl->hw, dsi_ctrl->cmd_mode); - dsi_ctrl->cmd_success_line = (reg & 0xFFFF); - dsi_ctrl->cmd_success_frame = ((reg >> 16) & 0xFFFF); + atomic_set(&dsi_ctrl->cmd_success_line, (reg & 0xFFFF)); + atomic_set(&dsi_ctrl->cmd_success_frame, ((reg >> 16) & 0xFFFF)); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, dsi_ctrl->cmd_success_line, dsi_ctrl->cmd_success_frame); diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index a3290750520b..944debaa28a4 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ @@ -309,8 +310,8 @@ struct dsi_ctrl { bool cmd_mode; u32 cmd_trigger_line; u32 cmd_trigger_frame; - u32 cmd_success_line; - u32 cmd_success_frame; + atomic_t cmd_success_line; + atomic_t cmd_success_frame; }; /** From a74bd43d86ff4b26a891093ff5bd24b888436fce Mon Sep 17 00:00:00 2001 From: Gopi Botlagunta Date: Wed, 7 Jan 2026 15:37:06 +0530 Subject: [PATCH 200/306] disp: msm: dsi: Fix potential data race in ctrl isr Use atomic operations for shared variables to ensure safe concurrent access from both ISR and task context. Change-Id: I02d4bde88692d0be7027b158648a3ab8a5704b2d Signed-off-by: Gopi Botlagunta --- msm/dsi/dsi_ctrl.c | 10 ++-------- msm/dsi/dsi_ctrl.h | 3 --- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/msm/dsi/dsi_ctrl.c b/msm/dsi/dsi_ctrl.c index 122fb10c18a5..988b3e60a462 100644 --- a/msm/dsi/dsi_ctrl.c +++ b/msm/dsi/dsi_ctrl.c @@ -2889,12 +2889,8 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) if (status & DSI_CMD_MODE_DMA_DONE) { if (dsi_ctrl->enable_cmd_dma_stats) { - if (dsi_ctrl->hw.ops.log_line_count[dsi_ctrl->disp_op]) - reg = - dsi_ctrl->hw.ops.log_line_count[dsi_ctrl->disp_op](&dsi_ctrl->hw, - dsi_ctrl->cmd_mode); - else - reg = 0; + u32 reg = dsi_ctrl->hw.ops.log_line_count(&dsi_ctrl->hw, + dsi_ctrl->cmd_mode); atomic_set(&dsi_ctrl->cmd_success_line, (reg & 0xFFFF)); atomic_set(&dsi_ctrl->cmd_success_frame, ((reg >> 16) & 0xFFFF)); SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_CASE1, @@ -2902,7 +2898,6 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) dsi_ctrl->cmd_success_frame); } - atomic64_set(&dsi_ctrl->cmd_success_ts, ktime_get()); atomic_set(&dsi_ctrl->dma_irq_trig, 1); dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE); @@ -3487,7 +3482,6 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl, rc); } - cmd->ts = atomic64_read(&dsi_ctrl->cmd_success_ts); dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_TX, 0x0); error: diff --git a/msm/dsi/dsi_ctrl.h b/msm/dsi/dsi_ctrl.h index f66be7fb6b70..944debaa28a4 100644 --- a/msm/dsi/dsi_ctrl.h +++ b/msm/dsi/dsi_ctrl.h @@ -312,9 +312,6 @@ struct dsi_ctrl { u32 cmd_trigger_frame; atomic_t cmd_success_line; atomic_t cmd_success_frame; - u32 cmd_engine_refcount; - u32 pending_cmd_flags; - atomic64_t cmd_success_ts; }; /** From 365834436c0aa0f53cd5a0901deebf652859cfef Mon Sep 17 00:00:00 2001 From: kamasali Satyanarayan Date: Mon, 12 Jan 2026 14:13:47 +0530 Subject: [PATCH 201/306] reverting all USB patches ac91ada020c1 usb: xhci: plat: Facilitate using autosuspend for xhci plat devices e9d2ab8795d1 usb: mon: Increase BUFF_MAX to 64 MiB to support multi-MB URBs 3248107d0094 usb: gadget: f_hid: Fix zero length packet transfer a3f918b791cd usb: gadget: f_ncm: Fix MAC assignment NCM ethernet b00d2572c16e usb: gadget: f_fs: Fix epfile null pointer access after ep enable. 428c8047526a xhci: dbc: enable back DbC in resume if it was enabled before suspend 02a089cf4042 usb/core/quirks: Add Huawei ME906S to wakeup quirk 2b24cd3ab1c7 USB: serial: option: add Telit FN920C04 ECM compositions e9639d4237e8 USB: serial: option: add Quectel RG255C 84c73088ec0d USB: serial: option: add UNISOC UIS7720 0ba8541351bf usb: vhci-hcd: Prevent suspending virtually attached devices b86de42c4276 usb: gadget: configfs: Correctly set use_os_string at bind a88df3897031 usb: phy: twl6030: Fix incorrect type for ret 89838fe5c6c0 usb: host: max3421-hcd: Fix error pointer dereference in probe cleanup a1f24c2e911a USB: serial: option: add SIMCom 8230C compositions f5fcec379ef4 usb: core: Add 0x prefix to quirks debug output ea748ebb9084 USB: gadget: dummy-hcd: Fix locking bug in RT-enabled kernels 6070c741cc5c usb: gadget: dummy_hcd: remove usage of list iterator past the loop body 2f28d51cf862 USB: serial: option: add Telit Cinterion LE910C4-WWX new compositions b896501ea175 USB: serial: option: add Telit Cinterion FN990A w/audio compositions 6ddde3e46176 usb: hub: Fix flushing of delayed work used for post resume purposes ef49d17eac00 usb: xhci: Fix slot_id resource race conflict 07dad577076f usb: musb: omap2430: fix device leak at unbind 2cbf9f514ed1 usb: typec: fusb302: cache PD RX state 0e35cac65aae cdc-acm: fix race between initial clearing halt and open 46ce8549441c USB: cdc-acm: do not log successful probe on later errors b25dad547b44 usb: hub: Don't try to recover devices lost during warm reset. 1bd9246548a1 usb: hub: avoid warm port reset during USB3 disconnect 0c1699135dc6 usb: dwc3: Ignore late xferNotReady event to prevent halt timeout f93fb614d3f4 USB: storage: Ignore driver CD mode for Realtek multi-mode Wi-Fi dongles a648cc7c4946 usb: storage: realtek_cr: Use correct byte order for bcs->Residue eb2223e2c8a5 USB: storage: Add unusual-devs entry for Novatek NTK96550-based camera deef90c5a489 usb: quirks: Add DELAY_INIT quick for another SanDisk 3.2Gen1 Flash Drive 57df8e2a67f7 usb: dwc3: meson-g12a: fix device leaks at unbind 22ac4969dc37 usb: gadget: udc: renesas_usb3: fix device leak at unbind c280a4427add usb: atm: cxacru: Merge cxacru_upload_firmware() into cxacru_heavy_init() c41fef8b2dfe usb: core: usb_submit_urb: downgrade type check 608ab9ff2118 usb: xhci: Avoid showing errors during surprise removal 0913e9234c0f usb: xhci: Set avg_trb_len = 8 for EP0 during Address Device Command fcd65f353012 usb: xhci: Avoid showing warnings for dying controller c698f6d03d17 usb: xhci: print xhci->xhc_state when queue_command failed dba96dfa5a0f usb: gadget : fix use-after-free in composite_dev_cleanup() 1db292bca68e USB: serial: option: add Foxconn T99W709 651a71f931f8 usb: chipidea: udc: fix sleeping function called from invalid context d12d31cd5bdb usb: early: xhci-dbc: Fix early_ioremap leak e5d396f42d75 usb: phy: mxs: disconnect line when USB charger is attached 4eb4ad451e3f usb: chipidea: add USB PHY event f2b6a88c1cbd usb: chipidea: introduce CI_HDRC_CONTROLLER_VBUS_EVENT glue layer use 770809a95864 usb: chipidea: udc: protect usb interrupt enable 4fbf6bb0f97c usb: chipidea: udc: add new API ci_hdrc_gadget_connect c72cd4c92e06 usb: hub: Fix flushing and scheduling of delayed work that tunes runtime pm 042959e9b479 usb: hub: fix detection of high tier USB3 devices behind suspended hubs c7e68db993c2 xhci: Disable stream for xHC controller with XHCI_BROKEN_STREAMS 3451944a8cde usb: dwc3: qcom: Don't leave BCR asserted 4ea93e0eb91f usb: musb: fix gadget state on disconnect 78b41148cfea usb: gadget: configfs: Fix OOB read on empty string write bc5c5490062a USB: serial: ftdi_sio: add support for NDI EMGUIDE GEMINI aad2f69c55be USB: serial: option: add Foxconn T99W640 d5e3bcff9b43 USB: serial: option: add Telit Cinterion FE910C04 (ECM) composition 18d58a467ccf usb: gadget: u_serial: Fix race condition in TTY wakeup 749d9076735f usb: typec: displayport: Fix potential deadlock 0722035aef27 Logitech C-270 even more broken c93bc959788e usb: typec: altmodes/displayport: do not index invalid pin_assignments e0359c66c1be usb: typec: displayport: Receive DP Status Update NAK request exit dp altmode df6701168a28 usb: cdc-wdm: avoid setting WDM_READ for ZLP-s 13d8f52c88fa usb: Add checks for snprintf() calls in usb_alloc_dev() 0861b9cb2ff5 usb: potential integer overflow in usbg_make_tpg() Change-Id: I9ebeadf2e42fc9b870af3d93a65724819e9d41ae Signed-off-by: kamasali Satyanarayan --- drivers/usb/atm/cxacru.c | 172 ++++++++++++----------- drivers/usb/chipidea/ci.h | 18 +-- drivers/usb/chipidea/udc.c | 89 +++++------- drivers/usb/class/cdc-acm.c | 13 +- drivers/usb/class/cdc-wdm.c | 23 +-- drivers/usb/core/hub.c | 60 +------- drivers/usb/core/hub.h | 1 - drivers/usb/core/quirks.c | 8 +- drivers/usb/core/urb.c | 2 +- drivers/usb/core/usb.c | 14 +- drivers/usb/dwc3/dwc3-meson-g12a.c | 3 - drivers/usb/dwc3/dwc3-qcom.c | 8 +- drivers/usb/dwc3/gadget.c | 9 -- drivers/usb/early/xhci-dbc.c | 4 - drivers/usb/gadget/composite.c | 5 - drivers/usb/gadget/configfs.c | 4 - drivers/usb/gadget/function/f_fs.c | 8 +- drivers/usb/gadget/function/f_hid.c | 4 +- drivers/usb/gadget/function/f_ncm.c | 3 +- drivers/usb/gadget/function/f_tcm.c | 4 +- drivers/usb/gadget/function/u_serial.c | 6 +- drivers/usb/gadget/udc/dummy_hcd.c | 25 ++-- drivers/usb/gadget/udc/renesas_usb3.c | 1 - drivers/usb/host/max3421-hcd.c | 2 +- drivers/usb/host/xhci-dbgcap.c | 9 +- drivers/usb/host/xhci-hub.c | 3 +- drivers/usb/host/xhci-mem.c | 24 ++-- drivers/usb/host/xhci-plat.c | 4 +- drivers/usb/host/xhci-ring.c | 19 +-- drivers/usb/host/xhci.c | 24 +--- drivers/usb/host/xhci.h | 3 +- drivers/usb/mon/mon_bin.c | 14 +- drivers/usb/musb/musb_gadget.c | 2 - drivers/usb/musb/omap2430.c | 10 +- drivers/usb/phy/phy-mxs-usb.c | 4 +- drivers/usb/phy/phy-twl6030-usb.c | 3 +- drivers/usb/serial/ftdi_sio.c | 2 - drivers/usb/serial/ftdi_sio_ids.h | 3 - drivers/usb/serial/option.c | 40 ------ drivers/usb/storage/realtek_cr.c | 2 +- drivers/usb/storage/unusual_devs.h | 29 ---- drivers/usb/typec/altmodes/displayport.c | 5 +- drivers/usb/typec/tcpm/fusb302.c | 8 -- drivers/usb/usbip/vhci_hcd.c | 22 --- include/linux/usb/chipidea.h | 1 - include/linux/usb/typec_dp.h | 1 - 46 files changed, 231 insertions(+), 487 deletions(-) diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 58e5bc574e6a..a4d863f6cda7 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -984,6 +984,94 @@ cleanup: return ret; } +static void cxacru_upload_firmware(struct cxacru_data *instance, + const struct firmware *fw, + const struct firmware *bp) +{ + int ret; + struct usbatm_data *usbatm = instance->usbatm; + struct usb_device *usb_dev = usbatm->usb_dev; + __le16 signature[] = { usb_dev->descriptor.idVendor, + usb_dev->descriptor.idProduct }; + __le32 val; + + usb_dbg(usbatm, "%s\n", __func__); + + /* FirmwarePllFClkValue */ + val = cpu_to_le32(instance->modem_type->pll_f_clk); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); + if (ret) { + usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret); + return; + } + + /* FirmwarePllBClkValue */ + val = cpu_to_le32(instance->modem_type->pll_b_clk); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); + if (ret) { + usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret); + return; + } + + /* Enable SDRAM */ + val = cpu_to_le32(SDRAM_ENA); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); + if (ret) { + usb_err(usbatm, "Enable SDRAM failed: %d\n", ret); + return; + } + + /* Firmware */ + usb_info(usbatm, "loading firmware\n"); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); + if (ret) { + usb_err(usbatm, "Firmware upload failed: %d\n", ret); + return; + } + + /* Boot ROM patch */ + if (instance->modem_type->boot_rom_patch) { + usb_info(usbatm, "loading boot ROM patch\n"); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); + if (ret) { + usb_err(usbatm, "Boot ROM patching failed: %d\n", ret); + return; + } + } + + /* Signature */ + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); + if (ret) { + usb_err(usbatm, "Signature storing failed: %d\n", ret); + return; + } + + usb_info(usbatm, "starting device\n"); + if (instance->modem_type->boot_rom_patch) { + val = cpu_to_le32(BR_ADDR); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); + } else { + ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0); + } + if (ret) { + usb_err(usbatm, "Passing control to firmware failed: %d\n", ret); + return; + } + + /* Delay to allow firmware to start up. */ + msleep_interruptible(1000); + + usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD)); + usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD)); + usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA)); + usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA)); + + ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); + if (ret < 0) { + usb_err(usbatm, "modem failed to initialize: %d\n", ret); + return; + } +} static int cxacru_find_firmware(struct cxacru_data *instance, char *phase, const struct firmware **fw_p) @@ -1010,14 +1098,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, { const struct firmware *fw, *bp; struct cxacru_data *instance = usbatm_instance->driver_data; - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - __le16 signature[] = { usb_dev->descriptor.idVendor, - usb_dev->descriptor.idProduct }; - __le32 val; - int ret; + int ret = cxacru_find_firmware(instance, "fw", &fw); - ret = cxacru_find_firmware(instance, "fw", &fw); if (ret) { usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); return ret; @@ -1032,82 +1114,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, } } - /* FirmwarePllFClkValue */ - val = cpu_to_le32(instance->modem_type->pll_f_clk); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret); - goto done; - } + cxacru_upload_firmware(instance, fw, bp); - /* FirmwarePllBClkValue */ - val = cpu_to_le32(instance->modem_type->pll_b_clk); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret); - goto done; - } - - /* Enable SDRAM */ - val = cpu_to_le32(SDRAM_ENA); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "Enable SDRAM failed: %d\n", ret); - goto done; - } - - /* Firmware */ - usb_info(usbatm, "loading firmware\n"); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); - if (ret) { - usb_err(usbatm, "Firmware upload failed: %d\n", ret); - goto done; - } - - /* Boot ROM patch */ - if (instance->modem_type->boot_rom_patch) { - usb_info(usbatm, "loading boot ROM patch\n"); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); - if (ret) { - usb_err(usbatm, "Boot ROM patching failed: %d\n", ret); - goto done; - } - } - - /* Signature */ - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); - if (ret) { - usb_err(usbatm, "Signature storing failed: %d\n", ret); - goto done; - } - - usb_info(usbatm, "starting device\n"); - if (instance->modem_type->boot_rom_patch) { - val = cpu_to_le32(BR_ADDR); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); - } else { - ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0); - } - if (ret) { - usb_err(usbatm, "Passing control to firmware failed: %d\n", ret); - goto done; - } - - /* Delay to allow firmware to start up. */ - msleep_interruptible(1000); - - usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD)); - usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD)); - usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA)); - usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA)); - - ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); - if (ret < 0) { - usb_err(usbatm, "modem failed to initialize: %d\n", ret); - goto done; - } - -done: if (instance->modem_type->boot_rom_patch) release_firmware(bp); release_firmware(fw); diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 3a22bc727bb9..ff61f88fc867 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -277,19 +277,8 @@ static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role) return -ENXIO; ret = ci->roles[role]->start(ci); - if (ret) - return ret; - - ci->role = role; - - if (ci->usb_phy) { - if (role == CI_ROLE_HOST) - usb_phy_set_event(ci->usb_phy, USB_EVENT_ID); - else - /* in device mode but vbus is invalid*/ - usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE); - } - + if (!ret) + ci->role = role; return ret; } @@ -303,9 +292,6 @@ static inline void ci_role_stop(struct ci_hdrc *ci) ci->role = CI_ROLE_END; ci->roles[role]->stop(ci); - - if (ci->usb_phy) - usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE); } static inline enum usb_role ci_role_to_usb_role(struct ci_hdrc *ci) diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index d483a957804b..a6ce6b89b271 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1533,68 +1533,44 @@ static const struct usb_ep_ops usb_ep_ops = { /****************************************************************************** * GADGET block *****************************************************************************/ -/** - * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded - */ -static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active) -{ - struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); - - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(ci); - spin_lock_irq(&ci->lock); - if (ci->driver) { - hw_device_state(ci, ci->ep0out->qh.dma); - usb_gadget_set_state(_gadget, USB_STATE_POWERED); - spin_unlock_irq(&ci->lock); - usb_udc_vbus_handler(_gadget, true); - } else { - spin_unlock_irq(&ci->lock); - } - } else { - usb_udc_vbus_handler(_gadget, false); - if (ci->driver) - ci->driver->disconnect(&ci->gadget); - hw_device_state(ci, 0); - if (ci->platdata->notify_event) - ci->platdata->notify_event(ci, - CI_HDRC_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&ci->gadget); - pm_runtime_put_sync(&_gadget->dev); - usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); - } -} - static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) { struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); unsigned long flags; - int ret = 0; + int gadget_ready = 0; spin_lock_irqsave(&ci->lock, flags); ci->vbus_active = is_active; + if (ci->driver) + gadget_ready = 1; spin_unlock_irqrestore(&ci->lock, flags); if (ci->usb_phy) usb_phy_set_charger_state(ci->usb_phy, is_active ? USB_CHARGER_PRESENT : USB_CHARGER_ABSENT); - if (ci->platdata->notify_event) - ret = ci->platdata->notify_event(ci, - CI_HDRC_CONTROLLER_VBUS_EVENT); - - if (ci->usb_phy) { - if (is_active) - usb_phy_set_event(ci->usb_phy, USB_EVENT_VBUS); - else - usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE); + if (gadget_ready) { + if (is_active) { + pm_runtime_get_sync(&_gadget->dev); + hw_device_reset(ci); + hw_device_state(ci, ci->ep0out->qh.dma); + usb_gadget_set_state(_gadget, USB_STATE_POWERED); + usb_udc_vbus_handler(_gadget, true); + } else { + usb_udc_vbus_handler(_gadget, false); + if (ci->driver) + ci->driver->disconnect(&ci->gadget); + hw_device_state(ci, 0); + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_STOPPED_EVENT); + _gadget_stop_activity(&ci->gadget); + pm_runtime_put_sync(&_gadget->dev); + usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); + } } - if (ci->driver) - ci_hdrc_gadget_connect(_gadget, is_active); - - return ret; + return 0; } static int ci_udc_wakeup(struct usb_gadget *_gadget) @@ -1818,10 +1794,18 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; } - if (ci->vbus_active) - ci_hdrc_gadget_connect(gadget, 1); - else + pm_runtime_get_sync(&ci->gadget.dev); + if (ci->vbus_active) { + hw_device_reset(ci); + } else { usb_udc_vbus_handler(&ci->gadget, false); + pm_runtime_put_sync(&ci->gadget.dev); + return retval; + } + + retval = hw_device_state(ci, ci->ep0out->qh.dma); + if (retval) + pm_runtime_put_sync(&ci->gadget.dev); return retval; } @@ -1851,7 +1835,6 @@ static int ci_udc_stop(struct usb_gadget *gadget) unsigned long flags; spin_lock_irqsave(&ci->lock, flags); - ci->driver = NULL; if (ci->vbus_active) { hw_device_state(ci, 0); @@ -1864,6 +1847,7 @@ static int ci_udc_stop(struct usb_gadget *gadget) pm_runtime_put(&ci->gadget.dev); } + ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); ci_udc_stop_for_otg_fsm(ci); @@ -1906,9 +1890,6 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) if (USBi_PCI & intr) { ci->gadget.speed = hw_port_is_high_speed(ci) ? USB_SPEED_HIGH : USB_SPEED_FULL; - if (ci->usb_phy) - usb_phy_set_event(ci->usb_phy, - USB_EVENT_ENUMERATED); if (ci->suspended) { if (ci->driver->resume) { spin_unlock(&ci->lock); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 4730089a771b..59a354822413 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1520,6 +1520,8 @@ skip_countries: acm->nb_index = 0; acm->nb_size = 0; + dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); + acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); @@ -1527,12 +1529,6 @@ skip_countries: usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_set_intfdata(data_interface, acm); - if (quirks & CLEAR_HALT_CONDITIONS) { - /* errors intentionally ignored */ - usb_clear_halt(usb_dev, acm->in); - usb_clear_halt(usb_dev, acm->out); - } - tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor, &control_interface->dev); if (IS_ERR(tty_dev)) { @@ -1540,7 +1536,10 @@ skip_countries: goto alloc_fail6; } - dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); + if (quirks & CLEAR_HALT_CONDITIONS) { + usb_clear_halt(usb_dev, acm->in); + usb_clear_halt(usb_dev, acm->out); + } return 0; alloc_fail6: diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 6afb941dd267..bc925394e881 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -89,6 +89,7 @@ struct wdm_device { u16 wMaxCommand; u16 wMaxPacketSize; __le16 inum; + int reslength; int length; int read; int count; @@ -200,11 +201,6 @@ static void wdm_in_callback(struct urb *urb) if (desc->rerr == 0 && status != -EPIPE) desc->rerr = status; - if (length == 0) { - dev_dbg(&desc->intf->dev, "received ZLP\n"); - goto skip_zlp; - } - if (length + desc->length > desc->wMaxCommand) { /* The buffer would overflow */ set_bit(WDM_OVERFLOW, &desc->flags); @@ -213,18 +209,18 @@ static void wdm_in_callback(struct urb *urb) if (!test_bit(WDM_OVERFLOW, &desc->flags)) { memmove(desc->ubuf + desc->length, desc->inbuf, length); desc->length += length; + desc->reslength = length; } } skip_error: if (desc->rerr) { /* - * If there was a ZLP or an error, userspace may decide to not - * read any data after poll'ing. + * Since there was an error, userspace may decide to not read + * any data after poll'ing. * We should respond to further attempts from the device to send * data, so that we can get unstuck. */ -skip_zlp: schedule_work(&desc->service_outs_intr); } else { set_bit(WDM_READ, &desc->flags); @@ -575,6 +571,15 @@ retry: goto retry; } + if (!desc->reslength) { /* zero length read */ + dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n"); + clear_bit(WDM_READ, &desc->flags); + rv = service_outstanding_interrupt(desc); + spin_unlock_irq(&desc->iuspin); + if (rv < 0) + goto err; + goto retry; + } cntr = desc->length; spin_unlock_irq(&desc->iuspin); } @@ -834,7 +839,7 @@ static void service_interrupt_work(struct work_struct *work) spin_lock_irq(&desc->iuspin); service_outstanding_interrupt(desc); - if (!desc->resp_count && (desc->length || desc->rerr)) { + if (!desc->resp_count) { set_bit(WDM_READ, &desc->flags); wake_up(&desc->wait); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1b477936fa17..44e7c2c39320 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -52,12 +52,6 @@ #define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ #define USB_PING_RESPONSE_TIME 400 /* ns */ -/* - * Give SS hubs 200ms time after wake to train downstream links before - * assuming no port activity and allowing hub to runtime suspend back. - */ -#define USB_SS_PORT_U0_WAKE_TIME 200 /* ms */ - /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -1058,7 +1052,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) goto init2; goto init3; } - kref_get(&hub->kref); /* The superspeed hub except for root hub has to use Hub Depth @@ -1307,17 +1300,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) device_unlock(&hdev->dev); } - if (type == HUB_RESUME && hub_is_superspeed(hub->hdev)) { - /* give usb3 downstream links training time after hub resume */ - usb_autopm_get_interface_no_resume( - to_usb_interface(hub->intfdev)); - - queue_delayed_work(system_power_efficient_wq, - &hub->post_resume_work, - msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); - return; - } - kref_put(&hub->kref, hub_release); } @@ -1336,14 +1318,6 @@ static void hub_init_func3(struct work_struct *ws) hub_activate(hub, HUB_INIT3); } -static void hub_post_resume(struct work_struct *ws) -{ - struct usb_hub *hub = container_of(ws, struct usb_hub, post_resume_work.work); - - usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); - kref_put(&hub->kref, hub_release); -} - enum hub_quiescing_type { HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND }; @@ -1369,7 +1343,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) /* Stop hub_wq and related activity */ del_timer_sync(&hub->irq_urb_retry); - flush_delayed_work(&hub->post_resume_work); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); @@ -1916,7 +1889,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) hub->hdev = hdev; INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); - INIT_DELAYED_WORK(&hub->post_resume_work, hub_post_resume); INIT_WORK(&hub->events, hub_event); spin_lock_init(&hub->irq_urb_lock); timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); @@ -2784,8 +2756,6 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) #define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)(scheme)) -#define DETECT_DISCONNECT_TRIES 5 - #define HUB_ROOT_RESET_TIME 60 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 #define HUB_BH_RESET_TIME 50 @@ -5420,8 +5390,6 @@ static void port_event(struct usb_hub *hub, int port1) struct usb_device *udev = port_dev->child; struct usb_device *hdev = hub->hdev; u16 portstatus, portchange; - int i = 0; - int err; connect_change = test_bit(port1, hub->change_bits); clear_bit(port1, hub->event_bits); @@ -5498,30 +5466,17 @@ static void port_event(struct usb_hub *hub, int port1) connect_change = 1; /* - * Avoid trying to recover a USB3 SS.Inactive port with a warm reset if - * the device was disconnected. A 12ms disconnect detect timer in - * SS.Inactive state transitions the port to RxDetect automatically. - * SS.Inactive link error state is common during device disconnect. + * Warm reset a USB3 protocol port if it's in + * SS.Inactive state. */ - while (hub_port_warm_reset_required(hub, port1, portstatus)) { - if ((i++ < DETECT_DISCONNECT_TRIES) && udev) { - u16 unused; - - msleep(20); - hub_port_status(hub, port1, &portstatus, &unused); - dev_dbg(&port_dev->dev, "Wait for inactive link disconnect detect\n"); - continue; - } else if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) + if (hub_port_warm_reset_required(hub, port1, portstatus)) { + dev_dbg(&port_dev->dev, "do warm reset\n"); + if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) || udev->state == USB_STATE_NOTATTACHED) { - dev_dbg(&port_dev->dev, "do warm reset, port only\n"); - err = hub_port_reset(hub, port1, NULL, - HUB_BH_RESET_TIME, true); - if (!udev && err == -ENOTCONN) - connect_change = 0; - else if (err < 0) + if (hub_port_reset(hub, port1, NULL, + HUB_BH_RESET_TIME, true) < 0) hub_port_disable(hub, port1, 1); } else { - dev_dbg(&port_dev->dev, "do warm reset, full device\n"); usb_unlock_port(port_dev); usb_lock_device(udev); usb_reset_device(udev); @@ -5529,7 +5484,6 @@ static void port_event(struct usb_hub *hub, int port1) usb_lock_port(port_dev); connect_change = 0; } - break; } if (connect_change) diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index de29ce856953..1c455800f7d3 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,7 +69,6 @@ struct usb_hub { u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; struct delayed_work init_work; - struct delayed_work post_resume_work; struct work_struct events; spinlock_t irq_urb_lock; struct timer_list irq_urb_retry; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index aa6c9a6810b9..98b1c457a091 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -224,8 +224,7 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, /* Logitech HD Webcam C270 */ - { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME | - USB_QUIRK_NO_LPM}, + { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, /* Logitech HD Pro Webcams C920, C920-C, C922, C925e and C930e */ { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -368,7 +367,6 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM }, /* SanDisk Corp. SanDisk 3.2Gen1 */ - { USB_DEVICE(0x0781, 0x5596), .driver_info = USB_QUIRK_DELAY_INIT }, { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, /* SanDisk Extreme 55AE */ @@ -462,8 +460,6 @@ static const struct usb_device_id usb_quirk_list[] = { /* Huawei 4G LTE module */ { USB_DEVICE(0x12d1, 0x15bb), .driver_info = USB_QUIRK_DISCONNECT_SUSPEND }, - { USB_DEVICE(0x12d1, 0x15c1), .driver_info = - USB_QUIRK_DISCONNECT_SUSPEND }, { USB_DEVICE(0x12d1, 0x15c3), .driver_info = USB_QUIRK_DISCONNECT_SUSPEND }, @@ -730,7 +726,7 @@ void usb_detect_quirks(struct usb_device *udev) udev->quirks ^= usb_detect_dynamic_quirks(udev); if (udev->quirks) - dev_dbg(&udev->dev, "USB quirks for this device: 0x%x\n", + dev_dbg(&udev->dev, "USB quirks for this device: %x\n", udev->quirks); #ifdef CONFIG_USB_DEFAULT_PERSIST diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index e60f4ef06e3d..850d0fffe1c6 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -490,7 +490,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* Check that the pipe's type matches the endpoint's type */ if (usb_pipe_type_check(urb->dev, urb->pipe)) - dev_warn_once(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", + dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); /* Check against a simple/standard policy */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 571ab8e0c759..502d911f71fa 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -717,16 +717,15 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev_set_name(&dev->dev, "usb%d", bus->busnum); root_hub = 1; } else { - int n; - /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') { - n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1); + snprintf(dev->devpath, sizeof dev->devpath, + "%d", port1); /* Root ports are not counted in route string */ dev->route = 0; } else { - n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d", - parent->devpath, port1); + snprintf(dev->devpath, sizeof dev->devpath, + "%s.%d", parent->devpath, port1); /* Route string assumes hubs have less than 16 ports */ if (port1 < 15) dev->route = parent->route + @@ -735,11 +734,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->route = parent->route + (15 << ((parent->level - 1)*4)); } - if (n >= sizeof(dev->devpath)) { - usb_put_hcd(bus_to_hcd(bus)); - usb_put_dev(dev); - return NULL; - } dev->dev.parent = &parent->dev; dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 9bb1edb81d6e..8a3ec1a951fe 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -529,9 +529,6 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev) usb_role_switch_unregister(priv->role_switch); - put_device(priv->switch_desc.udc); - put_device(priv->switch_desc.usb2_port); - of_platform_depopulate(dev); for (i = 0 ; i < PHY_COUNT ; ++i) { diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 8be05c7fc98b..742be1e07a01 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -615,13 +615,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev) ret = reset_control_deassert(qcom->resets); if (ret) { dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret); - return ret; + goto reset_assert; } ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); if (ret) { dev_err(dev, "failed to get clocks\n"); - return ret; + goto reset_assert; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -700,6 +700,8 @@ clk_disable: clk_disable_unprepare(qcom->clks[i]); clk_put(qcom->clks[i]); } +reset_assert: + reset_control_assert(qcom->resets); return ret; } @@ -723,6 +725,8 @@ static int dwc3_qcom_remove(struct platform_device *pdev) } qcom->num_clocks = 0; + reset_control_assert(qcom->resets); + pm_runtime_allow(dev); pm_runtime_disable(dev); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 73608332d78d..76316205483b 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2937,15 +2937,6 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep, static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { - /* - * During a device-initiated disconnect, a late xferNotReady event can - * be generated after the End Transfer command resets the event filter, - * but before the controller is halted. Ignore it to prevent a new - * transfer from starting. - */ - if (!dep->dwc->connected) - return; - dwc3_gadget_endpoint_frame_from_event(dep, event); (void) __dwc3_gadget_start_isoc(dep); } diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 7673ded077a4..5a462a1d1896 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -678,10 +678,6 @@ int __init early_xdbc_setup_hardware(void) xdbc.table_base = NULL; xdbc.out_buf = NULL; - - early_iounmap(xdbc.xhci_base, xdbc.xhci_length); - xdbc.xhci_base = NULL; - xdbc.xhci_length = 0; } return ret; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 55597a898f40..4b2e9df97b11 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2241,11 +2241,6 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, if (!cdev->os_desc_req->buf) { ret = -ENOMEM; usb_ep_free_request(ep0, cdev->os_desc_req); - /* - * Set os_desc_req to NULL so that composite_dev_cleanup() - * will not try to free it again. - */ - cdev->os_desc_req = NULL; goto end; } cdev->os_desc_req->context = cdev; diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index e3f200f05a4e..cfae163e6502 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -888,8 +888,6 @@ static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page, struct gadget_info *gi = os_desc_item_to_gadget_info(item); int res, l; - if (!len) - return len; l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); if (page[l - 1] == '\n') --l; @@ -1391,8 +1389,6 @@ static int configfs_composite_bind(struct usb_gadget *gadget, cdev->use_os_string = true; cdev->b_vendor_code = gi->b_vendor_code; memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); - } else { - cdev->use_os_string = false; } if (gadget_is_otg(gadget) && !otg_desc[0]) { diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e0a35dc19e45..9b5f9d503ff0 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2012,12 +2012,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) ep = func->eps; epfile = ffs->epfiles; count = ffs->eps_count; - if (!epfile) { - ret = -ENOMEM; - goto done; - } - - while (count--) { + while(count--) { ep->ep->driver_data = ep; ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); @@ -2041,7 +2036,6 @@ static int ffs_func_eps_enable(struct ffs_function *func) } wake_up_interruptible(&ffs->wait); -done: spin_unlock_irqrestore(&func->ffs->eps_lock, flags); return ret; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index cea9157ea2b4..77354626252c 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -496,7 +496,7 @@ try_again: } req->status = 0; - req->zero = 1; + req->zero = 0; req->length = count; req->complete = f_hidg_req_complete; req->context = hidg; @@ -767,7 +767,7 @@ stall: return -EOPNOTSUPP; respond: - req->zero = 1; + req->zero = 0; req->length = length; status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); if (status < 0) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index b1e569337382..ca50257b9538 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1472,8 +1472,6 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) ncm_opts->bound = true; - ncm_string_defs[1].s = ncm->ethaddr; - us = usb_gstrings_attach(cdev, ncm_strings, ARRAY_SIZE(ncm_string_defs)); if (IS_ERR(us)) { @@ -1737,6 +1735,7 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi) mutex_unlock(&opts->lock); return ERR_PTR(-EINVAL); } + ncm_string_defs[STRING_MAC_IDX].s = ncm->ethaddr; spin_lock_init(&ncm->lock); ncm_reset_values(ncm); diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 48d02c5ff849..90fe33f9e095 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1320,14 +1320,14 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn, struct usbg_tport *tport = container_of(wwn, struct usbg_tport, tport_wwn); struct usbg_tpg *tpg; - u16 tpgt; + unsigned long tpgt; int ret; struct f_tcm_opts *opts; unsigned i; if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtou16(name + 5, 0, &tpgt)) + if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX) return ERR_PTR(-EINVAL); ret = -ENODEV; mutex_lock(&tpg_instances_lock); diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index fc67797a0095..d432f96ec419 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -286,8 +286,8 @@ __acquires(&port->port_lock) break; } - if (do_tty_wake) - tty_port_tty_wakeup(&port->port); + if (do_tty_wake && port->port.tty) + tty_wakeup(port->port.tty); return status; } @@ -564,7 +564,7 @@ static int gs_start_io(struct gs_port *port) gs_start_tx(port); /* Unblock any pending writes into our circular buffer, in case * we didn't in gs_start_tx() */ - tty_port_tty_wakeup(&port->port); + tty_wakeup(port->port.tty); } else { /* Free reqs only if we are still connected */ if (port->port_usb) { diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 55f40902bfd4..730f15fd92c2 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -748,7 +748,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) struct dummy *dum; int retval = -EINVAL; unsigned long flags; - struct dummy_request *req = NULL, *iter; + struct dummy_request *req = NULL; if (!_ep || !_req) return retval; @@ -758,26 +758,25 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) if (!dum->driver) return -ESHUTDOWN; - spin_lock_irqsave(&dum->lock, flags); - list_for_each_entry(iter, &ep->queue, queue) { - if (&iter->req != _req) - continue; - list_del_init(&iter->queue); - _req->status = -ECONNRESET; - req = iter; - retval = 0; - break; + local_irq_save(flags); + spin_lock(&dum->lock); + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) { + list_del_init(&req->queue); + _req->status = -ECONNRESET; + retval = 0; + break; + } } + spin_unlock(&dum->lock); if (retval == 0) { dev_dbg(udc_dev(dum), "dequeued req %p from %s, len %d buf %p\n", req, _ep->name, _req->length, _req->buf); - spin_unlock(&dum->lock); usb_gadget_giveback_request(_ep, _req); - spin_lock(&dum->lock); } - spin_unlock_irqrestore(&dum->lock, flags); + local_irq_restore(flags); return retval; } diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 90114c09a711..2952e5feb2ee 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -2551,7 +2551,6 @@ static int renesas_usb3_remove(struct platform_device *pdev) struct renesas_usb3 *usb3 = platform_get_drvdata(pdev); debugfs_remove_recursive(usb3->dentry); - put_device(usb3->host_dev); device_remove_file(&pdev->dev, &dev_attr_role); cancel_work_sync(&usb3->role_work); diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index cfdbe90f867e..5a21777197e9 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1925,7 +1925,7 @@ error: if (hcd) { kfree(max3421_hcd->tx); kfree(max3421_hcd->rx); - if (!IS_ERR_OR_NULL(max3421_hcd->spi_thread)) + if (max3421_hcd->spi_thread) kthread_stop(max3421_hcd->spi_thread); usb_put_hcd(hcd); } diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 4e65ebbaa09b..93e2cca5262d 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -975,15 +975,8 @@ int xhci_dbc_suspend(struct xhci_hcd *xhci) if (!dbc) return 0; - switch (dbc->state) { - case DS_ENABLED: - case DS_CONNECTED: - case DS_CONFIGURED: + if (dbc->state == DS_CONFIGURED) dbc->resume_required = 1; - break; - default: - break; - } xhci_dbc_stop(xhci); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 2c9015f2a7d3..66cb9f08bff1 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -628,7 +628,8 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, if (!xhci->devs[i]) continue; - retval = xhci_disable_and_free_slot(xhci, i); + retval = xhci_disable_slot(xhci, i); + xhci_free_virt_device(xhci, i); if (retval) xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n", i, retval); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4f4c4cae99c4..b3ee977fab99 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -879,20 +879,21 @@ free_tts: * will be manipulated by the configure endpoint, allocate device, or update * hub functions while this function is removing the TT entries from the list. */ -void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, - int slot_id) +void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) { + struct xhci_virt_device *dev; int i; int old_active_eps = 0; /* Slot ID 0 is reserved */ - if (slot_id == 0 || !dev) + if (slot_id == 0 || !xhci->devs[slot_id]) return; - /* If device ctx array still points to _this_ device, clear it */ - if (dev->out_ctx && - xhci->dcbaa->dev_context_ptrs[slot_id] == cpu_to_le64(dev->out_ctx->dma)) - xhci->dcbaa->dev_context_ptrs[slot_id] = 0; + dev = xhci->devs[slot_id]; + + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; + if (!dev) + return; trace_xhci_free_virt_device(dev); @@ -931,9 +932,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, if (dev->udev && dev->udev->slot_id) dev->udev->slot_id = 0; - if (xhci->devs[slot_id] == dev) - xhci->devs[slot_id] = NULL; - kfree(dev); + kfree(xhci->devs[slot_id]); + xhci->devs[slot_id] = NULL; } /* @@ -975,7 +975,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i out: /* we are now at a leaf device */ xhci_debugfs_remove_slot(xhci, slot_id); - xhci_free_virt_device(xhci, vdev, slot_id); + xhci_free_virt_device(xhci, slot_id); } int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, @@ -1214,8 +1214,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | dev->eps[0].ring->cycle_state); - ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8)); - trace_xhci_setup_addressable_virt_device(dev); /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 85a39a4b85ce..fa320006b04d 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -222,7 +222,6 @@ static int xhci_plat_probe(struct platform_device *pdev) } pm_runtime_set_active(&pdev->dev); - pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); @@ -334,8 +333,7 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4 && - !(xhci->quirks & XHCI_BROKEN_STREAMS)) + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) xhci->shared_hcd->can_do_streams = 1; ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 845bbf3d7a7b..086c567ca7d0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -971,15 +971,12 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, */ void xhci_hc_died(struct xhci_hcd *xhci) { - bool notify; int i, j; if (xhci->xhc_state & XHCI_STATE_DYING) return; - notify = !(xhci->xhc_state & XHCI_STATE_REMOVING); - if (notify) - xhci_err(xhci, "xHCI host controller not responding, assume dead\n"); + xhci_err(xhci, "xHCI host controller not responding, assume dead\n"); xhci->xhc_state |= XHCI_STATE_DYING; xhci_cleanup_command_queue(xhci); @@ -993,7 +990,7 @@ void xhci_hc_died(struct xhci_hcd *xhci) } /* inform usb core hc died if PCI remove isn't already handling it */ - if (notify) + if (!(xhci->xhc_state & XHCI_STATE_REMOVING)) usb_hc_died(xhci_to_hcd(xhci)); } @@ -1256,8 +1253,7 @@ static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, command->slot_id = 0; } -static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id, - u32 cmd_comp_code) +static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) { struct xhci_virt_device *virt_dev; struct xhci_slot_ctx *slot_ctx; @@ -1272,10 +1268,6 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id, if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) /* Delete default control endpoint resources */ xhci_free_device_endpoint_resources(xhci, virt_dev, true); - if (cmd_comp_code == COMP_SUCCESS) { - xhci->dcbaa->dev_context_ptrs[slot_id] = 0; - xhci->devs[slot_id] = NULL; - } } static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, @@ -1515,7 +1507,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci_handle_cmd_enable_slot(xhci, slot_id, cmd, cmd_comp_code); break; case TRB_DISABLE_SLOT: - xhci_handle_cmd_disable_slot(xhci, slot_id, cmd_comp_code); + xhci_handle_cmd_disable_slot(xhci, slot_id); break; case TRB_CONFIG_EP: if (!cmd->completion) @@ -4082,8 +4074,7 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, if ((xhci->xhc_state & XHCI_STATE_DYING) || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "xHCI dying or halted, can't queue_command. state: 0x%x\n", - xhci->xhc_state); + xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n"); return -ESHUTDOWN; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ba0223d5f4a1..dfc406be0856 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -118,8 +118,7 @@ int xhci_halt(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); if (ret) { - if (!(xhci->xhc_state & XHCI_STATE_DYING)) - xhci_warn(xhci, "Host halt failed, %d\n", ret); + xhci_warn(xhci, "Host halt failed, %d\n", ret); return ret; } xhci->xhc_state |= XHCI_STATE_HALTED; @@ -176,8 +175,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) state = readl(&xhci->op_regs->status); if (state == ~(u32)0) { - if (!(xhci->xhc_state & XHCI_STATE_DYING)) - xhci_warn(xhci, "Host not accessible, reset failed.\n"); + xhci_warn(xhci, "Host not accessible, reset failed.\n"); return -ENODEV; } @@ -3947,7 +3945,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_disable_slot(xhci, udev->slot_id); spin_lock_irqsave(&xhci->lock, flags); - xhci_free_virt_device(xhci, virt_dev, udev->slot_id); + xhci_free_virt_device(xhci, udev->slot_id); spin_unlock_irqrestore(&xhci->lock, flags); } @@ -3996,16 +3994,6 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) return ret; } -int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id) -{ - struct xhci_virt_device *vdev = xhci->devs[slot_id]; - int ret; - - ret = xhci_disable_slot(xhci, slot_id); - xhci_free_virt_device(xhci, vdev, slot_id); - return ret; -} - /* * Checks if we have enough host controller resources for the default control * endpoint. @@ -4111,7 +4099,8 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) return 1; disable_slot: - xhci_disable_and_free_slot(xhci, udev->slot_id); + xhci_disable_slot(xhci, udev->slot_id); + xhci_free_virt_device(xhci, udev->slot_id); return 0; } @@ -4240,7 +4229,8 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, dev_warn(&udev->dev, "Device not responding to setup %s.\n", act); mutex_unlock(&xhci->mutex); - ret = xhci_disable_and_free_slot(xhci, udev->slot_id); + ret = xhci_disable_slot(xhci, udev->slot_id); + xhci_free_virt_device(xhci, udev->slot_id); if (!ret) { if (xhci_alloc_dev(hcd, udev) == 1) xhci_setup_addressable_virt_dev(xhci, udev); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 1cb97df1e8b0..421bc7ad413e 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1992,7 +1992,7 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *), /* xHCI memory management */ void xhci_mem_cleanup(struct xhci_hcd *xhci); int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); -void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, int slot_id); +void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, @@ -2082,7 +2082,6 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); -int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id); int xhci_ext_cap_init(struct xhci_hcd *xhci); int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 93998d328d9a..35483217b1f6 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -68,20 +68,18 @@ * The magic limit was calculated so that it allows the monitoring * application to pick data once in two ticks. This way, another application, * which presumably drives the bus, gets to hog CPU, yet we collect our data. - * - * Originally, for a 480 Mbit/s bus this required a buffer of about 1 MB. For - * modern 20 Gbps buses, this value increases to over 50 MB. The maximum - * buffer size is set to 64 MiB to accommodate this. + * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an + * enormous overhead built into the bus protocol, so we need about 1000 KB. * * This is still too much for most cases, where we just snoop a few * descriptor fetches for enumeration. So, the default is a "reasonable" - * amount for typical, low-throughput use cases. + * amount for systems with HZ=250 and incomplete bus saturation. * * XXX What about multi-megabyte URBs which take minutes to transfer? */ -#define BUFF_MAX CHUNK_ALIGN(64*1024*1024) -#define BUFF_DFL CHUNK_ALIGN(300*1024) -#define BUFF_MIN CHUNK_ALIGN(8*1024) +#define BUFF_MAX CHUNK_ALIGN(1200*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) /* * The per-event API header (2 per URB). diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index efb70b5c9e8e..b8fc818c154a 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1910,7 +1910,6 @@ static int musb_gadget_stop(struct usb_gadget *g) * gadget driver here and have everything work; * that currently misbehaves. */ - usb_gadget_set_state(g, USB_STATE_NOTATTACHED); /* Force check of devctl register for PM runtime */ schedule_delayed_work(&musb->irq_work, 0); @@ -2019,7 +2018,6 @@ void musb_g_disconnect(struct musb *musb) case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: musb->xceiv->otg->state = OTG_STATE_B_IDLE; - usb_gadget_set_state(&musb->g, USB_STATE_NOTATTACHED); break; case OTG_STATE_B_SRP_INIT: break; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 76b7ac1103ab..8def19fc5025 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -476,13 +476,13 @@ static int omap2430_probe(struct platform_device *pdev) ARRAY_SIZE(musb_resources)); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err_put_control_otghs; + goto err2; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err_put_control_otghs; + goto err2; } pm_runtime_enable(glue->dev); @@ -497,9 +497,7 @@ static int omap2430_probe(struct platform_device *pdev) err3: pm_runtime_disable(glue->dev); -err_put_control_otghs: - if (!IS_ERR(glue->control_otghs)) - put_device(glue->control_otghs); + err2: platform_device_put(musb); @@ -513,8 +511,6 @@ static int omap2430_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); pm_runtime_disable(glue->dev); - if (!IS_ERR(glue->control_otghs)) - put_device(glue->control_otghs); return 0; } diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 7c81ccaaf2e9..6dfecbd47d7a 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -394,7 +394,6 @@ static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy) static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) { bool vbus_is_on = false; - enum usb_phy_events last_event = mxs_phy->phy.last_event; /* If the SoCs don't need to disconnect line without vbus, quit */ if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS)) @@ -406,8 +405,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) vbus_is_on = mxs_phy_get_vbus_status(mxs_phy); - if (on && ((!vbus_is_on && !mxs_phy_is_otg_host(mxs_phy)) - || (last_event == USB_EVENT_VBUS))) + if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy)) __mxs_phy_disconnect_line(mxs_phy, true); else __mxs_phy_disconnect_line(mxs_phy, false); diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 607c3f18356a..9337c30f0743 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -328,8 +328,9 @@ static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled) static int twl6030_usb_probe(struct platform_device *pdev) { + u32 ret; struct twl6030_usb *twl; - int status, err, ret; + int status, err; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ee01061b413c..d13b8e35ce33 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -781,8 +781,6 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, - { USB_DEVICE(FTDI_NDI_VID, FTDI_NDI_EMGUIDE_GEMINI_PID), - .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) }, { USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 324065cc352c..9c95ca876bae 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -197,9 +197,6 @@ #define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ #define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ -#define FTDI_NDI_VID 0x23F2 -#define FTDI_NDI_EMGUIDE_GEMINI_PID 0x0003 /* NDI Emguide Gemini */ - /* * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 4a93bfbe4c6c..08d70256e72e 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -273,7 +273,6 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EM05CN 0x0312 #define QUECTEL_PRODUCT_EM05G_GR 0x0313 #define QUECTEL_PRODUCT_EM05G_RS 0x0314 -#define QUECTEL_PRODUCT_RG255C 0x0316 #define QUECTEL_PRODUCT_EM12 0x0512 #define QUECTEL_PRODUCT_RM500Q 0x0800 #define QUECTEL_PRODUCT_RM520N 0x0801 @@ -618,7 +617,6 @@ static void option_instat_callback(struct urb *urb); #define UNISOC_VENDOR_ID 0x1782 /* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */ #define TOZED_PRODUCT_LT70C 0x4055 -#define UNISOC_PRODUCT_UIS7720 0x4064 /* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */ #define LUAT_PRODUCT_AIR720U 0x4e00 @@ -1272,9 +1270,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x30) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x40) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, @@ -1327,18 +1322,7 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff), /* Telit LE910C1-EUX (ECM) */ .driver_info = NCTRL(0) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1034, 0xff), /* Telit LE910C4-WWX (rmnet) */ - .driver_info = RSVD(2) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1035, 0xff) }, /* Telit LE910C4-WWX (ECM) */ - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1036, 0xff) }, /* Telit LE910C4-WWX */ - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1037, 0xff), /* Telit LE910C4-WWX (rmnet) */ - .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1038, 0xff), /* Telit LE910C4-WWX (rmnet) */ - .driver_info = NCTRL(0) | RSVD(3) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103b, 0xff), /* Telit LE910C4-WWX */ - .driver_info = NCTRL(0) | NCTRL(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103c, 0xff), /* Telit LE910C4-WWX */ - .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1), @@ -1385,12 +1369,6 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990A (PCIe) */ .driver_info = RSVD(0) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1077, 0xff), /* Telit FN990A (rmnet + audio) */ - .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1078, 0xff), /* Telit FN990A (MBIM + audio) */ - .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1079, 0xff), /* Telit FN990A (RNDIS + audio) */ - .driver_info = NCTRL(2) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990A (rmnet) */ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990A (MBIM) */ @@ -1403,14 +1381,10 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a2, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(4) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a3, 0xff), /* Telit FN920C04 (ECM) */ - .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a4, 0xff), /* Telit FN20C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a7, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(4) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a8, 0xff), /* Telit FN920C04 (ECM) */ - .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a9, 0xff), /* Telit FN20C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff), /* Telit FN920C04 (MBIM) */ @@ -1441,9 +1415,6 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(5) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x60) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x30), /* Telit FE910C04 (ECM) */ - .driver_info = NCTRL(4) }, - { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x30), /* Telit FN990B (MBIM) */ .driver_info = NCTRL(6) }, { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x40) }, @@ -2123,12 +2094,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */ .driver_info = RSVD(7) }, - { USB_DEVICE(0x1e0e, 0x9071), /* Simcom SIM8230 RMNET mode */ - .driver_info = RSVD(3) | RSVD(4) }, - { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9078, 0xff), /* Simcom SIM8230 ECM mode */ - .driver_info = RSVD(5) }, - { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x907b, 0xff), /* Simcom SIM8230 RNDIS mode */ - .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9205, 0xff) }, /* Simcom SIM7070/SIM7080/SIM7090 AT+ECM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9206, 0xff) }, /* Simcom SIM7070/SIM7080/SIM7090 AT-only mode */ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), @@ -2378,10 +2343,6 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe145, 0xff), /* Foxconn T99W651 RNDIS */ .driver_info = RSVD(5) | RSVD(6) }, - { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe15f, 0xff), /* Foxconn T99W709 */ - .driver_info = RSVD(5) }, - { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ - .driver_info = RSVD(3) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */ @@ -2475,7 +2436,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, UNISOC_PRODUCT_UIS7720, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff), /* TCL IK512 MBIM */ .driver_info = NCTRL(1) }, diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index a026c6cb6e68..0c423916d7bf 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -252,7 +252,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, return USB_STOR_TRANSPORT_ERROR; } - residue = le32_to_cpu(bcs->Residue); + residue = bcs->Residue; if (bcs->Tag != us->tag) return USB_STOR_TRANSPORT_ERROR; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 509e4e155f41..a6dc2faae85d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -934,13 +934,6 @@ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SANE_SENSE ), -/* Added by Maël GUERIN */ -UNUSUAL_DEV( 0x0603, 0x8611, 0x0000, 0xffff, - "Novatek", - "NTK96550-based camera", - USB_SC_SCSI, USB_PR_BULK, NULL, - US_FL_BULK_IGNORE_TAG ), - /* * Reported by Hanno Boeck * Taken from the Lycoris Kernel @@ -1490,28 +1483,6 @@ UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_WP_DETECT ), -/* - * Reported by Zenm Chen - * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch - * the device into Wi-Fi mode. - */ -UNUSUAL_DEV( 0x0bda, 0x1a2b, 0x0000, 0xffff, - "Realtek", - "DISK", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_DEVICE ), - -/* - * Reported by Zenm Chen - * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch - * the device into Wi-Fi mode. - */ -UNUSUAL_DEV( 0x0bda, 0xa192, 0x0000, 0xffff, - "Realtek", - "DISK", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_DEVICE ), - UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999, "Maxtor", "USB to SATA", diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 464fd15e12ad..a2a1baabca93 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -288,9 +288,6 @@ static int dp_altmode_vdm(struct typec_altmode *alt, break; case CMDT_RSP_NAK: switch (cmd) { - case DP_CMD_STATUS_UPDATE: - dp->state = DP_STATE_EXIT; - break; case DP_CMD_CONFIGURE: dp->data.conf = 0; ret = dp_altmode_configured(dp); @@ -491,7 +488,7 @@ static ssize_t pin_assignment_show(struct device *dev, assignments = get_current_pin_assignments(dp); - for (i = 0; assignments && i < DP_PIN_ASSIGN_MAX; assignments >>= 1, i++) { + for (i = 0; assignments; assignments >>= 1, i++) { if (assignments & 1) { if (i == cur) len += sprintf(buf + len, "[%s] ", diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 9d242c5213e1..5e661bae3997 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -104,7 +104,6 @@ struct fusb302_chip { bool vconn_on; bool vbus_on; bool charge_on; - bool pd_rx_on; bool vbus_present; enum typec_cc_polarity cc_polarity; enum typec_cc_status cc1; @@ -842,11 +841,6 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) int ret = 0; mutex_lock(&chip->lock); - if (chip->pd_rx_on == on) { - fusb302_log(chip, "pd is already %s", on ? "on" : "off"); - goto done; - } - ret = fusb302_pd_rx_flush(chip); if (ret < 0) { fusb302_log(chip, "cannot flush pd rx buffer, ret=%d", ret); @@ -869,8 +863,6 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) on ? "on" : "off", ret); goto done; } - - chip->pd_rx_on = on; fusb302_log(chip, "pd := %s", on ? "on" : "off"); done: mutex_unlock(&chip->lock); diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index d31b7e5895ce..ee8fa558e3ed 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -765,17 +765,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ctrlreq->wValue, vdev->rhport); vdev->udev = usb_get_dev(urb->dev); - /* - * NOTE: A similar operation has been done via - * USB_REQ_GET_DESCRIPTOR handler below, which is - * supposed to always precede USB_REQ_SET_ADDRESS. - * - * It's not entirely clear if operating on a different - * usb_device instance here is a real possibility, - * otherwise this call and vdev->udev assignment above - * should be dropped. - */ - dev_pm_syscore_device(&vdev->udev->dev, true); usb_put_dev(old); spin_lock(&vdev->ud.lock); @@ -796,17 +785,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n"); vdev->udev = usb_get_dev(urb->dev); - /* - * Set syscore PM flag for the virtually attached - * devices to ensure they will not enter suspend on - * the client side. - * - * Note this doesn't have any impact on the physical - * devices attached to the host system on the server - * side, hence there is no need to undo the operation - * on disconnect. - */ - dev_pm_syscore_device(&vdev->udev->dev, true); usb_put_dev(old); goto out; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 54167a2d28ea..edd89b7c8f18 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -67,7 +67,6 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 #define CI_HDRC_IMX_HSIC_ACTIVE_EVENT 2 #define CI_HDRC_IMX_HSIC_SUSPEND_EVENT 3 -#define CI_HDRC_CONTROLLER_VBUS_EVENT 4 int (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h index afb73b3e0b80..296909ea04f2 100644 --- a/include/linux/usb/typec_dp.h +++ b/include/linux/usb/typec_dp.h @@ -56,7 +56,6 @@ enum { DP_PIN_ASSIGN_D, DP_PIN_ASSIGN_E, DP_PIN_ASSIGN_F, /* Not supported after v1.0b */ - DP_PIN_ASSIGN_MAX, }; /* DisplayPort alt mode specific commands */ From 7e703907b400cad6f1ca69cc0746a5f6a6d18d6e Mon Sep 17 00:00:00 2001 From: Gaurav Singh Date: Wed, 14 Jan 2026 06:28:33 -0800 Subject: [PATCH 202/306] msm:kgsl: Prevent sign extension on alignments Currently we allow alignments from userland which eventually can be sign extended which cause havoc down in the memory management routines. Fix the issue by changing the return type of kgsl_memdesc_get_align in case we use it differently in the future and expliticly start with a unsigned type for bit shifts. Change-Id: I03ad7e260434a5b5a3ea08c006128bc59cbcd617 Signed-off-by: Scott Bauer Signed-off-by: Gaurav Singh --- drivers/gpu/msm/kgsl.c | 10 +++++----- drivers/gpu/msm/kgsl.h | 4 +++- drivers/gpu/msm/kgsl_debugfs.c | 3 ++- drivers/gpu/msm/kgsl_iommu.c | 5 ++--- drivers/gpu/msm/kgsl_sharedmem.h | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index ff7e3e5468ea..d10d6dbac3db 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -4054,9 +4054,9 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private, return addr; } -static unsigned long get_align(struct kgsl_mem_entry *entry) +unsigned long kgsl_get_align(struct kgsl_memdesc *memdesc) { - int bit = kgsl_memdesc_get_align(&entry->memdesc); + u32 bit = kgsl_memdesc_get_align(memdesc); if (bit >= ilog2(SZ_2M)) return SZ_2M; @@ -4065,7 +4065,7 @@ static unsigned long get_align(struct kgsl_mem_entry *entry) else if (bit >= ilog2(SZ_64K)) return SZ_64K; - return SZ_4K; + return PAGE_SIZE; } static unsigned long set_svm_area(struct file *file, @@ -4098,7 +4098,7 @@ static unsigned long get_svm_unmapped_area(struct file *file, { struct kgsl_device_private *dev_priv = file->private_data; struct kgsl_process_private *private = dev_priv->process_priv; - unsigned long align = get_align(entry); + unsigned long align = kgsl_get_align(&entry->memdesc); unsigned long ret, iova; u64 start = 0, end = 0; struct vm_area_struct *vma; diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h index 0f0721522574..4698aacf94cf 100644 --- a/drivers/gpu/msm/kgsl.h +++ b/drivers/gpu/msm/kgsl.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2008-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef __KGSL_H #define __KGSL_H @@ -473,6 +473,8 @@ void kgsl_mmu_remove_global(struct kgsl_device *device, struct kgsl_memdesc *memdesc); /* Helper functions */ +unsigned long kgsl_get_align(struct kgsl_memdesc *memdesc); + int kgsl_request_irq(struct platform_device *pdev, const char *name, irq_handler_t handler, void *data); diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index a90636a16f82..1298f6247c9e 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2002,2008-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -146,7 +147,7 @@ static const char *memtype_str(int memtype) static char get_alignflag(const struct kgsl_memdesc *m) { - int align = kgsl_memdesc_get_align(m); + u32 align = kgsl_memdesc_get_align(m); if (align >= ilog2(SZ_1M)) return 'L'; diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 690ffe008811..25a5750e452a 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -2229,8 +2229,7 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable, size = kgsl_memdesc_footprint(memdesc); - align = max_t(uint64_t, 1 << kgsl_memdesc_get_align(memdesc), - PAGE_SIZE); + align = kgsl_get_align(memdesc); if (memdesc->flags & KGSL_MEMFLAGS_FORCE_32BIT) { start = pt->compat_va_start; diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h index 389fd86078ff..1f55ffcfb265 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.h +++ b/drivers/gpu/msm/kgsl_sharedmem.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2002,2007-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef __KGSL_SHAREDMEM_H #define __KGSL_SHAREDMEM_H @@ -157,7 +158,7 @@ void kgsl_free_globals(struct kgsl_device *device); * * Returns the alignment requested, as power of 2 exponent. */ -static inline int +static inline u32 kgsl_memdesc_get_align(const struct kgsl_memdesc *memdesc) { return MEMFLAGS(memdesc->flags, KGSL_MEMALIGN_MASK, From af20c219259af1342affe777c8cf9bce55c24b49 Mon Sep 17 00:00:00 2001 From: angelomds42 Date: Fri, 10 Apr 2026 20:20:24 -0300 Subject: [PATCH 203/306] Makefile: Fix LLVM_IAS condition after IAS default flip The commit 01ecebdbac6e ("BACKPORT: scripts/Makefile.clang: default to LLVM_IAS=1") flipped LLVM_IAS to opt-out but did not update the ifneq ($(LLVM_IAS),1) condition introduced by 2f5d594440ac ("FROMLIST: Kbuild: do not emit debug info for assembly with LLVM_IAS=1"), causing warnings when LLVM_IAS is unset: warning: DWARF2 only supports one section per compilation unit Fixes: 01ecebdbac6e ("BACKPORT: scripts/Makefile.clang: default to LLVM_IAS=1") Change-Id: If373071466d851ee8d814751f9bc4672e68aaf34 --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 4593e9d0cdde..29d4cff5f7de 100644 --- a/Makefile +++ b/Makefile @@ -871,10 +871,10 @@ DEBUG_CFLAGS += -gsplit-dwarf else DEBUG_CFLAGS += -g endif -ifeq ($(LLVM_IAS),1) -KBUILD_AFLAGS += -g -else +ifeq ($(LLVM_IAS),0) KBUILD_AFLAGS += -Wa,-gdwarf-2 +else +KBUILD_AFLAGS += -g endif endif From af92965dcbdfa38a0fa43c1ed33659906328a8d8 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Thu, 30 Apr 2026 21:06:21 +0300 Subject: [PATCH 204/306] usb: Undo qcom damage Revert "reverting all USB patches" This reverts commit 365834436c0aa0f53cd5a0901deebf652859cfef. Conflicts: drivers/usb/core/quirks.c drivers/usb/dwc3/dwc3-qcom.c drivers/usb/host/xhci-plat.c drivers/usb/serial/option.c Partially revert "reverting enum-conversion, Handle CPU state and all USB patches" This partially reverts commit 2c3bda25f8d797fe3b81218180bc8778e06b74b9. Conflicts: drivers/usb/core/quirks.c drivers/usb/dwc3/gadget.c drivers/usb/gadget/function/f_fs.c drivers/usb/serial/option.c Change-Id: I89f5ca04b3306fddb8b9ebd5382ec495ff9e1030 --- drivers/hid/hid-hyperv.c | 5 +- drivers/hid/usbhid/hid-core.c | 25 +-- drivers/usb/atm/cxacru.c | 185 +++++++++++------------ drivers/usb/cdns3/gadget.c | 2 + drivers/usb/chipidea/ci.h | 18 ++- drivers/usb/chipidea/ci_hdrc_imx.c | 42 ++--- drivers/usb/chipidea/udc.c | 89 ++++++----- drivers/usb/class/cdc-acm.c | 41 +++-- drivers/usb/class/cdc-wdm.c | 23 ++- drivers/usb/class/usblp.c | 7 +- drivers/usb/class/usbtmc.c | 63 +++++--- drivers/usb/core/hub.c | 93 ++++++++++-- drivers/usb/core/hub.h | 1 + drivers/usb/core/port.c | 7 +- drivers/usb/core/quirks.c | 27 +++- drivers/usb/core/urb.c | 2 +- drivers/usb/core/usb.c | 14 +- drivers/usb/dwc2/gadget.c | 1 + drivers/usb/dwc3/core.c | 11 +- drivers/usb/dwc3/dwc3-meson-g12a.c | 3 + drivers/usb/dwc3/dwc3-qcom.c | 8 +- drivers/usb/dwc3/gadget.c | 9 ++ drivers/usb/early/xhci-dbc.c | 4 + drivers/usb/gadget/composite.c | 22 ++- drivers/usb/gadget/configfs.c | 4 + drivers/usb/gadget/function/f_fs.c | 8 +- drivers/usb/gadget/function/f_hid.c | 16 +- drivers/usb/gadget/function/f_midi.c | 22 +-- drivers/usb/gadget/function/f_tcm.c | 58 +++---- drivers/usb/gadget/function/u_serial.c | 6 +- drivers/usb/gadget/udc/aspeed-vhub/dev.c | 3 + drivers/usb/gadget/udc/dummy_hcd.c | 25 +-- drivers/usb/gadget/udc/renesas_usb3.c | 3 +- drivers/usb/host/max3421-hcd.c | 9 +- drivers/usb/host/ohci-pci.c | 23 +++ drivers/usb/host/pci-quirks.c | 9 ++ drivers/usb/host/uhci-platform.c | 2 +- drivers/usb/host/xhci-dbgcap.c | 9 +- drivers/usb/host/xhci-hub.c | 3 +- drivers/usb/host/xhci-mem.c | 24 +-- drivers/usb/host/xhci-pci.c | 8 +- drivers/usb/host/xhci-ring.c | 19 ++- drivers/usb/host/xhci.c | 24 ++- drivers/usb/host/xhci.h | 3 +- drivers/usb/mon/mon_bin.c | 14 +- drivers/usb/musb/musb_gadget.c | 2 + drivers/usb/musb/omap2430.c | 10 +- drivers/usb/phy/phy-mxs-usb.c | 4 +- drivers/usb/phy/phy-twl6030-usb.c | 3 +- drivers/usb/renesas_usbhs/common.c | 56 +++++-- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- drivers/usb/roles/class.c | 5 +- drivers/usb/serial/cp210x.c | 1 + drivers/usb/serial/ftdi_sio.c | 18 +++ drivers/usb/serial/ftdi_sio_ids.h | 21 +++ drivers/usb/serial/option.c | 116 +++++++++++--- drivers/usb/serial/quatech2.c | 2 +- drivers/usb/serial/usb-serial-simple.c | 7 + drivers/usb/storage/realtek_cr.c | 2 +- drivers/usb/storage/unusual_devs.h | 36 +++++ drivers/usb/storage/unusual_uas.h | 14 ++ drivers/usb/typec/altmodes/displayport.c | 5 +- drivers/usb/typec/tcpm/fusb302.c | 8 + drivers/usb/typec/tcpm/tcpci_rt1711h.c | 11 ++ drivers/usb/typec/tcpm/tcpm.c | 4 +- drivers/usb/typec/ucsi/displayport.c | 2 + drivers/usb/typec/ucsi/ucsi.c | 2 +- drivers/usb/usbip/vhci_hcd.c | 22 +++ include/linux/hid.h | 3 +- include/linux/usb.h | 3 +- include/linux/usb/chipidea.h | 1 + include/linux/usb/hcd.h | 2 - include/linux/usb/typec_dp.h | 1 + 73 files changed, 932 insertions(+), 425 deletions(-) diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 5928e934d734..f9eb7ebec76f 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -197,7 +197,8 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, if (!input_device->hid_desc) goto cleanup; - input_device->report_desc_size = desc->desc[0].wDescriptorLength; + input_device->report_desc_size = le16_to_cpu( + desc->rpt_desc.wDescriptorLength); if (input_device->report_desc_size == 0) { input_device->dev_info_status = -EINVAL; goto cleanup; @@ -213,7 +214,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, memcpy(input_device->report_desc, ((unsigned char *)desc) + desc->bLength, - desc->desc[0].wDescriptorLength); + le16_to_cpu(desc->rpt_desc.wDescriptorLength)); /* Send the ack */ memset(&ack, 0, sizeof(struct mousevsc_prt_msg)); diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 8537fcdb456d..6e5770b8cc4c 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -984,12 +984,11 @@ static int usbhid_parse(struct hid_device *hid) struct usb_host_interface *interface = intf->cur_altsetting; struct usb_device *dev = interface_to_usbdev (intf); struct hid_descriptor *hdesc; + struct hid_class_descriptor *hcdesc; u32 quirks = 0; unsigned int rsize = 0; char *rdesc; - int ret, n; - int num_descriptors; - size_t offset = offsetof(struct hid_descriptor, desc); + int ret; quirks = hid_lookup_quirk(hid); @@ -1011,20 +1010,19 @@ static int usbhid_parse(struct hid_device *hid) return -ENODEV; } - if (hdesc->bLength < sizeof(struct hid_descriptor)) { - dbg_hid("hid descriptor is too short\n"); + if (!hdesc->bNumDescriptors || + hdesc->bLength != sizeof(*hdesc) + + (hdesc->bNumDescriptors - 1) * sizeof(*hcdesc)) { + dbg_hid("hid descriptor invalid, bLen=%hhu bNum=%hhu\n", + hdesc->bLength, hdesc->bNumDescriptors); return -EINVAL; } hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - num_descriptors = min_t(int, hdesc->bNumDescriptors, - (hdesc->bLength - offset) / sizeof(struct hid_class_descriptor)); - - for (n = 0; n < num_descriptors; n++) - if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) - rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); + if (hdesc->rpt_desc.bDescriptorType == HID_DT_REPORT) + rsize = le16_to_cpu(hdesc->rpt_desc.wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dbg_hid("weird size of report descriptor (%u)\n", rsize); @@ -1052,6 +1050,11 @@ static int usbhid_parse(struct hid_device *hid) goto err; } + if (hdesc->bNumDescriptors > 1) + hid_warn(intf, + "%u unsupported optional hid class descriptors\n", + (int)(hdesc->bNumDescriptors - 1)); + hid->quirks |= quirks; return 0; diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 51d42c69fb5e..58e5bc574e6a 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -984,94 +984,6 @@ cleanup: return ret; } -static void cxacru_upload_firmware(struct cxacru_data *instance, - const struct firmware *fw, - const struct firmware *bp) -{ - int ret; - struct usbatm_data *usbatm = instance->usbatm; - struct usb_device *usb_dev = usbatm->usb_dev; - __le16 signature[] = { usb_dev->descriptor.idVendor, - usb_dev->descriptor.idProduct }; - __le32 val; - - usb_dbg(usbatm, "%s\n", __func__); - - /* FirmwarePllFClkValue */ - val = cpu_to_le32(instance->modem_type->pll_f_clk); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret); - return; - } - - /* FirmwarePllBClkValue */ - val = cpu_to_le32(instance->modem_type->pll_b_clk); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret); - return; - } - - /* Enable SDRAM */ - val = cpu_to_le32(SDRAM_ENA); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); - if (ret) { - usb_err(usbatm, "Enable SDRAM failed: %d\n", ret); - return; - } - - /* Firmware */ - usb_info(usbatm, "loading firmware\n"); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); - if (ret) { - usb_err(usbatm, "Firmware upload failed: %d\n", ret); - return; - } - - /* Boot ROM patch */ - if (instance->modem_type->boot_rom_patch) { - usb_info(usbatm, "loading boot ROM patch\n"); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); - if (ret) { - usb_err(usbatm, "Boot ROM patching failed: %d\n", ret); - return; - } - } - - /* Signature */ - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); - if (ret) { - usb_err(usbatm, "Signature storing failed: %d\n", ret); - return; - } - - usb_info(usbatm, "starting device\n"); - if (instance->modem_type->boot_rom_patch) { - val = cpu_to_le32(BR_ADDR); - ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); - } else { - ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0); - } - if (ret) { - usb_err(usbatm, "Passing control to firmware failed: %d\n", ret); - return; - } - - /* Delay to allow firmware to start up. */ - msleep_interruptible(1000); - - usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD)); - usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD)); - usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA)); - usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA)); - - ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); - if (ret < 0) { - usb_err(usbatm, "modem failed to initialize: %d\n", ret); - return; - } -} static int cxacru_find_firmware(struct cxacru_data *instance, char *phase, const struct firmware **fw_p) @@ -1098,8 +1010,14 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, { const struct firmware *fw, *bp; struct cxacru_data *instance = usbatm_instance->driver_data; - int ret = cxacru_find_firmware(instance, "fw", &fw); + struct usbatm_data *usbatm = instance->usbatm; + struct usb_device *usb_dev = usbatm->usb_dev; + __le16 signature[] = { usb_dev->descriptor.idVendor, + usb_dev->descriptor.idProduct }; + __le32 val; + int ret; + ret = cxacru_find_firmware(instance, "fw", &fw); if (ret) { usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n"); return ret; @@ -1114,8 +1032,82 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, } } - cxacru_upload_firmware(instance, fw, bp); + /* FirmwarePllFClkValue */ + val = cpu_to_le32(instance->modem_type->pll_f_clk); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4); + if (ret) { + usb_err(usbatm, "FirmwarePllFClkValue failed: %d\n", ret); + goto done; + } + /* FirmwarePllBClkValue */ + val = cpu_to_le32(instance->modem_type->pll_b_clk); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4); + if (ret) { + usb_err(usbatm, "FirmwarePllBClkValue failed: %d\n", ret); + goto done; + } + + /* Enable SDRAM */ + val = cpu_to_le32(SDRAM_ENA); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4); + if (ret) { + usb_err(usbatm, "Enable SDRAM failed: %d\n", ret); + goto done; + } + + /* Firmware */ + usb_info(usbatm, "loading firmware\n"); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size); + if (ret) { + usb_err(usbatm, "Firmware upload failed: %d\n", ret); + goto done; + } + + /* Boot ROM patch */ + if (instance->modem_type->boot_rom_patch) { + usb_info(usbatm, "loading boot ROM patch\n"); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size); + if (ret) { + usb_err(usbatm, "Boot ROM patching failed: %d\n", ret); + goto done; + } + } + + /* Signature */ + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4); + if (ret) { + usb_err(usbatm, "Signature storing failed: %d\n", ret); + goto done; + } + + usb_info(usbatm, "starting device\n"); + if (instance->modem_type->boot_rom_patch) { + val = cpu_to_le32(BR_ADDR); + ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); + } else { + ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0); + } + if (ret) { + usb_err(usbatm, "Passing control to firmware failed: %d\n", ret); + goto done; + } + + /* Delay to allow firmware to start up. */ + msleep_interruptible(1000); + + usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD)); + usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD)); + usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA)); + usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA)); + + ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); + if (ret < 0) { + usb_err(usbatm, "modem failed to initialize: %d\n", ret); + goto done; + } + +done: if (instance->modem_type->boot_rom_patch) release_firmware(bp); release_firmware(fw); @@ -1135,7 +1127,10 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, struct cxacru_data *instance; struct usb_device *usb_dev = interface_to_usbdev(intf); struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD]; - struct usb_endpoint_descriptor *in, *out; + static const u8 ep_addrs[] = { + CXACRU_EP_CMD + USB_DIR_IN, + CXACRU_EP_CMD + USB_DIR_OUT, + 0}; int ret; /* instance init */ @@ -1183,13 +1178,11 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, } if (usb_endpoint_xfer_int(&cmd_ep->desc)) - ret = usb_find_common_endpoints(intf->cur_altsetting, - NULL, NULL, &in, &out); + ret = usb_check_int_endpoints(intf, ep_addrs); else - ret = usb_find_common_endpoints(intf->cur_altsetting, - &in, &out, NULL, NULL); + ret = usb_check_bulk_endpoints(intf, ep_addrs); - if (ret) { + if (!ret) { usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n"); ret = -ENODEV; goto fail; diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 61283e7e602a..88c3c3a1e189 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -1920,6 +1920,7 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep) "%s is already disabled\n", priv_ep->name)) return 0; + local_bh_disable(); spin_lock_irqsave(&priv_dev->lock, flags); trace_cdns3_gadget_ep_disable(priv_ep); @@ -1976,6 +1977,7 @@ static int cdns3_gadget_ep_disable(struct usb_ep *ep) priv_ep->flags &= ~EP_ENABLED; spin_unlock_irqrestore(&priv_dev->lock, flags); + local_bh_enable(); return ret; } diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index ff61f88fc867..3a22bc727bb9 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -277,8 +277,19 @@ static inline int ci_role_start(struct ci_hdrc *ci, enum ci_role role) return -ENXIO; ret = ci->roles[role]->start(ci); - if (!ret) - ci->role = role; + if (ret) + return ret; + + ci->role = role; + + if (ci->usb_phy) { + if (role == CI_ROLE_HOST) + usb_phy_set_event(ci->usb_phy, USB_EVENT_ID); + else + /* in device mode but vbus is invalid*/ + usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE); + } + return ret; } @@ -292,6 +303,9 @@ static inline void ci_role_stop(struct ci_hdrc *ci) ci->role = CI_ROLE_END; ci->roles[role]->stop(ci); + + if (ci->usb_phy) + usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE); } static inline enum usb_role ci_role_to_usb_role(struct ci_hdrc *ci) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 0fe545815c5c..d4566b5ec348 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -340,11 +340,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) pdata.flags |= CI_HDRC_IMX_IS_HSIC; data->usbmisc_data->hsic = 1; data->pinctrl = devm_pinctrl_get(dev); - if (IS_ERR(data->pinctrl)) { - dev_err(dev, "pinctrl get failed, err=%ld\n", - PTR_ERR(data->pinctrl)); - return PTR_ERR(data->pinctrl); - } + if (PTR_ERR(data->pinctrl) == -ENODEV) + data->pinctrl = NULL; + else if (IS_ERR(data->pinctrl)) + return dev_err_probe(dev, PTR_ERR(data->pinctrl), + "pinctrl get failed\n"); pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle"); if (IS_ERR(pinctrl_hsic_idle)) { @@ -369,17 +369,14 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) return PTR_ERR(data->pinctrl_hsic_active); } - data->hsic_pad_regulator = devm_regulator_get(dev, "hsic"); - if (PTR_ERR(data->hsic_pad_regulator) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { + data->hsic_pad_regulator = + devm_regulator_get_optional(dev, "hsic"); + if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { /* no pad regualator is needed */ data->hsic_pad_regulator = NULL; - } else if (IS_ERR(data->hsic_pad_regulator)) { - dev_err(dev, "Get HSIC pad regulator error: %ld\n", - PTR_ERR(data->hsic_pad_regulator)); - return PTR_ERR(data->hsic_pad_regulator); - } + } else if (IS_ERR(data->hsic_pad_regulator)) + return dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator), + "Get HSIC pad regulator error\n"); if (data->hsic_pad_regulator) { ret = regulator_enable(data->hsic_pad_regulator); @@ -420,7 +417,11 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) { pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL; data->override_phy_control = true; - usb_phy_init(pdata.usb_phy); + ret = usb_phy_init(pdata.usb_phy); + if (ret) { + dev_err(dev, "Failed to init phy\n"); + goto err_clk; + } } if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM) @@ -429,7 +430,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) ret = imx_usbmisc_init(data->usbmisc_data); if (ret) { dev_err(dev, "usbmisc init failed, ret=%d\n", ret); - goto err_clk; + goto phy_shutdown; } data->ci_pdev = ci_hdrc_add_device(dev, @@ -437,10 +438,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) &pdata); if (IS_ERR(data->ci_pdev)) { ret = PTR_ERR(data->ci_pdev); - if (ret != -EPROBE_DEFER) - dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", - ret); - goto err_clk; + dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n"); + goto phy_shutdown; } ret = imx_usbmisc_init_post(data->usbmisc_data); @@ -460,6 +459,9 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) disable_device: ci_hdrc_remove_device(data->ci_pdev); +phy_shutdown: + if (data->override_phy_control) + usb_phy_shutdown(data->phy); err_clk: imx_disable_unprepare_clks(dev); disable_hsic_regulator: diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a6ce6b89b271..d483a957804b 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1533,44 +1533,68 @@ static const struct usb_ep_ops usb_ep_ops = { /****************************************************************************** * GADGET block *****************************************************************************/ +/** + * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded + */ +static void ci_hdrc_gadget_connect(struct usb_gadget *_gadget, int is_active) +{ + struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); + + if (is_active) { + pm_runtime_get_sync(&_gadget->dev); + hw_device_reset(ci); + spin_lock_irq(&ci->lock); + if (ci->driver) { + hw_device_state(ci, ci->ep0out->qh.dma); + usb_gadget_set_state(_gadget, USB_STATE_POWERED); + spin_unlock_irq(&ci->lock); + usb_udc_vbus_handler(_gadget, true); + } else { + spin_unlock_irq(&ci->lock); + } + } else { + usb_udc_vbus_handler(_gadget, false); + if (ci->driver) + ci->driver->disconnect(&ci->gadget); + hw_device_state(ci, 0); + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_STOPPED_EVENT); + _gadget_stop_activity(&ci->gadget); + pm_runtime_put_sync(&_gadget->dev); + usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); + } +} + static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active) { struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); unsigned long flags; - int gadget_ready = 0; + int ret = 0; spin_lock_irqsave(&ci->lock, flags); ci->vbus_active = is_active; - if (ci->driver) - gadget_ready = 1; spin_unlock_irqrestore(&ci->lock, flags); if (ci->usb_phy) usb_phy_set_charger_state(ci->usb_phy, is_active ? USB_CHARGER_PRESENT : USB_CHARGER_ABSENT); - if (gadget_ready) { - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(ci); - hw_device_state(ci, ci->ep0out->qh.dma); - usb_gadget_set_state(_gadget, USB_STATE_POWERED); - usb_udc_vbus_handler(_gadget, true); - } else { - usb_udc_vbus_handler(_gadget, false); - if (ci->driver) - ci->driver->disconnect(&ci->gadget); - hw_device_state(ci, 0); - if (ci->platdata->notify_event) - ci->platdata->notify_event(ci, - CI_HDRC_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&ci->gadget); - pm_runtime_put_sync(&_gadget->dev); - usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED); - } + if (ci->platdata->notify_event) + ret = ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_VBUS_EVENT); + + if (ci->usb_phy) { + if (is_active) + usb_phy_set_event(ci->usb_phy, USB_EVENT_VBUS); + else + usb_phy_set_event(ci->usb_phy, USB_EVENT_NONE); } - return 0; + if (ci->driver) + ci_hdrc_gadget_connect(_gadget, is_active); + + return ret; } static int ci_udc_wakeup(struct usb_gadget *_gadget) @@ -1794,18 +1818,10 @@ static int ci_udc_start(struct usb_gadget *gadget, return retval; } - pm_runtime_get_sync(&ci->gadget.dev); - if (ci->vbus_active) { - hw_device_reset(ci); - } else { + if (ci->vbus_active) + ci_hdrc_gadget_connect(gadget, 1); + else usb_udc_vbus_handler(&ci->gadget, false); - pm_runtime_put_sync(&ci->gadget.dev); - return retval; - } - - retval = hw_device_state(ci, ci->ep0out->qh.dma); - if (retval) - pm_runtime_put_sync(&ci->gadget.dev); return retval; } @@ -1835,6 +1851,7 @@ static int ci_udc_stop(struct usb_gadget *gadget) unsigned long flags; spin_lock_irqsave(&ci->lock, flags); + ci->driver = NULL; if (ci->vbus_active) { hw_device_state(ci, 0); @@ -1847,7 +1864,6 @@ static int ci_udc_stop(struct usb_gadget *gadget) pm_runtime_put(&ci->gadget.dev); } - ci->driver = NULL; spin_unlock_irqrestore(&ci->lock, flags); ci_udc_stop_for_otg_fsm(ci); @@ -1890,6 +1906,9 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci) if (USBi_PCI & intr) { ci->gadget.speed = hw_port_is_high_speed(ci) ? USB_SPEED_HIGH : USB_SPEED_FULL; + if (ci->usb_phy) + usb_phy_set_event(ci->usb_phy, + USB_EVENT_ENUMERATED); if (ci->suspended) { if (ci->driver->resume) { spin_unlock(&ci->lock); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8b9740142152..4730089a771b 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -359,7 +359,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) static void acm_ctrl_irq(struct urb *urb) { struct acm *acm = urb->context; - struct usb_cdc_notification *dr = urb->transfer_buffer; + struct usb_cdc_notification *dr; unsigned int current_size = urb->actual_length; unsigned int expected_size, copy_size, alloc_size; int retval; @@ -386,14 +386,25 @@ static void acm_ctrl_irq(struct urb *urb) usb_mark_last_busy(acm->dev); - if (acm->nb_index) + if (acm->nb_index == 0) { + /* + * The first chunk of a message must contain at least the + * notification header with the length field, otherwise we + * can't get an expected_size. + */ + if (current_size < sizeof(struct usb_cdc_notification)) { + dev_dbg(&acm->control->dev, "urb too short\n"); + goto exit; + } + dr = urb->transfer_buffer; + } else { dr = (struct usb_cdc_notification *)acm->notification_buffer; - + } /* size = notification-header + (optional) data */ expected_size = sizeof(struct usb_cdc_notification) + le16_to_cpu(dr->wLength); - if (current_size < expected_size) { + if (acm->nb_index != 0 || current_size < expected_size) { /* notification is transmitted fragmented, reassemble */ if (acm->nb_size < expected_size) { u8 *new_buffer; @@ -1509,8 +1520,6 @@ skip_countries: acm->nb_index = 0; acm->nb_size = 0; - dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); - acm->line.dwDTERate = cpu_to_le32(9600); acm->line.bDataBits = 8; acm_set_line(acm, &acm->line); @@ -1518,6 +1527,12 @@ skip_countries: usb_driver_claim_interface(&acm_driver, data_interface, acm); usb_set_intfdata(data_interface, acm); + if (quirks & CLEAR_HALT_CONDITIONS) { + /* errors intentionally ignored */ + usb_clear_halt(usb_dev, acm->in); + usb_clear_halt(usb_dev, acm->out); + } + tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor, &control_interface->dev); if (IS_ERR(tty_dev)) { @@ -1525,10 +1540,7 @@ skip_countries: goto alloc_fail6; } - if (quirks & CLEAR_HALT_CONDITIONS) { - usb_clear_halt(usb_dev, acm->in); - usb_clear_halt(usb_dev, acm->out); - } + dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); return 0; alloc_fail6: @@ -1733,13 +1745,16 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, - { USB_DEVICE(0x045b, 0x023c), /* Renesas USB Download mode */ + { USB_DEVICE(0x045b, 0x023c), /* Renesas R-Car H3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, - { USB_DEVICE(0x045b, 0x0248), /* Renesas USB Download mode */ + { USB_DEVICE(0x045b, 0x0247), /* Renesas R-Car D3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, - { USB_DEVICE(0x045b, 0x024D), /* Renesas USB Download mode */ + { USB_DEVICE(0x045b, 0x0248), /* Renesas R-Car M3-N USB Download mode */ + .driver_info = DISABLE_ECHO, /* Don't echo banner */ + }, + { USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bc925394e881..6afb941dd267 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -89,7 +89,6 @@ struct wdm_device { u16 wMaxCommand; u16 wMaxPacketSize; __le16 inum; - int reslength; int length; int read; int count; @@ -201,6 +200,11 @@ static void wdm_in_callback(struct urb *urb) if (desc->rerr == 0 && status != -EPIPE) desc->rerr = status; + if (length == 0) { + dev_dbg(&desc->intf->dev, "received ZLP\n"); + goto skip_zlp; + } + if (length + desc->length > desc->wMaxCommand) { /* The buffer would overflow */ set_bit(WDM_OVERFLOW, &desc->flags); @@ -209,18 +213,18 @@ static void wdm_in_callback(struct urb *urb) if (!test_bit(WDM_OVERFLOW, &desc->flags)) { memmove(desc->ubuf + desc->length, desc->inbuf, length); desc->length += length; - desc->reslength = length; } } skip_error: if (desc->rerr) { /* - * Since there was an error, userspace may decide to not read - * any data after poll'ing. + * If there was a ZLP or an error, userspace may decide to not + * read any data after poll'ing. * We should respond to further attempts from the device to send * data, so that we can get unstuck. */ +skip_zlp: schedule_work(&desc->service_outs_intr); } else { set_bit(WDM_READ, &desc->flags); @@ -571,15 +575,6 @@ retry: goto retry; } - if (!desc->reslength) { /* zero length read */ - dev_dbg(&desc->intf->dev, "zero length - clearing WDM_READ\n"); - clear_bit(WDM_READ, &desc->flags); - rv = service_outstanding_interrupt(desc); - spin_unlock_irq(&desc->iuspin); - if (rv < 0) - goto err; - goto retry; - } cntr = desc->length; spin_unlock_irq(&desc->iuspin); } @@ -839,7 +834,7 @@ static void service_interrupt_work(struct work_struct *work) spin_lock_irq(&desc->iuspin); service_outstanding_interrupt(desc); - if (!desc->resp_count) { + if (!desc->resp_count && (desc->length || desc->rerr)) { set_bit(WDM_READ, &desc->flags); wake_up(&desc->wait); } diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index f27b4aecff3d..759f567538e2 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -1337,11 +1337,12 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) if (protocol < USBLP_FIRST_PROTOCOL || protocol > USBLP_LAST_PROTOCOL) return -EINVAL; + alts = usblp->protocol[protocol].alt_setting; + if (alts < 0) + return -EINVAL; + /* Don't unnecessarily set the interface if there's a single alt. */ if (usblp->intf->num_altsetting > 1) { - alts = usblp->protocol[protocol].alt_setting; - if (alts < 0) - return -EINVAL; r = usb_set_interface(usblp->dev, usblp->ifnum, alts); if (r < 0) { printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n", diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 00345a51f18d..d8ed205e6b43 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -485,6 +485,8 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, u8 tag; __u8 stb; int rv; + long wait_rv; + unsigned long expire; dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n", data->iin_ep_present); @@ -527,16 +529,18 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, } if (data->iin_ep_present) { - rv = wait_event_interruptible_timeout( + expire = msecs_to_jiffies(file_data->timeout); + wait_rv = wait_event_interruptible_timeout( data->waitq, atomic_read(&data->iin_data_valid) != 0, - file_data->timeout); - if (rv < 0) { - dev_dbg(dev, "wait interrupted %d\n", rv); + expire); + if (wait_rv < 0) { + dev_dbg(dev, "wait interrupted %ld\n", wait_rv); + rv = wait_rv; goto exit; } - if (rv == 0) { + if (wait_rv == 0) { dev_dbg(dev, "wait timed out\n"); rv = -ETIMEDOUT; goto exit; @@ -556,6 +560,8 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data, rv = put_user(stb, (__u8 __user *)arg); dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv); + rv = 0; + exit: /* bump interrupt bTag */ data->iin_bTag += 1; @@ -572,9 +578,9 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, { struct usbtmc_device_data *data = file_data->data; struct device *dev = &data->intf->dev; - int rv; u32 timeout; unsigned long expire; + long wait_rv; if (!data->iin_ep_present) { dev_dbg(dev, "no interrupt endpoint present\n"); @@ -588,25 +594,24 @@ static int usbtmc488_ioctl_wait_srq(struct usbtmc_file_data *file_data, mutex_unlock(&data->io_mutex); - rv = wait_event_interruptible_timeout( - data->waitq, - atomic_read(&file_data->srq_asserted) != 0 || - atomic_read(&file_data->closing), - expire); + wait_rv = wait_event_interruptible_timeout( + data->waitq, + atomic_read(&file_data->srq_asserted) != 0 || + atomic_read(&file_data->closing), + expire); mutex_lock(&data->io_mutex); /* Note! disconnect or close could be called in the meantime */ if (atomic_read(&file_data->closing) || data->zombie) - rv = -ENODEV; + return -ENODEV; - if (rv < 0) { - /* dev can be invalid now! */ - pr_debug("%s - wait interrupted %d\n", __func__, rv); - return rv; + if (wait_rv < 0) { + dev_dbg(dev, "%s - wait interrupted %ld\n", __func__, wait_rv); + return wait_rv; } - if (rv == 0) { + if (wait_rv == 0) { dev_dbg(dev, "%s - wait timed out\n", __func__); return -ETIMEDOUT; } @@ -800,6 +805,7 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, unsigned long expire; int bufcount = 1; int again = 0; + long wait_rv; /* mutex already locked */ @@ -912,19 +918,24 @@ static ssize_t usbtmc_generic_read(struct usbtmc_file_data *file_data, if (!(flags & USBTMC_FLAG_ASYNC)) { dev_dbg(dev, "%s: before wait time %lu\n", __func__, expire); - retval = wait_event_interruptible_timeout( + wait_rv = wait_event_interruptible_timeout( file_data->wait_bulk_in, usbtmc_do_transfer(file_data), expire); - dev_dbg(dev, "%s: wait returned %d\n", - __func__, retval); + dev_dbg(dev, "%s: wait returned %ld\n", + __func__, wait_rv); - if (retval <= 0) { - if (retval == 0) - retval = -ETIMEDOUT; + if (wait_rv < 0) { + retval = wait_rv; goto error; } + + if (wait_rv == 0) { + retval = -ETIMEDOUT; + goto error; + } + } urb = usb_get_from_anchor(&file_data->in_anchor); @@ -1350,7 +1361,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, if (!buffer) return -ENOMEM; - mutex_lock(&data->io_mutex); + retval = mutex_lock_interruptible(&data->io_mutex); + if (retval < 0) + goto exit_nolock; + if (data->zombie) { retval = -ENODEV; goto exit; @@ -1473,6 +1487,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, exit: mutex_unlock(&data->io_mutex); +exit_nolock: kfree(buffer); return retval; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bef2a5001aed..870353b82cdc 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -55,6 +55,12 @@ #define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ #define USB_PING_RESPONSE_TIME 400 /* ns */ +/* + * Give SS hubs 200ms time after wake to train downstream links before + * assuming no port activity and allowing hub to runtime suspend back. + */ +#define USB_SS_PORT_U0_WAKE_TIME 200 /* ms */ + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -1055,6 +1061,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) goto init2; goto init3; } + kref_get(&hub->kref); /* The superspeed hub except for root hub has to use Hub Depth @@ -1303,6 +1310,17 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) device_unlock(&hdev->dev); } + if (type == HUB_RESUME && hub_is_superspeed(hub->hdev)) { + /* give usb3 downstream links training time after hub resume */ + usb_autopm_get_interface_no_resume( + to_usb_interface(hub->intfdev)); + + queue_delayed_work(system_power_efficient_wq, + &hub->post_resume_work, + msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); + return; + } + kref_put(&hub->kref, hub_release); } @@ -1321,6 +1339,14 @@ static void hub_init_func3(struct work_struct *ws) hub_activate(hub, HUB_INIT3); } +static void hub_post_resume(struct work_struct *ws) +{ + struct usb_hub *hub = container_of(ws, struct usb_hub, post_resume_work.work); + + usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); + kref_put(&hub->kref, hub_release); +} + enum hub_quiescing_type { HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND }; @@ -1346,6 +1372,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) /* Stop hub_wq and related activity */ del_timer_sync(&hub->irq_urb_retry); + flush_delayed_work(&hub->post_resume_work); usb_kill_urb(hub->urb); if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); @@ -1796,6 +1823,17 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); + /* + * The USB 2.0 spec prohibits hubs from having more than one + * configuration or interface, and we rely on this prohibition. + * Refuse to accept a device that violates it. + */ + if (hdev->descriptor.bNumConfigurations > 1 || + hdev->actconfig->desc.bNumInterfaces > 1) { + dev_err(&intf->dev, "Invalid hub with more than one config or interface\n"); + return -EINVAL; + } + /* * Set default autosuspend delay as 0 to speedup bus suspend, * based on the below considerations: @@ -1881,6 +1919,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) hub->hdev = hdev; INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); + INIT_DELAYED_WORK(&hub->post_resume_work, hub_post_resume); INIT_WORK(&hub->events, hub_event); spin_lock_init(&hub->irq_urb_lock); timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); @@ -2596,13 +2635,13 @@ int usb_new_device(struct usb_device *udev) err = sysfs_create_link(&udev->dev.kobj, &port_dev->dev.kobj, "port"); if (err) - goto fail; + goto out_del_dev; err = sysfs_create_link(&port_dev->dev.kobj, &udev->dev.kobj, "device"); if (err) { sysfs_remove_link(&udev->dev.kobj, "port"); - goto fail; + goto out_del_dev; } if (!test_and_set_bit(port1, hub->child_usage_bits)) @@ -2614,6 +2653,8 @@ int usb_new_device(struct usb_device *udev) pm_runtime_put_sync_autosuspend(&udev->dev); return err; +out_del_dev: + device_del(&udev->dev); fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); pm_runtime_disable(&udev->dev); @@ -2746,6 +2787,8 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) #define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)(scheme)) +#define DETECT_DISCONNECT_TRIES 5 + #define HUB_ROOT_RESET_TIME 60 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 #define HUB_BH_RESET_TIME 50 @@ -5381,6 +5424,8 @@ static void port_event(struct usb_hub *hub, int port1) struct usb_device *udev = port_dev->child; struct usb_device *hdev = hub->hdev; u16 portstatus, portchange; + int i = 0; + int err; connect_change = test_bit(port1, hub->change_bits); clear_bit(port1, hub->event_bits); @@ -5457,17 +5502,30 @@ static void port_event(struct usb_hub *hub, int port1) connect_change = 1; /* - * Warm reset a USB3 protocol port if it's in - * SS.Inactive state. + * Avoid trying to recover a USB3 SS.Inactive port with a warm reset if + * the device was disconnected. A 12ms disconnect detect timer in + * SS.Inactive state transitions the port to RxDetect automatically. + * SS.Inactive link error state is common during device disconnect. */ - if (hub_port_warm_reset_required(hub, port1, portstatus)) { - dev_dbg(&port_dev->dev, "do warm reset\n"); - if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) + while (hub_port_warm_reset_required(hub, port1, portstatus)) { + if ((i++ < DETECT_DISCONNECT_TRIES) && udev) { + u16 unused; + + msleep(20); + hub_port_status(hub, port1, &portstatus, &unused); + dev_dbg(&port_dev->dev, "Wait for inactive link disconnect detect\n"); + continue; + } else if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) || udev->state == USB_STATE_NOTATTACHED) { - if (hub_port_reset(hub, port1, NULL, - HUB_BH_RESET_TIME, true) < 0) + dev_dbg(&port_dev->dev, "do warm reset, port only\n"); + err = hub_port_reset(hub, port1, NULL, + HUB_BH_RESET_TIME, true); + if (!udev && err == -ENOTCONN) + connect_change = 0; + else if (err < 0) hub_port_disable(hub, port1, 1); } else { + dev_dbg(&port_dev->dev, "do warm reset, full device\n"); usb_unlock_port(port_dev); usb_lock_device(udev); usb_reset_device(udev); @@ -5475,6 +5533,7 @@ static void port_event(struct usb_hub *hub, int port1) usb_lock_port(port_dev); connect_change = 0; } + break; } if (connect_change) @@ -5822,6 +5881,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) struct usb_hub *parent_hub; struct usb_hcd *hcd = bus_to_hcd(udev->bus); struct usb_device_descriptor descriptor = udev->descriptor; + struct usb_interface *intf; struct usb_host_bos *bos; char buf[50]; int i, j, ret = 0; @@ -5884,6 +5944,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (!udev->actconfig) goto done; + /* + * Some devices can't handle setting default altsetting 0 with a + * Set-Interface request. Disable host-side endpoints of those + * interfaces here. Enable and reset them back after host has set + * its internal endpoint structures during usb_hcd_alloc_bandwith() + */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (intf->cur_altsetting->desc.bAlternateSetting == 0) + usb_disable_interface(udev, intf, true); + } + mutex_lock(hcd->bandwidth_mutex); ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL); if (ret < 0) { @@ -5927,12 +5999,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { struct usb_host_config *config = udev->actconfig; - struct usb_interface *intf = config->interface[i]; struct usb_interface_descriptor *desc; + intf = config->interface[i]; desc = &intf->cur_altsetting->desc; if (desc->bAlternateSetting == 0) { - usb_disable_interface(udev, intf, true); usb_enable_interface(udev, intf, true); ret = 0; } else { diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 1c455800f7d3..de29ce856953 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -69,6 +69,7 @@ struct usb_hub { u8 indicator[USB_MAXCHILDREN]; struct delayed_work leds; struct delayed_work init_work; + struct delayed_work post_resume_work; struct work_struct events; spinlock_t irq_urb_lock; struct timer_list irq_urb_retry; diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 86e8585a5512..f01b0103fe12 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -294,10 +294,11 @@ static int usb_port_runtime_suspend(struct device *dev) static void usb_port_shutdown(struct device *dev) { struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *udev = port_dev->child; - if (port_dev->child) { - usb_disable_usb2_hardware_lpm(port_dev->child); - usb_unlocked_disable_lpm(port_dev->child); + if (udev && !udev->port_is_suspended) { + usb_disable_usb2_hardware_lpm(udev); + usb_unlocked_disable_lpm(udev); } } diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 25af0a9c62cc..de52ed067d24 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -224,7 +224,8 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x046a, 0x0023), .driver_info = USB_QUIRK_RESET_RESUME }, /* Logitech HD Webcam C270 */ - { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, + { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME | + USB_QUIRK_NO_LPM}, /* Logitech HD Pro Webcams C920, C920-C, C922, C925e and C930e */ { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -338,6 +339,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0638, 0x0a13), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + /* Prolific Single-LUN Mass Storage Card Reader */ + { USB_DEVICE(0x067b, 0x2731), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_NO_LPM }, + /* Saitek Cyborg Gold Joystick */ { USB_DEVICE(0x06a3, 0x0006), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, @@ -362,6 +367,13 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0781, 0x5583), .driver_info = USB_QUIRK_NO_LPM }, { USB_DEVICE(0x0781, 0x5591), .driver_info = USB_QUIRK_NO_LPM }, + /* SanDisk Corp. SanDisk 3.2Gen1 */ + { USB_DEVICE(0x0781, 0x5596), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x0781, 0x55a3), .driver_info = USB_QUIRK_DELAY_INIT }, + + /* SanDisk Extreme 55AE */ + { USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM }, + /* Realforce 87U Keyboard */ { USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM }, @@ -434,6 +446,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0c45, 0x7056), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Sony Xperia XZ1 Compact (lilac) smartphone in fastboot mode */ + { USB_DEVICE(0x0fce, 0x0dde), .driver_info = USB_QUIRK_NO_LPM }, + /* Action Semiconductor flash disk */ { USB_DEVICE(0x10d6, 0x2200), .driver_info = USB_QUIRK_STRING_FETCH_255 }, @@ -448,6 +463,8 @@ static const struct usb_device_id usb_quirk_list[] = { /* Huawei 4G LTE module */ { USB_DEVICE(0x12d1, 0x15bb), .driver_info = USB_QUIRK_DISCONNECT_SUSPEND }, + { USB_DEVICE(0x12d1, 0x15c1), .driver_info = + USB_QUIRK_DISCONNECT_SUSPEND }, { USB_DEVICE(0x12d1, 0x15c3), .driver_info = USB_QUIRK_DISCONNECT_SUSPEND }, @@ -524,10 +541,16 @@ static const struct usb_device_id usb_quirk_list[] = { /* Blackmagic Design UltraStudio SDI */ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM }, + /* Teclast disk */ + { USB_DEVICE(0x1f75, 0x0917), .driver_info = USB_QUIRK_NO_LPM }, + /* Hauppauge HVR-950q */ { USB_DEVICE(0x2040, 0x7200), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* VLI disk */ + { USB_DEVICE(0x2109, 0x0711), .driver_info = USB_QUIRK_NO_LPM }, + /* Raydium Touchscreen */ { USB_DEVICE(0x2386, 0x3114), .driver_info = USB_QUIRK_NO_LPM }, @@ -708,7 +731,7 @@ void usb_detect_quirks(struct usb_device *udev) udev->quirks ^= usb_detect_dynamic_quirks(udev); if (udev->quirks) - dev_dbg(&udev->dev, "USB quirks for this device: %x\n", + dev_dbg(&udev->dev, "USB quirks for this device: 0x%x\n", udev->quirks); #ifdef CONFIG_USB_DEFAULT_PERSIST diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index 850d0fffe1c6..e60f4ef06e3d 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -490,7 +490,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) /* Check that the pipe's type matches the endpoint's type */ if (usb_pipe_type_check(urb->dev, urb->pipe)) - dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", + dev_warn_once(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); /* Check against a simple/standard policy */ diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 502d911f71fa..571ab8e0c759 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -717,15 +717,16 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev_set_name(&dev->dev, "usb%d", bus->busnum); root_hub = 1; } else { + int n; + /* match any labeling on the hubs; it's one-based */ if (parent->devpath[0] == '0') { - snprintf(dev->devpath, sizeof dev->devpath, - "%d", port1); + n = snprintf(dev->devpath, sizeof(dev->devpath), "%d", port1); /* Root ports are not counted in route string */ dev->route = 0; } else { - snprintf(dev->devpath, sizeof dev->devpath, - "%s.%d", parent->devpath, port1); + n = snprintf(dev->devpath, sizeof(dev->devpath), "%s.%d", + parent->devpath, port1); /* Route string assumes hubs have less than 16 ports */ if (port1 < 15) dev->route = parent->route + @@ -734,6 +735,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->route = parent->route + (15 << ((parent->level - 1)*4)); } + if (n >= sizeof(dev->devpath)) { + usb_put_hcd(bus_to_hcd(bus)); + usb_put_dev(dev); + return NULL; + } dev->dev.parent = &parent->dev; dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index abc2271799e0..74d2dbf9a535 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4548,6 +4548,7 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) spin_lock_irqsave(&hsotg->lock, flags); hsotg->driver = NULL; + hsotg->gadget.dev.of_node = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; hsotg->enabled = 0; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index ee89b55a179e..2fb3f23a8dc7 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -120,17 +120,19 @@ static void __dwc3_set_mode(struct work_struct *work) if (dwc->dr_mode != USB_DR_MODE_OTG) return; + pm_runtime_get_sync(dwc->dev); + if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG) dwc3_otg_update(dwc, 0); if (!dwc->desired_dr_role) - return; + goto out; if (dwc->desired_dr_role == dwc->current_dr_role) - return; + goto out; if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) - return; + goto out; switch (dwc->current_dr_role) { case DWC3_GCTL_PRTCAP_HOST: @@ -194,6 +196,9 @@ static void __dwc3_set_mode(struct work_struct *work) break; } +out: + pm_runtime_mark_last_busy(dwc->dev); + pm_runtime_put_autosuspend(dwc->dev); } void dwc3_set_mode(struct dwc3 *dwc, u32 mode) diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 8a3ec1a951fe..9bb1edb81d6e 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -529,6 +529,9 @@ static int dwc3_meson_g12a_remove(struct platform_device *pdev) usb_role_switch_unregister(priv->role_switch); + put_device(priv->switch_desc.udc); + put_device(priv->switch_desc.usb2_port); + of_platform_depopulate(dev); for (i = 0 ; i < PHY_COUNT ; ++i) { diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index f6d569dacb87..9d28d95d3e92 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -641,13 +641,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev) ret = reset_control_deassert(qcom->resets); if (ret) { dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret); - goto reset_assert; + return ret; } ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np)); if (ret) { dev_err(dev, "failed to get clocks\n"); - goto reset_assert; + return ret; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -729,8 +729,6 @@ clk_disable: if (qcom->gdsc) if (regulator_disable(qcom->gdsc)) dev_err(qcom->dev, "unable to disable usb3 gdsc\n"); -reset_assert: - reset_control_assert(qcom->resets); return ret; } @@ -754,8 +752,6 @@ static int dwc3_qcom_remove(struct platform_device *pdev) } qcom->num_clocks = 0; - reset_control_assert(qcom->resets); - pm_runtime_allow(dev); pm_runtime_disable(dev); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4bf209f4d92d..21e0c4ca592c 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3535,6 +3535,15 @@ out: static void dwc3_gadget_endpoint_transfer_not_ready(struct dwc3_ep *dep, const struct dwc3_event_depevt *event) { + /* + * During a device-initiated disconnect, a late xferNotReady event can + * be generated after the End Transfer command resets the event filter, + * but before the controller is halted. Ignore it to prevent a new + * transfer from starting. + */ + if (!dep->dwc->connected) + return; + dwc3_gadget_endpoint_frame_from_event(dep, event); (void) __dwc3_gadget_start_isoc(dep); } diff --git a/drivers/usb/early/xhci-dbc.c b/drivers/usb/early/xhci-dbc.c index 5a462a1d1896..7673ded077a4 100644 --- a/drivers/usb/early/xhci-dbc.c +++ b/drivers/usb/early/xhci-dbc.c @@ -678,6 +678,10 @@ int __init early_xdbc_setup_hardware(void) xdbc.table_base = NULL; xdbc.out_buf = NULL; + + early_iounmap(xdbc.xhci_base, xdbc.xhci_length); + xdbc.xhci_base = NULL; + xdbc.xhci_length = 0; } return ret; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 13f953240fca..a873266cf09b 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -970,10 +970,11 @@ static int set_config(struct usb_composite_dev *cdev, else power = min(power, 900U); done: - if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) - usb_gadget_set_selfpowered(gadget); - else + if (power > USB_SELF_POWER_VBUS_MAX_DRAW || + (c && !(c->bmAttributes & USB_CONFIG_ATT_SELFPOWER))) usb_gadget_clear_selfpowered(gadget); + else + usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, power); if (result >= 0 && cdev->delayed_status) @@ -2321,6 +2322,11 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, if (!cdev->os_desc_req->buf) { ret = -ENOMEM; usb_ep_free_request(ep0, cdev->os_desc_req); + /* + * Set os_desc_req to NULL so that composite_dev_cleanup() + * will not try to free it again. + */ + cdev->os_desc_req = NULL; goto end; } cdev->os_desc_req->context = cdev; @@ -2446,7 +2452,10 @@ void composite_suspend(struct usb_gadget *gadget) cdev->suspended = 1; - usb_gadget_set_selfpowered(gadget); + if (cdev->config && + cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER) + usb_gadget_set_selfpowered(gadget); + usb_gadget_vbus_draw(gadget, 2); } @@ -2478,8 +2487,11 @@ void composite_resume(struct usb_gadget *gadget) else maxpower = min(maxpower, 900U); - if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW) + if (maxpower > USB_SELF_POWER_VBUS_MAX_DRAW || + !(cdev->config->bmAttributes & USB_CONFIG_ATT_SELFPOWER)) usb_gadget_clear_selfpowered(gadget); + else + usb_gadget_set_selfpowered(gadget); usb_gadget_vbus_draw(gadget, maxpower); } diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index f4f8e0c32c03..cd75b204454a 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -938,6 +938,8 @@ static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page, struct gadget_info *gi = os_desc_item_to_gadget_info(item); int res, l; + if (!len) + return len; l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); if (page[l - 1] == '\n') --l; @@ -1439,6 +1441,8 @@ static int configfs_composite_bind(struct usb_gadget *gadget, cdev->use_os_string = true; cdev->b_vendor_code = gi->b_vendor_code; memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + } else { + cdev->use_os_string = false; } if (gadget_is_otg(gadget) && !otg_desc[0]) { diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 397a4f9417d5..11c5cd728594 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2254,7 +2254,12 @@ static int ffs_func_eps_enable(struct ffs_function *func) ep = func->eps; epfile = ffs->epfiles; count = ffs->eps_count; - while(count--) { + if (!epfile) { + ret = -ENOMEM; + goto done; + } + + while (count--) { ep->ep->driver_data = ep; ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); @@ -2280,6 +2285,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) } wake_up_interruptible(&ffs->wait); +done: spin_unlock_irqrestore(&func->ffs->eps_lock, flags); return ret; diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 571560d689c8..cea9157ea2b4 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -114,8 +114,8 @@ static struct hid_descriptor hidg_desc = { .bcdHID = cpu_to_le16(0x0101), .bCountryCode = 0x00, .bNumDescriptors = 0x1, - /*.desc[0].bDescriptorType = DYNAMIC */ - /*.desc[0].wDescriptorLenght = DYNAMIC */ + /*.rpt_desc.bDescriptorType = DYNAMIC */ + /*.rpt_desc.wDescriptorLength = DYNAMIC */ }; /* Super-Speed Support */ @@ -496,7 +496,7 @@ try_again: } req->status = 0; - req->zero = 0; + req->zero = 1; req->length = count; req->complete = f_hidg_req_complete; req->context = hidg; @@ -730,8 +730,8 @@ static int hidg_setup(struct usb_function *f, struct hid_descriptor hidg_desc_copy = hidg_desc; VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: HID\n"); - hidg_desc_copy.desc[0].bDescriptorType = HID_DT_REPORT; - hidg_desc_copy.desc[0].wDescriptorLength = + hidg_desc_copy.rpt_desc.bDescriptorType = HID_DT_REPORT; + hidg_desc_copy.rpt_desc.wDescriptorLength = cpu_to_le16(hidg->report_desc_length); length = min_t(unsigned short, length, @@ -767,7 +767,7 @@ stall: return -EOPNOTSUPP; respond: - req->zero = 0; + req->zero = 1; req->length = length; status = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); if (status < 0) @@ -972,8 +972,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) * We can use hidg_desc struct here but we should not relay * that its content won't change after returning from this function. */ - hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT; - hidg_desc.desc[0].wDescriptorLength = + hidg_desc.rpt_desc.bDescriptorType = HID_DT_REPORT; + hidg_desc.rpt_desc.wDescriptorLength = cpu_to_le16(hidg->report_desc_length); hidg_hs_in_ep_desc.bEndpointAddress = diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index ad36375544c6..f5acbcf90cbf 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -87,7 +87,7 @@ struct f_midi { struct snd_rawmidi_substream *out_substream[MAX_PORTS]; unsigned long out_triggered; - struct tasklet_struct tasklet; + struct work_struct work; unsigned int in_ports; unsigned int out_ports; int index; @@ -282,7 +282,7 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req) /* Our transmit completed. See if there's more to go. * f_midi_transmit eats req, don't queue it again. */ req->length = 0; - f_midi_transmit(midi); + queue_work(system_highpri_wq, &midi->work); return; } break; @@ -698,9 +698,11 @@ drop_out: f_midi_drop_out_substreams(midi); } -static void f_midi_in_tasklet(unsigned long data) +static void f_midi_in_work(struct work_struct *work) { - struct f_midi *midi = (struct f_midi *) data; + struct f_midi *midi; + + midi = container_of(work, struct f_midi, work); f_midi_transmit(midi); } @@ -737,7 +739,7 @@ static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) VDBG(midi, "%s() %d\n", __func__, up); midi->in_ports_array[substream->number].active = up; if (up) - tasklet_hi_schedule(&midi->tasklet); + queue_work(system_highpri_wq, &midi->work); } static int f_midi_out_open(struct snd_rawmidi_substream *substream) @@ -875,7 +877,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0; midi->gadget = cdev->gadget; - tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); + INIT_WORK(&midi->work, f_midi_in_work); status = f_midi_register_card(midi); if (status < 0) goto fail_register; @@ -997,11 +999,11 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) } /* configure the endpoint descriptors ... */ - ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); - ms_out_desc.bNumEmbMIDIJack = midi->in_ports; + ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); + ms_out_desc.bNumEmbMIDIJack = midi->out_ports; - ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); - ms_in_desc.bNumEmbMIDIJack = midi->out_ports; + ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); + ms_in_desc.bNumEmbMIDIJack = midi->in_ports; /* ... and add them to the list */ endpoint_descriptor_index = i; diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 41a10bcc2efc..48d02c5ff849 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -245,7 +245,6 @@ static int bot_send_write_request(struct usbg_cmd *cmd) { struct f_uas *fu = cmd->fu; struct se_cmd *se_cmd = &cmd->se_cmd; - struct usb_gadget *gadget = fuas_to_gadget(fu); int ret; init_completion(&cmd->write_complete); @@ -256,22 +255,6 @@ static int bot_send_write_request(struct usbg_cmd *cmd) return -EINVAL; } - if (!gadget->sg_supported) { - cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL); - if (!cmd->data_buf) - return -ENOMEM; - - fu->bot_req_out->buf = cmd->data_buf; - } else { - fu->bot_req_out->buf = NULL; - fu->bot_req_out->num_sgs = se_cmd->t_data_nents; - fu->bot_req_out->sg = se_cmd->t_data_sg; - } - - fu->bot_req_out->complete = usbg_data_write_cmpl; - fu->bot_req_out->length = se_cmd->data_length; - fu->bot_req_out->context = cmd; - ret = usbg_prepare_w_request(cmd, fu->bot_req_out); if (ret) goto cleanup; @@ -971,6 +954,7 @@ static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req) return; cleanup: + target_put_sess_cmd(se_cmd); transport_generic_free_cmd(&cmd->se_cmd, 0); } @@ -1063,8 +1047,7 @@ static void usbg_cmd_work(struct work_struct *work) out: transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - transport_generic_free_cmd(&cmd->se_cmd, 0); + TCM_UNSUPPORTED_SCSI_OPCODE, 0); } static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, @@ -1193,8 +1176,7 @@ static void bot_cmd_work(struct work_struct *work) out: transport_send_check_condition_and_sense(se_cmd, - TCM_UNSUPPORTED_SCSI_OPCODE, 1); - transport_generic_free_cmd(&cmd->se_cmd, 0); + TCM_UNSUPPORTED_SCSI_OPCODE, 0); } static int bot_submit_command(struct f_uas *fu, @@ -1338,14 +1320,14 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn, struct usbg_tport *tport = container_of(wwn, struct usbg_tport, tport_wwn); struct usbg_tpg *tpg; - unsigned long tpgt; + u16 tpgt; int ret; struct f_tcm_opts *opts; unsigned i; if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX) + if (kstrtou16(name + 5, 0, &tpgt)) return ERR_PTR(-EINVAL); ret = -ENODEV; mutex_lock(&tpg_instances_lock); @@ -2017,43 +1999,39 @@ static int tcm_bind(struct usb_configuration *c, struct usb_function *f) bot_intf_desc.bInterfaceNumber = iface; uasp_intf_desc.bInterfaceNumber = iface; fu->iface = iface; - ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc, - &uasp_bi_ep_comp_desc); + ep = usb_ep_autoconfig(gadget, &uasp_fs_bi_desc); if (!ep) goto ep_fail; fu->ep_in = ep; - ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc, - &uasp_bo_ep_comp_desc); + ep = usb_ep_autoconfig(gadget, &uasp_fs_bo_desc); if (!ep) goto ep_fail; fu->ep_out = ep; - ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc, - &uasp_status_in_ep_comp_desc); + ep = usb_ep_autoconfig(gadget, &uasp_fs_status_desc); if (!ep) goto ep_fail; fu->ep_status = ep; - ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc, - &uasp_cmd_comp_desc); + ep = usb_ep_autoconfig(gadget, &uasp_fs_cmd_desc); if (!ep) goto ep_fail; fu->ep_cmd = ep; /* Assume endpoint addresses are the same for both speeds */ - uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; - uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; + uasp_bi_desc.bEndpointAddress = uasp_fs_bi_desc.bEndpointAddress; + uasp_bo_desc.bEndpointAddress = uasp_fs_bo_desc.bEndpointAddress; uasp_status_desc.bEndpointAddress = - uasp_ss_status_desc.bEndpointAddress; - uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + uasp_fs_status_desc.bEndpointAddress; + uasp_cmd_desc.bEndpointAddress = uasp_fs_cmd_desc.bEndpointAddress; - uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; - uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; - uasp_fs_status_desc.bEndpointAddress = - uasp_ss_status_desc.bEndpointAddress; - uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + uasp_ss_bi_desc.bEndpointAddress = uasp_fs_bi_desc.bEndpointAddress; + uasp_ss_bo_desc.bEndpointAddress = uasp_fs_bo_desc.bEndpointAddress; + uasp_ss_status_desc.bEndpointAddress = + uasp_fs_status_desc.bEndpointAddress; + uasp_ss_cmd_desc.bEndpointAddress = uasp_fs_cmd_desc.bEndpointAddress; ret = usb_assign_descriptors(f, uasp_fs_function_desc, uasp_hs_function_desc, uasp_ss_function_desc, diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 246395d16121..c5cffdae9e4e 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -286,8 +286,8 @@ __acquires(&port->port_lock) break; } - if (do_tty_wake && port->port.tty) - tty_wakeup(port->port.tty); + if (do_tty_wake) + tty_port_tty_wakeup(&port->port); return status; } @@ -564,7 +564,7 @@ static int gs_start_io(struct gs_port *port) gs_start_tx(port); /* Unblock any pending writes into our circular buffer, in case * we didn't in gs_start_tx() */ - tty_wakeup(port->port.tty); + tty_port_tty_wakeup(&port->port); } else { /* Free reqs only if we are still connected */ if (port->port_usb) { diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 4008e7a51188..89d7d3b24718 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -542,6 +542,9 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx) d->vhub = vhub; d->index = idx; d->name = devm_kasprintf(parent, GFP_KERNEL, "port%d", idx+1); + if (!d->name) + return -ENOMEM; + d->regs = vhub->regs + 0x100 + 0x10 * idx; ast_vhub_init_ep0(vhub, &d->ep0, d); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 730f15fd92c2..55f40902bfd4 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -748,7 +748,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) struct dummy *dum; int retval = -EINVAL; unsigned long flags; - struct dummy_request *req = NULL; + struct dummy_request *req = NULL, *iter; if (!_ep || !_req) return retval; @@ -758,25 +758,26 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req) if (!dum->driver) return -ESHUTDOWN; - local_irq_save(flags); - spin_lock(&dum->lock); - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) { - list_del_init(&req->queue); - _req->status = -ECONNRESET; - retval = 0; - break; - } + spin_lock_irqsave(&dum->lock, flags); + list_for_each_entry(iter, &ep->queue, queue) { + if (&iter->req != _req) + continue; + list_del_init(&iter->queue); + _req->status = -ECONNRESET; + req = iter; + retval = 0; + break; } - spin_unlock(&dum->lock); if (retval == 0) { dev_dbg(udc_dev(dum), "dequeued req %p from %s, len %d buf %p\n", req, _ep->name, _req->length, _req->buf); + spin_unlock(&dum->lock); usb_gadget_giveback_request(_ep, _req); + spin_lock(&dum->lock); } - local_irq_restore(flags); + spin_unlock_irqrestore(&dum->lock, flags); return retval; } diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index e04acf2dfa65..90114c09a711 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -306,7 +306,7 @@ struct renesas_usb3_request { struct list_head queue; }; -#define USB3_EP_NAME_SIZE 8 +#define USB3_EP_NAME_SIZE 16 struct renesas_usb3_ep { struct usb_ep ep; struct renesas_usb3 *usb3; @@ -2551,6 +2551,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) struct renesas_usb3 *usb3 = platform_get_drvdata(pdev); debugfs_remove_recursive(usb3->dentry); + put_device(usb3->host_dev); device_remove_file(&pdev->dev, &dev_attr_role); cancel_work_sync(&usb3->role_work); diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 0a5e0e644982..cfdbe90f867e 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1925,7 +1925,7 @@ error: if (hcd) { kfree(max3421_hcd->tx); kfree(max3421_hcd->rx); - if (max3421_hcd->spi_thread) + if (!IS_ERR_OR_NULL(max3421_hcd->spi_thread)) kthread_stop(max3421_hcd->spi_thread); usb_put_hcd(hcd); } @@ -1956,6 +1956,12 @@ max3421_remove(struct spi_device *spi) return 0; } +static const struct spi_device_id max3421_spi_ids[] = { + { "max3421" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, max3421_spi_ids); + static const struct of_device_id max3421_of_match_table[] = { { .compatible = "maxim,max3421", }, {}, @@ -1965,6 +1971,7 @@ MODULE_DEVICE_TABLE(of, max3421_of_match_table); static struct spi_driver max3421_driver = { .probe = max3421_probe, .remove = max3421_remove, + .id_table = max3421_spi_ids, .driver = { .name = "max3421-hcd", .of_match_table = of_match_ptr(max3421_of_match_table), diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index f4e13a3fddee..f9719ee5ba9e 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -165,6 +165,25 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) return 0; } +static int ohci_quirk_loongson(struct usb_hcd *hcd) +{ + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* + * Loongson's LS7A OHCI controller (rev 0x02) has a + * flaw. MMIO register with offset 0x60/64 is treated + * as legacy PS2-compatible keyboard/mouse interface. + * Since OHCI only use 4KB BAR resource, LS7A OHCI's + * 32KB BAR is wrapped around (the 2nd 4KB BAR space + * is the same as the 1st 4KB internally). So add 4KB + * offset (0x1000) to the OHCI registers as a quirk. + */ + if (pdev->revision == 0x2) + hcd->regs += SZ_4K; /* SZ_4K = 0x1000 */ + + return 0; +} + static int ohci_quirk_qemu(struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci(hcd); @@ -224,6 +243,10 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), .driver_data = (unsigned long)ohci_quirk_amd700, }, + { + PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x7a24), + .driver_data = (unsigned long)ohci_quirk_loongson, + }, { .vendor = PCI_VENDOR_ID_APPLE, .device = 0x003f, diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index f6d04491df60..7c98941d1108 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -945,6 +945,15 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev) * booting from USB disk or using a usb keyboard */ hcc_params = readl(base + EHCI_HCC_PARAMS); + + /* LS7A EHCI controller doesn't have extended capabilities, the + * EECP (EHCI Extended Capabilities Pointer) field of HCCPARAMS + * register should be 0x0 but it reads as 0xa0. So clear it to + * avoid error messages on boot. + */ + if (pdev->vendor == PCI_VENDOR_ID_LOONGSON && pdev->device == 0x7a14) + hcc_params &= ~(0xffL << 8); + offset = (hcc_params >> 8) & 0xff; while (offset && --count) { pci_read_config_dword(pdev, offset, &cap); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index be9e9db7cad1..c0834bac4c95 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -122,7 +122,7 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev) } /* Get and enable clock if any specified */ - uhci->clk = devm_clk_get(&pdev->dev, NULL); + uhci->clk = devm_clk_get_optional(&pdev->dev, NULL); if (IS_ERR(uhci->clk)) { ret = PTR_ERR(uhci->clk); goto err_rmr; diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 93e2cca5262d..4e65ebbaa09b 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -975,8 +975,15 @@ int xhci_dbc_suspend(struct xhci_hcd *xhci) if (!dbc) return 0; - if (dbc->state == DS_CONFIGURED) + switch (dbc->state) { + case DS_ENABLED: + case DS_CONNECTED: + case DS_CONFIGURED: dbc->resume_required = 1; + break; + default: + break; + } xhci_dbc_stop(xhci); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 55a617e9b0a7..b06b083d0d9e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -629,8 +629,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, if (!xhci->devs[i]) continue; - retval = xhci_disable_slot(xhci, i); - xhci_free_virt_device(xhci, i); + retval = xhci_disable_and_free_slot(xhci, i); if (retval) xhci_err(xhci, "Failed to disable slot %d, %d. Enter test mode anyway\n", i, retval); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 4383a08b396d..c527157612d0 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -879,21 +879,20 @@ free_tts: * will be manipulated by the configure endpoint, allocate device, or update * hub functions while this function is removing the TT entries from the list. */ -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) +void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, + int slot_id) { - struct xhci_virt_device *dev; int i; int old_active_eps = 0; /* Slot ID 0 is reserved */ - if (slot_id == 0 || !xhci->devs[slot_id]) + if (slot_id == 0 || !dev) return; - dev = xhci->devs[slot_id]; - - xhci->dcbaa->dev_context_ptrs[slot_id] = 0; - if (!dev) - return; + /* If device ctx array still points to _this_ device, clear it */ + if (dev->out_ctx && + xhci->dcbaa->dev_context_ptrs[slot_id] == cpu_to_le64(dev->out_ctx->dma)) + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; trace_xhci_free_virt_device(dev); @@ -932,8 +931,9 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->udev && dev->udev->slot_id) dev->udev->slot_id = 0; - kfree(xhci->devs[slot_id]); - xhci->devs[slot_id] = NULL; + if (xhci->devs[slot_id] == dev) + xhci->devs[slot_id] = NULL; + kfree(dev); } /* @@ -975,7 +975,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i out: /* we are now at a leaf device */ xhci_debugfs_remove_slot(xhci, slot_id); - xhci_free_virt_device(xhci, slot_id); + xhci_free_virt_device(xhci, vdev, slot_id); } int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, @@ -1214,6 +1214,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | dev->eps[0].ring->cycle_state); + ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(8)); + trace_xhci_setup_addressable_virt_device(dev); /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index b5ebbb9092f1..8056be6a368a 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -26,8 +26,8 @@ #define SPARSE_CNTL_ENABLE 0xC12C /* Device for a quirk */ -#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 -#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 +#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 +#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1009 0x1009 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1100 0x1100 #define PCI_DEVICE_ID_FRESCO_LOGIC_FL1400 0x1400 @@ -36,8 +36,8 @@ #define PCI_DEVICE_ID_EJ168 0x7023 #define PCI_DEVICE_ID_EJ188 0x7052 -#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 -#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI 0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_XHCI 0x9cb1 #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 992736350d0b..5cbd459b6b6c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -977,12 +977,15 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, */ void xhci_hc_died(struct xhci_hcd *xhci) { + bool notify; int i, j; if (xhci->xhc_state & XHCI_STATE_DYING) return; - xhci_err(xhci, "xHCI host controller not responding, assume dead\n"); + notify = !(xhci->xhc_state & XHCI_STATE_REMOVING); + if (notify) + xhci_err(xhci, "xHCI host controller not responding, assume dead\n"); xhci->xhc_state |= XHCI_STATE_DYING; xhci_cleanup_command_queue(xhci); @@ -996,7 +999,7 @@ void xhci_hc_died(struct xhci_hcd *xhci) } /* inform usb core hc died if PCI remove isn't already handling it */ - if (!(xhci->xhc_state & XHCI_STATE_REMOVING)) + if (notify) usb_hc_died(xhci_to_hcd(xhci)); } @@ -1259,7 +1262,8 @@ static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, command->slot_id = 0; } -static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) +static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id, + u32 cmd_comp_code) { struct xhci_virt_device *virt_dev; struct xhci_slot_ctx *slot_ctx; @@ -1274,6 +1278,10 @@ static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id) if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) /* Delete default control endpoint resources */ xhci_free_device_endpoint_resources(xhci, virt_dev, true); + if (cmd_comp_code == COMP_SUCCESS) { + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; + xhci->devs[slot_id] = NULL; + } } static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, @@ -1513,7 +1521,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, xhci_handle_cmd_enable_slot(xhci, slot_id, cmd, cmd_comp_code); break; case TRB_DISABLE_SLOT: - xhci_handle_cmd_disable_slot(xhci, slot_id); + xhci_handle_cmd_disable_slot(xhci, slot_id, cmd_comp_code); break; case TRB_CONFIG_EP: if (!cmd->completion) @@ -4225,7 +4233,8 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, if ((xhci->xhc_state & XHCI_STATE_DYING) || (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg(xhci, "xHCI dying or halted, can't queue_command\n"); + xhci_dbg(xhci, "xHCI dying or halted, can't queue_command. state: 0x%x\n", + xhci->xhc_state); return -ESHUTDOWN; } diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 667b703d5147..0f2a7f001d19 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -139,7 +139,8 @@ int xhci_halt(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_HALT, STS_HALT, 3 * XHCI_MAX_HALT_USEC); if (ret) { - xhci_warn(xhci, "Host halt failed, %d\n", ret); + if (!(xhci->xhc_state & XHCI_STATE_DYING)) + xhci_warn(xhci, "Host halt failed, %d\n", ret); return ret; } xhci->xhc_state |= XHCI_STATE_HALTED; @@ -204,7 +205,8 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us) state = readl(&xhci->op_regs->status); if (state == ~(u32)0) { - xhci_warn(xhci, "Host not accessible, reset failed.\n"); + if (!(xhci->xhc_state & XHCI_STATE_DYING)) + xhci_warn(xhci, "Host not accessible, reset failed.\n"); return -ENODEV; } @@ -4130,7 +4132,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_disable_slot(xhci, udev->slot_id); spin_lock_irqsave(&xhci->lock, flags); - xhci_free_virt_device(xhci, udev->slot_id); + xhci_free_virt_device(xhci, virt_dev, udev->slot_id); spin_unlock_irqrestore(&xhci->lock, flags); } @@ -4179,6 +4181,16 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id) return ret; } +int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id) +{ + struct xhci_virt_device *vdev = xhci->devs[slot_id]; + int ret; + + ret = xhci_disable_slot(xhci, slot_id); + xhci_free_virt_device(xhci, vdev, slot_id); + return ret; +} + /* * Checks if we have enough host controller resources for the default control * endpoint. @@ -4284,8 +4296,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) return 1; disable_slot: - xhci_disable_slot(xhci, udev->slot_id); - xhci_free_virt_device(xhci, udev->slot_id); + xhci_disable_and_free_slot(xhci, udev->slot_id); return 0; } @@ -4414,8 +4425,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, dev_warn(&udev->dev, "Device not responding to setup %s.\n", act); mutex_unlock(&xhci->mutex); - ret = xhci_disable_slot(xhci, udev->slot_id); - xhci_free_virt_device(xhci, udev->slot_id); + ret = xhci_disable_and_free_slot(xhci, udev->slot_id); if (!ret) { if (xhci_alloc_dev(hcd, udev) == 1) xhci_setup_addressable_virt_dev(xhci, udev); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 1003a02f40c1..681b36e8a981 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2031,7 +2031,7 @@ void xhci_dbg_trace(struct xhci_hcd *xhci, void (*trace)(struct va_format *), /* xHCI memory management */ void xhci_mem_cleanup(struct xhci_hcd *xhci); int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags); -void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id); +void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev, int slot_id); int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags); int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci, @@ -2123,6 +2123,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev); int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id); +int xhci_disable_and_free_slot(struct xhci_hcd *xhci, u32 slot_id); int xhci_ext_cap_init(struct xhci_hcd *xhci); int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 35483217b1f6..93998d328d9a 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -68,18 +68,20 @@ * The magic limit was calculated so that it allows the monitoring * application to pick data once in two ticks. This way, another application, * which presumably drives the bus, gets to hog CPU, yet we collect our data. - * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an - * enormous overhead built into the bus protocol, so we need about 1000 KB. + * + * Originally, for a 480 Mbit/s bus this required a buffer of about 1 MB. For + * modern 20 Gbps buses, this value increases to over 50 MB. The maximum + * buffer size is set to 64 MiB to accommodate this. * * This is still too much for most cases, where we just snoop a few * descriptor fetches for enumeration. So, the default is a "reasonable" - * amount for systems with HZ=250 and incomplete bus saturation. + * amount for typical, low-throughput use cases. * * XXX What about multi-megabyte URBs which take minutes to transfer? */ -#define BUFF_MAX CHUNK_ALIGN(1200*1024) -#define BUFF_DFL CHUNK_ALIGN(300*1024) -#define BUFF_MIN CHUNK_ALIGN(8*1024) +#define BUFF_MAX CHUNK_ALIGN(64*1024*1024) +#define BUFF_DFL CHUNK_ALIGN(300*1024) +#define BUFF_MIN CHUNK_ALIGN(8*1024) /* * The per-event API header (2 per URB). diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index b8fc818c154a..efb70b5c9e8e 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1910,6 +1910,7 @@ static int musb_gadget_stop(struct usb_gadget *g) * gadget driver here and have everything work; * that currently misbehaves. */ + usb_gadget_set_state(g, USB_STATE_NOTATTACHED); /* Force check of devctl register for PM runtime */ schedule_delayed_work(&musb->irq_work, 0); @@ -2018,6 +2019,7 @@ void musb_g_disconnect(struct musb *musb) case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_IDLE: musb->xceiv->otg->state = OTG_STATE_B_IDLE; + usb_gadget_set_state(&musb->g, USB_STATE_NOTATTACHED); break; case OTG_STATE_B_SRP_INIT: break; diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 8def19fc5025..76b7ac1103ab 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -476,13 +476,13 @@ static int omap2430_probe(struct platform_device *pdev) ARRAY_SIZE(musb_resources)); if (ret) { dev_err(&pdev->dev, "failed to add resources\n"); - goto err2; + goto err_put_control_otghs; } ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); if (ret) { dev_err(&pdev->dev, "failed to add platform_data\n"); - goto err2; + goto err_put_control_otghs; } pm_runtime_enable(glue->dev); @@ -497,7 +497,9 @@ static int omap2430_probe(struct platform_device *pdev) err3: pm_runtime_disable(glue->dev); - +err_put_control_otghs: + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); err2: platform_device_put(musb); @@ -511,6 +513,8 @@ static int omap2430_remove(struct platform_device *pdev) platform_device_unregister(glue->musb); pm_runtime_disable(glue->dev); + if (!IS_ERR(glue->control_otghs)) + put_device(glue->control_otghs); return 0; } diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index 6dfecbd47d7a..7c81ccaaf2e9 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -394,6 +394,7 @@ static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy) static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) { bool vbus_is_on = false; + enum usb_phy_events last_event = mxs_phy->phy.last_event; /* If the SoCs don't need to disconnect line without vbus, quit */ if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS)) @@ -405,7 +406,8 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) vbus_is_on = mxs_phy_get_vbus_status(mxs_phy); - if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy)) + if (on && ((!vbus_is_on && !mxs_phy_is_otg_host(mxs_phy)) + || (last_event == USB_EVENT_VBUS))) __mxs_phy_disconnect_line(mxs_phy, true); else __mxs_phy_disconnect_line(mxs_phy, false); diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 9337c30f0743..607c3f18356a 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -328,9 +328,8 @@ static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled) static int twl6030_usb_probe(struct platform_device *pdev) { - u32 ret; struct twl6030_usb *twl; - int status, err; + int status, err, ret; struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index a3c30b609433..c395f5e23f8b 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -313,8 +313,10 @@ static int usbhsc_clk_get(struct device *dev, struct usbhs_priv *priv) priv->clks[1] = of_clk_get(dev_of_node(dev), 1); if (PTR_ERR(priv->clks[1]) == -ENOENT) priv->clks[1] = NULL; - else if (IS_ERR(priv->clks[1])) + else if (IS_ERR(priv->clks[1])) { + clk_put(priv->clks[0]); return PTR_ERR(priv->clks[1]); + } return 0; } @@ -678,10 +680,29 @@ static int usbhs_probe(struct platform_device *pdev) INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug); spin_lock_init(usbhs_priv_to_lock(priv)); + /* + * Acquire clocks and enable power management (PM) early in the + * probe process, as the driver accesses registers during + * initialization. Ensure the device is active before proceeding. + */ + pm_runtime_enable(dev); + + ret = usbhsc_clk_get(dev, priv); + if (ret) + goto probe_pm_disable; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + goto probe_clk_put; + + ret = usbhsc_clk_prepare_enable(priv); + if (ret) + goto probe_pm_put; + /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) - return ret; + goto probe_clk_dis_unprepare; ret = usbhs_fifo_probe(priv); if (ret < 0) @@ -698,10 +719,6 @@ static int usbhs_probe(struct platform_device *pdev) if (ret) goto probe_fail_rst; - ret = usbhsc_clk_get(dev, priv); - if (ret) - goto probe_fail_clks; - /* * deviece reset here because * USB device might be used in boot loader. @@ -717,7 +734,7 @@ static int usbhs_probe(struct platform_device *pdev) dev_warn(dev, "USB function not selected (GPIO %d)\n", priv->dparam.enable_gpio); ret = -ENOTSUPP; - goto probe_end_mod_exit; + goto probe_assert_rest; } } @@ -731,14 +748,19 @@ static int usbhs_probe(struct platform_device *pdev) ret = usbhs_platform_call(priv, hardware_init, pdev); if (ret < 0) { dev_err(dev, "platform init failed.\n"); - goto probe_end_mod_exit; + goto probe_assert_rest; } /* reset phy for connection */ usbhs_platform_call(priv, phy_reset, pdev); - /* power control */ - pm_runtime_enable(dev); + /* + * Disable the clocks that were enabled earlier in the probe path, + * and let the driver handle the clocks beyond this point. + */ + usbhsc_clk_disable_unprepare(priv); + pm_runtime_put(dev); + if (!usbhs_get_dparam(priv, runtime_pwctrl)) { usbhsc_power_ctrl(priv, 1); usbhs_mod_autonomy_mode(priv); @@ -755,9 +777,7 @@ static int usbhs_probe(struct platform_device *pdev) return ret; -probe_end_mod_exit: - usbhsc_clk_put(priv); -probe_fail_clks: +probe_assert_rest: reset_control_assert(priv->rsts); probe_fail_rst: usbhs_mod_remove(priv); @@ -765,6 +785,14 @@ probe_end_fifo_exit: usbhs_fifo_remove(priv); probe_end_pipe_exit: usbhs_pipe_remove(priv); +probe_clk_dis_unprepare: + usbhsc_clk_disable_unprepare(priv); +probe_pm_put: + pm_runtime_put(dev); +probe_clk_put: + usbhsc_clk_put(priv); +probe_pm_disable: + pm_runtime_disable(dev); dev_info(dev, "probe failed (%d)\n", ret); @@ -777,6 +805,8 @@ static int usbhs_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "usb remove\n"); + flush_delayed_work(&priv->notify_hotplug_work); + /* power off */ if (!usbhs_get_dparam(priv, runtime_pwctrl)) usbhsc_power_ctrl(priv, 0); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 53489cafecc1..5a4605bbaa8b 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -1094,7 +1094,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) goto usbhs_mod_gadget_probe_err_gpriv; } - gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED); + gpriv->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_UNDEFINED); dev_info(dev, "%stransceiver found\n", !IS_ERR(gpriv->transceiver) ? "" : "no "); diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index aa4fb7a66dce..4e00a185a4b6 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -317,14 +317,15 @@ usb_role_switch_register(struct device *parent, sw->dev.type = &usb_role_dev_type; dev_set_name(&sw->dev, "%s-role-switch", dev_name(parent)); + sw->registered = true; + ret = device_register(&sw->dev); if (ret) { + sw->registered = false; put_device(&sw->dev); return ERR_PTR(ret); } - sw->registered = true; - /* TODO: Symlinks for the host port and the device controller. */ return sw; diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 5353fa7e5969..39c9d1f857fc 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -224,6 +224,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ + { USB_DEVICE(0x1B93, 0x1013) }, /* Phoenix Contact UPS Device */ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ { USB_DEVICE(0x1D6F, 0x0010) }, /* Seluxit ApS RF Dongle */ diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index bfb0be4e70d5..ee01061b413c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -781,6 +781,8 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID), .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, + { USB_DEVICE(FTDI_NDI_VID, FTDI_NDI_EMGUIDE_GEMINI_PID), + .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) }, { USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) }, @@ -1057,6 +1059,22 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, /* GMC devices */ { USB_DEVICE(GMC_VID, GMC_Z216C_PID) }, + /* Altera USB Blaster 3 */ + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6022_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6025_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6026_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6026_PID, 3) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_6029_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602A_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602A_PID, 3) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602C_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602D_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602D_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 1) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 2) }, + { USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) }, + /* Abacus Electrics */ + { USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index b2aec1106678..324065cc352c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -197,6 +197,9 @@ #define FTDI_NDI_FUTURE_3_PID 0xDA73 /* NDI future device #3 */ #define FTDI_NDI_AURORA_SCU_PID 0xDA74 /* NDI Aurora SCU */ +#define FTDI_NDI_VID 0x23F2 +#define FTDI_NDI_EMGUIDE_GEMINI_PID 0x0003 /* NDI Emguide Gemini */ + /* * ChamSys Limited (www.chamsys.co.uk) USB wing/interface product IDs */ @@ -435,6 +438,11 @@ #define LINX_FUTURE_1_PID 0xF44B /* Linx future device */ #define LINX_FUTURE_2_PID 0xF44C /* Linx future device */ +/* + * Abacus Electrics + */ +#define ABACUS_OPTICAL_PROBE_PID 0xf458 /* ABACUS ELECTRICS Optical Probe */ + /* * Oceanic product ids */ @@ -1605,3 +1613,16 @@ */ #define GMC_VID 0x1cd7 #define GMC_Z216C_PID 0x0217 /* GMC Z216C Adapter IR-USB */ + +/* + * Altera USB Blaster 3 (http://www.altera.com). + */ +#define ALTERA_VID 0x09fb +#define ALTERA_UB3_6022_PID 0x6022 +#define ALTERA_UB3_6025_PID 0x6025 +#define ALTERA_UB3_6026_PID 0x6026 +#define ALTERA_UB3_6029_PID 0x6029 +#define ALTERA_UB3_602A_PID 0x602a +#define ALTERA_UB3_602C_PID 0x602c +#define ALTERA_UB3_602D_PID 0x602d +#define ALTERA_UB3_602E_PID 0x602e diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 3ae4ac4d9857..4a93bfbe4c6c 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -273,6 +273,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EM05CN 0x0312 #define QUECTEL_PRODUCT_EM05G_GR 0x0313 #define QUECTEL_PRODUCT_EM05G_RS 0x0314 +#define QUECTEL_PRODUCT_RG255C 0x0316 #define QUECTEL_PRODUCT_EM12 0x0512 #define QUECTEL_PRODUCT_RM500Q 0x0800 #define QUECTEL_PRODUCT_RM520N 0x0801 @@ -611,23 +612,16 @@ static void option_instat_callback(struct urb *urb); /* Sierra Wireless products */ #define SIERRA_VENDOR_ID 0x1199 #define SIERRA_PRODUCT_EM9191 0x90d3 +#define SIERRA_PRODUCT_EM9291 0x90e3 /* UNISOC (Spreadtrum) products */ #define UNISOC_VENDOR_ID 0x1782 /* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */ #define TOZED_PRODUCT_LT70C 0x4055 +#define UNISOC_PRODUCT_UIS7720 0x4064 /* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */ #define LUAT_PRODUCT_AIR720U 0x4e00 -/* MeiG Smart Technology products */ -#define MEIGSMART_VENDOR_ID 0x2dee -/* MeiG Smart SRM825L based on Qualcomm 315 */ -#define MEIGSMART_PRODUCT_SRM825L 0x4d22 -/* MeiG Smart SLM320 based on UNISOC UIS8910 */ -#define MEIGSMART_PRODUCT_SLM320 0x4d41 -/* MeiG Smart SLM770A based on ASR1803 */ -#define MEIGSMART_PRODUCT_SLM770A 0x4d57 - /* Device flags */ /* Highest interface number which can be used with NCTRL() and RSVD() */ @@ -1278,6 +1272,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x40) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, @@ -1330,7 +1327,18 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(0) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1033, 0xff), /* Telit LE910C1-EUX (ECM) */ .driver_info = NCTRL(0) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1034, 0xff), /* Telit LE910C4-WWX (rmnet) */ + .driver_info = RSVD(2) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1035, 0xff) }, /* Telit LE910C4-WWX (ECM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1036, 0xff) }, /* Telit LE910C4-WWX */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1037, 0xff), /* Telit LE910C4-WWX (rmnet) */ + .driver_info = NCTRL(0) | NCTRL(1) | RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1038, 0xff), /* Telit LE910C4-WWX (rmnet) */ + .driver_info = NCTRL(0) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103b, 0xff), /* Telit LE910C4-WWX */ + .driver_info = NCTRL(0) | NCTRL(1) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x103c, 0xff), /* Telit LE910C4-WWX */ + .driver_info = NCTRL(0) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0), .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG1), @@ -1367,42 +1375,87 @@ static const struct usb_device_id option_ids[] = { .driver_info = NCTRL(2) | RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1063, 0xff), /* Telit LN920 (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1070, 0xff), /* Telit FN990 (rmnet) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1070, 0xff), /* Telit FN990A (rmnet) */ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1071, 0xff), /* Telit FN990 (MBIM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1071, 0xff), /* Telit FN990A (MBIM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1072, 0xff), /* Telit FN990 (RNDIS) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1072, 0xff), /* Telit FN990A (RNDIS) */ .driver_info = NCTRL(2) | RSVD(3) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff), /* Telit FN990 (ECM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1073, 0xff), /* Telit FN990A (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990 (PCIe) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1075, 0xff), /* Telit FN990A (PCIe) */ .driver_info = RSVD(0) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990 (rmnet) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1077, 0xff), /* Telit FN990A (rmnet + audio) */ .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990 (MBIM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1078, 0xff), /* Telit FN990A (MBIM + audio) */ .driver_info = NCTRL(0) | RSVD(1) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1082, 0xff), /* Telit FE990 (RNDIS) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1079, 0xff), /* Telit FN990A (RNDIS + audio) */ .driver_info = NCTRL(2) | RSVD(3) }, - { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1083, 0xff), /* Telit FE990 (ECM) */ + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1080, 0xff), /* Telit FE990A (rmnet) */ + .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1081, 0xff), /* Telit FE990A (MBIM) */ + .driver_info = NCTRL(0) | RSVD(1) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1082, 0xff), /* Telit FE990A (RNDIS) */ + .driver_info = NCTRL(2) | RSVD(3) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1083, 0xff), /* Telit FE990A (ECM) */ .driver_info = NCTRL(0) | RSVD(1) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a0, 0xff), /* Telit FN20C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a2, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a3, 0xff), /* Telit FN920C04 (ECM) */ + .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a4, 0xff), /* Telit FN20C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a7, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(4) }, + { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a8, 0xff), /* Telit FN920C04 (ECM) */ + .driver_info = NCTRL(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a9, 0xff), /* Telit FN20C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff), /* Telit FN920C04 (MBIM) */ .driver_info = NCTRL(3) | RSVD(4) | RSVD(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x30), /* Telit FE990B (rmnet) */ + .driver_info = NCTRL(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b1, 0xff, 0xff, 0x30), /* Telit FE990B (MBIM) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b1, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b1, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b2, 0xff, 0xff, 0x30), /* Telit FE990B (RNDIS) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b2, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b2, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x30), /* Telit FE990B (ECM) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b3, 0xff, 0xff, 0x60) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c0, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c4, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(3) }, { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10c8, 0xff), /* Telit FE910C04 (rmnet) */ .driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x30), /* Telit FN990B (rmnet) */ + .driver_info = NCTRL(5) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d0, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x30), /* Telit FE910C04 (ECM) */ + .driver_info = NCTRL(4) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10c7, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x30), /* Telit FN990B (MBIM) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d1, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d2, 0xff, 0xff, 0x30), /* Telit FN990B (RNDIS) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d2, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d2, 0xff, 0xff, 0x60) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d3, 0xff, 0xff, 0x30), /* Telit FN990B (ECM) */ + .driver_info = NCTRL(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d3, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10d3, 0xff, 0xff, 0x60) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), @@ -2070,6 +2123,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */ .driver_info = RSVD(7) }, + { USB_DEVICE(0x1e0e, 0x9071), /* Simcom SIM8230 RMNET mode */ + .driver_info = RSVD(3) | RSVD(4) }, + { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9078, 0xff), /* Simcom SIM8230 ECM mode */ + .driver_info = RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x907b, 0xff), /* Simcom SIM8230 RNDIS mode */ + .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9205, 0xff) }, /* Simcom SIM7070/SIM7080/SIM7090 AT+ECM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9206, 0xff) }, /* Simcom SIM7070/SIM7080/SIM7090 AT-only mode */ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200), @@ -2319,6 +2378,10 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(3) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe145, 0xff), /* Foxconn T99W651 RNDIS */ .driver_info = RSVD(5) | RSVD(6) }, + { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe15f, 0xff), /* Foxconn T99W709 */ + .driver_info = RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ + .driver_info = RSVD(3) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */ @@ -2347,6 +2410,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a05, 0xff) }, /* Fibocom FM650-CN (NCM mode) */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a06, 0xff) }, /* Fibocom FM650-CN (RNDIS mode) */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0a07, 0xff) }, /* Fibocom FM650-CN (MBIM mode) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d41, 0xff, 0, 0) }, /* MeiG Smart SLM320 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d57, 0xff, 0, 0) }, /* MeiG Smart SLM770A */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0, 0) }, /* MeiG Smart SRM815 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0x10, 0x02) }, /* MeiG Smart SLM828 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0x10, 0x03) }, /* MeiG Smart SLM828 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM815 and SRM825L */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825L */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825L */ { USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */ @@ -2401,17 +2472,16 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9291, 0xff, 0xff, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, UNISOC_PRODUCT_UIS7720, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM320, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SLM770A, 0xff, 0, 0) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x30) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x40) }, - { USB_DEVICE_AND_INTERFACE_INFO(MEIGSMART_VENDOR_ID, MEIGSMART_PRODUCT_SRM825L, 0xff, 0xff, 0x60) }, { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0530, 0xff), /* TCL IK512 MBIM */ .driver_info = NCTRL(1) }, { USB_DEVICE_INTERFACE_CLASS(0x1bbb, 0x0640, 0xff), /* TCL IK512 ECM */ .driver_info = NCTRL(3) }, + { USB_DEVICE_INTERFACE_CLASS(0x2949, 0x8700, 0xff) }, /* Neoway N723-EA */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index d172e8642d4a..5501898dfcfb 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -555,7 +555,7 @@ static void qt2_process_read_urb(struct urb *urb) newport = *(ch + 3); - if (newport > serial->num_ports) { + if (newport >= serial->num_ports) { dev_err(&port->dev, "%s - port change to invalid port: %i\n", __func__, newport); diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 24b8772a345e..bac5ab6377ae 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -101,6 +101,11 @@ DEVICE(nokia, NOKIA_IDS); { USB_DEVICE(0x09d7, 0x0100) } /* NovAtel FlexPack GPS */ DEVICE_N(novatel_gps, NOVATEL_IDS, 3); +/* OWON electronic test and measurement equipment driver */ +#define OWON_IDS() \ + { USB_DEVICE(0x5345, 0x1234) } /* HDS200 oscilloscopes and others */ +DEVICE(owon, OWON_IDS); + /* Siemens USB/MPI adapter */ #define SIEMENS_IDS() \ { USB_DEVICE(0x908, 0x0004) } @@ -135,6 +140,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &motorola_tetra_device, &nokia_device, &novatel_gps_device, + &owon_device, &siemens_mpi_device, &suunto_device, &vivopay_device, @@ -154,6 +160,7 @@ static const struct usb_device_id id_table[] = { MOTOROLA_TETRA_IDS(), NOKIA_IDS(), NOVATEL_IDS(), + OWON_IDS(), SIEMENS_IDS(), SUUNTO_IDS(), VIVOPAY_IDS(), diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 0c423916d7bf..a026c6cb6e68 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -252,7 +252,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun, return USB_STOR_TRANSPORT_ERROR; } - residue = bcs->Residue; + residue = le32_to_cpu(bcs->Residue); if (bcs->Tag != us->tag) return USB_STOR_TRANSPORT_ERROR; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 606a68bd8059..509e4e155f41 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -255,6 +255,13 @@ UNUSUAL_DEV( 0x0421, 0x06aa, 0x1110, 0x1110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_MAX_SECTORS_64 ), +/* Added by Lubomir Rintel , a very fine chap */ +UNUSUAL_DEV( 0x0421, 0x06c2, 0x0000, 0x0406, + "Nokia", + "Nokia 208", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + #ifdef NO_SDDR09 UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", @@ -927,6 +934,13 @@ UNUSUAL_DEV( 0x05e3, 0x0723, 0x9451, 0x9451, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_SANE_SENSE ), +/* Added by Maël GUERIN */ +UNUSUAL_DEV( 0x0603, 0x8611, 0x0000, 0xffff, + "Novatek", + "NTK96550-based camera", + USB_SC_SCSI, USB_PR_BULK, NULL, + US_FL_BULK_IGNORE_TAG ), + /* * Reported by Hanno Boeck * Taken from the Lycoris Kernel @@ -1476,6 +1490,28 @@ UNUSUAL_DEV( 0x0bc2, 0x3332, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_WP_DETECT ), +/* + * Reported by Zenm Chen + * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch + * the device into Wi-Fi mode. + */ +UNUSUAL_DEV( 0x0bda, 0x1a2b, 0x0000, 0xffff, + "Realtek", + "DISK", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE ), + +/* + * Reported by Zenm Chen + * Ignore driver CD mode, otherwise usb_modeswitch may fail to switch + * the device into Wi-Fi mode. + */ +UNUSUAL_DEV( 0x0bda, 0xa192, 0x0000, 0xffff, + "Realtek", + "DISK", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_DEVICE ), + UNUSUAL_DEV( 0x0d49, 0x7310, 0x0000, 0x9999, "Maxtor", "USB to SATA", diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index a4513dd931b2..ff296434d601 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -52,6 +52,13 @@ UNUSUAL_DEV(0x059f, 0x1061, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_OPCODES | US_FL_NO_SAME), +/* Reported-by: Zhihong Zhou */ +UNUSUAL_DEV(0x0781, 0x55e8, 0x0000, 0x9999, + "SanDisk", + "", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_IGNORE_UAS), + /* Reported-by: Hongling Zeng */ UNUSUAL_DEV(0x090c, 0x2000, 0x0000, 0x9999, "Hiksemi", @@ -83,6 +90,13 @@ UNUSUAL_DEV(0x0bc2, 0x331a, 0x0000, 0x9999, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_LUNS), +/* Reported-by: Oliver Neukum */ +UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, + "ADATA", + "Portable HDD CH94", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_ATA_1X), + /* Reported-by: Benjamin Tissoires */ UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x9999, "Initio Corporation", diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index a2a1baabca93..464fd15e12ad 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -288,6 +288,9 @@ static int dp_altmode_vdm(struct typec_altmode *alt, break; case CMDT_RSP_NAK: switch (cmd) { + case DP_CMD_STATUS_UPDATE: + dp->state = DP_STATE_EXIT; + break; case DP_CMD_CONFIGURE: dp->data.conf = 0; ret = dp_altmode_configured(dp); @@ -488,7 +491,7 @@ static ssize_t pin_assignment_show(struct device *dev, assignments = get_current_pin_assignments(dp); - for (i = 0; assignments; assignments >>= 1, i++) { + for (i = 0; assignments && i < DP_PIN_ASSIGN_MAX; assignments >>= 1, i++) { if (assignments & 1) { if (i == cur) len += sprintf(buf + len, "[%s] ", diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 5e661bae3997..9d242c5213e1 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -104,6 +104,7 @@ struct fusb302_chip { bool vconn_on; bool vbus_on; bool charge_on; + bool pd_rx_on; bool vbus_present; enum typec_cc_polarity cc_polarity; enum typec_cc_status cc1; @@ -841,6 +842,11 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) int ret = 0; mutex_lock(&chip->lock); + if (chip->pd_rx_on == on) { + fusb302_log(chip, "pd is already %s", on ? "on" : "off"); + goto done; + } + ret = fusb302_pd_rx_flush(chip); if (ret < 0) { fusb302_log(chip, "cannot flush pd rx buffer, ret=%d", ret); @@ -863,6 +869,8 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) on ? "on" : "off", ret); goto done; } + + chip->pd_rx_on = on; fusb302_log(chip, "pd := %s", on ? "on" : "off"); done: mutex_unlock(&chip->lock); diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index b56a0880a044..76ab5eb6d7f2 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -217,6 +217,11 @@ static int rt1711h_probe(struct i2c_client *client, { int ret; struct rt1711h_chip *chip; + const u16 alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED | + TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST | + TCPC_ALERT_RX_STATUS | TCPC_ALERT_POWER_STATUS | + TCPC_ALERT_CC_STATUS | TCPC_ALERT_RX_BUF_OVF | + TCPC_ALERT_FAULT; ret = rt1711h_check_revision(client); if (ret < 0) { @@ -258,6 +263,12 @@ static int rt1711h_probe(struct i2c_client *client, dev_name(chip->dev), chip); if (ret < 0) return ret; + + /* Enable alert interrupts */ + ret = rt1711h_write16(chip, TCPC_ALERT_MASK, alert_mask); + if (ret < 0) + return ret; + enable_irq_wake(client->irq); return 0; diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 446d09d89860..ae2d03c3ec1e 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -3009,7 +3009,7 @@ static void run_state_machine(struct tcpm_port *port) port->caps_count = 0; port->pd_capable = true; tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT, - PD_T_SEND_SOURCE_CAP); + PD_T_SENDER_RESPONSE); } break; case SRC_SEND_CAPABILITIES_TIMEOUT: @@ -3761,7 +3761,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, case SNK_TRY_WAIT_DEBOUNCE: if (!tcpm_port_is_sink(port)) { port->max_wait = 0; - tcpm_set_state(port, SRC_TRYWAIT, 0); + tcpm_set_state(port, SRC_TRYWAIT, PD_T_PD_DEBOUNCE); } break; case SRC_TRY_WAIT: diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index 7f843e3b182d..fb01280e71e4 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -270,6 +270,8 @@ void ucsi_displayport_remove_partner(struct typec_altmode *alt) if (!dp) return; + cancel_work_sync(&dp->work); + dp->data.conf = 0; dp->data.status = 0; dp->initialized = false; diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 4cf64c45732c..f0e11da306d9 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -25,7 +25,7 @@ * difficult to estimate the time it takes for the system to process the command * before it is actually passed to the PPM. */ -#define UCSI_TIMEOUT_MS 5000 +#define UCSI_TIMEOUT_MS 10000 /* * UCSI_SWAP_TIMEOUT_MS - Timeout for role swap requests diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index ee8fa558e3ed..d31b7e5895ce 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -765,6 +765,17 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag ctrlreq->wValue, vdev->rhport); vdev->udev = usb_get_dev(urb->dev); + /* + * NOTE: A similar operation has been done via + * USB_REQ_GET_DESCRIPTOR handler below, which is + * supposed to always precede USB_REQ_SET_ADDRESS. + * + * It's not entirely clear if operating on a different + * usb_device instance here is a real possibility, + * otherwise this call and vdev->udev assignment above + * should be dropped. + */ + dev_pm_syscore_device(&vdev->udev->dev, true); usb_put_dev(old); spin_lock(&vdev->ud.lock); @@ -785,6 +796,17 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flag "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n"); vdev->udev = usb_get_dev(urb->dev); + /* + * Set syscore PM flag for the virtually attached + * devices to ensure they will not enter suspend on + * the client side. + * + * Note this doesn't have any impact on the physical + * devices attached to the host system on the server + * side, hence there is no need to undo the operation + * on disconnect. + */ + dev_pm_syscore_device(&vdev->udev->dev, true); usb_put_dev(old); goto out; diff --git a/include/linux/hid.h b/include/linux/hid.h index 115224aefa94..ec0efababc79 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -671,8 +671,9 @@ struct hid_descriptor { __le16 bcdHID; __u8 bCountryCode; __u8 bNumDescriptors; + struct hid_class_descriptor rpt_desc; - struct hid_class_descriptor desc[1]; + struct hid_class_descriptor opt_descs[]; } __attribute__ ((packed)); #define HID_DEVICE(b, g, ven, prod) \ diff --git a/include/linux/usb.h b/include/linux/usb.h index aaf6016614ee..14f72024d108 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -713,13 +713,12 @@ struct usb_device { unsigned long active_duration; -#ifdef CONFIG_PM unsigned long connect_time; unsigned do_remote_wakeup:1; unsigned reset_resume:1; unsigned port_is_suspended:1; -#endif + struct wusb_dev *wusb_dev; int slot_id; enum usb_device_removable removable; diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index edd89b7c8f18..54167a2d28ea 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -67,6 +67,7 @@ struct ci_hdrc_platform_data { #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 #define CI_HDRC_IMX_HSIC_ACTIVE_EVENT 2 #define CI_HDRC_IMX_HSIC_SUSPEND_EVENT 3 +#define CI_HDRC_CONTROLLER_VBUS_EVENT 4 int (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index ca8ec43770a9..91e9db289303 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -498,9 +498,7 @@ extern void usb_hcd_pci_shutdown(struct pci_dev *dev); extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); -#ifdef CONFIG_PM extern const struct dev_pm_ops usb_hcd_pci_pm_ops; -#endif #endif /* CONFIG_USB_PCI */ /* pci-ish (pdev null is ok) buffer alloc/mapping support */ diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h index 296909ea04f2..afb73b3e0b80 100644 --- a/include/linux/usb/typec_dp.h +++ b/include/linux/usb/typec_dp.h @@ -56,6 +56,7 @@ enum { DP_PIN_ASSIGN_D, DP_PIN_ASSIGN_E, DP_PIN_ASSIGN_F, /* Not supported after v1.0b */ + DP_PIN_ASSIGN_MAX, }; /* DisplayPort alt mode specific commands */ From 1df27edaaf6a80ffe005d571acd173db1c0b3688 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Tue, 5 May 2026 20:00:10 +0300 Subject: [PATCH 205/306] Revert "wifi: cfg80211: Increase akm_suites array size in" This reverts commit 525fb1b48fc85dcf0855c0a415b4deed063e85b0. Reason for revert: Breaks WiFi, likely needs additional changes to be backported for it to work properly. Change-Id: Ifc537c0dc80d759a9ab12671c7ff053ad6c31759 --- drivers/net/wireless/quantenna/qtnfmac/commands.c | 12 ++++-------- include/net/cfg80211.h | 12 +----------- include/uapi/linux/nl80211.h | 14 -------------- net/wireless/core.c | 6 ------ net/wireless/nl80211.c | 7 +------ 5 files changed, 6 insertions(+), 45 deletions(-) diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index 9c7f2121970d..106f1a846f49 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -222,7 +222,6 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, struct qlink_auth_encr *aen; int ret; int i; - int n; if (!qtnf_cmd_start_ap_can_fit(vif, s)) return -E2BIG; @@ -254,9 +253,8 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif, for (i = 0; i < QLINK_MAX_NR_CIPHER_SUITES; i++) aen->ciphers_pairwise[i] = cpu_to_le32(s->crypto.ciphers_pairwise[i]); - n = min(QLINK_MAX_NR_AKM_SUITES, s->crypto.n_akm_suites); - aen->n_akm_suites = cpu_to_le32(n); - for (i = 0; i < n; i++) + aen->n_akm_suites = cpu_to_le32(s->crypto.n_akm_suites); + for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) aen->akm_suites[i] = cpu_to_le32(s->crypto.akm_suites[i]); aen->control_port = s->crypto.control_port; aen->control_port_no_encrypt = s->crypto.control_port_no_encrypt; @@ -2202,7 +2200,6 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, struct qlink_auth_encr *aen; int ret; int i; - int n; u32 connect_flags = 0; cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2259,10 +2256,9 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif, aen->ciphers_pairwise[i] = cpu_to_le32(sme->crypto.ciphers_pairwise[i]); - n = min(QLINK_MAX_NR_AKM_SUITES, sme->crypto.n_akm_suites); - aen->n_akm_suites = cpu_to_le32(n); + aen->n_akm_suites = cpu_to_le32(sme->crypto.n_akm_suites); - for (i = 0; i < n; i++) + for (i = 0; i < QLINK_MAX_NR_AKM_SUITES; i++) aen->akm_suites[i] = cpu_to_le32(sme->crypto.akm_suites[i]); aen->control_port = sme->crypto.control_port; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 44f8a22d95e7..9a9c633f84a4 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -903,7 +903,6 @@ struct survey_info { }; #define CFG80211_MAX_WEP_KEYS 4 -#define CFG80211_MAX_NUM_AKM_SUITES 10 /** * struct cfg80211_crypto_settings - Crypto settings @@ -938,7 +937,7 @@ struct cfg80211_crypto_settings { int n_ciphers_pairwise; u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; int n_akm_suites; - u32 akm_suites[CFG80211_MAX_NUM_AKM_SUITES]; + u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; bool control_port; __be16 control_port_ethertype; bool control_port_no_encrypt; @@ -4683,13 +4682,6 @@ struct wiphy_iftype_akm_suites { * supported by the driver for each vif * @tid_config_support.peer: bitmap of attributes (configurations) * supported by the driver for each peer - * @max_num_akm_suites: maximum number of AKM suites allowed for - * configuration through %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and - * %NL80211_CMD_START_AP. Set to NL80211_MAX_NR_AKM_SUITES if not set by - * driver. If set by driver minimum allowed value is - * NL80211_MAX_NR_AKM_SUITES in order to avoid compatibility issues with - * legacy userspace and maximum allowed value is - * CFG80211_MAX_NUM_AKM_SUITES. */ struct wiphy { /* assign these fields before you register the wiphy */ @@ -4841,8 +4833,6 @@ struct wiphy { u64 peer, vif; } tid_config_support; - u16 max_num_akm_suites; - char priv[0] __aligned(NETDEV_ALIGN); }; diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index d485d9d3e574..05e7a411cfa0 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2465,13 +2465,6 @@ enum nl80211_commands { * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from * association request when used with NL80211_CMD_NEW_STATION). * - * @NL80211_ATTR_MAX_NUM_AKM_SUITES: U16 attribute. Indicates maximum number of - * AKM suites allowed for %NL80211_CMD_CONNECT, %NL80211_CMD_ASSOCIATE and - * %NL80211_CMD_START_AP in %NL80211_CMD_GET_WIPHY response. If this - * attribute is not present userspace shall consider maximum number of AKM - * suites allowed as %NL80211_MAX_NR_AKM_SUITES which is the legacy maximum - * number prior to the introduction of this attribute. - * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2949,8 +2942,6 @@ enum nl80211_attrs { NL80211_ATTR_HE_6GHZ_CAPABILITY, - NL80211_ATTR_MAX_NUM_AKM_SUITES = 316, - /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3003,11 +2994,6 @@ enum nl80211_attrs { #define NL80211_HE_MIN_CAPABILITY_LEN 16 #define NL80211_HE_MAX_CAPABILITY_LEN 54 #define NL80211_MAX_NR_CIPHER_SUITES 5 - -/* - * NL80211_MAX_NR_AKM_SUITES is obsolete when %NL80211_ATTR_MAX_NUM_AKM_SUITES - * present in %NL80211_CMD_GET_WIPHY response. - */ #define NL80211_MAX_NR_AKM_SUITES 2 #define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 diff --git a/net/wireless/core.c b/net/wireless/core.c index e558b71acdfc..3983251f2756 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -894,12 +894,6 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; #endif - if (!wiphy->max_num_akm_suites) - wiphy->max_num_akm_suites = NL80211_MAX_NR_AKM_SUITES; - else if (wiphy->max_num_akm_suites < NL80211_MAX_NR_AKM_SUITES || - wiphy->max_num_akm_suites > CFG80211_MAX_NUM_AKM_SUITES) - return -EINVAL; - /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e665193c968e..f3f467ab44a7 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -656,7 +656,6 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { .type = NLA_EXACT_LEN, .len = sizeof(struct ieee80211_he_6ghz_capa), }, - [NL80211_ATTR_MAX_NUM_AKM_SUITES] = { .type = NLA_REJECT }, }; /* policy for the key attributes */ @@ -2575,10 +2574,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev, if (nl80211_put_tid_config_support(rdev, msg)) goto nla_put_failure; - if (nla_put_u16(msg, NL80211_ATTR_MAX_NUM_AKM_SUITES, - rdev->wiphy.max_num_akm_suites)) - goto nla_put_failure; - /* done */ state->split_start = 0; break; @@ -9385,7 +9380,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev, if (len % sizeof(u32)) return -EINVAL; - if (settings->n_akm_suites > rdev->wiphy.max_num_akm_suites) + if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES) return -EINVAL; memcpy(settings->akm_suites, data, len); From 374cf47171076659ea3bdfd9d62bee601e80e41b Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Tue, 19 Aug 2025 11:00:16 +0530 Subject: [PATCH 206/306] kgsl: Avoid use after free in kgsl_destroy_ion() When deallocating dma-buf metadata in kgsl_destroy_ion, the priv_data pointer in the associated kgsl_mem_entry structure is not reset after kfree(). To avoid use after free, set entry->priv_data to NULL immediately after freeing metadata. Change-Id: Ia222d3a88666b7ee406f1508eb37a4eef766c83e Signed-off-by: Shiv Kumar Signed-off-by: Pankaj Gupta --- drivers/gpu/msm/kgsl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 2082d4f27f83..0699fdadade3 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -355,6 +355,7 @@ static void kgsl_destroy_ion(struct kgsl_memdesc *memdesc) } memdesc->sgt = NULL; + entry->priv_data = NULL; } static const struct kgsl_memdesc_ops kgsl_dmabuf_ops = { From 28e935c7d0921ec0ef5f10e82777559a1fb41a00 Mon Sep 17 00:00:00 2001 From: Om Deore Date: Tue, 15 Jul 2025 13:30:42 +0530 Subject: [PATCH 207/306] BACKPORT: dsp-kernel: Validate page range with map range before passing to DSP In case of unaligned start address and NOVA flag set, range validation is by-passed. The page size calculated using unaligned address passed by user is aligned to nearest boundary internally which returns page size 4KB more. In order to avoid out of bounds issue, check page range is within map range. Change-Id: Ie2de944206eee0730c8ba081f05b7d7cccc72276 Signed-off-by: Om Deore --- drivers/misc/fastrpc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 3cf9ba563cfc..c3603eb6f538 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -813,6 +813,22 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) PAGE_SHIFT; pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE; + /* + * Check for page range overflow and validate page + * range is not greater than map buffer range. + * This prevents potential buffer overflow + * and memory corruption that could be exploited. + */ + if (pages[i].addr > (ULLONG_MAX - pages[i].size) || + (pages[i].addr + pages[i].size) > + (ctx->maps[i]->phys + ctx->maps[i]->size)) { + err = -EFAULT; + dev_err(dev, + "Invalid buffer addr 0x%llx len 0x%llx IPA 0x%llx size 0x%llx fd %d\n", + ctx->args[i].ptr, len, ctx->maps[i]->phys, + ctx->maps[i]->size, ctx->maps[i]->fd); + goto bail; + } } else { if (ctx->olaps[oix].offset == 0) { From 5920e58e41cf0d30508c600d68202970ad533174 Mon Sep 17 00:00:00 2001 From: Ramesh Nallagopu Date: Tue, 8 Jul 2025 15:00:51 +0530 Subject: [PATCH 208/306] BACKPORT: dsp-kernel: Separate overlap handling for ION and non-ION buffers Currently, overlap calculation did not distinguish between ION and non-ION buffers. This could result in incorrect offsets when an ION buffer overlapped with a non-ION buffer, leading to out-of-bounds writes and potential security issues. Calculate overlap ranges separately for ION and non-ION buffers. Change-Id: If5eb57d447b68d58d8821ecfbf2d9375b2cd1f8e Signed-off-by: Ramesh Nallagopu --- drivers/misc/fastrpc.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index c3603eb6f538..198d22d73724 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -379,9 +379,21 @@ static int olaps_cmp(const void *a, const void *b) return st == 0 ? ed : st; } +/** + * fastrpc_get_buff_overlaps - Detect and handle buffer overlaps in RPC args + * @ctx: The invoke context containing buffer information + * + * This function detects overlapping memory regions in the RPC arguments and + * adjusts the memory mapping accordingly. It handles ION and non-ION buffers + * separately to prevent incorrect overlap detection between different buf types. + * For each buffer type: + * - If a buffer overlaps with a previous buffer of the same type, it adjusts + * the mapping to avoid the overlap + * - If no overlap is detected, it uses the full buffer range + */ static void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx) { - u64 max_end = 0; + u64 ion_buf_end_pos = 0, non_ion_buf_end_pos = 0; int i; for (i = 0; i < ctx->nbufs; ++i) { @@ -393,24 +405,29 @@ static void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx) sort(ctx->olaps, ctx->nbufs, sizeof(*ctx->olaps), olaps_cmp, NULL); for (i = 0; i < ctx->nbufs; ++i) { - /* Falling inside previous range */ - if (ctx->olaps[i].start < max_end) { - ctx->olaps[i].mstart = max_end; - ctx->olaps[i].mend = ctx->olaps[i].end; - ctx->olaps[i].offset = max_end - ctx->olaps[i].start; + /* Separate ION and non-ION buffers; fd <= 0 indicates non-ION */ + u64 *last_buf_end = (ctx->args[ctx->olaps[i].raix].fd <= 0) ? + &non_ion_buf_end_pos : &ion_buf_end_pos; - if (ctx->olaps[i].end > max_end) { - max_end = ctx->olaps[i].end; + if (ctx->olaps[i].start < *last_buf_end) { + /* Overlap detected within same buffer type */ + ctx->olaps[i].mstart = *last_buf_end; + ctx->olaps[i].mend = ctx->olaps[i].end; + ctx->olaps[i].offset = *last_buf_end - ctx->olaps[i].start; + + if (ctx->olaps[i].end > *last_buf_end) { + *last_buf_end = ctx->olaps[i].end; } else { ctx->olaps[i].mend = 0; ctx->olaps[i].mstart = 0; } } else { + /* No overlap, assign full range */ ctx->olaps[i].mend = ctx->olaps[i].end; ctx->olaps[i].mstart = ctx->olaps[i].start; ctx->olaps[i].offset = 0; - max_end = ctx->olaps[i].end; + *last_buf_end = ctx->olaps[i].end; } } } From 9d360777daa3cabde6efc4c55ce10b0ef6165fab Mon Sep 17 00:00:00 2001 From: "liuwei.a" Date: Mon, 31 May 2021 16:20:14 +0800 Subject: [PATCH 209/306] ANDROID: GKI: Request enable some kernel configs for background speed limit function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change reason:to support the background speed limit function, we need to enable the configs as follow: CONFIG_NET_SCH_PRIO=y [*] CONFIG_NET_SCH_MULTIQ=y [*] CONFIG_NET_SCH_TBF=y CONFIG_NET_SCH_NETEM=y CONFIG_CLS_U32_MARK=y CONFIG_NET_CLS_FLOW=y CONFIG_NET_EMATCH_CMP=y CONFIG_NET_EMATCH_NBYTE=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_ACT_POLICE=y [*] CONFIG_NET_ACT_GACT=y [*] CONFIG_NET_ACT_MIRRED=y [*] CONFIG_NET_ACT_SKBEDIT=y [*] additionally enabled during backport to android11-5.4 to match 5.10+ Bug: 189705988 Signed-off-by: Maciej Żenczykowski Signed-off-by: liuwei.a Change-Id: I6f9a627bc2a2197b0da8a371ccd2a762b3147fc1 (cherry picked from commit da4b3a9637de63da6259e43bd4c0ead9504a8e40) --- arch/arm64/configs/gki_defconfig | 13 +++++++++++++ arch/x86/configs/gki_defconfig | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/arch/arm64/configs/gki_defconfig b/arch/arm64/configs/gki_defconfig index 59ddabbd31fc..e019f7338cf9 100644 --- a/arch/arm64/configs/gki_defconfig +++ b/arch/arm64/configs/gki_defconfig @@ -209,14 +209,27 @@ CONFIG_L2TP=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_NETEM=y CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y CONFIG_NET_CLS_BPF=y CONFIG_NET_CLS_MATCHALL=y CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y CONFIG_NET_ACT_BPF=y CONFIG_BPF_JIT=y CONFIG_BT=y diff --git a/arch/x86/configs/gki_defconfig b/arch/x86/configs/gki_defconfig index 5e751e6cb304..69c584a27a3a 100644 --- a/arch/x86/configs/gki_defconfig +++ b/arch/x86/configs/gki_defconfig @@ -188,14 +188,27 @@ CONFIG_L2TP=y CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_NETEM=y CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y CONFIG_NET_CLS_BPF=y CONFIG_NET_CLS_MATCHALL=y CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y CONFIG_NET_ACT_BPF=y CONFIG_BPF_JIT=y CONFIG_BT=y From 83fb6ffcab53f292b9c7d1ee214ef0742aa8d764 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 8 Apr 2020 00:53:52 +0900 Subject: [PATCH 210/306] UPSTREAM: kbuild: add dummy toolchains to enable all cc-option etc. in Kconfig Staring v4.18, Kconfig evaluates compiler capabilities, and hides CONFIG options your compiler does not support. This works well if you configure and build the kernel on the same host machine. It is inconvenient if you prepare the .config that is carried to a different build environment (typically this happens when you package the kernel for distros) because using a different compiler potentially produces different CONFIG options than the real build environment. So, you probably want to make as many options visible as possible. In other words, you need to create a super-set of CONFIG options that cover any build environment. If some of the CONFIG options turned out to be unsupported on the build machine, they are automatically disabled by the nature of Kconfig. However, it is not feasible to get a full-featured compiler for every arch. This issue was discussed here: https://lkml.org/lkml/2019/12/9/620 Other than distros, savedefconfig is also a problem. Some arch sub-systems periodically resync defconfig files. If you use a less-capable compiler for savedefconfig, options that do not meet 'depends on $(cc-option,...)' will be forcibly disabled. So, 'make defconfig && make savedefconfig' may silently change the behavior. This commit adds a set of dummy toolchains that pretend to support any feature. Most of compiler features are tested by cc-option, which simply checks the exit code of $(CC). The dummy tools are shell scripts that always exit with 0. So, $(cc-option, ...) is evaluated as 'y'. There are more complicated checks such as: scripts/gcc-x86_{32,64}-has-stack-protector.sh scripts/gcc-plugin.sh scripts/tools-support-relr.sh scripts/dummy-tools/gcc passes all checks. From the top directory of the source tree, you can do: $ make CROSS_COMPILE=scripts/dummy-tools/ oldconfig Change-Id: Ic0ed9f3c73888a14c38c5ce546bc171b479c35ed Signed-off-by: Masahiro Yamada Reviewed-by: Philipp Rudo Tested-by: Jeremy Cline --- scripts/dummy-tools/gcc | 91 +++++++++++++++++++++++++++++++++++++ scripts/dummy-tools/ld | 30 ++++++++++++ scripts/dummy-tools/nm | 1 + scripts/dummy-tools/objcopy | 1 + 4 files changed, 123 insertions(+) create mode 100755 scripts/dummy-tools/gcc create mode 100755 scripts/dummy-tools/ld create mode 120000 scripts/dummy-tools/nm create mode 120000 scripts/dummy-tools/objcopy diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc new file mode 100755 index 000000000000..33487e99d83e --- /dev/null +++ b/scripts/dummy-tools/gcc @@ -0,0 +1,91 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Staring v4.18, Kconfig evaluates compiler capabilities, and hides CONFIG +# options your compiler does not support. This works well if you configure and +# build the kernel on the same host machine. +# +# It is inconvenient if you prepare the .config that is carried to a different +# build environment (typically this happens when you package the kernel for +# distros) because using a different compiler potentially produces different +# CONFIG options than the real build environment. So, you probably want to make +# as many options visible as possible. In other words, you need to create a +# super-set of CONFIG options that cover any build environment. If some of the +# CONFIG options turned out to be unsupported on the build machine, they are +# automatically disabled by the nature of Kconfig. +# +# However, it is not feasible to get a full-featured compiler for every arch. +# Hence these dummy toolchains to make all compiler tests pass. +# +# Usage: +# +# From the top directory of the source tree, run +# +# $ make CROSS_COMPILE=scripts/dummy-tools/ oldconfig +# +# Most of compiler features are tested by cc-option, which simply checks the +# exit code of $(CC). This script does nothing and just exits with 0 in most +# cases. So, $(cc-option, ...) is evaluated as 'y'. +# +# This scripts caters to more checks; handle --version and pre-process __GNUC__ +# etc. to pretend to be GCC, and also do right things to satisfy some scripts. + +# Check if the first parameter appears in the rest. Succeeds if found. +# This helper is useful if a particular option was passed to this script. +# Typically used like this: +# arg_contain "$@" +arg_contain () +{ + search="$1" + shift + + while [ $# -gt 0 ] + do + if [ "$search" = "$1" ]; then + return 0 + fi + shift + done + + return 1 +} + +# To set CONFIG_CC_IS_GCC=y +if arg_contain --version "$@"; then + echo "gcc (scripts/dummy-tools/gcc)" + exit 0 +fi + +if arg_contain -E "$@"; then + # For scripts/gcc-version.sh; This emulates GCC 20.0.0 + if arg_contain - "$@"; then + sed 's/^__GNUC__$/20/; s/^__GNUC_MINOR__$/0/; s/^__GNUC_PATCHLEVEL__$/0/' + exit 0 + else + echo "no input files" >&2 + exit 1 + fi +fi + +if arg_contain -S "$@"; then + # For scripts/gcc-x86-*-has-stack-protector.sh + if arg_contain -fstack-protector "$@"; then + echo "%gs" + exit 0 + fi +fi + +# For scripts/gcc-plugin.sh +if arg_contain -print-file-name=plugin "$@"; then + plugin_dir=$(mktemp -d) + + sed -n 's/.*#include "\(.*\)"/\1/p' $(dirname $0)/../gcc-plugins/gcc-common.h | + while read header + do + mkdir -p $plugin_dir/include/$(dirname $header) + touch $plugin_dir/include/$header + done + + echo $plugin_dir + exit 0 +fi diff --git a/scripts/dummy-tools/ld b/scripts/dummy-tools/ld new file mode 100755 index 000000000000..f68233050405 --- /dev/null +++ b/scripts/dummy-tools/ld @@ -0,0 +1,30 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +# Dummy script that always succeeds. + +# Check if the first parameter appears in the rest. Succeeds if found. +# This helper is useful if a particular option was passed to this script. +# Typically used like this: +# arg_contain "$@" +arg_contain () +{ + search="$1" + shift + + while [ $# -gt 0 ] + do + if [ "$search" = "$1" ]; then + return 0 + fi + shift + done + + return 1 +} + +if arg_contain --version "$@" || arg_contain -v "$@"; then + progname=$(basename $0) + echo "GNU $progname (scripts/dummy-tools/$progname) 2.50" + exit 0 +fi diff --git a/scripts/dummy-tools/nm b/scripts/dummy-tools/nm new file mode 120000 index 000000000000..c0648b38dd42 --- /dev/null +++ b/scripts/dummy-tools/nm @@ -0,0 +1 @@ +ld \ No newline at end of file diff --git a/scripts/dummy-tools/objcopy b/scripts/dummy-tools/objcopy new file mode 120000 index 000000000000..c0648b38dd42 --- /dev/null +++ b/scripts/dummy-tools/objcopy @@ -0,0 +1 @@ +ld \ No newline at end of file From f8e9ee98c3c2d108c403f7f30ec9c5b59087e93a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 3 Mar 2021 11:43:14 +0100 Subject: [PATCH 211/306] UPSTREAM: kbuild: dummy-tools: fix inverted tests for gcc [ Upstream commit b3d9fc1436808a4ef9927e558b3415e728e710c5 ] There is a test in Kconfig which takes inverted value of a compiler check: * config CC_HAS_INT128 def_bool !$(cc-option,$(m64-flag) -D__SIZEOF_INT128__=0) This results in CC_HAS_INT128 not being in super-config generated by dummy-tools. So take this into account in the gcc script. Change-Id: Iaf7eb5d969bd92617c622a164bf7a2db58675932 Signed-off-by: Jiri Slaby Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin --- scripts/dummy-tools/gcc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc index 33487e99d83e..11c9f045ee4b 100755 --- a/scripts/dummy-tools/gcc +++ b/scripts/dummy-tools/gcc @@ -89,3 +89,8 @@ if arg_contain -print-file-name=plugin "$@"; then echo $plugin_dir exit 0 fi + +# inverted return value +if arg_contain -D__SIZEOF_INT128__=0 "$@"; then + exit 1 +fi From 0458cbd7932ecab3558601f84b2f0117688106dd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 23 Jan 2021 18:16:30 +0900 Subject: [PATCH 212/306] UPSTREAM: kbuild: simplify GCC_PLUGINS enablement in dummy-tools/gcc commit f4c3b83b75b91c5059726cb91e3165cc01764ce7 upstream. With commit 1e860048c53e ("gcc-plugins: simplify GCC plugin-dev capability test") applied, this hunk can be way simplified because now scripts/gcc-plugins/Kconfig only checks plugin-version.h Change-Id: Ic718951bcba65cdfe92ac2b8b6857ad96424408c Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- scripts/dummy-tools/gcc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc index 11c9f045ee4b..0d0589cf8184 100755 --- a/scripts/dummy-tools/gcc +++ b/scripts/dummy-tools/gcc @@ -75,16 +75,12 @@ if arg_contain -S "$@"; then fi fi -# For scripts/gcc-plugin.sh +# To set GCC_PLUGINS if arg_contain -print-file-name=plugin "$@"; then plugin_dir=$(mktemp -d) - sed -n 's/.*#include "\(.*\)"/\1/p' $(dirname $0)/../gcc-plugins/gcc-common.h | - while read header - do - mkdir -p $plugin_dir/include/$(dirname $header) - touch $plugin_dir/include/$header - done + mkdir -p $plugin_dir/include + touch $plugin_dir/include/plugin-version.h echo $plugin_dir exit 0 From 9c8324ac4b78d042a3346a1a859a62aad8d16711 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 16 Mar 2021 01:12:56 +0900 Subject: [PATCH 213/306] BACKPORT: kbuild: check the minimum assembler version in Kconfig Documentation/process/changes.rst defines the minimum assembler version (binutils version), but we have never checked it in the build time. Kbuild never invokes 'as' directly because all assembly files in the kernel tree are *.S, hence must be preprocessed. I do not expect raw assembly source files (*.s) would be added to the kernel tree. Therefore, we always use $(CC) as the assembler driver, and commit aa824e0c962b ("kbuild: remove AS variable") removed 'AS'. However, we are still interested in the version of the assembler acting behind. As usual, the --version option prints the version string. $ as --version | head -n 1 GNU assembler (GNU Binutils for Ubuntu) 2.35.1 But, we do not have $(AS). So, we can add the -Wa prefix so that $(CC) passes --version down to the backing assembler. $ gcc -Wa,--version | head -n 1 gcc: fatal error: no input files compilation terminated. OK, we need to input something to satisfy gcc. $ gcc -Wa,--version -c -x assembler /dev/null -o /dev/null | head -n 1 GNU assembler (GNU Binutils for Ubuntu) 2.35.1 The combination of Clang and GNU assembler works in the same way: $ clang -no-integrated-as -Wa,--version -c -x assembler /dev/null -o /dev/null | head -n 1 GNU assembler (GNU Binutils for Ubuntu) 2.35.1 Clang with the integrated assembler fails like this: $ clang -integrated-as -Wa,--version -c -x assembler /dev/null -o /dev/null | head -n 1 clang: error: unsupported argument '--version' to option 'Wa,' For the last case, checking the error message is fragile. If the proposal for -Wa,--version support [1] is accepted, this may not be even an error in the future. One easy way is to check if -integrated-as is present in the passed arguments. We did not pass -integrated-as to CLANG_FLAGS before, but we can make it explicit. Nathan pointed out -integrated-as is the default for all of the architectures/targets that the kernel cares about, but it goes along with "explicit is better than implicit" policy. [2] With all this in my mind, I implemented scripts/as-version.sh to check the assembler version in Kconfig time. $ scripts/as-version.sh gcc GNU 23501 $ scripts/as-version.sh clang -no-integrated-as GNU 23501 $ scripts/as-version.sh clang -integrated-as LLVM 0 [1]: https://github.com/ClangBuiltLinux/linux/issues/1320 [2]: https://lore.kernel.org/linux-kbuild/20210307044253.v3h47ucq6ng25iay@archlinux-ax161/ Signed-off-by: Masahiro Yamada Reviewed-by: Nathan Chancellor [nd: conflict in arch/Kconfig due to missing dc5723b02e523 ("kbuild: add support for Clang LTO") which landed in v5.12-rc1] Signed-off-by: Nick Desaulniers (cherry picked from commit ba64beb17493a4bfec563100c86a462a15926f24) Bug: 210043760 Change-Id: I9bcc528adbb86fa902123611ce979af0dd455ad5 --- Makefile | 2 + init/Kconfig | 12 ++++++ scripts/Kconfig.include | 6 +++ scripts/as-version.sh | 82 +++++++++++++++++++++++++++++++++++++++++ scripts/dummy-tools/gcc | 6 +++ 5 files changed, 108 insertions(+) create mode 100755 scripts/as-version.sh diff --git a/Makefile b/Makefile index 29d4cff5f7de..3649f002f2db 100644 --- a/Makefile +++ b/Makefile @@ -599,6 +599,8 @@ ifeq ($(LLVM_IAS),0) CLANG_FLAGS += -no-integrated-as GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit)) CLANG_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE)) +else +CLANG_FLAGS += -integrated-as endif CLANG_FLAGS += -Werror=unknown-warning-option KBUILD_CPPFLAGS += $(CLANG_FLAGS) diff --git a/init/Kconfig b/init/Kconfig index 6eec64944307..4a08321034a6 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -44,6 +44,18 @@ config CLANG_VERSION int default $(shell,$(srctree)/scripts/clang-version.sh $(CC)) +config AS_IS_GNU + def_bool $(success,test "$(as-name)" = GNU) + +config AS_IS_LLVM + def_bool $(success,test "$(as-name)" = LLVM) + +config AS_VERSION + int + # Use clang version if this is the integrated assembler + default CLANG_VERSION if AS_IS_LLVM + default $(as-version) + config CC_CAN_LINK bool default $(success,$(srctree)/scripts/cc-can-link.sh $(CC) $(CLANG_FLAGS) $(USERCFLAGS) $(USERLDFLAGS) $(m64-flag)) if 64BIT diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include index 496d11c92c97..363c354e9562 100644 --- a/scripts/Kconfig.include +++ b/scripts/Kconfig.include @@ -51,3 +51,9 @@ gcc-version := $(shell,$(srctree)/scripts/gcc-version.sh $(CC)) cc-option-bit = $(if-success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null,$(1)) m32-flag := $(cc-option-bit,-m32) m64-flag := $(cc-option-bit,-m64) + +# Get the assembler name, version, and error out if it is not supported. +as-info := $(shell,$(srctree)/scripts/as-version.sh $(CC) $(CLANG_FLAGS)) +$(error-if,$(success,test -z "$(as-info)"),Sorry$(comma) this assembler is not supported.) +as-name := $(shell,set -- $(as-info) && echo $1) +as-version := $(shell,set -- $(as-info) && echo $2) diff --git a/scripts/as-version.sh b/scripts/as-version.sh new file mode 100755 index 000000000000..8b9410e329df --- /dev/null +++ b/scripts/as-version.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Print the assembler name and its version in a 5 or 6-digit form. +# Also, perform the minimum version check. +# (If it is the integrated assembler, return 0 as the version, and +# skip the version check.) + +set -e + +# Convert the version string x.y.z to a canonical 5 or 6-digit form. +get_canonical_version() +{ + IFS=. + set -- $1 + + # If the 2nd or 3rd field is missing, fill it with a zero. + # + # The 4th field, if present, is ignored. + # This occurs in development snapshots as in 2.35.1.20201116 + echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0})) +} + +# Clang fails to handle -Wa,--version unless -no-integrated-as is given. +# We check -(f)integrated-as, expecting it is explicitly passed in for the +# integrated assembler case. +check_integrated_as() +{ + while [ $# -gt 0 ]; do + if [ "$1" = -integrated-as -o "$1" = -fintegrated-as ]; then + # For the intergrated assembler, we do not check the + # version here. It is the same as the clang version, and + # it has been already checked by scripts/cc-version.sh. + echo LLVM 0 + exit 0 + fi + shift + done +} + +check_integrated_as "$@" + +orig_args="$@" + +# Get the first line of the --version output. +IFS=' +' +set -- $(LC_ALL=C "$@" -Wa,--version -c -x assembler /dev/null -o /dev/null 2>/dev/null) + +# Split the line on spaces. +IFS=' ' +set -- $1 + +min_tool_version=$(dirname $0)/min-tool-version.sh + +if [ "$1" = GNU -a "$2" = assembler ]; then + shift $(($# - 1)) + version=$1 + min_version=$($min_tool_version binutils) + name=GNU +else + echo "$orig_args: unknown assembler invoked" >&2 + exit 1 +fi + +# Some distributions append a package release number, as in 2.34-4.fc32 +# Trim the hyphen and any characters that follow. +version=${version%-*} + +cversion=$(get_canonical_version $version) +min_cversion=$(get_canonical_version $min_version) + +if [ "$cversion" -lt "$min_cversion" ]; then + echo >&2 "***" + echo >&2 "*** Assembler is too old." + echo >&2 "*** Your $name assembler version: $version" + echo >&2 "*** Minimum $name assembler version: $min_version" + echo >&2 "***" + exit 1 +fi + +echo $name $cversion diff --git a/scripts/dummy-tools/gcc b/scripts/dummy-tools/gcc index 0d0589cf8184..9f5e943e7491 100755 --- a/scripts/dummy-tools/gcc +++ b/scripts/dummy-tools/gcc @@ -67,6 +67,12 @@ if arg_contain -E "$@"; then fi fi +# To set CONFIG_AS_IS_GNU +if arg_contain -Wa,--version "$@"; then + echo "GNU assembler (scripts/dummy-tools) 2.50" + exit 0 +fi + if arg_contain -S "$@"; then # For scripts/gcc-x86-*-has-stack-protector.sh if arg_contain -fstack-protector "$@"; then From 74212e4117519c9adad1450a477fec36711e197a Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 28 Mar 2023 17:08:30 -0700 Subject: [PATCH 214/306] BACKPORT: kbuild: Switch to 'f' variants of integrated assembler flag commit 2185a7e4b0ade86c2c57fc63d4a7535c40254bd0 upstream. It has been brought up a few times in various code reviews that clang 3.5 introduced -f{,no-}integrated-as as the preferred way to enable and disable the integrated assembler, mentioning that -{no-,}integrated-as are now considered legacy flags. Switch the kernel over to using those variants in case there is ever a time where clang decides to remove the non-'f' variants of the flag. Also, fix a typo in a comment ("intergrated" -> "integrated"). Link: https://releases.llvm.org/3.5.0/tools/clang/docs/ReleaseNotes.html#new-compiler-flags Reviewed-by: Nick Desaulniers Change-Id: Id848bd57d5e27afb85cf51c26d9312751168407e Signed-off-by: Nathan Chancellor Signed-off-by: Masahiro Yamada [nathan: Backport to 5.10] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- Makefile | 4 ++-- scripts/as-version.sh | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 3649f002f2db..468bd11ba3a5 100644 --- a/Makefile +++ b/Makefile @@ -596,11 +596,11 @@ CLANG_FLAGS += --target=$(notdir $(CROSS_COMPILE:%-=%)) endif # CROSS_COMPILE ifeq ($(LLVM_IAS),0) -CLANG_FLAGS += -no-integrated-as +CLANG_FLAGS += -fno-integrated-as GCC_TOOLCHAIN_DIR := $(dir $(shell which $(CROSS_COMPILE)elfedit)) CLANG_FLAGS += --prefix=$(GCC_TOOLCHAIN_DIR)$(notdir $(CROSS_COMPILE)) else -CLANG_FLAGS += -integrated-as +CLANG_FLAGS += -fintegrated-as endif CLANG_FLAGS += -Werror=unknown-warning-option KBUILD_CPPFLAGS += $(CLANG_FLAGS) diff --git a/scripts/as-version.sh b/scripts/as-version.sh index 8b9410e329df..1a21495e9ff0 100755 --- a/scripts/as-version.sh +++ b/scripts/as-version.sh @@ -21,14 +21,14 @@ get_canonical_version() echo $((10000 * $1 + 100 * ${2:-0} + ${3:-0})) } -# Clang fails to handle -Wa,--version unless -no-integrated-as is given. -# We check -(f)integrated-as, expecting it is explicitly passed in for the +# Clang fails to handle -Wa,--version unless -fno-integrated-as is given. +# We check -fintegrated-as, expecting it is explicitly passed in for the # integrated assembler case. check_integrated_as() { while [ $# -gt 0 ]; do - if [ "$1" = -integrated-as -o "$1" = -fintegrated-as ]; then - # For the intergrated assembler, we do not check the + if [ "$1" = -fintegrated-as ]; then + # For the integrated assembler, we do not check the # version here. It is the same as the clang version, and # it has been already checked by scripts/cc-version.sh. echo LLVM 0 From 61798133a024b6d06cf8c5ebea08742d9e8cde2a Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Sun, 3 May 2026 19:55:51 +0300 Subject: [PATCH 215/306] Revert "Makefile: Fix LLVM_IAS condition after IAS default flip" This reverts commit af20c219259af1342affe777c8cf9bce55c24b49. Reason for revert: Replaced by upstream commit. Change-Id: I1482b87ca2fe94a377454728c004f3038df02137 --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 468bd11ba3a5..81fa87bd03e2 100644 --- a/Makefile +++ b/Makefile @@ -873,10 +873,10 @@ DEBUG_CFLAGS += -gsplit-dwarf else DEBUG_CFLAGS += -g endif -ifeq ($(LLVM_IAS),0) -KBUILD_AFLAGS += -Wa,-gdwarf-2 -else +ifeq ($(LLVM_IAS),1) KBUILD_AFLAGS += -g +else +KBUILD_AFLAGS += -Wa,-gdwarf-2 endif endif From 6d288859ed184849c4e5067e84e1186a5b677eb0 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 28 Mar 2023 17:08:31 -0700 Subject: [PATCH 216/306] BACKPORT: kbuild: check CONFIG_AS_IS_LLVM instead of LLVM_IAS commit 52cc02b910284d6bddba46cce402044ab775f314 upstream. LLVM_IAS is the user interface to set the -(no-)integrated-as flag, and it should be used only for that purpose. LLVM_IAS is checked in some places to determine the assembler type, but it is not precise. For example, $ make CC=gcc LLVM_IAS=1 ... will use the GNU assembler (i.e. binutils) since LLVM_IAS=1 is effective only when $(CC) is clang. Of course, 'CC=gcc LLVM_IAS=1' is an odd combination, but the build system can be more robust against such insane input. Commit ba64beb17493a ("kbuild: check the minimum assembler version in Kconfig") introduced CONFIG_AS_IS_GNU/LLVM, which is more precise because Kconfig checks the version string from the assembler in use. Change-Id: I190f91350cdb4305a01cabc80d952b0541aef521 Signed-off-by: Masahiro Yamada Reviewed-by: Nick Desaulniers Reviewed-by: Nathan Chancellor [nathan: Backport to 5.10] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- Makefile | 3 ++- arch/riscv/Makefile | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 81fa87bd03e2..b42946eb1203 100644 --- a/Makefile +++ b/Makefile @@ -873,7 +873,8 @@ DEBUG_CFLAGS += -gsplit-dwarf else DEBUG_CFLAGS += -g endif -ifeq ($(LLVM_IAS),1) + +ifdef CONFIG_AS_IS_LLVM KBUILD_AFLAGS += -g else KBUILD_AFLAGS += -Wa,-gdwarf-2 diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 1641d8201412..054ab2f280db 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -38,7 +38,7 @@ ifeq ($(CONFIG_LD_IS_LLD),y) ifeq ($(shell test $(CONFIG_LLD_VERSION) -lt 150000; echo $$?),0) KBUILD_CFLAGS += -mno-relax KBUILD_AFLAGS += -mno-relax -ifneq ($(LLVM_IAS),1) +ifndef CONFIG_AS_IS_LLVM KBUILD_CFLAGS += -Wa,-mno-relax KBUILD_AFLAGS += -Wa,-mno-relax endif From a8c70a62b8c16364bcab5045d84fa5c355e755f8 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 13 Oct 2023 14:44:12 -0700 Subject: [PATCH 217/306] BACKPORT: net: add sysctl accept_ra_min_rtr_lft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1671bcfd76fdc0b9e65153cf759153083755fe4c upstream. This change adds a new sysctl accept_ra_min_rtr_lft to specify the minimum acceptable router lifetime in an RA. If the received RA router lifetime is less than the configured value (and not 0), the RA is ignored. This is useful for mobile devices, whose battery life can be impacted by networks that configure RAs with a short lifetime. On such networks, the device should never gain IPv6 provisioning and should attempt to drop RAs via hardware offload, if available. Change-Id: I5e575f2e2d303c6736fc5e983b65003c7e7a075a Signed-off-by: Patrick Rohr Cc: Maciej Żenczykowski Cc: Lorenzo Colitti Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- Documentation/networking/ip-sysctl.txt | 8 ++++++++ include/linux/ipv6.h | 1 + include/uapi/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 10 ++++++++++ net/ipv6/ndisc.c | 18 ++++++++++++++++-- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 12cf648120f4..4f48e6398975 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1660,6 +1660,14 @@ accept_ra_min_hop_limit - INTEGER Default: 1 +accept_ra_min_rtr_lft - INTEGER + Minimum acceptable router lifetime in Router Advertisement. + + RAs with a router lifetime less than this value shall be + ignored. RAs with a router lifetime of 0 are unaffected. + + Default: 0 + accept_ra_pinfo - BOOLEAN Learn Prefix Information in Router Advertisement. diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 6f006ccbdca7..fbdbef37b4f4 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -33,6 +33,7 @@ struct ipv6_devconf { __s32 max_addresses; __s32 accept_ra_defrtr; __s32 accept_ra_min_hop_limit; + __s32 accept_ra_min_rtr_lft; __s32 accept_ra_pinfo; __s32 ignore_routes_with_linkdown; #ifdef CONFIG_IPV6_ROUTER_PREF diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 9c0f4a92bcff..79c11618a6b7 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -187,6 +187,7 @@ enum { DEVCONF_DISABLE_POLICY, DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN, DEVCONF_NDISC_TCLASS, + DEVCONF_ACCEPT_RA_MIN_RTR_LFT, DEVCONF_MAX }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 7b9ac231b654..0bd88451596c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -208,6 +208,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .accept_ra_defrtr = 1, .accept_ra_from_local = 0, .accept_ra_min_hop_limit= 1, + .accept_ra_min_rtr_lft = 0, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, @@ -263,6 +264,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .accept_ra_defrtr = 1, .accept_ra_from_local = 0, .accept_ra_min_hop_limit= 1, + .accept_ra_min_rtr_lft = 0, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, @@ -5547,6 +5549,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ADDR_GEN_MODE] = cnf->addr_gen_mode; array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy; array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass; + array[DEVCONF_ACCEPT_RA_MIN_RTR_LFT] = cnf->accept_ra_min_rtr_lft; } static inline size_t inet6_ifla6_size(void) @@ -6714,6 +6717,13 @@ static const struct ctl_table addrconf_sysctl[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "accept_ra_min_rtr_lft", + .data = &ipv6_devconf.accept_ra_min_rtr_lft, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, { .procname = "accept_ra_pinfo", .data = &ipv6_devconf.accept_ra_pinfo, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f6b5340c5e11..2b170586da01 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1224,6 +1224,8 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } + lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); + if (!ipv6_accept_ra(in6_dev)) { ND_PRINTK(2, info, "RA: %s, did not accept ra for dev: %s\n", @@ -1231,6 +1233,13 @@ static void ndisc_router_discovery(struct sk_buff *skb) goto skip_linkparms; } + if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_rtr_lft) { + ND_PRINTK(2, info, + "RA: router lifetime (%ds) is too short: %s\n", + lifetime, skb->dev->name); + goto skip_linkparms; + } + #ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific parameters from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { @@ -1283,8 +1292,6 @@ static void ndisc_router_discovery(struct sk_buff *skb) goto skip_defrtr; } - lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); - #ifdef CONFIG_IPV6_ROUTER_PREF pref = ra_msg->icmph.icmp6_router_pref; /* 10b is handled as if it were 00b (medium) */ @@ -1431,6 +1438,13 @@ skip_linkparms: goto out; } + if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_rtr_lft) { + ND_PRINTK(2, info, + "RA: router lifetime (%ds) is too short: %s\n", + lifetime, skb->dev->name); + goto out; + } + #ifdef CONFIG_IPV6_ROUTE_INFO if (!in6_dev->cnf.accept_ra_from_local && ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, From 2d6c1375ba3035256364bee4fe56dbef6dc54d32 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 13 Oct 2023 14:44:13 -0700 Subject: [PATCH 218/306] BACKPORT: net: change accept_ra_min_rtr_lft to affect all RA lifetimes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5027d54a9c30bc7ec808360378e2b4753f053f25 upstream. accept_ra_min_rtr_lft only considered the lifetime of the default route and discarded entire RAs accordingly. This change renames accept_ra_min_rtr_lft to accept_ra_min_lft, and applies the value to individual RA sections; in particular, router lifetime, PIO preferred lifetime, and RIO lifetime. If any of those lifetimes are lower than the configured value, the specific RA section is ignored. In order for the sysctl to be useful to Android, it should really apply to all lifetimes in the RA, since that is what determines the minimum frequency at which RAs must be processed by the kernel. Android uses hardware offloads to drop RAs for a fraction of the minimum of all lifetimes present in the RA (some networks have very frequent RAs (5s) with high lifetimes (2h)). Despite this, we have encountered networks that set the router lifetime to 30s which results in very frequent CPU wakeups. Instead of disabling IPv6 (and dropping IPv6 ethertype in the WiFi firmware) entirely on such networks, it seems better to ignore the misconfigured routers while still processing RAs from other IPv6 routers on the same network (i.e. to support IoT applications). The previous implementation dropped the entire RA based on router lifetime. This turned out to be hard to expand to the other lifetimes present in the RA in a consistent manner; dropping the entire RA based on RIO/PIO lifetimes would essentially require parsing the whole thing twice. Change-Id: I2168608875629ae07bbd30a02a061284110693e7 Fixes: 1671bcfd76fd ("net: add sysctl accept_ra_min_rtr_lft") Cc: Lorenzo Colitti Signed-off-by: Patrick Rohr Reviewed-by: Maciej Żenczykowski Reviewed-by: David Ahern Link: https://lore.kernel.org/r/20230726230701.919212-1-prohr@google.com Signed-off-by: Jakub Kicinski Signed-off-by: Greg Kroah-Hartman --- Documentation/networking/ip-sysctl.txt | 8 ++++---- include/linux/ipv6.h | 2 +- include/uapi/linux/ipv6.h | 2 +- net/ipv6/addrconf.c | 13 ++++++++----- net/ipv6/ndisc.c | 27 +++++++++++--------------- 5 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 4f48e6398975..11ad3403bdda 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1660,11 +1660,11 @@ accept_ra_min_hop_limit - INTEGER Default: 1 -accept_ra_min_rtr_lft - INTEGER - Minimum acceptable router lifetime in Router Advertisement. +accept_ra_min_lft - INTEGER + Minimum acceptable lifetime value in Router Advertisement. - RAs with a router lifetime less than this value shall be - ignored. RAs with a router lifetime of 0 are unaffected. + RA sections with a lifetime less than this value shall be + ignored. Zero lifetimes stay unaffected. Default: 0 diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index fbdbef37b4f4..6003273ec2e9 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -33,7 +33,7 @@ struct ipv6_devconf { __s32 max_addresses; __s32 accept_ra_defrtr; __s32 accept_ra_min_hop_limit; - __s32 accept_ra_min_rtr_lft; + __s32 accept_ra_min_lft; __s32 accept_ra_pinfo; __s32 ignore_routes_with_linkdown; #ifdef CONFIG_IPV6_ROUTER_PREF diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 79c11618a6b7..45406a092e4e 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -187,7 +187,7 @@ enum { DEVCONF_DISABLE_POLICY, DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN, DEVCONF_NDISC_TCLASS, - DEVCONF_ACCEPT_RA_MIN_RTR_LFT, + DEVCONF_ACCEPT_RA_MIN_LFT, DEVCONF_MAX }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0bd88451596c..051bbc0e7c74 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -208,7 +208,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .accept_ra_defrtr = 1, .accept_ra_from_local = 0, .accept_ra_min_hop_limit= 1, - .accept_ra_min_rtr_lft = 0, + .accept_ra_min_lft = 0, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, @@ -264,7 +264,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .accept_ra_defrtr = 1, .accept_ra_from_local = 0, .accept_ra_min_hop_limit= 1, - .accept_ra_min_rtr_lft = 0, + .accept_ra_min_lft = 0, .accept_ra_pinfo = 1, #ifdef CONFIG_IPV6_ROUTER_PREF .accept_ra_rtr_pref = 1, @@ -2751,6 +2751,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) return; } + if (valid_lft != 0 && valid_lft < in6_dev->cnf.accept_ra_min_lft) + return; + /* * Two things going on here: * 1) Add routes for on-link prefixes @@ -5549,7 +5552,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ADDR_GEN_MODE] = cnf->addr_gen_mode; array[DEVCONF_DISABLE_POLICY] = cnf->disable_policy; array[DEVCONF_NDISC_TCLASS] = cnf->ndisc_tclass; - array[DEVCONF_ACCEPT_RA_MIN_RTR_LFT] = cnf->accept_ra_min_rtr_lft; + array[DEVCONF_ACCEPT_RA_MIN_LFT] = cnf->accept_ra_min_lft; } static inline size_t inet6_ifla6_size(void) @@ -6718,8 +6721,8 @@ static const struct ctl_table addrconf_sysctl[] = { .proc_handler = proc_dointvec, }, { - .procname = "accept_ra_min_rtr_lft", - .data = &ipv6_devconf.accept_ra_min_rtr_lft, + .procname = "accept_ra_min_lft", + .data = &ipv6_devconf.accept_ra_min_lft, .maxlen = sizeof(int), .mode = 0644, .proc_handler = proc_dointvec, diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 2b170586da01..653e5bc7f047 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1224,8 +1224,6 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } - lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); - if (!ipv6_accept_ra(in6_dev)) { ND_PRINTK(2, info, "RA: %s, did not accept ra for dev: %s\n", @@ -1233,13 +1231,6 @@ static void ndisc_router_discovery(struct sk_buff *skb) goto skip_linkparms; } - if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_rtr_lft) { - ND_PRINTK(2, info, - "RA: router lifetime (%ds) is too short: %s\n", - lifetime, skb->dev->name); - goto skip_linkparms; - } - #ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific parameters from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { @@ -1280,6 +1271,14 @@ static void ndisc_router_discovery(struct sk_buff *skb) goto skip_defrtr; } + lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); + if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_lft) { + ND_PRINTK(2, info, + "RA: router lifetime (%ds) is too short: %s\n", + lifetime, skb->dev->name); + goto skip_defrtr; + } + /* Do not accept RA with source-addr found on local machine unless * accept_ra_from_local is set to true. */ @@ -1438,13 +1437,6 @@ skip_linkparms: goto out; } - if (lifetime != 0 && lifetime < in6_dev->cnf.accept_ra_min_rtr_lft) { - ND_PRINTK(2, info, - "RA: router lifetime (%ds) is too short: %s\n", - lifetime, skb->dev->name); - goto out; - } - #ifdef CONFIG_IPV6_ROUTE_INFO if (!in6_dev->cnf.accept_ra_from_local && ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, @@ -1469,6 +1461,9 @@ skip_linkparms: if (ri->prefix_len == 0 && !in6_dev->cnf.accept_ra_defrtr) continue; + if (ri->lifetime != 0 && + ntohl(ri->lifetime) < in6_dev->cnf.accept_ra_min_lft) + continue; if (ri->prefix_len < in6_dev->cnf.accept_ra_rt_info_min_plen) continue; if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) From f8a55ca46874cbf3f53446037a8cc90f19dea43b Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 13 Oct 2023 14:44:14 -0700 Subject: [PATCH 219/306] BACKPORT: net: release reference to inet6_dev pointer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 5cb249686e67dbef3ffe53887fa725eefc5a7144 upstream. addrconf_prefix_rcv returned early without releasing the inet6_dev pointer when the PIO lifetime is less than accept_ra_min_lft. Change-Id: Ic633a1ea28c96f712dce8875f24227ce02ab86b0 Fixes: 5027d54a9c30 ("net: change accept_ra_min_rtr_lft to affect all RA lifetimes") Cc: Maciej Żenczykowski Cc: Lorenzo Colitti Cc: David Ahern Cc: Simon Horman Reviewed-by: Simon Horman Reviewed-by: Maciej Żenczykowski Signed-off-by: Patrick Rohr Reviewed-by: Leon Romanovsky Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 051bbc0e7c74..318d0111455d 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2752,7 +2752,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) } if (valid_lft != 0 && valid_lft < in6_dev->cnf.accept_ra_min_lft) - return; + goto put; /* * Two things going on here: From 9db11ce119062f10f7f06ac9bebe104cda60bb63 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 13 May 2020 14:11:26 -0700 Subject: [PATCH 220/306] UPSTREAM: seccomp: Report number of loaded filters in /proc/$pid/status A common question asked when debugging seccomp filters is "how many filters are attached to your process?" Provide a way to easily answer this question through /proc/$pid/status with a "Seccomp_filters" line. Signed-off-by: Kees Cook (cherry picked from commit c818c03b661cd769e035e41673d5543ba2ebda64) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: Ib189ea77511a6088d5d328706c77c88709d8d63e --- fs/proc/array.c | 2 ++ include/linux/seccomp.h | 2 ++ init/init_task.c | 3 +++ kernel/seccomp.c | 3 +++ 4 files changed, 10 insertions(+) diff --git a/fs/proc/array.c b/fs/proc/array.c index 46dcb6f0eccf..6d9e56d19b9e 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -342,6 +342,8 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) seq_put_decimal_ull(m, "NoNewPrivs:\t", task_no_new_privs(p)); #ifdef CONFIG_SECCOMP seq_put_decimal_ull(m, "\nSeccomp:\t", p->seccomp.mode); + seq_put_decimal_ull(m, "\nSeccomp_filters:\t", + atomic_read(&p->seccomp.filter_count)); #endif seq_puts(m, "\nSpeculation_Store_Bypass:\t"); switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) { diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 84868d37b35d..262ff997870d 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -12,6 +12,7 @@ #ifdef CONFIG_SECCOMP #include +#include #include struct seccomp_filter; @@ -28,6 +29,7 @@ struct seccomp_filter; */ struct seccomp { int mode; + atomic_t filter_count; struct seccomp_filter *filter; }; diff --git a/init/init_task.c b/init/init_task.c index afaea5d7cb8a..b6fa82920e5d 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -193,6 +193,9 @@ struct task_struct init_task #ifdef CONFIG_SECURITY .security = NULL, #endif +#ifdef CONFIG_SECCOMP + .seccomp = { .filter_count = ATOMIC_INIT(0) }, +#endif }; EXPORT_SYMBOL(init_task); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index f1bff3f17583..5b9ddc9b8a26 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -410,6 +410,8 @@ static inline void seccomp_sync_threads(unsigned long flags) put_seccomp_filter(thread); smp_store_release(&thread->seccomp.filter, caller->seccomp.filter); + atomic_set(&thread->seccomp.filter_count, + atomic_read(&thread->seccomp.filter_count)); /* * Don't let an unprivileged task work around @@ -551,6 +553,7 @@ static long seccomp_attach_filter(unsigned int flags, */ filter->prev = current->seccomp.filter; current->seccomp.filter = filter; + atomic_inc(¤t->seccomp.filter_count); /* Now that the new filter is in place, synchronize to all threads. */ if (flags & SECCOMP_FILTER_FLAG_TSYNC) From 3c6d93041e7ebd83f73f82269b620947c429daf7 Mon Sep 17 00:00:00 2001 From: Sargun Dhillon Date: Mon, 1 Jun 2020 04:25:32 -0700 Subject: [PATCH 221/306] UPSTREAM: seccomp: Add find_notification helper This adds a helper which can iterate through a seccomp_filter to find a notification matching an ID. It removes several replicated chunks of code. Signed-off-by: Sargun Dhillon Acked-by: Christian Brauner Reviewed-by: Tycho Andersen Cc: Matt Denton Cc: Kees Cook , Cc: Jann Horn , Cc: Robert Sesek , Cc: Chris Palmer Cc: Christian Brauner Cc: Tycho Andersen Link: https://lore.kernel.org/r/20200601112532.150158-1-sargun@sargun.me Signed-off-by: Kees Cook (cherry picked from commit 9f87dcf14b82b05ff0e26970439b372ae135de0c) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I328edd8717fc06a415f7d4cf4fe561d86b2d4682 --- kernel/seccomp.c | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 5b9ddc9b8a26..8d6ae2e75d0a 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -44,6 +44,7 @@ #include #include #include +#include /* * When SECCOMP_IOCTL_NOTIF_ID_VALID was first introduced, it had the @@ -1030,6 +1031,23 @@ static int seccomp_notify_release(struct inode *inode, struct file *file) return 0; } +/* must be called with notif_lock held */ +static inline struct seccomp_knotif * +find_notification(struct seccomp_filter *filter, u64 id) +{ + struct seccomp_knotif *cur; + + lockdep_assert_held(&filter->notify_lock); + + list_for_each_entry(cur, &filter->notif->notifications, list) { + if (cur->id == id) + return cur; + } + + return NULL; +} + + static long seccomp_notify_recv(struct seccomp_filter *filter, void __user *buf) { @@ -1087,15 +1105,8 @@ out: * may have died when we released the lock, so we need to make * sure it's still around. */ - knotif = NULL; mutex_lock(&filter->notify_lock); - list_for_each_entry(cur, &filter->notif->notifications, list) { - if (cur->id == unotif.id) { - knotif = cur; - break; - } - } - + knotif = find_notification(filter, unotif.id); if (knotif) { knotif->state = SECCOMP_NOTIFY_INIT; up(&filter->notif->request); @@ -1110,7 +1121,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter, void __user *buf) { struct seccomp_notif_resp resp = {}; - struct seccomp_knotif *knotif = NULL, *cur; + struct seccomp_knotif *knotif; long ret; if (copy_from_user(&resp, buf, sizeof(resp))) @@ -1123,13 +1134,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter, if (ret < 0) return ret; - list_for_each_entry(cur, &filter->notif->notifications, list) { - if (cur->id == resp.id) { - knotif = cur; - break; - } - } - + knotif = find_notification(filter, resp.id); if (!knotif) { ret = -ENOENT; goto out; @@ -1154,7 +1159,7 @@ out: static long seccomp_notify_id_valid(struct seccomp_filter *filter, void __user *buf) { - struct seccomp_knotif *knotif = NULL; + struct seccomp_knotif *knotif; u64 id; long ret; @@ -1165,16 +1170,12 @@ static long seccomp_notify_id_valid(struct seccomp_filter *filter, if (ret < 0) return ret; - ret = -ENOENT; - list_for_each_entry(knotif, &filter->notif->notifications, list) { - if (knotif->id == id) { - if (knotif->state == SECCOMP_NOTIFY_SENT) - ret = 0; - goto out; - } - } + knotif = find_notification(filter, id); + if (knotif && knotif->state == SECCOMP_NOTIFY_SENT) + ret = 0; + else + ret = -ENOENT; -out: mutex_unlock(&filter->notify_lock); return ret; } From 07bd1e5332ee65cff533a351fab829faf14f65b7 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 31 May 2020 13:50:28 +0200 Subject: [PATCH 222/306] UPSTREAM: seccomp: rename "usage" to "refs" and document Naming the lifetime counter of a seccomp filter "usage" suggests a little too strongly that its about tasks that are using this filter while it also tracks other references such as the user notifier or ptrace. This also updates the documentation to note this fact. We'll be introducing an actual usage counter in a follow-up patch. Cc: Tycho Andersen Cc: Kees Cook Cc: Matt Denton Cc: Sargun Dhillon Cc: Jann Horn Cc: Chris Palmer Cc: Aleksa Sarai Cc: Robert Sesek Cc: Jeffrey Vander Stoep Cc: Linux Containers Signed-off-by: Christian Brauner Link: https://lore.kernel.org/r/20200531115031.391515-1-christian.brauner@ubuntu.com Signed-off-by: Kees Cook (cherry picked from commit b707ddee11d1dc4518ab7f1aa5e7af9ceaa23317) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: If4c78f85b9873aea2dffa1c8afb250f534d0fedc --- kernel/seccomp.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 8d6ae2e75d0a..338718730790 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -117,10 +117,11 @@ struct notification { /** * struct seccomp_filter - container for seccomp BPF programs * - * @usage: reference count to manage the object lifetime. - * get/put helpers should be used when accessing an instance - * outside of a lifetime-guarded section. In general, this - * is only needed for handling filters shared across tasks. + * @refs: Reference count to manage the object lifetime. + * A filter's reference count is incremented for each directly + * attached task, once for the dependent filter, and if + * requested for the user notifier. When @refs reaches zero, + * the filter can be freed. * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged * @prev: points to a previously installed, or inherited, filter * @prog: the BPF program to evaluate @@ -135,10 +136,10 @@ struct notification { * how namespaces work. * * seccomp_filter objects should never be modified after being attached - * to a task_struct (other than @usage). + * to a task_struct (other than @refs). */ struct seccomp_filter { - refcount_t usage; + refcount_t refs; bool log; struct seccomp_filter *prev; struct bpf_prog *prog; @@ -475,7 +476,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) return ERR_PTR(ret); } - refcount_set(&sfilter->usage, 1); + refcount_set(&sfilter->refs, 1); return sfilter; } @@ -565,7 +566,7 @@ static long seccomp_attach_filter(unsigned int flags, static void __get_seccomp_filter(struct seccomp_filter *filter) { - refcount_inc(&filter->usage); + refcount_inc(&filter->refs); } /* get_seccomp_filter - increments the reference count of the filter on @tsk */ @@ -588,7 +589,7 @@ static inline void seccomp_filter_free(struct seccomp_filter *filter) static void __put_seccomp_filter(struct seccomp_filter *orig) { /* Clean up single-reference branches iteratively. */ - while (orig && refcount_dec_and_test(&orig->usage)) { + while (orig && refcount_dec_and_test(&orig->refs)) { struct seccomp_filter *freeme = orig; orig = orig->prev; seccomp_filter_free(freeme); From 31e7b9c9d82549f7c400fa33001fb163e016f312 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 31 May 2020 13:50:29 +0200 Subject: [PATCH 223/306] BACKPORT: seccomp: release filter after task is fully dead The seccomp filter used to be released in free_task() which is called asynchronously via call_rcu() and assorted mechanisms. Since we need to inform tasks waiting on the seccomp notifier when a filter goes empty we will notify them as soon as a task has been marked fully dead in release_task(). To not split seccomp cleanup into two parts, move filter release out of free_task() and into release_task() after we've unhashed struct task from struct pid, exited signals, and unlinked it from the threadgroups' thread list. We'll put the empty filter notification infrastructure into it in a follow up patch. This also renames put_seccomp_filter() to seccomp_filter_release() which is a more descriptive name of what we're doing here especially once we've added the empty filter notification mechanism in there. We're also NULL-ing the task's filter tree entrypoint which seems cleaner than leaving a dangling pointer in there. Note that this shouldn't need any memory barriers since we're calling this when the task is in release_task() which means it's EXIT_DEAD. So it can't modify its seccomp filters anymore. You can also see this from the point where we're calling seccomp_filter_release(). It's after __exit_signal() and at this point, tsk->sighand will already have been NULLed which is required for thread-sync and filter installation alike. Cc: Tycho Andersen Cc: Kees Cook Cc: Matt Denton Cc: Sargun Dhillon Cc: Jann Horn Cc: Chris Palmer Cc: Aleksa Sarai Cc: Robert Sesek Cc: Jeffrey Vander Stoep Cc: Linux Containers Signed-off-by: Christian Brauner Link: https://lore.kernel.org/r/20200531115031.391515-2-christian.brauner@ubuntu.com Signed-off-by: Kees Cook (cherry picked from commit 3a15fb6ed92cb32b0a83f406aa4a96f28c9adbc3) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Resolved minor merge conflict in kernel/exit.c where 5.4 does not have commits 7bc3e6e55acf0 and 6ade99ec6175a. Change-Id: I4a0113f3f64a86937ba5c9ac6e2537926e2827be --- include/linux/seccomp.h | 4 +-- kernel/exit.c | 1 + kernel/fork.c | 1 - kernel/seccomp.c | 62 ++++++++++++++++++++++++----------------- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 262ff997870d..a6f90d9cea47 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -83,10 +83,10 @@ static inline int seccomp_mode(struct seccomp *s) #endif /* CONFIG_SECCOMP */ #ifdef CONFIG_SECCOMP_FILTER -extern void put_seccomp_filter(struct task_struct *tsk); +extern void seccomp_filter_release(struct task_struct *tsk); extern void get_seccomp_filter(struct task_struct *tsk); #else /* CONFIG_SECCOMP_FILTER */ -static inline void put_seccomp_filter(struct task_struct *tsk) +static inline void seccomp_filter_release(struct task_struct *tsk) { return; } diff --git a/kernel/exit.c b/kernel/exit.c index f8c860063100..d5d584cd79ce 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -274,6 +274,7 @@ repeat: } write_unlock_irq(&tasklist_lock); + seccomp_filter_release(p); release_thread(p); put_task_struct_rcu_user(p); diff --git a/kernel/fork.c b/kernel/fork.c index 68b18c603925..bb45f6817d52 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -474,7 +474,6 @@ void free_task(struct task_struct *tsk) #endif rt_mutex_debug_task_free(tsk); ftrace_graph_exit_task(tsk); - put_seccomp_filter(tsk); arch_release_task_struct(tsk); if (tsk->flags & PF_KTHREAD) free_kthread_struct(tsk); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 338718730790..0d3a191b1918 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -380,6 +380,42 @@ static inline pid_t seccomp_can_sync_threads(void) return 0; } +static inline void seccomp_filter_free(struct seccomp_filter *filter) +{ + if (filter) { + bpf_prog_destroy(filter->prog); + kfree(filter); + } +} + +static void __put_seccomp_filter(struct seccomp_filter *orig) +{ + /* Clean up single-reference branches iteratively. */ + while (orig && refcount_dec_and_test(&orig->refs)) { + struct seccomp_filter *freeme = orig; + orig = orig->prev; + seccomp_filter_free(freeme); + } +} + +/** + * seccomp_filter_release - Detach the task from its filter tree + * and drop its reference count during + * exit. + * + * This function should only be called when the task is exiting as + * it detaches it from its filter tree. As such, READ_ONCE() and + * barriers are not needed here, as would normally be needed. + */ +void seccomp_filter_release(struct task_struct *tsk) +{ + struct seccomp_filter *orig = tsk->seccomp.filter; + + /* Detach task from its filter tree. */ + tsk->seccomp.filter = NULL; + __put_seccomp_filter(orig); +} + /** * seccomp_sync_threads: sets all threads to use current's filter * @@ -409,7 +445,7 @@ static inline void seccomp_sync_threads(unsigned long flags) * current's path will hold a reference. (This also * allows a put before the assignment.) */ - put_seccomp_filter(thread); + __put_seccomp_filter(thread->seccomp.filter); smp_store_release(&thread->seccomp.filter, caller->seccomp.filter); atomic_set(&thread->seccomp.filter_count, @@ -578,30 +614,6 @@ void get_seccomp_filter(struct task_struct *tsk) __get_seccomp_filter(orig); } -static inline void seccomp_filter_free(struct seccomp_filter *filter) -{ - if (filter) { - bpf_prog_destroy(filter->prog); - kfree(filter); - } -} - -static void __put_seccomp_filter(struct seccomp_filter *orig) -{ - /* Clean up single-reference branches iteratively. */ - while (orig && refcount_dec_and_test(&orig->refs)) { - struct seccomp_filter *freeme = orig; - orig = orig->prev; - seccomp_filter_free(freeme); - } -} - -/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ -void put_seccomp_filter(struct task_struct *tsk) -{ - __put_seccomp_filter(tsk->seccomp.filter); -} - static void seccomp_init_siginfo(kernel_siginfo_t *info, int syscall, int reason) { clear_siginfo(info); From 902f009956344ce1578e58623c78bfee7d044a64 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Mon, 1 Jun 2020 11:50:07 -0700 Subject: [PATCH 224/306] UPSTREAM: seccomp: Lift wait_queue into struct seccomp_filter Lift the wait_queue from struct notification into struct seccomp_filter. This is cleaner overall and lets us avoid having to take the notifier mutex in the future for EPOLLHUP notifications since we need to neither read nor modify the notifier specific aspects of the seccomp filter. In the exit path I'd very much like to avoid having to take the notifier mutex for each filter in the task's filter hierarchy. Cc: Tycho Andersen Cc: Kees Cook Cc: Matt Denton Cc: Sargun Dhillon Cc: Jann Horn Cc: Chris Palmer Cc: Aleksa Sarai Cc: Robert Sesek Cc: Jeffrey Vander Stoep Cc: Linux Containers Signed-off-by: Christian Brauner Signed-off-by: Kees Cook (cherry picked from commit 76194c4e830d570d9e369d637bb907591d2b3111) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: Id87b359f1155d26068cd62d5295dc39849d46495 --- kernel/seccomp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 0d3a191b1918..a616810c29e8 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -105,13 +105,11 @@ struct seccomp_knotif { * filter->notify_lock. * @next_id: The id of the next request. * @notifications: A list of struct seccomp_knotif elements. - * @wqh: A wait queue for poll. */ struct notification { struct semaphore request; u64 next_id; struct list_head notifications; - wait_queue_head_t wqh; }; /** @@ -127,6 +125,7 @@ struct notification { * @prog: the BPF program to evaluate * @notif: the struct that holds all notification related information * @notify_lock: A lock for all notification-related accesses. + * @wqh: A wait queue for poll if a notifier is in use. * * seccomp_filter objects are organized in a tree linked via the @prev * pointer. For any task, it appears to be a singly-linked list starting @@ -145,6 +144,7 @@ struct seccomp_filter { struct bpf_prog *prog; struct notification *notif; struct mutex notify_lock; + wait_queue_head_t wqh; }; /* Limit any path through the tree to 256KB worth of instructions. */ @@ -513,6 +513,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) } refcount_set(&sfilter->refs, 1); + init_waitqueue_head(&sfilter->wqh); return sfilter; } @@ -781,7 +782,7 @@ static void seccomp_do_user_notification(int this_syscall, list_add(&n.list, &match->notif->notifications); up(&match->notif->request); - wake_up_poll(&match->notif->wqh, EPOLLIN | EPOLLRDNORM); + wake_up_poll(&match->wqh, EPOLLIN | EPOLLRDNORM); mutex_unlock(&match->notify_lock); /* @@ -1104,7 +1105,7 @@ static long seccomp_notify_recv(struct seccomp_filter *filter, unotif.data = *(knotif->data); knotif->state = SECCOMP_NOTIFY_SENT; - wake_up_poll(&filter->notif->wqh, EPOLLOUT | EPOLLWRNORM); + wake_up_poll(&filter->wqh, EPOLLOUT | EPOLLWRNORM); ret = 0; out: mutex_unlock(&filter->notify_lock); @@ -1219,7 +1220,7 @@ static __poll_t seccomp_notify_poll(struct file *file, __poll_t ret = 0; struct seccomp_knotif *cur; - poll_wait(file, &filter->notif->wqh, poll_tab); + poll_wait(file, &filter->wqh, poll_tab); if (mutex_lock_interruptible(&filter->notify_lock) < 0) return EPOLLERR; @@ -1257,7 +1258,6 @@ static struct file *init_listener(struct seccomp_filter *filter) sema_init(&filter->notif->request, 0); filter->notif->next_id = get_random_u64(); INIT_LIST_HEAD(&filter->notif->notifications); - init_waitqueue_head(&filter->notif->wqh); ret = anon_inode_getfile("seccomp notify", &seccomp_notify_ops, filter, O_RDWR); From 246a019c84a148d096d61a915f6c3a5081b43aba Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 31 May 2020 13:50:30 +0200 Subject: [PATCH 225/306] UPSTREAM: seccomp: notify about unused filter We've been making heavy use of the seccomp notifier to intercept and handle certain syscalls for containers. This patch allows a syscall supervisor listening on a given notifier to be notified when a seccomp filter has become unused. A container is often managed by a singleton supervisor process the so-called "monitor". This monitor process has an event loop which has various event handlers registered. If the user specified a seccomp profile that included a notifier for various syscalls then we also register a seccomp notify even handler. For any container using a separate pid namespace the lifecycle of the seccomp notifier is bound to the init process of the pid namespace, i.e. when the init process exits the filter must be unused. If a new process attaches to a container we force it to assume a seccomp profile. This can either be the same seccomp profile as the container was started with or a modified one. If the attaching process makes use of the seccomp notifier we will register a new seccomp notifier handler in the monitor's event loop. However, when the attaching process exits we can't simply delete the handler since other child processes could've been created (daemons spawned etc.) that have inherited the seccomp filter and so we need to keep the seccomp notifier fd alive in the event loop. But this is problematic since we don't get a notification when the seccomp filter has become unused and so we currently never remove the seccomp notifier fd from the event loop and just keep accumulating fds in the event loop. We've had this issue for a while but it has recently become more pressing as more and larger users make use of this. To fix this, we introduce a new "users" reference counter that tracks any tasks and dependent filters making use of a filter. When a notifier is registered waiting tasks will be notified that the filter is now empty by receiving a (E)POLLHUP event. The concept in this patch introduces is the same as for signal_struct, i.e. reference counting for life-cycle management is decoupled from reference counting taks using the object. There's probably some trickery possible but the second counter is just the correct way of doing this IMHO and has precedence. Cc: Tycho Andersen Cc: Kees Cook Cc: Matt Denton Cc: Sargun Dhillon Cc: Jann Horn Cc: Chris Palmer Cc: Aleksa Sarai Cc: Robert Sesek Cc: Jeffrey Vander Stoep Cc: Linux Containers Signed-off-by: Christian Brauner Link: https://lore.kernel.org/r/20200531115031.391515-3-christian.brauner@ubuntu.com Signed-off-by: Kees Cook (cherry picked from commit 99cdb8b9a57393b5978e7a6310a2cba511dd179b) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I1501f5134bf738fa641c8b35ed65a4bed01e6fef --- kernel/seccomp.c | 44 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index a616810c29e8..3e9d8a3eb87e 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -120,6 +120,14 @@ struct notification { * attached task, once for the dependent filter, and if * requested for the user notifier. When @refs reaches zero, * the filter can be freed. + * @users: A filter's @users count is incremented for each directly + * attached task (filter installation, fork(), thread_sync), + * and once for the dependent filter (tracked in filter->prev). + * When it reaches zero it indicates that no direct or indirect + * users of that filter exist. No new tasks can get associated with + * this filter after reaching 0. The @users count is always smaller + * or equal to @refs. Hence, reaching 0 for @users does not mean + * the filter can be freed. * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged * @prev: points to a previously installed, or inherited, filter * @prog: the BPF program to evaluate @@ -139,6 +147,7 @@ struct notification { */ struct seccomp_filter { refcount_t refs; + refcount_t users; bool log; struct seccomp_filter *prev; struct bpf_prog *prog; @@ -388,6 +397,15 @@ static inline void seccomp_filter_free(struct seccomp_filter *filter) } } +static void __seccomp_filter_orphan(struct seccomp_filter *orig) +{ + while (orig && refcount_dec_and_test(&orig->users)) { + if (waitqueue_active(&orig->wqh)) + wake_up_poll(&orig->wqh, EPOLLHUP); + orig = orig->prev; + } +} + static void __put_seccomp_filter(struct seccomp_filter *orig) { /* Clean up single-reference branches iteratively. */ @@ -398,10 +416,18 @@ static void __put_seccomp_filter(struct seccomp_filter *orig) } } +static void __seccomp_filter_release(struct seccomp_filter *orig) +{ + /* Notify about any unused filters in the task's former filter tree. */ + __seccomp_filter_orphan(orig); + /* Finally drop all references to the task's former tree. */ + __put_seccomp_filter(orig); +} + /** - * seccomp_filter_release - Detach the task from its filter tree - * and drop its reference count during - * exit. + * seccomp_filter_release - Detach the task from its filter tree, + * drop its reference count, and notify + * about unused filters * * This function should only be called when the task is exiting as * it detaches it from its filter tree. As such, READ_ONCE() and @@ -413,7 +439,7 @@ void seccomp_filter_release(struct task_struct *tsk) /* Detach task from its filter tree. */ tsk->seccomp.filter = NULL; - __put_seccomp_filter(orig); + __seccomp_filter_release(orig); } /** @@ -440,12 +466,15 @@ static inline void seccomp_sync_threads(unsigned long flags) /* Get a task reference for the new leaf node. */ get_seccomp_filter(caller); + /* * Drop the task reference to the shared ancestor since * current's path will hold a reference. (This also * allows a put before the assignment.) */ - __put_seccomp_filter(thread->seccomp.filter); + __seccomp_filter_release(thread->seccomp.filter); + + /* Make our new filter tree visible. */ smp_store_release(&thread->seccomp.filter, caller->seccomp.filter); atomic_set(&thread->seccomp.filter_count, @@ -513,6 +542,7 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) } refcount_set(&sfilter->refs, 1); + refcount_set(&sfilter->users, 1); init_waitqueue_head(&sfilter->wqh); return sfilter; @@ -613,6 +643,7 @@ void get_seccomp_filter(struct task_struct *tsk) if (!orig) return; __get_seccomp_filter(orig); + refcount_inc(&orig->users); } static void seccomp_init_siginfo(kernel_siginfo_t *info, int syscall, int reason) @@ -1236,6 +1267,9 @@ static __poll_t seccomp_notify_poll(struct file *file, mutex_unlock(&filter->notify_lock); + if (refcount_read(&filter->users) == 0) + ret |= EPOLLHUP; + return ret; } From d3720689a90373910179bbe56cf388aa1006fb0b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 15 Jun 2020 22:02:56 -0700 Subject: [PATCH 226/306] UPSTREAM: seccomp: Use pr_fmt Avoid open-coding "seccomp: " prefixes for pr_*() calls. Signed-off-by: Kees Cook (cherry picked from commit e68f9d49dda1744d548426c8b4335a8d693a36d0) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I2fa08d91c11b59dbb962cc767aa4cd25a42f761d --- kernel/seccomp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 3e9d8a3eb87e..01990e33dbe7 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -13,6 +13,7 @@ * Mode 2 allows user-defined system call filters in the form * of Berkeley Packet Filters/Linux Socket Filters. */ +#define pr_fmt(fmt) "seccomp: " fmt #include #include @@ -1897,7 +1898,7 @@ static int __init seccomp_sysctl_init(void) hdr = register_sysctl_paths(seccomp_sysctl_path, seccomp_sysctl_table); if (!hdr) - pr_warn("seccomp: sysctl registration failed\n"); + pr_warn("sysctl registration failed\n"); else kmemleak_not_leak(hdr); From 2e686a7319baaaa7a26776e80f92b7b95f2e18b8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 19 Jun 2020 12:20:15 -0700 Subject: [PATCH 227/306] UPSTREAM: seccomp: Use -1 marker for end of mode 1 syscall list The terminator for the mode 1 syscalls list was a 0, but that could be a valid syscall number (e.g. x86_64 __NR_read). By luck, __NR_read was listed first and the loop construct would not test it, so there was no bug. However, this is fragile. Replace the terminator with -1 instead, and make the variable name for mode 1 syscall lists more descriptive. Cc: Andy Lutomirski Cc: Will Drewry Signed-off-by: Kees Cook (cherry picked from commit fe4bfff86ec54773df3db79e8112e3b0f820c799) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I3d91bf57236f2c20d71f22fa9c0ef7b0b8869bcf --- arch/mips/include/asm/seccomp.h | 4 ++-- include/asm-generic/seccomp.h | 2 +- kernel/seccomp.c | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/mips/include/asm/seccomp.h b/arch/mips/include/asm/seccomp.h index e383d7e27b93..aa809589a181 100644 --- a/arch/mips/include/asm/seccomp.h +++ b/arch/mips/include/asm/seccomp.h @@ -9,12 +9,12 @@ static inline const int *get_compat_mode1_syscalls(void) static const int syscalls_O32[] = { __NR_O32_Linux + 3, __NR_O32_Linux + 4, __NR_O32_Linux + 1, __NR_O32_Linux + 193, - 0, /* null terminated */ + -1, /* negative terminated */ }; static const int syscalls_N32[] = { __NR_N32_Linux + 0, __NR_N32_Linux + 1, __NR_N32_Linux + 58, __NR_N32_Linux + 211, - 0, /* null terminated */ + -1, /* negative terminated */ }; if (IS_ENABLED(CONFIG_MIPS32_O32) && test_thread_flag(TIF_32BIT_REGS)) diff --git a/include/asm-generic/seccomp.h b/include/asm-generic/seccomp.h index 1321ac7821d7..6b6f42bc58f9 100644 --- a/include/asm-generic/seccomp.h +++ b/include/asm-generic/seccomp.h @@ -33,7 +33,7 @@ static inline const int *get_compat_mode1_syscalls(void) static const int mode1_syscalls_32[] = { __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32, - 0, /* null terminated */ + -1, /* negative terminated */ }; return mode1_syscalls_32; } diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 01990e33dbe7..96512747ee49 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -741,20 +741,20 @@ static inline void seccomp_log(unsigned long syscall, long signr, u32 action, */ static const int mode1_syscalls[] = { __NR_seccomp_read, __NR_seccomp_write, __NR_seccomp_exit, __NR_seccomp_sigreturn, - 0, /* null terminated */ + -1, /* negative terminated */ }; static void __secure_computing_strict(int this_syscall) { - const int *syscall_whitelist = mode1_syscalls; + const int *allowed_syscalls = mode1_syscalls; #ifdef CONFIG_COMPAT if (in_compat_syscall()) - syscall_whitelist = get_compat_mode1_syscalls(); + allowed_syscalls = get_compat_mode1_syscalls(); #endif do { - if (*syscall_whitelist == this_syscall) + if (*allowed_syscalls == this_syscall) return; - } while (*++syscall_whitelist); + } while (*++allowed_syscalls != -1); #ifdef SECCOMP_DEBUG dump_stack(); From bcce8defc3c033a719f6c2264225ed3ba1be1925 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Fri, 20 Sep 2019 10:30:05 +0200 Subject: [PATCH 228/306] UPSTREAM: seccomp: add SECCOMP_USER_NOTIF_FLAG_CONTINUE This allows the seccomp notifier to continue a syscall. A positive discussion about this feature was triggered by a post to the ksummit-discuss mailing list (cf. [3]) and took place during KSummit (cf. [1]) and again at the containers/checkpoint-restore micro-conference at Linux Plumbers. Recently we landed seccomp support for SECCOMP_RET_USER_NOTIF (cf. [4]) which enables a process (watchee) to retrieve an fd for its seccomp filter. This fd can then be handed to another (usually more privileged) process (watcher). The watcher will then be able to receive seccomp messages about the syscalls having been performed by the watchee. This feature is heavily used in some userspace workloads. For example, it is currently used to intercept mknod() syscalls in user namespaces aka in containers. The mknod() syscall can be easily filtered based on dev_t. This allows us to only intercept a very specific subset of mknod() syscalls. Furthermore, mknod() is not possible in user namespaces toto coelo and so intercepting and denying syscalls that are not in the whitelist on accident is not a big deal. The watchee won't notice a difference. In contrast to mknod(), a lot of other syscall we intercept (e.g. setxattr()) cannot be easily filtered like mknod() because they have pointer arguments. Additionally, some of them might actually succeed in user namespaces (e.g. setxattr() for all "user.*" xattrs). Since we currently cannot tell seccomp to continue from a user notifier we are stuck with performing all of the syscalls in lieu of the container. This is a huge security liability since it is extremely difficult to correctly assume all of the necessary privileges of the calling task such that the syscall can be successfully emulated without escaping other additional security restrictions (think missing CAP_MKNOD for mknod(), or MS_NODEV on a filesystem etc.). This can be solved by telling seccomp to resume the syscall. One thing that came up in the discussion was the problem that another thread could change the memory after userspace has decided to let the syscall continue which is a well known TOCTOU with seccomp which is present in other ways already. The discussion showed that this feature is already very useful for any syscall without pointer arguments. For any accidentally intercepted non-pointer syscall it is safe to continue. For syscalls with pointer arguments there is a race but for any cautious userspace and the main usec cases the race doesn't matter. The notifier is intended to be used in a scenario where a more privileged watcher supervises the syscalls of lesser privileged watchee to allow it to get around kernel-enforced limitations by performing the syscall for it whenever deemed save by the watcher. Hence, if a user tricks the watcher into allowing a syscall they will either get a deny based on kernel-enforced restrictions later or they will have changed the arguments in such a way that they manage to perform a syscall with arguments that they would've been allowed to do anyway. In general, it is good to point out again, that the notifier fd was not intended to allow userspace to implement a security policy but rather to work around kernel security mechanisms in cases where the watcher knows that a given action is safe to perform. /* References */ [1]: https://linuxplumbersconf.org/event/4/contributions/560 [2]: https://linuxplumbersconf.org/event/4/contributions/477 [3]: https://lore.kernel.org/r/20190719093538.dhyopljyr5ns33qx@brauner.io [4]: commit 6a21cc50f0c7 ("seccomp: add a return code to trap to userspace") Co-developed-by: Kees Cook Signed-off-by: Christian Brauner Reviewed-by: Tycho Andersen Cc: Andy Lutomirski Cc: Will Drewry CC: Tyler Hicks Link: https://lore.kernel.org/r/20190920083007.11475-2-christian.brauner@ubuntu.com Signed-off-by: Kees Cook (cherry picked from commit fb3c5386b382d4097476ce9647260fc89b34afdb) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: Ifd5de971a0da6a507cb8ca1178381ca715693e07 --- include/uapi/linux/seccomp.h | 29 +++++++++++++++++++++++++++++ kernel/seccomp.c | 28 ++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index b5f901af79f0..df1f4711d0b7 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h @@ -76,6 +76,35 @@ struct seccomp_notif { struct seccomp_data data; }; +/* + * Valid flags for struct seccomp_notif_resp + * + * Note, the SECCOMP_USER_NOTIF_FLAG_CONTINUE flag must be used with caution! + * If set by the process supervising the syscalls of another process the + * syscall will continue. This is problematic because of an inherent TOCTOU. + * An attacker can exploit the time while the supervised process is waiting on + * a response from the supervising process to rewrite syscall arguments which + * are passed as pointers of the intercepted syscall. + * It should be absolutely clear that this means that the seccomp notifier + * _cannot_ be used to implement a security policy! It should only ever be used + * in scenarios where a more privileged process supervises the syscalls of a + * lesser privileged process to get around kernel-enforced security + * restrictions when the privileged process deems this safe. In other words, + * in order to continue a syscall the supervising process should be sure that + * another security mechanism or the kernel itself will sufficiently block + * syscalls if arguments are rewritten to something unsafe. + * + * Similar precautions should be applied when stacking SECCOMP_RET_USER_NOTIF + * or SECCOMP_RET_TRACE. For SECCOMP_RET_USER_NOTIF filters acting on the + * same syscall, the most recently added filter takes precedence. This means + * that the new SECCOMP_RET_USER_NOTIF filter can override any + * SECCOMP_IOCTL_NOTIF_SEND from earlier filters, essentially allowing all + * such filtered syscalls to be executed by sending the response + * SECCOMP_USER_NOTIF_FLAG_CONTINUE. Note that SECCOMP_RET_TRACE can equally + * be overriden by SECCOMP_USER_NOTIF_FLAG_CONTINUE. + */ +#define SECCOMP_USER_NOTIF_FLAG_CONTINUE BIT(0) + struct seccomp_notif_resp { __u64 id; __s64 val; diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 96512747ee49..6c4d4d4ffdf2 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -88,6 +88,7 @@ struct seccomp_knotif { /* The return values, only valid when in SECCOMP_NOTIFY_REPLIED */ int error; long val; + u32 flags; /* Signals when this has entered SECCOMP_NOTIFY_REPLIED */ struct completion ready; @@ -793,11 +794,12 @@ static u64 seccomp_next_notify_id(struct seccomp_filter *filter) return filter->notif->next_id++; } -static void seccomp_do_user_notification(int this_syscall, - struct seccomp_filter *match, - const struct seccomp_data *sd) +static int seccomp_do_user_notification(int this_syscall, + struct seccomp_filter *match, + const struct seccomp_data *sd) { int err; + u32 flags = 0; long ret = 0; struct seccomp_knotif n = {}; @@ -825,6 +827,7 @@ static void seccomp_do_user_notification(int this_syscall, if (err == 0) { ret = n.val; err = n.error; + flags = n.flags; } /* @@ -841,8 +844,14 @@ static void seccomp_do_user_notification(int this_syscall, list_del(&n.list); out: mutex_unlock(&match->notify_lock); + + /* Userspace requests to continue the syscall. */ + if (flags & SECCOMP_USER_NOTIF_FLAG_CONTINUE) + return 0; + syscall_set_return_value(current, task_pt_regs(current), err, ret); + return -1; } static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, @@ -928,8 +937,10 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, return 0; case SECCOMP_RET_USER_NOTIF: - seccomp_do_user_notification(this_syscall, match, sd); - goto skip; + if (seccomp_do_user_notification(this_syscall, match, sd)) + goto skip; + + return 0; case SECCOMP_RET_LOG: seccomp_log(this_syscall, 0, action, true); @@ -1173,7 +1184,11 @@ static long seccomp_notify_send(struct seccomp_filter *filter, if (copy_from_user(&resp, buf, sizeof(resp))) return -EFAULT; - if (resp.flags) + if (resp.flags & ~SECCOMP_USER_NOTIF_FLAG_CONTINUE) + return -EINVAL; + + if ((resp.flags & SECCOMP_USER_NOTIF_FLAG_CONTINUE) && + (resp.error || resp.val)) return -EINVAL; ret = mutex_lock_interruptible(&filter->notify_lock); @@ -1196,6 +1211,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter, knotif->state = SECCOMP_NOTIFY_REPLIED; knotif->error = resp.error; knotif->val = resp.val; + knotif->flags = resp.flags; complete(&knotif->ready); out: mutex_unlock(&filter->notify_lock); From 0506d711a322d1dcbd9a52b00b0bb7330bd25f15 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Tue, 1 Sep 2020 19:40:16 -0600 Subject: [PATCH 229/306] UPSTREAM: seccomp: don't leak memory when filter install races In seccomp_set_mode_filter() with TSYNC | NEW_LISTENER, we first initialize the listener fd, then check to see if we can actually use it later in seccomp_may_assign_mode(), which can fail if anyone else in our thread group has installed a filter and caused some divergence. If we can't, we partially clean up the newly allocated file: we put the fd, put the file, but don't actually clean up the *memory* that was allocated at filter->notif. Let's clean that up too. To accomplish this, let's hoist the actual "detach a notifier from a filter" code to its own helper out of seccomp_notify_release(), so that in case anyone adds stuff to init_listener(), they only have to add the cleanup code in one spot. This does a bit of extra locking and such on the failure path when the filter is not attached, but it's a slow failure path anyway. Fixes: 51891498f2da ("seccomp: allow TSYNC and USER_NOTIF together") Reported-by: syzbot+3ad9614a12f80994c32e@syzkaller.appspotmail.com Signed-off-by: Tycho Andersen Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20200902014017.934315-1-tycho@tycho.pizza Signed-off-by: Kees Cook (cherry picked from commit a566a9012acd7c9a4be7e30dc7acb7a811ec2260) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I8e6ce0f1646ff997623458f25b733ba79c0a47a2 --- kernel/seccomp.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 6c4d4d4ffdf2..a0d5889cc5ff 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -1056,13 +1056,12 @@ out: } #ifdef CONFIG_SECCOMP_FILTER -static int seccomp_notify_release(struct inode *inode, struct file *file) +static void seccomp_notify_detach(struct seccomp_filter *filter) { - struct seccomp_filter *filter = file->private_data; struct seccomp_knotif *knotif; if (!filter) - return 0; + return; mutex_lock(&filter->notify_lock); @@ -1084,6 +1083,13 @@ static int seccomp_notify_release(struct inode *inode, struct file *file) kfree(filter->notif); filter->notif = NULL; mutex_unlock(&filter->notify_lock); +} + +static int seccomp_notify_release(struct inode *inode, struct file *file) +{ + struct seccomp_filter *filter = file->private_data; + + seccomp_notify_detach(filter); __put_seccomp_filter(filter); return 0; } @@ -1441,6 +1447,7 @@ out_put_fd: listener_f->private_data = NULL; fput(listener_f); put_unused_fd(listener); + seccomp_notify_detach(prepared); } else { fd_install(listener, listener_f); ret = listener; From 43c11dbfa82bf89ab87e23de0a0c03bf6c8aa636 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Wed, 2 Sep 2020 08:09:53 -0600 Subject: [PATCH 230/306] UPSTREAM: seccomp: don't leave dangling ->notif if file allocation fails Christian and Kees both pointed out that this is a bit sloppy to open-code both places, and Christian points out that we leave a dangling pointer to ->notif if file allocation fails. Since we check ->notif for null in order to determine if it's ok to install a filter, this means people won't be able to install a filter if the file allocation fails for some reason, even if they subsequently should be able to. To fix this, let's hoist this free+null into its own little helper and use it. Reported-by: Kees Cook Reported-by: Christian Brauner Signed-off-by: Tycho Andersen Acked-by: Christian Brauner Link: https://lore.kernel.org/r/20200902140953.1201956-1-tycho@tycho.pizza Signed-off-by: Kees Cook (cherry picked from commit e839317900e9f13c83d8711d684de88c625b307a) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: Ie20e79fa15b6891895b7ada1f6ef7d08fdf81e01 --- kernel/seccomp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index a0d5889cc5ff..10706321c705 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -1056,6 +1056,12 @@ out: } #ifdef CONFIG_SECCOMP_FILTER +static void seccomp_notify_free(struct seccomp_filter *filter) +{ + kfree(filter->notif); + filter->notif = NULL; +} + static void seccomp_notify_detach(struct seccomp_filter *filter) { struct seccomp_knotif *knotif; @@ -1080,8 +1086,7 @@ static void seccomp_notify_detach(struct seccomp_filter *filter) complete(&knotif->ready); } - kfree(filter->notif); - filter->notif = NULL; + seccomp_notify_free(filter); mutex_unlock(&filter->notify_lock); } @@ -1326,7 +1331,7 @@ static struct file *init_listener(struct seccomp_filter *filter) out_notif: if (IS_ERR(ret)) - kfree(filter->notif); + seccomp_notify_free(filter); out: return ret; } From c6279c1cb7a76ef3162a0ec5d9b81eed15a088c6 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Fri, 28 Aug 2020 21:56:13 -0400 Subject: [PATCH 231/306] UPSTREAM: seccomp: kill process instead of thread for unknown actions Asynchronous termination of a thread outside of the userspace thread library's knowledge is an unsafe operation that leaves the process in an inconsistent, corrupt, and possibly unrecoverable state. In order to make new actions that may be added in the future safe on kernels not aware of them, change the default action from SECCOMP_RET_KILL_THREAD to SECCOMP_RET_KILL_PROCESS. Signed-off-by: Rich Felker Link: https://lore.kernel.org/r/20200829015609.GA32566@brightrain.aerifal.cx [kees: Fixed up coredump selection logic to match] Signed-off-by: Kees Cook (cherry picked from commit 4d671d922d51907bc41f1f7f2dc737c928ae78fd) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I23140e1efbb4346de8566421c35d2810de26b209 --- kernel/seccomp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 10706321c705..3ffd9db5c936 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -960,7 +960,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, current->seccomp.mode = SECCOMP_MODE_DEAD; seccomp_log(this_syscall, SIGSYS, action, true); /* Dump core only if this is the last remaining thread. */ - if (action == SECCOMP_RET_KILL_PROCESS || + if (action != SECCOMP_RET_KILL_THREAD || get_nr_threads(current) == 1) { kernel_siginfo_t info; @@ -970,10 +970,10 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, seccomp_init_siginfo(&info, this_syscall, data); do_coredump(&info); } - if (action == SECCOMP_RET_KILL_PROCESS) - do_group_exit(SIGSYS); - else + if (action == SECCOMP_RET_KILL_THREAD) do_exit(SIGSYS); + else + do_group_exit(SIGSYS); } unreachable(); From e24e8cf80241e04b2a6048fb0dceeaca7a7287d5 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Mon, 24 Aug 2020 15:59:21 +0300 Subject: [PATCH 232/306] UPSTREAM: seccomp: Use current_pt_regs() instead of task_pt_regs(current) As described in commit a3460a59747c ("new helper: current_pt_regs()"): - arch versions are "optimized versions". - some architectures have task_pt_regs() working only for traced tasks blocked on signal delivery. current_pt_regs() needs to work for *all* processes. In preparation for adding a coccinelle rule for using current_*(), instead of raw accesses to current members, modify seccomp_do_user_notification(), __seccomp_filter(), __secure_computing() to use current_pt_regs(). Signed-off-by: Denis Efremov Link: https://lore.kernel.org/r/20200824125921.488311-1-efremov@linux.com [kees: Reworded commit log, add comment to populate_seccomp_data()] Signed-off-by: Kees Cook (cherry picked from commit 2d9ca267a944c2b6ed5b4d750b1cf0407b6262b4) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: Ib66bcc8cfa077c7a493fb9d14501279f32f48550 --- kernel/seccomp.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 3ffd9db5c936..dcdd649d6824 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -167,6 +167,10 @@ struct seccomp_filter { */ static void populate_seccomp_data(struct seccomp_data *sd) { + /* + * Instead of using current_pt_reg(), we're already doing the work + * to safely fetch "current", so just use "task" everywhere below. + */ struct task_struct *task = current; struct pt_regs *regs = task_pt_regs(task); unsigned long args[6]; @@ -849,7 +853,7 @@ out: if (flags & SECCOMP_USER_NOTIF_FLAG_CONTINUE) return 0; - syscall_set_return_value(current, task_pt_regs(current), + syscall_set_return_value(current, current_pt_regs(), err, ret); return -1; } @@ -882,13 +886,13 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, /* Set low-order bits as an errno, capped at MAX_ERRNO. */ if (data > MAX_ERRNO) data = MAX_ERRNO; - syscall_set_return_value(current, task_pt_regs(current), + syscall_set_return_value(current, current_pt_regs(), -data, 0); goto skip; case SECCOMP_RET_TRAP: /* Show the handler the original registers. */ - syscall_rollback(current, task_pt_regs(current)); + syscall_rollback(current, current_pt_regs()); /* Let the filter pass back 16 bits of data. */ seccomp_send_sigsys(this_syscall, data); goto skip; @@ -901,7 +905,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, /* ENOSYS these calls if there is no tracer attached. */ if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { syscall_set_return_value(current, - task_pt_regs(current), + current_pt_regs(), -ENOSYS, 0); goto skip; } @@ -921,7 +925,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, if (fatal_signal_pending(current)) goto skip; /* Check if the tracer forced the syscall to be skipped. */ - this_syscall = syscall_get_nr(current, task_pt_regs(current)); + this_syscall = syscall_get_nr(current, current_pt_regs()); if (this_syscall < 0) goto skip; @@ -965,7 +969,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd, kernel_siginfo_t info; /* Show the original registers in the dump. */ - syscall_rollback(current, task_pt_regs(current)); + syscall_rollback(current, current_pt_regs()); /* Trigger a manual coredump since do_exit skips it. */ seccomp_init_siginfo(&info, this_syscall, data); do_coredump(&info); @@ -1002,7 +1006,7 @@ int __secure_computing(const struct seccomp_data *sd) return 0; this_syscall = sd ? sd->nr : - syscall_get_nr(current, task_pt_regs(current)); + syscall_get_nr(current, current_pt_regs()); switch (mode) { case SECCOMP_MODE_STRICT: From 993d91ceea3f58700a4192ef5d9c680c8de74553 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Sun, 11 Oct 2020 10:47:42 -0500 Subject: [PATCH 233/306] UPSTREAM: seccomp/cache: Lookup syscall allowlist bitmap for fast path The overhead of running Seccomp filters has been part of some past discussions [1][2][3]. Oftentimes, the filters have a large number of instructions that check syscall numbers one by one and jump based on that. Some users chain BPF filters which further enlarge the overhead. A recent work [6] comprehensively measures the Seccomp overhead and shows that the overhead is non-negligible and has a non-trivial impact on application performance. We observed some common filters, such as docker's [4] or systemd's [5], will make most decisions based only on the syscall numbers, and as past discussions considered, a bitmap where each bit represents a syscall makes most sense for these filters. The fast (common) path for seccomp should be that the filter permits the syscall to pass through, and failing seccomp is expected to be an exceptional case; it is not expected for userspace to call a denylisted syscall over and over. When it can be concluded that an allow must occur for the given architecture and syscall pair (this determination is introduced in the next commit), seccomp will immediately allow the syscall, bypassing further BPF execution. Each architecture number has its own bitmap. The architecture number in seccomp_data is checked against the defined architecture number constant before proceeding to test the bit against the bitmap with the syscall number as the index of the bit in the bitmap, and if the bit is set, seccomp returns allow. The bitmaps are all clear in this patch and will be initialized in the next commit. When only one architecture exists, the check against architecture number is skipped, suggested by Kees Cook [7]. [1] https://lore.kernel.org/linux-security-module/c22a6c3cefc2412cad00ae14c1371711@huawei.com/T/ [2] https://lore.kernel.org/lkml/202005181120.971232B7B@keescook/T/ [3] https://github.com/seccomp/libseccomp/issues/116 [4] https://github.com/moby/moby/blob/ae0ef82b90356ac613f329a8ef5ee42ca923417d/profiles/seccomp/default.json [5] https://github.com/systemd/systemd/blob/6743a1caf4037f03dc51a1277855018e4ab61957/src/shared/seccomp-util.c#L270 [6] Draco: Architectural and Operating System Support for System Call Security https://tianyin.github.io/pub/draco.pdf, MICRO-53, Oct. 2020 [7] https://lore.kernel.org/bpf/202010091614.8BB0EB64@keescook/ Co-developed-by: Dimitrios Skarlatos Signed-off-by: Dimitrios Skarlatos Signed-off-by: YiFei Zhu Reviewed-by: Jann Horn Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/10f91a367ec4fcdea7fc3f086de3f5f13a4a7436.1602431034.git.yifeifz2@illinois.edu (cherry picked from commit f9d480b6ffbeb336bf7f6ce44825c00f61b3abae)A Signed-off-by: Jeff Vander Stoep Change-Id: I50b6682e17dc6e91b5e92017361200d722282825 Bug: 176068146 --- kernel/seccomp.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index dcdd649d6824..327c2bbb6113 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -114,6 +114,34 @@ struct notification { struct list_head notifications; }; +#ifdef SECCOMP_ARCH_NATIVE +/** + * struct action_cache - per-filter cache of seccomp actions per + * arch/syscall pair + * + * @allow_native: A bitmap where each bit represents whether the + * filter will always allow the syscall, for the + * native architecture. + * @allow_compat: A bitmap where each bit represents whether the + * filter will always allow the syscall, for the + * compat architecture. + */ +struct action_cache { + DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR); +#ifdef SECCOMP_ARCH_COMPAT + DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR); +#endif +}; +#else +struct action_cache { }; + +static inline bool seccomp_cache_check_allow(const struct seccomp_filter *sfilter, + const struct seccomp_data *sd) +{ + return false; +} +#endif /* SECCOMP_ARCH_NATIVE */ + /** * struct seccomp_filter - container for seccomp BPF programs * @@ -269,6 +297,52 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) return 0; } +#ifdef SECCOMP_ARCH_NATIVE +static inline bool seccomp_cache_check_allow_bitmap(const void *bitmap, + size_t bitmap_size, + int syscall_nr) +{ + if (unlikely(syscall_nr < 0 || syscall_nr >= bitmap_size)) + return false; + syscall_nr = array_index_nospec(syscall_nr, bitmap_size); + + return test_bit(syscall_nr, bitmap); +} + +/** + * seccomp_cache_check_allow - lookup seccomp cache + * @sfilter: The seccomp filter + * @sd: The seccomp data to lookup the cache with + * + * Returns true if the seccomp_data is cached and allowed. + */ +static inline bool seccomp_cache_check_allow(const struct seccomp_filter *sfilter, + const struct seccomp_data *sd) +{ + int syscall_nr = sd->nr; + const struct action_cache *cache = &sfilter->cache; + +#ifndef SECCOMP_ARCH_COMPAT + /* A native-only architecture doesn't need to check sd->arch. */ + return seccomp_cache_check_allow_bitmap(cache->allow_native, + SECCOMP_ARCH_NATIVE_NR, + syscall_nr); +#else + if (likely(sd->arch == SECCOMP_ARCH_NATIVE)) + return seccomp_cache_check_allow_bitmap(cache->allow_native, + SECCOMP_ARCH_NATIVE_NR, + syscall_nr); + if (likely(sd->arch == SECCOMP_ARCH_COMPAT)) + return seccomp_cache_check_allow_bitmap(cache->allow_compat, + SECCOMP_ARCH_COMPAT_NR, + syscall_nr); +#endif /* SECCOMP_ARCH_COMPAT */ + + WARN_ON_ONCE(true); + return false; +} +#endif /* SECCOMP_ARCH_NATIVE */ + /** * seccomp_run_filters - evaluates all seccomp filters against @sd * @sd: optional seccomp data to be passed to filters @@ -291,6 +365,9 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd, if (WARN_ON(f == NULL)) return SECCOMP_RET_KILL_PROCESS; + if (seccomp_cache_check_allow(f, sd)) + return SECCOMP_RET_ALLOW; + /* * All filters in the list are evaluated and the lowest BPF return * value always takes priority (ignoring the DATA). From c639e51eeff4b4b0c9a5b72618d8109f3d4b3718 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Sun, 11 Oct 2020 10:47:43 -0500 Subject: [PATCH 234/306] UPSTREAM: seccomp/cache: Add "emulator" to check if filter is constant allow SECCOMP_CACHE will only operate on syscalls that do not access any syscall arguments or instruction pointer. To facilitate this we need a static analyser to know whether a filter will return allow regardless of syscall arguments for a given architecture number / syscall number pair. This is implemented here with a pseudo-emulator, and stored in a per-filter bitmap. In order to build this bitmap at filter attach time, each filter is emulated for every syscall (under each possible architecture), and checked for any accesses of struct seccomp_data that are not the "arch" nor "nr" (syscall) members. If only "arch" and "nr" are examined, and the program returns allow, then we can be sure that the filter must return allow independent from syscall arguments. Nearly all seccomp filters are built from these cBPF instructions: BPF_LD | BPF_W | BPF_ABS BPF_JMP | BPF_JEQ | BPF_K BPF_JMP | BPF_JGE | BPF_K BPF_JMP | BPF_JGT | BPF_K BPF_JMP | BPF_JSET | BPF_K BPF_JMP | BPF_JA BPF_RET | BPF_K BPF_ALU | BPF_AND | BPF_K Each of these instructions are emulated. Any weirdness or loading from a syscall argument will cause the emulator to bail. The emulation is also halted if it reaches a return. In that case, if it returns an SECCOMP_RET_ALLOW, the syscall is marked as good. Emulator structure and comments are from Kees [1] and Jann [2]. Emulation is done at attach time. If a filter depends on more filters, and if the dependee does not guarantee to allow the syscall, then we skip the emulation of this syscall. [1] https://lore.kernel.org/lkml/20200923232923.3142503-5-keescook@chromium.org/ [2] https://lore.kernel.org/lkml/CAG48ez1p=dR_2ikKq=xVxkoGg0fYpTBpkhJSv1w-6BG=76PAvw@mail.gmail.com/ Suggested-by: Jann Horn Signed-off-by: YiFei Zhu Reviewed-by: Jann Horn Co-developed-by: Kees Cook Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/71c7be2db5ee08905f41c3be5c1ad6e2601ce88f.1602431034.git.yifeifz2@illinois.edu (cherry picked from commit 8e01b51a31a1e08e2c3e8fcc0ef6790441be2f61) Signed-off-by: Jeff Vander Stoep Change-Id: I5047f7f0d6502e5de6c047743f1053fda3025a6e Bug: 176068146 --- kernel/seccomp.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 327c2bbb6113..0263bc055d49 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -140,6 +140,10 @@ static inline bool seccomp_cache_check_allow(const struct seccomp_filter *sfilte { return false; } + +static inline void seccomp_cache_prepare(struct seccomp_filter *sfilter) +{ +} #endif /* SECCOMP_ARCH_NATIVE */ /** @@ -158,6 +162,7 @@ static inline bool seccomp_cache_check_allow(const struct seccomp_filter *sfilte * this filter after reaching 0. The @users count is always smaller * or equal to @refs. Hence, reaching 0 for @users does not mean * the filter can be freed. + * @cache: cache of arch/syscall mappings to actions * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged * @prev: points to a previously installed, or inherited, filter * @prog: the BPF program to evaluate @@ -179,6 +184,7 @@ struct seccomp_filter { refcount_t refs; refcount_t users; bool log; + struct action_cache cache; struct seccomp_filter *prev; struct bpf_prog *prog; struct notification *notif; @@ -594,7 +600,12 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) { struct seccomp_filter *sfilter; int ret; - const bool save_orig = IS_ENABLED(CONFIG_CHECKPOINT_RESTORE); + const bool save_orig = +#if defined(CONFIG_CHECKPOINT_RESTORE) || defined(SECCOMP_ARCH_NATIVE) + true; +#else + false; +#endif if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) return ERR_PTR(-EINVAL); @@ -659,6 +670,148 @@ out: return filter; } +#ifdef SECCOMP_ARCH_NATIVE +/** + * seccomp_is_const_allow - check if filter is constant allow with given data + * @fprog: The BPF programs + * @sd: The seccomp data to check against, only syscall number and arch + * number are considered constant. + */ +static bool seccomp_is_const_allow(struct sock_fprog_kern *fprog, + struct seccomp_data *sd) +{ + unsigned int reg_value = 0; + unsigned int pc; + bool op_res; + + if (WARN_ON_ONCE(!fprog)) + return false; + + for (pc = 0; pc < fprog->len; pc++) { + struct sock_filter *insn = &fprog->filter[pc]; + u16 code = insn->code; + u32 k = insn->k; + + switch (code) { + case BPF_LD | BPF_W | BPF_ABS: + switch (k) { + case offsetof(struct seccomp_data, nr): + reg_value = sd->nr; + break; + case offsetof(struct seccomp_data, arch): + reg_value = sd->arch; + break; + default: + /* can't optimize (non-constant value load) */ + return false; + } + break; + case BPF_RET | BPF_K: + /* reached return with constant values only, check allow */ + return k == SECCOMP_RET_ALLOW; + case BPF_JMP | BPF_JA: + pc += insn->k; + break; + case BPF_JMP | BPF_JEQ | BPF_K: + case BPF_JMP | BPF_JGE | BPF_K: + case BPF_JMP | BPF_JGT | BPF_K: + case BPF_JMP | BPF_JSET | BPF_K: + switch (BPF_OP(code)) { + case BPF_JEQ: + op_res = reg_value == k; + break; + case BPF_JGE: + op_res = reg_value >= k; + break; + case BPF_JGT: + op_res = reg_value > k; + break; + case BPF_JSET: + op_res = !!(reg_value & k); + break; + default: + /* can't optimize (unknown jump) */ + return false; + } + + pc += op_res ? insn->jt : insn->jf; + break; + case BPF_ALU | BPF_AND | BPF_K: + reg_value &= k; + break; + default: + /* can't optimize (unknown insn) */ + return false; + } + } + + /* ran off the end of the filter?! */ + WARN_ON(1); + return false; +} + +static void seccomp_cache_prepare_bitmap(struct seccomp_filter *sfilter, + void *bitmap, const void *bitmap_prev, + size_t bitmap_size, int arch) +{ + struct sock_fprog_kern *fprog = sfilter->prog->orig_prog; + struct seccomp_data sd; + int nr; + + if (bitmap_prev) { + /* The new filter must be as restrictive as the last. */ + bitmap_copy(bitmap, bitmap_prev, bitmap_size); + } else { + /* Before any filters, all syscalls are always allowed. */ + bitmap_fill(bitmap, bitmap_size); + } + + for (nr = 0; nr < bitmap_size; nr++) { + /* No bitmap change: not a cacheable action. */ + if (!test_bit(nr, bitmap)) + continue; + + sd.nr = nr; + sd.arch = arch; + + /* No bitmap change: continue to always allow. */ + if (seccomp_is_const_allow(fprog, &sd)) + continue; + + /* + * Not a cacheable action: always run filters. + * atomic clear_bit() not needed, filter not visible yet. + */ + __clear_bit(nr, bitmap); + } +} + +/** + * seccomp_cache_prepare - emulate the filter to find cachable syscalls + * @sfilter: The seccomp filter + * + * Returns 0 if successful or -errno if error occurred. + */ +static void seccomp_cache_prepare(struct seccomp_filter *sfilter) +{ + struct action_cache *cache = &sfilter->cache; + const struct action_cache *cache_prev = + sfilter->prev ? &sfilter->prev->cache : NULL; + + seccomp_cache_prepare_bitmap(sfilter, cache->allow_native, + cache_prev ? cache_prev->allow_native : NULL, + SECCOMP_ARCH_NATIVE_NR, + SECCOMP_ARCH_NATIVE); + +#ifdef SECCOMP_ARCH_COMPAT + seccomp_cache_prepare_bitmap(sfilter, cache->allow_compat, + cache_prev ? cache_prev->allow_compat : NULL, + SECCOMP_ARCH_COMPAT_NR, + SECCOMP_ARCH_COMPAT); +#endif /* SECCOMP_ARCH_COMPAT */ +} +#endif /* SECCOMP_ARCH_NATIVE */ + /** * seccomp_attach_filter: validate and attach filter * @flags: flags to change filter behavior @@ -704,6 +857,7 @@ static long seccomp_attach_filter(unsigned int flags, * task reference. */ filter->prev = current->seccomp.filter; + seccomp_cache_prepare(filter); current->seccomp.filter = filter; atomic_inc(¤t->seccomp.filter_count); From 6faba4c16875fcff3c4a89dd24bfcc66d36deb67 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 11 Oct 2020 10:47:44 -0500 Subject: [PATCH 235/306] UPSTREAM: x86: Enable seccomp architecture tracking Provide seccomp internals with the details to calculate which syscall table the running kernel is expecting to deal with. This allows for efficient architecture pinning and paves the way for constant-action bitmaps. Co-developed-by: YiFei Zhu Signed-off-by: YiFei Zhu Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/da58c3733d95c4f2115dd94225dfbe2573ba4d87.1602431034.git.yifeifz2@illinois.edu (cherry picked from commit 25db91209a910a0ccf8b093743088d0f4bf5659f) Signed-off-by: Jeff Vander Stoep Change-Id: I48a434063e401b27834e4ba37b88a852da51300b Bug: 176068146 --- arch/x86/include/asm/seccomp.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/arch/x86/include/asm/seccomp.h b/arch/x86/include/asm/seccomp.h index 2bd1338de236..fef16e398161 100644 --- a/arch/x86/include/asm/seccomp.h +++ b/arch/x86/include/asm/seccomp.h @@ -16,6 +16,26 @@ #define __NR_seccomp_sigreturn_32 __NR_ia32_sigreturn #endif +#ifdef CONFIG_X86_64 +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_X86_64 +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "x86_64" +# ifdef CONFIG_COMPAT +# define SECCOMP_ARCH_COMPAT AUDIT_ARCH_I386 +# define SECCOMP_ARCH_COMPAT_NR IA32_NR_syscalls +# define SECCOMP_ARCH_COMPAT_NAME "ia32" +# endif +/* + * x32 will have __X32_SYSCALL_BIT set in syscall number. We don't support + * caching them and they are treated as out of range syscalls, which will + * always pass through the BPF filter. + */ +#else /* !CONFIG_X86_64 */ +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_I386 +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "ia32" +#endif + #include #endif /* _ASM_X86_SECCOMP_H */ From f8da9865cebe6a3bf0df595b411905c0a38a1ecc Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 1 Jun 2020 12:34:44 -0700 Subject: [PATCH 236/306] UPSTREAM: selftests/seccomp: Expand benchmark to per-filter measurements It's useful to see how much (at a minimum) each filter adds to the syscall overhead. Add additional calculations. Signed-off-by: Kees Cook (cherry picked from commit d3a37ea9f6e548388b83fe895c7a037bc2ec3f7f) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: Ibc36b007b580cc129b2880b12b151a659590abb9 --- .../selftests/seccomp/seccomp_benchmark.c | 36 +++++++++++++++---- tools/testing/selftests/seccomp/seccomp_bpf.c | 2 -- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/seccomp/seccomp_benchmark.c b/tools/testing/selftests/seccomp/seccomp_benchmark.c index 5838c8697ec3..eca13fe1fba9 100644 --- a/tools/testing/selftests/seccomp/seccomp_benchmark.c +++ b/tools/testing/selftests/seccomp/seccomp_benchmark.c @@ -68,32 +68,54 @@ int main(int argc, char *argv[]) }; long ret; unsigned long long samples; - unsigned long long native, filtered; + unsigned long long native, filter1, filter2; if (argc > 1) samples = strtoull(argv[1], NULL, 0); else samples = calibrate(); + printf("Current BPF sysctl settings:\n"); + system("sysctl net.core.bpf_jit_enable"); + system("sysctl net.core.bpf_jit_harden"); printf("Benchmarking %llu samples...\n", samples); + /* Native call */ native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; printf("getpid native: %llu ns\n", native); ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); assert(ret == 0); + /* One filter */ ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); assert(ret == 0); - filtered = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; - printf("getpid RET_ALLOW: %llu ns\n", filtered); + filter1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; + printf("getpid RET_ALLOW 1 filter: %llu ns\n", filter1); - printf("Estimated seccomp overhead per syscall: %llu ns\n", - filtered - native); + if (filter1 == native) + printf("No overhead measured!? Try running again with more samples.\n"); - if (filtered == native) - printf("Trying running again with more samples.\n"); + /* Two filters */ + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); + assert(ret == 0); + + filter2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; + printf("getpid RET_ALLOW 2 filters: %llu ns\n", filter2); + + /* Calculations */ + printf("Estimated total seccomp overhead for 1 filter: %llu ns\n", + filter1 - native); + + printf("Estimated total seccomp overhead for 2 filters: %llu ns\n", + filter2 - native); + + printf("Estimated seccomp per-filter overhead: %llu ns\n", + filter2 - filter1); + + printf("Estimated seccomp entry overhead: %llu ns\n", + filter1 - native - (filter2 - filter1)); return 0; } diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index a12eea3aff10..412e69e11620 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -3504,7 +3504,6 @@ TEST(seccomp_get_notif_sizes) /* * TODO: - * - add microbenchmarks * - expand NNP testing * - better arch-specific TRACE and TRAP handlers. * - endianness checking when appropriate @@ -3512,7 +3511,6 @@ TEST(seccomp_get_notif_sizes) * - arch value testing (x86 modes especially) * - verify that FILTER_FLAG_LOG filters generate log messages * - verify that RET_LOG generates log messages - * - ... */ TEST_HARNESS_MAIN From 43e7581e2ebe3ab20bfe1c9cedc3e60817479380 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sat, 6 Jun 2020 09:37:17 -0700 Subject: [PATCH 237/306] UPSTREAM: selftests/seccomp: Improve calibration loop The seccomp benchmark calibration loop did not need to take so long. Instead, use a simple 1 second timeout and multiply up to target. It does not need to be accurate. Signed-off-by: Kees Cook (cherry picked from commit 81a0c8bc82be7c15dbf3e54832334552e6b76e2b) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I5583b28bb635c01413548dbe05b2bed8d50def00 --- .../selftests/seccomp/seccomp_benchmark.c | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/seccomp/seccomp_benchmark.c b/tools/testing/selftests/seccomp/seccomp_benchmark.c index eca13fe1fba9..91f5a89cadac 100644 --- a/tools/testing/selftests/seccomp/seccomp_benchmark.c +++ b/tools/testing/selftests/seccomp/seccomp_benchmark.c @@ -18,9 +18,9 @@ unsigned long long timing(clockid_t clk_id, unsigned long long samples) { - pid_t pid, ret; - unsigned long long i; struct timespec start, finish; + unsigned long long i; + pid_t pid, ret; pid = getpid(); assert(clock_gettime(clk_id, &start) == 0); @@ -31,30 +31,43 @@ unsigned long long timing(clockid_t clk_id, unsigned long long samples) assert(clock_gettime(clk_id, &finish) == 0); i = finish.tv_sec - start.tv_sec; - i *= 1000000000; + i *= 1000000000ULL; i += finish.tv_nsec - start.tv_nsec; - printf("%lu.%09lu - %lu.%09lu = %llu\n", + printf("%lu.%09lu - %lu.%09lu = %llu (%.1fs)\n", finish.tv_sec, finish.tv_nsec, start.tv_sec, start.tv_nsec, - i); + i, (double)i / 1000000000.0); return i; } unsigned long long calibrate(void) { - unsigned long long i; + struct timespec start, finish; + unsigned long long i, samples, step = 9973; + pid_t pid, ret; + int seconds = 15; - printf("Calibrating reasonable sample size...\n"); + printf("Calibrating sample size for %d seconds worth of syscalls ...\n", seconds); - for (i = 5; ; i++) { - unsigned long long samples = 1 << i; + samples = 0; + pid = getpid(); + assert(clock_gettime(CLOCK_MONOTONIC, &start) == 0); + do { + for (i = 0; i < step; i++) { + ret = syscall(__NR_getpid); + assert(pid == ret); + } + assert(clock_gettime(CLOCK_MONOTONIC, &finish) == 0); - /* Find something that takes more than 5 seconds to run. */ - if (timing(CLOCK_REALTIME, samples) / 1000000000ULL > 5) - return samples; - } + samples += step; + i = finish.tv_sec - start.tv_sec; + i *= 1000000000ULL; + i += finish.tv_nsec - start.tv_nsec; + } while (i < 1000000000ULL); + + return samples * seconds; } int main(int argc, char *argv[]) @@ -70,15 +83,16 @@ int main(int argc, char *argv[]) unsigned long long samples; unsigned long long native, filter1, filter2; + printf("Current BPF sysctl settings:\n"); + system("sysctl net.core.bpf_jit_enable"); + system("sysctl net.core.bpf_jit_harden"); + if (argc > 1) samples = strtoull(argv[1], NULL, 0); else samples = calibrate(); - printf("Current BPF sysctl settings:\n"); - system("sysctl net.core.bpf_jit_enable"); - system("sysctl net.core.bpf_jit_harden"); - printf("Benchmarking %llu samples...\n", samples); + printf("Benchmarking %llu syscalls...\n", samples); /* Native call */ native = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; From df0d2c88242f62eaade9161c2524da90f9cc68cb Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Mon, 1 Jun 2020 12:50:12 -0700 Subject: [PATCH 238/306] UPSTREAM: selftests/seccomp: use 90s as timeout As seccomp_benchmark tries to calibrate how many samples will take more than 5 seconds to execute, it may end up picking up a number of samples that take 10 (but up to 12) seconds. As the calibration will take double that time, it takes around 20 seconds. Then, it executes the whole thing again, and then once more, with some added overhead. So, the thing might take more than 40 seconds, which is too close to the 45s timeout. That is very dependent on the system where it's executed, so may not be observed always, but it has been observed on x86 VMs. Using a 90s timeout seems safe enough. Signed-off-by: Thadeu Lima de Souza Cascardo Link: https://lore.kernel.org/r/20200601123202.1183526-1-cascardo@canonical.com Signed-off-by: Kees Cook (cherry picked from commit bc32c9c86581abf7baacf71342df3b0affe367db) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I52379d62bddc9163c6cbbb934483ceabb10cc909 --- tools/testing/selftests/seccomp/settings | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/testing/selftests/seccomp/settings diff --git a/tools/testing/selftests/seccomp/settings b/tools/testing/selftests/seccomp/settings new file mode 100644 index 000000000000..ba4d85f74cd6 --- /dev/null +++ b/tools/testing/selftests/seccomp/settings @@ -0,0 +1 @@ +timeout=90 From a8ea366f5692d2503af0960c7796937dd6e85b03 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 11 Oct 2020 10:47:45 -0500 Subject: [PATCH 239/306] UPSTREAM: selftests/seccomp: Compare bitmap vs filter overhead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of the seccomp benchmarking, include the expectations with regard to the timing behavior of the constant action bitmaps, and report inconsistencies better. Example output with constant action bitmaps on x86: $ sudo ./seccomp_benchmark 100000000 Current BPF sysctl settings: net.core.bpf_jit_enable = 1 net.core.bpf_jit_harden = 0 Benchmarking 200000000 syscalls... 129.359381409 - 0.008724424 = 129350656985 (129.4s) getpid native: 646 ns 264.385890006 - 129.360453229 = 135025436777 (135.0s) getpid RET_ALLOW 1 filter (bitmap): 675 ns 399.400511893 - 264.387045901 = 135013465992 (135.0s) getpid RET_ALLOW 2 filters (bitmap): 675 ns 545.872866260 - 399.401718327 = 146471147933 (146.5s) getpid RET_ALLOW 3 filters (full): 732 ns 696.337101319 - 545.874097681 = 150463003638 (150.5s) getpid RET_ALLOW 4 filters (full): 752 ns Estimated total seccomp overhead for 1 bitmapped filter: 29 ns Estimated total seccomp overhead for 2 bitmapped filters: 29 ns Estimated total seccomp overhead for 3 full filters: 86 ns Estimated total seccomp overhead for 4 full filters: 106 ns Estimated seccomp entry overhead: 29 ns Estimated seccomp per-filter overhead (last 2 diff): 20 ns Estimated seccomp per-filter overhead (filters / 4): 19 ns Expectations: native ≤ 1 bitmap (646 ≤ 675): ✔️ native ≤ 1 filter (646 ≤ 732): ✔️ per-filter (last 2 diff) ≈ per-filter (filters / 4) (20 ≈ 19): ✔️ 1 bitmapped ≈ 2 bitmapped (29 ≈ 29): ✔️ entry ≈ 1 bitmapped (29 ≈ 29): ✔️ entry ≈ 2 bitmapped (29 ≈ 29): ✔️ native + entry + (per filter * 4) ≈ 4 filters total (755 ≈ 752): ✔️ [YiFei: Changed commit message to show stats for this patch series] Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/1b61df3db85c5f7f1b9202722c45e7b39df73ef2.1602431034.git.yifeifz2@illinois.edu (cherry picked from commit 192cf32243ce39af65bd095625aec374b38c03df) Signed-off-by: Jeff Vander Stoep Change-Id: Idd30139b4fbb2c06f4b043756bbb09bbacf3b123 Bug: 176068146 --- .../selftests/seccomp/seccomp_benchmark.c | 147 +++++++++++++++--- tools/testing/selftests/seccomp/settings | 2 +- 2 files changed, 128 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/seccomp/seccomp_benchmark.c b/tools/testing/selftests/seccomp/seccomp_benchmark.c index 91f5a89cadac..fcc806585266 100644 --- a/tools/testing/selftests/seccomp/seccomp_benchmark.c +++ b/tools/testing/selftests/seccomp/seccomp_benchmark.c @@ -4,12 +4,16 @@ */ #define _GNU_SOURCE #include +#include +#include +#include #include #include #include #include #include #include +#include #include #include #include @@ -70,18 +74,74 @@ unsigned long long calibrate(void) return samples * seconds; } +bool approx(int i_one, int i_two) +{ + double one = i_one, one_bump = one * 0.01; + double two = i_two, two_bump = two * 0.01; + + one_bump = one + MAX(one_bump, 2.0); + two_bump = two + MAX(two_bump, 2.0); + + /* Equal to, or within 1% or 2 digits */ + if (one == two || + (one > two && one <= two_bump) || + (two > one && two <= one_bump)) + return true; + return false; +} + +bool le(int i_one, int i_two) +{ + if (i_one <= i_two) + return true; + return false; +} + +long compare(const char *name_one, const char *name_eval, const char *name_two, + unsigned long long one, bool (*eval)(int, int), unsigned long long two) +{ + bool good; + + printf("\t%s %s %s (%lld %s %lld): ", name_one, name_eval, name_two, + (long long)one, name_eval, (long long)two); + if (one > INT_MAX) { + printf("Miscalculation! Measurement went negative: %lld\n", (long long)one); + return 1; + } + if (two > INT_MAX) { + printf("Miscalculation! Measurement went negative: %lld\n", (long long)two); + return 1; + } + + good = eval(one, two); + printf("%s\n", good ? "✔️" : "❌"); + + return good ? 0 : 1; +} + int main(int argc, char *argv[]) { + struct sock_filter bitmap_filter[] = { + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), + BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), + }; + struct sock_fprog bitmap_prog = { + .len = (unsigned short)ARRAY_SIZE(bitmap_filter), + .filter = bitmap_filter, + }; struct sock_filter filter[] = { + BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, args[0])), BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), }; struct sock_fprog prog = { .len = (unsigned short)ARRAY_SIZE(filter), .filter = filter, }; - long ret; - unsigned long long samples; - unsigned long long native, filter1, filter2; + + long ret, bits; + unsigned long long samples, calc; + unsigned long long native, filter1, filter2, bitmap1, bitmap2; + unsigned long long entry, per_filter1, per_filter2; printf("Current BPF sysctl settings:\n"); system("sysctl net.core.bpf_jit_enable"); @@ -101,35 +161,82 @@ int main(int argc, char *argv[]) ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); assert(ret == 0); - /* One filter */ + /* One filter resulting in a bitmap */ + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog); + assert(ret == 0); + + bitmap1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; + printf("getpid RET_ALLOW 1 filter (bitmap): %llu ns\n", bitmap1); + + /* Second filter resulting in a bitmap */ + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog); + assert(ret == 0); + + bitmap2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; + printf("getpid RET_ALLOW 2 filters (bitmap): %llu ns\n", bitmap2); + + /* Third filter, can no longer be converted to bitmap */ ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); assert(ret == 0); filter1 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; - printf("getpid RET_ALLOW 1 filter: %llu ns\n", filter1); + printf("getpid RET_ALLOW 3 filters (full): %llu ns\n", filter1); - if (filter1 == native) - printf("No overhead measured!? Try running again with more samples.\n"); - - /* Two filters */ - ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); + /* Fourth filter, can not be converted to bitmap because of filter 3 */ + ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &bitmap_prog); assert(ret == 0); filter2 = timing(CLOCK_PROCESS_CPUTIME_ID, samples) / samples; - printf("getpid RET_ALLOW 2 filters: %llu ns\n", filter2); + printf("getpid RET_ALLOW 4 filters (full): %llu ns\n", filter2); - /* Calculations */ - printf("Estimated total seccomp overhead for 1 filter: %llu ns\n", - filter1 - native); + /* Estimations */ +#define ESTIMATE(fmt, var, what) do { \ + var = (what); \ + printf("Estimated " fmt ": %llu ns\n", var); \ + if (var > INT_MAX) \ + goto more_samples; \ + } while (0) - printf("Estimated total seccomp overhead for 2 filters: %llu ns\n", - filter2 - native); + ESTIMATE("total seccomp overhead for 1 bitmapped filter", calc, + bitmap1 - native); + ESTIMATE("total seccomp overhead for 2 bitmapped filters", calc, + bitmap2 - native); + ESTIMATE("total seccomp overhead for 3 full filters", calc, + filter1 - native); + ESTIMATE("total seccomp overhead for 4 full filters", calc, + filter2 - native); + ESTIMATE("seccomp entry overhead", entry, + bitmap1 - native - (bitmap2 - bitmap1)); + ESTIMATE("seccomp per-filter overhead (last 2 diff)", per_filter1, + filter2 - filter1); + ESTIMATE("seccomp per-filter overhead (filters / 4)", per_filter2, + (filter2 - native - entry) / 4); - printf("Estimated seccomp per-filter overhead: %llu ns\n", - filter2 - filter1); + printf("Expectations:\n"); + ret |= compare("native", "≤", "1 bitmap", native, le, bitmap1); + bits = compare("native", "≤", "1 filter", native, le, filter1); + if (bits) + goto more_samples; - printf("Estimated seccomp entry overhead: %llu ns\n", - filter1 - native - (filter2 - filter1)); + ret |= compare("per-filter (last 2 diff)", "≈", "per-filter (filters / 4)", + per_filter1, approx, per_filter2); + bits = compare("1 bitmapped", "≈", "2 bitmapped", + bitmap1 - native, approx, bitmap2 - native); + if (bits) { + printf("Skipping constant action bitmap expectations: they appear unsupported.\n"); + goto out; + } + + ret |= compare("entry", "≈", "1 bitmapped", entry, approx, bitmap1 - native); + ret |= compare("entry", "≈", "2 bitmapped", entry, approx, bitmap2 - native); + ret |= compare("native + entry + (per filter * 4)", "≈", "4 filters total", + entry + (per_filter1 * 4) + native, approx, filter2); + if (ret == 0) + goto out; + +more_samples: + printf("Saw unexpected benchmark result. Try running again with more samples?\n"); +out: return 0; } diff --git a/tools/testing/selftests/seccomp/settings b/tools/testing/selftests/seccomp/settings index ba4d85f74cd6..6091b45d226b 100644 --- a/tools/testing/selftests/seccomp/settings +++ b/tools/testing/selftests/seccomp/settings @@ -1 +1 @@ -timeout=90 +timeout=120 From 17d2800a6b2b29939f99379191cbfe0aae4686ee Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 27 Oct 2020 12:23:19 -0700 Subject: [PATCH 240/306] UPSTREAM: arm64: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for arm64. Signed-off-by: Kees Cook (cherry picked from commit ffde703470b03b1000017ed35c4f90a90caa22cf) Signed-off-by: Jeff Vander Stoep Change-Id: Ib21059de0928a61bd76202a67732432e88c5a5f0 Bug: 176068146 --- arch/arm64/include/asm/seccomp.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h index c36387170936..30256233788b 100644 --- a/arch/arm64/include/asm/seccomp.h +++ b/arch/arm64/include/asm/seccomp.h @@ -19,4 +19,13 @@ #include +#define SECCOMP_ARCH_NATIVE AUDIT_ARCH_AARCH64 +#define SECCOMP_ARCH_NATIVE_NR NR_syscalls +#define SECCOMP_ARCH_NATIVE_NAME "aarch64" +#ifdef CONFIG_COMPAT +# define SECCOMP_ARCH_COMPAT AUDIT_ARCH_ARM +# define SECCOMP_ARCH_COMPAT_NR __NR_compat_syscalls +# define SECCOMP_ARCH_COMPAT_NAME "arm" +#endif + #endif /* _ASM_SECCOMP_H */ From a6ecb44045638b7d5026ed4ebfa6239d8209b543 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 27 Oct 2020 12:26:58 -0700 Subject: [PATCH 241/306] UPSTREAM: arm: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for arm. Signed-off-by: Kees Cook (cherry picked from commit 424c9102fa7b2a5c15afe47fd14278c849f4eefb) Signed-off-by: Jeff Vander Stoep Change-Id: I90eaafdc43f618ce7dcf76e1cbb8ae1ff542ead9 Bug: 176068146 --- arch/arm/include/asm/Kbuild | 1 - arch/arm/include/asm/seccomp.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/seccomp.h diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 68ca86f85eb7..580ed13b70a7 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -15,7 +15,6 @@ generic-y += mmiowb.h generic-y += msi.h generic-y += parport.h generic-y += preempt.h -generic-y += seccomp.h generic-y += serial.h generic-y += trace_clock.h diff --git a/arch/arm/include/asm/seccomp.h b/arch/arm/include/asm/seccomp.h new file mode 100644 index 000000000000..e9ad0f37d2ba --- /dev/null +++ b/arch/arm/include/asm/seccomp.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include + +#define SECCOMP_ARCH_NATIVE AUDIT_ARCH_ARM +#define SECCOMP_ARCH_NATIVE_NR NR_syscalls +#define SECCOMP_ARCH_NATIVE_NAME "arm" + +#endif /* _ASM_SECCOMP_H */ From 48350fd86e8605d6981148fe513bd779db8fb9d4 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Wed, 11 Nov 2020 07:33:47 -0600 Subject: [PATCH 242/306] UPSTREAM: csky: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for csky. Signed-off-by: YiFei Zhu Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/f9219026d4803b22f3e57e3768b4e42e004ef236.1605101222.git.yifeifz2@illinois.edu (cherry picked from commit 6e9ae6f98809e0d123ff4d769ba2e6f652119138) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I1fea89150f06be98ea4ee4357ad441e60aa6589f --- arch/csky/include/asm/seccomp.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 arch/csky/include/asm/seccomp.h diff --git a/arch/csky/include/asm/seccomp.h b/arch/csky/include/asm/seccomp.h new file mode 100644 index 000000000000..d33e758126fb --- /dev/null +++ b/arch/csky/include/asm/seccomp.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include + +#define SECCOMP_ARCH_NATIVE AUDIT_ARCH_CSKY +#define SECCOMP_ARCH_NATIVE_NR NR_syscalls +#define SECCOMP_ARCH_NATIVE_NAME "csky" + +#endif /* _ASM_SECCOMP_H */ From f33c0d2fed861f18ebe909950535bf9e7b50a421 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Wed, 11 Nov 2020 07:33:48 -0600 Subject: [PATCH 243/306] UPSTREAM: parisc: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for parisc. Signed-off-by: YiFei Zhu Acked-by: Helge Deller Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/9bb86c546eda753adf5270425e7353202dbce87c.1605101222.git.yifeifz2@illinois.edu (cherry picked from commit 6aa7923c8737d1f8fd2a06154155d68dec646464) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I48ef86a4127b9cc87dff5235ded3733c098db7e1 --- arch/parisc/include/asm/Kbuild | 1 - arch/parisc/include/asm/seccomp.h | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 arch/parisc/include/asm/seccomp.h diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild index 9ceedf6393c4..ae63364de2cf 100644 --- a/arch/parisc/include/asm/Kbuild +++ b/arch/parisc/include/asm/Kbuild @@ -19,7 +19,6 @@ generic-y += mm-arch-hooks.h generic-y += mmiowb.h generic-y += percpu.h generic-y += preempt.h -generic-y += seccomp.h generic-y += trace_clock.h generic-y += user.h generic-y += vga.h diff --git a/arch/parisc/include/asm/seccomp.h b/arch/parisc/include/asm/seccomp.h new file mode 100644 index 000000000000..b058b2220322 --- /dev/null +++ b/arch/parisc/include/asm/seccomp.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include + +#ifdef CONFIG_64BIT +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PARISC64 +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "parisc64" +# ifdef CONFIG_COMPAT +# define SECCOMP_ARCH_COMPAT AUDIT_ARCH_PARISC +# define SECCOMP_ARCH_COMPAT_NR NR_syscalls +# define SECCOMP_ARCH_COMPAT_NAME "parisc" +# endif +#else /* !CONFIG_64BIT */ +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PARISC +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "parisc" +#endif + +#endif /* _ASM_SECCOMP_H */ From ced31049ee127e924d3d5d9304625f683a0f67d3 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Wed, 11 Nov 2020 07:33:49 -0600 Subject: [PATCH 244/306] UPSTREAM: powerpc: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for powerpc. __LITTLE_ENDIAN__ is used here instead of CONFIG_CPU_LITTLE_ENDIAN to keep it consistent with asm/syscall.h. Signed-off-by: YiFei Zhu Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/0b64925362671cdaa26d01bfe50b3ba5e164adfd.1605101222.git.yifeifz2@illinois.edu (cherry picked from commit e7bcb4622ddf4473da6c03fa8423919a568c57dc) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I917b30a0c8cc6697513cc7f12bc84691e3166745 --- arch/powerpc/include/asm/seccomp.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/powerpc/include/asm/seccomp.h b/arch/powerpc/include/asm/seccomp.h index 51209f6071c5..ac2033f134f0 100644 --- a/arch/powerpc/include/asm/seccomp.h +++ b/arch/powerpc/include/asm/seccomp.h @@ -8,4 +8,27 @@ #include +#ifdef __LITTLE_ENDIAN__ +#define __SECCOMP_ARCH_LE __AUDIT_ARCH_LE +#define __SECCOMP_ARCH_LE_NAME "le" +#else +#define __SECCOMP_ARCH_LE 0 +#define __SECCOMP_ARCH_LE_NAME +#endif + +#ifdef CONFIG_PPC64 +# define SECCOMP_ARCH_NATIVE (AUDIT_ARCH_PPC64 | __SECCOMP_ARCH_LE) +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "ppc64" __SECCOMP_ARCH_LE_NAME +# ifdef CONFIG_COMPAT +# define SECCOMP_ARCH_COMPAT (AUDIT_ARCH_PPC | __SECCOMP_ARCH_LE) +# define SECCOMP_ARCH_COMPAT_NR NR_syscalls +# define SECCOMP_ARCH_COMPAT_NAME "ppc" __SECCOMP_ARCH_LE_NAME +# endif +#else /* !CONFIG_PPC64 */ +# define SECCOMP_ARCH_NATIVE (AUDIT_ARCH_PPC | __SECCOMP_ARCH_LE) +# define SECCOMP_ARCH_NATIVE_NR NR_syscalls +# define SECCOMP_ARCH_NATIVE_NAME "ppc" __SECCOMP_ARCH_LE_NAME +#endif + #endif /* _ASM_POWERPC_SECCOMP_H */ From d02da3450d020b9ccd8145f3d40f3d3877f77755 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Wed, 11 Nov 2020 07:33:51 -0600 Subject: [PATCH 245/306] UPSTREAM: s390: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for s390. Signed-off-by: YiFei Zhu Acked-by: Heiko Carstens Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/a381b10aa2c5b1e583642f3cd46ced842d9d4ce5.1605101222.git.yifeifz2@illinois.edu (cherry picked from commit c09058eda2654c37fd7ac28c2004c3aae8b988e9) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I643cdd2a001f80bd5f6a64298e4a42412d66651e --- arch/s390/include/asm/seccomp.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/s390/include/asm/seccomp.h b/arch/s390/include/asm/seccomp.h index 795bbe0d7ca6..71d46f0ba97b 100644 --- a/arch/s390/include/asm/seccomp.h +++ b/arch/s390/include/asm/seccomp.h @@ -16,4 +16,13 @@ #include +#define SECCOMP_ARCH_NATIVE AUDIT_ARCH_S390X +#define SECCOMP_ARCH_NATIVE_NR NR_syscalls +#define SECCOMP_ARCH_NATIVE_NAME "s390x" +#ifdef CONFIG_COMPAT +# define SECCOMP_ARCH_COMPAT AUDIT_ARCH_S390 +# define SECCOMP_ARCH_COMPAT_NR NR_syscalls +# define SECCOMP_ARCH_COMPAT_NAME "s390" +#endif + #endif /* _ASM_S390_SECCOMP_H */ From c632efe06e94a3fc5f221a923774fedb57722866 Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Wed, 11 Nov 2020 07:33:52 -0600 Subject: [PATCH 246/306] UPSTREAM: sh: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for sh. Signed-off-by: YiFei Zhu Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/61ae084cd4783b9b50860d9dedb4a348cf1b7b6f.1605101222.git.yifeifz2@illinois.edu (cherry picked from commit 4c18bc054bffe415bec9e0edaa9ff1a84c1a6973) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I4cdb3b9fda0af5e5d1e4eede11661c828f41aad5 --- arch/sh/include/asm/seccomp.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/sh/include/asm/seccomp.h b/arch/sh/include/asm/seccomp.h index 54111e4d32b8..d4578395fd66 100644 --- a/arch/sh/include/asm/seccomp.h +++ b/arch/sh/include/asm/seccomp.h @@ -8,4 +8,14 @@ #define __NR_seccomp_exit __NR_exit #define __NR_seccomp_sigreturn __NR_rt_sigreturn +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define __SECCOMP_ARCH_LE __AUDIT_ARCH_LE +#else +#define __SECCOMP_ARCH_LE 0 +#endif + +#define SECCOMP_ARCH_NATIVE (AUDIT_ARCH_SH | __SECCOMP_ARCH_LE) +#define SECCOMP_ARCH_NATIVE_NR NR_syscalls +#define SECCOMP_ARCH_NATIVE_NAME "sh" + #endif /* __ASM_SECCOMP_H */ From b3dbf346004f3db0f5ef50cf28a4cc578031a0fc Mon Sep 17 00:00:00 2001 From: YiFei Zhu Date: Wed, 11 Nov 2020 07:33:53 -0600 Subject: [PATCH 247/306] UPSTREAM: xtensa: Enable seccomp architecture tracking To enable seccomp constant action bitmaps, we need to have a static mapping to the audit architecture and system call table size. Add these for xtensa. Signed-off-by: YiFei Zhu Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/79669648ba167d668ea6ffb4884250abcd5ed254.1605101222.git.yifeifz2@illinois.edu (cherry picked from commit 445247b02342a05b7d528bba6d85d2d418875b69) Signed-off-by: Jeff Vander Stoep Bug: 176068146 Change-Id: I7f8ecb0da495552c062e39e1b9bd5ba0aace3b01 --- arch/xtensa/include/asm/seccomp.h | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 arch/xtensa/include/asm/seccomp.h diff --git a/arch/xtensa/include/asm/seccomp.h b/arch/xtensa/include/asm/seccomp.h new file mode 100644 index 000000000000..f1cb6b0a9e1f --- /dev/null +++ b/arch/xtensa/include/asm/seccomp.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_SECCOMP_H +#define _ASM_SECCOMP_H + +#include + +#define SECCOMP_ARCH_NATIVE AUDIT_ARCH_XTENSA +#define SECCOMP_ARCH_NATIVE_NR NR_syscalls +#define SECCOMP_ARCH_NATIVE_NAME "xtensa" + +#endif /* _ASM_SECCOMP_H */ From c83d6f169d62ba4304469c76399b814b4b337f64 Mon Sep 17 00:00:00 2001 From: Hsuan-Chi Kuo Date: Thu, 4 Mar 2021 17:37:08 -0600 Subject: [PATCH 248/306] UPSTREAM: seccomp: Fix setting loaded filter count during TSYNC The desired behavior is to set the caller's filter count to thread's. This value is reported via /proc, so this fixes the inaccurate count exposed to userspace; it is not used for reference counting, etc. Signed-off-by: Hsuan-Chi Kuo Link: https://lore.kernel.org/r/20210304233708.420597-1-hsuanchikuo@gmail.com Co-developed-by: Wiktor Garbacz Signed-off-by: Wiktor Garbacz Link: https://lore.kernel.org/lkml/20210810125158.329849-1-wiktorg@google.com Signed-off-by: Kees Cook Cc: stable@vger.kernel.org Fixes: c818c03b661c ("seccomp: Report number of loaded filters in /proc/$pid/status") (cherry picked from commit b4d8a58f8dcfcc890f296696cadb76e77be44b5f) Bug: 187129171 Signed-off-by: Connor O'Brien Change-Id: Ia3ee7ec71e9fdbb8d958f9b42b1c6e02c761503f --- kernel/seccomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 0263bc055d49..1ec9bdc1e208 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -567,7 +567,7 @@ static inline void seccomp_sync_threads(unsigned long flags) smp_store_release(&thread->seccomp.filter, caller->seccomp.filter); atomic_set(&thread->seccomp.filter_count, - atomic_read(&thread->seccomp.filter_count)); + atomic_read(&caller->seccomp.filter_count)); /* * Don't let an unprivileged task work around From 2d2e51415146876a88d28d3dd230563d9f30bfae Mon Sep 17 00:00:00 2001 From: "Kenta.Tada@sony.com" Date: Sun, 21 Mar 2021 15:52:19 +0000 Subject: [PATCH 249/306] UPSTREAM: seccomp: Fix CONFIG tests for Seccomp_filters Strictly speaking, seccomp filters are only used when CONFIG_SECCOMP_FILTER. This patch fixes the condition to enable "Seccomp_filters" in /proc/$pid/status. Signed-off-by: Kenta Tada Fixes: c818c03b661c ("seccomp: Report number of loaded filters in /proc/$pid/status") Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/OSBPR01MB26772D245E2CF4F26B76A989F5669@OSBPR01MB2677.jpnprd01.prod.outlook.com (cherry picked from commit 64bdc0244054f7d4bb621c8b4455e292f4e421bc) Bug: 187129171 Signed-off-by: Connor O'Brien Change-Id: I44541ba5bac773b10b2593e47be943536b5ce3dd --- fs/proc/array.c | 2 ++ init/init_task.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index 6d9e56d19b9e..be8a186d21ad 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -342,8 +342,10 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) seq_put_decimal_ull(m, "NoNewPrivs:\t", task_no_new_privs(p)); #ifdef CONFIG_SECCOMP seq_put_decimal_ull(m, "\nSeccomp:\t", p->seccomp.mode); +#ifdef CONFIG_SECCOMP_FILTER seq_put_decimal_ull(m, "\nSeccomp_filters:\t", atomic_read(&p->seccomp.filter_count)); +#endif #endif seq_puts(m, "\nSpeculation_Store_Bypass:\t"); switch (arch_prctl_spec_ctrl_get(p, PR_SPEC_STORE_BYPASS)) { diff --git a/init/init_task.c b/init/init_task.c index b6fa82920e5d..b27ceec394d7 100644 --- a/init/init_task.c +++ b/init/init_task.c @@ -193,7 +193,7 @@ struct task_struct init_task #ifdef CONFIG_SECURITY .security = NULL, #endif -#ifdef CONFIG_SECCOMP +#ifdef CONFIG_SECCOMP_FILTER .seccomp = { .filter_count = ATOMIC_INIT(0) }, #endif }; From cb8dc8a108d69ce584fd1f44c5a738c4e11dcb49 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 28 Jan 2022 08:11:48 +0100 Subject: [PATCH 250/306] Revert "UPSTREAM: seccomp: Remove bogus __user annotations" This reverts commit 5444477e8a4d31f6e6ff720c2d018d06e405bcc1. Bug: 176068146 Signed-off-by: Jeff Vander Stoep Change-Id: Ic35b23f2f3ad99093b7df5e82633bba90acbe82a --- kernel/seccomp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 1ec9bdc1e208..455330c8b9ba 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -2035,7 +2035,7 @@ static bool seccomp_actions_logged_from_names(u32 *actions_logged, char *names) return true; } -static int read_actions_logged(struct ctl_table *ro_table, void *buffer, +static int read_actions_logged(struct ctl_table *ro_table, void __user *buffer, size_t *lenp, loff_t *ppos) { char names[sizeof(seccomp_actions_avail)]; @@ -2053,7 +2053,7 @@ static int read_actions_logged(struct ctl_table *ro_table, void *buffer, return proc_dostring(&table, 0, buffer, lenp, ppos); } -static int write_actions_logged(struct ctl_table *ro_table, void *buffer, +static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer, size_t *lenp, loff_t *ppos, u32 *actions_logged) { char names[sizeof(seccomp_actions_avail)]; From ae6919a83ca809630c56a05d3d5cfbc36514dcf7 Mon Sep 17 00:00:00 2001 From: Martynas Pumputis Date: Wed, 23 Jun 2021 15:56:45 +0200 Subject: [PATCH 251/306] UPSTREAM: net: retrieve netns cookie via getsocketopt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's getting more common to run nested container environments for testing cloud software. One of such examples is Kind [1] which runs a Kubernetes cluster in Docker containers on a single host. Each container acts as a Kubernetes node, and thus can run any Pod (aka container) inside the former. This approach simplifies testing a lot, as it eliminates complicated VM setups. Unfortunately, such a setup breaks some functionality when cgroupv2 BPF programs are used for load-balancing. The load-balancer BPF program needs to detect whether a request originates from the host netns or a container netns in order to allow some access, e.g. to a service via a loopback IP address. Typically, the programs detect this by comparing netns cookies with the one of the init ns via a call to bpf_get_netns_cookie(NULL). However, in nested environments the latter cannot be used given the Kubernetes node's netns is outside the init ns. To fix this, we need to pass the Kubernetes node netns cookie to the program in a different way: by extending getsockopt() with a SO_NETNS_COOKIE option, the orchestrator which runs in the Kubernetes node netns can retrieve the cookie and pass it to the program instead. Thus, this is following up on Eric's commit 3d368ab87cf6 ("net: initialize net->net_cookie at netns setup") to allow retrieval via SO_NETNS_COOKIE. This is also in line in how we retrieve socket cookie via SO_COOKIE. [1] https://kind.sigs.k8s.io/ Signed-off-by: Lorenz Bauer Signed-off-by: Martynas Pumputis Cc: Eric Dumazet Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller (cherry picked from commit e8b9eab99232c4e62ada9d7976c80fd5e8118289) Bug: 274789652 Tested: builds, net_test passes Signed-off-by: Maciej Żenczykowski Change-Id: If784a592450af38d70f16da61e36cbbaff80ebca --- arch/alpha/include/uapi/asm/socket.h | 2 ++ arch/mips/include/uapi/asm/socket.h | 2 ++ arch/parisc/include/uapi/asm/socket.h | 2 ++ arch/sparc/include/uapi/asm/socket.h | 2 ++ include/uapi/asm-generic/socket.h | 2 ++ net/core/sock.c | 7 +++++++ 6 files changed, 17 insertions(+) diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h index de6c4df61082..d033d3f92d6d 100644 --- a/arch/alpha/include/uapi/asm/socket.h +++ b/arch/alpha/include/uapi/asm/socket.h @@ -124,6 +124,8 @@ #define SO_DETACH_REUSEPORT_BPF 68 +#define SO_NETNS_COOKIE 71 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h index d0a9ed2ca2d6..ff3ab771e769 100644 --- a/arch/mips/include/uapi/asm/socket.h +++ b/arch/mips/include/uapi/asm/socket.h @@ -135,6 +135,8 @@ #define SO_DETACH_REUSEPORT_BPF 68 +#define SO_NETNS_COOKIE 71 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h index 10173c32195e..1a8ec3838c9b 100644 --- a/arch/parisc/include/uapi/asm/socket.h +++ b/arch/parisc/include/uapi/asm/socket.h @@ -116,6 +116,8 @@ #define SO_DETACH_REUSEPORT_BPF 0x4042 +#define SO_NETNS_COOKIE 0x4045 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h index 8029b681fc7c..08f9bbbf5bf2 100644 --- a/arch/sparc/include/uapi/asm/socket.h +++ b/arch/sparc/include/uapi/asm/socket.h @@ -117,6 +117,8 @@ #define SO_DETACH_REUSEPORT_BPF 0x0047 +#define SO_NETNS_COOKIE 0x0050 + #if !defined(__KERNEL__) diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h index 77f7c1638eb1..645606824258 100644 --- a/include/uapi/asm-generic/socket.h +++ b/include/uapi/asm-generic/socket.h @@ -119,6 +119,8 @@ #define SO_DETACH_REUSEPORT_BPF 68 +#define SO_NETNS_COOKIE 71 + #if !defined(__KERNEL__) #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) diff --git a/net/core/sock.c b/net/core/sock.c index cf74d31f61ff..7ffdb2bc1c20 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1542,6 +1542,13 @@ static int sk_getsockopt(struct sock *sk, int level, int optname, v.val = sk->sk_bound_dev_if; break; + case SO_NETNS_COOKIE: + lv = sizeof(u64); + if (len != lv) + return -EINVAL; + v.val64 = sock_net(sk)->net_cookie; + break; + default: /* We implement the SO_SNDLOWAT etc to not be settable * (1003.1g 7). From 95dcc82b80b73d36f99ddd8ebdd6ec11bad23444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 22 Mar 2023 16:13:37 -0700 Subject: [PATCH 252/306] ANDROID: fix ABI by undoing atomic64_t -> u64 type conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is pretty much a no-op, but avoids changing struct net ABI. Bug: 274789652 Test: builds, net_test Signed-off-by: Maciej Żenczykowski Original-Change-Id: Ia744bdf0a026adccaef8382aaecc771a8d0763a6 Change-Id: Ic22d6bb5e35a7634c1dd4d4c3ed3b142b885ec6f --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index 7ffdb2bc1c20..296907faf35e 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1546,7 +1546,7 @@ static int sk_getsockopt(struct sock *sk, int level, int optname, lv = sizeof(u64); if (len != lv) return -EINVAL; - v.val64 = sock_net(sk)->net_cookie; + v.val64 = atomic64_read(&sock_net(sk)->net_cookie); break; default: From eab1bfc6b7150bce6d4414a459f5cd581a191c07 Mon Sep 17 00:00:00 2001 From: Peiyong Wang Date: Thu, 7 Mar 2024 02:19:15 +0000 Subject: [PATCH 253/306] BACKPORT: net: core: enable SO_BINDTODEVICE for non-root users Currently, SO_BINDTODEVICE requires CAP_NET_RAW. This change allows a non-root user to bind a socket to an interface if it is not already bound. This is useful to allow an application to bind itself to a specific VRF for outgoing or incoming connections. Currently, an application wanting to manage connections through several VRF need to be privileged. Previously, IP_UNICAST_IF and IPV6_UNICAST_IF were added for Wine (76e21053b5bf3 and c4062dfc425e9) specifically for use by non-root processes. However, they are restricted to sendmsg() and not usable with TCP. Allowing SO_BINDTODEVICE would allow TCP clients to get the same privilege. As for TCP servers, outside the VRF use case, SO_BINDTODEVICE would only further restrict connections a server could accept. When an application is restricted to a VRF (with `ip vrf exec`), the socket is bound to an interface at creation and therefore, a non-privileged call to SO_BINDTODEVICE to escape the VRF fails. When an application bound a socket to SO_BINDTODEVICE and transmit it to a non-privileged process through a Unix socket, a tentative to change the bound device also fails. Before: >>> import socket >>> s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) >>> s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, b"dummy0") Traceback (most recent call last): File "", line 1, in PermissionError: [Errno 1] Operation not permitted After: >>> import socket >>> s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) >>> s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, b"dummy0") >>> s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, b"dummy0") Traceback (most recent call last): File "", line 1, in PermissionError: [Errno 1] Operation not permitted Bug: 323792489 Signed-off-by: Vincent Bernat Reviewed-by: David Ahern Signed-off-by: David S. Miller (cherry picked from commit c427bfec18f2190b8f4718785ee8ed2db4f84ee6) Change-Id: Ie3f4c536b78da12dd961dc681c6dfb0cdf1a06b7 Signed-off-by: Peiyong Wang --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index 296907faf35e..1c9d99fe59cb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -578,7 +578,7 @@ static int sock_bindtoindex_locked(struct sock *sk, int ifindex) /* Sorry... */ ret = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_RAW)) + if (sk->sk_bound_dev_if && !ns_capable(net->user_ns, CAP_NET_RAW)) goto out; ret = -EINVAL; From fac0966223895f20d5287406002965782e5c6f90 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Wed, 30 Jun 2021 18:54:44 -0700 Subject: [PATCH 254/306] UPSTREAM: procfs: allow reading fdinfo with PTRACE_MODE_READ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Android captures per-process system memory state when certain low memory events (e.g a foreground app kill) occur, to identify potential memory hoggers. In order to measure how much memory a process actually consumes, it is necessary to include the DMA buffer sizes for that process in the memory accounting. Since the handle to DMA buffers are raw FDs, it is important to be able to identify which processes have FD references to a DMA buffer. Currently, DMA buffer FDs can be accounted using /proc//fd/* and /proc//fdinfo -- both are only readable by the process owner, as follows: 1. Do a readlink on each FD. 2. If the target path begins with "/dmabuf", then the FD is a dmabuf FD. 3. stat the file to get the dmabuf inode number. 4. Read/ proc//fdinfo/, to get the DMA buffer size. Accessing other processes' fdinfo requires root privileges. This limits the use of the interface to debugging environments and is not suitable for production builds. Granting root privileges even to a system process increases the attack surface and is highly undesirable. Since fdinfo doesn't permit reading process memory and manipulating process state, allow accessing fdinfo under PTRACE_MODE_READ_FSCRED. Link: https://lkml.kernel.org/r/20210308170651.919148-1-kaleshsingh@google.com Signed-off-by: Kalesh Singh Suggested-by: Jann Horn Acked-by: Christian König Cc: Alexander Viro Cc: Alexey Dobriyan Cc: Alexey Gladkov Cc: Andrei Vagin Cc: Bernd Edlinger Cc: Christian Brauner Cc: Eric W. Biederman Cc: Helge Deller Cc: Hridya Valsaraju Cc: James Morris Cc: Jeff Vander Stoep Cc: Jonathan Corbet Cc: Kees Cook Cc: Matthew Wilcox Cc: Mauro Carvalho Chehab Cc: Michal Hocko Cc: Michel Lespinasse Cc: Minchan Kim Cc: Randy Dunlap Cc: Suren Baghdasaryan Cc: Szabolcs Nagy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 7bc3fa0172a423afb34e6df7a3998e5f23b1a94a) Bug: 159126739 Bug: 167141117 Signed-off-by: Kalesh Singh Change-Id: I842b689670f731138592f45c7124ef446d9aa59a --- fs/proc/base.c | 4 ++-- fs/proc/fd.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 6cac23a218a5..9143e5f41890 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3330,7 +3330,7 @@ static const struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), + DIR("fdinfo", S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations), DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), #ifdef CONFIG_NET DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), @@ -3750,7 +3750,7 @@ static const struct inode_operations proc_tid_comm_inode_operations = { */ static const struct pid_entry tid_base_stuff[] = { DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), + DIR("fdinfo", S_IRUGO|S_IXUGO, proc_fdinfo_inode_operations, proc_fdinfo_operations), DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), #ifdef CONFIG_NET DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 81882a13212d..b0357e5d3950 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,18 @@ out: static int seq_fdinfo_open(struct inode *inode, struct file *file) { + bool allowed = false; + struct task_struct *task = get_proc_task(inode); + + if (!task) + return -ESRCH; + + allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); + put_task_struct(task); + + if (!allowed) + return -EACCES; + return single_open(file, seq_show, inode); } @@ -325,7 +338,7 @@ static struct dentry *proc_fdinfo_instantiate(struct dentry *dentry, struct proc_inode *ei; struct inode *inode; - inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUSR); + inode = proc_pid_make_inode(dentry->d_sb, task, S_IFREG | S_IRUGO); if (!inode) return ERR_PTR(-ENOENT); From 7062e8847aa8164940bc315c232cbc213477687f Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Wed, 30 Jun 2021 18:54:49 -0700 Subject: [PATCH 255/306] UPSTREAM: BACKPORT: procfs/dmabuf: add inode number to /proc/*/fdinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And 'ino' field to /proc//fdinfo/ and /proc//task//fdinfo/. The inode numbers can be used to uniquely identify DMA buffers in user space and avoids a dependency on /proc//fd/* when accounting per-process DMA buffer sizes. Link: https://lkml.kernel.org/r/20210308170651.919148-2-kaleshsingh@google.com Signed-off-by: Kalesh Singh Acked-by: Randy Dunlap Acked-by: Christian König Cc: Jann Horn Cc: Jeff Vander Stoep Cc: Kees Cook Cc: Suren Baghdasaryan Cc: Minchan Kim Cc: Hridya Valsaraju Cc: Matthew Wilcox Cc: Alexander Viro Cc: Kalesh Singh Cc: Alexey Dobriyan Cc: Jonathan Corbet Cc: Mauro Carvalho Chehab Cc: Michal Hocko Cc: Alexey Gladkov Cc: Szabolcs Nagy Cc: Eric W. Biederman Cc: Christian Brauner Cc: Michel Lespinasse Cc: Bernd Edlinger Cc: Andrei Vagin Cc: Helge Deller Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 3845f256a8b527127bfbd4ced21e93d9e89aa6d7) [Kalesh Singh - Resolve conflict in Documentation/filesystems/proc.txt] Bug: 159126739 Bug: 167141117 Signed-off-by: Kalesh Singh Change-Id: Id07beac3edcc95c0b42805e24e5486965acbb46e --- Documentation/filesystems/proc.txt | 37 +++++++++++++++++++++++++----- fs/proc/fd.c | 5 ++-- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 6882bfd2c097..8acb7244b2e6 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1823,18 +1823,20 @@ if precise results are needed. 3.8 /proc//fdinfo/ - Information about opened file --------------------------------------------------------------- This file provides information associated with an opened file. The regular -files have at least three fields -- 'pos', 'flags' and mnt_id. The 'pos' -represents the current offset of the opened file in decimal form [see lseek(2) -for details], 'flags' denotes the octal O_xxx mask the file has been -created with [see open(2) for details] and 'mnt_id' represents mount ID of -the file system containing the opened file [see 3.5 /proc//mountinfo -for details]. +files have at least four fields -- 'pos', 'flags', 'mnt_id' and 'ino'. +The 'pos' represents the current offset of the opened file in decimal +form [see lseek(2) for details], 'flags' denotes the octal O_xxx mask the +file has been created with [see open(2) for details] and 'mnt_id' represents +mount ID of the file system containing the opened file [see 3.5 +/proc//mountinfo for details]. 'ino' represents the inode number of +the file. A typical output is pos: 0 flags: 0100002 mnt_id: 19 + ino: 63107 All locks associated with a file descriptor are shown in its fdinfo too. @@ -1848,6 +1850,7 @@ pair provide additional information particular to the objects they represent. pos: 0 flags: 04002 mnt_id: 9 + ino: 63107 eventfd-count: 5a where 'eventfd-count' is hex value of a counter. @@ -1857,6 +1860,7 @@ pair provide additional information particular to the objects they represent. pos: 0 flags: 04002 mnt_id: 9 + ino: 63107 sigmask: 0000000000000200 where 'sigmask' is hex value of the signal mask associated @@ -1867,6 +1871,7 @@ pair provide additional information particular to the objects they represent. pos: 0 flags: 02 mnt_id: 9 + ino: 63107 tfd: 5 events: 1d data: ffffffffffffffff pos:0 ino:61af sdev:7 where 'tfd' is a target file descriptor number in decimal form, @@ -1883,6 +1888,8 @@ pair provide additional information particular to the objects they represent. pos: 0 flags: 02000000 + mnt_id: 9 + ino: 63107 inotify wd:3 ino:9e7e sdev:800013 mask:800afce ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:7e9e0000640d1b6d where 'wd' is a watch descriptor in decimal form, ie a target file @@ -1905,6 +1912,7 @@ pair provide additional information particular to the objects they represent. pos: 0 flags: 02 mnt_id: 9 + ino: 63107 fanotify flags:10 event-flags:0 fanotify mnt_id:12 mflags:40 mask:38 ignored_mask:40000003 fanotify ino:4f969 sdev:800013 mflags:0 mask:3b ignored_mask:40000000 fhandle-bytes:8 fhandle-type:1 f_handle:69f90400c275b5b4 @@ -1927,6 +1935,7 @@ pair provide additional information particular to the objects they represent. pos: 0 flags: 02 mnt_id: 9 + ino: 63107 clockid: 0 ticks: 0 settime flags: 01 @@ -1941,6 +1950,22 @@ pair provide additional information particular to the objects they represent. with TIMER_ABSTIME option which will be shown in 'settime flags', but 'it_value' still exhibits timer's remaining time. +DMA Buffer files +~~~~~~~~~~~~~~~~ + +:: + + pos: 0 + flags: 04002 + mnt_id: 9 + ino: 63107 + size: 32768 + count: 2 + exp_name: system-heap + +where 'size' is the size of the DMA buffer in bytes. 'count' is the file count of +the DMA buffer file. 'exp_name' is the name of the DMA buffer exporter. + 3.9 /proc//map_files - Information about memory mapped files --------------------------------------------------------------------- This directory contains symbolic links which represent memory mapped files diff --git a/fs/proc/fd.c b/fs/proc/fd.c index b0357e5d3950..6157913911f8 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -54,9 +54,10 @@ static int seq_show(struct seq_file *m, void *v) if (ret) return ret; - seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", + seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\nino:\t%lu\n", (long long)file->f_pos, f_flags, - real_mount(file->f_path.mnt)->mnt_id); + real_mount(file->f_path.mnt)->mnt_id, + file_inode(file)->i_ino); show_fd_locks(m, file, files); if (seq_has_overflowed(m)) From d4d6a087de31919c7fc69bd8984c9e9b3baa65a4 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Thu, 29 Jul 2021 15:52:49 +0100 Subject: [PATCH 256/306] FROMGIT: procfs: prevent unpriveleged processes accessing fdinfo dir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file permissions on the fdinfo dir from were changed from S_IRUSR|S_IXUSR to S_IRUGO|S_IXUGO, and a PTRACE_MODE_READ check was added for opening the fdinfo files [1]. However, the ptrace permission check was not added to the directory, allowing anyone to get the open FD numbers by reading the fdinfo directory. Add the missing ptrace permission check for opening the fdinfo directory. [1] https://lkml.kernel.org/r/20210308170651.919148-1-kaleshsingh@google.com Link: https://lkml.kernel.org/r/20210713162008.1056986-1-kaleshsingh@google.com Fixes: 7bc3fa0172a4 ("procfs: allow reading fdinfo with PTRACE_MODE_READ") Signed-off-by: Kalesh Singh Cc: Kees Cook Cc: Eric W. Biederman Cc: Christian Brauner Cc: Christian König Cc: Suren Baghdasaryan Cc: Hridya Valsaraju Cc: Jann Horn Signed-off-by: Andrew Morton Signed-off-by: Mark Brown Bug: 151772539 Change-Id: I274b30aa0a5ce8412eae7161d31c6ee955035da9 (cherry picked from commit fc73829fa54b0c7af32d6da7c972eb3390957da4 git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master) Signed-off-by: Kalesh Singh --- fs/proc/fd.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 6157913911f8..6b634c0a9b6e 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -71,7 +71,7 @@ out: return 0; } -static int seq_fdinfo_open(struct inode *inode, struct file *file) +static int proc_fdinfo_access_allowed(struct inode *inode) { bool allowed = false; struct task_struct *task = get_proc_task(inode); @@ -85,6 +85,16 @@ static int seq_fdinfo_open(struct inode *inode, struct file *file) if (!allowed) return -EACCES; + return 0; +} + +static int seq_fdinfo_open(struct inode *inode, struct file *file) +{ + int ret = proc_fdinfo_access_allowed(inode); + + if (ret) + return ret; + return single_open(file, seq_show, inode); } @@ -365,12 +375,23 @@ static int proc_readfdinfo(struct file *file, struct dir_context *ctx) proc_fdinfo_instantiate); } +static int proc_open_fdinfo(struct inode *inode, struct file *file) +{ + int ret = proc_fdinfo_access_allowed(inode); + + if (ret) + return ret; + + return 0; +} + const struct inode_operations proc_fdinfo_inode_operations = { .lookup = proc_lookupfdinfo, .setattr = proc_setattr, }; const struct file_operations proc_fdinfo_operations = { + .open = proc_open_fdinfo, .read = generic_read_dir, .iterate_shared = proc_readfdinfo, .llseek = generic_file_llseek, From 695569241b29dbd333ee8d515183de8c6e60d667 Mon Sep 17 00:00:00 2001 From: Tashfin Shakeer Rhythm Date: Thu, 16 Jan 2025 06:53:31 +0600 Subject: [PATCH 257/306] devfreq: bimc-bwmon: Don't free/reallocate IRQ during suspend/resume In __resume_bw_hwmon(), request_threaded_irq() tries to make a big allocation before everything is thawed and oom killer is re-enabled, which triggers an order-2 memory allocation failure from kthreadd. This causes the devfreq device to fail to create the IRQ thread, and therefore, it can't resume. At this point, IRQs like qcom,cpu-cpu-llcc-bwmon, qcom,cpu-llcc-ddr-bwmon, qcom,snoop-l3-bwmon are not allocated. But __suspend_bw_hwmon() tries to free them anyway, causing the following series of call traces: [49231.949317] kthreadd: page allocation failure: order:2, mode:0x400d00(GFP_NOIO|__GFP_ZERO|__GFP_ACCOUNT), nodemask=(null),cpuset=/,mems_allowed=0 [49231.949341] CPU: 2 PID: 2 Comm: kthreadd Not tainted 5.4.278-Scarlet-v1.0-beta8 #1 [49231.949345] Hardware name: redwood based Qualcomm Technologies, Inc. SM7325 (DT) [49231.949349] Call trace: [49231.949366] dump_backtrace+0x0/0x1a0 [49231.949373] show_stack+0x14/0x20 [49231.949384] dump_stack+0x8c/0xcc [49231.949394] warn_alloc+0xec/0x110 [49231.949401] __alloc_pages_slowpath+0xe80/0xf00 [49231.949409] __alloc_pages_nodemask+0x150/0x180 [49231.949421] dup_task_struct+0x90/0x1e0 [49231.949427] copy_process+0x150/0xb30 [49231.949433] _do_fork+0x88/0x350 [49231.949439] kernel_thread+0x48/0x70 [49231.949448] kthreadd+0x1ec/0x280 [49231.949454] ret_from_fork+0x10/0x18 [49231.949470] Mem-Info: [49231.949488] active_anon:348299 inactive_anon:132548 isolated_anon:0 active_file:97104 inactive_file:98252 isolated_file:0 unevictable:61330 dirty:0 writeback:0 unstable:0 slab_reclaimable:23532 slab_unreclaimable:64025 mapped:208056 shmem:15179 pagetables:31685 bounce:0 free:36974 free_pcp:0 free_cma:46 [49231.949502] Node 0 active_anon:1393196kB inactive_anon:530192kB active_file:388416kB inactive_file:393008kB unevictable:245320kB isolated(anon):0kB isolated(file):0kB mapped:832224kB dirty:0kB writeback:0kB shmem:60716kB writeback_tmp:0kB unstable:0kB all_unreclaimable? no [49231.949519] Normal free:147896kB min:9312kB low:44784kB high:50268kB active_anon:1393080kB inactive_anon:530372kB active_file:388236kB inactive_file:392776kB unevictable:245320kB writepending:0kB present:5642556kB managed:5484672kB mlocked:244888kB kernel_stack:82704kB pagetables:126740kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:184kB [49231.949522] lowmem_reserve[]: 0 0 [49231.949530] Normal: 32941*4kB (UMECH) 2020*8kB (UMEH) 35*16kB (H) 7*32kB (H) 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 148708kB [49231.949568] 257736 total pagecache pages [49231.949573] 3431 pages in swap cache [49231.949578] Swap cache stats: add 7482872, delete 7479455, find 338640/3769326 [49231.949581] Free swap = 2294120kB [49231.949584] Total swap = 4194300kB [49231.949588] 1410639 pages RAM [49231.949591] 0 pages HighMem/MovableOnly [49231.949594] 39471 pages reserved [49231.949597] 72704 pages cma reserved [49231.949606] cma: cma-0 pages: => 579 used of 5120 total pages [49231.949613] cma: cma-1 pages: => 512 used of 3072 total pages [49231.949619] cma: cma-2 pages: => 0 used of 4096 total pages [49231.949627] cma: cma-3 pages: => 826 used of 8192 total pages [49231.949635] cma: cma-4 pages: => 0 used of 7168 total pages [49231.949669] cma: cma-5 pages: => 0 used of 35840 total pages [49231.949676] cma: cma-6 pages: => 0 used of 4096 total pages [49231.949683] cma: cma-7 pages: => 0 used of 5120 total pages [49231.949725] bimc-bwmon 90b9100.qcom,snoop-l3-bwmon: Unable to register interrupt handler! (-12) [49231.949738] devfreq-icc 18590100.qcom,snoop-l3-bw: Unable to start HW monitor! (-12) [49231.949741] devfreq-icc 18590100.qcom,snoop-l3-bw: Unable to resume BW HW mon governor (-12) [49231.949744] devfreq 18590100.qcom,snoop-l3-bw: failed to resume devfreq device [49231.949880] bimc-bwmon 9091000.qcom,cpu-llcc-ddr-bwmon: Unable to register interrupt handler! (-12) [49231.949884] devfreq-icc soc:qcom,cpu-llcc-ddr-bw: Unable to start HW monitor! (-12) [49231.949885] devfreq-icc soc:qcom,cpu-llcc-ddr-bw: Unable to resume BW HW mon governor (-12) [49231.949888] devfreq soc:qcom,cpu-llcc-ddr-bw: failed to resume devfreq device [49231.950002] bimc-bwmon 90b6400.qcom,cpu-cpu-llcc-bwmon: Unable to register interrupt handler! (-12) [49231.950004] devfreq-icc soc:qcom,cpu-cpu-llcc-bw: Unable to start HW monitor! (-12) [49231.950006] devfreq-icc soc:qcom,cpu-cpu-llcc-bw: Unable to resume BW HW mon governor (-12) [49231.950009] devfreq soc:qcom,cpu-cpu-llcc-bw: failed to resume devfreq device [49232.171457] Filesystems sync: 0.005 seconds [49232.398473] Filesystems sync: 0.008 seconds [49232.417668] ------------[ cut here ]------------ [49232.417674] Trying to free already-free IRQ 53 [49232.417702] WARNING: CPU: 6 PID: 3656 at kernel/irq/manage.c:1765 __free_irq+0x2fc/0x400 [49232.417710] CPU: 6 PID: 3656 Comm: binder:502_7 Not tainted 5.4.278-Scarlet-v1.0-beta8 #1 [49232.417714] Hardware name: redwood based Qualcomm Technologies, Inc. SM7325 (DT) [49232.417717] pstate: 60000085 (nZCv daIf -PAN -UAO) [49232.417722] pc : __free_irq+0x2fc/0x400 [49232.417726] lr : __free_irq+0x2f8/0x400 [49232.417728] sp : ffffffaa166669e0 [49232.417731] x29: ffffffaa166669e0 x28: ffffffa9ae80d400 [49232.417735] x27: 0000000000000000 x26: 0000000000000000 [49232.417739] x25: ffffffa91ff3e268 x24: ffffffa9ae80d400 [49232.417742] x23: ffffffaa1948dc40 x22: 0000000000000035 [49232.417746] x21: ffffffa91ff3e2a0 x20: 0000000000000000 [49232.417749] x19: ffffffa91ff3e200 x18: 00000000ffed03ec [49232.417753] x17: 00000000000d03ec x16: ffffffda6c1a54e8 [49232.417756] x15: 0000000000000000 x14: 0000000000000082 [49232.417759] x13: 0000000000000034 x12: 0000000000000004 [49232.417761] x11: ffffffda6c1a54e0 x10: 00000000ffffffff [49232.417764] x9 : 115043787f31d900 x8 : 0000000000000000 [49232.417767] x7 : 0000000000000000 x6 : 7420676e69797254 [49232.417770] x5 : ffffffda6c2d5126 x4 : 0000000000000000 [49232.417773] x3 : 0000000000000000 x2 : ffffffffffffc9ff [49232.417776] x1 : 0000000000000000 x0 : 0000000000000022 [49232.417780] Call trace: [49232.417785] __free_irq+0x2fc/0x400 [49232.417789] free_irq+0x30/0x90 [49232.417802] suspend_bw_hwmon2+0xb8/0x140 [49232.417809] devfreq_bw_hwmon_ev_handler+0x1b4/0x520 [49232.417820] devfreq_suspend_device+0x58/0xe0 [49232.417825] devfreq_suspend+0x54/0x90 [49232.417838] dpm_suspend+0x2c/0x340 [49232.417841] dpm_suspend_start+0x7c/0xa0 [49232.417846] suspend_devices_and_enter+0xe0/0x5c0 [49232.417849] pm_suspend+0x258/0x280 [49232.417858] state_store+0x100/0x150 [49232.417869] kobj_attr_store+0x14/0x30 [49232.417883] sysfs_kf_write+0x38/0x50 [49232.417888] kernfs_fop_write+0x168/0x290 [49232.417896] __vfs_write+0x34/0x190 [49232.417899] vfs_write+0x11c/0x2d0 [49232.417903] __arm64_sys_write+0x78/0x110 [49232.417910] el0_svc_common+0xb0/0x120 [49232.417913] do_el0_svc+0x18/0x20 [49232.417918] el0_sync_handler+0x148/0x190 [49232.417922] el0_sync+0x140/0x180 [49232.417925] ---[ end trace b44a82c335d29d61 ]--- [49232.417952] ------------[ cut here ]------------ [49232.417954] Trying to free already-free IRQ 52 [49232.417962] WARNING: CPU: 6 PID: 3656 at kernel/irq/manage.c:1765 __free_irq+0x2fc/0x400 [49232.417966] CPU: 6 PID: 3656 Comm: binder:502_7 Tainted: G W 5.4.278-Scarlet-v1.0-beta8 #1 [49232.417968] Hardware name: redwood based Qualcomm Technologies, Inc. SM7325 (DT) [49232.417970] pstate: 60000085 (nZCv daIf -PAN -UAO) [49232.417974] pc : __free_irq+0x2fc/0x400 [49232.417977] lr : __free_irq+0x2f8/0x400 [49232.417979] sp : ffffffaa166669e0 [49232.417980] x29: ffffffaa166669e0 x28: ffffffa9ae80d400 [49232.417984] x27: 0000000000000000 x26: 0000000000000000 [49232.417987] x25: ffffffa91ff3e068 x24: ffffffa9ae80d400 [49232.417990] x23: ffffffaa1948d840 x22: 0000000000000034 [49232.417992] x21: ffffffa91ff3e0a0 x20: 0000000000000000 [49232.417995] x19: ffffffa91ff3e000 x18: 00000000ffecfa44 [49232.417998] x17: 00000000000cfa44 x16: ffffffda6c1a54e8 [49232.418001] x15: 0000000000000000 x14: 0000000000000082 [49232.418004] x13: 0000000000000034 x12: 0000000000000004 [49232.418006] x11: ffffffda6c1a54e0 x10: 00000000ffffffff [49232.418009] x9 : 115043787f31d900 x8 : 0000000000000000 [49232.418012] x7 : 0000000000000000 x6 : 7420676e69797254 [49232.418015] x5 : ffffffda6c2d5ace x4 : 0000000000000000 [49232.418018] x3 : 0000000000000000 x2 : ffffffffffffc9d0 [49232.418021] x1 : 0000000000000000 x0 : 0000000000000022 [49232.418023] Call trace: [49232.418027] __free_irq+0x2fc/0x400 [49232.418030] free_irq+0x30/0x90 [49232.418034] suspend_bw_hwmon3+0x94/0x110 [49232.418038] devfreq_bw_hwmon_ev_handler+0x1b4/0x520 [49232.418043] devfreq_suspend_device+0x58/0xe0 [49232.418047] devfreq_suspend+0x54/0x90 [49232.418050] dpm_suspend+0x2c/0x340 [49232.418053] dpm_suspend_start+0x7c/0xa0 [49232.418056] suspend_devices_and_enter+0xe0/0x5c0 [49232.418058] pm_suspend+0x258/0x280 [49232.418062] state_store+0x100/0x150 [49232.418066] kobj_attr_store+0x14/0x30 [49232.418070] sysfs_kf_write+0x38/0x50 [49232.418074] kernfs_fop_write+0x168/0x290 [49232.418077] __vfs_write+0x34/0x190 [49232.418080] vfs_write+0x11c/0x2d0 [49232.418083] __arm64_sys_write+0x78/0x110 [49232.418085] el0_svc_common+0xb0/0x120 [49232.418087] do_el0_svc+0x18/0x20 [49232.418091] el0_sync_handler+0x148/0x190 [49232.418094] el0_sync+0x140/0x180 [49232.418095] ---[ end trace b44a82c335d29d62 ]--- [49232.418112] ------------[ cut here ]------------ [49232.418113] Trying to free already-free IRQ 51 [49232.418120] WARNING: CPU: 6 PID: 3656 at kernel/irq/manage.c:1765 __free_irq+0x2fc/0x400 [49232.418122] CPU: 6 PID: 3656 Comm: binder:502_7 Tainted: G W 5.4.278-Scarlet-v1.0-beta8 #1 [49232.418124] Hardware name: redwood based Qualcomm Technologies, Inc. SM7325 (DT) [49232.418126] pstate: 60000085 (nZCv daIf -PAN -UAO) [49232.418130] pc : __free_irq+0x2fc/0x400 [49232.418133] lr : __free_irq+0x2f8/0x400 [49232.418135] sp : ffffffaa166669e0 [49232.418136] x29: ffffffaa166669e0 x28: ffffffa9ae80d400 [49232.418139] x27: 0000000000000000 x26: 0000000000000000 [49232.418142] x25: ffffffa91ff3de68 x24: ffffffa9ae80d400 [49232.418146] x23: ffffffaa1948d440 x22: 0000000000000033 [49232.418148] x21: ffffffa91ff3dea0 x20: 0000000000000000 [49232.418151] x19: ffffffa91ff3de00 x18: 00000000ffecf08c [49232.418154] x17: 00000000000cf08c x16: ffffffda6c1a54e8 [49232.418156] x15: 0000000000000000 x14: 0000000000000082 [49232.418159] x13: 0000000000000034 x12: 0000000000000004 [49232.418162] x11: ffffffda6c1a54e0 x10: 00000000ffffffff [49232.418165] x9 : 115043787f31d900 x8 : 0000000000000000 [49232.418168] x7 : 0000000000000000 x6 : 7420676e69797254 [49232.418171] x5 : ffffffda6c2d6486 x4 : 0000000000000000 [49232.418174] x3 : 0000000000000000 x2 : ffffffffffffc9a1 [49232.418176] x1 : 0000000000000000 x0 : 0000000000000022 [49232.418179] Call trace: [49232.418182] __free_irq+0x2fc/0x400 [49232.418186] free_irq+0x30/0x90 [49232.418188] suspend_bw_hwmon2+0xb8/0x140 [49232.418192] devfreq_bw_hwmon_ev_handler+0x1b4/0x520 [49232.418197] devfreq_suspend_device+0x58/0xe0 [49232.418201] devfreq_suspend+0x54/0x90 [49232.418204] dpm_suspend+0x2c/0x340 [49232.418207] dpm_suspend_start+0x7c/0xa0 [49232.418209] suspend_devices_and_enter+0xe0/0x5c0 [49232.418212] pm_suspend+0x258/0x280 [49232.418216] state_store+0x100/0x150 [49232.418219] kobj_attr_store+0x14/0x30 [49232.418223] sysfs_kf_write+0x38/0x50 [49232.418227] kernfs_fop_write+0x168/0x290 [49232.418230] __vfs_write+0x34/0x190 [49232.418233] vfs_write+0x11c/0x2d0 [49232.418236] __arm64_sys_write+0x78/0x110 [49232.418238] el0_svc_common+0xb0/0x120 [49232.418240] do_el0_svc+0x18/0x20 [49232.418243] el0_sync_handler+0x148/0x190 [49232.418246] el0_sync+0x140/0x180 [49232.418247] ---[ end trace b44a82c335d29d63 ]--- There is no need to reallocate and free the IRQs during suspend and resume. Replace IRQ thread creation with a simpler [enable|disable]_irq() approach to fix the issue. Co-authored-by: Sultan Alsawaf Change-Id: Ia12b8d24feddaef75792988ea55a6e8e29bf687a Signed-off-by: Sultan Alsawaf Signed-off-by: Tashfin Shakeer Rhythm --- drivers/devfreq/bimc-bwmon.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/devfreq/bimc-bwmon.c b/drivers/devfreq/bimc-bwmon.c index 668477348ae9..f7be1c0353d2 100644 --- a/drivers/devfreq/bimc-bwmon.c +++ b/drivers/devfreq/bimc-bwmon.c @@ -882,7 +882,7 @@ int __suspend_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) struct bwmon *m = to_bwmon(hw); mon_irq_disable(m, type); - free_irq(m->irq, m); + disable_irq(m->irq); mon_disable(m, type); mon_irq_clear(m, type); @@ -908,7 +908,6 @@ static __always_inline int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) { struct bwmon *m = to_bwmon(hw); - int ret; irq_handler_t handler; switch (type) { @@ -924,15 +923,7 @@ int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type) } mon_clear(m, false, type); - ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread, - IRQF_ONESHOT | IRQF_SHARED, - dev_name(m->dev), m); - if (ret < 0) { - dev_err(m->dev, "Unable to register interrupt handler! (%d)\n", - ret); - return ret; - } - + enable_irq(m->irq); mon_irq_enable(m, type); mon_enable(m, type); From 1eee152fce93763f5eac4e49c7dbd62562518b98 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:31 +0000 Subject: [PATCH 258/306] BACKPORT: mm: add Kernel Electric-Fence infrastructure Patch series "KFENCE: A low-overhead sampling-based memory safety error detector", v7. This adds the Kernel Electric-Fence (KFENCE) infrastructure. KFENCE is a low-overhead sampling-based memory safety error detector of heap use-after-free, invalid-free, and out-of-bounds access errors. This series enables KFENCE for the x86 and arm64 architectures, and adds KFENCE hooks to the SLAB and SLUB allocators. KFENCE is designed to be enabled in production kernels, and has near zero performance overhead. Compared to KASAN, KFENCE trades performance for precision. The main motivation behind KFENCE's design, is that with enough total uptime KFENCE will detect bugs in code paths not typically exercised by non-production test workloads. One way to quickly achieve a large enough total uptime is when the tool is deployed across a large fleet of machines. KFENCE objects each reside on a dedicated page, at either the left or right page boundaries. The pages to the left and right of the object page are "guard pages", whose attributes are changed to a protected state, and cause page faults on any attempted access to them. Such page faults are then intercepted by KFENCE, which handles the fault gracefully by reporting a memory access error. Guarded allocations are set up based on a sample interval (can be set via kfence.sample_interval). After expiration of the sample interval, the next allocation through the main allocator (SLAB or SLUB) returns a guarded allocation from the KFENCE object pool. At this point, the timer is reset, and the next allocation is set up after the expiration of the interval. To enable/disable a KFENCE allocation through the main allocator's fast-path without overhead, KFENCE relies on static branches via the static keys infrastructure. The static branch is toggled to redirect the allocation to KFENCE. The KFENCE memory pool is of fixed size, and if the pool is exhausted no further KFENCE allocations occur. The default config is conservative with only 255 objects, resulting in a pool size of 2 MiB (with 4 KiB pages). We have verified by running synthetic benchmarks (sysbench I/O, hackbench) and production server-workload benchmarks that a kernel with KFENCE (using sample intervals 100-500ms) is performance-neutral compared to a non-KFENCE baseline kernel. KFENCE is inspired by GWP-ASan [1], a userspace tool with similar properties. The name "KFENCE" is a homage to the Electric Fence Malloc Debugger [2]. For more details, see Documentation/dev-tools/kfence.rst added in the series -- also viewable here: https://raw.githubusercontent.com/google/kasan/kfence/Documentation/dev-tools/kfence.rst [1] http://llvm.org/docs/GwpAsan.html [2] https://linux.die.net/man/3/efence This patch (of 9): This adds the Kernel Electric-Fence (KFENCE) infrastructure. KFENCE is a low-overhead sampling-based memory safety error detector of heap use-after-free, invalid-free, and out-of-bounds access errors. KFENCE is designed to be enabled in production kernels, and has near zero performance overhead. Compared to KASAN, KFENCE trades performance for precision. The main motivation behind KFENCE's design, is that with enough total uptime KFENCE will detect bugs in code paths not typically exercised by non-production test workloads. One way to quickly achieve a large enough total uptime is when the tool is deployed across a large fleet of machines. KFENCE objects each reside on a dedicated page, at either the left or right page boundaries. The pages to the left and right of the object page are "guard pages", whose attributes are changed to a protected state, and cause page faults on any attempted access to them. Such page faults are then intercepted by KFENCE, which handles the fault gracefully by reporting a memory access error. To detect out-of-bounds writes to memory within the object's page itself, KFENCE also uses pattern-based redzones. The following figure illustrates the page layout: ---+-----------+-----------+-----------+-----------+-----------+--- | xxxxxxxxx | O : | xxxxxxxxx | : O | xxxxxxxxx | | xxxxxxxxx | B : | xxxxxxxxx | : B | xxxxxxxxx | | x GUARD x | J : RED- | x GUARD x | RED- : J | x GUARD x | | xxxxxxxxx | E : ZONE | xxxxxxxxx | ZONE : E | xxxxxxxxx | | xxxxxxxxx | C : | xxxxxxxxx | : C | xxxxxxxxx | | xxxxxxxxx | T : | xxxxxxxxx | : T | xxxxxxxxx | ---+-----------+-----------+-----------+-----------+-----------+--- Guarded allocations are set up based on a sample interval (can be set via kfence.sample_interval). After expiration of the sample interval, a guarded allocation from the KFENCE object pool is returned to the main allocator (SLAB or SLUB). At this point, the timer is reset, and the next allocation is set up after the expiration of the interval. To enable/disable a KFENCE allocation through the main allocator's fast-path without overhead, KFENCE relies on static branches via the static keys infrastructure. The static branch is toggled to redirect the allocation to KFENCE. To date, we have verified by running synthetic benchmarks (sysbench I/O, hackbench) that a kernel compiled with KFENCE is performance-neutral compared to the non-KFENCE baseline. For more details, see Documentation/dev-tools/kfence.rst (added later in the series). Link: https://lkml.kernel.org/r/20201103175841.3495947-2-elver@google.com Signed-off-by: Marco Elver Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov Reviewed-by: SeongJae Park Co-developed-by: Marco Elver Reviewed-by: Jann Horn Cc: "H. Peter Anvin" Cc: Paul E. McKenney Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: Ingo Molnar Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Joern Engel Cc: Kees Cook Cc: Mark Rutland Cc: Pekka Enberg Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 2a8dede73c3496bbd917644657f3735a4f508cb9 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: dropped KCSAN bits missing in 5.4, resolved minor conflict in init/main.c] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I6b474675cc9732c31118df53fa06c3997f577218 --- include/linux/kfence.h | 201 ++++++++++ init/main.c | 3 + lib/Kconfig.debug | 1 + lib/Kconfig.kfence | 57 +++ mm/Makefile | 1 + mm/kfence/Makefile | 3 + mm/kfence/core.c | 822 +++++++++++++++++++++++++++++++++++++++++ mm/kfence/kfence.h | 107 ++++++ mm/kfence/report.c | 235 ++++++++++++ 9 files changed, 1430 insertions(+) create mode 100644 include/linux/kfence.h create mode 100644 lib/Kconfig.kfence create mode 100644 mm/kfence/Makefile create mode 100644 mm/kfence/core.c create mode 100644 mm/kfence/kfence.h create mode 100644 mm/kfence/report.c diff --git a/include/linux/kfence.h b/include/linux/kfence.h new file mode 100644 index 000000000000..ed2d48acdafe --- /dev/null +++ b/include/linux/kfence.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_KFENCE_H +#define _LINUX_KFENCE_H + +#include +#include +#include + +#ifdef CONFIG_KFENCE + +/* + * We allocate an even number of pages, as it simplifies calculations to map + * address to metadata indices; effectively, the very first page serves as an + * extended guard page, but otherwise has no special purpose. + */ +#define KFENCE_POOL_SIZE ((CONFIG_KFENCE_NUM_OBJECTS + 1) * 2 * PAGE_SIZE) +extern char *__kfence_pool; + +DECLARE_STATIC_KEY_FALSE(kfence_allocation_key); + +/** + * is_kfence_address() - check if an address belongs to KFENCE pool + * @addr: address to check + * + * Return: true or false depending on whether the address is within the KFENCE + * object range. + * + * KFENCE objects live in a separate page range and are not to be intermixed + * with regular heap objects (e.g. KFENCE objects must never be added to the + * allocator freelists). Failing to do so may and will result in heap + * corruptions, therefore is_kfence_address() must be used to check whether + * an object requires specific handling. + * + * Note: This function may be used in fast-paths, and is performance critical. + * Future changes should take this into account; for instance, we want to avoid + * introducing another load and therefore need to keep KFENCE_POOL_SIZE a + * constant (until immediate patching support is added to the kernel). + */ +static __always_inline bool is_kfence_address(const void *addr) +{ + /* + * The non-NULL check is required in case the __kfence_pool pointer was + * never initialized; keep it in the slow-path after the range-check. + */ + return unlikely((unsigned long)((char *)addr - __kfence_pool) < KFENCE_POOL_SIZE && addr); +} + +/** + * kfence_alloc_pool() - allocate the KFENCE pool via memblock + */ +void __init kfence_alloc_pool(void); + +/** + * kfence_init() - perform KFENCE initialization at boot time + * + * Requires that kfence_alloc_pool() was called before. This sets up the + * allocation gate timer, and requires that workqueues are available. + */ +void __init kfence_init(void); + +/** + * kfence_shutdown_cache() - handle shutdown_cache() for KFENCE objects + * @s: cache being shut down + * + * Before shutting down a cache, one must ensure there are no remaining objects + * allocated from it. Because KFENCE objects are not referenced from the cache + * directly, we need to check them here. + * + * Note that shutdown_cache() is internal to SL*B, and kmem_cache_destroy() does + * not return if allocated objects still exist: it prints an error message and + * simply aborts destruction of a cache, leaking memory. + * + * If the only such objects are KFENCE objects, we will not leak the entire + * cache, but instead try to provide more useful debug info by making allocated + * objects "zombie allocations". Objects may then still be used or freed (which + * is handled gracefully), but usage will result in showing KFENCE error reports + * which include stack traces to the user of the object, the original allocation + * site, and caller to shutdown_cache(). + */ +void kfence_shutdown_cache(struct kmem_cache *s); + +/* + * Allocate a KFENCE object. Allocators must not call this function directly, + * use kfence_alloc() instead. + */ +void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags); + +/** + * kfence_alloc() - allocate a KFENCE object with a low probability + * @s: struct kmem_cache with object requirements + * @size: exact size of the object to allocate (can be less than @s->size + * e.g. for kmalloc caches) + * @flags: GFP flags + * + * Return: + * * NULL - must proceed with allocating as usual, + * * non-NULL - pointer to a KFENCE object. + * + * kfence_alloc() should be inserted into the heap allocation fast path, + * allowing it to transparently return KFENCE-allocated objects with a low + * probability using a static branch (the probability is controlled by the + * kfence.sample_interval boot parameter). + */ +static __always_inline void *kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) +{ + if (static_branch_unlikely(&kfence_allocation_key)) + return __kfence_alloc(s, size, flags); + return NULL; +} + +/** + * kfence_ksize() - get actual amount of memory allocated for a KFENCE object + * @addr: pointer to a heap object + * + * Return: + * * 0 - not a KFENCE object, must call __ksize() instead, + * * non-0 - this many bytes can be accessed without causing a memory error. + * + * kfence_ksize() returns the number of bytes requested for a KFENCE object at + * allocation time. This number may be less than the object size of the + * corresponding struct kmem_cache. + */ +size_t kfence_ksize(const void *addr); + +/** + * kfence_object_start() - find the beginning of a KFENCE object + * @addr - address within a KFENCE-allocated object + * + * Return: address of the beginning of the object. + * + * SL[AU]B-allocated objects are laid out within a page one by one, so it is + * easy to calculate the beginning of an object given a pointer inside it and + * the object size. The same is not true for KFENCE, which places a single + * object at either end of the page. This helper function is used to find the + * beginning of a KFENCE-allocated object. + */ +void *kfence_object_start(const void *addr); + +/** + * __kfence_free() - release a KFENCE heap object to KFENCE pool + * @addr: object to be freed + * + * Requires: is_kfence_address(addr) + * + * Release a KFENCE object and mark it as freed. + */ +void __kfence_free(void *addr); + +/** + * kfence_free() - try to release an arbitrary heap object to KFENCE pool + * @addr: object to be freed + * + * Return: + * * false - object doesn't belong to KFENCE pool and was ignored, + * * true - object was released to KFENCE pool. + * + * Release a KFENCE object and mark it as freed. May be called on any object, + * even non-KFENCE objects, to simplify integration of the hooks into the + * allocator's free codepath. The allocator must check the return value to + * determine if it was a KFENCE object or not. + */ +static __always_inline __must_check bool kfence_free(void *addr) +{ + if (!is_kfence_address(addr)) + return false; + __kfence_free(addr); + return true; +} + +/** + * kfence_handle_page_fault() - perform page fault handling for KFENCE pages + * @addr: faulting address + * + * Return: + * * false - address outside KFENCE pool, + * * true - page fault handled by KFENCE, no additional handling required. + * + * A page fault inside KFENCE pool indicates a memory error, such as an + * out-of-bounds access, a use-after-free or an invalid memory access. In these + * cases KFENCE prints an error message and marks the offending page as + * present, so that the kernel can proceed. + */ +bool __must_check kfence_handle_page_fault(unsigned long addr); + +#else /* CONFIG_KFENCE */ + +static inline bool is_kfence_address(const void *addr) { return false; } +static inline void kfence_alloc_pool(void) { } +static inline void kfence_init(void) { } +static inline void kfence_shutdown_cache(struct kmem_cache *s) { } +static inline void *kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) { return NULL; } +static inline size_t kfence_ksize(const void *addr) { return 0; } +static inline void *kfence_object_start(const void *addr) { return NULL; } +static inline void __kfence_free(void *addr) { } +static inline bool __must_check kfence_free(void *addr) { return false; } +static inline bool __must_check kfence_handle_page_fault(unsigned long addr) { return false; } + +#endif + +#endif /* _LINUX_KFENCE_H */ diff --git a/init/main.c b/init/main.c index ea899e9d7743..d283c689496a 100644 --- a/init/main.c +++ b/init/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -557,6 +558,7 @@ static void __init mm_init(void) */ page_ext_init_flatmem(); init_debug_pagealloc(); + kfence_alloc_pool(); report_meminit(); mem_init(); /* page_owner must be initialized after buddy is ready */ @@ -685,6 +687,7 @@ asmlinkage __visible void __init start_kernel(void) hrtimers_init(); softirq_init(); timekeeping_init(); + kfence_init(); time_init(); /* diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b74832919af2..f47cbf5660b1 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -782,6 +782,7 @@ config DEBUG_STACKOVERFLOW If in doubt, say "N". source "lib/Kconfig.kasan" +source "lib/Kconfig.kfence" endmenu # "Memory Debugging" diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence new file mode 100644 index 000000000000..b209cd02042b --- /dev/null +++ b/lib/Kconfig.kfence @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config HAVE_ARCH_KFENCE + bool + +menuconfig KFENCE + bool "KFENCE: low-overhead sampling-based memory safety error detector" + depends on HAVE_ARCH_KFENCE && !KASAN && (SLAB || SLUB) + depends on JUMP_LABEL # To ensure performance, require jump labels + select STACKTRACE + help + KFENCE is a low-overhead sampling-based detector of heap out-of-bounds + access, use-after-free, and invalid-free errors. KFENCE is designed + to have negligible cost to permit enabling it in production + environments. + + Note that, KFENCE is not a substitute for explicit testing with tools + such as KASAN. KFENCE can detect a subset of bugs that KASAN can + detect, albeit at very different performance profiles. If you can + afford to use KASAN, continue using KASAN, for example in test + environments. If your kernel targets production use, and cannot + enable KASAN due to its cost, consider using KFENCE. + +if KFENCE + +config KFENCE_SAMPLE_INTERVAL + int "Default sample interval in milliseconds" + default 100 + help + The KFENCE sample interval determines the frequency with which heap + allocations will be guarded by KFENCE. May be overridden via boot + parameter "kfence.sample_interval". + + Set this to 0 to disable KFENCE by default, in which case only + setting "kfence.sample_interval" to a non-zero value enables KFENCE. + +config KFENCE_NUM_OBJECTS + int "Number of guarded objects available" + range 1 65535 + default 255 + help + The number of guarded objects available. For each KFENCE object, 2 + pages are required; with one containing the object and two adjacent + ones used as guard pages. + +config KFENCE_STRESS_TEST_FAULTS + int "Stress testing of fault handling and error reporting" if EXPERT + default 0 + help + The inverse probability with which to randomly protect KFENCE object + pages, resulting in spurious use-after-frees. The main purpose of + this option is to stress test KFENCE with concurrent error reports + and allocations/frees. A value of 0 disables stress testing logic. + + Only for KFENCE testing; set to 0 if you are not a KFENCE developer. + +endif # KFENCE diff --git a/mm/Makefile b/mm/Makefile index d433568ee189..7d852be8167b 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_PAGE_POISONING) += page_poison.o obj-$(CONFIG_SLAB) += slab.o obj-$(CONFIG_SLUB) += slub.o obj-$(CONFIG_KASAN) += kasan/ +obj-$(CONFIG_KFENCE) += kfence/ obj-$(CONFIG_FAILSLAB) += failslab.o obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o obj-$(CONFIG_MEMTEST) += memtest.o diff --git a/mm/kfence/Makefile b/mm/kfence/Makefile new file mode 100644 index 000000000000..d991e9a349f0 --- /dev/null +++ b/mm/kfence/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_KFENCE) := core.o report.o diff --git a/mm/kfence/core.c b/mm/kfence/core.c new file mode 100644 index 000000000000..4972cc6217dd --- /dev/null +++ b/mm/kfence/core.c @@ -0,0 +1,822 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) "kfence: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kfence.h" + +/* + * Android 4.19 kernel does not support KCSAN, so we have to disable data race + * annotations. + */ +#ifndef data_race +#define data_race(x) (x) +#endif + +/* Disables KFENCE on the first warning assuming an irrecoverable error. */ +#define KFENCE_WARN_ON(cond) \ + ({ \ + const bool __cond = WARN_ON(cond); \ + if (unlikely(__cond)) \ + WRITE_ONCE(kfence_enabled, false); \ + __cond; \ + }) + +/* === Data ================================================================= */ + +static bool kfence_enabled __read_mostly; + +static unsigned long kfence_sample_interval __read_mostly = CONFIG_KFENCE_SAMPLE_INTERVAL; + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "kfence." + +static int param_set_sample_interval(const char *val, const struct kernel_param *kp) +{ + unsigned long num; + int ret = kstrtoul(val, 0, &num); + + if (ret < 0) + return ret; + + if (!num) /* Using 0 to indicate KFENCE is disabled. */ + WRITE_ONCE(kfence_enabled, false); + else if (!READ_ONCE(kfence_enabled) && system_state != SYSTEM_BOOTING) + return -EINVAL; /* Cannot (re-)enable KFENCE on-the-fly. */ + + *((unsigned long *)kp->arg) = num; + return 0; +} + +static int param_get_sample_interval(char *buffer, const struct kernel_param *kp) +{ + if (!READ_ONCE(kfence_enabled)) + return sprintf(buffer, "0\n"); + + return param_get_ulong(buffer, kp); +} + +static const struct kernel_param_ops sample_interval_param_ops = { + .set = param_set_sample_interval, + .get = param_get_sample_interval, +}; +module_param_cb(sample_interval, &sample_interval_param_ops, &kfence_sample_interval, 0600); + +/* The pool of pages used for guard pages and objects. */ +char *__kfence_pool __ro_after_init; +EXPORT_SYMBOL(__kfence_pool); /* Export for test modules. */ + +/* + * Per-object metadata, with one-to-one mapping of object metadata to + * backing pages (in __kfence_pool). + */ +static_assert(CONFIG_KFENCE_NUM_OBJECTS > 0); +struct kfence_metadata kfence_metadata[CONFIG_KFENCE_NUM_OBJECTS]; + +/* Freelist with available objects. */ +static struct list_head kfence_freelist = LIST_HEAD_INIT(kfence_freelist); +static DEFINE_RAW_SPINLOCK(kfence_freelist_lock); /* Lock protecting freelist. */ + +/* The static key to set up a KFENCE allocation. */ +DEFINE_STATIC_KEY_FALSE(kfence_allocation_key); + +/* Gates the allocation, ensuring only one succeeds in a given period. */ +static atomic_t allocation_gate = ATOMIC_INIT(1); + +/* Wait queue to wake up allocation-gate timer task. */ +static DECLARE_WAIT_QUEUE_HEAD(allocation_wait); + +/* Statistics counters for debugfs. */ +enum kfence_counter_id { + KFENCE_COUNTER_ALLOCATED, + KFENCE_COUNTER_ALLOCS, + KFENCE_COUNTER_FREES, + KFENCE_COUNTER_ZOMBIES, + KFENCE_COUNTER_BUGS, + KFENCE_COUNTER_COUNT, +}; +static atomic_long_t counters[KFENCE_COUNTER_COUNT]; +static const char *const counter_names[] = { + [KFENCE_COUNTER_ALLOCATED] = "currently allocated", + [KFENCE_COUNTER_ALLOCS] = "total allocations", + [KFENCE_COUNTER_FREES] = "total frees", + [KFENCE_COUNTER_ZOMBIES] = "zombie allocations", + [KFENCE_COUNTER_BUGS] = "total bugs", +}; +static_assert(ARRAY_SIZE(counter_names) == KFENCE_COUNTER_COUNT); + +/* === Internals ============================================================ */ + +static bool kfence_protect(unsigned long addr) +{ + return !KFENCE_WARN_ON(!kfence_protect_page(ALIGN_DOWN(addr, PAGE_SIZE), true)); +} + +static bool kfence_unprotect(unsigned long addr) +{ + return !KFENCE_WARN_ON(!kfence_protect_page(ALIGN_DOWN(addr, PAGE_SIZE), false)); +} + +static inline struct kfence_metadata *addr_to_metadata(unsigned long addr) +{ + long index; + + /* The checks do not affect performance; only called from slow-paths. */ + + if (!is_kfence_address((void *)addr)) + return NULL; + + /* + * May be an invalid index if called with an address at the edge of + * __kfence_pool, in which case we would report an "invalid access" + * error. + */ + index = (addr - (unsigned long)__kfence_pool) / (PAGE_SIZE * 2) - 1; + if (index < 0 || index >= CONFIG_KFENCE_NUM_OBJECTS) + return NULL; + + return &kfence_metadata[index]; +} + +static inline unsigned long metadata_to_pageaddr(const struct kfence_metadata *meta) +{ + unsigned long offset = (meta - kfence_metadata + 1) * PAGE_SIZE * 2; + unsigned long pageaddr = (unsigned long)&__kfence_pool[offset]; + + /* The checks do not affect performance; only called from slow-paths. */ + + /* Only call with a pointer into kfence_metadata. */ + if (KFENCE_WARN_ON(meta < kfence_metadata || + meta >= kfence_metadata + CONFIG_KFENCE_NUM_OBJECTS)) + return 0; + + /* + * This metadata object only ever maps to 1 page; verify that the stored + * address is in the expected range. + */ + if (KFENCE_WARN_ON(ALIGN_DOWN(meta->addr, PAGE_SIZE) != pageaddr)) + return 0; + + return pageaddr; +} + +/* + * Update the object's metadata state, including updating the alloc/free stacks + * depending on the state transition. + */ +static noinline void metadata_update_state(struct kfence_metadata *meta, + enum kfence_object_state next) +{ + struct kfence_track *track = + next == KFENCE_OBJECT_FREED ? &meta->free_track : &meta->alloc_track; + + lockdep_assert_held(&meta->lock); + + /* + * Skip over 1 (this) functions; noinline ensures we do not accidentally + * skip over the caller by never inlining. + */ + track->num_stack_entries = stack_trace_save(track->stack_entries, KFENCE_STACK_DEPTH, 1); + track->pid = task_pid_nr(current); + + /* + * Pairs with READ_ONCE() in + * kfence_shutdown_cache(), + * kfence_handle_page_fault(). + */ + WRITE_ONCE(meta->state, next); +} + +/* Write canary byte to @addr. */ +static inline bool set_canary_byte(u8 *addr) +{ + *addr = KFENCE_CANARY_PATTERN(addr); + return true; +} + +/* Check canary byte at @addr. */ +static inline bool check_canary_byte(u8 *addr) +{ + if (likely(*addr == KFENCE_CANARY_PATTERN(addr))) + return true; + + atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); + kfence_report_error((unsigned long)addr, addr_to_metadata((unsigned long)addr), + KFENCE_ERROR_CORRUPTION); + return false; +} + +/* __always_inline this to ensure we won't do an indirect call to fn. */ +static __always_inline void for_each_canary(const struct kfence_metadata *meta, bool (*fn)(u8 *)) +{ + const unsigned long pageaddr = ALIGN_DOWN(meta->addr, PAGE_SIZE); + unsigned long addr; + + lockdep_assert_held(&meta->lock); + + /* + * We'll iterate over each canary byte per-side until fn() returns + * false. However, we'll still iterate over the canary bytes to the + * right of the object even if there was an error in the canary bytes to + * the left of the object. Specifically, if check_canary_byte() + * generates an error, showing both sides might give more clues as to + * what the error is about when displaying which bytes were corrupted. + */ + + /* Apply to left of object. */ + for (addr = pageaddr; addr < meta->addr; addr++) { + if (!fn((u8 *)addr)) + break; + } + + /* Apply to right of object. */ + for (addr = meta->addr + meta->size; addr < pageaddr + PAGE_SIZE; addr++) { + if (!fn((u8 *)addr)) + break; + } +} + +static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t gfp) +{ + struct kfence_metadata *meta = NULL; + unsigned long flags; + struct page *page; + void *addr; + + /* Try to obtain a free object. */ + raw_spin_lock_irqsave(&kfence_freelist_lock, flags); + if (!list_empty(&kfence_freelist)) { + meta = list_entry(kfence_freelist.next, struct kfence_metadata, list); + list_del_init(&meta->list); + } + raw_spin_unlock_irqrestore(&kfence_freelist_lock, flags); + if (!meta) + return NULL; + + if (unlikely(!raw_spin_trylock_irqsave(&meta->lock, flags))) { + /* + * This is extremely unlikely -- we are reporting on a + * use-after-free, which locked meta->lock, and the reporting + * code via printk calls kmalloc() which ends up in + * kfence_alloc() and tries to grab the same object that we're + * reporting on. While it has never been observed, lockdep does + * report that there is a possibility of deadlock. Fix it by + * using trylock and bailing out gracefully. + */ + raw_spin_lock_irqsave(&kfence_freelist_lock, flags); + /* Put the object back on the freelist. */ + list_add_tail(&meta->list, &kfence_freelist); + raw_spin_unlock_irqrestore(&kfence_freelist_lock, flags); + + return NULL; + } + + meta->addr = metadata_to_pageaddr(meta); + /* Unprotect if we're reusing this page. */ + if (meta->state == KFENCE_OBJECT_FREED) + kfence_unprotect(meta->addr); + + /* + * Note: for allocations made before RNG initialization, will always + * return zero. We still benefit from enabling KFENCE as early as + * possible, even when the RNG is not yet available, as this will allow + * KFENCE to detect bugs due to earlier allocations. The only downside + * is that the out-of-bounds accesses detected are deterministic for + * such allocations. + */ + if (prandom_u32_max(2)) { + /* Allocate on the "right" side, re-calculate address. */ + meta->addr += PAGE_SIZE - size; + meta->addr = ALIGN_DOWN(meta->addr, cache->align); + } + + addr = (void *)meta->addr; + + /* Update remaining metadata. */ + metadata_update_state(meta, KFENCE_OBJECT_ALLOCATED); + /* Pairs with READ_ONCE() in kfence_shutdown_cache(). */ + WRITE_ONCE(meta->cache, cache); + meta->size = size; + for_each_canary(meta, set_canary_byte); + + /* Set required struct page fields. */ + page = virt_to_page(meta->addr); + page->slab_cache = cache; + + raw_spin_unlock_irqrestore(&meta->lock, flags); + + /* Memory initialization. */ + + /* + * We check slab_want_init_on_alloc() ourselves, rather than letting + * SL*B do the initialization, as otherwise we might overwrite KFENCE's + * redzone. + */ + if (unlikely(slab_want_init_on_alloc(gfp, cache))) + memzero_explicit(addr, size); + if (cache->ctor) + cache->ctor(addr); + + if (CONFIG_KFENCE_STRESS_TEST_FAULTS && !prandom_u32_max(CONFIG_KFENCE_STRESS_TEST_FAULTS)) + kfence_protect(meta->addr); /* Random "faults" by protecting the object. */ + + atomic_long_inc(&counters[KFENCE_COUNTER_ALLOCATED]); + atomic_long_inc(&counters[KFENCE_COUNTER_ALLOCS]); + + return addr; +} + +static void kfence_guarded_free(void *addr, struct kfence_metadata *meta, bool zombie) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&meta->lock, flags); + + if (meta->state != KFENCE_OBJECT_ALLOCATED || meta->addr != (unsigned long)addr) { + /* Invalid or double-free, bail out. */ + atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); + kfence_report_error((unsigned long)addr, meta, KFENCE_ERROR_INVALID_FREE); + raw_spin_unlock_irqrestore(&meta->lock, flags); + return; + } + + if (CONFIG_KFENCE_STRESS_TEST_FAULTS) + kfence_unprotect((unsigned long)addr); /* To check canary bytes. */ + + /* Restore page protection if there was an OOB access. */ + if (meta->unprotected_page) { + kfence_protect(meta->unprotected_page); + meta->unprotected_page = 0; + } + + /* Check canary bytes for memory corruption. */ + for_each_canary(meta, check_canary_byte); + + /* + * Clear memory if init-on-free is set. While we protect the page, the + * data is still there, and after a use-after-free is detected, we + * unprotect the page, so the data is still accessible. + */ + if (!zombie && unlikely(slab_want_init_on_free(meta->cache))) + memzero_explicit(addr, meta->size); + + /* Mark the object as freed. */ + metadata_update_state(meta, KFENCE_OBJECT_FREED); + + raw_spin_unlock_irqrestore(&meta->lock, flags); + + /* Protect to detect use-after-frees. */ + kfence_protect((unsigned long)addr); + + if (!zombie) { + /* Add it to the tail of the freelist for reuse. */ + raw_spin_lock_irqsave(&kfence_freelist_lock, flags); + KFENCE_WARN_ON(!list_empty(&meta->list)); + list_add_tail(&meta->list, &kfence_freelist); + raw_spin_unlock_irqrestore(&kfence_freelist_lock, flags); + + atomic_long_dec(&counters[KFENCE_COUNTER_ALLOCATED]); + atomic_long_inc(&counters[KFENCE_COUNTER_FREES]); + } else { + /* See kfence_shutdown_cache(). */ + atomic_long_inc(&counters[KFENCE_COUNTER_ZOMBIES]); + } +} + +static void rcu_guarded_free(struct rcu_head *h) +{ + struct kfence_metadata *meta = container_of(h, struct kfence_metadata, rcu_head); + + kfence_guarded_free((void *)meta->addr, meta, false); +} + +static bool __init kfence_init_pool(void) +{ + unsigned long addr = (unsigned long)__kfence_pool; + struct page *pages; + int i; + + if (!__kfence_pool) + return false; + + if (!arch_kfence_init_pool()) + goto err; + + pages = virt_to_page(addr); + + /* + * Set up object pages: they must have PG_slab set, to avoid freeing + * these as real pages. + * + * We also want to avoid inserting kfence_free() in the kfree() + * fast-path in SLUB, and therefore need to ensure kfree() correctly + * enters __slab_free() slow-path. + */ + for (i = 0; i < KFENCE_POOL_SIZE / PAGE_SIZE; i++) { + if (!i || (i % 2)) + continue; + + /* Verify we do not have a compound head page. */ + if (WARN_ON(compound_head(&pages[i]) != &pages[i])) + goto err; + + __SetPageSlab(&pages[i]); + } + + /* + * Protect the first 2 pages. The first page is mostly unnecessary, and + * merely serves as an extended guard page. However, adding one + * additional page in the beginning gives us an even number of pages, + * which simplifies the mapping of address to metadata index. + */ + for (i = 0; i < 2; i++) { + if (unlikely(!kfence_protect(addr))) + goto err; + + addr += PAGE_SIZE; + } + + for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) { + struct kfence_metadata *meta = &kfence_metadata[i]; + + /* Initialize metadata. */ + INIT_LIST_HEAD(&meta->list); + raw_spin_lock_init(&meta->lock); + meta->state = KFENCE_OBJECT_UNUSED; + meta->addr = addr; /* Initialize for validation in metadata_to_pageaddr(). */ + list_add_tail(&meta->list, &kfence_freelist); + + /* Protect the right redzone. */ + if (unlikely(!kfence_protect(addr + PAGE_SIZE))) + goto err; + + addr += 2 * PAGE_SIZE; + } + + return true; + +err: + /* + * Only release unprotected pages, and do not try to go back and change + * page attributes due to risk of failing to do so as well. If changing + * page attributes for some pages fails, it is very likely that it also + * fails for the first page, and therefore expect addr==__kfence_pool in + * most failure cases. + */ + memblock_free_late(__pa(addr), KFENCE_POOL_SIZE - (addr - (unsigned long)__kfence_pool)); + __kfence_pool = NULL; + return false; +} + +/* === DebugFS Interface ==================================================== */ + +static int stats_show(struct seq_file *seq, void *v) +{ + int i; + + seq_printf(seq, "enabled: %i\n", READ_ONCE(kfence_enabled)); + for (i = 0; i < KFENCE_COUNTER_COUNT; i++) + seq_printf(seq, "%s: %ld\n", counter_names[i], atomic_long_read(&counters[i])); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(stats); + +/* + * debugfs seq_file operations for /sys/kernel/debug/kfence/objects. + * start_object() and next_object() return the object index + 1, because NULL is used + * to stop iteration. + */ +static void *start_object(struct seq_file *seq, loff_t *pos) +{ + if (*pos < CONFIG_KFENCE_NUM_OBJECTS) + return (void *)((long)*pos + 1); + return NULL; +} + +static void stop_object(struct seq_file *seq, void *v) +{ +} + +static void *next_object(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + if (*pos < CONFIG_KFENCE_NUM_OBJECTS) + return (void *)((long)*pos + 1); + return NULL; +} + +static int show_object(struct seq_file *seq, void *v) +{ + struct kfence_metadata *meta = &kfence_metadata[(long)v - 1]; + unsigned long flags; + + raw_spin_lock_irqsave(&meta->lock, flags); + kfence_print_object(seq, meta); + raw_spin_unlock_irqrestore(&meta->lock, flags); + seq_puts(seq, "---------------------------------\n"); + + return 0; +} + +static const struct seq_operations object_seqops = { + .start = start_object, + .next = next_object, + .stop = stop_object, + .show = show_object, +}; + +static int open_objects(struct inode *inode, struct file *file) +{ + return seq_open(file, &object_seqops); +} + +static const struct file_operations objects_fops = { + .open = open_objects, + .read = seq_read, + .llseek = seq_lseek, +}; + +static int __init kfence_debugfs_init(void) +{ + struct dentry *kfence_dir = debugfs_create_dir("kfence", NULL); + + debugfs_create_file("stats", 0444, kfence_dir, NULL, &stats_fops); + debugfs_create_file("objects", 0400, kfence_dir, NULL, &objects_fops); + return 0; +} + +late_initcall(kfence_debugfs_init); + +/* === Allocation Gate Timer ================================================ */ + +/* + * Set up delayed work, which will enable and disable the static key. We need to + * use a work queue (rather than a simple timer), since enabling and disabling a + * static key cannot be done from an interrupt. + * + * Note: Toggling a static branch currently causes IPIs, and here we'll end up + * with a total of 2 IPIs to all CPUs. If this ends up a problem in future (with + * more aggressive sampling intervals), we could get away with a variant that + * avoids IPIs, at the cost of not immediately capturing allocations if the + * instructions remain cached. + */ +static struct delayed_work kfence_timer; +static void toggle_allocation_gate(struct work_struct *work) +{ + if (!READ_ONCE(kfence_enabled)) + return; + + /* Enable static key, and await allocation to happen. */ + atomic_set(&allocation_gate, 0); + static_branch_enable(&kfence_allocation_key); + wait_event(allocation_wait, atomic_read(&allocation_gate) != 0); + + /* Disable static key and reset timer. */ + static_branch_disable(&kfence_allocation_key); + schedule_delayed_work(&kfence_timer, msecs_to_jiffies(kfence_sample_interval)); +} +static DECLARE_DELAYED_WORK(kfence_timer, toggle_allocation_gate); + +/* === Public interface ===================================================== */ + +void __init kfence_alloc_pool(void) +{ + if (!kfence_sample_interval) + return; + + __kfence_pool = memblock_alloc(KFENCE_POOL_SIZE, PAGE_SIZE); + + if (!__kfence_pool) + pr_err("failed to allocate pool\n"); +} + +void __init kfence_init(void) +{ + /* Setting kfence_sample_interval to 0 on boot disables KFENCE. */ + if (!kfence_sample_interval) + return; + + if (!kfence_init_pool()) { + pr_err("%s failed\n", __func__); + return; + } + + WRITE_ONCE(kfence_enabled, true); + schedule_delayed_work(&kfence_timer, 0); + pr_info("initialized - using %lu bytes for %d objects", KFENCE_POOL_SIZE, + CONFIG_KFENCE_NUM_OBJECTS); + if (IS_ENABLED(CONFIG_DEBUG_KERNEL)) + pr_cont(" at 0x%px-0x%px\n", (void *)__kfence_pool, + (void *)(__kfence_pool + KFENCE_POOL_SIZE)); + else + pr_cont("\n"); +} + +void kfence_shutdown_cache(struct kmem_cache *s) +{ + unsigned long flags; + struct kfence_metadata *meta; + int i; + + for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) { + bool in_use; + + meta = &kfence_metadata[i]; + + /* + * If we observe some inconsistent cache and state pair where we + * should have returned false here, cache destruction is racing + * with either kmem_cache_alloc() or kmem_cache_free(). Taking + * the lock will not help, as different critical section + * serialization will have the same outcome. + */ + if (READ_ONCE(meta->cache) != s || + READ_ONCE(meta->state) != KFENCE_OBJECT_ALLOCATED) + continue; + + raw_spin_lock_irqsave(&meta->lock, flags); + in_use = meta->cache == s && meta->state == KFENCE_OBJECT_ALLOCATED; + raw_spin_unlock_irqrestore(&meta->lock, flags); + + if (in_use) { + /* + * This cache still has allocations, and we should not + * release them back into the freelist so they can still + * safely be used and retain the kernel's default + * behaviour of keeping the allocations alive (leak the + * cache); however, they effectively become "zombie + * allocations" as the KFENCE objects are the only ones + * still in use and the owning cache is being destroyed. + * + * We mark them freed, so that any subsequent use shows + * more useful error messages that will include stack + * traces of the user of the object, the original + * allocation, and caller to shutdown_cache(). + */ + kfence_guarded_free((void *)meta->addr, meta, /*zombie=*/true); + } + } + + for (i = 0; i < CONFIG_KFENCE_NUM_OBJECTS; i++) { + meta = &kfence_metadata[i]; + + /* See above. */ + if (READ_ONCE(meta->cache) != s || READ_ONCE(meta->state) != KFENCE_OBJECT_FREED) + continue; + + raw_spin_lock_irqsave(&meta->lock, flags); + if (meta->cache == s && meta->state == KFENCE_OBJECT_FREED) + meta->cache = NULL; + raw_spin_unlock_irqrestore(&meta->lock, flags); + } +} + +void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) +{ + /* + * allocation_gate only needs to become non-zero, so it doesn't make + * sense to continue writing to it and pay the associated contention + * cost, in case we have a large number of concurrent allocations. + */ + if (atomic_read(&allocation_gate) || atomic_inc_return(&allocation_gate) > 1) + return NULL; + wake_up(&allocation_wait); + + if (!READ_ONCE(kfence_enabled)) + return NULL; + + if (size > PAGE_SIZE) + return NULL; + + return kfence_guarded_alloc(s, size, flags); +} + +size_t kfence_ksize(const void *addr) +{ + const struct kfence_metadata *meta = addr_to_metadata((unsigned long)addr); + + /* + * Read locklessly -- if there is a race with __kfence_alloc(), this is + * either a use-after-free or invalid access. + */ + return meta ? meta->size : 0; +} + +void *kfence_object_start(const void *addr) +{ + const struct kfence_metadata *meta = addr_to_metadata((unsigned long)addr); + + /* + * Read locklessly -- if there is a race with __kfence_alloc(), this is + * either a use-after-free or invalid access. + */ + return meta ? (void *)meta->addr : NULL; +} + +void __kfence_free(void *addr) +{ + struct kfence_metadata *meta = addr_to_metadata((unsigned long)addr); + + /* + * If the objects of the cache are SLAB_TYPESAFE_BY_RCU, defer freeing + * the object, as the object page may be recycled for other-typed + * objects once it has been freed. meta->cache may be NULL if the cache + * was destroyed. + */ + if (unlikely(meta->cache && (meta->cache->flags & SLAB_TYPESAFE_BY_RCU))) + call_rcu(&meta->rcu_head, rcu_guarded_free); + else + kfence_guarded_free(addr, meta, false); +} + +bool kfence_handle_page_fault(unsigned long addr) +{ + const int page_index = (addr - (unsigned long)__kfence_pool) / PAGE_SIZE; + struct kfence_metadata *to_report = NULL; + enum kfence_error_type error_type; + unsigned long flags; + + if (!is_kfence_address((void *)addr)) + return false; + + if (!READ_ONCE(kfence_enabled)) /* If disabled at runtime ... */ + return kfence_unprotect(addr); /* ... unprotect and proceed. */ + + atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); + + if (page_index % 2) { + /* This is a redzone, report a buffer overflow. */ + struct kfence_metadata *meta; + int distance = 0; + + meta = addr_to_metadata(addr - PAGE_SIZE); + if (meta && READ_ONCE(meta->state) == KFENCE_OBJECT_ALLOCATED) { + to_report = meta; + /* Data race ok; distance calculation approximate. */ + distance = addr - data_race(meta->addr + meta->size); + } + + meta = addr_to_metadata(addr + PAGE_SIZE); + if (meta && READ_ONCE(meta->state) == KFENCE_OBJECT_ALLOCATED) { + /* Data race ok; distance calculation approximate. */ + if (!to_report || distance > data_race(meta->addr) - addr) + to_report = meta; + } + + if (!to_report) + goto out; + + raw_spin_lock_irqsave(&to_report->lock, flags); + to_report->unprotected_page = addr; + error_type = KFENCE_ERROR_OOB; + + /* + * If the object was freed before we took the look we can still + * report this as an OOB -- the report will simply show the + * stacktrace of the free as well. + */ + } else { + to_report = addr_to_metadata(addr); + if (!to_report) + goto out; + + raw_spin_lock_irqsave(&to_report->lock, flags); + error_type = KFENCE_ERROR_UAF; + /* + * We may race with __kfence_alloc(), and it is possible that a + * freed object may be reallocated. We simply report this as a + * use-after-free, with the stack trace showing the place where + * the object was re-allocated. + */ + } + +out: + if (to_report) { + kfence_report_error(addr, to_report, error_type); + raw_spin_unlock_irqrestore(&to_report->lock, flags); + } else { + /* This may be a UAF or OOB access, but we can't be sure. */ + kfence_report_error(addr, NULL, KFENCE_ERROR_INVALID); + } + + return kfence_unprotect(addr); /* Unprotect and let access proceed. */ +} diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h new file mode 100644 index 000000000000..f115aabc2052 --- /dev/null +++ b/mm/kfence/kfence.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef MM_KFENCE_KFENCE_H +#define MM_KFENCE_KFENCE_H + +#include +#include +#include +#include + +#include "../slab.h" /* for struct kmem_cache */ + +/* For non-debug builds, avoid leaking kernel pointers into dmesg. */ +#ifdef CONFIG_DEBUG_KERNEL +#define PTR_FMT "%px" +#else +#define PTR_FMT "%p" +#endif + +/* + * Get the canary byte pattern for @addr. Use a pattern that varies based on the + * lower 3 bits of the address, to detect memory corruptions with higher + * probability, where similar constants are used. + */ +#define KFENCE_CANARY_PATTERN(addr) ((u8)0xaa ^ (u8)((unsigned long)(addr) & 0x7)) + +/* Maximum stack depth for reports. */ +#define KFENCE_STACK_DEPTH 64 + +/* KFENCE object states. */ +enum kfence_object_state { + KFENCE_OBJECT_UNUSED, /* Object is unused. */ + KFENCE_OBJECT_ALLOCATED, /* Object is currently allocated. */ + KFENCE_OBJECT_FREED, /* Object was allocated, and then freed. */ +}; + +/* Alloc/free tracking information. */ +struct kfence_track { + pid_t pid; + int num_stack_entries; + unsigned long stack_entries[KFENCE_STACK_DEPTH]; +}; + +/* KFENCE metadata per guarded allocation. */ +struct kfence_metadata { + struct list_head list; /* Freelist node; access under kfence_freelist_lock. */ + struct rcu_head rcu_head; /* For delayed freeing. */ + + /* + * Lock protecting below data; to ensure consistency of the below data, + * since the following may execute concurrently: __kfence_alloc(), + * __kfence_free(), kfence_handle_page_fault(). However, note that we + * cannot grab the same metadata off the freelist twice, and multiple + * __kfence_alloc() cannot run concurrently on the same metadata. + */ + raw_spinlock_t lock; + + /* The current state of the object; see above. */ + enum kfence_object_state state; + + /* + * Allocated object address; cannot be calculated from size, because of + * alignment requirements. + * + * Invariant: ALIGN_DOWN(addr, PAGE_SIZE) is constant. + */ + unsigned long addr; + + /* + * The size of the original allocation. + */ + size_t size; + + /* + * The kmem_cache cache of the last allocation; NULL if never allocated + * or the cache has already been destroyed. + */ + struct kmem_cache *cache; + + /* + * In case of an invalid access, the page that was unprotected; we + * optimistically only store one address. + */ + unsigned long unprotected_page; + + /* Allocation and free stack information. */ + struct kfence_track alloc_track; + struct kfence_track free_track; +}; + +extern struct kfence_metadata kfence_metadata[CONFIG_KFENCE_NUM_OBJECTS]; + +/* KFENCE error types for report generation. */ +enum kfence_error_type { + KFENCE_ERROR_OOB, /* Detected a out-of-bounds access. */ + KFENCE_ERROR_UAF, /* Detected a use-after-free access. */ + KFENCE_ERROR_CORRUPTION, /* Detected a memory corruption on free. */ + KFENCE_ERROR_INVALID, /* Invalid access of unknown type. */ + KFENCE_ERROR_INVALID_FREE, /* Invalid free. */ +}; + +void kfence_report_error(unsigned long address, const struct kfence_metadata *meta, + enum kfence_error_type type); + +void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *meta); + +#endif /* MM_KFENCE_KFENCE_H */ diff --git a/mm/kfence/report.c b/mm/kfence/report.c new file mode 100644 index 000000000000..0fdaa3ddf1b4 --- /dev/null +++ b/mm/kfence/report.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "kfence.h" + +/* Helper function to either print to a seq_file or to console. */ +__printf(2, 3) +static void seq_con_printf(struct seq_file *seq, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (seq) + seq_vprintf(seq, fmt, args); + else + vprintk(fmt, args); + va_end(args); +} + +/* + * Get the number of stack entries to skip to get out of MM internals. @type is + * optional, and if set to NULL, assumes an allocation or free stack. + */ +static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries, + const enum kfence_error_type *type) +{ + char buf[64]; + int skipnr, fallback = 0; + bool is_access_fault = false; + + if (type) { + /* Depending on error type, find different stack entries. */ + switch (*type) { + case KFENCE_ERROR_UAF: + case KFENCE_ERROR_OOB: + case KFENCE_ERROR_INVALID: + is_access_fault = true; + break; + case KFENCE_ERROR_CORRUPTION: + case KFENCE_ERROR_INVALID_FREE: + break; + } + } + + for (skipnr = 0; skipnr < num_entries; skipnr++) { + int len = scnprintf(buf, sizeof(buf), "%ps", (void *)stack_entries[skipnr]); + + if (is_access_fault) { + if (!strncmp(buf, KFENCE_SKIP_ARCH_FAULT_HANDLER, len)) + goto found; + } else { + if (str_has_prefix(buf, "kfence_") || str_has_prefix(buf, "__kfence_") || + !strncmp(buf, "__slab_free", len)) { + /* + * In case of tail calls from any of the below + * to any of the above. + */ + fallback = skipnr + 1; + } + + /* Also the *_bulk() variants by only checking prefixes. */ + if (str_has_prefix(buf, "kfree") || + str_has_prefix(buf, "kmem_cache_free") || + str_has_prefix(buf, "__kmalloc") || + str_has_prefix(buf, "kmem_cache_alloc")) + goto found; + } + } + if (fallback < num_entries) + return fallback; +found: + skipnr++; + return skipnr < num_entries ? skipnr : 0; +} + +static void kfence_print_stack(struct seq_file *seq, const struct kfence_metadata *meta, + bool show_alloc) +{ + const struct kfence_track *track = show_alloc ? &meta->alloc_track : &meta->free_track; + + if (track->num_stack_entries) { + /* Skip allocation/free internals stack. */ + int i = get_stack_skipnr(track->stack_entries, track->num_stack_entries, NULL); + + /* stack_trace_seq_print() does not exist; open code our own. */ + for (; i < track->num_stack_entries; i++) + seq_con_printf(seq, " %pS\n", (void *)track->stack_entries[i]); + } else { + seq_con_printf(seq, " no %s stack\n", show_alloc ? "allocation" : "deallocation"); + } +} + +void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *meta) +{ + const int size = abs(meta->size); + const unsigned long start = meta->addr; + const struct kmem_cache *const cache = meta->cache; + + lockdep_assert_held(&meta->lock); + + if (meta->state == KFENCE_OBJECT_UNUSED) { + seq_con_printf(seq, "kfence-#%zd unused\n", meta - kfence_metadata); + return; + } + + seq_con_printf(seq, + "kfence-#%zd [0x" PTR_FMT "-0x" PTR_FMT + ", size=%d, cache=%s] allocated by task %d:\n", + meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size, + (cache && cache->name) ? cache->name : "", meta->alloc_track.pid); + kfence_print_stack(seq, meta, true); + + if (meta->state == KFENCE_OBJECT_FREED) { + seq_con_printf(seq, "\nfreed by task %d:\n", meta->free_track.pid); + kfence_print_stack(seq, meta, false); + } +} + +/* + * Show bytes at @addr that are different from the expected canary values, up to + * @max_bytes. + */ +static void print_diff_canary(unsigned long address, size_t bytes_to_show, + const struct kfence_metadata *meta) +{ + const unsigned long show_until_addr = address + bytes_to_show; + const u8 *cur, *end; + + /* Do not show contents of object nor read into following guard page. */ + end = (const u8 *)(address < meta->addr ? min(show_until_addr, meta->addr) + : min(show_until_addr, PAGE_ALIGN(address))); + + pr_cont("["); + for (cur = (const u8 *)address; cur < end; cur++) { + if (*cur == KFENCE_CANARY_PATTERN(cur)) + pr_cont(" ."); + else if (IS_ENABLED(CONFIG_DEBUG_KERNEL)) + pr_cont(" 0x%02x", *cur); + else /* Do not leak kernel memory in non-debug builds. */ + pr_cont(" !"); + } + pr_cont(" ]"); +} + +void kfence_report_error(unsigned long address, const struct kfence_metadata *meta, + enum kfence_error_type type) +{ + unsigned long stack_entries[KFENCE_STACK_DEPTH] = { 0 }; + int num_stack_entries = stack_trace_save(stack_entries, KFENCE_STACK_DEPTH, 1); + int skipnr = get_stack_skipnr(stack_entries, num_stack_entries, &type); + const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1; + + /* Require non-NULL meta, except if KFENCE_ERROR_INVALID. */ + if (WARN_ON(type != KFENCE_ERROR_INVALID && !meta)) + return; + + if (meta) + lockdep_assert_held(&meta->lock); + /* + * Because we may generate reports in printk-unfriendly parts of the + * kernel, such as scheduler code, the use of printk() could deadlock. + * Until such time that all printing code here is safe in all parts of + * the kernel, accept the risk, and just get our message out (given the + * system might already behave unpredictably due to the memory error). + * As such, also disable lockdep to hide warnings, and avoid disabling + * lockdep for the rest of the kernel. + */ + lockdep_off(); + + pr_err("==================================================================\n"); + /* Print report header. */ + switch (type) { + case KFENCE_ERROR_OOB: { + const bool left_of_object = address < meta->addr; + + pr_err("BUG: KFENCE: out-of-bounds in %pS\n\n", (void *)stack_entries[skipnr]); + pr_err("Out-of-bounds access at 0x" PTR_FMT " (%luB %s of kfence-#%zd):\n", + (void *)address, + left_of_object ? meta->addr - address : address - meta->addr, + left_of_object ? "left" : "right", object_index); + break; + } + case KFENCE_ERROR_UAF: + pr_err("BUG: KFENCE: use-after-free in %pS\n\n", (void *)stack_entries[skipnr]); + pr_err("Use-after-free access at 0x" PTR_FMT " (in kfence-#%zd):\n", + (void *)address, object_index); + break; + case KFENCE_ERROR_CORRUPTION: + pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]); + pr_err("Corrupted memory at 0x" PTR_FMT " ", (void *)address); + print_diff_canary(address, 16, meta); + pr_cont(" (in kfence-#%zd):\n", object_index); + break; + case KFENCE_ERROR_INVALID: + pr_err("BUG: KFENCE: invalid access in %pS\n\n", (void *)stack_entries[skipnr]); + pr_err("Invalid access at 0x" PTR_FMT ":\n", (void *)address); + break; + case KFENCE_ERROR_INVALID_FREE: + pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]); + pr_err("Invalid free of 0x" PTR_FMT " (in kfence-#%zd):\n", (void *)address, + object_index); + break; + } + + /* Print stack trace and object info. */ + stack_trace_print(stack_entries + skipnr, num_stack_entries - skipnr, 0); + + if (meta) { + pr_err("\n"); + kfence_print_object(NULL, meta); + } + + /* Print report footer. */ + pr_err("\n"); + dump_stack_print_info(KERN_ERR); + pr_err("==================================================================\n"); + + lockdep_on(); + + if (panic_on_warn) + panic("panic_on_warn set ...\n"); + + /* We encountered a memory unsafety error, taint the kernel! */ + add_taint(TAINT_BAD_PAGE, LOCKDEP_STILL_OK); +} From ed710264470e78af0b8bb7a28abb4c4ce1087866 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:32 +0000 Subject: [PATCH 259/306] FROMGIT: kfence: Fix parameter description for kfence_object_start() Describe parameter @addr correctly by delimiting with ':'. Link: https://lkml.kernel.org/r/20201106092149.GA2851373@elver.google.com Signed-off-by: Marco Elver Reviewed-by: Alexander Potapenko Reported-by: Stephen Rothwell Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 65f5b471bfd099a54862e14a895724e982a381c9 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Ieb71f57f82351eaaabd3c63cd52e97fbfbfca2f1 --- include/linux/kfence.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/kfence.h b/include/linux/kfence.h index ed2d48acdafe..e1f984697d06 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -125,7 +125,7 @@ size_t kfence_ksize(const void *addr); /** * kfence_object_start() - find the beginning of a KFENCE object - * @addr - address within a KFENCE-allocated object + * @addr: address within a KFENCE-allocated object * * Return: address of the beginning of the object. * From c28a20991103490ca4f6e2192c0274e591aa803a Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:32 +0000 Subject: [PATCH 260/306] FROMGIT: kfence: avoid stalling work queue task without allocations To toggle the allocation gates, we set up a delayed work that calls toggle_allocation_gate(). Here we use wait_event() to await an allocation and subsequently disable the static branch again. However, if the kernel has stopped doing allocations entirely, we'd wait indefinitely, and stall the worker task. This may also result in the appropriate warnings if CONFIG_DETECT_HUNG_TASK=y. Therefore, introduce a 1 second timeout and use wait_event_timeout(). If the timeout is reached, the static branch is disabled and a new delayed work is scheduled to try setting up an allocation at a later time. Note that, this scenario is very unlikely during normal workloads once the kernel has booted and user space tasks are running. It can, however, happen during early boot after KFENCE has been enabled, when e.g. running tests that do not result in any allocations. Link: https://lkml.kernel.org/r/CADYN=9J0DQhizAGB0-jz4HOBBh+05kMBXb4c0cXMS7Qi5NAJiw@mail.gmail.com Link: https://lkml.kernel.org/r/20201110135320.3309507-1-elver@google.com Signed-off-by: Marco Elver Reported-by: Anders Roxell Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: SeongJae Park Cc: Jann Horn Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 80d4693491f6f20de01437319b081fdda2079e67 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I2332ff8144b8bce5c4574b01ea2863e0e71e6124 --- mm/kfence/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 4972cc6217dd..1624b7ee6868 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -588,7 +588,11 @@ static void toggle_allocation_gate(struct work_struct *work) /* Enable static key, and await allocation to happen. */ atomic_set(&allocation_gate, 0); static_branch_enable(&kfence_allocation_key); - wait_event(allocation_wait, atomic_read(&allocation_gate) != 0); + /* + * Await an allocation. Timeout after 1 second, in case the kernel stops + * doing allocations, to avoid stalling this worker task for too long. + */ + wait_event_timeout(allocation_wait, atomic_read(&allocation_gate) != 0, HZ); /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); From fa80023f3c90145869a7cbc1c948657bfd36df74 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:33 +0000 Subject: [PATCH 261/306] FROMGIT: kfence: fix potential deadlock due to wake_up() Lockdep reports that we may deadlock when calling wake_up() in __kfence_alloc(), because we may already hold base->lock. This can happen if debug objects are enabled: ... __kfence_alloc+0xa0/0xbc0 mm/kfence/core.c:710 kfence_alloc include/linux/kfence.h:108 [inline] ... kmem_cache_zalloc include/linux/slab.h:672 [inline] fill_pool+0x264/0x5c0 lib/debugobjects.c:171 __debug_object_init+0x7a/0xd10 lib/debugobjects.c:560 debug_object_init lib/debugobjects.c:615 [inline] debug_object_activate+0x32c/0x3e0 lib/debugobjects.c:701 debug_timer_activate kernel/time/timer.c:727 [inline] __mod_timer+0x77d/0xe30 kernel/time/timer.c:1048 ... Therefore, switch to an open-coded wait loop. The difference to before is that the waiter wakes up and rechecks the condition after 1 jiffy; however, given the infrequency of kfence allocations, the difference is insignificant. Link: https://lkml.kernel.org/r/000000000000c0645805b7f982e4@google.com Link: https://lkml.kernel.org/r/20210104130749.1768991-1-elver@google.com Reported-by: syzbot+8983d6d4f7df556be565@syzkaller.appspotmail.com Signed-off-by: Marco Elver Suggested-by: Hillf Danton Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Jann Horn Cc: Mark Rutland Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit c5fb1ab1a3c6d0ee02d1054a10d51ffcac57aed5 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Iee40e9f216afbc3fce8e43c0e2a4bc807fdddf39 --- mm/kfence/core.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 1624b7ee6868..edfb0a76f14b 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -101,9 +101,6 @@ DEFINE_STATIC_KEY_FALSE(kfence_allocation_key); /* Gates the allocation, ensuring only one succeeds in a given period. */ static atomic_t allocation_gate = ATOMIC_INIT(1); -/* Wait queue to wake up allocation-gate timer task. */ -static DECLARE_WAIT_QUEUE_HEAD(allocation_wait); - /* Statistics counters for debugfs. */ enum kfence_counter_id { KFENCE_COUNTER_ALLOCATED, @@ -582,6 +579,8 @@ late_initcall(kfence_debugfs_init); static struct delayed_work kfence_timer; static void toggle_allocation_gate(struct work_struct *work) { + unsigned long end_wait; + if (!READ_ONCE(kfence_enabled)) return; @@ -592,7 +591,14 @@ static void toggle_allocation_gate(struct work_struct *work) * Await an allocation. Timeout after 1 second, in case the kernel stops * doing allocations, to avoid stalling this worker task for too long. */ - wait_event_timeout(allocation_wait, atomic_read(&allocation_gate) != 0, HZ); + end_wait = jiffies + HZ; + do { + set_current_state(TASK_UNINTERRUPTIBLE); + if (atomic_read(&allocation_gate) != 0) + break; + schedule_timeout(1); + } while (time_before(jiffies, end_wait)); + __set_current_state(TASK_RUNNING); /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); @@ -703,7 +709,6 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) */ if (atomic_read(&allocation_gate) || atomic_inc_return(&allocation_gate) > 1) return NULL; - wake_up(&allocation_wait); if (!READ_ONCE(kfence_enabled)) return NULL; From 9339667c955d308956a68a2990650ea25a0fced4 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:33 +0000 Subject: [PATCH 262/306] FROMGIT: kfence: add option to use KFENCE without static keys MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For certain usecases, specifically where the sample interval is always set to a very low value such as 1ms, it can make sense to use a dynamic branch instead of static branches due to the overhead of toggling a static branch. Therefore, add a new Kconfig option to remove the static branches and instead check kfence_allocation_gate if a KFENCE allocation should be set up. Link: https://lkml.kernel.org/r/20210111091544.3287013-1-elver@google.com Signed-off-by: Marco Elver Suggested-by: Jörn Engel Reviewed-by: Jörn Engel Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Jann Horn Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit c01761611b325c1e4ec7d3e236cc9db003cb82fd https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I68a112a8ff68fa24742b198e036f130a9757c27f --- include/linux/kfence.h | 11 ++++++++++- lib/Kconfig.kfence | 12 +++++++++++- mm/kfence/core.c | 30 +++++++++++++++++------------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/linux/kfence.h b/include/linux/kfence.h index e1f984697d06..ed4affc4f6ac 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -4,7 +4,6 @@ #define _LINUX_KFENCE_H #include -#include #include #ifdef CONFIG_KFENCE @@ -17,7 +16,13 @@ #define KFENCE_POOL_SIZE ((CONFIG_KFENCE_NUM_OBJECTS + 1) * 2 * PAGE_SIZE) extern char *__kfence_pool; +#ifdef CONFIG_KFENCE_STATIC_KEYS +#include DECLARE_STATIC_KEY_FALSE(kfence_allocation_key); +#else +#include +extern atomic_t kfence_allocation_gate; +#endif /** * is_kfence_address() - check if an address belongs to KFENCE pool @@ -104,7 +109,11 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags); */ static __always_inline void *kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) { +#ifdef CONFIG_KFENCE_STATIC_KEYS if (static_branch_unlikely(&kfence_allocation_key)) +#else + if (unlikely(!atomic_read(&kfence_allocation_gate))) +#endif return __kfence_alloc(s, size, flags); return NULL; } diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence index b209cd02042b..b88ac9d6b2e6 100644 --- a/lib/Kconfig.kfence +++ b/lib/Kconfig.kfence @@ -6,7 +6,6 @@ config HAVE_ARCH_KFENCE menuconfig KFENCE bool "KFENCE: low-overhead sampling-based memory safety error detector" depends on HAVE_ARCH_KFENCE && !KASAN && (SLAB || SLUB) - depends on JUMP_LABEL # To ensure performance, require jump labels select STACKTRACE help KFENCE is a low-overhead sampling-based detector of heap out-of-bounds @@ -23,6 +22,17 @@ menuconfig KFENCE if KFENCE +config KFENCE_STATIC_KEYS + bool "Use static keys to set up allocations" + default y + depends on JUMP_LABEL # To ensure performance, require jump labels + help + Use static keys (static branches) to set up KFENCE allocations. Using + static keys is normally recommended, because it avoids a dynamic + branch in the allocator's fast path. However, with very low sample + intervals, or on systems that do not support jump labels, a dynamic + branch may still be an acceptable performance trade-off. + config KFENCE_SAMPLE_INTERVAL int "Default sample interval in milliseconds" default 100 diff --git a/mm/kfence/core.c b/mm/kfence/core.c index edfb0a76f14b..a3e1cbae464b 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -95,11 +95,13 @@ struct kfence_metadata kfence_metadata[CONFIG_KFENCE_NUM_OBJECTS]; static struct list_head kfence_freelist = LIST_HEAD_INIT(kfence_freelist); static DEFINE_RAW_SPINLOCK(kfence_freelist_lock); /* Lock protecting freelist. */ +#ifdef CONFIG_KFENCE_STATIC_KEYS /* The static key to set up a KFENCE allocation. */ DEFINE_STATIC_KEY_FALSE(kfence_allocation_key); +#endif /* Gates the allocation, ensuring only one succeeds in a given period. */ -static atomic_t allocation_gate = ATOMIC_INIT(1); +atomic_t kfence_allocation_gate = ATOMIC_INIT(1); /* Statistics counters for debugfs. */ enum kfence_counter_id { @@ -579,29 +581,31 @@ late_initcall(kfence_debugfs_init); static struct delayed_work kfence_timer; static void toggle_allocation_gate(struct work_struct *work) { - unsigned long end_wait; - if (!READ_ONCE(kfence_enabled)) return; /* Enable static key, and await allocation to happen. */ - atomic_set(&allocation_gate, 0); + atomic_set(&kfence_allocation_gate, 0); +#ifdef CONFIG_KFENCE_STATIC_KEYS static_branch_enable(&kfence_allocation_key); /* * Await an allocation. Timeout after 1 second, in case the kernel stops * doing allocations, to avoid stalling this worker task for too long. */ - end_wait = jiffies + HZ; - do { - set_current_state(TASK_UNINTERRUPTIBLE); - if (atomic_read(&allocation_gate) != 0) - break; - schedule_timeout(1); - } while (time_before(jiffies, end_wait)); - __set_current_state(TASK_RUNNING); + { + unsigned long end_wait = jiffies + HZ; + do { + set_current_state(TASK_UNINTERRUPTIBLE); + if (atomic_read(&kfence_allocation_gate) != 0) + break; + schedule_timeout(1); + } while (time_before(jiffies, end_wait)); + __set_current_state(TASK_RUNNING); + } /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); +#endif schedule_delayed_work(&kfence_timer, msecs_to_jiffies(kfence_sample_interval)); } static DECLARE_DELAYED_WORK(kfence_timer, toggle_allocation_gate); @@ -707,7 +711,7 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) * sense to continue writing to it and pay the associated contention * cost, in case we have a large number of concurrent allocations. */ - if (atomic_read(&allocation_gate) || atomic_inc_return(&allocation_gate) > 1) + if (atomic_read(&kfence_allocation_gate) || atomic_inc_return(&kfence_allocation_gate) > 1) return NULL; if (!READ_ONCE(kfence_enabled)) From 0c26e79c37586c3e5f37ff237985782dae054b57 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:34 +0000 Subject: [PATCH 263/306] FROMGIT: kfence: add missing copyright and description headers Add missing copyright and description headers to KFENCE source files. Link: https://lkml.kernel.org/r/20210118092159.145934-1-elver@google.com Signed-off-by: Marco Elver Reviewed-by: Alexander Potapenko Cc: Andrey Konovalov Cc: Dmitry Vyukov Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit b86d1ed1155ce1d2420057bfbdcc62b9fd53c1d6 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I95eb6756baaa0d8ca1dbc656708667372cff546d --- include/linux/kfence.h | 6 ++++++ mm/kfence/core.c | 5 +++++ mm/kfence/kfence.h | 6 ++++++ mm/kfence/report.c | 5 +++++ 4 files changed, 22 insertions(+) diff --git a/include/linux/kfence.h b/include/linux/kfence.h index ed4affc4f6ac..81f3911cb298 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -1,4 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Kernel Electric-Fence (KFENCE). Public interface for allocator and fault + * handler integration. For more info see Documentation/dev-tools/kfence.rst. + * + * Copyright (C) 2020, Google LLC. + */ #ifndef _LINUX_KFENCE_H #define _LINUX_KFENCE_H diff --git a/mm/kfence/core.c b/mm/kfence/core.c index a3e1cbae464b..9ff74bcf23f2 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -1,4 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * KFENCE guarded object allocator and fault handling. + * + * Copyright (C) 2020, Google LLC. + */ #define pr_fmt(fmt) "kfence: " fmt diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h index f115aabc2052..1014060f9707 100644 --- a/mm/kfence/kfence.h +++ b/mm/kfence/kfence.h @@ -1,4 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Kernel Electric-Fence (KFENCE). For more info please see + * Documentation/dev-tools/kfence.rst. + * + * Copyright (C) 2020, Google LLC. + */ #ifndef MM_KFENCE_KFENCE_H #define MM_KFENCE_KFENCE_H diff --git a/mm/kfence/report.c b/mm/kfence/report.c index 0fdaa3ddf1b4..64f27c8d46a3 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -1,4 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * KFENCE reporting. + * + * Copyright (C) 2020, Google LLC. + */ #include From 1a8ea8501d907dbc57116afd5edc7b509bb2b191 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:35 +0000 Subject: [PATCH 264/306] BACKPORT: x86, kfence: enable KFENCE for x86 Add architecture specific implementation details for KFENCE and enable KFENCE for the x86 architecture. In particular, this implements the required interface in for setting up the pool and providing helper functions for protecting and unprotecting pages. For x86, we need to ensure that the pool uses 4K pages, which is done using the set_memory_4k() helper function. Link: https://lkml.kernel.org/r/20201103175841.3495947-3-elver@google.com Signed-off-by: Marco Elver Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov Co-developed-by: Marco Elver Reviewed-by: Jann Horn Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Joern Engel Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Kees Cook Cc: Mark Rutland Cc: Paul E. McKenney Cc: Pekka Enberg Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit cb99fcd83140d0d58ea36db6c1c2034abc95f983 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: resolved a minor conflict in arch/x86/Kconfig, s/flush_tlb_one_kernel/__flush_tlb_one_kernel] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I111caffb0b88c34ed9ff57b95f127b08eacedcb9 --- arch/x86/Kconfig | 1 + arch/x86/include/asm/kfence.h | 65 +++++++++++++++++++++++++++++++++++ arch/x86/mm/fault.c | 5 +++ 3 files changed, 71 insertions(+) create mode 100644 arch/x86/include/asm/kfence.h diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6e1e5f49664e..8a42463ffee5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -139,6 +139,7 @@ config X86 select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if X86_64 + select HAVE_ARCH_KFENCE select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_MMAP_RND_COMPAT_BITS if MMU && COMPAT diff --git a/arch/x86/include/asm/kfence.h b/arch/x86/include/asm/kfence.h new file mode 100644 index 000000000000..737edb28061f --- /dev/null +++ b/arch/x86/include/asm/kfence.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_X86_KFENCE_H +#define _ASM_X86_KFENCE_H + +#include +#include + +#include +#include +#include +#include + +/* + * The page fault handler entry function, up to which the stack trace is + * truncated in reports. + */ +#define KFENCE_SKIP_ARCH_FAULT_HANDLER "asm_exc_page_fault" + +/* Force 4K pages for __kfence_pool. */ +static inline bool arch_kfence_init_pool(void) +{ + unsigned long addr; + + for (addr = (unsigned long)__kfence_pool; is_kfence_address((void *)addr); + addr += PAGE_SIZE) { + unsigned int level; + + if (!lookup_address(addr, &level)) + return false; + + if (level != PG_LEVEL_4K) + set_memory_4k(addr, 1); + } + + return true; +} + +/* Protect the given page and flush TLB. */ +static inline bool kfence_protect_page(unsigned long addr, bool protect) +{ + unsigned int level; + pte_t *pte = lookup_address(addr, &level); + + if (WARN_ON(!pte || level != PG_LEVEL_4K)) + return false; + + /* + * We need to avoid IPIs, as we may get KFENCE allocations or faults + * with interrupts disabled. Therefore, the below is best-effort, and + * does not flush TLBs on all CPUs. We can tolerate some inaccuracy; + * lazy fault handling takes care of faults after the page is PRESENT. + */ + + if (protect) + set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); + else + set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); + + /* Flush this CPU's TLB. */ + __flush_tlb_one_kernel(addr); + return true; +} + +#endif /* _ASM_X86_KFENCE_H */ diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 2fa5e0e5f8e5..3bb2e6175337 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -9,6 +9,7 @@ #include /* oops_begin/end, ... */ #include /* search_exception_tables */ #include /* max_low_pfn */ +#include /* kfence_handle_page_fault */ #include /* NOKPROBE_SYMBOL, ... */ #include /* kmmio_handler, ... */ #include /* perf_sw_event */ @@ -801,6 +802,10 @@ no_context(struct pt_regs *regs, unsigned long error_code, if (IS_ENABLED(CONFIG_EFI)) efi_recover_from_page_fault(address); + /* Only not-present faults should be handled by KFENCE. */ + if (!(error_code & X86_PF_PROT) && kfence_handle_page_fault(address)) + return; + oops: /* * Oops. The kernel tried to access some bad page. We'll have to From 097baa99241e04024d5a13f501d1192f56950ebe Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:35 +0000 Subject: [PATCH 265/306] FROMGIT: kfence, x86: add missing copyright and description header Add missing copyright and description header to KFENCE source file. Link: https://lkml.kernel.org/r/20210118092159.145934-2-elver@google.com Signed-off-by: Marco Elver Reviewed-by: Alexander Potapenko Cc: Andrey Konovalov Cc: Dmitry Vyukov Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 8470d53956b7e1b6f3f2dd17f277b9d2bb1472ae https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I90aef6f80e7b5a46f5168d1a24c02a5737785831 --- arch/x86/include/asm/kfence.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/include/asm/kfence.h b/arch/x86/include/asm/kfence.h index 737edb28061f..b3cf41f54604 100644 --- a/arch/x86/include/asm/kfence.h +++ b/arch/x86/include/asm/kfence.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * x86 KFENCE support. + * + * Copyright (C) 2020, Google LLC. + */ #ifndef _ASM_X86_KFENCE_H #define _ASM_X86_KFENCE_H From b5e331effb1bed303d31bce350271ff73035a9c1 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:37 +0000 Subject: [PATCH 266/306] BACKPORT: arm64, kfence: enable KFENCE for ARM64 Add architecture specific implementation details for KFENCE and enable KFENCE for the arm64 architecture. In particular, this implements the required interface in . KFENCE requires that attributes for pages from its memory pool can individually be set. Therefore, force the entire linear map to be mapped at page granularity. Doing so may result in extra memory allocated for page tables in case rodata=full is not set; however, currently CONFIG_RODATA_FULL_DEFAULT_ENABLED=y is the default, and the common case is therefore not affected by this change. Link: https://lkml.kernel.org/r/20201103175841.3495947-4-elver@google.com Signed-off-by: Alexander Potapenko Signed-off-by: Marco Elver Reviewed-by: Dmitry Vyukov Co-developed-by: Alexander Potapenko Reviewed-by: Jann Horn Reviewed-by: Mark Rutland Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Joern Engel Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Kees Cook Cc: Paul E. McKenney Cc: Pekka Enberg Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit d3cb0555da9b469c3f9ebe663d4c0d6265757175 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: resolved a minor conflict in arch/arm64/Kconfig] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Ibe9d26c2c9088862ba8855c18e0c5210a68c7f50 --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/kfence.h | 19 +++++++++++++++++++ arch/arm64/mm/fault.c | 4 ++++ arch/arm64/mm/mmu.c | 7 ++++++- 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/kfence.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 68c3f7f248f5..325b5dbe124a 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -129,6 +129,7 @@ config ARM64 select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_KASAN if !(ARM64_16K_PAGES && ARM64_VA_BITS_48) select HAVE_ARCH_KASAN_SW_TAGS if HAVE_ARCH_KASAN + select HAVE_ARCH_KFENCE select HAVE_ARCH_KGDB select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT diff --git a/arch/arm64/include/asm/kfence.h b/arch/arm64/include/asm/kfence.h new file mode 100644 index 000000000000..5ac0f599cc9a --- /dev/null +++ b/arch/arm64/include/asm/kfence.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_KFENCE_H +#define __ASM_KFENCE_H + +#include + +#define KFENCE_SKIP_ARCH_FAULT_HANDLER "el1_sync" + +static inline bool arch_kfence_init_pool(void) { return true; } + +static inline bool kfence_protect_page(unsigned long addr, bool protect) +{ + set_memory_valid(addr, 1, !protect); + + return true; +} + +#endif /* __ASM_KFENCE_H */ diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 8fcd1dbe1fb7..527980514d6a 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -327,6 +328,9 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, } else if (addr < PAGE_SIZE) { msg = "NULL pointer dereference"; } else { + if (kfence_handle_page_fault(addr)) + return; + msg = "paging request"; } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 9eaaa69fea9a..637348d57c87 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -1470,7 +1470,12 @@ int arch_add_memory(int nid, u64 start, u64 size, return -1; } - if (rodata_full || debug_pagealloc_enabled()) + /* + * KFENCE requires linear map to be mapped at page granularity, so that + * it is possible to protect/unprotect single pages in the KFENCE pool. + */ + if (rodata_full || debug_pagealloc_enabled() || + IS_ENABLED(CONFIG_KFENCE)) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start), From 3670dc7688d915d528d9afbea2555615ad21fa19 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:37 +0000 Subject: [PATCH 267/306] FROMGIT: kfence, arm64: add missing copyright and description header Add missing copyright and description header to KFENCE source file. Link: https://lkml.kernel.org/r/20210118092159.145934-3-elver@google.com Signed-off-by: Marco Elver Reviewed-by: Alexander Potapenko Cc: Andrey Konovalov Cc: Dmitry Vyukov Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit ce19707fadfe62b7441f2a9455b6866161fbc1f0 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I75c06e57e4bb906626c13318d00cfc7d47b76bde --- arch/arm64/include/asm/kfence.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/include/asm/kfence.h b/arch/arm64/include/asm/kfence.h index 5ac0f599cc9a..42a06f83850a 100644 --- a/arch/arm64/include/asm/kfence.h +++ b/arch/arm64/include/asm/kfence.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * arm64 KFENCE support. + * + * Copyright (C) 2020, Google LLC. + */ #ifndef __ASM_KFENCE_H #define __ASM_KFENCE_H From b5c9938cb470f6384f2c3377d78c984b64f5caac Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:38 +0000 Subject: [PATCH 268/306] FROMGIT: kfence: use pt_regs to generate stack trace on faults Instead of removing the fault handling portion of the stack trace based on the fault handler's name, just use struct pt_regs directly. Change kfence_handle_page_fault() to take a struct pt_regs, and plumb it through to kfence_report_error() for out-of-bounds, use-after-free, or invalid access errors, where pt_regs is used to generate the stack trace. If the kernel is a DEBUG_KERNEL, also show registers for more information. Link: https://lkml.kernel.org/r/20201105092133.2075331-1-elver@google.com Signed-off-by: Marco Elver Suggested-by: Mark Rutland Acked-by: Mark Rutland Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Alexander Potapenko Cc: Jann Horn Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 54a5abe9b5d542ee71836439cc662efe178c8211 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I3a60060b24f0efb4faee2e6c953973bc1263e8d1 --- arch/arm64/include/asm/kfence.h | 2 -- arch/arm64/mm/fault.c | 2 +- arch/x86/include/asm/kfence.h | 6 ---- arch/x86/mm/fault.c | 2 +- include/linux/kfence.h | 5 +-- mm/kfence/core.c | 10 +++--- mm/kfence/kfence.h | 4 +-- mm/kfence/report.c | 63 +++++++++++++++++++-------------- 8 files changed, 48 insertions(+), 46 deletions(-) diff --git a/arch/arm64/include/asm/kfence.h b/arch/arm64/include/asm/kfence.h index 42a06f83850a..d061176d57ea 100644 --- a/arch/arm64/include/asm/kfence.h +++ b/arch/arm64/include/asm/kfence.h @@ -10,8 +10,6 @@ #include -#define KFENCE_SKIP_ARCH_FAULT_HANDLER "el1_sync" - static inline bool arch_kfence_init_pool(void) { return true; } static inline bool kfence_protect_page(unsigned long addr, bool protect) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 527980514d6a..53cfe537da62 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -328,7 +328,7 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, } else if (addr < PAGE_SIZE) { msg = "NULL pointer dereference"; } else { - if (kfence_handle_page_fault(addr)) + if (kfence_handle_page_fault(addr, regs)) return; msg = "paging request"; diff --git a/arch/x86/include/asm/kfence.h b/arch/x86/include/asm/kfence.h index b3cf41f54604..2d66d70600bd 100644 --- a/arch/x86/include/asm/kfence.h +++ b/arch/x86/include/asm/kfence.h @@ -16,12 +16,6 @@ #include #include -/* - * The page fault handler entry function, up to which the stack trace is - * truncated in reports. - */ -#define KFENCE_SKIP_ARCH_FAULT_HANDLER "asm_exc_page_fault" - /* Force 4K pages for __kfence_pool. */ static inline bool arch_kfence_init_pool(void) { diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 3bb2e6175337..5c22cfa2b936 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -803,7 +803,7 @@ no_context(struct pt_regs *regs, unsigned long error_code, efi_recover_from_page_fault(address); /* Only not-present faults should be handled by KFENCE. */ - if (!(error_code & X86_PF_PROT) && kfence_handle_page_fault(address)) + if (!(error_code & X86_PF_PROT) && kfence_handle_page_fault(address, regs)) return; oops: diff --git a/include/linux/kfence.h b/include/linux/kfence.h index 81f3911cb298..5a56bcf5606c 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -186,6 +186,7 @@ static __always_inline __must_check bool kfence_free(void *addr) /** * kfence_handle_page_fault() - perform page fault handling for KFENCE pages * @addr: faulting address + * @regs: current struct pt_regs (can be NULL, but shows full stack trace) * * Return: * * false - address outside KFENCE pool, @@ -196,7 +197,7 @@ static __always_inline __must_check bool kfence_free(void *addr) * cases KFENCE prints an error message and marks the offending page as * present, so that the kernel can proceed. */ -bool __must_check kfence_handle_page_fault(unsigned long addr); +bool __must_check kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs); #else /* CONFIG_KFENCE */ @@ -209,7 +210,7 @@ static inline size_t kfence_ksize(const void *addr) { return 0; } static inline void *kfence_object_start(const void *addr) { return NULL; } static inline void __kfence_free(void *addr) { } static inline bool __must_check kfence_free(void *addr) { return false; } -static inline bool __must_check kfence_handle_page_fault(unsigned long addr) { return false; } +static inline bool __must_check kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs) { return false; } #endif diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 9ff74bcf23f2..515403bc269d 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -223,7 +223,7 @@ static inline bool check_canary_byte(u8 *addr) return true; atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); - kfence_report_error((unsigned long)addr, addr_to_metadata((unsigned long)addr), + kfence_report_error((unsigned long)addr, NULL, addr_to_metadata((unsigned long)addr), KFENCE_ERROR_CORRUPTION); return false; } @@ -357,7 +357,7 @@ static void kfence_guarded_free(void *addr, struct kfence_metadata *meta, bool z if (meta->state != KFENCE_OBJECT_ALLOCATED || meta->addr != (unsigned long)addr) { /* Invalid or double-free, bail out. */ atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); - kfence_report_error((unsigned long)addr, meta, KFENCE_ERROR_INVALID_FREE); + kfence_report_error((unsigned long)addr, NULL, meta, KFENCE_ERROR_INVALID_FREE); raw_spin_unlock_irqrestore(&meta->lock, flags); return; } @@ -766,7 +766,7 @@ void __kfence_free(void *addr) kfence_guarded_free(addr, meta, false); } -bool kfence_handle_page_fault(unsigned long addr) +bool kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs) { const int page_index = (addr - (unsigned long)__kfence_pool) / PAGE_SIZE; struct kfence_metadata *to_report = NULL; @@ -829,11 +829,11 @@ bool kfence_handle_page_fault(unsigned long addr) out: if (to_report) { - kfence_report_error(addr, to_report, error_type); + kfence_report_error(addr, regs, to_report, error_type); raw_spin_unlock_irqrestore(&to_report->lock, flags); } else { /* This may be a UAF or OOB access, but we can't be sure. */ - kfence_report_error(addr, NULL, KFENCE_ERROR_INVALID); + kfence_report_error(addr, regs, NULL, KFENCE_ERROR_INVALID); } return kfence_unprotect(addr); /* Unprotect and let access proceed. */ diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h index 1014060f9707..0d83e628a97d 100644 --- a/mm/kfence/kfence.h +++ b/mm/kfence/kfence.h @@ -105,8 +105,8 @@ enum kfence_error_type { KFENCE_ERROR_INVALID_FREE, /* Invalid free. */ }; -void kfence_report_error(unsigned long address, const struct kfence_metadata *meta, - enum kfence_error_type type); +void kfence_report_error(unsigned long address, struct pt_regs *regs, + const struct kfence_metadata *meta, enum kfence_error_type type); void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *meta); diff --git a/mm/kfence/report.c b/mm/kfence/report.c index 64f27c8d46a3..4dbfa9a382e4 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries { char buf[64]; int skipnr, fallback = 0; - bool is_access_fault = false; if (type) { /* Depending on error type, find different stack entries. */ @@ -49,8 +49,12 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries case KFENCE_ERROR_UAF: case KFENCE_ERROR_OOB: case KFENCE_ERROR_INVALID: - is_access_fault = true; - break; + /* + * kfence_handle_page_fault() may be called with pt_regs + * set to NULL; in that case we'll simply show the full + * stack trace. + */ + return 0; case KFENCE_ERROR_CORRUPTION: case KFENCE_ERROR_INVALID_FREE: break; @@ -60,26 +64,21 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries for (skipnr = 0; skipnr < num_entries; skipnr++) { int len = scnprintf(buf, sizeof(buf), "%ps", (void *)stack_entries[skipnr]); - if (is_access_fault) { - if (!strncmp(buf, KFENCE_SKIP_ARCH_FAULT_HANDLER, len)) - goto found; - } else { - if (str_has_prefix(buf, "kfence_") || str_has_prefix(buf, "__kfence_") || - !strncmp(buf, "__slab_free", len)) { - /* - * In case of tail calls from any of the below - * to any of the above. - */ - fallback = skipnr + 1; - } - - /* Also the *_bulk() variants by only checking prefixes. */ - if (str_has_prefix(buf, "kfree") || - str_has_prefix(buf, "kmem_cache_free") || - str_has_prefix(buf, "__kmalloc") || - str_has_prefix(buf, "kmem_cache_alloc")) - goto found; + if (str_has_prefix(buf, "kfence_") || str_has_prefix(buf, "__kfence_") || + !strncmp(buf, "__slab_free", len)) { + /* + * In case of tail calls from any of the below + * to any of the above. + */ + fallback = skipnr + 1; } + + /* Also the *_bulk() variants by only checking prefixes. */ + if (str_has_prefix(buf, "kfree") || + str_has_prefix(buf, "kmem_cache_free") || + str_has_prefix(buf, "__kmalloc") || + str_has_prefix(buf, "kmem_cache_alloc")) + goto found; } if (fallback < num_entries) return fallback; @@ -157,13 +156,20 @@ static void print_diff_canary(unsigned long address, size_t bytes_to_show, pr_cont(" ]"); } -void kfence_report_error(unsigned long address, const struct kfence_metadata *meta, - enum kfence_error_type type) +void kfence_report_error(unsigned long address, struct pt_regs *regs, + const struct kfence_metadata *meta, enum kfence_error_type type) { unsigned long stack_entries[KFENCE_STACK_DEPTH] = { 0 }; - int num_stack_entries = stack_trace_save(stack_entries, KFENCE_STACK_DEPTH, 1); - int skipnr = get_stack_skipnr(stack_entries, num_stack_entries, &type); const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1; + int num_stack_entries; + int skipnr = 0; + + if (regs) { + num_stack_entries = stack_trace_save_regs(regs, stack_entries, KFENCE_STACK_DEPTH, 0); + } else { + num_stack_entries = stack_trace_save(stack_entries, KFENCE_STACK_DEPTH, 1); + skipnr = get_stack_skipnr(stack_entries, num_stack_entries, &type); + } /* Require non-NULL meta, except if KFENCE_ERROR_INVALID. */ if (WARN_ON(type != KFENCE_ERROR_INVALID && !meta)) @@ -227,7 +233,10 @@ void kfence_report_error(unsigned long address, const struct kfence_metadata *me /* Print report footer. */ pr_err("\n"); - dump_stack_print_info(KERN_ERR); + if (IS_ENABLED(CONFIG_DEBUG_KERNEL) && regs) + show_regs(regs); + else + dump_stack_print_info(KERN_ERR); pr_err("==================================================================\n"); lockdep_on(); From 40edd642cbcfd52cd66396affda797fcb0a5e563 Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Mon, 14 Dec 2020 19:04:33 -0800 Subject: [PATCH 269/306] FROMGIT: mm/slab: rerform init_on_free earlier Currently in CONFIG_SLAB init_on_free happens too late, and heap objects go to the heap quarantine not being erased. Lets move init_on_free clearing before calling kasan_slab_free(). In that case heap quarantine will store erased objects, similarly to CONFIG_SLUB=y behavior. Link: https://lkml.kernel.org/r/20201210183729.1261524-1-alex.popov@linux.com Signed-off-by: Alexander Popov Reviewed-by: Alexander Potapenko Acked-by: David Rientjes Acked-by: Joonsoo Kim Cc: Christoph Lameter Cc: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 177201466 (cherry picked from commit a32d654db543843a5ffb248feaec1a909718addd https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I2bf5e70c1524619526efd792bbdd959b813af1e4 --- mm/slab.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/slab.c b/mm/slab.c index 1a75a1204ff4..670374c15bcf 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3425,6 +3425,9 @@ free_done: static __always_inline void __cache_free(struct kmem_cache *cachep, void *objp, unsigned long caller) { + if (unlikely(slab_want_init_on_free(cachep))) + memset(objp, 0, cachep->object_size); + /* Put the object into the quarantine, don't touch it for now. */ if (kasan_slab_free(cachep, objp, _RET_IP_)) return; @@ -3438,8 +3441,6 @@ void ___cache_free(struct kmem_cache *cachep, void *objp, struct array_cache *ac = cpu_cache_get(cachep); check_irq_off(); - if (unlikely(slab_want_init_on_free(cachep))) - memset(objp, 0, cachep->object_size); kmemleak_free_recursive(objp, cachep->flags); objp = cache_free_debugcheck(cachep, objp, caller); From 5ae04c6867149348a9852dc46ef7a7f526cf1d79 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:38 +0000 Subject: [PATCH 270/306] BACKPORT: mm, kfence: insert KFENCE hooks for SLAB Inserts KFENCE hooks into the SLAB allocator. To pass the originally requested size to KFENCE, add an argument 'orig_size' to slab_alloc*(). The additional argument is required to preserve the requested original size for kmalloc() allocations, which uses size classes (e.g. an allocation of 272 bytes will return an object of size 512). Therefore, kmem_cache::size does not represent the kmalloc-caller's requested size, and we must introduce the argument 'orig_size' to propagate the originally requested size to KFENCE. Without the originally requested size, we would not be able to detect out-of-bounds accesses for objects placed at the end of a KFENCE object page if that object is not equal to the kmalloc-size class it was bucketed into. When KFENCE is disabled, there is no additional overhead, since slab_alloc*() functions are __always_inline. Link: https://lkml.kernel.org/r/20201103175841.3495947-5-elver@google.com Signed-off-by: Marco Elver Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov Co-developed-by: Marco Elver Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Dave Hansen Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Jann Horn Cc: Joern Engel Cc: Jonathan Corbet Cc: Kees Cook Cc: Mark Rutland Cc: Paul E. McKenney Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 840c0553e89413319d67971a321bcc07114da9b8 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: resolved minor API change in mm/slab_common.c, dropped changes to include/linux/slab_def.h, resolved conflicts in mm/slab.c, always pass root cache pointer to kfence_alloc] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Iab2ba9c7b06b9a234d93ba892be639941861f8ab --- mm/kfence/core.c | 2 ++ mm/slab.c | 57 ++++++++++++++++++++++++++++++++++++++++-------- mm/slab_common.c | 5 ++++- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 515403bc269d..06604376759a 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -324,6 +324,8 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g /* Set required struct page fields. */ page = virt_to_page(meta->addr); page->slab_cache = cache; + if (IS_ENABLED(CONFIG_SLAB)) + page->s_mem = addr; raw_spin_unlock_irqrestore(&meta->lock, flags); diff --git a/mm/slab.c b/mm/slab.c index 670374c15bcf..a9a5fb49373d 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -100,6 +100,7 @@ #include #include #include +#include #include #include #include @@ -3219,18 +3220,28 @@ must_grow: } static __always_inline void * -slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, +slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, size_t orig_size, unsigned long caller) { unsigned long save_flags; void *ptr; int slab_node = numa_mem_id(); + struct kmem_cache *orig_cachep = cachep; flags &= gfp_allowed_mask; cachep = slab_pre_alloc_hook(cachep, flags); if (unlikely(!cachep)) return NULL; + /* + * 5.4 note: passing in original cachep to avoid problems with memcg + * accounting. Making KFENCE properly work with memcgs on older kernels + * is not worth the effort. + */ + ptr = kfence_alloc(orig_cachep, orig_size, flags); + if (unlikely(ptr)) + goto out_hooks; + cache_alloc_debugcheck_before(cachep, flags); local_irq_save(save_flags); @@ -3263,6 +3274,7 @@ slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid, if (unlikely(slab_want_init_on_alloc(flags, cachep)) && ptr) memset(ptr, 0, cachep->object_size); +out_hooks: slab_post_alloc_hook(cachep, flags, 1, &ptr); return ptr; } @@ -3300,16 +3312,26 @@ __do_cache_alloc(struct kmem_cache *cachep, gfp_t flags) #endif /* CONFIG_NUMA */ static __always_inline void * -slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller) +slab_alloc(struct kmem_cache *cachep, gfp_t flags, size_t orig_size, unsigned long caller) { unsigned long save_flags; void *objp; + struct kmem_cache *orig_cachep = cachep; flags &= gfp_allowed_mask; cachep = slab_pre_alloc_hook(cachep, flags); if (unlikely(!cachep)) return NULL; + /* + * 5.4 note: passing in original cachep to avoid problems with memcg + * accounting. Making KFENCE properly work with memcgs on older kernels + * is not worth the effort. + */ + objp = kfence_alloc(orig_cachep, orig_size, flags); + if (unlikely(objp)) + goto out; + cache_alloc_debugcheck_before(cachep, flags); local_irq_save(save_flags); objp = __do_cache_alloc(cachep, flags); @@ -3320,6 +3342,7 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller) if (unlikely(slab_want_init_on_alloc(flags, cachep)) && objp) memset(objp, 0, cachep->object_size); +out: slab_post_alloc_hook(cachep, flags, 1, &objp); return objp; } @@ -3425,6 +3448,12 @@ free_done: static __always_inline void __cache_free(struct kmem_cache *cachep, void *objp, unsigned long caller) { + if (is_kfence_address(objp)) { + kmemleak_free_recursive(objp, cachep->flags); + __kfence_free(objp); + return; + } + if (unlikely(slab_want_init_on_free(cachep))) memset(objp, 0, cachep->object_size); @@ -3485,7 +3514,7 @@ void ___cache_free(struct kmem_cache *cachep, void *objp, */ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) { - void *ret = slab_alloc(cachep, flags, _RET_IP_); + void *ret = slab_alloc(cachep, flags, cachep->object_size, _RET_IP_); trace_kmem_cache_alloc(_RET_IP_, ret, cachep->object_size, cachep->size, flags); @@ -3508,6 +3537,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, void **p) { size_t i; + struct kmem_cache *root_s = s; s = slab_pre_alloc_hook(s, flags); if (!s) @@ -3517,7 +3547,13 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, local_irq_disable(); for (i = 0; i < size; i++) { - void *objp = __do_cache_alloc(s, flags); + /* + * 5.4 note: passing in original cachep to avoid problems with + * memcg accounting. Making KFENCE properly work with memcgs on + * older kernels is not worth the effort. + */ + void *objp = kfence_alloc(root_s, s->object_size, flags) ?: + __do_cache_alloc(s, flags); if (unlikely(!objp)) goto error; @@ -3550,7 +3586,7 @@ kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size) { void *ret; - ret = slab_alloc(cachep, flags, _RET_IP_); + ret = slab_alloc(cachep, flags, size, _RET_IP_); ret = kasan_kmalloc(cachep, ret, size, flags); trace_kmalloc(_RET_IP_, ret, @@ -3576,7 +3612,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_trace); */ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid) { - void *ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_); + void *ret = slab_alloc_node(cachep, flags, nodeid, cachep->object_size, _RET_IP_); trace_kmem_cache_alloc_node(_RET_IP_, ret, cachep->object_size, cachep->size, @@ -3594,7 +3630,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep, { void *ret; - ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_); + ret = slab_alloc_node(cachep, flags, nodeid, size, _RET_IP_); ret = kasan_kmalloc(cachep, ret, size, flags); trace_kmalloc_node(_RET_IP_, ret, @@ -3655,7 +3691,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags, cachep = kmalloc_slab(size, flags); if (unlikely(ZERO_OR_NULL_PTR(cachep))) return cachep; - ret = slab_alloc(cachep, flags, caller); + ret = slab_alloc(cachep, flags, size, caller); ret = kasan_kmalloc(cachep, ret, size, flags); trace_kmalloc(caller, ret, @@ -4204,7 +4240,10 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page, BUG_ON(objnr >= cachep->num); /* Find offset within object. */ - offset = ptr - index_to_obj(cachep, page, objnr) - obj_offset(cachep); + if (is_kfence_address(ptr)) + offset = ptr - kfence_object_start(ptr); + else + offset = ptr - index_to_obj(cachep, page, objnr) - obj_offset(cachep); /* Allow address range falling entirely within usercopy region. */ if (offset >= cachep->useroffset && diff --git a/mm/slab_common.c b/mm/slab_common.c index ca398f6bfa48..f024c2067aa0 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -593,6 +594,7 @@ static void slab_caches_to_rcu_destroy_workfn(struct work_struct *work) rcu_barrier(); list_for_each_entry_safe(s, s2, &to_destroy, list) { + kfence_shutdown_cache(s); #ifdef SLAB_SUPPORTS_SYSFS sysfs_slab_release(s); #else @@ -619,6 +621,7 @@ static int shutdown_cache(struct kmem_cache *s) list_add_tail(&s->list, &slab_caches_to_rcu_destroy); schedule_work(&slab_caches_to_rcu_destroy_work); } else { + kfence_shutdown_cache(s); #ifdef SLAB_SUPPORTS_SYSFS sysfs_slab_unlink(s); sysfs_slab_release(s); @@ -1870,7 +1873,7 @@ size_t ksize(const void *objp) if (unlikely(objp == ZERO_SIZE_PTR) || !__kasan_check_read(objp, 1)) return 0; - size = __ksize(objp); + size = kfence_ksize(objp) ?: __ksize(objp); /* * We assume that ksize callers could use whole allocated area, * so we need to unpoison this area. From a8558dff464e052b2b29c4e656d68cb5e714e083 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:39 +0000 Subject: [PATCH 271/306] BACKPORT: mm, kfence: insert KFENCE hooks for SLUB Inserts KFENCE hooks into the SLUB allocator. To pass the originally requested size to KFENCE, add an argument 'orig_size' to slab_alloc*(). The additional argument is required to preserve the requested original size for kmalloc() allocations, which uses size classes (e.g. an allocation of 272 bytes will return an object of size 512). Therefore, kmem_cache::size does not represent the kmalloc-caller's requested size, and we must introduce the argument 'orig_size' to propagate the originally requested size to KFENCE. Without the originally requested size, we would not be able to detect out-of-bounds accesses for objects placed at the end of a KFENCE object page if that object is not equal to the kmalloc-size class it was bucketed into. When KFENCE is disabled, there is no additional overhead, since slab_alloc*() functions are __always_inline. Link: https://lkml.kernel.org/r/20201103175841.3495947-6-elver@google.com Signed-off-by: Marco Elver Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov Reviewed-by: Jann Horn Co-developed-by: Marco Elver Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Joern Engel Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Kees Cook Cc: Mark Rutland Cc: Paul E. McKenney Cc: Pekka Enberg Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 5aa4d4f541f500cd63f814ae39bea55024ed5c6b https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: dropped changes to include/linux/slub_def.h, fixed conflict in mm/slub.c, always pass root cache pointer to kfence_alloc()] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Iacfc22088087cb920107a595f71b09e21d5f2f47 --- mm/kfence/core.c | 2 ++ mm/slub.c | 72 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 06604376759a..9be94e8c136a 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -324,6 +324,8 @@ static void *kfence_guarded_alloc(struct kmem_cache *cache, size_t size, gfp_t g /* Set required struct page fields. */ page = virt_to_page(meta->addr); page->slab_cache = cache; + if (IS_ENABLED(CONFIG_SLUB)) + page->objects = 1; if (IS_ENABLED(CONFIG_SLAB)) page->s_mem = addr; diff --git a/mm/slub.c b/mm/slub.c index ff869e0e2369..638736789987 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1486,6 +1487,11 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, void *old_tail = *tail ? *tail : *head; int rsize; + if (is_kfence_address(next)) { + slab_free_hook(s, next); + return true; + } + /* Head and tail of the reconstructed freelist */ *head = NULL; *tail = NULL; @@ -2770,16 +2776,27 @@ static __always_inline void maybe_wipe_obj_freeptr(struct kmem_cache *s, * Otherwise we can simply pick the next object from the lockless free list. */ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - gfp_t gfpflags, int node, unsigned long addr) + gfp_t gfpflags, int node, unsigned long addr, size_t orig_size) { void *object; struct kmem_cache_cpu *c; struct page *page; unsigned long tid; + struct kmem_cache *root_s = s; s = slab_pre_alloc_hook(s, gfpflags); if (!s) return NULL; + + /* + * 5.4 note: passing in original cachep to avoid problems with memcg + * accounting. Making KFENCE properly work with memcgs on older kernels + * is not worth the effort. + */ + object = kfence_alloc(root_s, orig_size, gfpflags); + if (unlikely(object)) + goto out; + redo: /* * Must read kmem_cache cpu data via this cpu ptr. Preemption is @@ -2853,20 +2870,21 @@ redo: if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) memset(object, 0, s->object_size); +out: slab_post_alloc_hook(s, gfpflags, 1, &object); return object; } static __always_inline void *slab_alloc(struct kmem_cache *s, - gfp_t gfpflags, unsigned long addr) + gfp_t gfpflags, unsigned long addr, size_t orig_size) { - return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr); + return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr, orig_size); } void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) { - void *ret = slab_alloc(s, gfpflags, _RET_IP_); + void *ret = slab_alloc(s, gfpflags, _RET_IP_, s->object_size); trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags); @@ -2878,7 +2896,7 @@ EXPORT_SYMBOL(kmem_cache_alloc); #ifdef CONFIG_TRACING void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size) { - void *ret = slab_alloc(s, gfpflags, _RET_IP_); + void *ret = slab_alloc(s, gfpflags, _RET_IP_, size); trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags); ret = kasan_kmalloc(s, ret, size, gfpflags); return ret; @@ -2889,7 +2907,7 @@ EXPORT_SYMBOL(kmem_cache_alloc_trace); #ifdef CONFIG_NUMA void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) { - void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_); + void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_, s->object_size); trace_kmem_cache_alloc_node(_RET_IP_, ret, s->object_size, s->size, gfpflags, node); @@ -2903,7 +2921,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s, gfp_t gfpflags, int node, size_t size) { - void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_); + void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_, size); trace_kmalloc_node(_RET_IP_, ret, size, s->size, gfpflags, node); @@ -2937,6 +2955,9 @@ static void __slab_free(struct kmem_cache *s, struct page *page, stat(s, FREE_SLOWPATH); + if (kfence_free(head)) + return; + if (kmem_cache_debug(s) && !free_debug_processing(s, page, head, tail, cnt, addr)) return; @@ -3178,6 +3199,13 @@ int build_detached_freelist(struct kmem_cache *s, size_t size, df->s = cache_from_obj(s, object); /* Support for memcg */ } + if (is_kfence_address(object)) { + slab_free_hook(df->s, object); + __kfence_free(object); + p[size] = NULL; /* mark object processed */ + return size; + } + /* Start new detached freelist */ df->page = page; set_freepointer(df->s, object, NULL); @@ -3237,6 +3265,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, { struct kmem_cache_cpu *c; int i; + struct kmem_cache *root_s = s; /* memcg and kmem_cache debug support */ s = slab_pre_alloc_hook(s, flags); @@ -3251,8 +3280,19 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, c = this_cpu_ptr(s->cpu_slab); for (i = 0; i < size; i++) { - void *object = c->freelist; + /* + * 5.4 note: passing in original cachep to avoid problems with memcg + * accounting. Making KFENCE properly work with memcgs on older kernels + * is not worth the effort. + */ + void *object = kfence_alloc(root_s, s->object_size, flags); + if (unlikely(object)) { + p[i] = object; + continue; + } + + object = c->freelist; if (unlikely(!object)) { /* * We may have removed an object from c->freelist using @@ -3911,7 +3951,7 @@ void *__kmalloc(size_t size, gfp_t flags) if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc(s, flags, _RET_IP_); + ret = slab_alloc(s, flags, _RET_IP_, size); trace_kmalloc(_RET_IP_, ret, size, s->size, flags); @@ -3959,7 +3999,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc_node(s, flags, node, _RET_IP_); + ret = slab_alloc_node(s, flags, node, _RET_IP_, size); trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node); @@ -3985,6 +4025,7 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page, struct kmem_cache *s; unsigned int offset; size_t object_size; + bool is_kfence = is_kfence_address(ptr); ptr = kasan_reset_tag(ptr); @@ -3997,10 +4038,13 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page, to_user, 0, n); /* Find offset within object. */ - offset = (ptr - page_address(page)) % s->size; + if (is_kfence) + offset = ptr - kfence_object_start(ptr); + else + offset = (ptr - page_address(page)) % s->size; /* Adjust for redzone and reject if within the redzone. */ - if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) { + if (!is_kfence && kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) { if (offset < s->red_left_pad) usercopy_abort("SLUB object in left red zone", s->name, to_user, offset, n); @@ -4447,7 +4491,7 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller) if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc(s, gfpflags, caller); + ret = slab_alloc(s, gfpflags, caller, size); /* Honor the call site pointer we received. */ trace_kmalloc(caller, ret, size, s->size, gfpflags); @@ -4478,7 +4522,7 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, if (unlikely(ZERO_OR_NULL_PTR(s))) return s; - ret = slab_alloc_node(s, gfpflags, node, caller); + ret = slab_alloc_node(s, gfpflags, node, caller, size); /* Honor the call site pointer we received. */ trace_kmalloc_node(caller, ret, size, s->size, gfpflags, node); From 07ab8ca5d30f1abde862d45eb8934b24a754fb2c Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:39 +0000 Subject: [PATCH 272/306] BACKPORT: kfence, kasan: make KFENCE compatible with KASAN Make KFENCE compatible with KASAN. Currently this helps test KFENCE itself, where KASAN can catch potential corruptions to KFENCE state, or other corruptions that may be a result of freepointer corruptions in the main allocators. Link: https://lkml.kernel.org/r/20201103175841.3495947-7-elver@google.com Signed-off-by: Marco Elver Signed-off-by: Alexander Potapenko Reviewed-by: Dmitry Vyukov Reviewed-by: Jann Horn Co-developed-by: Marco Elver Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Joern Engel Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Kees Cook Cc: Mark Rutland Cc: Paul E. McKenney Cc: Pekka Enberg Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 8ab944ae627dc9fb165bff68acc465751a0b8de2 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: resolved a conflict in mm/kasan/generic.c] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I2f862c2e514e7fcff50a019048c8f0d22f46e6c4 --- lib/Kconfig.kfence | 2 +- mm/kasan/common.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence index b88ac9d6b2e6..edfecb5d6165 100644 --- a/lib/Kconfig.kfence +++ b/lib/Kconfig.kfence @@ -5,7 +5,7 @@ config HAVE_ARCH_KFENCE menuconfig KFENCE bool "KFENCE: low-overhead sampling-based memory safety error detector" - depends on HAVE_ARCH_KFENCE && !KASAN && (SLAB || SLUB) + depends on HAVE_ARCH_KFENCE && (SLAB || SLUB) select STACKTRACE help KFENCE is a low-overhead sampling-based detector of heap out-of-bounds diff --git a/mm/kasan/common.c b/mm/kasan/common.c index ac9f624158b9..f8e330596664 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +446,9 @@ static bool __kasan_slab_free(struct kmem_cache *cache, void *object, tagged_object = object; object = reset_tag(object); + if (is_kfence_address(object)) + return false; + if (unlikely(nearest_obj(cache, virt_to_head_page(object), object) != object)) { kasan_report_invalid_free(tagged_object, ip); @@ -493,6 +497,9 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, if (unlikely(object == NULL)) return NULL; + if (is_kfence_address(object)) + return (void *)object; + redzone_start = round_up((unsigned long)(object + size), KASAN_SHADOW_SCALE_SIZE); redzone_end = round_up((unsigned long)object + cache->object_size, From bb03f417cbc71aad42acb83afc4340b047779074 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:40 +0000 Subject: [PATCH 273/306] BACKPORT: kfence, Documentation: add KFENCE documentation Add KFENCE documentation in dev-tools/kfence.rst, and add to index. Link: https://lkml.kernel.org/r/20201103175841.3495947-8-elver@google.com Signed-off-by: Alexander Potapenko Signed-off-by: Marco Elver Reviewed-by: Dmitry Vyukov Co-developed-by: Alexander Potapenko Reviewed-by: Jann Horn Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Joern Engel Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Kees Cook Cc: Mark Rutland Cc: Paul E. McKenney Cc: Pekka Enberg Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit f63eeaffb09b57d4c9cb9c92c4925ee3bd3df457 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: fixed a minor conflict in Documentation/dev-tools/index.rst] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Iaedafbf20944d68c87229f6c8b2a6e5155fcee60 --- Documentation/dev-tools/index.rst | 1 + Documentation/dev-tools/kfence.rst | 297 +++++++++++++++++++++++++++++ lib/Kconfig.kfence | 2 + 3 files changed, 300 insertions(+) create mode 100644 Documentation/dev-tools/kfence.rst diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index b0522a4dd107..cdabec1e168c 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -21,6 +21,7 @@ whole; patches welcome! kasan ubsan kmemleak + kfence gdb-kernel-debugging kgdb kselftest diff --git a/Documentation/dev-tools/kfence.rst b/Documentation/dev-tools/kfence.rst new file mode 100644 index 000000000000..d7329f2caa5a --- /dev/null +++ b/Documentation/dev-tools/kfence.rst @@ -0,0 +1,297 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel Electric-Fence (KFENCE) +============================== + +Kernel Electric-Fence (KFENCE) is a low-overhead sampling-based memory safety +error detector. KFENCE detects heap out-of-bounds access, use-after-free, and +invalid-free errors. + +KFENCE is designed to be enabled in production kernels, and has near zero +performance overhead. Compared to KASAN, KFENCE trades performance for +precision. The main motivation behind KFENCE's design, is that with enough +total uptime KFENCE will detect bugs in code paths not typically exercised by +non-production test workloads. One way to quickly achieve a large enough total +uptime is when the tool is deployed across a large fleet of machines. + +Usage +----- + +To enable KFENCE, configure the kernel with:: + + CONFIG_KFENCE=y + +To build a kernel with KFENCE support, but disabled by default (to enable, set +``kfence.sample_interval`` to non-zero value), configure the kernel with:: + + CONFIG_KFENCE=y + CONFIG_KFENCE_SAMPLE_INTERVAL=0 + +KFENCE provides several other configuration options to customize behaviour (see +the respective help text in ``lib/Kconfig.kfence`` for more info). + +Tuning performance +~~~~~~~~~~~~~~~~~~ + +The most important parameter is KFENCE's sample interval, which can be set via +the kernel boot parameter ``kfence.sample_interval`` in milliseconds. The +sample interval determines the frequency with which heap allocations will be +guarded by KFENCE. The default is configurable via the Kconfig option +``CONFIG_KFENCE_SAMPLE_INTERVAL``. Setting ``kfence.sample_interval=0`` +disables KFENCE. + +The KFENCE memory pool is of fixed size, and if the pool is exhausted, no +further KFENCE allocations occur. With ``CONFIG_KFENCE_NUM_OBJECTS`` (default +255), the number of available guarded objects can be controlled. Each object +requires 2 pages, one for the object itself and the other one used as a guard +page; object pages are interleaved with guard pages, and every object page is +therefore surrounded by two guard pages. + +The total memory dedicated to the KFENCE memory pool can be computed as:: + + ( #objects + 1 ) * 2 * PAGE_SIZE + +Using the default config, and assuming a page size of 4 KiB, results in +dedicating 2 MiB to the KFENCE memory pool. + +Note: On architectures that support huge pages, KFENCE will ensure that the +pool is using pages of size ``PAGE_SIZE``. This will result in additional page +tables being allocated. + +Error reports +~~~~~~~~~~~~~ + +A typical out-of-bounds access looks like this:: + + ================================================================== + BUG: KFENCE: out-of-bounds in test_out_of_bounds_read+0xa3/0x22b + + Out-of-bounds access at 0xffffffffb672efff (1B left of kfence-#17): + test_out_of_bounds_read+0xa3/0x22b + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + kfence-#17 [0xffffffffb672f000-0xffffffffb672f01f, size=32, cache=kmalloc-32] allocated by task 507: + test_alloc+0xf3/0x25b + test_out_of_bounds_read+0x98/0x22b + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + CPU: 4 PID: 107 Comm: kunit_try_catch Not tainted 5.8.0-rc6+ #7 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 + ================================================================== + +The header of the report provides a short summary of the function involved in +the access. It is followed by more detailed information about the access and +its origin. Note that, real kernel addresses are only shown for +``CONFIG_DEBUG_KERNEL=y`` builds. + +Use-after-free accesses are reported as:: + + ================================================================== + BUG: KFENCE: use-after-free in test_use_after_free_read+0xb3/0x143 + + Use-after-free access at 0xffffffffb673dfe0 (in kfence-#24): + test_use_after_free_read+0xb3/0x143 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + kfence-#24 [0xffffffffb673dfe0-0xffffffffb673dfff, size=32, cache=kmalloc-32] allocated by task 507: + test_alloc+0xf3/0x25b + test_use_after_free_read+0x76/0x143 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + freed by task 507: + test_use_after_free_read+0xa8/0x143 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + CPU: 4 PID: 109 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 + ================================================================== + +KFENCE also reports on invalid frees, such as double-frees:: + + ================================================================== + BUG: KFENCE: invalid free in test_double_free+0xdc/0x171 + + Invalid free of 0xffffffffb6741000: + test_double_free+0xdc/0x171 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + kfence-#26 [0xffffffffb6741000-0xffffffffb674101f, size=32, cache=kmalloc-32] allocated by task 507: + test_alloc+0xf3/0x25b + test_double_free+0x76/0x171 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + freed by task 507: + test_double_free+0xa8/0x171 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + CPU: 4 PID: 111 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 + ================================================================== + +KFENCE also uses pattern-based redzones on the other side of an object's guard +page, to detect out-of-bounds writes on the unprotected side of the object. +These are reported on frees:: + + ================================================================== + BUG: KFENCE: memory corruption in test_kmalloc_aligned_oob_write+0xef/0x184 + + Corrupted memory at 0xffffffffb6797ff9 [ 0xac . . . . . . ] (in kfence-#69): + test_kmalloc_aligned_oob_write+0xef/0x184 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + kfence-#69 [0xffffffffb6797fb0-0xffffffffb6797ff8, size=73, cache=kmalloc-96] allocated by task 507: + test_alloc+0xf3/0x25b + test_kmalloc_aligned_oob_write+0x57/0x184 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + CPU: 4 PID: 120 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 + ================================================================== + +For such errors, the address where the corruption occurred as well as the +invalidly written bytes (offset from the address) are shown; in this +representation, '.' denote untouched bytes. In the example above ``0xac`` is +the value written to the invalid address at offset 0, and the remaining '.' +denote that no following bytes have been touched. Note that, real values are +only shown for ``CONFIG_DEBUG_KERNEL=y`` builds; to avoid information +disclosure for non-debug builds, '!' is used instead to denote invalidly +written bytes. + +And finally, KFENCE may also report on invalid accesses to any protected page +where it was not possible to determine an associated object, e.g. if adjacent +object pages had not yet been allocated:: + + ================================================================== + BUG: KFENCE: invalid access in test_invalid_access+0x26/0xe0 + + Invalid access at 0xffffffffb670b00a: + test_invalid_access+0x26/0xe0 + kunit_try_run_case+0x51/0x85 + kunit_generic_run_threadfn_adapter+0x16/0x30 + kthread+0x137/0x160 + ret_from_fork+0x22/0x30 + + CPU: 4 PID: 124 Comm: kunit_try_catch Tainted: G W 5.8.0-rc6+ #7 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1 04/01/2014 + ================================================================== + +DebugFS interface +~~~~~~~~~~~~~~~~~ + +Some debugging information is exposed via debugfs: + +* The file ``/sys/kernel/debug/kfence/stats`` provides runtime statistics. + +* The file ``/sys/kernel/debug/kfence/objects`` provides a list of objects + allocated via KFENCE, including those already freed but protected. + +Implementation Details +---------------------- + +Guarded allocations are set up based on the sample interval. After expiration +of the sample interval, the next allocation through the main allocator (SLAB or +SLUB) returns a guarded allocation from the KFENCE object pool (allocation +sizes up to PAGE_SIZE are supported). At this point, the timer is reset, and +the next allocation is set up after the expiration of the interval. To "gate" a +KFENCE allocation through the main allocator's fast-path without overhead, +KFENCE relies on static branches via the static keys infrastructure. The static +branch is toggled to redirect the allocation to KFENCE. + +KFENCE objects each reside on a dedicated page, at either the left or right +page boundaries selected at random. The pages to the left and right of the +object page are "guard pages", whose attributes are changed to a protected +state, and cause page faults on any attempted access. Such page faults are then +intercepted by KFENCE, which handles the fault gracefully by reporting an +out-of-bounds access, and marking the page as accessible so that the faulting +code can (wrongly) continue executing (set ``panic_on_warn`` to panic instead). + +To detect out-of-bounds writes to memory within the object's page itself, +KFENCE also uses pattern-based redzones. For each object page, a redzone is set +up for all non-object memory. For typical alignments, the redzone is only +required on the unguarded side of an object. Because KFENCE must honor the +cache's requested alignment, special alignments may result in unprotected gaps +on either side of an object, all of which are redzoned. + +The following figure illustrates the page layout:: + + ---+-----------+-----------+-----------+-----------+-----------+--- + | xxxxxxxxx | O : | xxxxxxxxx | : O | xxxxxxxxx | + | xxxxxxxxx | B : | xxxxxxxxx | : B | xxxxxxxxx | + | x GUARD x | J : RED- | x GUARD x | RED- : J | x GUARD x | + | xxxxxxxxx | E : ZONE | xxxxxxxxx | ZONE : E | xxxxxxxxx | + | xxxxxxxxx | C : | xxxxxxxxx | : C | xxxxxxxxx | + | xxxxxxxxx | T : | xxxxxxxxx | : T | xxxxxxxxx | + ---+-----------+-----------+-----------+-----------+-----------+--- + +Upon deallocation of a KFENCE object, the object's page is again protected and +the object is marked as freed. Any further access to the object causes a fault +and KFENCE reports a use-after-free access. Freed objects are inserted at the +tail of KFENCE's freelist, so that the least recently freed objects are reused +first, and the chances of detecting use-after-frees of recently freed objects +is increased. + +Interface +--------- + +The following describes the functions which are used by allocators as well as +page handling code to set up and deal with KFENCE allocations. + +.. kernel-doc:: include/linux/kfence.h + :functions: is_kfence_address + kfence_shutdown_cache + kfence_alloc kfence_free __kfence_free + kfence_ksize kfence_object_start + kfence_handle_page_fault + +Related Tools +------------- + +In userspace, a similar approach is taken by `GWP-ASan +`_. GWP-ASan also relies on guard pages and +a sampling strategy to detect memory unsafety bugs at scale. KFENCE's design is +directly influenced by GWP-ASan, and can be seen as its kernel sibling. Another +similar but non-sampling approach, that also inspired the name "KFENCE", can be +found in the userspace `Electric Fence Malloc Debugger +`_. + +In the kernel, several tools exist to debug memory access errors, and in +particular KASAN can detect all bug classes that KFENCE can detect. While KASAN +is more precise, relying on compiler instrumentation, this comes at a +performance cost. + +It is worth highlighting that KASAN and KFENCE are complementary, with +different target environments. For instance, KASAN is the better debugging-aid, +where test cases or reproducers exists: due to the lower chance to detect the +error, it would require more effort using KFENCE to debug. Deployments at scale +that cannot afford to enable KASAN, however, would benefit from using KFENCE to +discover bugs due to code paths not exercised by test cases or fuzzers. diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence index edfecb5d6165..605125ac2ae0 100644 --- a/lib/Kconfig.kfence +++ b/lib/Kconfig.kfence @@ -13,6 +13,8 @@ menuconfig KFENCE to have negligible cost to permit enabling it in production environments. + See for more details. + Note that, KFENCE is not a substitute for explicit testing with tools such as KASAN. KFENCE can detect a subset of bugs that KASAN can detect, albeit at very different performance profiles. If you can From cff0059497bbb5f7758fb14b8c7bcd919af3f788 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:41 +0000 Subject: [PATCH 274/306] FROMGIT: kfence: add missing copyright header to documentation Add missing copyright header to KFENCE documentation. Link: https://lkml.kernel.org/r/20210118092159.145934-4-elver@google.com Signed-off-by: Marco Elver Reviewed-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 14c8d0148b7b44c549c8892a93a800a9650fa31c https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Iaf953c9bf1f220054b1ec4068f2ba0bd9a7e9fc4 --- Documentation/dev-tools/kfence.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/dev-tools/kfence.rst b/Documentation/dev-tools/kfence.rst index d7329f2caa5a..0e2fb6ef3016 100644 --- a/Documentation/dev-tools/kfence.rst +++ b/Documentation/dev-tools/kfence.rst @@ -1,4 +1,5 @@ .. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2020, Google LLC. Kernel Electric-Fence (KFENCE) ============================== From f272e18c0d93e24bb7979571769d42891a309f0f Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:41 +0000 Subject: [PATCH 275/306] BACKPORT: kfence: add test suite Add KFENCE test suite, testing various error detection scenarios. Makes use of KUnit for test organization. Since KFENCE's interface to obtain error reports is via the console, the test verifies that KFENCE outputs expected reports to the console. Link: https://lkml.kernel.org/r/20201103175841.3495947-9-elver@google.com Signed-off-by: Alexander Potapenko Signed-off-by: Marco Elver Reviewed-by: Dmitry Vyukov Co-developed-by: Alexander Potapenko Reviewed-by: Jann Horn Cc: Andrey Konovalov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Catalin Marinas Cc: Christopher Lameter Cc: Dave Hansen Cc: David Rientjes Cc: Eric Dumazet Cc: Greg Kroah-Hartman Cc: Hillf Danton Cc: "H. Peter Anvin" Cc: Ingo Molnar Cc: Joern Engel Cc: Jonathan Corbet Cc: Joonsoo Kim Cc: Kees Cook Cc: Mark Rutland Cc: Paul E. McKenney Cc: Pekka Enberg Cc: Peter Zijlstra Cc: SeongJae Park Cc: Thomas Gleixner Cc: Vlastimil Babka Cc: Will Deacon Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit d6364119849bb0432e9a46e9699519ea9ff1bb77 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: removed memcg sanity checks from the tests] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I733090d4109a795c078fe8090c46b19cdfe9413f --- lib/Kconfig.kfence | 13 + mm/kfence/Makefile | 3 + mm/kfence/kfence_test.c | 815 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 831 insertions(+) create mode 100644 mm/kfence/kfence_test.c diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence index 605125ac2ae0..78f50ccb3b45 100644 --- a/lib/Kconfig.kfence +++ b/lib/Kconfig.kfence @@ -66,4 +66,17 @@ config KFENCE_STRESS_TEST_FAULTS Only for KFENCE testing; set to 0 if you are not a KFENCE developer. +config KFENCE_KUNIT_TEST + tristate "KFENCE integration test suite" if !KUNIT_ALL_TESTS + default KUNIT_ALL_TESTS + depends on TRACEPOINTS && KUNIT + help + Test suite for KFENCE, testing various error detection scenarios with + various allocation types, and checking that reports are correctly + output to console. + + Say Y here if you want the test to be built into the kernel and run + during boot; say M if you want the test to build as a module; say N + if you are unsure. + endif # KFENCE diff --git a/mm/kfence/Makefile b/mm/kfence/Makefile index d991e9a349f0..6872cd5e5390 100644 --- a/mm/kfence/Makefile +++ b/mm/kfence/Makefile @@ -1,3 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_KFENCE) := core.o report.o + +CFLAGS_kfence_test.o := -g -fno-omit-frame-pointer -fno-optimize-sibling-calls +obj-$(CONFIG_KFENCE_KUNIT_TEST) += kfence_test.o diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c new file mode 100644 index 000000000000..87b80ba1c573 --- /dev/null +++ b/mm/kfence/kfence_test.c @@ -0,0 +1,815 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test cases for KFENCE memory safety error detector. Since the interface with + * which KFENCE's reports are obtained is via the console, this is the output we + * should verify. For each test case checks the presence (or absence) of + * generated reports. Relies on 'console' tracepoint to capture reports as they + * appear in the kernel log. + * + * Copyright (C) 2020, Google LLC. + * Author: Alexander Potapenko + * Marco Elver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kfence.h" + +/* Report as observed from console. */ +static struct { + spinlock_t lock; + int nlines; + char lines[2][256]; +} observed = { + .lock = __SPIN_LOCK_UNLOCKED(observed.lock), +}; + +/* Probe for console output: obtains observed lines of interest. */ +static void probe_console(void *ignore, const char *buf, size_t len) +{ + unsigned long flags; + int nlines; + + spin_lock_irqsave(&observed.lock, flags); + nlines = observed.nlines; + + if (strnstr(buf, "BUG: KFENCE: ", len) && strnstr(buf, "test_", len)) { + /* + * KFENCE report and related to the test. + * + * The provided @buf is not NUL-terminated; copy no more than + * @len bytes and let strscpy() add the missing NUL-terminator. + */ + strscpy(observed.lines[0], buf, min(len + 1, sizeof(observed.lines[0]))); + nlines = 1; + } else if (nlines == 1 && (strnstr(buf, "at 0x", len) || strnstr(buf, "of 0x", len))) { + strscpy(observed.lines[nlines++], buf, min(len + 1, sizeof(observed.lines[0]))); + } + + WRITE_ONCE(observed.nlines, nlines); /* Publish new nlines. */ + spin_unlock_irqrestore(&observed.lock, flags); +} + +/* Check if a report related to the test exists. */ +static bool report_available(void) +{ + return READ_ONCE(observed.nlines) == ARRAY_SIZE(observed.lines); +} + +/* Information we expect in a report. */ +struct expect_report { + enum kfence_error_type type; /* The type or error. */ + void *fn; /* Function pointer to expected function where access occurred. */ + char *addr; /* Address at which the bad access occurred. */ +}; + +/* Check observed report matches information in @r. */ +static bool report_matches(const struct expect_report *r) +{ + bool ret = false; + unsigned long flags; + typeof(observed.lines) expect; + const char *end; + char *cur; + + /* Doubled-checked locking. */ + if (!report_available()) + return false; + + /* Generate expected report contents. */ + + /* Title */ + cur = expect[0]; + end = &expect[0][sizeof(expect[0]) - 1]; + switch (r->type) { + case KFENCE_ERROR_OOB: + cur += scnprintf(cur, end - cur, "BUG: KFENCE: out-of-bounds"); + break; + case KFENCE_ERROR_UAF: + cur += scnprintf(cur, end - cur, "BUG: KFENCE: use-after-free"); + break; + case KFENCE_ERROR_CORRUPTION: + cur += scnprintf(cur, end - cur, "BUG: KFENCE: memory corruption"); + break; + case KFENCE_ERROR_INVALID: + cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid access"); + break; + case KFENCE_ERROR_INVALID_FREE: + cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid free"); + break; + } + + scnprintf(cur, end - cur, " in %pS", r->fn); + /* The exact offset won't match, remove it; also strip module name. */ + cur = strchr(expect[0], '+'); + if (cur) + *cur = '\0'; + + /* Access information */ + cur = expect[1]; + end = &expect[1][sizeof(expect[1]) - 1]; + + switch (r->type) { + case KFENCE_ERROR_OOB: + cur += scnprintf(cur, end - cur, "Out-of-bounds access at"); + break; + case KFENCE_ERROR_UAF: + cur += scnprintf(cur, end - cur, "Use-after-free access at"); + break; + case KFENCE_ERROR_CORRUPTION: + cur += scnprintf(cur, end - cur, "Corrupted memory at"); + break; + case KFENCE_ERROR_INVALID: + cur += scnprintf(cur, end - cur, "Invalid access at"); + break; + case KFENCE_ERROR_INVALID_FREE: + cur += scnprintf(cur, end - cur, "Invalid free of"); + break; + } + + cur += scnprintf(cur, end - cur, " 0x" PTR_FMT, (void *)r->addr); + + spin_lock_irqsave(&observed.lock, flags); + if (!report_available()) + goto out; /* A new report is being captured. */ + + /* Finally match expected output to what we actually observed. */ + ret = strstr(observed.lines[0], expect[0]) && strstr(observed.lines[1], expect[1]); +out: + spin_unlock_irqrestore(&observed.lock, flags); + return ret; +} + +/* ===== Test cases ===== */ + +#define TEST_PRIV_WANT_MEMCACHE ((void *)1) + +/* Cache used by tests; if NULL, allocate from kmalloc instead. */ +static struct kmem_cache *test_cache; + +static size_t setup_test_cache(struct kunit *test, size_t size, slab_flags_t flags, + void (*ctor)(void *)) +{ + if (test->priv != TEST_PRIV_WANT_MEMCACHE) + return size; + + kunit_info(test, "%s: size=%zu, ctor=%ps\n", __func__, size, ctor); + + /* + * Use SLAB_NOLEAKTRACE to prevent merging with existing caches. Any + * other flag in SLAB_NEVER_MERGE also works. Use SLAB_ACCOUNT to + * allocate via memcg, if enabled. + */ + flags |= SLAB_NOLEAKTRACE | SLAB_ACCOUNT; + test_cache = kmem_cache_create("test", size, 1, flags, ctor); + KUNIT_ASSERT_TRUE_MSG(test, test_cache, "could not create cache"); + + return size; +} + +static void test_cache_destroy(void) +{ + if (!test_cache) + return; + + kmem_cache_destroy(test_cache); + test_cache = NULL; +} + +static inline size_t kmalloc_cache_alignment(size_t size) +{ + return kmalloc_caches[kmalloc_type(GFP_KERNEL)][kmalloc_index(size)]->align; +} + +/* Must always inline to match stack trace against caller. */ +static __always_inline void test_free(void *ptr) +{ + if (test_cache) + kmem_cache_free(test_cache, ptr); + else + kfree(ptr); +} + +/* + * If this should be a KFENCE allocation, and on which side the allocation and + * the closest guard page should be. + */ +enum allocation_policy { + ALLOCATE_ANY, /* KFENCE, any side. */ + ALLOCATE_LEFT, /* KFENCE, left side of page. */ + ALLOCATE_RIGHT, /* KFENCE, right side of page. */ + ALLOCATE_NONE, /* No KFENCE allocation. */ +}; + +/* + * Try to get a guarded allocation from KFENCE. Uses either kmalloc() or the + * current test_cache if set up. + */ +static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocation_policy policy) +{ + void *alloc; + unsigned long timeout, resched_after; + const char *policy_name; + + switch (policy) { + case ALLOCATE_ANY: + policy_name = "any"; + break; + case ALLOCATE_LEFT: + policy_name = "left"; + break; + case ALLOCATE_RIGHT: + policy_name = "right"; + break; + case ALLOCATE_NONE: + policy_name = "none"; + break; + } + + kunit_info(test, "%s: size=%zu, gfp=%x, policy=%s, cache=%i\n", __func__, size, gfp, + policy_name, !!test_cache); + + /* + * 100x the sample interval should be more than enough to ensure we get + * a KFENCE allocation eventually. + */ + timeout = jiffies + msecs_to_jiffies(100 * CONFIG_KFENCE_SAMPLE_INTERVAL); + /* + * Especially for non-preemption kernels, ensure the allocation-gate + * timer can catch up: after @resched_after, every failed allocation + * attempt yields, to ensure the allocation-gate timer is scheduled. + */ + resched_after = jiffies + msecs_to_jiffies(CONFIG_KFENCE_SAMPLE_INTERVAL); + do { + if (test_cache) + alloc = kmem_cache_alloc(test_cache, gfp); + else + alloc = kmalloc(size, gfp); + + if (is_kfence_address(alloc)) { + struct page *page = virt_to_head_page(alloc); + struct kmem_cache *s = test_cache ?: kmalloc_caches[kmalloc_type(GFP_KERNEL)][kmalloc_index(size)]; + + if (policy == ALLOCATE_ANY) + return alloc; + if (policy == ALLOCATE_LEFT && IS_ALIGNED((unsigned long)alloc, PAGE_SIZE)) + return alloc; + if (policy == ALLOCATE_RIGHT && + !IS_ALIGNED((unsigned long)alloc, PAGE_SIZE)) + return alloc; + } else if (policy == ALLOCATE_NONE) + return alloc; + + test_free(alloc); + + if (time_after(jiffies, resched_after)) + cond_resched(); + } while (time_before(jiffies, timeout)); + + KUNIT_ASSERT_TRUE_MSG(test, false, "failed to allocate from KFENCE"); + return NULL; /* Unreachable. */ +} + +static void test_out_of_bounds_read(struct kunit *test) +{ + size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_OOB, + .fn = test_out_of_bounds_read, + }; + char *buf; + + setup_test_cache(test, size, 0, NULL); + + /* + * If we don't have our own cache, adjust based on alignment, so that we + * actually access guard pages on either side. + */ + if (!test_cache) + size = kmalloc_cache_alignment(size); + + /* Test both sides. */ + + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_LEFT); + expect.addr = buf - 1; + READ_ONCE(*expect.addr); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); + test_free(buf); + + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_RIGHT); + expect.addr = buf + size; + READ_ONCE(*expect.addr); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); + test_free(buf); +} + +static void test_use_after_free_read(struct kunit *test) +{ + const size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_UAF, + .fn = test_use_after_free_read, + }; + + setup_test_cache(test, size, 0, NULL); + expect.addr = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + test_free(expect.addr); + READ_ONCE(*expect.addr); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +static void test_double_free(struct kunit *test) +{ + const size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_INVALID_FREE, + .fn = test_double_free, + }; + + setup_test_cache(test, size, 0, NULL); + expect.addr = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + test_free(expect.addr); + test_free(expect.addr); /* Double-free. */ + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +static void test_invalid_addr_free(struct kunit *test) +{ + const size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_INVALID_FREE, + .fn = test_invalid_addr_free, + }; + char *buf; + + setup_test_cache(test, size, 0, NULL); + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + expect.addr = buf + 1; /* Free on invalid address. */ + test_free(expect.addr); /* Invalid address free. */ + test_free(buf); /* No error. */ + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +static void test_corruption(struct kunit *test) +{ + size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_CORRUPTION, + .fn = test_corruption, + }; + char *buf; + + setup_test_cache(test, size, 0, NULL); + + /* Test both sides. */ + + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_LEFT); + expect.addr = buf + size; + WRITE_ONCE(*expect.addr, 42); + test_free(buf); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); + + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_RIGHT); + expect.addr = buf - 1; + WRITE_ONCE(*expect.addr, 42); + test_free(buf); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +/* + * KFENCE is unable to detect an OOB if the allocation's alignment requirements + * leave a gap between the object and the guard page. Specifically, an + * allocation of e.g. 73 bytes is aligned on 8 and 128 bytes for SLUB or SLAB + * respectively. Therefore it is impossible for the allocated object to + * contiguously line up with the right guard page. + * + * However, we test that an access to memory beyond the gap results in KFENCE + * detecting an OOB access. + */ +static void test_kmalloc_aligned_oob_read(struct kunit *test) +{ + const size_t size = 73; + const size_t align = kmalloc_cache_alignment(size); + struct expect_report expect = { + .type = KFENCE_ERROR_OOB, + .fn = test_kmalloc_aligned_oob_read, + }; + char *buf; + + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_RIGHT); + + /* + * The object is offset to the right, so there won't be an OOB to the + * left of it. + */ + READ_ONCE(*(buf - 1)); + KUNIT_EXPECT_FALSE(test, report_available()); + + /* + * @buf must be aligned on @align, therefore buf + size belongs to the + * same page -> no OOB. + */ + READ_ONCE(*(buf + size)); + KUNIT_EXPECT_FALSE(test, report_available()); + + /* Overflowing by @align bytes will result in an OOB. */ + expect.addr = buf + size + align; + READ_ONCE(*expect.addr); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); + + test_free(buf); +} + +static void test_kmalloc_aligned_oob_write(struct kunit *test) +{ + const size_t size = 73; + struct expect_report expect = { + .type = KFENCE_ERROR_CORRUPTION, + .fn = test_kmalloc_aligned_oob_write, + }; + char *buf; + + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_RIGHT); + /* + * The object is offset to the right, so we won't get a page + * fault immediately after it. + */ + expect.addr = buf + size; + WRITE_ONCE(*expect.addr, READ_ONCE(*expect.addr) + 1); + KUNIT_EXPECT_FALSE(test, report_available()); + test_free(buf); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +/* Test cache shrinking and destroying with KFENCE. */ +static void test_shrink_memcache(struct kunit *test) +{ + const size_t size = 32; + void *buf; + + setup_test_cache(test, size, 0, NULL); + KUNIT_EXPECT_TRUE(test, test_cache); + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + kmem_cache_shrink(test_cache); + test_free(buf); + + KUNIT_EXPECT_FALSE(test, report_available()); +} + +static void ctor_set_x(void *obj) +{ + /* Every object has at least 8 bytes. */ + memset(obj, 'x', 8); +} + +/* Ensure that SL*B does not modify KFENCE objects on bulk free. */ +static void test_free_bulk(struct kunit *test) +{ + int iter; + + for (iter = 0; iter < 5; iter++) { + const size_t size = setup_test_cache(test, 8 + prandom_u32_max(300), 0, + (iter & 1) ? ctor_set_x : NULL); + void *objects[] = { + test_alloc(test, size, GFP_KERNEL, ALLOCATE_RIGHT), + test_alloc(test, size, GFP_KERNEL, ALLOCATE_NONE), + test_alloc(test, size, GFP_KERNEL, ALLOCATE_LEFT), + test_alloc(test, size, GFP_KERNEL, ALLOCATE_NONE), + test_alloc(test, size, GFP_KERNEL, ALLOCATE_NONE), + }; + + kmem_cache_free_bulk(test_cache, ARRAY_SIZE(objects), objects); + KUNIT_ASSERT_FALSE(test, report_available()); + test_cache_destroy(); + } +} + +/* Test init-on-free works. */ +static void test_init_on_free(struct kunit *test) +{ + const size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_UAF, + .fn = test_init_on_free, + }; + int i; + + if (!IS_ENABLED(CONFIG_INIT_ON_FREE_DEFAULT_ON)) + return; + /* Assume it hasn't been disabled on command line. */ + + setup_test_cache(test, size, 0, NULL); + expect.addr = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + for (i = 0; i < size; i++) + expect.addr[i] = i + 1; + test_free(expect.addr); + + for (i = 0; i < size; i++) { + /* + * This may fail if the page was recycled by KFENCE and then + * written to again -- this however, is near impossible with a + * default config. + */ + KUNIT_EXPECT_EQ(test, expect.addr[i], (char)0); + + if (!i) /* Only check first access to not fail test if page is ever re-protected. */ + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); + } +} + +/* Ensure that constructors work properly. */ +static void test_memcache_ctor(struct kunit *test) +{ + const size_t size = 32; + char *buf; + int i; + + setup_test_cache(test, size, 0, ctor_set_x); + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + + for (i = 0; i < 8; i++) + KUNIT_EXPECT_EQ(test, buf[i], (char)'x'); + + test_free(buf); + + KUNIT_EXPECT_FALSE(test, report_available()); +} + +/* Test that memory is zeroed if requested. */ +static void test_gfpzero(struct kunit *test) +{ + const size_t size = PAGE_SIZE; /* PAGE_SIZE so we can use ALLOCATE_ANY. */ + char *buf1, *buf2; + int i; + + if (CONFIG_KFENCE_SAMPLE_INTERVAL > 100) { + kunit_warn(test, "skipping ... would take too long\n"); + return; + } + + setup_test_cache(test, size, 0, NULL); + buf1 = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + for (i = 0; i < size; i++) + buf1[i] = i + 1; + test_free(buf1); + + /* Try to get same address again -- this can take a while. */ + for (i = 0;; i++) { + buf2 = test_alloc(test, size, GFP_KERNEL | __GFP_ZERO, ALLOCATE_ANY); + if (buf1 == buf2) + break; + test_free(buf2); + + if (i == CONFIG_KFENCE_NUM_OBJECTS) { + kunit_warn(test, "giving up ... cannot get same object back\n"); + return; + } + } + + for (i = 0; i < size; i++) + KUNIT_EXPECT_EQ(test, buf2[i], (char)0); + + test_free(buf2); + + KUNIT_EXPECT_FALSE(test, report_available()); +} + +static void test_invalid_access(struct kunit *test) +{ + const struct expect_report expect = { + .type = KFENCE_ERROR_INVALID, + .fn = test_invalid_access, + .addr = &__kfence_pool[10], + }; + + READ_ONCE(__kfence_pool[10]); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +/* Test SLAB_TYPESAFE_BY_RCU works. */ +static void test_memcache_typesafe_by_rcu(struct kunit *test) +{ + const size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_UAF, + .fn = test_memcache_typesafe_by_rcu, + }; + + setup_test_cache(test, size, SLAB_TYPESAFE_BY_RCU, NULL); + KUNIT_EXPECT_TRUE(test, test_cache); /* Want memcache. */ + + expect.addr = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY); + *expect.addr = 42; + + rcu_read_lock(); + test_free(expect.addr); + KUNIT_EXPECT_EQ(test, *expect.addr, (char)42); + /* + * Up to this point, memory should not have been freed yet, and + * therefore there should be no KFENCE report from the above access. + */ + rcu_read_unlock(); + + /* Above access to @expect.addr should not have generated a report! */ + KUNIT_EXPECT_FALSE(test, report_available()); + + /* Only after rcu_barrier() is the memory guaranteed to be freed. */ + rcu_barrier(); + + /* Expect use-after-free. */ + KUNIT_EXPECT_EQ(test, *expect.addr, (char)42); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); +} + +/* Test krealloc(). */ +static void test_krealloc(struct kunit *test) +{ + const size_t size = 32; + const struct expect_report expect = { + .type = KFENCE_ERROR_UAF, + .fn = test_krealloc, + .addr = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY), + }; + char *buf = expect.addr; + int i; + + KUNIT_EXPECT_FALSE(test, test_cache); + KUNIT_EXPECT_EQ(test, ksize(buf), size); /* Precise size match after KFENCE alloc. */ + for (i = 0; i < size; i++) + buf[i] = i + 1; + + /* Check that we successfully change the size. */ + buf = krealloc(buf, size * 3, GFP_KERNEL); /* Grow. */ + /* Note: Might no longer be a KFENCE alloc. */ + KUNIT_EXPECT_GE(test, ksize(buf), size * 3); + for (i = 0; i < size; i++) + KUNIT_EXPECT_EQ(test, buf[i], (char)(i + 1)); + for (; i < size * 3; i++) /* Fill to extra bytes. */ + buf[i] = i + 1; + + buf = krealloc(buf, size * 2, GFP_KERNEL * 2); /* Shrink. */ + KUNIT_EXPECT_GE(test, ksize(buf), size * 2); + for (i = 0; i < size * 2; i++) + KUNIT_EXPECT_EQ(test, buf[i], (char)(i + 1)); + + buf = krealloc(buf, 0, GFP_KERNEL); /* Free. */ + KUNIT_EXPECT_EQ(test, (unsigned long)buf, (unsigned long)ZERO_SIZE_PTR); + KUNIT_ASSERT_FALSE(test, report_available()); /* No reports yet! */ + + READ_ONCE(*expect.addr); /* Ensure krealloc() actually freed earlier KFENCE object. */ + KUNIT_ASSERT_TRUE(test, report_matches(&expect)); +} + +/* Test that some objects from a bulk allocation belong to KFENCE pool. */ +static void test_memcache_alloc_bulk(struct kunit *test) +{ + const size_t size = 32; + bool pass = false; + unsigned long timeout; + + setup_test_cache(test, size, 0, NULL); + KUNIT_EXPECT_TRUE(test, test_cache); /* Want memcache. */ + /* + * 100x the sample interval should be more than enough to ensure we get + * a KFENCE allocation eventually. + */ + timeout = jiffies + msecs_to_jiffies(100 * CONFIG_KFENCE_SAMPLE_INTERVAL); + do { + void *objects[100]; + int i, num = kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC, ARRAY_SIZE(objects), + objects); + if (!num) + continue; + for (i = 0; i < ARRAY_SIZE(objects); i++) { + if (is_kfence_address(objects[i])) { + pass = true; + break; + } + } + kmem_cache_free_bulk(test_cache, num, objects); + /* + * kmem_cache_alloc_bulk() disables interrupts, and calling it + * in a tight loop may not give KFENCE a chance to switch the + * static branch. Call cond_resched() to let KFENCE chime in. + */ + cond_resched(); + } while (!pass && time_before(jiffies, timeout)); + + KUNIT_EXPECT_TRUE(test, pass); + KUNIT_EXPECT_FALSE(test, report_available()); +} + +/* + * KUnit does not provide a way to provide arguments to tests, and we encode + * additional info in the name. Set up 2 tests per test case, one using the + * default allocator, and another using a custom memcache (suffix '-memcache'). + */ +#define KFENCE_KUNIT_CASE(test_name) \ + { .run_case = test_name, .name = #test_name }, \ + { .run_case = test_name, .name = #test_name "-memcache" } + +static struct kunit_case kfence_test_cases[] = { + KFENCE_KUNIT_CASE(test_out_of_bounds_read), + KFENCE_KUNIT_CASE(test_use_after_free_read), + KFENCE_KUNIT_CASE(test_double_free), + KFENCE_KUNIT_CASE(test_invalid_addr_free), + KFENCE_KUNIT_CASE(test_corruption), + KFENCE_KUNIT_CASE(test_free_bulk), + KFENCE_KUNIT_CASE(test_init_on_free), + KUNIT_CASE(test_kmalloc_aligned_oob_read), + KUNIT_CASE(test_kmalloc_aligned_oob_write), + KUNIT_CASE(test_shrink_memcache), + KUNIT_CASE(test_memcache_ctor), + KUNIT_CASE(test_invalid_access), + KUNIT_CASE(test_gfpzero), + KUNIT_CASE(test_memcache_typesafe_by_rcu), + KUNIT_CASE(test_krealloc), + KUNIT_CASE(test_memcache_alloc_bulk), + {}, +}; + +/* ===== End test cases ===== */ + +static int test_init(struct kunit *test) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&observed.lock, flags); + for (i = 0; i < ARRAY_SIZE(observed.lines); i++) + observed.lines[i][0] = '\0'; + observed.nlines = 0; + spin_unlock_irqrestore(&observed.lock, flags); + + /* Any test with 'memcache' in its name will want a memcache. */ + if (strstr(test->name, "memcache")) + test->priv = TEST_PRIV_WANT_MEMCACHE; + else + test->priv = NULL; + + return 0; +} + +static void test_exit(struct kunit *test) +{ + test_cache_destroy(); +} + +static struct kunit_suite kfence_test_suite = { + .name = "kfence", + .test_cases = kfence_test_cases, + .init = test_init, + .exit = test_exit, +}; +static struct kunit_suite *kfence_test_suites[] = { &kfence_test_suite, NULL }; + +static void register_tracepoints(struct tracepoint *tp, void *ignore) +{ + check_trace_callback_type_console(probe_console); + if (!strcmp(tp->name, "console")) + WARN_ON(tracepoint_probe_register(tp, probe_console, NULL)); +} + +static void unregister_tracepoints(struct tracepoint *tp, void *ignore) +{ + if (!strcmp(tp->name, "console")) + tracepoint_probe_unregister(tp, probe_console, NULL); +} + +/* + * We only want to do tracepoints setup and teardown once, therefore we have to + * customize the init and exit functions and cannot rely on kunit_test_suite(). + */ +static int __init kfence_test_init(void) +{ + /* + * Because we want to be able to build the test as a module, we need to + * iterate through all known tracepoints, since the static registration + * won't work here. + */ + for_each_kernel_tracepoint(register_tracepoints, NULL); + return __kunit_test_suites_init(kfence_test_suites); +} + +static void kfence_test_exit(void) +{ + __kunit_test_suites_exit(kfence_test_suites); + for_each_kernel_tracepoint(unregister_tracepoints, NULL); + tracepoint_synchronize_unregister(); +} + +late_initcall(kfence_test_init); +module_exit(kfence_test_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Potapenko , Marco Elver "); From 3b6152db165d1edc55a4c97c559745d26618d55b Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:42 +0000 Subject: [PATCH 276/306] FROMGIT: kfence: fix typo in test Fix a typo/accidental copy-paste that resulted in the obviously incorrect 'GFP_KERNEL * 2' expression. Link: https://lkml.kernel.org/r/X9lHQExmHGvETxY4@elver.google.com Signed-off-by: Marco Elver Reported-by: kernel test robot Acked-by: Alexander Potapenko Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 161c8770c371ca3992565d8f1db1ad4a88a562e9 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I4c26617c64fd2e6d410e6e793bb0eebf8fc87e55 --- mm/kfence/kfence_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c index 87b80ba1c573..0f057f9e1e67 100644 --- a/mm/kfence/kfence_test.c +++ b/mm/kfence/kfence_test.c @@ -657,7 +657,7 @@ static void test_krealloc(struct kunit *test) for (; i < size * 3; i++) /* Fill to extra bytes. */ buf[i] = i + 1; - buf = krealloc(buf, size * 2, GFP_KERNEL * 2); /* Shrink. */ + buf = krealloc(buf, size * 2, GFP_KERNEL); /* Shrink. */ KUNIT_EXPECT_GE(test, ksize(buf), size * 2); for (i = 0; i < size * 2; i++) KUNIT_EXPECT_EQ(test, buf[i], (char)(i + 1)); From 7540bb92fb8184aece25b25390902cc15a398e9d Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 22 Jan 2021 09:18:43 +0000 Subject: [PATCH 277/306] FROMGIT: kfence: show access type in report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Show the access type in KFENCE reports by plumbing through read/write information from the page fault handler. Update the documentation and test accordingly. Link: https://lkml.kernel.org/r/20210111091544.3287013-2-elver@google.com Signed-off-by: Marco Elver Suggested-by: Jörn Engel Reviewed-by: Jörn Engel Cc: Alexander Potapenko Cc: Marco Elver Cc: Dmitry Vyukov Cc: Jann Horn Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit e29117c1fbf30d27d5afe41cf34263e1fd8e4f04 https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I2e9bb224292cf92ac828232c51cd57024ac56d7d --- Documentation/dev-tools/kfence.rst | 12 ++++---- arch/arm64/mm/fault.c | 2 +- arch/x86/mm/fault.c | 3 +- include/linux/kfence.h | 9 ++++-- mm/kfence/core.c | 11 +++---- mm/kfence/kfence.h | 2 +- mm/kfence/kfence_test.c | 47 ++++++++++++++++++++++++++---- mm/kfence/report.c | 27 +++++++++++------ 8 files changed, 82 insertions(+), 31 deletions(-) diff --git a/Documentation/dev-tools/kfence.rst b/Documentation/dev-tools/kfence.rst index 0e2fb6ef3016..58a0a5fa1ddc 100644 --- a/Documentation/dev-tools/kfence.rst +++ b/Documentation/dev-tools/kfence.rst @@ -65,9 +65,9 @@ Error reports A typical out-of-bounds access looks like this:: ================================================================== - BUG: KFENCE: out-of-bounds in test_out_of_bounds_read+0xa3/0x22b + BUG: KFENCE: out-of-bounds read in test_out_of_bounds_read+0xa3/0x22b - Out-of-bounds access at 0xffffffffb672efff (1B left of kfence-#17): + Out-of-bounds read at 0xffffffffb672efff (1B left of kfence-#17): test_out_of_bounds_read+0xa3/0x22b kunit_try_run_case+0x51/0x85 kunit_generic_run_threadfn_adapter+0x16/0x30 @@ -94,9 +94,9 @@ its origin. Note that, real kernel addresses are only shown for Use-after-free accesses are reported as:: ================================================================== - BUG: KFENCE: use-after-free in test_use_after_free_read+0xb3/0x143 + BUG: KFENCE: use-after-free read in test_use_after_free_read+0xb3/0x143 - Use-after-free access at 0xffffffffb673dfe0 (in kfence-#24): + Use-after-free read at 0xffffffffb673dfe0 (in kfence-#24): test_use_after_free_read+0xb3/0x143 kunit_try_run_case+0x51/0x85 kunit_generic_run_threadfn_adapter+0x16/0x30 @@ -193,9 +193,9 @@ where it was not possible to determine an associated object, e.g. if adjacent object pages had not yet been allocated:: ================================================================== - BUG: KFENCE: invalid access in test_invalid_access+0x26/0xe0 + BUG: KFENCE: invalid read in test_invalid_access+0x26/0xe0 - Invalid access at 0xffffffffb670b00a: + Invalid read at 0xffffffffb670b00a: test_invalid_access+0x26/0xe0 kunit_try_run_case+0x51/0x85 kunit_generic_run_threadfn_adapter+0x16/0x30 diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 53cfe537da62..ae412b438122 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -328,7 +328,7 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, } else if (addr < PAGE_SIZE) { msg = "NULL pointer dereference"; } else { - if (kfence_handle_page_fault(addr, regs)) + if (kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs)) return; msg = "paging request"; diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 5c22cfa2b936..e6dc014ece01 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -803,7 +803,8 @@ no_context(struct pt_regs *regs, unsigned long error_code, efi_recover_from_page_fault(address); /* Only not-present faults should be handled by KFENCE. */ - if (!(error_code & X86_PF_PROT) && kfence_handle_page_fault(address, regs)) + if (!(error_code & X86_PF_PROT) && + kfence_handle_page_fault(address, error_code & X86_PF_WRITE, regs)) return; oops: diff --git a/include/linux/kfence.h b/include/linux/kfence.h index 5a56bcf5606c..a70d1ea03532 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -186,6 +186,7 @@ static __always_inline __must_check bool kfence_free(void *addr) /** * kfence_handle_page_fault() - perform page fault handling for KFENCE pages * @addr: faulting address + * @is_write: is access a write * @regs: current struct pt_regs (can be NULL, but shows full stack trace) * * Return: @@ -197,7 +198,7 @@ static __always_inline __must_check bool kfence_free(void *addr) * cases KFENCE prints an error message and marks the offending page as * present, so that the kernel can proceed. */ -bool __must_check kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs); +bool __must_check kfence_handle_page_fault(unsigned long addr, bool is_write, struct pt_regs *regs); #else /* CONFIG_KFENCE */ @@ -210,7 +211,11 @@ static inline size_t kfence_ksize(const void *addr) { return 0; } static inline void *kfence_object_start(const void *addr) { return NULL; } static inline void __kfence_free(void *addr) { } static inline bool __must_check kfence_free(void *addr) { return false; } -static inline bool __must_check kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs) { return false; } +static inline bool __must_check kfence_handle_page_fault(unsigned long addr, bool is_write, + struct pt_regs *regs) +{ + return false; +} #endif diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 9be94e8c136a..a1ce4f454928 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -223,7 +223,7 @@ static inline bool check_canary_byte(u8 *addr) return true; atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); - kfence_report_error((unsigned long)addr, NULL, addr_to_metadata((unsigned long)addr), + kfence_report_error((unsigned long)addr, false, NULL, addr_to_metadata((unsigned long)addr), KFENCE_ERROR_CORRUPTION); return false; } @@ -361,7 +361,8 @@ static void kfence_guarded_free(void *addr, struct kfence_metadata *meta, bool z if (meta->state != KFENCE_OBJECT_ALLOCATED || meta->addr != (unsigned long)addr) { /* Invalid or double-free, bail out. */ atomic_long_inc(&counters[KFENCE_COUNTER_BUGS]); - kfence_report_error((unsigned long)addr, NULL, meta, KFENCE_ERROR_INVALID_FREE); + kfence_report_error((unsigned long)addr, false, NULL, meta, + KFENCE_ERROR_INVALID_FREE); raw_spin_unlock_irqrestore(&meta->lock, flags); return; } @@ -770,7 +771,7 @@ void __kfence_free(void *addr) kfence_guarded_free(addr, meta, false); } -bool kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs) +bool kfence_handle_page_fault(unsigned long addr, bool is_write, struct pt_regs *regs) { const int page_index = (addr - (unsigned long)__kfence_pool) / PAGE_SIZE; struct kfence_metadata *to_report = NULL; @@ -833,11 +834,11 @@ bool kfence_handle_page_fault(unsigned long addr, struct pt_regs *regs) out: if (to_report) { - kfence_report_error(addr, regs, to_report, error_type); + kfence_report_error(addr, is_write, regs, to_report, error_type); raw_spin_unlock_irqrestore(&to_report->lock, flags); } else { /* This may be a UAF or OOB access, but we can't be sure. */ - kfence_report_error(addr, regs, NULL, KFENCE_ERROR_INVALID); + kfence_report_error(addr, is_write, regs, NULL, KFENCE_ERROR_INVALID); } return kfence_unprotect(addr); /* Unprotect and let access proceed. */ diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h index 0d83e628a97d..1accc840dbbe 100644 --- a/mm/kfence/kfence.h +++ b/mm/kfence/kfence.h @@ -105,7 +105,7 @@ enum kfence_error_type { KFENCE_ERROR_INVALID_FREE, /* Invalid free. */ }; -void kfence_report_error(unsigned long address, struct pt_regs *regs, +void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, const struct kfence_metadata *meta, enum kfence_error_type type); void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *meta); diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c index 0f057f9e1e67..bb988747e83e 100644 --- a/mm/kfence/kfence_test.c +++ b/mm/kfence/kfence_test.c @@ -71,8 +71,14 @@ struct expect_report { enum kfence_error_type type; /* The type or error. */ void *fn; /* Function pointer to expected function where access occurred. */ char *addr; /* Address at which the bad access occurred. */ + bool is_write; /* Is access a write. */ }; +static const char *get_access_type(const struct expect_report *r) +{ + return r->is_write ? "write" : "read"; +} + /* Check observed report matches information in @r. */ static bool report_matches(const struct expect_report *r) { @@ -93,16 +99,19 @@ static bool report_matches(const struct expect_report *r) end = &expect[0][sizeof(expect[0]) - 1]; switch (r->type) { case KFENCE_ERROR_OOB: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: out-of-bounds"); + cur += scnprintf(cur, end - cur, "BUG: KFENCE: out-of-bounds %s", + get_access_type(r)); break; case KFENCE_ERROR_UAF: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: use-after-free"); + cur += scnprintf(cur, end - cur, "BUG: KFENCE: use-after-free %s", + get_access_type(r)); break; case KFENCE_ERROR_CORRUPTION: cur += scnprintf(cur, end - cur, "BUG: KFENCE: memory corruption"); break; case KFENCE_ERROR_INVALID: - cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid access"); + cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid %s", + get_access_type(r)); break; case KFENCE_ERROR_INVALID_FREE: cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid free"); @@ -121,16 +130,16 @@ static bool report_matches(const struct expect_report *r) switch (r->type) { case KFENCE_ERROR_OOB: - cur += scnprintf(cur, end - cur, "Out-of-bounds access at"); + cur += scnprintf(cur, end - cur, "Out-of-bounds %s at", get_access_type(r)); break; case KFENCE_ERROR_UAF: - cur += scnprintf(cur, end - cur, "Use-after-free access at"); + cur += scnprintf(cur, end - cur, "Use-after-free %s at", get_access_type(r)); break; case KFENCE_ERROR_CORRUPTION: cur += scnprintf(cur, end - cur, "Corrupted memory at"); break; case KFENCE_ERROR_INVALID: - cur += scnprintf(cur, end - cur, "Invalid access at"); + cur += scnprintf(cur, end - cur, "Invalid %s at", get_access_type(r)); break; case KFENCE_ERROR_INVALID_FREE: cur += scnprintf(cur, end - cur, "Invalid free of"); @@ -286,6 +295,7 @@ static void test_out_of_bounds_read(struct kunit *test) struct expect_report expect = { .type = KFENCE_ERROR_OOB, .fn = test_out_of_bounds_read, + .is_write = false, }; char *buf; @@ -313,12 +323,31 @@ static void test_out_of_bounds_read(struct kunit *test) test_free(buf); } +static void test_out_of_bounds_write(struct kunit *test) +{ + size_t size = 32; + struct expect_report expect = { + .type = KFENCE_ERROR_OOB, + .fn = test_out_of_bounds_write, + .is_write = true, + }; + char *buf; + + setup_test_cache(test, size, 0, NULL); + buf = test_alloc(test, size, GFP_KERNEL, ALLOCATE_LEFT); + expect.addr = buf - 1; + WRITE_ONCE(*expect.addr, 42); + KUNIT_EXPECT_TRUE(test, report_matches(&expect)); + test_free(buf); +} + static void test_use_after_free_read(struct kunit *test) { const size_t size = 32; struct expect_report expect = { .type = KFENCE_ERROR_UAF, .fn = test_use_after_free_read, + .is_write = false, }; setup_test_cache(test, size, 0, NULL); @@ -403,6 +432,7 @@ static void test_kmalloc_aligned_oob_read(struct kunit *test) struct expect_report expect = { .type = KFENCE_ERROR_OOB, .fn = test_kmalloc_aligned_oob_read, + .is_write = false, }; char *buf; @@ -501,6 +531,7 @@ static void test_init_on_free(struct kunit *test) struct expect_report expect = { .type = KFENCE_ERROR_UAF, .fn = test_init_on_free, + .is_write = false, }; int i; @@ -590,6 +621,7 @@ static void test_invalid_access(struct kunit *test) .type = KFENCE_ERROR_INVALID, .fn = test_invalid_access, .addr = &__kfence_pool[10], + .is_write = false, }; READ_ONCE(__kfence_pool[10]); @@ -603,6 +635,7 @@ static void test_memcache_typesafe_by_rcu(struct kunit *test) struct expect_report expect = { .type = KFENCE_ERROR_UAF, .fn = test_memcache_typesafe_by_rcu, + .is_write = false, }; setup_test_cache(test, size, SLAB_TYPESAFE_BY_RCU, NULL); @@ -639,6 +672,7 @@ static void test_krealloc(struct kunit *test) .type = KFENCE_ERROR_UAF, .fn = test_krealloc, .addr = test_alloc(test, size, GFP_KERNEL, ALLOCATE_ANY), + .is_write = false, }; char *buf = expect.addr; int i; @@ -720,6 +754,7 @@ static void test_memcache_alloc_bulk(struct kunit *test) static struct kunit_case kfence_test_cases[] = { KFENCE_KUNIT_CASE(test_out_of_bounds_read), + KFENCE_KUNIT_CASE(test_out_of_bounds_write), KFENCE_KUNIT_CASE(test_use_after_free_read), KFENCE_KUNIT_CASE(test_double_free), KFENCE_KUNIT_CASE(test_invalid_addr_free), diff --git a/mm/kfence/report.c b/mm/kfence/report.c index 4dbfa9a382e4..901bd7ee83d8 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -156,7 +156,12 @@ static void print_diff_canary(unsigned long address, size_t bytes_to_show, pr_cont(" ]"); } -void kfence_report_error(unsigned long address, struct pt_regs *regs, +static const char *get_access_type(bool is_write) +{ + return is_write ? "write" : "read"; +} + +void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *regs, const struct kfence_metadata *meta, enum kfence_error_type type) { unsigned long stack_entries[KFENCE_STACK_DEPTH] = { 0 }; @@ -194,17 +199,19 @@ void kfence_report_error(unsigned long address, struct pt_regs *regs, case KFENCE_ERROR_OOB: { const bool left_of_object = address < meta->addr; - pr_err("BUG: KFENCE: out-of-bounds in %pS\n\n", (void *)stack_entries[skipnr]); - pr_err("Out-of-bounds access at 0x" PTR_FMT " (%luB %s of kfence-#%zd):\n", - (void *)address, + pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write), + (void *)stack_entries[skipnr]); + pr_err("Out-of-bounds %s at 0x" PTR_FMT " (%luB %s of kfence-#%zd):\n", + get_access_type(is_write), (void *)address, left_of_object ? meta->addr - address : address - meta->addr, left_of_object ? "left" : "right", object_index); break; } case KFENCE_ERROR_UAF: - pr_err("BUG: KFENCE: use-after-free in %pS\n\n", (void *)stack_entries[skipnr]); - pr_err("Use-after-free access at 0x" PTR_FMT " (in kfence-#%zd):\n", - (void *)address, object_index); + pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write), + (void *)stack_entries[skipnr]); + pr_err("Use-after-free %s at 0x" PTR_FMT " (in kfence-#%zd):\n", + get_access_type(is_write), (void *)address, object_index); break; case KFENCE_ERROR_CORRUPTION: pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]); @@ -213,8 +220,10 @@ void kfence_report_error(unsigned long address, struct pt_regs *regs, pr_cont(" (in kfence-#%zd):\n", object_index); break; case KFENCE_ERROR_INVALID: - pr_err("BUG: KFENCE: invalid access in %pS\n\n", (void *)stack_entries[skipnr]); - pr_err("Invalid access at 0x" PTR_FMT ":\n", (void *)address); + pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write), + (void *)stack_entries[skipnr]); + pr_err("Invalid %s at 0x" PTR_FMT ":\n", get_access_type(is_write), + (void *)address); break; case KFENCE_ERROR_INVALID_FREE: pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]); From 741d9ecaccee02ecebff10ae1168ddf1b97ea372 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:44 +0000 Subject: [PATCH 278/306] FROMGIT: tracing: add error_report_end trace point Patch series "Add error_report_end tracepoint to KFENCE and KASAN", v3. This patchset adds a tracepoint, error_repor_end, that is to be used by KFENCE, KASAN, and potentially other bug detection tools, when they print an error report. One of the possible use cases is userspace collection of kernel error reports: interested parties can subscribe to the tracing event via tracefs, and get notified when an error report occurs. This patch (of 3): Introduce error_report_end tracepoint. It can be used in debugging tools like KASAN, KFENCE, etc. to provide extensions to the error reporting mechanisms (e.g. allow tests hook into error reporting, ease error report collection from production kernels). Another benefit would be making use of ftrace for debugging or benchmarking the tools themselves. Should we need it, the tracepoint name leaves us with the possibility to introduce a complementary error_report_start tracepoint in the future. Link: https://lkml.kernel.org/r/20210121131915.1331302-1-glider@google.com Link: https://lkml.kernel.org/r/20210121131915.1331302-2-glider@google.com Signed-off-by: Alexander Potapenko Suggested-by: Marco Elver Cc: Andrey Konovalov Cc: Dmitry Vyukov Cc: Ingo Molnar Cc: Petr Mladek Cc: Steven Rostedt Cc: Sergey Senozhatsky Cc: Greg Kroah-Hartman Cc: Vlastimil Babka Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit ba7612c00686f204f7bca4ceb7394a9e705e84bd https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: Ic86e29982c04dad4b3b7889a424f37b22cc5f22b --- include/trace/events/error_report.h | 74 +++++++++++++++++++++++++++++ kernel/trace/Makefile | 1 + kernel/trace/error_report-traces.c | 12 +++++ 3 files changed, 87 insertions(+) create mode 100644 include/trace/events/error_report.h create mode 100644 kernel/trace/error_report-traces.c diff --git a/include/trace/events/error_report.h b/include/trace/events/error_report.h new file mode 100644 index 000000000000..96f64bf218b2 --- /dev/null +++ b/include/trace/events/error_report.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Declarations for error reporting tracepoints. + * + * Copyright (C) 2021, Google LLC. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM error_report + +#if !defined(_TRACE_ERROR_REPORT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_ERROR_REPORT_H + +#include + +#ifndef __ERROR_REPORT_DECLARE_TRACE_ENUMS_ONCE_ONLY +#define __ERROR_REPORT_DECLARE_TRACE_ENUMS_ONCE_ONLY + +enum error_detector { + ERROR_DETECTOR_KFENCE, + ERROR_DETECTOR_KASAN +}; + +#endif /* __ERROR_REPORT_DECLARE_TRACE_ENUMS_ONCE_ONLY */ + +#define error_detector_list \ + EM(ERROR_DETECTOR_KFENCE, "kfence") \ + EMe(ERROR_DETECTOR_KASAN, "kasan") +/* Always end the list with an EMe. */ + +#undef EM +#undef EMe + +#define EM(a, b) TRACE_DEFINE_ENUM(a); +#define EMe(a, b) TRACE_DEFINE_ENUM(a); + +error_detector_list + +#undef EM +#undef EMe + +#define EM(a, b) { a, b }, +#define EMe(a, b) { a, b } + +#define show_error_detector_list(val) \ + __print_symbolic(val, error_detector_list) + +DECLARE_EVENT_CLASS(error_report_template, + TP_PROTO(enum error_detector error_detector, unsigned long id), + TP_ARGS(error_detector, id), + TP_STRUCT__entry(__field(enum error_detector, error_detector) + __field(unsigned long, id)), + TP_fast_assign(__entry->error_detector = error_detector; + __entry->id = id;), + TP_printk("[%s] %lx", + show_error_detector_list(__entry->error_detector), + __entry->id)); + +/** + * error_report_end - called after printing the error report + * @error_detector: short string describing the error detection tool + * @id: pseudo-unique descriptor identifying the report + * (e.g. the memory access address) + * + * This event occurs right after a debugging tool finishes printing the error + * report. + */ +DEFINE_EVENT(error_report_template, error_report_end, + TP_PROTO(enum error_detector error_detector, unsigned long id), + TP_ARGS(error_detector, id)); + +#endif /* _TRACE_ERROR_REPORT_H */ + +/* This part must be outside protection */ +#include diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile index 3f30b6c2d659..d09dfa4226b8 100644 --- a/kernel/trace/Makefile +++ b/kernel/trace/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_EVENT_TRACING) += trace_events_trigger.o obj-$(CONFIG_HIST_TRIGGERS) += trace_events_hist.o obj-$(CONFIG_BPF_EVENTS) += bpf_trace.o obj-$(CONFIG_KPROBE_EVENTS) += trace_kprobe.o +obj-$(CONFIG_TRACEPOINTS) += error_report-traces.o obj-$(CONFIG_TRACEPOINTS) += power-traces.o ifeq ($(CONFIG_PM),y) obj-$(CONFIG_TRACEPOINTS) += rpm-traces.o diff --git a/kernel/trace/error_report-traces.c b/kernel/trace/error_report-traces.c new file mode 100644 index 000000000000..632c8c7ff079 --- /dev/null +++ b/kernel/trace/error_report-traces.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Error reporting trace points. + * + * Copyright (C) 2021, Google LLC. + */ + +#define CREATE_TRACE_POINTS +#include + +EXPORT_TRACEPOINT_SYMBOL_GPL(error_report_end); + From 614a75eabd1290877d2208854c7eb24ef484597b Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:44 +0000 Subject: [PATCH 279/306] FROMGIT: kfence: use error_report_end tracepoint Make it possible to trace KFENCE error reporting. A good usecase is watching for trace events from the userspace to detect and process memory corruption reports from the kernel. Link: https://lkml.kernel.org/r/20210121131915.1331302-3-glider@google.com Signed-off-by: Alexander Potapenko Suggested-by: Marco Elver Cc: Andrey Konovalov Cc: Dmitry Vyukov Cc: Ingo Molnar Cc: Petr Mladek Cc: Steven Rostedt Cc: Sergey Senozhatsky Cc: Vlastimil Babka Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 2eb9559621418b844b29d2b56d9962ac019f600b https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I991cd1eee48d107bcdf5e1c0d9194e6a386b9bdf --- mm/kfence/report.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/kfence/report.c b/mm/kfence/report.c index 901bd7ee83d8..f9fc93b2fe2e 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -246,6 +247,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r show_regs(regs); else dump_stack_print_info(KERN_ERR); + trace_error_report_end(ERROR_DETECTOR_KFENCE, address); pr_err("==================================================================\n"); lockdep_on(); From 763c4060385deb378b939f62edb6cd6fa89263d4 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 22 Jan 2021 09:18:45 +0000 Subject: [PATCH 280/306] BACKPORT: kasan: use error_report_end tracepoint Make it possible to trace KASAN error reporting. A good usecase is watching for trace events from the userspace to detect and process memory corruption reports from the kernel. Link: https://lkml.kernel.org/r/20210121131915.1331302-4-glider@google.com Signed-off-by: Alexander Potapenko Suggested-by: Marco Elver Cc: Andrey Konovalov Cc: Dmitry Vyukov Cc: Ingo Molnar Cc: Petr Mladek Cc: Steven Rostedt Cc: Sergey Senozhatsky Cc: Greg Kroah-Hartman Cc: Vlastimil Babka Signed-off-by: Andrew Morton Bug: 177201466 (cherry picked from commit 99bbc9fba9b0c8956b817dd21ecb510da8b676dc https://github.com/hnaz/linux-mm v5.11-rc4-mmots-2021-01-21-20-10) [glider: resolved conflicts in mm/kasan/report.c] Test: CONFIG_KFENCE_KUNIT_TEST=y passes on Cuttlefish Signed-off-by: Alexander Potapenko Change-Id: I60ca062373d13f08ed4ed05bee341a8c28619407 --- mm/kasan/report.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 4d87df96acc1..783301f294de 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -87,8 +88,9 @@ static void start_report(unsigned long *flags) pr_err("==================================================================\n"); } -static void end_report(unsigned long *flags) +static void end_report(unsigned long *flags, unsigned long addr) { + trace_error_report_end(ERROR_DETECTOR_KASAN, addr); pr_err("==================================================================\n"); add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); spin_unlock_irqrestore(&report_lock, *flags); @@ -468,7 +470,7 @@ void kasan_report_invalid_free(void *object, unsigned long ip) print_address_description(object, tag); pr_err("\n"); print_shadow_for_address(object); - end_report(&flags); + end_report(&flags, (unsigned long)object); } void __kasan_report(unsigned long addr, size_t size, bool is_write, unsigned long ip) @@ -510,5 +512,5 @@ void __kasan_report(unsigned long addr, size_t size, bool is_write, unsigned lon dump_stack(); } - end_report(&flags); + end_report(&flags, addr); } From 0da2ef239476b48b0883f17af985d4cc212b22a8 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Sun, 14 Feb 2021 10:13:46 -0600 Subject: [PATCH 281/306] UPSTREAM: lib: use KSTM_MODULE_GLOBALS macro in kselftest drivers Instead of defining the total/failed test counters manually, test drivers that are clients of kselftest should use the macro created for this purpose. Signed-off-by: Timur Tabi Reviewed-by: Petr Mladek Acked-by: Marco Elver Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20210214161348.369023-2-timur@kernel.org Bug: 177201466 Bug: 180086542 (cherry picked from commit 4e89a78779647ca7ee2967551c599633fe9d3647) Signed-off-by: Alexander Potapenko Change-Id: I5d60024e8214548ef1ee3a4e48b0dbc50a8adde9 --- lib/test_bitmap.c | 3 +-- lib/test_printf.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 51a98f7ee79e..1ee9d95898b5 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -16,8 +16,7 @@ #include "../tools/testing/selftests/kselftest_module.h" -static unsigned total_tests __initdata; -static unsigned failed_tests __initdata; +KSTM_MODULE_GLOBALS(); static char pbl_buffer[PAGE_SIZE] __initdata; diff --git a/lib/test_printf.c b/lib/test_printf.c index d4b711b53942..0f28f7a00684 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -28,8 +28,8 @@ #define PAD_SIZE 16 #define FILL_CHAR '$' -static unsigned total_tests __initdata; -static unsigned failed_tests __initdata; +KSTM_MODULE_GLOBALS(); + static char *test_buffer __initdata; static char *alloced_buffer __initdata; From f2d2bc78482a800ea145e69db344434ae4993275 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Sun, 14 Feb 2021 10:13:47 -0600 Subject: [PATCH 282/306] UPSTREAM: kselftest: add support for skipped tests Update the kselftest framework to allow client drivers to specify that some tests were skipped. Signed-off-by: Timur Tabi Reviewed-by: Petr Mladek Tested-by: Petr Mladek Acked-by: Marco Elver Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20210214161348.369023-3-timur@kernel.org Bug: 177201466 Bug: 180086542 (cherry picked from commit d9d4de2309cd1721421c6488f1bb5744d2c83a39) Signed-off-by: Alexander Potapenko Change-Id: Ifbfd5c75c207d9491dd8d7d5133ea30d12a85b12 --- tools/testing/selftests/kselftest_module.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kselftest_module.h b/tools/testing/selftests/kselftest_module.h index e8eafaf0941a..e2ea41de3f35 100644 --- a/tools/testing/selftests/kselftest_module.h +++ b/tools/testing/selftests/kselftest_module.h @@ -11,7 +11,8 @@ #define KSTM_MODULE_GLOBALS() \ static unsigned int total_tests __initdata; \ -static unsigned int failed_tests __initdata +static unsigned int failed_tests __initdata; \ +static unsigned int skipped_tests __initdata #define KSTM_CHECK_ZERO(x) do { \ total_tests++; \ @@ -21,11 +22,16 @@ static unsigned int failed_tests __initdata } \ } while (0) -static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests) +static inline int kstm_report(unsigned int total_tests, unsigned int failed_tests, + unsigned int skipped_tests) { - if (failed_tests == 0) - pr_info("all %u tests passed\n", total_tests); - else + if (failed_tests == 0) { + if (skipped_tests) { + pr_info("skipped %u tests\n", skipped_tests); + pr_info("remaining %u tests passed\n", total_tests); + } else + pr_info("all %u tests passed\n", total_tests); + } else pr_warn("failed %u out of %u tests\n", failed_tests, total_tests); return failed_tests ? -EINVAL : 0; @@ -36,7 +42,7 @@ static int __init __module##_init(void) \ { \ pr_info("loaded.\n"); \ selftest(); \ - return kstm_report(total_tests, failed_tests); \ + return kstm_report(total_tests, failed_tests, skipped_tests); \ } \ static void __exit __module##_exit(void) \ { \ From b25c7b6b0f9535a9313e0ba998dba335fa7b930f Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Sun, 14 Feb 2021 10:13:48 -0600 Subject: [PATCH 283/306] UPSTREAM: lib/vsprintf: no_hash_pointers prints all addresses as unhashed If the no_hash_pointers command line parameter is set, then printk("%p") will print pointers as unhashed, which is useful for debugging purposes. This change applies to any function that uses vsprintf, such as print_hex_dump() and seq_buf_printf(). A large warning message is displayed if this option is enabled. Unhashed pointers expose kernel addresses, which can be a security risk. Also update test_printf to skip the hashed pointer tests if the command-line option is set. Signed-off-by: Timur Tabi Acked-by: Petr Mladek Acked-by: Randy Dunlap Acked-by: Sergey Senozhatsky Acked-by: Vlastimil Babka Acked-by: Marco Elver Signed-off-by: Petr Mladek Link: https://lore.kernel.org/r/20210214161348.369023-4-timur@kernel.org Bug: 177201466 Bug: 180086542 (cherry picked from commit 5ead723a20e0447bc7db33dc3070b420e5f80aa6) Signed-off-by: Alexander Potapenko Change-Id: I9680bb5e076da9f766a66e6076e5c39291188e40 --- .../admin-guide/kernel-parameters.txt | 15 ++++++++ lib/test_printf.c | 8 +++++ lib/vsprintf.c | 36 +++++++++++++++++-- 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 25443c227e27..c33eb805ec85 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3187,6 +3187,21 @@ in certain environments such as networked servers or real-time systems. + no_hash_pointers + Force pointers printed to the console or buffers to be + unhashed. By default, when a pointer is printed via %p + format string, that pointer is "hashed", i.e. obscured + by hashing the pointer value. This is a security feature + that hides actual kernel addresses from unprivileged + users, but it also makes debugging the kernel more + difficult since unequal pointers can no longer be + compared. However, if this command-line option is + specified, then all normal pointers will have their true + value printed. Pointers printed via %pK may still be + hashed. This option should only be specified when + debugging the kernel. Please do not use on production + kernels. + nohibernate [HIBERNATION] Disable hibernation and resume. nohz= [KNL] Boottime enable/disable dynamic ticks diff --git a/lib/test_printf.c b/lib/test_printf.c index 0f28f7a00684..0a3153f162c7 100644 --- a/lib/test_printf.c +++ b/lib/test_printf.c @@ -33,6 +33,8 @@ KSTM_MODULE_GLOBALS(); static char *test_buffer __initdata; static char *alloced_buffer __initdata; +extern bool no_hash_pointers; + static int __printf(4, 0) __init do_test(int bufsize, const char *expect, int elen, const char *fmt, va_list ap) @@ -299,6 +301,12 @@ plain(void) { int err; + if (no_hash_pointers) { + pr_warn("skipping plain 'p' tests"); + skipped_tests += 2; + return; + } + err = plain_hash(); if (err) { pr_warn("plain 'p' does not appear to be hashed\n"); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d377456b8c39..f3d84136199b 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -2057,6 +2057,32 @@ static char *kobject_string(char *buf, char *end, void *ptr, return error_string(buf, end, "(%pO?)", spec); } +/* Disable pointer hashing if requested */ +bool no_hash_pointers __ro_after_init; +EXPORT_SYMBOL_GPL(no_hash_pointers); + +static int __init no_hash_pointers_enable(char *str) +{ + no_hash_pointers = true; + + pr_warn("**********************************************************\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("** **\n"); + pr_warn("** This system shows unhashed kernel memory addresses **\n"); + pr_warn("** via the console, logs, and other interfaces. This **\n"); + pr_warn("** might reduce the security of your system. **\n"); + pr_warn("** **\n"); + pr_warn("** If you see this message and you are not debugging **\n"); + pr_warn("** the kernel, report this immediately to your system **\n"); + pr_warn("** administrator! **\n"); + pr_warn("** **\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("**********************************************************\n"); + + return 0; +} +early_param("no_hash_pointers", no_hash_pointers_enable); + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -2259,8 +2285,14 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, if (IS_ENABLED(CONFIG_DEBUG_CONSOLE_UNHASHED_POINTERS)) return pointer_string(buf, end, ptr, spec); - /* default is to _not_ leak addresses, hash before printing */ - return ptr_to_id(buf, end, ptr, spec); + /* + * default is to _not_ leak addresses, so hash before printing, + * unless no_hash_pointers is specified on the command line. + */ + if (unlikely(no_hash_pointers)) + return pointer_string(buf, end, ptr, spec); + else + return ptr_to_id(buf, end, ptr, spec); } /* From 5f44e5ced3643c2081496614e53dc23e6ab22469 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 25 Feb 2021 17:19:40 -0800 Subject: [PATCH 284/306] UPSTREAM: kfence: report sensitive information based on no_hash_pointers We cannot rely on CONFIG_DEBUG_KERNEL to decide if we're running a "debug kernel" where we can safely show potentially sensitive information in the kernel log. Instead, simply rely on the newly introduced "no_hash_pointers" to print unhashed kernel pointers, as well as decide if our reports can include other potentially sensitive information such as registers and corrupted bytes. Link: https://lkml.kernel.org/r/20210223082043.1972742-1-elver@google.com Signed-off-by: Marco Elver Cc: Timur Tabi Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Jann Horn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 177201466 Bug: 180086542 (cherry picked from commit 35beccf0926d42ee0d56e41979ec8cdf814c4769) Signed-off-by: Alexander Potapenko Change-Id: Ie76403ee1b902742a6ac300ad13bd117a02f93f1 --- Documentation/dev-tools/kfence.rst | 8 ++++---- mm/kfence/core.c | 10 +++------- mm/kfence/kfence.h | 7 ------- mm/kfence/kfence_test.c | 2 +- mm/kfence/report.c | 18 ++++++++++-------- 5 files changed, 18 insertions(+), 27 deletions(-) diff --git a/Documentation/dev-tools/kfence.rst b/Documentation/dev-tools/kfence.rst index 58a0a5fa1ddc..fdf04e741ea5 100644 --- a/Documentation/dev-tools/kfence.rst +++ b/Documentation/dev-tools/kfence.rst @@ -88,8 +88,8 @@ A typical out-of-bounds access looks like this:: The header of the report provides a short summary of the function involved in the access. It is followed by more detailed information about the access and -its origin. Note that, real kernel addresses are only shown for -``CONFIG_DEBUG_KERNEL=y`` builds. +its origin. Note that, real kernel addresses are only shown when using the +kernel command line option ``no_hash_pointers``. Use-after-free accesses are reported as:: @@ -184,8 +184,8 @@ invalidly written bytes (offset from the address) are shown; in this representation, '.' denote untouched bytes. In the example above ``0xac`` is the value written to the invalid address at offset 0, and the remaining '.' denote that no following bytes have been touched. Note that, real values are -only shown for ``CONFIG_DEBUG_KERNEL=y`` builds; to avoid information -disclosure for non-debug builds, '!' is used instead to denote invalidly +only shown if the kernel was booted with ``no_hash_pointers``; to avoid +information disclosure otherwise, '!' is used instead to denote invalidly written bytes. And finally, KFENCE may also report on invalid accesses to any protected page diff --git a/mm/kfence/core.c b/mm/kfence/core.c index a1ce4f454928..f29400a8c5e4 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -646,13 +646,9 @@ void __init kfence_init(void) WRITE_ONCE(kfence_enabled, true); schedule_delayed_work(&kfence_timer, 0); - pr_info("initialized - using %lu bytes for %d objects", KFENCE_POOL_SIZE, - CONFIG_KFENCE_NUM_OBJECTS); - if (IS_ENABLED(CONFIG_DEBUG_KERNEL)) - pr_cont(" at 0x%px-0x%px\n", (void *)__kfence_pool, - (void *)(__kfence_pool + KFENCE_POOL_SIZE)); - else - pr_cont("\n"); + pr_info("initialized - using %lu bytes for %d objects at 0x%p-0x%p\n", KFENCE_POOL_SIZE, + CONFIG_KFENCE_NUM_OBJECTS, (void *)__kfence_pool, + (void *)(__kfence_pool + KFENCE_POOL_SIZE)); } void kfence_shutdown_cache(struct kmem_cache *s) diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h index 1accc840dbbe..24065321ff8a 100644 --- a/mm/kfence/kfence.h +++ b/mm/kfence/kfence.h @@ -16,13 +16,6 @@ #include "../slab.h" /* for struct kmem_cache */ -/* For non-debug builds, avoid leaking kernel pointers into dmesg. */ -#ifdef CONFIG_DEBUG_KERNEL -#define PTR_FMT "%px" -#else -#define PTR_FMT "%p" -#endif - /* * Get the canary byte pattern for @addr. Use a pattern that varies based on the * lower 3 bits of the address, to detect memory corruptions with higher diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c index bb988747e83e..9c9d74dc8497 100644 --- a/mm/kfence/kfence_test.c +++ b/mm/kfence/kfence_test.c @@ -146,7 +146,7 @@ static bool report_matches(const struct expect_report *r) break; } - cur += scnprintf(cur, end - cur, " 0x" PTR_FMT, (void *)r->addr); + cur += scnprintf(cur, end - cur, " 0x%p", (void *)r->addr); spin_lock_irqsave(&observed.lock, flags); if (!report_available()) diff --git a/mm/kfence/report.c b/mm/kfence/report.c index f9fc93b2fe2e..ab83d5a59bb1 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -20,6 +20,8 @@ #include "kfence.h" +extern bool no_hash_pointers; + /* Helper function to either print to a seq_file or to console. */ __printf(2, 3) static void seq_con_printf(struct seq_file *seq, const char *fmt, ...) @@ -119,7 +121,7 @@ void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *met } seq_con_printf(seq, - "kfence-#%zd [0x" PTR_FMT "-0x" PTR_FMT + "kfence-#%zd [0x%p-0x%p" ", size=%d, cache=%s] allocated by task %d:\n", meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size, (cache && cache->name) ? cache->name : "", meta->alloc_track.pid); @@ -149,7 +151,7 @@ static void print_diff_canary(unsigned long address, size_t bytes_to_show, for (cur = (const u8 *)address; cur < end; cur++) { if (*cur == KFENCE_CANARY_PATTERN(cur)) pr_cont(" ."); - else if (IS_ENABLED(CONFIG_DEBUG_KERNEL)) + else if (no_hash_pointers) pr_cont(" 0x%02x", *cur); else /* Do not leak kernel memory in non-debug builds. */ pr_cont(" !"); @@ -202,7 +204,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write), (void *)stack_entries[skipnr]); - pr_err("Out-of-bounds %s at 0x" PTR_FMT " (%luB %s of kfence-#%zd):\n", + pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%zd):\n", get_access_type(is_write), (void *)address, left_of_object ? meta->addr - address : address - meta->addr, left_of_object ? "left" : "right", object_index); @@ -211,24 +213,24 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r case KFENCE_ERROR_UAF: pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write), (void *)stack_entries[skipnr]); - pr_err("Use-after-free %s at 0x" PTR_FMT " (in kfence-#%zd):\n", + pr_err("Use-after-free %s at 0x%p (in kfence-#%zd):\n", get_access_type(is_write), (void *)address, object_index); break; case KFENCE_ERROR_CORRUPTION: pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]); - pr_err("Corrupted memory at 0x" PTR_FMT " ", (void *)address); + pr_err("Corrupted memory at 0x%p ", (void *)address); print_diff_canary(address, 16, meta); pr_cont(" (in kfence-#%zd):\n", object_index); break; case KFENCE_ERROR_INVALID: pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write), (void *)stack_entries[skipnr]); - pr_err("Invalid %s at 0x" PTR_FMT ":\n", get_access_type(is_write), + pr_err("Invalid %s at 0x%p:\n", get_access_type(is_write), (void *)address); break; case KFENCE_ERROR_INVALID_FREE: pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]); - pr_err("Invalid free of 0x" PTR_FMT " (in kfence-#%zd):\n", (void *)address, + pr_err("Invalid free of 0x%p (in kfence-#%zd):\n", (void *)address, object_index); break; } @@ -243,7 +245,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r /* Print report footer. */ pr_err("\n"); - if (IS_ENABLED(CONFIG_DEBUG_KERNEL) && regs) + if (no_hash_pointers && regs) show_regs(regs); else dump_stack_print_info(KERN_ERR); From 7e67299a8b6791c037483f3b8ef19c3c23a9daa6 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 12 Mar 2021 21:07:50 -0800 Subject: [PATCH 285/306] UPSTREAM: kfence: fix printk format for ptrdiff_t Use %td for ptrdiff_t. Link: https://lkml.kernel.org/r/3abbe4c9-16ad-c168-a90f-087978ccd8f7@csgroup.eu Link: https://lkml.kernel.org/r/20210303121157.3430807-1-elver@google.com Signed-off-by: Marco Elver Reported-by: Christophe Leroy Reviewed-by: Alexander Potapenko Cc: Dmitriy Vyukov Cc: Andrey Konovalov Cc: Jann Horn Cc: Christophe Leroy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 172317151 Test: build and run on an ARM64 device (cherry picked from commit 702b16d724a61cb97461f403d7a2da29324471b3) Signed-off-by: Alexander Potapenko Change-Id: I49c7a8ed6dfecceafd4e25e979c6dd58b1d2dbe2 --- mm/kfence/report.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mm/kfence/report.c b/mm/kfence/report.c index ab83d5a59bb1..519f037720f5 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -116,12 +116,12 @@ void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *met lockdep_assert_held(&meta->lock); if (meta->state == KFENCE_OBJECT_UNUSED) { - seq_con_printf(seq, "kfence-#%zd unused\n", meta - kfence_metadata); + seq_con_printf(seq, "kfence-#%td unused\n", meta - kfence_metadata); return; } seq_con_printf(seq, - "kfence-#%zd [0x%p-0x%p" + "kfence-#%td [0x%p-0x%p" ", size=%d, cache=%s] allocated by task %d:\n", meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size, (cache && cache->name) ? cache->name : "", meta->alloc_track.pid); @@ -204,7 +204,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write), (void *)stack_entries[skipnr]); - pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%zd):\n", + pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%td):\n", get_access_type(is_write), (void *)address, left_of_object ? meta->addr - address : address - meta->addr, left_of_object ? "left" : "right", object_index); @@ -213,14 +213,14 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r case KFENCE_ERROR_UAF: pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write), (void *)stack_entries[skipnr]); - pr_err("Use-after-free %s at 0x%p (in kfence-#%zd):\n", + pr_err("Use-after-free %s at 0x%p (in kfence-#%td):\n", get_access_type(is_write), (void *)address, object_index); break; case KFENCE_ERROR_CORRUPTION: pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]); pr_err("Corrupted memory at 0x%p ", (void *)address); print_diff_canary(address, 16, meta); - pr_cont(" (in kfence-#%zd):\n", object_index); + pr_cont(" (in kfence-#%td):\n", object_index); break; case KFENCE_ERROR_INVALID: pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write), @@ -230,7 +230,7 @@ void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r break; case KFENCE_ERROR_INVALID_FREE: pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]); - pr_err("Invalid free of 0x%p (in kfence-#%zd):\n", (void *)address, + pr_err("Invalid free of 0x%p (in kfence-#%td):\n", (void *)address, object_index); break; } From 6edcf5510c9a4b78913d508fe4c0f6b445a7f576 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 12 Mar 2021 21:08:00 -0800 Subject: [PATCH 286/306] UPSTREAM: kfence: fix reports if constant function prefixes exist Some architectures prefix all functions with a constant string ('.' on ppc64). Add ARCH_FUNC_PREFIX, which may optionally be defined in , so that get_stack_skipnr() can work properly. Link: https://lkml.kernel.org/r/f036c53d-7e81-763c-47f4-6024c6c5f058@csgroup.eu Link: https://lkml.kernel.org/r/20210304144000.1148590-1-elver@google.com Signed-off-by: Marco Elver Reported-by: Christophe Leroy Tested-by: Christophe Leroy Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Jann Horn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 172317151 Test: build and run on an ARM64 device (cherry picked from commit 0aa41cae92c1e2e61ae5b3a2dde8e674172e40ac) Signed-off-by: Alexander Potapenko Change-Id: Iad99dd75be77c26359723d1336e2d1b25beb5a26 --- mm/kfence/report.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/mm/kfence/report.c b/mm/kfence/report.c index 519f037720f5..e3f71451ad9e 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -20,6 +20,11 @@ #include "kfence.h" +/* May be overridden by . */ +#ifndef ARCH_FUNC_PREFIX +#define ARCH_FUNC_PREFIX "" +#endif + extern bool no_hash_pointers; /* Helper function to either print to a seq_file or to console. */ @@ -67,8 +72,9 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries for (skipnr = 0; skipnr < num_entries; skipnr++) { int len = scnprintf(buf, sizeof(buf), "%ps", (void *)stack_entries[skipnr]); - if (str_has_prefix(buf, "kfence_") || str_has_prefix(buf, "__kfence_") || - !strncmp(buf, "__slab_free", len)) { + if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfence_") || + str_has_prefix(buf, ARCH_FUNC_PREFIX "__kfence_") || + !strncmp(buf, ARCH_FUNC_PREFIX "__slab_free", len)) { /* * In case of tail calls from any of the below * to any of the above. @@ -77,10 +83,10 @@ static int get_stack_skipnr(const unsigned long stack_entries[], int num_entries } /* Also the *_bulk() variants by only checking prefixes. */ - if (str_has_prefix(buf, "kfree") || - str_has_prefix(buf, "kmem_cache_free") || - str_has_prefix(buf, "__kmalloc") || - str_has_prefix(buf, "kmem_cache_alloc")) + if (str_has_prefix(buf, ARCH_FUNC_PREFIX "kfree") || + str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_free") || + str_has_prefix(buf, ARCH_FUNC_PREFIX "__kmalloc") || + str_has_prefix(buf, ARCH_FUNC_PREFIX "kmem_cache_alloc")) goto found; } if (fallback < num_entries) From ee44b646ff5549fe8e3bc9534689ded56ff081ce Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Wed, 24 Mar 2021 21:37:47 -0700 Subject: [PATCH 287/306] UPSTREAM: kfence: make compatible with kmemleak Because memblock allocations are registered with kmemleak, the KFENCE pool was seen by kmemleak as one large object. Later allocations through kfence_alloc() that were registered with kmemleak via slab_post_alloc_hook() would then overlap and trigger a warning. Therefore, once the pool is initialized, we can remove (free) it from kmemleak again, since it should be treated as allocator-internal and be seen as "free memory". The second problem is that kmemleak is passed the rounded size, and not the originally requested size, which is also the size of KFENCE objects. To avoid kmemleak scanning past the end of an object and trigger a KFENCE out-of-bounds error, fix the size if it is a KFENCE object. For simplicity, to avoid a call to kfence_ksize() in slab_post_alloc_hook() (and avoid new IS_ENABLED(CONFIG_DEBUG_KMEMLEAK) guard), just call kfence_ksize() in mm/kmemleak.c:create_object(). Link: https://lkml.kernel.org/r/20210317084740.3099921-1-elver@google.com Signed-off-by: Marco Elver Reported-by: Luis Henriques Reviewed-by: Catalin Marinas Tested-by: Luis Henriques Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Jann Horn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Bug: 172317151 Test: build and run on an ARM64 device (cherry picked from commit 9551158069ba8fcc893798d42dc4f978b62ef60f) Signed-off-by: Alexander Potapenko Change-Id: Ida4d747d3b81b5e8a6f1047b864da89e8e110e61 --- mm/kfence/core.c | 9 +++++++++ mm/kmemleak.c | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index f29400a8c5e4..04195cb85e52 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -480,6 +481,14 @@ static bool __init kfence_init_pool(void) addr += 2 * PAGE_SIZE; } + /* + * The pool is live and will never be deallocated from this point on. + * Remove the pool object from the kmemleak object tree, as it would + * otherwise overlap with allocations returned by kfence_alloc(), which + * are registered with kmemleak through the slab post-alloc hook. + */ + kmemleak_free(__kfence_pool); + return true; err: diff --git a/mm/kmemleak.c b/mm/kmemleak.c index a7fc6b23c37e..dce9e2a42549 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -97,6 +97,7 @@ #include #include +#include #include #include @@ -592,7 +593,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size, atomic_set(&object->use_count, 1); object->flags = OBJECT_ALLOCATED; object->pointer = ptr; - object->size = size; + object->size = kfence_ksize((void *)ptr) ?: size; object->excess_ref = 0; object->min_count = min_count; object->count = 0; /* white color initially */ From 92fc9da9a4c2cd3f3a49d430dcf9da60668a8a27 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 22 Apr 2021 16:42:52 +1000 Subject: [PATCH 288/306] FROMGIT: kfence: zero guard page after out-of-bounds access After an out-of-bounds accesses, zero the guard page before re-protecting in kfence_guarded_free(). On one hand this helps make the failure mode of subsequent out-of-bounds accesses more deterministic, but could also prevent certain information leaks. Link: https://lkml.kernel.org/r/20210312121653.348518-1-elver@google.com Signed-off-by: Marco Elver Acked-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: Andrey Konovalov Cc: Jann Horn Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell Bug: 172317151 Test: build and run on an ARM64 device (cherry picked from commit 35eaef74e16dcc85b0659db1c7b4a8d83f7a34ef https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git akpm) Signed-off-by: Alexander Potapenko Change-Id: I2bad112b6cbf457892b1dd1a90b909cd88eee2c6 --- mm/kfence/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 04195cb85e52..c8069ef7e41d 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -373,6 +373,7 @@ static void kfence_guarded_free(void *addr, struct kfence_metadata *meta, bool z /* Restore page protection if there was an OOB access. */ if (meta->unprotected_page) { + memzero_explicit((void *)ALIGN_DOWN(meta->unprotected_page, PAGE_SIZE), PAGE_SIZE); kfence_protect(meta->unprotected_page); meta->unprotected_page = 0; } From 423c5febd42ee18a129c3e759b8c67eb7dd4f98b Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 22 Apr 2021 16:42:52 +1000 Subject: [PATCH 289/306] FROMGIT: kfence: await for allocation using wait_event Patch series "kfence: optimize timer scheduling", v2. We have observed that mostly-idle systems with KFENCE enabled wake up otherwise idle CPUs, preventing such to enter a lower power state. Debugging revealed that KFENCE spends too much active time in toggle_allocation_gate(). While the first version of KFENCE was using all the right bits to be scheduling optimal, and thus power efficient, by simply using wait_event() + wake_up(), that code was unfortunately removed. As KFENCE was exposed to various different configs and tests, the scheduling optimal code slowly disappeared. First because of hung task warnings, and finally because of deadlocks when an allocation is made by timer code with debug objects enabled. Clearly, the "fixes" were not too friendly for devices that want to be power efficient. Therefore, let's try a little harder to fix the hung task and deadlock problems that we have with wait_event() + wake_up(), while remaining as scheduling friendly and power efficient as possible. Crucially, we need to defer the wake_up() to an irq_work, avoiding any potential for deadlock. The result with this series is that on the devices where we observed a power regression, power usage returns back to baseline levels. This patch (of 3): On mostly-idle systems, we have observed that toggle_allocation_gate() is a cause of frequent wake-ups, preventing an otherwise idle CPU to go into a lower power state. A late change in KFENCE's development, due to a potential deadlock [1], required changing the scheduling-friendly wait_event_timeout() and wake_up() to an open-coded wait-loop using schedule_timeout(). [1] https://lkml.kernel.org/r/000000000000c0645805b7f982e4@google.com To avoid unnecessary wake-ups, switch to using wait_event_timeout(). Unfortunately, we still cannot use a version with direct wake_up() in __kfence_alloc() due to the same potential for deadlock as in [1]. Instead, add a level of indirection via an irq_work that is scheduled if we determine that the kfence_timer requires a wake_up(). Link: https://lkml.kernel.org/r/20210421105132.3965998-1-elver@google.com Link: https://lkml.kernel.org/r/20210421105132.3965998-2-elver@google.com Fixes: 0ce20dd84089 ("mm: add Kernel Electric-Fence infrastructure") Signed-off-by: Marco Elver Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Jann Horn Cc: Mark Rutland Cc: Hillf Danton Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell Bug: 172317151 Bug: 185280916 Test: power team confirmed there's no regression (cherry picked from commit 0ac66fbbadde5547db190e9d87ff2e77d245f9a2 https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git akpm) Signed-off-by: Alexander Potapenko Change-Id: Idba39683f0b76eb3f70df1113e43d94845fab5bf --- lib/Kconfig.kfence | 1 + mm/kfence/core.c | 43 ++++++++++++++++++++++++++++--------------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/lib/Kconfig.kfence b/lib/Kconfig.kfence index 78f50ccb3b45..e641add33947 100644 --- a/lib/Kconfig.kfence +++ b/lib/Kconfig.kfence @@ -7,6 +7,7 @@ menuconfig KFENCE bool "KFENCE: low-overhead sampling-based memory safety error detector" depends on HAVE_ARCH_KFENCE && (SLAB || SLUB) select STACKTRACE + select IRQ_WORK help KFENCE is a low-overhead sampling-based detector of heap out-of-bounds access, use-after-free, and invalid-free errors. KFENCE is designed diff --git a/mm/kfence/core.c b/mm/kfence/core.c index c8069ef7e41d..ed8ceab98794 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -587,6 +588,17 @@ late_initcall(kfence_debugfs_init); /* === Allocation Gate Timer ================================================ */ +#ifdef CONFIG_KFENCE_STATIC_KEYS +/* Wait queue to wake up allocation-gate timer task. */ +static DECLARE_WAIT_QUEUE_HEAD(allocation_wait); + +static void wake_up_kfence_timer(struct irq_work *work) +{ + wake_up(&allocation_wait); +} +static DEFINE_IRQ_WORK(wake_up_kfence_timer_work, wake_up_kfence_timer); +#endif + /* * Set up delayed work, which will enable and disable the static key. We need to * use a work queue (rather than a simple timer), since enabling and disabling a @@ -604,25 +616,13 @@ static void toggle_allocation_gate(struct work_struct *work) if (!READ_ONCE(kfence_enabled)) return; - /* Enable static key, and await allocation to happen. */ atomic_set(&kfence_allocation_gate, 0); #ifdef CONFIG_KFENCE_STATIC_KEYS + /* Enable static key, and await allocation to happen. */ static_branch_enable(&kfence_allocation_key); - /* - * Await an allocation. Timeout after 1 second, in case the kernel stops - * doing allocations, to avoid stalling this worker task for too long. - */ - { - unsigned long end_wait = jiffies + HZ; - do { - set_current_state(TASK_UNINTERRUPTIBLE); - if (atomic_read(&kfence_allocation_gate) != 0) - break; - schedule_timeout(1); - } while (time_before(jiffies, end_wait)); - __set_current_state(TASK_RUNNING); - } + wait_event_timeout(allocation_wait, atomic_read(&kfence_allocation_gate), HZ); + /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); #endif @@ -729,6 +729,19 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) */ if (atomic_read(&kfence_allocation_gate) || atomic_inc_return(&kfence_allocation_gate) > 1) return NULL; +#ifdef CONFIG_KFENCE_STATIC_KEYS + /* + * waitqueue_active() is fully ordered after the update of + * kfence_allocation_gate per atomic_inc_return(). + */ + if (waitqueue_active(&allocation_wait)) { + /* + * Calling wake_up() here may deadlock when allocations happen + * from within timer code. Use an irq_work to defer it. + */ + irq_work_queue(&wake_up_kfence_timer_work); + } +#endif if (!READ_ONCE(kfence_enabled)) return NULL; From 9e81328dbbc1dcaa2ebb27a097a006333f81ed42 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 22 Apr 2021 16:42:52 +1000 Subject: [PATCH 290/306] FROMGIT: kfence: maximize allocation wait timeout duration The allocation wait timeout was initially added because of warnings due to CONFIG_DETECT_HUNG_TASK=y [1]. While the 1 sec timeout is sufficient to resolve the warnings (given the hung task timeout must be 1 sec or larger) it may cause unnecessary wake-ups if the system is idle. [1] https://lkml.kernel.org/r/CADYN=9J0DQhizAGB0-jz4HOBBh+05kMBXb4c0cXMS7Qi5NAJiw@mail.gmail.com Fix it by computing the timeout duration in terms of the current sysctl_hung_task_timeout_secs value. Link: https://lkml.kernel.org/r/20210421105132.3965998-3-elver@google.com Signed-off-by: Marco Elver Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Hillf Danton Cc: Jann Horn Cc: Mark Rutland Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell Bug: 172317151 Bug: 185280916 Test: power team confirmed there's no regression (cherry picked from commit 5d744ff5acbb40f3b8f1703cb433432889f88fbd https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git akpm) Signed-off-by: Alexander Potapenko Change-Id: I1a8da1844aaded4827bda904ca621a27bbead4bc --- mm/kfence/core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index ed8ceab98794..87dddc35413b 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -621,7 +622,16 @@ static void toggle_allocation_gate(struct work_struct *work) /* Enable static key, and await allocation to happen. */ static_branch_enable(&kfence_allocation_key); - wait_event_timeout(allocation_wait, atomic_read(&kfence_allocation_gate), HZ); + if (sysctl_hung_task_timeout_secs) { + /* + * During low activity with no allocations we might wait a + * while; let's avoid the hung task warning. + */ + wait_event_timeout(allocation_wait, atomic_read(&kfence_allocation_gate), + sysctl_hung_task_timeout_secs * HZ / 2); + } else { + wait_event(allocation_wait, atomic_read(&kfence_allocation_gate)); + } /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); From 7bbdd5f5f09e96d0abbcc7fd80b1a71268cd0eb5 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 22 Apr 2021 16:42:53 +1000 Subject: [PATCH 291/306] FROMGIT: kfence: use power-efficient work queue to run delayed work Use the power-efficient work queue, to avoid the pathological case where we keep pinning ourselves on the same possibly idle CPU on systems that want to be power-efficient (https://lwn.net/Articles/731052/). Link: https://lkml.kernel.org/r/20210421105132.3965998-4-elver@google.com Signed-off-by: Marco Elver Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Hillf Danton Cc: Jann Horn Cc: Mark Rutland Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell Bug: 172317151 Bug: 185280916 Test: power team confirmed there's no regression (cherry picked from commit e5bcc059aa2321383325e98628d65258bdcb306f https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git akpm) Signed-off-by: Alexander Potapenko Change-Id: I53a2869987cdac165840e3878ff73735a03438fa --- mm/kfence/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 87dddc35413b..96258f3fc4d3 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -636,7 +636,8 @@ static void toggle_allocation_gate(struct work_struct *work) /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); #endif - schedule_delayed_work(&kfence_timer, msecs_to_jiffies(kfence_sample_interval)); + queue_delayed_work(system_power_efficient_wq, &kfence_timer, + msecs_to_jiffies(kfence_sample_interval)); } static DECLARE_DELAYED_WORK(kfence_timer, toggle_allocation_gate); @@ -665,7 +666,7 @@ void __init kfence_init(void) } WRITE_ONCE(kfence_enabled, true); - schedule_delayed_work(&kfence_timer, 0); + queue_delayed_work(system_power_efficient_wq, &kfence_timer, 0); pr_info("initialized - using %lu bytes for %d objects at 0x%p-0x%p\n", KFENCE_POOL_SIZE, CONFIG_KFENCE_NUM_OBJECTS, (void *)__kfence_pool, (void *)(__kfence_pool + KFENCE_POOL_SIZE)); From a9260cb494530356a494b91caca5e11ed9b25299 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Thu, 6 May 2021 23:09:22 +0000 Subject: [PATCH 292/306] ANDROID: kfence: clean up unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 62fa525d1e50 ("BACKPORT: kfence: add test suite") removed memcg sanity checks from original change as part of the backport. However, this left a couple variables unused. This patch removes such variables fixing the following warnings: mm/kfence/kfence_test.c:270:23: warning: unused variable ‘s’ [-Wunused-variable] 270 | struct kmem_cache *s = test_cache ?: kmalloc_caches[kmalloc_type(GFP_KERNEL)][kmalloc_index(size)]; | ^ mm/kfence/kfence_test.c:269:17: warning: unused variable ‘page’ [-Wunused-variable] 269 | struct page *page = virt_to_head_page(alloc); | ^~~~ Bug: 183339614 Fixes: 62fa525d1e50 ("BACKPORT: kfence: add test suite") Reported-by: kernelci.org bot Signed-off-by: Carlos Llamas Change-Id: Ifac52f9021be61840cb43bc8d20c9728f3beb948 --- mm/kfence/kfence_test.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c index 9c9d74dc8497..b959548a47ce 100644 --- a/mm/kfence/kfence_test.c +++ b/mm/kfence/kfence_test.c @@ -266,9 +266,6 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat alloc = kmalloc(size, gfp); if (is_kfence_address(alloc)) { - struct page *page = virt_to_head_page(alloc); - struct kmem_cache *s = test_cache ?: kmalloc_caches[kmalloc_type(GFP_KERNEL)][kmalloc_index(size)]; - if (policy == ALLOCATE_ANY) return alloc; if (policy == ALLOCATE_LEFT && IS_ALIGNED((unsigned long)alloc, PAGE_SIZE)) From 1d3c702cee20d0476ff8bb27e43fa3c580c2346f Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 25 May 2021 10:45:51 +0800 Subject: [PATCH 293/306] UPSTREAM: arm64: mm: don't use CON and BLK mapping if KFENCE is enabled When we added KFENCE support for arm64, we intended that it would force the entire linear map to be mapped at page granularity, but we only enforced this in arch_add_memory() and not in map_mem(), so memory mapped at boot time can be mapped at a larger granularity. When booting a kernel with KFENCE=y and RODATA_FULL=n, this results in the following WARNING at boot: [ 0.000000] ------------[ cut here ]------------ [ 0.000000] WARNING: CPU: 0 PID: 0 at mm/memory.c:2462 apply_to_pmd_range+0xec/0x190 [ 0.000000] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.13.0-rc1+ #10 [ 0.000000] Hardware name: linux,dummy-virt (DT) [ 0.000000] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO BTYPE=--) [ 0.000000] pc : apply_to_pmd_range+0xec/0x190 [ 0.000000] lr : __apply_to_page_range+0x94/0x170 [ 0.000000] sp : ffffffc010573e20 [ 0.000000] x29: ffffffc010573e20 x28: ffffff801f400000 x27: ffffff801f401000 [ 0.000000] x26: 0000000000000001 x25: ffffff801f400fff x24: ffffffc010573f28 [ 0.000000] x23: ffffffc01002b710 x22: ffffffc0105fa450 x21: ffffffc010573ee4 [ 0.000000] x20: ffffff801fffb7d0 x19: ffffff801f401000 x18: 00000000fffffffe [ 0.000000] x17: 000000000000003f x16: 000000000000000a x15: ffffffc01060b940 [ 0.000000] x14: 0000000000000000 x13: 0098968000000000 x12: 0000000098968000 [ 0.000000] x11: 0000000000000000 x10: 0000000098968000 x9 : 0000000000000001 [ 0.000000] x8 : 0000000000000000 x7 : ffffffc010573ee4 x6 : 0000000000000001 [ 0.000000] x5 : ffffffc010573f28 x4 : ffffffc01002b710 x3 : 0000000040000000 [ 0.000000] x2 : ffffff801f5fffff x1 : 0000000000000001 x0 : 007800005f400705 [ 0.000000] Call trace: [ 0.000000] apply_to_pmd_range+0xec/0x190 [ 0.000000] __apply_to_page_range+0x94/0x170 [ 0.000000] apply_to_page_range+0x10/0x20 [ 0.000000] __change_memory_common+0x50/0xdc [ 0.000000] set_memory_valid+0x30/0x40 [ 0.000000] kfence_init_pool+0x9c/0x16c [ 0.000000] kfence_init+0x20/0x98 [ 0.000000] start_kernel+0x284/0x3f8 Fixes: 840b23986344 ("arm64, kfence: enable KFENCE for ARM64") Cc: # 5.12.x Signed-off-by: Jisheng Zhang Acked-by: Mark Rutland Acked-by: Marco Elver Tested-by: Marco Elver Link: https://lore.kernel.org/r/20210525104551.2ec37f77@xhacker.debian Signed-off-by: Catalin Marinas (cherry picked from commit e69012400b0cb42b2070748322cb72f9effec00f) Bug: 187129171 Signed-off-by: Connor O'Brien Change-Id: I86fc6c1b9cbb748e2a8e483319e50b08c62cd1a9 --- arch/arm64/mm/mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 637348d57c87..b6983b5502bc 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -471,7 +471,8 @@ static void __init map_mem(pgd_t *pgdp) struct memblock_region *reg; int flags = 0; - if (rodata_full || debug_pagealloc_enabled()) + if (rodata_full || debug_pagealloc_enabled() || + IS_ENABLED(CONFIG_KFENCE)) flags = NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS; /* From 9484ee8820c6329ad72ed7e29b0c0b59d7a8caa7 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Wed, 9 Jun 2021 14:05:25 +0200 Subject: [PATCH 294/306] ANDROID: kasan: fix interoperability with KFENCE MTE-related KASAN changes were preceded by noticeable KASAN refactorings that were backported to android12-5.10, but not android12-5.4. As a result, some last-minute mm changes fixing "kfence, kasan: make KFENCE compatible with KASAN" (https://android.googlesource.com/kernel/common/+/f03825db4d6834a9d97e96eee2404a36ca79dafa) did not make it to android12-5.4. Given that they do not exist as separate upstream commits and do not apply cleanly to 5.4 kernels, reimplement them. These changes boil down to skipping KASAN poisoning for KFENCE-allocated objects and to resetting the object tag in __kasan_kmalloc(). Bug: 172318110 Bug: 190593700 Signed-off-by: Alexander Potapenko Change-Id: I117ea37a1d41514a3c5beaf87386bb5f2f0046c8 --- mm/kasan/common.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mm/kasan/common.c b/mm/kasan/common.c index f8e330596664..b71b16da066e 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -141,6 +141,10 @@ void kasan_poison_shadow(const void *address, size_t size, u8 value) */ address = reset_tag(address); + /* Skip KFENCE memory if called explicitly outside of sl*b. */ + if (is_kfence_address(address)) + return; + shadow_start = kasan_mem_to_shadow(address); shadow_end = kasan_mem_to_shadow(address + size); @@ -158,6 +162,14 @@ void kasan_unpoison_shadow(const void *address, size_t size) */ address = reset_tag(address); + /* + * Skip KFENCE memory if called explicitly outside of sl*b. Also note + * that calls to ksize(), where size is not a multiple of machine-word + * size, would otherwise poison the invalid portion of the word. + */ + if (is_kfence_address(address)) + return; + kasan_poison_shadow(address, size, tag); if (size & KASAN_SHADOW_MASK) { @@ -497,7 +509,7 @@ static void *__kasan_kmalloc(struct kmem_cache *cache, const void *object, if (unlikely(object == NULL)) return NULL; - if (is_kfence_address(object)) + if (is_kfence_address(kasan_reset_tag(object))) return (void *)object; redzone_start = round_up((unsigned long)(object + size), From c40071ccf87970bbfa90e9c3411afa4d4097dc91 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Wed, 30 Jun 2021 11:50:11 +0200 Subject: [PATCH 295/306] FROMLIST: kfence: move the size check to the beginning of __kfence_alloc() Check the allocation size before toggling kfence_allocation_gate. This way allocations that can't be served by KFENCE will not result in waiting for another CONFIG_KFENCE_SAMPLE_INTERVAL without allocating anything. Suggested-by: Marco Elver Cc: Andrew Morton Cc: Dmitry Vyukov Cc: Marco Elver Cc: Greg Kroah-Hartman Cc: stable@vger.kernel.org # 5.12+ Signed-off-by: Alexander Potapenko Reviewed-by: Marco Elver Bug: 192294212 Test: ran KFENCE test suite with __GFP_DMA on QEMU Link: https://lore.kernel.org/linux-mm/20210714092222.1890268-1-glider@google.com/ Change-Id: Ie69c6134fc1c3e68238457b146e26355c17f5295 Signed-off-by: Alexander Potapenko (cherry picked from commit 8478d8dc5381464999ac17a93e639f869d9b514f) --- mm/kfence/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 96258f3fc4d3..f3d1effc5dfa 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -733,6 +733,13 @@ void kfence_shutdown_cache(struct kmem_cache *s) void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) { + /* + * Perform size check before switching kfence_allocation_gate, so that + * we don't disable KFENCE without making an allocation. + */ + if (size > PAGE_SIZE) + return NULL; + /* * allocation_gate only needs to become non-zero, so it doesn't make * sense to continue writing to it and pay the associated contention @@ -757,9 +764,6 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) if (!READ_ONCE(kfence_enabled)) return NULL; - if (size > PAGE_SIZE) - return NULL; - return kfence_guarded_alloc(s, size, flags); } From 632650279957723a889a18992e55378e2149a2ca Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Tue, 29 Jun 2021 14:45:28 +0200 Subject: [PATCH 296/306] FROMLIST: kfence: skip all GFP_ZONEMASK allocations Allocation requests outside ZONE_NORMAL (MOVABLE, HIGHMEM or DMA) cannot be fulfilled by KFENCE, because KFENCE memory pool is located in a zone different from the requested one. Because callers of kmem_cache_alloc() may actually rely on the allocation to reside in the requested zone (e.g. memory allocations done with __GFP_DMA must be DMAable), skip all allocations done with GFP_ZONEMASK and/or respective SLAB flags (SLAB_CACHE_DMA and SLAB_CACHE_DMA32). Fixes: 0ce20dd84089 ("mm: add Kernel Electric-Fence infrastructure") Cc: Andrew Morton Cc: Dmitry Vyukov Cc: Marco Elver Cc: Greg Kroah-Hartman Cc: Souptick Joarder Cc: stable@vger.kernel.org # 5.12+ Signed-off-by: Alexander Potapenko Reviewed-by: Marco Elver Acked-by: Souptick Joarder Bug: 192294212 Test: ran KFENCE test suite with __GFP_DMA on QEMU Link: https://lore.kernel.org/linux-mm/20210714092222.1890268-2-glider@google.com/ Change-Id: I72d2e24185e213d0ce60155d5a78f29bca8c88cc Signed-off-by: Alexander Potapenko (cherry picked from commit 0f27e1d31707e09cf7bac781a08e5a46a9b6cfd1) --- mm/kfence/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index f3d1effc5dfa..e8825ae0b318 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -740,6 +740,15 @@ void *__kfence_alloc(struct kmem_cache *s, size_t size, gfp_t flags) if (size > PAGE_SIZE) return NULL; + /* + * Skip allocations from non-default zones, including DMA. We cannot + * guarantee that pages in the KFENCE pool will have the requested + * properties (e.g. reside in DMAable memory). + */ + if ((flags & GFP_ZONEMASK) || + (s->flags & (SLAB_CACHE_DMA | SLAB_CACHE_DMA32))) + return NULL; + /* * allocation_gate only needs to become non-zero, so it doesn't make * sense to continue writing to it and pay the associated contention From c78abaa8feb0ac3964932f16d33cad0e1bfb2e1d Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 19 Aug 2021 19:04:30 -0700 Subject: [PATCH 297/306] UPSTREAM: kfence: fix is_kfence_address() for addresses below KFENCE_POOL_SIZE Originally the addr != NULL check was meant to take care of the case where __kfence_pool == NULL (KFENCE is disabled). However, this does not work for addresses where addr > 0 && addr < KFENCE_POOL_SIZE. This can be the case on NULL-deref where addr > 0 && addr < PAGE_SIZE or any other faulting access with addr < KFENCE_POOL_SIZE. While the kernel would likely crash, the stack traces and report might be confusing due to double faults upon KFENCE's attempt to unprotect such an address. Fix it by just checking that __kfence_pool != NULL instead. Link: https://lkml.kernel.org/r/20210818130300.2482437-1-elver@google.com Fixes: 0ce20dd84089 ("mm: add Kernel Electric-Fence infrastructure") Signed-off-by: Marco Elver Reported-by: Kuan-Ying Lee Acked-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: [5.12+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit a7cb5d23eaea148f8582229846f8dfff192f05c3) Bug: 196937223 Bug: 197197917 Test: local QEMU runs with init/main.c modified to access the NULL page Signed-off-by: Alexander Potapenko Change-Id: I6a339e8c6b4d2bdc3ee9bd575725489a8233aade (cherry picked from commit 228d32e2d0b730f00eb0a8950698902b3ad23daf) --- include/linux/kfence.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/kfence.h b/include/linux/kfence.h index a70d1ea03532..3fe6dd8a18c1 100644 --- a/include/linux/kfence.h +++ b/include/linux/kfence.h @@ -51,10 +51,11 @@ extern atomic_t kfence_allocation_gate; static __always_inline bool is_kfence_address(const void *addr) { /* - * The non-NULL check is required in case the __kfence_pool pointer was - * never initialized; keep it in the slow-path after the range-check. + * The __kfence_pool != NULL check is required to deal with the case + * where __kfence_pool == NULL && addr < KFENCE_POOL_SIZE. Keep it in + * the slow-path after the range-check! */ - return unlikely((unsigned long)((char *)addr - __kfence_pool) < KFENCE_POOL_SIZE && addr); + return unlikely((unsigned long)((char *)addr - __kfence_pool) < KFENCE_POOL_SIZE && __kfence_pool); } /** From cbbfbfd13f4e687db3d5b5c557278bee93f3a38b Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Fri, 4 Jun 2021 20:01:11 -0700 Subject: [PATCH 298/306] UPSTREAM: kfence: use TASK_IDLE when awaiting allocation Since wait_event() uses TASK_UNINTERRUPTIBLE by default, waiting for an allocation counts towards load. However, for KFENCE, this does not make any sense, since there is no busy work we're awaiting. Instead, use TASK_IDLE via wait_event_idle() to not count towards load. BugLink: https://bugzilla.suse.com/show_bug.cgi?id=1185565 Link: https://lkml.kernel.org/r/20210521083209.3740269-1-elver@google.com Fixes: 407f1d8c1b5f ("kfence: await for allocation using wait_event") Signed-off-by: Marco Elver Cc: Mel Gorman Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: David Laight Cc: Hillf Danton Cc: [5.12+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 8fd0e995cc7b6a7a8a40bc03d52a2cd445beeff4) Bug: 187129171 Signed-off-by: Connor O'Brien Change-Id: Ida5cea821a5a8ef538d314a6e80680faf8aacbdc --- mm/kfence/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index e8825ae0b318..4a5ce51aa408 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -627,10 +627,10 @@ static void toggle_allocation_gate(struct work_struct *work) * During low activity with no allocations we might wait a * while; let's avoid the hung task warning. */ - wait_event_timeout(allocation_wait, atomic_read(&kfence_allocation_gate), - sysctl_hung_task_timeout_secs * HZ / 2); + wait_event_idle_timeout(allocation_wait, atomic_read(&kfence_allocation_gate), + sysctl_hung_task_timeout_secs * HZ / 2); } else { - wait_event(allocation_wait, atomic_read(&kfence_allocation_gate)); + wait_event_idle(allocation_wait, atomic_read(&kfence_allocation_gate)); } /* Disable static key and reset timer. */ From fd26c6ba53fffa7cfe18ee8940d5362f2d04f87d Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Wed, 30 Jun 2021 18:54:03 -0700 Subject: [PATCH 299/306] UPSTREAM: kfence: unconditionally use unbound work queue Unconditionally use unbound work queue, and not just if wq_power_efficient is true. Because if the system is idle, KFENCE may wait, and by being run on the unbound work queue, we permit the scheduler to make better scheduling decisions and not require pinning KFENCE to the same CPU upon waking up. Link: https://lkml.kernel.org/r/20210521111630.472579-1-elver@google.com Fixes: 36f0b35d0894 ("kfence: use power-efficient work queue to run delayed work") Signed-off-by: Marco Elver Reported-by: Hillf Danton Reviewed-by: Alexander Potapenko Cc: Dmitry Vyukov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit ff06e45d3aace3f93d23956c1e655224f363ebe2) Bug: 187129171 Signed-off-by: Connor O'Brien Change-Id: Ib0f1a18a42b71e57e8ec095be0b72bd298e8aec5 --- mm/kfence/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 4a5ce51aa408..6c669c2f276e 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -636,7 +636,7 @@ static void toggle_allocation_gate(struct work_struct *work) /* Disable static key and reset timer. */ static_branch_disable(&kfence_allocation_key); #endif - queue_delayed_work(system_power_efficient_wq, &kfence_timer, + queue_delayed_work(system_unbound_wq, &kfence_timer, msecs_to_jiffies(kfence_sample_interval)); } static DECLARE_DELAYED_WORK(kfence_timer, toggle_allocation_gate); @@ -666,7 +666,7 @@ void __init kfence_init(void) } WRITE_ONCE(kfence_enabled, true); - queue_delayed_work(system_power_efficient_wq, &kfence_timer, 0); + queue_delayed_work(system_unbound_wq, &kfence_timer, 0); pr_info("initialized - using %lu bytes for %d objects at 0x%p-0x%p\n", KFENCE_POOL_SIZE, CONFIG_KFENCE_NUM_OBJECTS, (void *)__kfence_pool, (void *)(__kfence_pool + KFENCE_POOL_SIZE)); From f794c870660edfee826a57bc97801b22c9c037ed Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Fri, 24 Dec 2021 21:12:32 -0800 Subject: [PATCH 300/306] UPSTREAM: kfence: fix memory leak when cat kfence objects Hulk robot reported a kmemleak problem: unreferenced object 0xffff93d1d8cc02e8 (size 248): comm "cat", pid 23327, jiffies 4624670141 (age 495992.217s) hex dump (first 32 bytes): 00 40 85 19 d4 93 ff ff 00 10 00 00 00 00 00 00 .@.............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: seq_open+0x2a/0x80 full_proxy_open+0x167/0x1e0 do_dentry_open+0x1e1/0x3a0 path_openat+0x961/0xa20 do_filp_open+0xae/0x120 do_sys_openat2+0x216/0x2f0 do_sys_open+0x57/0x80 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x44/0xa9 unreferenced object 0xffff93d419854000 (size 4096): comm "cat", pid 23327, jiffies 4624670141 (age 495992.217s) hex dump (first 32 bytes): 6b 66 65 6e 63 65 2d 23 32 35 30 3a 20 30 78 30 kfence-#250: 0x0 30 30 30 30 30 30 30 37 35 34 62 64 61 31 32 2d 0000000754bda12- backtrace: seq_read_iter+0x313/0x440 seq_read+0x14b/0x1a0 full_proxy_read+0x56/0x80 vfs_read+0xa5/0x1b0 ksys_read+0xa0/0xf0 do_syscall_64+0x33/0x40 entry_SYSCALL_64_after_hwframe+0x44/0xa9 I find that we can easily reproduce this problem with the following commands: cat /sys/kernel/debug/kfence/objects echo scan > /sys/kernel/debug/kmemleak cat /sys/kernel/debug/kmemleak The leaked memory is allocated in the stack below: do_syscall_64 do_sys_open do_dentry_open full_proxy_open seq_open ---> alloc seq_file vfs_read full_proxy_read seq_read seq_read_iter traverse ---> alloc seq_buf And it should have been released in the following process: do_syscall_64 syscall_exit_to_user_mode exit_to_user_mode_prepare task_work_run ____fput __fput full_proxy_release ---> free here However, the release function corresponding to file_operations is not implemented in kfence. As a result, a memory leak occurs. Therefore, the solution to this problem is to implement the corresponding release function. Link: https://lkml.kernel.org/r/20211206133628.2822545-1-libaokun1@huawei.com Fixes: 0ce20dd84089 ("mm: add Kernel Electric-Fence infrastructure") Signed-off-by: Baokun Li Reported-by: Hulk Robot Acked-by: Marco Elver Reviewed-by: Kefeng Wang Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Yu Kuai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry picked from commit 0129ab1f268b6cf88825eae819b9b84aa0a85634) Bug: 187129171 Signed-off-by: Connor O'Brien Change-Id: If4235f6dbdf89c45f832fab827eab4b6e0271190 (cherry picked from commit 64fe36c410b16e8bbf32bb2268296692eabda900) Signed-off-by: Mark-PK Tsai --- mm/kfence/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 6c669c2f276e..566a82c3cb20 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -574,6 +574,7 @@ static const struct file_operations objects_fops = { .open = open_objects, .read = seq_read, .llseek = seq_lseek, + .release = seq_release, }; static int __init kfence_debugfs_init(void) From dc9c8b5d3a39a22d8adbad48ea462ac43c8a1dd1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 1 Nov 2021 17:45:55 -0700 Subject: [PATCH 301/306] UPSTREAM: net: add and use skb_unclone_keeptruesize() helper While commit 097b9146c0e2 ("net: fix up truesize of cloned skb in skb_prepare_for_shift()") fixed immediate issues found when KFENCE was enabled/tested, there are still similar issues, when tcp_trim_head() hits KFENCE while the master skb is cloned. This happens under heavy networking TX workloads, when the TX completion might be delayed after incoming ACK. This patch fixes the WARNING in sk_stream_kill_queues when sk->sk_mem_queued/sk->sk_forward_alloc are not zero. Bug: 254441685 Fixes: d3fb45f370d9 ("mm, kfence: insert KFENCE hooks for SLAB") Signed-off-by: Eric Dumazet Acked-by: Marco Elver Link: https://lore.kernel.org/r/20211102004555.1359210-1-eric.dumazet@gmail.com Signed-off-by: Jakub Kicinski (cherry picked from commit c4777efa751d293e369aec464ce6875e957be255) Signed-off-by: Lee Jones Change-Id: I94082cca974d248a4b9376b41245bfc63bd1f134 --- include/linux/skbuff.h | 16 ++++++++++++++++ net/core/skbuff.c | 14 +------------- net/ipv4/tcp_output.c | 6 +++--- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 120a2162b844..add201a31f2c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1626,6 +1626,22 @@ static inline int skb_unclone(struct sk_buff *skb, gfp_t pri) return 0; } +/* This variant of skb_unclone() makes sure skb->truesize is not changed */ +static inline int skb_unclone_keeptruesize(struct sk_buff *skb, gfp_t pri) +{ + might_sleep_if(gfpflags_allow_blocking(pri)); + + if (skb_cloned(skb)) { + unsigned int save = skb->truesize; + int res; + + res = pskb_expand_head(skb, 0, 0, pri); + skb->truesize = save; + return res; + } + return 0; +} + /** * skb_header_cloned - is the header a clone * @skb: buffer to check diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0b21a9902e29..a7e5b5843539 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3359,19 +3359,7 @@ EXPORT_SYMBOL(skb_split); */ static int skb_prepare_for_shift(struct sk_buff *skb) { - int ret = 0; - - if (skb_cloned(skb)) { - /* Save and restore truesize: pskb_expand_head() may reallocate - * memory where ksize(kmalloc(S)) != ksize(kmalloc(S)), but we - * cannot change truesize at this point. - */ - unsigned int save_truesize = skb->truesize; - - ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - skb->truesize = save_truesize; - } - return ret; + return skb_unclone_keeptruesize(skb, GFP_ATOMIC); } /** diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cd252f530a2e..9a6e8eb85bdb 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1492,7 +1492,7 @@ int tcp_fragment(struct sock *sk, enum tcp_queue tcp_queue, return -ENOMEM; } - if (skb_unclone(skb, gfp)) + if (skb_unclone_keeptruesize(skb, gfp)) return -ENOMEM; /* Get a new skb... force flag on. */ @@ -1601,7 +1601,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) { u32 delta_truesize; - if (skb_unclone(skb, GFP_ATOMIC)) + if (skb_unclone_keeptruesize(skb, GFP_ATOMIC)) return -ENOMEM; delta_truesize = __pskb_trim_head(skb, len); @@ -3160,7 +3160,7 @@ start: cur_mss, GFP_ATOMIC)) return -ENOMEM; /* We'll try again later. */ } else { - if (skb_unclone(skb, GFP_ATOMIC)) + if (skb_unclone_keeptruesize(skb, GFP_ATOMIC)) return -ENOMEM; diff = tcp_skb_pcount(skb); From b3c8ca243a9e09f0e8913dfe2763d8cb41b68844 Mon Sep 17 00:00:00 2001 From: Marco Elver Date: Thu, 16 Mar 2023 23:47:04 +0100 Subject: [PATCH 302/306] UPSTREAM: kfence: avoid passing -g for test Nathan reported that when building with GNU as and a version of clang that defaults to DWARF5: $ make -skj"$(nproc)" ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- \ LLVM=1 LLVM_IAS=0 O=build \ mrproper allmodconfig mm/kfence/kfence_test.o /tmp/kfence_test-08a0a0.s: Assembler messages: /tmp/kfence_test-08a0a0.s:14627: Error: non-constant .uleb128 is not supported /tmp/kfence_test-08a0a0.s:14628: Error: non-constant .uleb128 is not supported /tmp/kfence_test-08a0a0.s:14632: Error: non-constant .uleb128 is not supported /tmp/kfence_test-08a0a0.s:14633: Error: non-constant .uleb128 is not supported /tmp/kfence_test-08a0a0.s:14639: Error: non-constant .uleb128 is not supported ... This is because `-g` defaults to the compiler debug info default. If the assembler does not support some of the directives used, the above errors occur. To fix, remove the explicit passing of `-g`. All the test wants is that stack traces print valid function names, and debug info is not required for that. (I currently cannot recall why I added the explicit `-g`.) Bug: 254441685 Link: https://lkml.kernel.org/r/20230316224705.709984-1-elver@google.com Fixes: bc8fbc5f305a ("kfence: add test suite") Signed-off-by: Marco Elver Reported-by: Nathan Chancellor Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Signed-off-by: Andrew Morton (cherry picked from commit 2e08ca1802441224f5b7cc6bffbb687f7406de95) Signed-off-by: Lee Jones Change-Id: I5646d8667f119147b92f4b86b4cf86cbc47dbdde --- mm/kfence/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/kfence/Makefile b/mm/kfence/Makefile index 6872cd5e5390..cb2bcf773083 100644 --- a/mm/kfence/Makefile +++ b/mm/kfence/Makefile @@ -2,5 +2,5 @@ obj-$(CONFIG_KFENCE) := core.o report.o -CFLAGS_kfence_test.o := -g -fno-omit-frame-pointer -fno-optimize-sibling-calls +CFLAGS_kfence_test.o := -fno-omit-frame-pointer -fno-optimize-sibling-calls obj-$(CONFIG_KFENCE_KUNIT_TEST) += kfence_test.o From c8b06c924221762f49987316bdc1eb21c3ebd26b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 26 Sep 2022 17:43:14 +0200 Subject: [PATCH 303/306] UPSTREAM: random: split initialization into early step and later step The full RNG initialization relies on some timestamps, made possible with initialization functions like time_init() and timekeeping_init(). However, these are only available rather late in initialization. Meanwhile, other things, such as memory allocator functions, make use of the RNG much earlier. So split RNG initialization into two phases. We can provide arch randomness very early on, and then later, after timekeeping and such are available, initialize the rest. This ensures that, for example, slabs are properly randomized if RDRAND is available. Without this, CONFIG_SLAB_FREELIST_RANDOM=y loses a degree of its security, because its random seed is potentially deterministic, since it hasn't yet incorporated RDRAND. It also makes it possible to use a better seed in kfence, which currently relies on only the cycle counter. Another positive consequence is that on systems with RDRAND, running with CONFIG_WARN_ALL_UNSEEDED_RANDOM=y results in no warnings at all. One subtle side effect of this change is that on systems with no RDRAND, RDTSC is now only queried by random_init() once, committing the moment of the function call, instead of multiple times as before. This is intentional, as the multiple RDTSCs in a loop before weren't accomplishing very much, with jitter being better provided by try_to_generate_entropy(). Plus, filling blocks with RDTSC is still being done in extract_entropy(), which is necessarily called before random bytes are served anyway. Cc: Andrew Morton Reviewed-by: Kees Cook Reviewed-by: Dominik Brodowski Signed-off-by: Jason A. Donenfeld (cherry picked from commit f62384995e4cb7703e5295779c44135c5311770d) Change-Id: Ibf5ca2ddea8d853c108c6191803046cae8808dfa [dereference23: Backport to 5.4] Signed-off-by: Alexander Winkowski --- drivers/char/random.c | 42 ++++++++++++++++++++++++++++-------------- include/linux/random.h | 3 ++- init/main.c | 17 ++++++++--------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 693640de7271..e7fc274a9608 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -799,16 +799,11 @@ early_param("random.trust_cpu", parse_trust_cpu); early_param("random.trust_bootloader", parse_trust_bootloader); /* - * The first collection of entropy occurs at system boot while interrupts - * are still turned off. Here we push in latent entropy, RDSEED, a timestamp, - * utsname(), and the command line. Depending on the above configuration knob, - * RDSEED may be considered sufficient for initialization. Note that much - * earlier setup may already have pushed entropy into the input pool by the - * time we get here. + * This is called extremely early, before time keeping functionality is + * available, but arch randomness is. Interrupts are not yet enabled. */ -int __init random_init(const char *command_line) +void __init random_init_early(const char *command_line) { - ktime_t now = ktime_get_real(); unsigned int i, arch_bits; unsigned long entropy; @@ -821,22 +816,41 @@ int __init random_init(const char *command_line) i < BLAKE2S_BLOCK_SIZE; i += sizeof(entropy)) { if (!arch_get_random_seed_long_early(&entropy) && !arch_get_random_long_early(&entropy)) { - entropy = random_get_entropy(); arch_bits -= sizeof(entropy) * 8; + continue; } _mix_pool_bytes(&entropy, sizeof(entropy)); } - _mix_pool_bytes(&now, sizeof(now)); - _mix_pool_bytes(utsname(), sizeof(*(utsname()))); - _mix_pool_bytes(command_line, strlen(command_line)); - add_latent_entropy(); + _mix_pool_bytes(command_line, strlen(command_line)); + + /* Reseed if already seeded by earlier phases. */ if (crng_ready()) crng_reseed(); else if (trust_cpu) _credit_init_bits(arch_bits); +} - return 0; +/* + * This is called a little bit after the prior function, and now there is + * access to timestamps counters. Interrupts are not yet enabled. + */ +void __init random_init(void) +{ + unsigned long entropy = random_get_entropy(); + ktime_t now = ktime_get_real(); + + _mix_pool_bytes(utsname(), sizeof(*(utsname()))); + _mix_pool_bytes(&now, sizeof(now)); + _mix_pool_bytes(&entropy, sizeof(entropy)); + add_latent_entropy(); + + /* Reseed if already seeded by earlier phases. */ + if (crng_ready()) + crng_reseed(); + + WARN(!entropy, "Missing cycle counter and fallback timer; RNG " + "entropy collection will consequently suffer."); } /* diff --git a/include/linux/random.h b/include/linux/random.h index 8ed2e245d51e..7e742ef51a83 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -64,7 +64,8 @@ static inline unsigned long get_random_canary(void) return get_random_long() & CANARY_MASK; } -int __init random_init(const char *command_line); +void __init random_init_early(const char *command_line); +void __init random_init(void); bool rng_is_initialized(void); int wait_for_random_bytes(void); int register_random_ready_notifier(struct notifier_block *nb); diff --git a/init/main.c b/init/main.c index d283c689496a..cb6c59db4188 100644 --- a/init/main.c +++ b/init/main.c @@ -625,6 +625,9 @@ asmlinkage __visible void __init start_kernel(void) parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, NULL, set_init_arg); + /* Architectural and non-timekeeping rng init, before allocator init */ + random_init_early(command_line); + /* * These use large bootmem allocations and must precede * kmem_cache_init() @@ -687,17 +690,13 @@ asmlinkage __visible void __init start_kernel(void) hrtimers_init(); softirq_init(); timekeeping_init(); - kfence_init(); time_init(); - /* - * For best initial stack canary entropy, prepare it after: - * - setup_arch() for any UEFI RNG entropy and boot cmdline access - * - timekeeping_init() for ktime entropy used in random_init() - * - time_init() for making random_get_entropy() work on some platforms - * - random_init() to initialize the RNG from from early entropy sources - */ - random_init(command_line); + /* This must be after timekeeping is initialized */ + random_init(); + + /* These make use of the fully initialized rng */ + kfence_init(); boot_init_stack_canary(); perf_event_init(); From fa638256447eb7ed1e4b995a0bbe7e9fed4b656c Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Wed, 3 Feb 2021 20:10:42 -0800 Subject: [PATCH 304/306] ANDROID: GKI: Enable KFENCE Set KFENCE_SAMPLE_INTERVAL to zero to runtime disable KFENCE for now. The feature can be activated with kfence.sample_interval=