6.12.110-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 950/1376 phy: qcom-sgmii-eth: relax order of .power_on() vs .set_mode*()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Russell King (Oracle) <[email protected]>
[ Upstream commit ebe8b48b88ad012cf6067226e184e9173b7ea9d6 ]
Allow any order of the .power_on() and .set_mode*() methods as per the recent discussion. This means phy_power_on() with this SerDes will now restore the previous setup without requiring a subsequent phy_set_mode*() call.
Stable-dep-of: 4f81684a1d10 ("phy: qcom: sgmii-eth: vote for both voltage rails with correct current loads")
--- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +13 -1
@@ -267,8 +267,17 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy)static int qcom_dwmac_sgmii_phy_power_on (struct phy *phy) {struct qcom_dwmac_sgmii_phy_data *data =phy_get_drvdata (phy); +int ret; -return clk_prepare_enable (data->refclk); + ret =clk_prepare_enable (data->refclk); +if (ret <0 ) +return ret; + + ret =qcom_dwmac_sgmii_phy_calibrate (phy); +if (ret <0 ) +clk_disable_unprepare (data->refclk); + +return ret; }static int qcom_dwmac_sgmii_phy_power_off (struct phy *phy)
@@ -293,6 +302,9 @@ static int qcom_dwmac_sgmii_phy_set_speed(struct phy *phy, int speed)if (speed != data->speed) data->speed = speed; +if (phy->power_count ==0 ) +return 0 ; +return qcom_dwmac_sgmii_phy_calibrate (phy); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 951/1376 phy: qcom: sgmii-eth: vote for both voltage rails with correct current loads
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohd Ayaan Anwar <[email protected]>
[ Upstream commit 4f81684a1d1018d7d0e5579f08d95e7701279358 ]
The SerDes PHY has two voltage supply rails, vdda-0p9 and vdda-1p2, that must both be enabled for calibration to succeed. Without them:
qcom-dwmac-sgmii-phy 8909000.phy: QSERDES_COM_C_READY_STATUS timed-out qcom-ethqos 23040000.ethernet eth0: __stmmac_open: Serdes powerup failed
The driver relied solely on the PHY framework's implicit enable of 'phy-supply', which only voted for a single rail and set no current load. Use devm_regulator_bulk_get_const() to acquire both supplies and set the peak current loads (46 mA for vdda-0p9, 15 mA for vdda-1p2) as required by the hardware.
--- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 37 ++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-)
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +33 -4
@@ -10,6 +10,7 @@#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include "phy-qcom-qmp-pcs-sgmii.h" #include "phy-qcom-qmp-qserdes-com-v5.h"
@@ -25,7 +26,15 @@#define QSERDES_PCS_SGMIIPHY_READY BIT(7)#define QSERDES_COM_C_PLL_LOCKED BIT(1) +static const struct regulator_bulk_data qcom_dwmac_sgmii_phy_vregs[] = { + { .supply ="vdda-0p9" , .init_load_uA =46000 }, + { .supply ="vdda-1p2" , .init_load_uA =15000 }, +}; + +#define QCOM_SGMII_NUM_SUPPLIES ARRAY_SIZE(qcom_dwmac_sgmii_phy_vregs) +struct qcom_dwmac_sgmii_phy_data { +struct regulator_bulk_data *vregs;struct regmap *regmap;struct clk *refclk;int speed;
@@ -269,13 +278,24 @@ static int qcom_dwmac_sgmii_phy_power_on(struct phy *phy)struct qcom_dwmac_sgmii_phy_data *data =phy_get_drvdata (phy);int ret; - ret =clk_prepare_enable (data->refclk); -if (ret <0 ) + ret =regulator_bulk_enable (QCOM_SGMII_NUM_SUPPLIES , data->vregs); +if (ret)return ret; + ret =clk_prepare_enable (data->refclk); +if (ret) + goto err_disable_regulators; + ret =qcom_dwmac_sgmii_phy_calibrate (phy); -if (ret <0 ) -clk_disable_unprepare (data->refclk); +if (ret) + goto err_disable_clk; + +return 0 ; + +err_disable_clk: +clk_disable_unprepare (data->refclk); +err_disable_regulators: +regulator_bulk_disable (QCOM_SGMII_NUM_SUPPLIES , data->vregs);return ret; }
@@ -292,6 +312,8 @@ static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy)clk_disable_unprepare (data->refclk); +regulator_bulk_disable (QCOM_SGMII_NUM_SUPPLIES , data->vregs); +return 0 ; }
@@ -331,6 +353,7 @@ static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev)struct phy_provider *provider;void __iomem *base;struct phy *phy; +int ret; data =devm_kzalloc (dev,sizeof (*data),GFP_KERNEL );if (!data)
@@ -355,6 +378,12 @@ static int qcom_dwmac_sgmii_phy_probe(struct platform_device *pdev)if (IS_ERR (data->refclk))return PTR_ERR (data->refclk); + ret =devm_regulator_bulk_get_const (dev,QCOM_SGMII_NUM_SUPPLIES , + qcom_dwmac_sgmii_phy_vregs, + &data->vregs); +if (ret) +return ret; + provider =devm_of_phy_provider_register (dev, of_phy_simple_xlate);if (IS_ERR (provider))return PTR_ERR (provider);
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0951/1376] phy: qcom: sgmii-eth: vote for both voltage rails with correct current loads
Quoted 43 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohd Ayaan Anwar <[email protected]>
[ Upstream commit
4f81684a1d1018d7d0e5579f08d95e7701279358]The SerDes PHY has two voltage supply rails, vdda-0p9 and vdda-1p2, that must both be enabled for calibration to succeed. Without them:
qcom-dwmac-sgmii-phy 8909000.phy:
QSERDES_COM_C_READY_STATUStimed-out qcom-ethqos 23040000.ethernet eth0:__stmmac_open: Serdes powerup failedThe driver relied solely on the PHY framework's implicit enable of 'phy-supply', which only voted for a single rail and set no current load. Use
devm_regulator_bulk_get_const()to acquire both supplies and set the peak current loads (46 mA for vdda-0p9, 15 mA for vdda-1p2) as required by the hardware.Fixes 601d06277007 ("phy: qcom: add the SGMII SerDes PHY driver")Signed-off-by Mohd Ayaan Anwar <[email protected]>Reviewed-by Manivannan Sadhasivam <[email protected]>Link https://patch.msgid.link/20260804-b4-sgmiieth_serdes_regulator-v2-2-c4bc688177dd@oss.qualcomm.com open hereSigned-off-by Vinod Koul <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- drivers/phy/qualcomm/phy-qcom-sgmii-eth.c | 37 ++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-)drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +1
-0@@ -10,6 +10,7 @@#include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/regulator/consumer.h> #include "phy-qcom-qmp-pcs-sgmii.h" #include "phy-qcom-qmp-qserdes-com-v5.h"
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c line 31
Quoted 6 lines
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +3
-0@@ -25,7 +26,15 @@#define QSERDES_PCS_SGMIIPHY_READY BIT(7)#define QSERDES_COM_C_PLL_LOCKED BIT(1) +static const struct regulator_bulk_data qcom_dwmac_sgmii_phy_vregs[] = { + { .supply ="vdda-0p9" , .init_load_uA =46000 }, + { .supply ="vdda-1p2" , .init_load_uA =15000 },
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream driver code:
{ .supply = "vdda-0p9", .init_load_uA = 46000 },
{ .supply = "vdda-1p2", .init_load_uA = 15000 },Downstream 6.12.y board code:
phy-supply = <&vreg_l5a>;
The downstream property matches neither required upstream supply name.
The driver now requires vdda-0p9 and vdda-1p2 supplies, but the enabled SA8775P SerDes nodes in 6.12 provide only phy-supply. Regulator lookup uses the exact named properties, so probe either fails or receives dummy supplies; it does not vote the physical rails which this fix requires.
Upstream companion 3719850f1b70dd adds that.
I suggest dropping the driver patch until that mapping is provided and validated. Thoughts?
thanks,
Harshit> +};
Quoted 36 lines
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +19
-4+ +#define QCOM_SGMII_NUM_SUPPLIES ARRAY_SIZE(qcom_dwmac_sgmii_phy_vregs) +struct qcom_dwmac_sgmii_phy_data { +struct regulator_bulk_data *vregs;struct regmap *regmap;struct clk *refclk;int speed;@@ -269,13 +278,24 @@ static int qcom_dwmac_sgmii_phy_power_on(struct phy *phy)struct qcom_dwmac_sgmii_phy_data *data =phy_get_drvdata (phy);int ret; - ret =clk_prepare_enable (data->refclk); -if (ret <0 ) + ret =regulator_bulk_enable (QCOM_SGMII_NUM_SUPPLIES , data->vregs); +if (ret)return ret; + ret =clk_prepare_enable (data->refclk); +if (ret) + goto err_disable_regulators; + ret =qcom_dwmac_sgmii_phy_calibrate (phy); -if (ret <0 ) -clk_disable_unprepare (data->refclk); +if (ret) + goto err_disable_clk; + +return 0 ; + +err_disable_clk: +clk_disable_unprepare (data->refclk); +err_disable_regulators: +regulator_bulk_disable (QCOM_SGMII_NUM_SUPPLIES , data->vregs);
Re: [PATCH 6.12 0951/1376] phy: qcom: sgmii-eth: vote for both voltage rails with correct current loads
Quoted 10 lines · Harshit Mogalapalli
Quoted 7 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohd Ayaan Anwar <[email protected]>
[ Upstream commit
4f81684a1d1018d7d0e5579f08d95e7701279358]
<snip>
Quoted 27 lines
drivers/phy/qualcomm/phy-qcom-sgmii-eth.c line 31
Quoted 4 lines
#define QSERDES_COM_C_PLL_LOCKED BIT(1)drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +3
-0+static const struct regulator_bulk_data qcom_dwmac_sgmii_phy_vregs[] = { + { .supply ="vdda-0p9" , .init_load_uA =46000 }, + { .supply ="vdda-1p2" , .init_load_uA =15000 },Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
Upstream driver code:
{ .supply = "vdda-0p9", .init_load_uA = 46000 }, { .supply = "vdda-1p2", .init_load_uA = 15000 },Downstream 6.12.y board code:
phy-supply = <&vreg_l5a>;The downstream property matches neither required upstream supply name.
The driver now requires vdda-0p9 and vdda-1p2 supplies, but the enabled SA8775P SerDes nodes in 6.12 provide only phy-supply. Regulator lookup uses the exact named properties, so probe either fails or receives dummy supplies; it does not vote the physical rails which this fix requires.
Quoted 7 lines
Upstream companion
3719850f1b70ddadds that.I suggest dropping the driver patch until that mapping is provided and validated. Thoughts?
thanks,
Harshit> +};
Actually, phy-core.c already takes care of regulators described by "phy-supply".
drivers/phy/phy-core.c
/* phy-supply */
phy->pwr = regulator_get_optional(&phy->dev, "phy");
if (IS_ERR(phy->pwr)) {
ret = PTR_ERR(phy->pwr);
if (ret == -EPROBE_DEFER)
goto put_dev;
phy->pwr = NULL;
}This patch only adds support for two additional regulators (vdda-0p9 and vdda-1p2). It does not remove or alter the existing "phy-supply" path handled by phy-core.c.
As a result, boards that only describe "phy-supply" continue to work as before. The new regulator lookups are optional and merely allow the PHY driver to vote for the dedicated rails when they are available.
Ayaan
Greg Kroah-Hartman
maintainerPATCH 952/1376 phy: qcom: qmp-usb-legacy: Fix possible NULL-deref on early runtime suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
[ Upstream commit 8e3687f7e18fe84372e86875709d56c37e7525a8 ]
There is a small window where the runtime suspend callback may run after pm_runtime_enable() and before pm_runtime_forbid(). In this case, a crash occurs because runtime suspend/resume dereferences qmp->phy pointer, which is not yet initialized:
`if (!qmp->phy->init_count) {`This can also happen if user re-enables runtime-pm via the sysfs attribute before qmp phy is initialized.
Similarly to other qcom phy drivers, introduce a qmp->phy_initialized variable that can be used to avoid relying on the possibly uninitialized phy pointer.
--- drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +10 -2
@@ -542,6 +542,8 @@ struct qmp_usb {enum phy_mode mode; +bool phy_initialized; +struct phy *phy;struct clk_fixed_rate pipe_clk_fixed;
@@ -895,6 +897,7 @@ static int qmp_usb_legacy_power_off(struct phy *phy)static int qmp_usb_legacy_enable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; ret =qmp_usb_legacy_init (phy);
@@ -904,14 +907,19 @@ static int qmp_usb_legacy_enable(struct phy *phy) ret =qmp_usb_legacy_power_on (phy);if (ret)qmp_usb_legacy_exit (phy); +else + qmp->phy_initialized = true;return ret; }static int qmp_usb_legacy_disable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; + qmp->phy_initialized = false; + ret =qmp_usb_legacy_power_off (phy);if (ret)return ret;
@@ -988,7 +996,7 @@ static int __maybe_unused qmp_usb_legacy_runtime_suspend(struct device *dev)dev_vdbg (dev,"Suspending QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
@@ -1009,7 +1017,7 @@ static int __maybe_unused qmp_usb_legacy_runtime_resume(struct device *dev)dev_vdbg (dev,"Resuming QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 953/1376 phy: qcom: snps-femto-v2: Fix possible NULL-deref on early runtime suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
[ Upstream commit c271a6926ea7d3c9566b033d63fd4e8c488dc860 ]
Runtime PM must be enabled before creating the PHY, since phy_create() only enables runtime PM on the PHY device if it is already enabled on this parent device. However, the runtime PM callbacks dereference the hsphy instance, which is not yet ready, leaving a window where a suspend callback may trigger a NULL pointer dereference.
Take a runtime PM usage reference with pm_runtime_get_noresume() before enabling runtime PM and release it once the PHY has been created, so that no runtime suspend can run before the PHY is ready. This also prevents a short window where an unnecessary runtime suspend can occur.
Use the devres-managed version to ensure PM runtime is symmetrically disabled during driver removal for proper cleanup.
--- drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-)
drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c +20 -6
@@ -599,8 +599,18 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)return dev_err_probe (dev, ret,"failed to get regulator supplies\n" ); +/* +* Enable runtime PM before creating the PHY, phy_create() only enables +* it on the PHY device if already enabled on the parent. Hold a usage +* reference so callbacks cannot run before the PHY is ready. +*/ +pm_runtime_get_noresume (dev);pm_runtime_set_active (dev); -pm_runtime_enable (dev); + ret =devm_pm_runtime_enable (dev); +if (ret) { +pm_runtime_put_noidle (dev); +return ret; + }/* * Prevent runtime pm from being ON by default. Users can enable * it using power/control in sysfs.
@@ -611,6 +621,7 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)if (IS_ERR (generic_phy)) { ret =PTR_ERR (generic_phy);dev_err (dev,"failed to create phy, %d\n" , ret); +pm_runtime_put_noidle (dev);return ret; } hsphy->phy = generic_phy;
@@ -620,12 +631,15 @@ static int qcom_snps_hsphy_probe(struct platform_device *pdev)qcom_snps_hsphy_read_override_param_seq (dev); phy_provider =devm_of_phy_provider_register (dev, of_phy_simple_xlate); -if (!IS_ERR (phy_provider)) -dev_dbg (dev,"Registered Qcom-SNPS HS phy\n" ); -else -pm_runtime_disable (dev); +if (IS_ERR (phy_provider)) { +pm_runtime_put_noidle (dev); +return PTR_ERR (phy_provider); + } -return PTR_ERR_OR_ZERO (phy_provider); +dev_dbg (dev,"Registered Qcom-SNPS HS phy\n" ); +pm_runtime_put (dev); + +return 0 ; }static struct platform_driver qcom_snps_hsphy_driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 954/1376 phy: qcom: qmp-usb: Fix possible NULL-deref on early runtime suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Loic Poulain <[email protected]>
[ Upstream commit 142c5593379273264474f31d5956b1a0065cd576 ]
There is a small window where the runtime suspend callback may run after pm_runtime_enable() and before pm_runtime_forbid(). In this case, a crash occurs because runtime suspend/resume dereferences qmp->phy pointer, which is not yet initialized:
`if (!qmp->phy->init_count) {`This can also happen if user re-enables runtime-pm via the sysfs attribute before qmp phy is initialized.
Similarly to other qcom phy drivers, introduce a qmp->phy_initialized variable that can be used to avoid relying on the possibly uninitialized phy pointer.
--- drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-usb.c +10 -2
@@ -1256,6 +1256,8 @@ struct qmp_usb {enum phy_mode mode; +bool phy_initialized; +struct phy *phy;struct clk_fixed_rate pipe_clk_fixed;
@@ -1786,6 +1788,7 @@ static int qmp_usb_power_off(struct phy *phy)static int qmp_usb_enable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; ret =qmp_usb_init (phy);
@@ -1795,14 +1798,19 @@ static int qmp_usb_enable(struct phy *phy) ret =qmp_usb_power_on (phy);if (ret)qmp_usb_exit (phy); +else + qmp->phy_initialized = true;return ret; }static int qmp_usb_disable (struct phy *phy) { +struct qmp_usb *qmp =phy_get_drvdata (phy);int ret; + qmp->phy_initialized = false; + ret =qmp_usb_power_off (phy);if (ret)return ret;
@@ -1878,7 +1886,7 @@ static int __maybe_unused qmp_usb_runtime_suspend(struct device *dev)dev_vdbg (dev,"Suspending QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
@@ -1898,7 +1906,7 @@ static int __maybe_unused qmp_usb_runtime_resume(struct device *dev)dev_vdbg (dev,"Resuming QMP phy, mode:%d\n" , qmp->mode); -if (!qmp->phy->init_count) { +if (!qmp->phy_initialized) {dev_vdbg (dev,"PHY not initialized, bailing out\n" );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 955/1376 md/raid5: round bitmap stripes with sector division
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 17ea021ae74987d6064c8195c4922fa025753892 ]
raid5_bitmap_sector_map() aligns the array range to full RAID5 stripe widths before converting it to component sectors. That width is chunk_sectors multiplied by the number of data disks, and it is not always a power of two.
Reproduce with a 4-disk RAID5, 1024-sector chunks, and three data disks. The full-stripe width is 3072 sectors. For a one-sector write at array sector 3072, correct rounding gives array range [3072, 6144), which maps to component range [1024, 2048). The old round_down()/round_up() logic instead gives [1024, 4096), which maps to [0, 1024).
Use sector_div() based arithmetic so the rounded range is aligned to the actual RAID5 stripe width.
The deterministic mapper test now reports the fixed component range as [1024, 2048), while the old mask-based range was [0, 1024).
--- drivers/md/raid5.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
drivers/md/raid5.c +9 -4
@@ -5918,8 +5918,11 @@ static void raid5_bitmap_sector(struct mddev *mddev, sector_t *offset, sectors_per_chunk = conf->chunk_sectors * (conf->raid_disks - conf->max_degraded); - start =round_down (start, sectors_per_chunk); - end =round_up (end, sectors_per_chunk); +sector_div (start, sectors_per_chunk); + start *= sectors_per_chunk; +if (sector_div (end, sectors_per_chunk)) + end++; + end *= sectors_per_chunk; start =raid5_compute_sector (conf, start,0 , &dd_idx,NULL ); end =raid5_compute_sector (conf, end,0 , &dd_idx,NULL );
@@ -5937,8 +5940,10 @@ static void raid5_bitmap_sector(struct mddev *mddev, sector_t *offset, sectors_per_chunk = conf->prev_chunk_sectors * (conf->previous_raid_disks - conf->max_degraded); - prev_start =round_down (prev_start, sectors_per_chunk); - prev_end =round_down (prev_end, sectors_per_chunk); +sector_div (prev_start, sectors_per_chunk); + prev_start *= sectors_per_chunk; +sector_div (prev_end, sectors_per_chunk); + prev_end *= sectors_per_chunk; prev_start =raid5_compute_sector (conf, prev_start,1 , &dd_idx,NULL ); prev_end =raid5_compute_sector (conf, prev_end,1 , &dd_idx,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 956/1376 md: avoid stale clone I/O accounting timestamps
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Kuai <[email protected]>
[ Upstream commit 45102fc8330525d35675b1c193242bba101df5ee ]
md_clone_bio() always allocates the clone from mddev->io_clone_set, even when queue I/O stats are disabled. In that case it does not call bio_start_io_acct(), but it also left md_io_clone->start_time untouched.
The clone private data comes from a mempool and can contain data from a previous user. md_end_clone_io() checks start_time to decide whether it needs to call bio_end_io_acct(), so a stale non-zero value can make the completion path end accounting that was never started for this bio.
Set start_time to 0 in the no-stats branch. This keeps the end path tied to whether bio_start_io_acct() actually ran.
--- drivers/md/md.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/md/md.c +2 -0
@@ -8836,6 +8836,8 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio) md_io_clone->mddev = mddev;if (blk_queue_io_stat (bdev->bd_disk->queue)) md_io_clone->start_time =bio_start_io_acct (*bio); +else + md_io_clone->start_time =0 ;if (bio_data_dir (*bio) ==WRITE && mddev->bitmap) { md_io_clone->offset = (*bio)->bi_iter.bi_sector;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 957/1376 md/raid1: dont set array_frozen in raid1_takeover()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bruce Johnston <[email protected]>
[ Upstream commit dc386aa0ac0a3ec06c9a3ea9b064b073fb72a916 ]
raid1_takeover() sets conf->array_frozen = 1 on the newly-allocated r1conf and nothing ever clears it, so every I/O to the array stalls permanently once _wait_barrier() sees it stuck at 1.
This used to be harmless: level_store() called mddev_resume() right after pers->run(), which called raid1_quiesce(mddev, 0) and cleared array_frozen back to 0 regardless of what raid1_takeover() set. Commit b39f35ebe86d ("md: don't quiesce in mddev_suspend()") removed that quiesce(mddev, 0) call, so the pre-set now sticks.
setup_conf() already zero-initializes the new r1conf via kzalloc, so just don't set array_frozen here.
Same class of bug as commit 892da88d1cd9 ("md/raid10: fix a 'conf->barrier' leakage in raid10_takeover()"), also triggered by b39f35ebe86d.
--- drivers/md/raid1.c | 2 -- 1 file changed, 2 deletions(-)
drivers/md/raid1.c +0 -2
@@ -3482,8 +3482,6 @@ static void *raid1_takeover(struct mddev *mddev) mddev->new_chunk_sectors =0 ; conf =setup_conf (mddev);if (!IS_ERR (conf)) { -/* Array must appear to be quiesced */ - conf->array_frozen =1 ;mddev_clear_unsupported_flags (mddev,UNSUPPORTED_MDDEV_FLAGS ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 958/1376 coresight: etm4x: fix wrong check of etm4x_sspcicrn_present()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <[email protected]>
[ Upstream commit 0e1cd4270b42a257c139165622091e1e8c7104a7 ]
According to Embedded Trace Macrocell Architecture Specification ETMv4.0 to ETM4.6 [0], TRCSSPCICR<n> is present only if all of the following are true:
- TRCIDR4.NUMSSCC > n.
- TRCIDR4.NUMPC > 0b0000.
- TRCSSCSR<n>.PC == 0b1.
Comment for etm4x_sspcicrn_present() is align with the specification. However, the check should use drvdata->nr_pe_cmp to check TRCIDR4.NUMPC not nr_pe.
--- drivers/hwtracing/coresight/coresight-etm4x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +1 -1
@@ -87,7 +87,7 @@ static int etm4_probe_cpu(unsigned int cpu);static inline bool etm4x_sspcicrn_present (struct etmv4_drvdata *drvdata,int n) {return (n < drvdata->nr_ss_cmp) && - drvdata->nr_pe && + drvdata->nr_pe_cmp && (drvdata->config.ss_status[n] & TRCSSCSRn_PC); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 959/1376 coresight: Change syncfreq to be a u8
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 10d4dbdc8fbce586b17be07b8138e025381453dd ]
TRCSYNCPR.PERIOD is the only functional part of TRCSYNCPR and it only has 5 valid bits so it can be stored in a u8.
Stable-dep-of: 1674d9bff807 ("coresight: etm4x: fix underflow for usage of (nrseqstate - 1)")
--- drivers/hwtracing/coresight/coresight-etm4x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-etm4x.h +1 -1
@@ -825,7 +825,6 @@ struct etmv4_config {u32 eventctrl1;u32 stall_ctrl;u32 ts_ctrl; -u32 syncfreq;u32 ccctlr;u32 bb_ctrl;u32 vinst_ctrl;
@@ -833,6 +832,7 @@ struct etmv4_config {u32 vissctlr;u32 vipcssctlr;u8 seq_idx; +u8 syncfreq;u32 seq_ctrl[ETM_MAX_SEQ_STATES ];u32 seq_rst;u32 seq_state;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 960/1376 coresight: etm4x: fix underflow for usage of (nrseqstate - 1)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <[email protected]>
[ Upstream commit 1674d9bff8073bdee5dbc200f56fc3caa28d0566 ]
According to IHI006H Embedded Trace Macrocell Architecture Specification[0], TRCSEQEVR<n> is implemented only when TRCIDR5.NUMSEQSTATE is 0b100, in which case n ranges from 0 to 2; otherwise, TRCIDR5.NUMSEQSTATE is 0b000.
IOW, the number of usage in the initialisation or setting TRCSEQEVR<n> with drvdata->nrseqstate - 1 in the loop could make underflow issue when TRCIDR5.NUMSEQSTATE is 0b000.
Therefore, introduce nr_seq_ctrls field and untie it from nrseqstate. As part of this introduce ETM_MAX_SEQ_TRANSITIONS macro and apply nr_seq_ctrls and above macro to TRCSEQEVR<n> relevant fields setup.
--- drivers/hwtracing/coresight/coresight-etm4x-cfg.c | 2 +- drivers/hwtracing/coresight/coresight-etm4x-core.c | 9 ++++++--- drivers/hwtracing/coresight/coresight-etm4x-sysfs.c | 6 ++++-- drivers/hwtracing/coresight/coresight-etm4x.h | 7 +++++-- 4 files changed, 16 insertions(+), 8 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-cfg.c +1 -1
@@ -76,7 +76,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata, }else if ((offset &GENMASK (11 ,4 )) ==TRCSEQEVRn (0 )) {/* sequencer state control registers */ idx = (offset &GENMASK (3 ,0 )) /4 ; -if (idx <ETM_MAX_SEQ_STATES ) { +if (idx <ETM_MAX_SEQ_TRANSITIONS ) { reg_csdev->driver_regval = &drvcfg->seq_ctrl[idx]; err =0 ; }
drivers/hwtracing/coresight/coresight-etm4x-core.c +6 -3
@@ -527,7 +527,8 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)etm4x_relaxed_write32 (csa, config->vissctlr,TRCVISSCTLR );if (drvdata->nr_pe_cmp)etm4x_relaxed_write32 (csa, config->vipcssctlr,TRCVIPCSSCTLR ); -for (i =0 ; i < drvdata->nrseqstate -1 ; i++) + +for (i =0 ; i < drvdata->nr_seq_ctrls; i++)etm4x_relaxed_write32 (csa, config->seq_ctrl[i],TRCSEQEVRn (i));if (drvdata->nrseqstate) {etm4x_relaxed_write32 (csa, config->seq_rst,TRCSEQRSTEVR );
@@ -1415,6 +1416,8 @@ static void etm4_init_arch_data(void *info) drvdata->lpoverride = (etmidr5 &TRCIDR5_LPOVERRIDE ) && (!drvdata->skip_power_up);/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */ drvdata->nrseqstate =FIELD_GET (TRCIDR5_NUMSEQSTATE_MASK , etmidr5); +if (drvdata->nrseqstate) + drvdata->nr_seq_ctrls =ETM_MAX_SEQ_TRANSITIONS ;/* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr =FIELD_GET (TRCIDR5_NUMCNTR_MASK , etmidr5);etm4_cs_lock (drvdata, csa);
@@ -1824,7 +1827,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)if (drvdata->nr_pe_cmp) state->trcvipcssctlr =etm4x_read32 (csa,TRCVIPCSSCTLR ); -for (i =0 ; i < drvdata->nrseqstate -1 ; i++) +for (i =0 ; i < drvdata->nr_seq_ctrls; i++) state->trcseqevr[i] =etm4x_read32 (csa,TRCSEQEVRn (i));if (drvdata->nrseqstate) {
@@ -1958,7 +1961,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)if (drvdata->nr_pe_cmp)etm4x_relaxed_write32 (csa, state->trcvipcssctlr,TRCVIPCSSCTLR ); -for (i =0 ; i < drvdata->nrseqstate -1 ; i++) +for (i =0 ; i < drvdata->nr_seq_ctrls; i++)etm4x_relaxed_write32 (csa, state->trcseqevr[i],TRCSEQEVRn (i));if (drvdata->nrseqstate) {
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +4 -2
@@ -221,7 +221,7 @@ static ssize_t reset_store(struct device *dev, config->vipcssctlr =0x0 ;/* Disable seq events */ -for (i =0 ; i < drvdata->nrseqstate-1 ; i++) +for (i =0 ; i < drvdata->nr_seq_ctrls; i++) config->seq_ctrl[i] =0x0 ; config->seq_rst =0x0 ; config->seq_state =0x0 ;
@@ -1393,9 +1393,11 @@ static ssize_t seq_idx_store(struct device *dev,struct etmv4_drvdata *drvdata =dev_get_drvdata (dev->parent);struct etmv4_config *config = &drvdata->config; +if (!drvdata->nr_seq_ctrls) +return -ENOTSUPP ;if (kstrtoul (buf,16 , &val))return -EINVAL ; -if (val >= drvdata->nrseqstate -1 ) +if (val >= drvdata->nr_seq_ctrls)return -EINVAL ;/*
drivers/hwtracing/coresight/coresight-etm4x.h +5 -2
@@ -570,6 +570,7 @@#define ETM_MAX_NR_PE 8#define ETMv4_MAX_CNTR 4#define ETM_MAX_SEQ_STATES 4 +#define ETM_MAX_SEQ_TRANSITIONS 3#define ETM_MAX_EXT_INP_SEL 4#define ETM_MAX_EXT_INP 256#define ETM_MAX_EXT_OUT 4
@@ -833,7 +834,7 @@ struct etmv4_config {u32 vipcssctlr;u8 seq_idx;u8 syncfreq; -u32 seq_ctrl[ETM_MAX_SEQ_STATES ]; +u32 seq_ctrl[ETM_MAX_SEQ_TRANSITIONS ];u32 seq_rst;u32 seq_state;u8 cntr_idx;
@@ -885,7 +886,7 @@ struct etmv4_save_state {u32 trcvissctlr;u32 trcvipcssctlr; -u32 trcseqevr[ETM_MAX_SEQ_STATES ]; +u32 trcseqevr[ETM_MAX_SEQ_TRANSITIONS ];u32 trcseqrstevr;u32 trcseqstr;u32 trcextinselr;
@@ -938,6 +939,7 @@ struct etmv4_save_state {* @numcidc: Number of contextID comparators. * @numvmidc: Number of VMID comparators. * @nrseqstate: The number of sequencer states that are implemented. +* @nr_seq_ctrls: The number of sequence state transition control registers. * @nr_event: Indicates how many events the trace unit support. * @nr_resource:The number of resource selection pairs available for tracing. * @nr_ss_cmp: Number of single-shot comparator controls that are available.
@@ -1004,6 +1006,7 @@ struct etmv4_drvdata {u8 numextinsel;u8 numvmidc;u8 nrseqstate; +u8 nr_seq_ctrls;u8 nr_event;u8 nr_resource;u8 nr_ss_cmp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 961/1376 coresight: etm4x: fix leaked trace id
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yeoreum Yun <[email protected]>
[ Upstream commit 467e5862ccb0eed907002f4c6d3badfe34360940 ]
If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(), the trace ID may be leaked because it is not released.
To address this, call etm4_release_trace_id() when etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config().
--- drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +3 -1
@@ -854,8 +854,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev)cscfg_config_sysfs_get_active_cfg (&cfg_hash, &preset);if (cfg_hash) { ret =cscfg_csdev_enable_active_config (csdev, cfg_hash, preset); -if (ret) +if (ret) { +etm4_release_trace_id (drvdata);return ret; + } }spin_lock (&drvdata->spinlock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 962/1376 regulator: qcom-rpmh: Fix PMIC5 BOB bypass mode handling
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kamal Wadhwa <[email protected]>
[ Upstream commit abd14bebb87e0fa2749371272c8b31d6ee5f0a36 ]
Currently, when rpmh_regulator_set_mode_bypass() helper function is called to set bypass mode, it sends PMIC4's BOB bypass mode value for even if its a PMIC5 BOB.
To fix this, introduce new hw_data parameterpmic_bypass_mode to store bypass mode value. Use it to send correct PMIC bypass mode value that corresponds to PMIC4/5 BOB regulators from the helper function.
--- drivers/regulator/qcom-rpmh-regulator.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/regulator/qcom-rpmh-regulator.c +5 -1
@@ -77,6 +77,7 @@ enum rpmh_regulator_type {* @hpm_min_load_uA: Minimum load current in microamps that requires * high power mode (HPM) operation. This is used * for LDO hardware type regulators only. +* @pmic_bypass_mode: The PMIC bypass mode value. * @pmic_mode_map: Array indexed by regulator framework mode * containing PMIC hardware modes. Must be large * enough to index all framework modes supported
@@ -91,6 +92,7 @@ struct rpmh_vreg_hw_data {int n_linear_ranges;int n_voltages;int hpm_min_load_uA; +int pmic_bypass_mode;const int *pmic_mode_map;unsigned int (*of_map_mode)(unsigned int mode); };
@@ -277,7 +279,7 @@ static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,return pmic_mode;if (bypassed) - cmd.data =PMIC4_BOB_MODE_PASS ; + cmd.data = vreg->hw_data->pmic_bypass_mode;else cmd.data = pmic_mode;
@@ -692,6 +694,7 @@ static const struct rpmh_vreg_hw_data pmic4_bob = { }, .n_linear_ranges = 1, .n_voltages = 84, + .pmic_bypass_mode = PMIC4_BOB_MODE_PASS, .pmic_mode_map = pmic_mode_map_pmic4_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, };
@@ -900,6 +903,7 @@ static const struct rpmh_vreg_hw_data pmic5_bob = { }, .n_linear_ranges = 1, .n_voltages = 32, + .pmic_bypass_mode = PMIC5_BOB_MODE_PASS, .pmic_mode_map = pmic_mode_map_pmic5_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 963/1376 ACPI: video: Release PCI device reference after lookup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 3d7ed9b8ef47b8bcae1fc3e12f7590a217862a89 ]
video_detect_portege_r100() uses pci_get_device() only as a boolean check for the Trident CyberBlade XP4m32 device. pci_get_device() takes a reference on a matching PCI device, but the callback returns without releasing it.
Drop the reference after selecting the vendor backlight quirk so the PCI device can be released normally.
--- drivers/acpi/video_detect.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/acpi/video_detect.c +3 -1
@@ -137,8 +137,10 @@ static int video_detect_portege_r100(const struct dmi_system_id *d)struct pci_dev *dev;/* Search for Trident CyberBlade XP4m32 to confirm Portégé R100 */ dev =pci_get_device (PCI_VENDOR_ID_TRIDENT ,0x2100 ,NULL ); -if (dev) +if (dev) { acpi_backlight_dmi = acpi_backlight_vendor; +pci_dev_put (dev); + }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 964/1376 perf/x86/intel/pt: Add support for pause / resume
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 08c7454ceb948d773fcd0ff7b6fb9c315e2f801a ]
Prevent tracing to start if aux_paused.
Implement support for PERF_EF_PAUSE / PERF_EF_RESUME. When aux_paused, stop tracing. When not aux_paused, only start tracing if it isn't currently meant to be stopped.
Stable-dep-of: 2e17bf3a469a ("perf/x86/intel/pt: Fix stop/start with no update")
--- arch/x86/events/intel/pt.c | 73 ++++++++++++++++++++++++++++++++++++-- arch/x86/events/intel/pt.h | 4 +++ 2 files changed, 74 insertions(+), 3 deletions(-)
arch/x86/events/intel/pt.c +70 -3
@@ -418,6 +418,9 @@ static void pt_config_start(struct perf_event *event)struct pt *pt =this_cpu_ptr (&pt_ctx);u64 ctl = event->hw.aux_config; +if (READ_ONCE (event->hw.aux_paused)) +return ; + ctl |=RTIT_CTL_TRACEEN ;if (READ_ONCE (pt->vmx_on))perf_aux_output_flag (&pt->handle,PERF_AUX_FLAG_PARTIAL );
@@ -534,7 +537,24 @@ static void pt_config(struct perf_event *event) reg |= (event->attr.config &PT_CONFIG_MASK ); event->hw.aux_config = reg; + +/* +* Allow resume before starting so as not to overwrite a value set by a +* PMI. +*/ +barrier (); +WRITE_ONCE (pt->resume_allowed,1 ); +/* Configuration is complete, it is now OK to handle an NMI */ +barrier (); +WRITE_ONCE (pt->handle_nmi,1 ); +barrier ();pt_config_start (event); +barrier (); +/* +* Allow pause after starting so its pt_config_stop() doesn't race with +* pt_config_start(). +*/ +WRITE_ONCE (pt->pause_allowed,1 ); }static void pt_config_stop (struct perf_event *event)
@@ -1516,6 +1536,7 @@ void intel_pt_interrupt(void) buf =perf_aux_output_begin (&pt->handle, event);if (!buf) { event->hw.state =PERF_HES_STOPPED ; +WRITE_ONCE (pt->resume_allowed,0 );return ; }
@@ -1524,6 +1545,7 @@ void intel_pt_interrupt(void) ret =pt_buffer_reset_markers (buf, &pt->handle);if (ret) {perf_aux_output_end (&pt->handle,0 ); +WRITE_ONCE (pt->resume_allowed,0 );return ; }
@@ -1578,6 +1600,26 @@ static void pt_event_start(struct perf_event *event, int mode)struct pt *pt =this_cpu_ptr (&pt_ctx);struct pt_buffer *buf; +if (mode &PERF_EF_RESUME ) { +if (READ_ONCE (pt->resume_allowed)) { +u64 status; + +/* +* Only if the trace is not active and the error and +* stopped bits are clear, is it safe to start, but a +* PMI might have just cleared these, so resume_allowed +* must be checked again also. +*/ +rdmsrl (MSR_IA32_RTIT_STATUS , status); +if (!(status & (RTIT_STATUS_TRIGGEREN | +RTIT_STATUS_ERROR | +RTIT_STATUS_STOPPED )) && +READ_ONCE (pt->resume_allowed)) +pt_config_start (event); + } +return ; + } + buf =perf_aux_output_begin (&pt->handle, event);if (!buf) goto fail_stop;
@@ -1588,7 +1630,6 @@ static void pt_event_start(struct perf_event *event, int mode) goto fail_end_stop; } -WRITE_ONCE (pt->handle_nmi,1 ); hwc->state =0 ;pt_config_buffer (buf);
@@ -1606,6 +1647,12 @@ static void pt_event_stop(struct perf_event *event, int mode) {struct pt *pt =this_cpu_ptr (&pt_ctx); +if (mode &PERF_EF_PAUSE ) { +if (READ_ONCE (pt->pause_allowed)) +pt_config_stop (event); +return ; + } +/* * Protect against the PMI racing with disabling wrmsr, * see comment in intel_pt_interrupt().
@@ -1613,6 +1660,15 @@ static void pt_event_stop(struct perf_event *event, int mode)WRITE_ONCE (pt->handle_nmi,0 );barrier (); +/* +* Prevent a resume from attempting to restart tracing, or a pause +* during a subsequent start. Do this after clearing handle_nmi so that +* pt_event_snapshot_aux() will not re-allow them. +*/ +WRITE_ONCE (pt->pause_allowed,0 ); +WRITE_ONCE (pt->resume_allowed,0 ); +barrier (); +pt_config_stop (event);if (event->hw.state ==PERF_HES_STOPPED )
@@ -1662,6 +1718,10 @@ static long pt_event_snapshot_aux(struct perf_event *event,if (WARN_ON_ONCE (!buf->snapshot))return 0 ; +/* Prevent pause/resume from attempting to start/stop tracing */ +WRITE_ONCE (pt->pause_allowed,0 ); +WRITE_ONCE (pt->resume_allowed,0 ); +barrier ();/* * There is no PT interrupt in this mode, so stop the trace and it will * remain stopped while the buffer is copied.
@@ -1681,8 +1741,13 @@ static long pt_event_snapshot_aux(struct perf_event *event,* Here, handle_nmi tells us if the tracing was on. * If the tracing was on, restart it. */ -if (READ_ONCE (pt->handle_nmi)) +if (READ_ONCE (pt->handle_nmi)) { +WRITE_ONCE (pt->resume_allowed,1 ); +barrier ();pt_config_start (event); +barrier (); +WRITE_ONCE (pt->pause_allowed,1 ); + }return ret; }
@@ -1798,7 +1863,9 @@ static __init int pt_init(void)if (!intel_pt_validate_hw_cap (PT_CAP_topa_multiple_entries)) pt_pmu.pmu.capabilities =PERF_PMU_CAP_AUX_NO_SG ; - pt_pmu.pmu.capabilities |=PERF_PMU_CAP_EXCLUSIVE |PERF_PMU_CAP_ITRACE ; + pt_pmu.pmu.capabilities |=PERF_PMU_CAP_EXCLUSIVE | +PERF_PMU_CAP_ITRACE | +PERF_PMU_CAP_AUX_PAUSE ; pt_pmu.pmu.attr_groups = pt_attr_groups; pt_pmu.pmu.task_ctx_nr = perf_sw_context; pt_pmu.pmu.event_init = pt_event_init;
arch/x86/events/intel/pt.h +4 -0
@@ -119,6 +119,8 @@ struct pt_filters {* @filters: last configured filters * @handle_nmi: do handle PT PMI on this cpu, there's an active event * @vmx_on: 1 if VMX is ON on this cpu +* @pause_allowed: PERF_EF_PAUSE is allowed to stop tracing +* @resume_allowed: PERF_EF_RESUME is allowed to start tracing * @output_base: cached RTIT_OUTPUT_BASE MSR value * @output_mask: cached RTIT_OUTPUT_MASK MSR value */
@@ -127,6 +129,8 @@ struct pt {struct pt_filters filters;int handle_nmi;int vmx_on; +int pause_allowed; +int resume_allowed;u64 output_base;u64 output_mask; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 965/1376 perf/x86/intel/pt: Factor out pt_config_enable()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit c6df517796189723ffbdd7679206c97d3642c2ef ]
pt_config() enables tracing by allowing NMIs and pause/resume, issuing the necessary barriers, and calling pt_config_start(). A later change needs to re-enable tracing on a (re-)start path without repeating the full pt_config() setup (filters, RTIT_CTL, buffer configuration).
Factor that enabling sequence out into a new helper, pt_config_enable(), so it can be called on its own.
No functional change intended.
Stable-dep-of: 2e17bf3a469a ("perf/x86/intel/pt: Fix stop/start with no update")
--- arch/x86/events/intel/pt.c | 41 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 17 deletions(-)
arch/x86/events/intel/pt.c +24 -17
@@ -499,6 +499,29 @@ static u64 pt_config_filters(struct perf_event *event)return rtit_ctl; } +static void pt_config_enable (struct perf_event *event) +{ +struct pt *pt =this_cpu_ptr (&pt_ctx); + +/* +* Allow resume before starting so as not to overwrite a value set by a +* PMI. +*/ +barrier (); +WRITE_ONCE (pt->resume_allowed,1 ); +/* Configuration is complete, it is now OK to handle an NMI */ +barrier (); +WRITE_ONCE (pt->handle_nmi,1 ); +barrier (); +pt_config_start (event); +barrier (); +/* +* Allow pause after starting so its pt_config_stop() doesn't race with +* pt_config_start(). +*/ +WRITE_ONCE (pt->pause_allowed,1 ); +} +static void pt_config (struct perf_event *event) {struct pt *pt =this_cpu_ptr (&pt_ctx);
@@ -538,23 +561,7 @@ static void pt_config(struct perf_event *event) event->hw.aux_config = reg; -/* -* Allow resume before starting so as not to overwrite a value set by a -* PMI. -*/ -barrier (); -WRITE_ONCE (pt->resume_allowed,1 ); -/* Configuration is complete, it is now OK to handle an NMI */ -barrier (); -WRITE_ONCE (pt->handle_nmi,1 ); -barrier (); -pt_config_start (event); -barrier (); -/* -* Allow pause after starting so its pt_config_stop() doesn't race with -* pt_config_start(). -*/ -WRITE_ONCE (pt->pause_allowed,1 ); +pt_config_enable (event); }static void pt_config_stop (struct perf_event *event)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 966/1376 perf/x86/intel/pt: Use bitwise access for PERF_HES_STOPPED
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 265bb4ef75fa657f4957d72087a6a246b89d5f0d ]
The Intel PT driver reads and writes event->hw.state as a whole value, assuming it is either 0 or PERF_HES_STOPPED. That is true today, but a subsequent fix needs to also track an open AUX output buffer using the PERF_HES_UPTODATE bit of the same field.
When more than one bit can be set, whole-value assignments would overwrite the other bits and whole-value comparisons would fail to match.
Convert all accesses to set, clear and test the PERF_HES_STOPPED bit individually, in preparation for that change.
No functional change intended: event->hw.state currently only ever holds 0 or PERF_HES_STOPPED, so the bitwise forms are equivalent.
Stable-dep-of: 2e17bf3a469a ("perf/x86/intel/pt: Fix stop/start with no update")
--- arch/x86/events/intel/pt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-)
arch/x86/events/intel/pt.c +8 -8
@@ -1537,12 +1537,12 @@ void intel_pt_interrupt(void)perf_aux_output_end (&pt->handle,local_xchg (&buf->data_size,0 )); -if (!event->hw.state) { +if (!(event->hw.state &PERF_HES_STOPPED )) {int ret; buf =perf_aux_output_begin (&pt->handle, event);if (!buf) { - event->hw.state =PERF_HES_STOPPED ; + event->hw.state |=PERF_HES_STOPPED ;WRITE_ONCE (pt->resume_allowed,0 );return ; }
@@ -1637,7 +1637,7 @@ static void pt_event_start(struct perf_event *event, int mode) goto fail_end_stop; } - hwc->state =0 ; + hwc->state &= ~PERF_HES_STOPPED ;pt_config_buffer (buf);pt_config (event);
@@ -1647,7 +1647,7 @@ static void pt_event_start(struct perf_event *event, int mode) fail_end_stop:perf_aux_output_end (&pt->handle,0 ); fail_stop: - hwc->state =PERF_HES_STOPPED ; + hwc->state |=PERF_HES_STOPPED ; }static void pt_event_stop (struct perf_event *event,int mode)
@@ -1678,10 +1678,10 @@ static void pt_event_stop(struct perf_event *event, int mode)pt_config_stop (event); -if (event->hw.state ==PERF_HES_STOPPED ) +if (event->hw.state &PERF_HES_STOPPED )return ; - event->hw.state =PERF_HES_STOPPED ; + event->hw.state |=PERF_HES_STOPPED ;if (mode &PERF_EF_UPDATE ) {struct pt_buffer *buf =perf_get_aux (&pt->handle);
@@ -1776,10 +1776,10 @@ static int pt_event_add(struct perf_event *event, int mode)if (mode &PERF_EF_START ) {pt_event_start (event,0 ); ret = -EINVAL ; -if (hwc->state ==PERF_HES_STOPPED ) +if (hwc->state &PERF_HES_STOPPED ) goto fail; }else { - hwc->state =PERF_HES_STOPPED ; + hwc->state |=PERF_HES_STOPPED ; } ret =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 967/1376 perf/x86/intel/pt: Fix stop/start with no update
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
[ Upstream commit 2e17bf3a469a41457a3bc31b1f8fd66b6ce94a6d ]
If pt_event_stop() is called without PERF_EF_UPDATE flag, then perf_aux_output_end() is not called. A subsequent call to pt_event_start() will call perf_aux_output_begin() again which violates the rule against nesting and triggers a WARNING in perf_aux_output_begin().
Originally, pt_event_stop() was never called without PERF_EF_UPDATE, because the only code paths to do so are from event overflow, and Intel PT does not do that.
However the introduction of group throttling by commit 9734e25fbf5ae ("perf: Fix the throttle logic for a group") meant that an Intel PT event could be throttled if it was part of a group. Throttling calls PMU
->stop() / ->start() callbacks without flags.
An example is when AUX area sampling is used. The following commands hit the issue:
echo 10000 > /proc/sys/kernel/perf_event_max_sample_rate
perf record -F32000 --aux-sample -e '{intel_pt//u,cycles:u}' \
-- bash -c 'for i in `seq 1 100000` ; do true ; done'Use PERF_HES_UPTODATE to track whether perf_aux_output_begin() and perf_aux_output_end() are balanced. A cleared PERF_HES_UPTODATE bit indicates that an AUX output context is still open.
Amend pt_event_start() / pt_event_stop() accordingly so that begin/end stay balanced:
- In non-snapshot mode, stop() always closes the buffer (the buffer may have run out of space, and that accounting is done by the update), so a following start() opens a fresh one as before.
- In snapshot/overwrite mode, stop() without PERF_EF_UPDATE leaves the buffer open so that pt_event_snapshot_aux() can still copy from it, and start() then only re-enables tracing instead of calling perf_aux_output_begin() again.
Note that pt_event_del() calls pt_event_stop() with PERF_EF_UPDATE flag set (as is required by the documentation), so a final call to perf_aux_output_end() is assured.
--- arch/x86/events/intel/pt.c | 45 ++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 9 deletions(-)
arch/x86/events/intel/pt.c +36 -9
@@ -1537,6 +1537,8 @@ void intel_pt_interrupt(void)perf_aux_output_end (&pt->handle,local_xchg (&buf->data_size,0 )); + event->hw.state |=PERF_HES_UPTODATE ; +if (!(event->hw.state &PERF_HES_STOPPED )) {int ret;
@@ -1558,6 +1560,8 @@ void intel_pt_interrupt(void)pt_config_buffer (buf);pt_config_start (event); + + event->hw.state &= ~PERF_HES_UPTODATE ; } }
@@ -1627,6 +1631,18 @@ static void pt_event_start(struct perf_event *event, int mode)return ; } +/* +* Re-start subsequent to a call to pt_event_stop() without the +* PERF_EF_UPDATE flag. Absence of PERF_HES_UPTODATE indicates that +* perf_aux_output_begin() has already been called. This path can +* come about only in snapshot/overwrite mode - see pt_event_stop(). +*/ +if (!(hwc->state &PERF_HES_UPTODATE )) { + hwc->state &= ~PERF_HES_STOPPED ; +pt_config_enable (event); +return ; + } + buf =perf_aux_output_begin (&pt->handle, event);if (!buf) goto fail_stop;
@@ -1637,7 +1653,7 @@ static void pt_event_start(struct perf_event *event, int mode) goto fail_end_stop; } - hwc->state &= ~PERF_HES_STOPPED ; + hwc->state &= ~(PERF_HES_STOPPED |PERF_HES_UPTODATE );pt_config_buffer (buf);pt_config (event);
@@ -1647,12 +1663,13 @@ static void pt_event_start(struct perf_event *event, int mode) fail_end_stop:perf_aux_output_end (&pt->handle,0 ); fail_stop: - hwc->state |=PERF_HES_STOPPED ; + hwc->state |=PERF_HES_STOPPED |PERF_HES_UPTODATE ; }static void pt_event_stop (struct perf_event *event,int mode) {struct pt *pt =this_cpu_ptr (&pt_ctx); +struct pt_buffer *buf;if (mode &PERF_EF_PAUSE ) {if (READ_ONCE (pt->pause_allowed))
@@ -1678,17 +1695,24 @@ static void pt_event_stop(struct perf_event *event, int mode)pt_config_stop (event); -if (event->hw.state &PERF_HES_STOPPED ) -return ; - event->hw.state |=PERF_HES_STOPPED ; -if (mode &PERF_EF_UPDATE ) { -struct pt_buffer *buf =perf_get_aux (&pt->handle); +if (event->hw.state &PERF_HES_UPTODATE ) +return ; -if (!buf) -return ; + buf =perf_get_aux (&pt->handle); +if (!buf) +return ; +/* +* When not in snapshot/overwrite mode, there is a possibility that the +* buffer has run out of space. The accounting for that is handled by +* the update, so always update in that case. Snapshot/overwrite mode is +* treated differently to allow for pt_event_snapshot_aux() which can +* still get called if the AUX-sampling event is not stopped until after +* PT is stopped. +*/ +if ((mode &PERF_EF_UPDATE ) || !buf->snapshot) {if (WARN_ON_ONCE (pt->handle.event != event))return ;
@@ -1703,6 +1727,7 @@ static void pt_event_stop(struct perf_event *event, int mode)local_xchg (&buf->data_size, buf->nr_pages <<PAGE_SHIFT );perf_aux_output_end (&pt->handle,local_xchg (&buf->data_size,0 )); + event->hw.state |=PERF_HES_UPTODATE ; } }
@@ -1773,6 +1798,8 @@ static int pt_event_add(struct perf_event *event, int mode)if (pt->handle.event) goto fail; + event->hw.state |=PERF_HES_UPTODATE ; +if (mode &PERF_EF_START ) {pt_event_start (event,0 ); ret = -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 968/1376 sched/fair: Check CPU capacity before comparing group types during load balance
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Neri <[email protected]>
[ Upstream commit 50b101f6e586b4417d060a976fd831cd87e86e2b ]
update_sd_pick_busiest() may incorrectly select a fully_busy group as the busiest group when its per-CPU capacity exceeds that of the destination CPU. This happens because the type of busiest group is initialized to group_has_spare and allows the fully_busy group to win the type comparison.
update_sd_pick_busiest() should not choose a candidate scheduling group with at most one runnable task if its per-CPU capacity is greater than that of the destination CPU. Such a check already exists, but it is done too
late: after the type comparison, preventing a subsequent fully_busy group of equal per-CPU capacity from being correctly selected.
Move this check to occur before comparing group types.
--- kernel/sched/fair.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
kernel/sched/fair.c +11 -11
@@ -10537,6 +10537,17 @@ static bool update_sd_pick_busiest(struct lb_env *env, sds->local_stat.group_type != group_has_spare))return false; +/* +* Candidate sg has no more than one task per CPU and has higher +* per-CPU capacity. Migrating tasks to less capable CPUs may harm +* throughput. Maximize throughput, power/energy consequences are not +* considered. +*/ +if ((env->sd->flags &SD_ASYM_CPUCAPACITY ) && + (sgs->group_type <= group_fully_busy) && + (capacity_greater (sg->sgc->min_capacity,capacity_of (env->dst_cpu)))) +return false; +if (sgs->group_type > busiest->group_type)return true;
@@ -10638,17 +10649,6 @@ static bool update_sd_pick_busiest(struct lb_env *env,break ; } -/* -* Candidate sg has no more than one task per CPU and has higher -* per-CPU capacity. Migrating tasks to less capable CPUs may harm -* throughput. Maximize throughput, power/energy consequences are not -* considered. -*/ -if ((env->sd->flags &SD_ASYM_CPUCAPACITY ) && - (sgs->group_type <= group_fully_busy) && - (capacity_greater (sg->sgc->min_capacity,capacity_of (env->dst_cpu)))) -return false; -return true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 969/1376 Bluetooth: btqca: Fix qca_set_bdaddr() waiting for wrong HCI event
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit cf81f0a3db2a5c34ee6e4ea379c631fab6d13e01 ]
qca_set_bdaddr() waits for HCI_EV_VENDOR when sending EDL_WRITE_BD_ADDR_OPCODE (0xFC14), but the controller responds with Command Complete event as confirmed by btmon on WCN7850:
< HCI Command: Vendor (0x3f|0x0014) plen 6 #3 [hci0]
11 22 33 44 55 66
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4 #4 [hci0]
Vendor (0x3f|0x0014) ncmd 1
Status: Success (0x00)Fix by passing 0 as the event parameter to __hci_cmd_sync_ev() to wait for the command complete event instead.
--- drivers/bluetooth/btqca.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/bluetooth/btqca.c +1 -2
@@ -996,8 +996,7 @@ int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)baswap (&bdaddr_swapped, bdaddr); skb =__hci_cmd_sync_ev (hdev,EDL_WRITE_BD_ADDR_OPCODE ,6 , - &bdaddr_swapped,HCI_EV_VENDOR , -HCI_INIT_TIMEOUT ); + &bdaddr_swapped,0 ,HCI_INIT_TIMEOUT );if (IS_ERR (skb)) { err =PTR_ERR (skb);bt_dev_err (hdev,"QCA Change address cmd failed (%d)" , err);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 970/1376 Bluetooth: btusb: Fix BD_ADDR byte order in btusb_set_bdaddr_wcn6855()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit d0b15d812688d3f0f3fe1c4426e12814d0c294dc ]
btusb_set_bdaddr_wcn6855() sends the address without swapping byte order for VSC 0xFC14, but the command expects the address in reversed byte order compared to other HCI commands like HCI_Create_Connection, resulting in a wrong BD_ADDR being set.
btmon log on WCN6855 shows VSC 0xFC14 is sent with swapped bytes 11 22 33 44 55 66, and Read BD ADDR returns the expected address 11:22:33:44:55:66:
< HCI Command: Vendor (0x3f|0x0014) plen 6 #3 [hci0]
11 22 33 44 55 66
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 4 #4 [hci0]
Vendor (0x3f|0x0014) ncmd 1
Status: Success (0x00)< HCI Command: Read BD ADDR (0x04|0x0009) plen 0 #11 [hci0]
Quoted 1 line
HCI Event: Command Complete (
0x0e) plen 10 #12 [hci0]
Read BD ADDR (0x04|0x0009) ncmd 1
Status: Success (0x00)
Address: 11:22:33:44:55:66 (OUI 11-22-33)Fix by swapping the input address before issuing the command.
--- drivers/bluetooth/btusb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/bluetooth/btusb.c +5 -4
@@ -2990,14 +2990,15 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,static int btusb_set_bdaddr_wcn6855 (struct hci_dev *hdev,const bdaddr_t *bdaddr) { +bdaddr_t bdaddr_swapped;struct sk_buff *skb; -u8 buf[6 ];long ret; -memcpy (buf, bdaddr,sizeof (bdaddr_t)); +baswap (&bdaddr_swapped, bdaddr); - skb =__hci_cmd_sync_ev (hdev,0xfc14 ,sizeof (buf), buf, -HCI_EV_CMD_COMPLETE ,HCI_INIT_TIMEOUT ); + skb =__hci_cmd_sync_ev (hdev,0xfc14 ,sizeof (bdaddr_swapped), + &bdaddr_swapped,HCI_EV_CMD_COMPLETE , +HCI_INIT_TIMEOUT );if (IS_ERR (skb)) { ret =PTR_ERR (skb);bt_dev_err (hdev,"Change address command failed (%ld)" , ret);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 971/1376 Bluetooth: btusb: refactor endpoint lookup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
[ Upstream commit 5c31aaa05624b54dc18c9e313bcee5a88c025593 ]
Use the common USB helper for looking up bulk and interrupt endpoints instead of open coding.
Stable-dep-of: 33c6a8d01889 ("Bluetooth: btusb: QCA: Fix populating devcoredump fields on unenabled devices")
--- drivers/bluetooth/btusb.c | 51 ++++++--------------------------------- 1 file changed, 8 insertions(+), 43 deletions(-)
drivers/bluetooth/btusb.c +8 -43
@@ -3597,31 +3597,14 @@ static inline int __set_diag_interface(struct hci_dev *hdev) {struct btusb_data *data =hci_get_drvdata (hdev);struct usb_interface *intf = data->diag; -int i; +int ret;if (!data->diag)return -ENODEV ; - data->diag_tx_ep =NULL ; - data->diag_rx_ep =NULL ; - -for (i =0 ; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { -struct usb_endpoint_descriptor *ep_desc; - - ep_desc = &intf->cur_altsetting->endpoint[i].desc; - -if (!data->diag_tx_ep &&usb_endpoint_is_bulk_out (ep_desc)) { - data->diag_tx_ep = ep_desc; -continue ; - } - -if (!data->diag_rx_ep &&usb_endpoint_is_bulk_in (ep_desc)) { - data->diag_rx_ep = ep_desc; -continue ; - } - } - -if (!data->diag_tx_ep || !data->diag_rx_ep) { + ret =usb_find_common_endpoints (intf->cur_altsetting, &data->diag_rx_ep, + &data->diag_tx_ep,NULL ,NULL ); +if (ret) {bt_dev_err (hdev,"invalid diagnostic descriptors" );return -ENODEV ; }
@@ -3822,12 +3805,11 @@ static const struct file_operations force_poll_sync_fops = {static int btusb_probe (struct usb_interface *intf,const struct usb_device_id *id) { -struct usb_endpoint_descriptor *ep_desc;struct gpio_desc *reset_gpio;struct btusb_data *data;struct hci_dev *hdev;unsigned ifnum_base; -int i, err, priv_size; +int err, priv_size;BT_DBG ("intf %p id %p" , intf, id);
@@ -3864,26 +3846,9 @@ static int btusb_probe(struct usb_interface *intf,if (!data)return -ENOMEM ; -for (i =0 ; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { - ep_desc = &intf->cur_altsetting->endpoint[i].desc; - -if (!data->intr_ep &&usb_endpoint_is_int_in (ep_desc)) { - data->intr_ep = ep_desc; -continue ; - } - -if (!data->bulk_tx_ep &&usb_endpoint_is_bulk_out (ep_desc)) { - data->bulk_tx_ep = ep_desc; -continue ; - } - -if (!data->bulk_rx_ep &&usb_endpoint_is_bulk_in (ep_desc)) { - data->bulk_rx_ep = ep_desc; -continue ; - } - } - -if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { + err =usb_find_common_endpoints (intf->cur_altsetting, &data->bulk_rx_ep, + &data->bulk_tx_ep, &data->intr_ep,NULL ); +if (err) {kfree (data);return -ENODEV ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 972/1376 Bluetooth: btusb: Record matched usb_device_id into btusb_data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit ff50db7a522e7bd3bd1c4db6da715e4bdb53af97 ]
Add @match_id to btusb_data to record the matched usb_device_id which will be used later.
Stable-dep-of: 33c6a8d01889 ("Bluetooth: btusb: QCA: Fix populating devcoredump fields on unenabled devices")
--- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/bluetooth/btusb.c +2 -0
@@ -949,6 +949,7 @@ struct btusb_data {bool usb_alt6_packet_flow;int isoc_altsetting;int suspend_count; +const struct usb_device_id *match_id;int (*recv_event)(struct hci_dev *hdev,struct sk_buff *skb);int (*recv_acl)(struct hci_dev *hdev,struct sk_buff *skb);
@@ -3846,6 +3847,7 @@ static int btusb_probe(struct usb_interface *intf,if (!data)return -ENOMEM ; + data->match_id = id; err =usb_find_common_endpoints (intf->cur_altsetting, &data->bulk_rx_ep, &data->bulk_tx_ep, &data->intr_ep,NULL );if (err) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 973/1376 Bluetooth: btusb: QCA: Fix populating devcoredump fields on unenabled devices
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit 33c6a8d01889a84cc773c0c20c8323bce84af27d ]
Devcoredump is not enabled for ATH3012 or QCA_ROME, but they unconditionally populate devcoredump fields in btusb_setup_qca().
Fix by populating devcoredump fields only when BTUSB_QCA_WCN6855 is set, which marks the first generation of QCA BT SoCs for which devcoredump is enabled.
--- drivers/bluetooth/btusb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/bluetooth/btusb.c +4 -2
@@ -3570,8 +3570,10 @@ static int btusb_setup_qca(struct hci_dev *hdev)if (err)return err; - btdata->qca_dump.fw_version =le32_to_cpu (ver.patch_version); - btdata->qca_dump.controller_id =le32_to_cpu (ver.rom_version); +if (btdata->match_id->driver_info &BTUSB_QCA_WCN6855 ) { + btdata->qca_dump.fw_version =le32_to_cpu (ver.patch_version); + btdata->qca_dump.controller_id =le32_to_cpu (ver.rom_version); + }if (!(status &QCA_SYSCFG_UPDATED )) { err =btusb_setup_qca_load_nvm (hdev, &ver, info);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 974/1376 perf trace-event: Fix integer truncation in do_read() and skip()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tanushree Shah <[email protected]>
[ Upstream commit c108c1391be0826920991d24532fbae8f6373ddc ]
The do_read() and skip() functions use 'int' for size parameters, truncating 64-bit sizes from callers. This causes two issues:
1. Uninitialized memory dump: do_read() reads fewer bytes than allocated, leaving uninitialized heap memory that gets written to output files.
2. Out-of-bounds read: Parsing functions process the full 64-bit size while only partial data was read into the buffer.
Change do_read(), __do_read(), and skip() to use size_t for size parameters and ssize_t for return values (where applicable), matching read()/write() system calls.
Update callers to use ssize_t for storing return values.
--- tools/perf/util/trace-event-read.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
tools/perf/util/trace-event-read.c +14 -14
@@ -25,18 +25,18 @@ static int input_fd;static ssize_t trace_data_size;static bool repipe; -static int __do_read (int fd,void *buf,int size) +static ssize_t __do_read (int fd,void *buf,size_t size) { -int rsize = size; +size_t rsize = size;while (size) { -int ret =read (fd, buf, size); +ssize_t ret =read (fd, buf, size);if (ret <=0 )return -1 ;if (repipe) { -int retw =write (STDOUT_FILENO , buf, ret); +ssize_t retw =write (STDOUT_FILENO , buf, ret);if (retw <=0 || retw != ret) {pr_debug ("repiping input file" );
@@ -51,13 +51,13 @@ static int __do_read(int fd, void *buf, int size)return rsize; } -static int do_read (void *data,int size) +static ssize_t do_read (void *data,size_t size) { -int r; +ssize_t r; r =__do_read (input_fd, data, size);if (r <=0 ) { -pr_debug ("reading input file (size expected=%d received=%d)" , +pr_debug ("reading input file (size expected=%zu received=%zd)" , size, r);return -1 ; }
@@ -68,10 +68,10 @@ static int do_read(void *data, int size) }/* If it fails, the next read will report it */ -static void skip (int size) +static void skip (size_t size) {char buf[BUFSIZ ]; -int r; +size_t r;while (size) { r = size >BUFSIZ ?BUFSIZ : size;
@@ -202,7 +202,7 @@ static int read_header_files(struct tep_handle *pevent)unsigned long long size;char *header_page;char buf[BUFSIZ ]; -int ret =0 ; +ssize_t ret =0 ;if (do_read (buf,12 ) <0 )return -1 ;
@@ -250,7 +250,7 @@ static int read_header_files(struct tep_handle *pevent)static int read_ftrace_file (struct tep_handle *pevent,unsigned long long size) { -int ret; +ssize_t ret;char *buf; buf =malloc (size);
@@ -276,7 +276,7 @@ static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)static int read_event_file (struct tep_handle *pevent,char *sys,unsigned long long size) { -int ret; +ssize_t ret;char *buf; buf =malloc (size);
@@ -322,7 +322,7 @@ static int read_event_files(struct tep_handle *pevent)int systems;int count;int i,x; -int ret; +ssize_t ret; systems =read4 (pevent);
@@ -350,7 +350,7 @@ static int read_saved_cmdline(struct tep_handle *pevent) {unsigned long long size;char *buf; -int ret; +ssize_t ret;/* it can have 0 size */ size =read8 (pevent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 975/1376 block/bdev: lift block size restrictions to 64k
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luis Chamberlain <[email protected]>
[ Upstream commit 47dd67532303803a87f43195e088b3b4bcf0454d ]
We now can support blocksizes larger than PAGE_SIZE, so in theory we should be able to lift the restriction up to the max supported page cache order. However bound ourselves to what we can currently validate and test. Through blktests and fstest we can validate up to 64k today.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- block/bdev.c | 3 +-- include/linux/blkdev.h | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-)
block/bdev.c +1 -2
@@ -198,8 +198,7 @@ int sb_set_blocksize(struct super_block *sb, int size) {if (set_blocksize (sb->s_bdev_file, size))return 0 ; -/* If we get here, we know size is power of two -* and it's value is between 512 and PAGE_SIZE */ +/* If we get here, we know size is validated */ sb->s_blocksize = size; sb->s_blocksize_bits =blksize_bits (size);return sb->s_blocksize;
include/linux/blkdev.h +7 -1
@@ -268,10 +268,16 @@ static inline dev_t disk_devt(struct gendisk *disk)return MKDEV (disk->major, disk->first_minor); } +/* +* We should strive for 1 << (PAGE_SHIFT + MAX_PAGECACHE_ORDER) +* however we constrain this to what we can validate and test. +*/ +#define BLK_MAX_BLOCK_SIZE SZ_64K +/* blk_validate_limits() validates bsize, so drivers don't usually need to */ static inline int blk_validate_block_size (unsigned long bsize) { -if (bsize <512 || bsize >PAGE_SIZE || !is_power_of_2 (bsize)) +if (bsize <512 || bsize >BLK_MAX_BLOCK_SIZE || !is_power_of_2 (bsize))return -EINVAL ;return 0 ;
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0975/1376] block/bdev: lift block size restrictions to 64k
Quoted 48 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luis Chamberlain <[email protected]>
[ Upstream commit
47dd67532303803a87f43195e088b3b4bcf0454d]We now can support blocksizes larger than
PAGE_SIZE, so in theory we should be able to lift the restriction up to the max supported page cache order. However bound ourselves to what we can currently validate and test. Through blktests and fstest we can validate up to 64k today.Reviewed-by Hannes Reinecke <[email protected]>Reviewed-by "Matthew Wilcox (Oracle)" <[email protected]>Signed-off-by Luis Chamberlain <[email protected]>Signed-off-by Christian Brauner <[email protected]>Stable-dep-of:
bb31844d88b7("scsi: sd: Fixspecial_vecmempool leak whenscsi_alloc_sgtables()fails")Signed-off-by Sasha Levin <[email protected]>--- block/bdev.c | 3 +-- include/linux/blkdev.h | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-)block/bdev.c +1
-2@@ -198,8 +198,7 @@ int sb_set_blocksize(struct super_block *sb, int size) {if (set_blocksize (sb->s_bdev_file, size))return 0 ; -/* If we get here, we know size is power of two -* and it's value is between 512 and PAGE_SIZE */ +/* If we get here, we know size is validated */ sb->s_blocksize = size; sb->s_blocksize_bits =blksize_bits (size);return sb->s_blocksize;include/linux/blkdev.h +1
-0@@ -268,10 +268,16 @@ static inline dev_t disk_devt(struct gendisk *disk)return MKDEV (disk->major, disk->first_minor); } +/*
include/linux/blkdev.h static inline dev_t disk_devt(struct gendisk *disk) · line 280
Quoted 10 lines
include/linux/blkdev.h +6
-1+* We should strive for 1 << (PAGE_SHIFT + MAX_PAGECACHE_ORDER) +* however we constrain this to what we can validate and test. +*/ +#define BLK_MAX_BLOCK_SIZE SZ_64K +/* blk_validate_limits() validates bsize, so drivers don't usually need to */ static inline int blk_validate_block_size (unsigned long bsize) { -if (bsize <512 || bsize >PAGE_SIZE || !is_power_of_2 (bsize)) +if (bsize <512 || bsize >BLK_MAX_BLOCK_SIZE || !is_power_of_2 (bsize))
Hi Greg/Sasha,
I ran an AI-assisted backport review and manually verified the finding.
The backport allows SCSI to accept logical sectors up to 64 KiB:
#define BLK_MAX_BLOCK_SIZE SZ_64K
if (blk_validate_block_size(sector_size)) {
sector_size = 512;
}However, set_init_blocksize() only changes i_blkbits; it does not establish the matching minimum folio order:
BD_INODE(bdev)->i_blkbits = blksize_bits(bsize);
A buffered read can therefore use a 4-KiB folio with a 64-KiB block size. folio_create_buffers() returns NULL because the buffer does not fit, and the caller immediately dereferences it:
head = folio_create_buffers(folio, inode, 0); blocksize = head->b_size;
The mpage path also retains:
block_in_file = (sector_t)folio->index << (PAGE_SHIFT - blkbits);
which uses an invalid negative shift when the block size exceeds PAGE_SIZE.
The missing support includes 26fff8a4432f, 86c60efd7c0e, 8b45a4f4133d, e59e97d42b05, 3c20917120ce, and 4cdf1bdd45ac.
Maybe we should drop this/revert this.
Thanks,
Harshit
Quoted 3 lines
include/linux/blkdev.h +0
-0return -EINVAL ;return 0 ;
Greg Kroah-Hartman
maintainerPATCH 976/1376 scsi: core: Pass a struct scsi_driver to scsi_{,un}register_driver()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 7d42bcea57ae139e2ed754425cc5fc44e260c890 ]
This aligns with what other subsystems do, reduces boilerplate a bit for device drivers and is less error prone.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- drivers/scsi/ch.c | 4 ++-- drivers/scsi/scsi_sysfs.c | 4 +++- drivers/scsi/sd.c | 4 ++-- drivers/scsi/ses.c | 4 ++-- drivers/scsi/sr.c | 4 ++-- drivers/scsi/st.c | 4 ++-- drivers/ufs/core/ufshcd.c | 4 ++-- include/scsi/scsi_driver.h | 4 ++-- 8 files changed, 17 insertions(+), 15 deletions(-)
drivers/scsi/ch.c +2 -2
@@ -1014,7 +1014,7 @@ static int __init init_ch_module(void) SCSI_CHANGER_MAJOR); goto fail1; } - rc =scsi_register_driver (&ch_template.gendrv); + rc =scsi_register_driver (&ch_template);if (rc <0 ) goto fail2;return 0 ;
@@ -1028,7 +1028,7 @@ static int __init init_ch_module(void) static void __exit exit_ch_module(void) { -scsi_unregister_driver (&ch_template.gendrv); +scsi_unregister_driver (&ch_template);unregister_chrdev (SCSI_CHANGER_MAJOR ,"ch" );class_unregister (&ch_sysfs_class);idr_destroy (&ch_index_idr);
drivers/scsi/scsi_sysfs.c +3 -1
@@ -1609,8 +1609,10 @@ void scsi_remove_target(struct device *dev) }EXPORT_SYMBOL (scsi_remove_target); -int __scsi_register_driver (struct device_driver *drv,struct module *owner) +int __scsi_register_driver (struct scsi_driver *sdrv,struct module *owner) { +struct device_driver *drv = &sdrv->gendrv; + drv->bus = &scsi_bus_type; drv->owner = owner;
drivers/scsi/sd.c +2 -2
@@ -4378,7 +4378,7 @@ static int __init init_sd(void) goto err_out_class; } - err =scsi_register_driver (&sd_template.gendrv); + err =scsi_register_driver (&sd_template);if (err) goto err_out_driver;
@@ -4405,7 +4405,7 @@ static void __exit exit_sd(void)SCSI_LOG_HLQUEUE (3 ,printk ("exit_sd: exiting sd driver\n" )); -scsi_unregister_driver (&sd_template.gendrv); +scsi_unregister_driver (&sd_template);mempool_destroy (sd_page_pool);class_unregister (&sd_disk_class);
drivers/scsi/ses.c +2 -2
@@ -920,7 +920,7 @@ static int __init ses_init(void)if (err)return err; - err =scsi_register_driver (&ses_template.gendrv); + err =scsi_register_driver (&ses_template);if (err) goto out_unreg;
@@ -933,7 +933,7 @@ static int __init ses_init(void) static void __exit ses_exit(void) { -scsi_unregister_driver (&ses_template.gendrv); +scsi_unregister_driver (&ses_template);scsi_unregister_interface (&ses_interface); }
drivers/scsi/sr.c +2 -2
@@ -994,7 +994,7 @@ static int __init init_sr(void) rc =register_blkdev (SCSI_CDROM_MAJOR ,"sr" );if (rc)return rc; - rc =scsi_register_driver (&sr_template.gendrv); + rc =scsi_register_driver (&sr_template);if (rc)unregister_blkdev (SCSI_CDROM_MAJOR ,"sr" );
@@ -1003,7 +1003,7 @@ static int __init init_sr(void) static void __exit exit_sr(void) { -scsi_unregister_driver (&sr_template.gendrv); +scsi_unregister_driver (&sr_template);unregister_blkdev (SCSI_CDROM_MAJOR ,"sr" ); }
drivers/scsi/st.c +2 -2
@@ -4510,7 +4510,7 @@ static int __init init_st(void) goto err_class; } - err =scsi_register_driver (&st_template.gendrv); + err =scsi_register_driver (&st_template);if (err) goto err_chrdev;
@@ -4526,7 +4526,7 @@ static int __init init_st(void) static void __exit exit_st(void) { -scsi_unregister_driver (&st_template.gendrv); +scsi_unregister_driver (&st_template);unregister_chrdev_region (MKDEV (SCSI_TAPE_MAJOR ,0 ),ST_MAX_TAPE_ENTRIES );class_unregister (&st_sysfs_class);
drivers/ufs/core/ufshcd.c +2 -2
@@ -10935,7 +10935,7 @@ static int __init ufshcd_core_init(void)ufs_debugfs_init (); - ret =scsi_register_driver (&ufs_dev_wlun_template.gendrv); + ret =scsi_register_driver (&ufs_dev_wlun_template);if (ret)ufs_debugfs_exit ();return ret;
@@ -10944,7 +10944,7 @@ static int __init ufshcd_core_init(void) static void __exit ufshcd_core_exit(void) {ufs_debugfs_exit (); -scsi_unregister_driver (&ufs_dev_wlun_template.gendrv); +scsi_unregister_driver (&ufs_dev_wlun_template); }module_init (ufshcd_core_init);
include/scsi/scsi_driver.h +2 -2
@@ -25,9 +25,9 @@ struct scsi_driver {#define scsi_register_driver (drv) \ __scsi_register_driver(drv, THIS_MODULE) -int __scsi_register_driver (struct device_driver *,struct module *); +int __scsi_register_driver (struct scsi_driver *,struct module *);#define scsi_unregister_driver (drv) \ - driver_unregister(drv); + driver_unregister(&(drv)->gendrv);extern int scsi_register_interface (struct class_interface *);#define scsi_unregister_interface (intf) \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 977/1376 scsi: core: sysfs: Make use of bus callbacks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit f7d4f1bf5724e52de049c619beddd53c62206624 ]
Introduce a bus-specific probe, remove and shutdown function. For now this only allows to get rid of a cast of the generic device to a SCSI device in the drivers and changes the remove prototype to return void---a non-zero return value is ignored anyhow.
The objective is to get rid of users of struct device_driver callbacks .probe(), .remove() and .shutdown() to eventually remove these. Until all SCSI drivers are converted, this results in a runtime warning about the drivers needing an update because there is a bus probe function and a driver probe function. The in-tree drivers are fixed by the following commits.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- drivers/scsi/scsi_sysfs.c | 73 ++++++++++++++++++++++++++++++++++++-- include/scsi/scsi_driver.h | 3 ++ 2 files changed, 74 insertions(+), 2 deletions(-)
drivers/scsi/scsi_sysfs.c +71 -2
@@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *envreturn 0 ; } +static int scsi_bus_probe (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv =to_scsi_driver (dev->driver); + +if (drv->probe) +return drv->probe (sdp); +else +return 0 ; +} + +static void scsi_bus_remove (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv =to_scsi_driver (dev->driver); + +if (drv->remove) + drv->remove (sdp); +} + +static void scsi_bus_shutdown (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv; + +if (!dev->driver) +return ; + + drv =to_scsi_driver (dev->driver); + +if (drv->shutdown) + drv->shutdown (sdp); +} + +const struct bus_type scsi_bus_type = { - .name ="scsi" , - .match = scsi_bus_match, + .name ="scsi" , + .match = scsi_bus_match, .uevent = scsi_bus_uevent, + .probe = scsi_bus_probe, + .remove = scsi_bus_remove, + .shutdown = scsi_bus_shutdown, #ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif
@@ -1609,6 +1647,30 @@ void scsi_remove_target(struct device *dev) }EXPORT_SYMBOL (scsi_remove_target); +static int scsi_legacy_probe (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + +return driver->probe (dev); +} + +static void scsi_legacy_remove (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + + driver->remove (dev); +} + +static void scsi_legacy_shutdown (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + + driver->shutdown (dev); +} +int __scsi_register_driver (struct scsi_driver *sdrv,struct module *owner) {struct device_driver *drv = &sdrv->gendrv;
@@ -1616,6 +1678,13 @@ int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) drv->bus = &scsi_bus_type; drv->owner = owner; +if (!sdrv->probe && drv->probe) + sdrv->probe = scsi_legacy_probe; +if (!sdrv->remove && drv->remove) + sdrv->remove = scsi_legacy_remove; +if (!sdrv->shutdown && drv->shutdown) + sdrv->shutdown = scsi_legacy_shutdown; +return driver_register (drv); }EXPORT_SYMBOL (__scsi_register_driver);
include/scsi/scsi_driver.h +3 -0
@@ -12,6 +12,9 @@ struct request;struct scsi_driver {struct device_driver gendrv; +int (*probe)(struct scsi_device *); +void (*remove)(struct scsi_device *); +void (*shutdown)(struct scsi_device *);int (*resume)(struct device *);void (*rescan)(struct device *);blk_status_t (*init_command)(struct scsi_cmnd *);
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0977/1376] scsi: core: sysfs: Make use of bus callbacks
Am 12.09.2026 um 08:56 schrieb Greg Kroah-Hartman:
Quoted 137 lines
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit
f7d4f1bf5724e52de049c619beddd53c62206624]Introduce a bus-specific probe, remove and shutdown function. For now this only allows to get rid of a cast of the generic device to a SCSI device in the drivers and changes the remove prototype to return void---a non-zero return value is ignored anyhow.
The objective is to get rid of users of struct
device_drivercallbacks .probe(), .remove() and .shutdown() to eventually remove these. Until all SCSI drivers are converted, this results in a runtime warning about the drivers needing an update because there is a bus probe function and a driver probe function. The in-tree drivers are fixed by the following commits.Signed-off-by Uwe Kleine-König <[email protected]>Reviewed-by Peter Wang <[email protected]>Reviewed-by Bart Van Assche <[email protected]>Link https://patch.msgid.link/a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com open hereSigned-off-by Martin K. Petersen <[email protected]>Stable-dep-of:
bb31844d88b7("scsi: sd: Fixspecial_vecmempool leak whenscsi_alloc_sgtables()fails")Signed-off-by Sasha Levin <[email protected]>--- drivers/scsi/scsi_sysfs.c | 73 ++++++++++++++++++++++++++++++++++++-- include/scsi/scsi_driver.h | 3 ++ 2 files changed, 74 insertions(+), 2 deletions(-)drivers/scsi/scsi_sysfs.c +71
-2@@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *envreturn 0 ; } +static int scsi_bus_probe (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv =to_scsi_driver (dev->driver); + +if (drv->probe) +return drv->probe (sdp); +else +return 0 ; +} + +static void scsi_bus_remove (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv =to_scsi_driver (dev->driver); + +if (drv->remove) + drv->remove (sdp); +} + +static void scsi_bus_shutdown (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv; + +if (!dev->driver) +return ; + + drv =to_scsi_driver (dev->driver); + +if (drv->shutdown) + drv->shutdown (sdp); +} + +const struct bus_type scsi_bus_type = { - .name ="scsi" , - .match = scsi_bus_match, + .name ="scsi" , + .match = scsi_bus_match, .uevent = scsi_bus_uevent, + .probe = scsi_bus_probe, + .remove = scsi_bus_remove, + .shutdown = scsi_bus_shutdown, #ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif@@ -1609,6 +1647,30 @@ void scsi_remove_target(struct device *dev) }EXPORT_SYMBOL (scsi_remove_target); +static int scsi_legacy_probe (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + +return driver->probe (dev); +} + +static void scsi_legacy_remove (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + + driver->remove (dev); +} + +static void scsi_legacy_shutdown (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + + driver->shutdown (dev); +} +int __scsi_register_driver (struct scsi_driver *sdrv,struct module *owner) {struct device_driver *drv = &sdrv->gendrv;@@ -1616,6 +1678,13 @@ int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) drv->bus = &scsi_bus_type; drv->owner = owner; +if (!sdrv->probe && drv->probe) + sdrv->probe = scsi_legacy_probe; +if (!sdrv->remove && drv->remove) + sdrv->remove = scsi_legacy_remove; +if (!sdrv->shutdown && drv->shutdown) + sdrv->shutdown = scsi_legacy_shutdown; +return driver_register (drv); }EXPORT_SYMBOL (__scsi_register_driver);include/scsi/scsi_driver.h +0
-0
include/scsi/scsi_driver.h struct request; · line 20
Quoted 9 lines
include/scsi/scsi_driver.h +3
-0@@ -12,6 +12,9 @@ struct request;struct scsi_driver {struct device_driver gendrv; +int (*probe)(struct scsi_device *); +void (*remove)(struct scsi_device *); +void (*shutdown)(struct scsi_device *);int (*resume)(struct device *);void (*rescan)(struct device *);blk_status_t (*init_command)(struct scsi_cmnd *);
As Wentao Guan pointed out, this is the patch that caused the dmesg warnings I encountered in boot-testing 6.12.110-rc1 and 6.18.52-rc1 on my machine:
[ 2.397237] Driver 'sr' needs updating - please use bus_type methods ... [ 84.031323] Driver 'ses' needs updating - please use bus_type methods
Is this really stable material? I feel that a new stable release should not trigger new warning messages. Feels like a regression, even if it does no harm... No?!
Or are there some driver patches missing that still need proper backports?
CC'ing linux-scsi list, too.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Greg Kroah-Hartman
maintainerRe: [PATCH 6.12 0977/1376] scsi: core: sysfs: Make use of bus callbacks
Quoted 152 lines · Peter Schneider
Am 12.09.2026 um 08:56 schrieb Greg Kroah-Hartman:
Quoted 134 lines
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit
f7d4f1bf5724e52de049c619beddd53c62206624]Introduce a bus-specific probe, remove and shutdown function. For now this only allows to get rid of a cast of the generic device to a SCSI device in the drivers and changes the remove prototype to return void---a non-zero return value is ignored anyhow.
The objective is to get rid of users of struct
device_drivercallbacks .probe(), .remove() and .shutdown() to eventually remove these. Until all SCSI drivers are converted, this results in a runtime warning about the drivers needing an update because there is a bus probe function and a driver probe function. The in-tree drivers are fixed by the following commits.Signed-off-by Uwe Kleine-König <[email protected]>Reviewed-by Peter Wang <[email protected]>Reviewed-by Bart Van Assche <[email protected]>Link https://patch.msgid.link/a54e363a3fd2054fb924afd7df44bca7f444b5f1.1766133330.git.u.kleine-koenig@baylibre.com open hereSigned-off-by Martin K. Petersen <[email protected]>Stable-dep-of:
bb31844d88b7("scsi: sd: Fixspecial_vecmempool leak whenscsi_alloc_sgtables()fails")Signed-off-by Sasha Levin <[email protected]>--- drivers/scsi/scsi_sysfs.c | 73 ++++++++++++++++++++++++++++++++++++-- include/scsi/scsi_driver.h | 3 ++ 2 files changed, 74 insertions(+), 2 deletions(-)drivers/scsi/scsi_sysfs.c +71
-2@@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *envreturn 0 ; } +static int scsi_bus_probe (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv =to_scsi_driver (dev->driver); + +if (drv->probe) +return drv->probe (sdp); +else +return 0 ; +} + +static void scsi_bus_remove (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv =to_scsi_driver (dev->driver); + +if (drv->remove) + drv->remove (sdp); +} + +static void scsi_bus_shutdown (struct device *dev) +{ +struct scsi_device *sdp =to_scsi_device (dev); +struct scsi_driver *drv; + +if (!dev->driver) +return ; + + drv =to_scsi_driver (dev->driver); + +if (drv->shutdown) + drv->shutdown (sdp); +} + +const struct bus_type scsi_bus_type = { - .name ="scsi" , - .match = scsi_bus_match, + .name ="scsi" , + .match = scsi_bus_match, .uevent = scsi_bus_uevent, + .probe = scsi_bus_probe, + .remove = scsi_bus_remove, + .shutdown = scsi_bus_shutdown, #ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif@@ -1609,6 +1647,30 @@ void scsi_remove_target(struct device *dev) }EXPORT_SYMBOL (scsi_remove_target); +static int scsi_legacy_probe (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + +return driver->probe (dev); +} + +static void scsi_legacy_remove (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + + driver->remove (dev); +} + +static void scsi_legacy_shutdown (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct device_driver *driver = dev->driver; + + driver->shutdown (dev); +} +int __scsi_register_driver (struct scsi_driver *sdrv,struct module *owner) {struct device_driver *drv = &sdrv->gendrv;@@ -1616,6 +1678,13 @@ int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) drv->bus = &scsi_bus_type; drv->owner = owner; +if (!sdrv->probe && drv->probe) + sdrv->probe = scsi_legacy_probe; +if (!sdrv->remove && drv->remove) + sdrv->remove = scsi_legacy_remove; +if (!sdrv->shutdown && drv->shutdown) + sdrv->shutdown = scsi_legacy_shutdown; +return driver_register (drv); }EXPORT_SYMBOL (__scsi_register_driver);include/scsi/scsi_driver.h +0
-0include/scsi/scsi_driver.h struct request; · line 19
Quoted 8 lines
include/scsi/scsi_driver.h +3
-0@@ -12,6 +12,9 @@ struct request;struct scsi_driver {struct device_driver gendrv; +int (*probe)(struct scsi_device *); +void (*remove)(struct scsi_device *); +void (*shutdown)(struct scsi_device *);int (*resume)(struct device *);void (*rescan)(struct device *);blk_status_t (*init_command)(struct scsi_cmnd *);As Wentao Guan pointed out, this is the patch that caused the dmesg warnings I encountered in boot-testing 6.12.110-rc1 and 6.18.52-rc1 on my machine:
[ 2.397237] Driver 'sr' needs updating - please use bus_type methods ... [ 84.031323] Driver 'ses' needs updating - please use bus_type methods
Quoted 7 lines
Is this really stable material? I feel that a new stable release should not trigger new warning messages. Feels like a regression, even if it does no harm... No?!
Or are there some driver patches missing that still need proper backports?
CC'ing linux-scsi list, too.
I've dropped this now, thanks.
greg k-h
Greg Kroah-Hartman
maintainerPATCH 978/1376 scsi: sd: Convert to SCSI bus methods
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uwe Kleine-König <[email protected]>
[ Upstream commit 63b541f054e7147f5a19fcd964677c189bad7cff ]
The SCSI subsystem has implemented dedicated callbacks for probe, remove and shutdown. Make use of them. This fixes a runtime warning about the driver needing to be converted to the bus probe method.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- drivers/scsi/sd.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
drivers/scsi/sd.c +13 -12
@@ -108,7 +108,7 @@ static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim);static int sd_revalidate_disk (struct gendisk *);static void sd_unlock_native_capacity (struct gendisk *disk); -static void sd_shutdown (struct device *); +static void sd_shutdown (struct scsi_device *);static void scsi_disk_release (struct device *cdev);static DEFINE_IDA (sd_index_ida);
@@ -3897,7 +3897,7 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)* sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once * for each scsi device (not just disks) present. -* @dev: pointer to device object +* @sdp: pointer to device object * * Returns 0 if successful (or not interested in this scsi device * (e.g. scanner)); 1 when there is an error.
@@ -3911,9 +3911,9 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen)* Assume sd_probe is not re-entrant (for time being) * Also think about sd_probe() and sd_remove() running coincidentally. **/ -static int sd_probe (struct device *dev) +static int sd_probe (struct scsi_device *sdp) { -struct scsi_device *sdp =to_scsi_device (dev); +struct device *dev = &sdp->sdev_gendev;struct scsi_disk *sdkp;struct gendisk *gd;int index;
@@ -4054,15 +4054,16 @@ static int sd_probe(struct device *dev)* sd_remove - called whenever a scsi disk (previously recognized by * sd_probe) is detached from the system. It is called (potentially * multiple times) during sd module unload. -* @dev: pointer to device object +* @sdp: pointer to device object * * Note: this function is invoked from the scsi mid-level. * This function potentially frees up a device name (e.g. /dev/sdc) * that could be re-used by a subsequent sd_probe(). * This function is not called when the built-in sd driver is "exit-ed". **/ -static int sd_remove (struct device *dev) +static void sd_remove (struct scsi_device *sdp) { +struct device *dev = &sdp->sdev_gendev;struct scsi_disk *sdkp =dev_get_drvdata (dev);scsi_autopm_get_device (sdkp->device);
@@ -4070,10 +4071,9 @@ static int sd_remove(struct device *dev)device_del (&sdkp->disk_dev);del_gendisk (sdkp->disk);if (!sdkp->suspended) -sd_shutdown (dev); +sd_shutdown (sdp);put_disk (sdkp->disk); -return 0 ; }static void scsi_disk_release (struct device *dev)
@@ -4160,8 +4160,9 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)* the normal SCSI command structure. Wait for the command to * complete. */ -static void sd_shutdown (struct device *dev) +static void sd_shutdown (struct scsi_device *sdp) { +struct device *dev = &sdp->sdev_gendev;struct scsi_disk *sdkp =dev_get_drvdata (dev);if (!sdkp)
@@ -4329,12 +4330,12 @@ static const struct dev_pm_ops sd_pm_ops = { };static struct scsi_driver sd_template = { + .probe = sd_probe, + .remove = sd_remove, + .shutdown = sd_shutdown, .gendrv = { .name ="sd" , - .probe = sd_probe, .probe_type =PROBE_PREFER_ASYNCHRONOUS , - .remove = sd_remove, - .shutdown = sd_shutdown, .pm = &sd_pm_ops, }, .rescan = sd_rescan,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 979/1376 scsi: sd: Move the sd_remove() function definition
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <[email protected]>
[ Upstream commit 4f39a4870a59971797be86fed72423b83b6b4e00 ]
Move the sd_remove() function definition such that the sd_shutdown() forward declaration can be removed.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- drivers/scsi/sd.c | 53 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-)
drivers/scsi/sd.c +26 -27
@@ -108,7 +108,6 @@ static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim);static int sd_revalidate_disk (struct gendisk *);static void sd_unlock_native_capacity (struct gendisk *disk); -static void sd_shutdown (struct scsi_device *);static void scsi_disk_release (struct device *cdev);static DEFINE_IDA (sd_index_ida);
@@ -4050,32 +4049,6 @@ static int sd_probe(struct scsi_device *sdp)return error; } -/** -* sd_remove - called whenever a scsi disk (previously recognized by -* sd_probe) is detached from the system. It is called (potentially -* multiple times) during sd module unload. -* @sdp: pointer to device object -* -* Note: this function is invoked from the scsi mid-level. -* This function potentially frees up a device name (e.g. /dev/sdc) -* that could be re-used by a subsequent sd_probe(). -* This function is not called when the built-in sd driver is "exit-ed". -**/ -static void sd_remove (struct scsi_device *sdp) -{ -struct device *dev = &sdp->sdev_gendev; -struct scsi_disk *sdkp =dev_get_drvdata (dev); - -scsi_autopm_get_device (sdkp->device); - -device_del (&sdkp->disk_dev); -del_gendisk (sdkp->disk); -if (!sdkp->suspended) -sd_shutdown (sdp); - -put_disk (sdkp->disk); -} -static void scsi_disk_release (struct device *dev) {struct scsi_disk *sdkp =to_scsi_disk (dev);
@@ -4187,6 +4160,32 @@ static void sd_shutdown(struct scsi_device *sdp) } } +/** +* sd_remove - called whenever a scsi disk (previously recognized by +* sd_probe) is detached from the system. It is called (potentially +* multiple times) during sd module unload. +* @sdp: pointer to device object +* +* Note: this function is invoked from the scsi mid-level. +* This function potentially frees up a device name (e.g. /dev/sdc) +* that could be re-used by a subsequent sd_probe(). +* This function is not called when the built-in sd driver is "exit-ed". +**/ +static void sd_remove (struct scsi_device *sdp) +{ +struct device *dev = &sdp->sdev_gendev; +struct scsi_disk *sdkp =dev_get_drvdata (dev); + +scsi_autopm_get_device (sdkp->device); + +device_del (&sdkp->disk_dev); +del_gendisk (sdkp->disk); +if (!sdkp->suspended) +sd_shutdown (sdp); + +put_disk (sdkp->disk); +} +static inline bool sd_do_start_stop (struct scsi_device *sdev,bool runtime) { return (sdev->manage_system_start_stop && !runtime) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 980/1376 scsi: sd: Move the sd_config_discard() function definition
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bart Van Assche <[email protected]>
[ Upstream commit c0daf4836114fcbdf64bf817cab00b75ce712945 ]
Move the sd_config_discard() function definition such that its forward declaration can be removed.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- drivers/scsi/sd.c | 114 +++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 58 deletions(-)
drivers/scsi/sd.c +56 -58
@@ -102,8 +102,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC);#define SD_MINORS 16 -static void sd_config_discard (struct scsi_disk *sdkp,struct queue_limits *lim, -unsigned int mode);static void sd_config_write_same (struct scsi_disk *sdkp,struct queue_limits *lim);static int sd_revalidate_disk (struct gendisk *);
@@ -120,6 +118,62 @@ static const char *sd_cache_types[] = {"write back, no read (daft)" }; +static void sd_disable_discard (struct scsi_disk *sdkp) +{ + sdkp->provisioning_mode =SD_LBP_DISABLE ; +blk_queue_disable_discard (sdkp->disk->queue); +} + +static void sd_config_discard (struct scsi_disk *sdkp,struct queue_limits *lim, +unsigned int mode) +{ +unsigned int logical_block_size = sdkp->device->sector_size; +unsigned int max_blocks =0 ; + + lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; + lim->discard_granularity =max (sdkp->physical_block_size, + sdkp->unmap_granularity * logical_block_size); + sdkp->provisioning_mode = mode; + +switch (mode) { + +case SD_LBP_FULL : +case SD_LBP_DISABLE : +break ; + +case SD_LBP_UNMAP : + max_blocks =min_not_zero (sdkp->max_unmap_blocks, + (u32 )SD_MAX_WS16_BLOCKS ); +break ; + +case SD_LBP_WS16 : +if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; +else + max_blocks = sdkp->max_ws_blocks; + + max_blocks =min_not_zero (max_blocks, (u32 )SD_MAX_WS16_BLOCKS ); +break ; + +case SD_LBP_WS10 : +if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; +else + max_blocks = sdkp->max_ws_blocks; + + max_blocks =min_not_zero (max_blocks, (u32 )SD_MAX_WS10_BLOCKS ); +break ; + +case SD_LBP_ZERO : + max_blocks =min_not_zero (sdkp->max_ws_blocks, + (u32 )SD_MAX_WS10_BLOCKS ); +break ; + } + + lim->max_hw_discard_sectors = max_blocks * + (logical_block_size >>SECTOR_SHIFT ); +} +static void sd_set_flush_flag (struct scsi_disk *sdkp,struct queue_limits *lim) {
@@ -835,62 +889,6 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,return protect; } -static void sd_disable_discard (struct scsi_disk *sdkp) -{ - sdkp->provisioning_mode =SD_LBP_DISABLE ; -blk_queue_disable_discard (sdkp->disk->queue); -} - -static void sd_config_discard (struct scsi_disk *sdkp,struct queue_limits *lim, -unsigned int mode) -{ -unsigned int logical_block_size = sdkp->device->sector_size; -unsigned int max_blocks =0 ; - - lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; - lim->discard_granularity =max (sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); - sdkp->provisioning_mode = mode; - -switch (mode) { - -case SD_LBP_FULL : -case SD_LBP_DISABLE : -break ; - -case SD_LBP_UNMAP : - max_blocks =min_not_zero (sdkp->max_unmap_blocks, - (u32 )SD_MAX_WS16_BLOCKS ); -break ; - -case SD_LBP_WS16 : -if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; -else - max_blocks = sdkp->max_ws_blocks; - - max_blocks =min_not_zero (max_blocks, (u32 )SD_MAX_WS16_BLOCKS ); -break ; - -case SD_LBP_WS10 : -if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; -else - max_blocks = sdkp->max_ws_blocks; - - max_blocks =min_not_zero (max_blocks, (u32 )SD_MAX_WS10_BLOCKS ); -break ; - -case SD_LBP_ZERO : - max_blocks =min_not_zero (sdkp->max_ws_blocks, - (u32 )SD_MAX_WS10_BLOCKS ); -break ; - } - - lim->max_hw_discard_sectors = max_blocks * - (logical_block_size >>SECTOR_SHIFT ); -} -static void *sd_set_special_bvec (struct request *rq,unsigned int data_len) {struct page *page;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 981/1376 scsi: sd: Enable sector size > PAGE_SIZE in SCSI sd driver
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Swarna Prabhu <[email protected]>
[ Upstream commit 7179e626b76eb42f2529c6f6dd6ba88ea2445372 ]
The WRITE SAME(16) and WRITE SAME(10) SCSI commands use a page from a dedicated mempool (sd_page_pool) for their payload. This pool was initialized to allocate single pages, which was sufficient as long as the device sector size did not exceed the PAGE_SIZE.
Given that block layer now supports block size upto 64KB, i.e. beyond PAGE_SIZE, initialize a large page pool in sd_probe() if a higher sector device is attached, ensuring atomicity. Adapt sd_set_special_bvec() to use large page pool when a higher sector size device is attached. Hence enable sector sizes > PAGE_SIZE in SCSI sd driver.
Stable-dep-of: bb31844d88b7 ("scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails")
--- drivers/scsi/sd.c | 80 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 12 deletions(-)
drivers/scsi/sd.c +68 -12
@@ -109,8 +109,11 @@ static void sd_unlock_native_capacity(struct gendisk *disk);static void scsi_disk_release (struct device *cdev);static DEFINE_IDA (sd_index_ida); +static DEFINE_MUTEX (sd_mutex_lock);static mempool_t *sd_page_pool; +static mempool_t *sd_large_page_pool; +static atomic_t sd_large_page_pool_users =ATOMIC_INIT (0 );static struct lock_class_key sd_bio_compl_lkclass;static const char *sd_cache_types[] = {
@@ -118,6 +121,33 @@ static const char *sd_cache_types[] = {"write back, no read (daft)" }; +static int sd_large_pool_create (void ) +{ +mutex_lock (&sd_mutex_lock); +if (!sd_large_page_pool) { + sd_large_page_pool =mempool_create_page_pool ( +SD_MEMPOOL_SIZE ,get_order (BLK_MAX_BLOCK_SIZE )); +if (!sd_large_page_pool) { +printk (KERN_ERR "sd: can't create large page mempool\n" ); +mutex_unlock (&sd_mutex_lock); +return -ENOMEM ; + } + } +atomic_inc (&sd_large_page_pool_users); +mutex_unlock (&sd_mutex_lock); +return 0 ; +} + +static void sd_large_pool_destroy (void ) +{ +mutex_lock (&sd_mutex_lock); +if (atomic_dec_and_test (&sd_large_page_pool_users)) { +mempool_destroy (sd_large_page_pool); + sd_large_page_pool =NULL ; + } +mutex_unlock (&sd_mutex_lock); +} +static void sd_disable_discard (struct scsi_disk *sdkp) { sdkp->provisioning_mode =SD_LBP_DISABLE ;
@@ -889,14 +919,24 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,return protect; } -static void *sd_set_special_bvec (struct request *rq,unsigned int data_len) +static void *sd_set_special_bvec (struct scsi_cmnd *cmd,unsigned int data_len) {struct page *page; +struct request *rq =scsi_cmd_to_rq (cmd); +struct scsi_device *sdp = cmd->device; +unsigned sector_size = sdp->sector_size; +unsigned int nr_pages =DIV_ROUND_UP (sector_size,PAGE_SIZE ); +int n; - page =mempool_alloc (sd_page_pool,GFP_ATOMIC ); +if (sector_size >PAGE_SIZE ) + page =mempool_alloc (sd_large_page_pool,GFP_ATOMIC ); +else + page =mempool_alloc (sd_page_pool,GFP_ATOMIC );if (!page)return NULL ; -clear_highpage (page); + +for (n =0 ; n < nr_pages; n++) +clear_highpage (page + n);bvec_set_page (&rq->special_vec, page, data_len,0 ); rq->rq_flags |=RQF_SPECIAL_PAYLOAD ;return bvec_virt (&rq->special_vec);
@@ -912,7 +952,7 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)unsigned int data_len =24 ;char *buf; - buf =sd_set_special_bvec (rq, data_len); + buf =sd_set_special_bvec (cmd, data_len);if (!buf)return BLK_STS_RESOURCE ;
@@ -1000,7 +1040,7 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd,u32 nr_blocks =sectors_to_logical (sdp,blk_rq_sectors (rq));u32 data_len = sdp->sector_size; -if (!sd_set_special_bvec (rq, data_len)) +if (!sd_set_special_bvec (cmd, data_len))return BLK_STS_RESOURCE ; cmd->cmd_len =16 ;
@@ -1027,7 +1067,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,u32 nr_blocks =sectors_to_logical (sdp,blk_rq_sectors (rq));u32 data_len = sdp->sector_size; -if (!sd_set_special_bvec (rq, data_len)) +if (!sd_set_special_bvec (cmd, data_len))return BLK_STS_RESOURCE ; cmd->cmd_len =10 ;
@@ -1468,9 +1508,15 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd)static void sd_uninit_command (struct scsi_cmnd *SCpnt) {struct request *rq =scsi_cmd_to_rq (SCpnt); +struct scsi_device *sdp = SCpnt->device; +unsigned sector_size = sdp->sector_size; -if (rq->rq_flags &RQF_SPECIAL_PAYLOAD ) -mempool_free (rq->special_vec.bv_page, sd_page_pool); +if (rq->rq_flags &RQF_SPECIAL_PAYLOAD ) { +if (sector_size >PAGE_SIZE ) +mempool_free (rq->special_vec.bv_page, sd_large_page_pool); +else +mempool_free (rq->special_vec.bv_page, sd_page_pool); + } }static bool sd_need_revalidate (struct gendisk *disk,struct scsi_disk *sdkp)
@@ -2870,10 +2916,7 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, "assuming 512.\n"); } -if (sector_size !=512 && - sector_size !=1024 && - sector_size !=2048 && - sector_size !=4096 ) { +if (blk_validate_block_size (sector_size)) {sd_printk (KERN_NOTICE , sdkp,"Unsupported sector size %d.\n" , sector_size);/*
@@ -4004,6 +4047,12 @@ static int sd_probe(struct scsi_device *sdp) sdkp->max_medium_access_timeouts =SD_MAX_MEDIUM_TIMEOUTS ;sd_revalidate_disk (gd); +if (sdp->sector_size >PAGE_SIZE ) { +if (sd_large_pool_create ()) { + error = -ENOMEM ; + goto out_free_index; + } + }if (sdp->removable) { gd->flags |=GENHD_FL_REMOVABLE ;
@@ -4021,6 +4070,8 @@ static int sd_probe(struct scsi_device *sdp)if (error) {device_unregister (&sdkp->disk_dev);put_disk (gd); +if (sdp->sector_size >PAGE_SIZE ) +sd_large_pool_destroy (); goto out; }
@@ -4182,6 +4233,9 @@ static void sd_remove(struct scsi_device *sdp)sd_shutdown (sdp);put_disk (sdkp->disk); + +if (sdp->sector_size >PAGE_SIZE ) +sd_large_pool_destroy (); }static inline bool sd_do_start_stop (struct scsi_device *sdev,bool runtime)
@@ -4405,6 +4459,8 @@ static void __exit exit_sd(void)scsi_unregister_driver (&sd_template);mempool_destroy (sd_page_pool); +if (sd_large_page_pool) +mempool_destroy (sd_large_page_pool);class_unregister (&sd_disk_class);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 982/1376 scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Xiuwei <[email protected]>
[ Upstream commit bb31844d88b77138b67aa20c3600203baff40140 ]
sd_set_special_bvec() allocates a special payload page for UNMAP and WRITE SAME commands. If scsi_alloc_sgtables() fails afterward in sd_setup_unmap_cmnd() or sd_setup_write_same{10,16}_cmnd(), the SCSI midlayer does not call uninit_command() because RQF_DONTPREP is not set yet, leaking the page.
Call sd_uninit_command() on error, and clear RQF_SPECIAL_PAYLOAD after freeing the page.
--- drivers/scsi/sd.c | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-)
drivers/scsi/sd.c +30 -17
@@ -919,6 +919,21 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,return protect; } +static void sd_uninit_command (struct scsi_cmnd *cmd) +{ +struct request *rq =scsi_cmd_to_rq (cmd); +struct scsi_device *sdp = cmd->device; + +if (!(rq->rq_flags &RQF_SPECIAL_PAYLOAD )) +return ; + +if (sdp->sector_size >PAGE_SIZE ) +mempool_free (rq->special_vec.bv_page, sd_large_page_pool); +else +mempool_free (rq->special_vec.bv_page, sd_page_pool); + rq->rq_flags &= ~RQF_SPECIAL_PAYLOAD ; +} +static void *sd_set_special_bvec (struct scsi_cmnd *cmd,unsigned int data_len) {struct page *page;
@@ -951,6 +966,7 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)u32 nr_blocks =sectors_to_logical (sdp,blk_rq_sectors (rq));unsigned int data_len =24 ;char *buf; +blk_status_t ret; buf =sd_set_special_bvec (cmd, data_len);if (!buf)
@@ -969,7 +985,10 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd) cmd->transfersize = data_len; rq->timeout =SD_TIMEOUT ; -return scsi_alloc_sgtables (cmd); + ret =scsi_alloc_sgtables (cmd); +if (ret !=BLK_STS_OK ) +sd_uninit_command (cmd); +return ret; }static void sd_config_atomic (struct scsi_disk *sdkp,struct queue_limits *lim)
@@ -1039,6 +1058,7 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd,u64 lba =sectors_to_logical (sdp,blk_rq_pos (rq));u32 nr_blocks =sectors_to_logical (sdp,blk_rq_sectors (rq));u32 data_len = sdp->sector_size; +blk_status_t ret;if (!sd_set_special_bvec (cmd, data_len))return BLK_STS_RESOURCE ;
@@ -1054,7 +1074,10 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd, cmd->transfersize = data_len; rq->timeout = unmap ?SD_TIMEOUT :SD_WRITE_SAME_TIMEOUT ; -return scsi_alloc_sgtables (cmd); + ret =scsi_alloc_sgtables (cmd); +if (ret !=BLK_STS_OK ) +sd_uninit_command (cmd); +return ret; } static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
@@ -1066,6 +1089,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,u64 lba =sectors_to_logical (sdp,blk_rq_pos (rq));u32 nr_blocks =sectors_to_logical (sdp,blk_rq_sectors (rq));u32 data_len = sdp->sector_size; +blk_status_t ret;if (!sd_set_special_bvec (cmd, data_len))return BLK_STS_RESOURCE ;
@@ -1081,7 +1105,10 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd, cmd->transfersize = data_len; rq->timeout = unmap ?SD_TIMEOUT :SD_WRITE_SAME_TIMEOUT ; -return scsi_alloc_sgtables (cmd); + ret =scsi_alloc_sgtables (cmd); +if (ret !=BLK_STS_OK ) +sd_uninit_command (cmd); +return ret; }static blk_status_t sd_setup_write_zeroes_cmnd (struct scsi_cmnd *cmd)
@@ -1505,20 +1532,6 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) } } -static void sd_uninit_command (struct scsi_cmnd *SCpnt) -{ -struct request *rq =scsi_cmd_to_rq (SCpnt); -struct scsi_device *sdp = SCpnt->device; -unsigned sector_size = sdp->sector_size; - -if (rq->rq_flags &RQF_SPECIAL_PAYLOAD ) { -if (sector_size >PAGE_SIZE ) -mempool_free (rq->special_vec.bv_page, sd_large_page_pool); -else -mempool_free (rq->special_vec.bv_page, sd_page_pool); - } -} -static bool sd_need_revalidate (struct gendisk *disk,struct scsi_disk *sdkp) {if (sdkp->device->removable || sdkp->write_prot) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 983/1376 scsi: sd: Fix sd_done() sense handling condition
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Xiuwei <[email protected]>
[ Upstream commit a640d4546b11be5709a82bdc63d7dafd8ddc6c9e ]
Only enter the sense_key switch when the command returned CHECK CONDITION with valid, non-deferred sense. The old condition let deferred or invalid sense fall through and mis-handle the I/O.
--- drivers/scsi/sd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/sd.c +2 -2
@@ -2378,8 +2378,8 @@ static int sd_done(struct scsi_cmnd *SCpnt) } sdkp->medium_access_timed_out =0 ; -if (!scsi_status_is_check_condition (result) && - (!sense_valid || sense_deferred)) +if (!scsi_status_is_check_condition (result) || + !sense_valid || sense_deferred) goto out;switch (sshdr.sense_key) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 984/1376 btrfs: retry verity reads for not-uptodate Merkle folios
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yichong Chen <[email protected]>
[ Upstream commit 8cc569696dac51fc62bb39b3b8f530582b916d29 ]
btrfs_read_merkle_tree_page() can find a folio in the mapping that is not uptodate. After taking the folio lock, the current code treats that state as a read error and returns -EIO.
That can make a previous transient read failure sticky. If the failed read left a not-uptodate folio in the mapping, later callers find that folio and fail instead of retrying the read.
Keep the existing page-cache insertion and locking order, but retry the Merkle item read when a not-uptodate folio is found in the mapping. Also unlock the folio when read_key_bytes() fails so that a later caller can lock it and retry the read.
--- fs/btrfs/verity.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
fs/btrfs/verity.c +11 -5
@@ -731,14 +731,18 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode, goto out;folio_lock (folio); -/* If it's not uptodate after we have the lock, we got a read error. */ -if (!folio_test_uptodate (folio)) { +/* Folio was truncated from mapping. */ +if (!folio->mapping) {folio_unlock (folio);folio_put (folio); -return ERR_PTR (-EIO ); + goto again; } -folio_unlock (folio); - goto out; +/* Another reader may have filled the folio while we waited. */ +if (folio_test_uptodate (folio)) { +folio_unlock (folio); + goto out; + } + goto read_folio; } folio = filemap_alloc_folio(mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS),
@@ -755,6 +759,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode,return ERR_PTR (ret); } +read_folio:/* * Merkle item keys are indexed from byte 0 in the merkle tree. * They have the form:
@@ -764,6 +769,7 @@ static struct page *btrfs_read_merkle_tree_page(struct inode *inode, ret =read_key_bytes (BTRFS_I (inode),BTRFS_VERITY_MERKLE_ITEM_KEY , off,folio_address (folio),PAGE_SIZE , folio);if (ret <0 ) { +folio_unlock (folio);folio_put (folio);return ERR_PTR (ret); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 985/1376 Bluetooth: virtio_bt: avoid OOB read of build info string
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 502adc06ba76dee19c292ae4a07d74d202fe734d ]
The virtbt_setup_zephyr() sends the Zephyr vendor command 0xfc08 (Read Build Information) and hands the response to bt_dev_info() and hci_set_fw_info() as a "%s" string starting at skb->data + 1, without checking the length. A backend that answers with status only leaves that pointer past the end of the received data, so the walk reads adjacent slab memory until it meets a NUL. Those bytes reach the kernel log and the firmware-info debugfs file.
To fix this, print the string with a bounded "%.*s" limited to skb->len - 1. A short or unterminated response then prints as much as arrived instead of failing setup.
This mirrors commit dd068ef04412 ("Bluetooth: bpa10x: avoid OOB read of revision string in bpa10x_setup()"), which fixed the identical pattern.
--- drivers/bluetooth/virtio_bt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/bluetooth/virtio_bt.c +6 -2
@@ -120,9 +120,13 @@ static int virtbt_setup_zephyr(struct hci_dev *hdev)if (IS_ERR (skb))return PTR_ERR (skb); -bt_dev_info (hdev,"%s" , (char *)(skb->data +1 )); +/* Bounded print: the backend controls skb->len. */ +if (skb->len >1 ) { +int len = skb->len -1 ; -hci_set_fw_info (hdev,"%s" , skb->data +1 ); +bt_dev_info (hdev,"%.*s" , len, (char *)(skb->data +1 )); +hci_set_fw_info (hdev,"%.*s" , len, skb->data +1 ); + }kfree_skb (skb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 986/1376 Bluetooth: btintel: Fix diagnostics event detection
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit ad0e7ac7da9a9a0095570bd6add3e27f259de104 ]
For a diagnostics VSE, diagnostics_hdr[] sits at the start of the event payload, skb->data[2], but btintel_recv_event() wrongly guards its memcmp with @len, which is measured from skb->data[3] for the earlier INTEL_BOOTLOADER check.
Fix by using (@len + 1) instead, which ==
(skb->len - HCI_EVENT_HDR_SIZE) exactly.
--- drivers/bluetooth/btintel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/btintel.c +1 -1
@@ -3399,7 +3399,7 @@ int btintel_recv_event(struct hci_dev *hdev, struct sk_buff *skb)/* Handle all diagnostics events separately. May still call * hci_recv_frame. */ -if (len >=sizeof (diagnostics_hdr) && +if (len +1 >=sizeof (diagnostics_hdr) &&memcmp (&skb->data[2 ], diagnostics_hdr,sizeof (diagnostics_hdr)) ==0 ) {return btintel_diagnostics (hdev, skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 987/1376 Bluetooth: hci_conn: fix the SCO setup context lifetime
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 42de40abe25db9211107af8896d0fd741f10648d ]
hci_setup_sync() queues a conn_handle_t with a NULL destroy callback, so the context is only freed if hci_enhanced_setup_sync() actually runs. An entry that is cancelled instead is leaked, as _hci_cmd_sync_cancel_entry() does not release entry->data when there is no destroy callback, and hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered.
The context also stores a bare hci_conn pointer, so the connection can be freed while the work is queued. The dequeue in hci_conn_del() does not cover it either, as it matches on entry->data == conn and entry->data is the wrapper here. Same problem as commit 2f5d635ad590 ("Bluetooth:hci_sync: hold conn in hci_connect_acl/le_sync() callbacks").
Hold the connection and release both from a destroy callback. The submission failure path drops both, since hci_cmd_sync_submit() does not call the destroy callback when it fails to queue.
--- net/bluetooth/hci_conn.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
net/bluetooth/hci_conn.c +15 -5
@@ -287,8 +287,6 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data)struct hci_cp_enhanced_setup_sync_conn cp;const struct sco_param *param; -kfree (conn_handle); -if (!hci_conn_valid (hdev, conn))return -ECANCELED ;
@@ -457,6 +455,15 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)return true; } +static void hci_enhanced_setup_sync_destroy (struct hci_dev *hdev,void *data, +int err) +{ +struct conn_handle_t *conn_handle = data; + +hci_conn_put (conn_handle->conn); +kfree (conn_handle); +} +bool hci_setup_sync (struct hci_conn *conn,__u16 handle) {int result;
@@ -468,12 +475,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)if (!conn_handle)return false; - conn_handle->conn = conn; + conn_handle->conn =hci_conn_get (conn); conn_handle->handle = handle; result =hci_cmd_sync_queue (conn->hdev, hci_enhanced_setup_sync, - conn_handle,NULL ); -if (result <0 ) + conn_handle, + hci_enhanced_setup_sync_destroy); +if (result <0 ) { +hci_conn_put (conn);kfree (conn_handle); + }return result ==0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 988/1376 Bluetooth: hci_sync: free the advertising instance on the failure and cancel paths
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 120d8dc042e3d45073bb6e50ee7b058a0b182627 ]
adv_timeout_expire() hands a kmalloc()ed instance byte to hci_cmd_sync_queue() with a NULL destroy callback, and only adv_timeout_expire_sync() frees it. That leaks on two paths:
- the return value is not checked, and hci_cmd_sync_queue() does not take ownership when it fails (-ENETDOWN, -ENODEV, -ENOMEM);
- a cancelled entry is not released, as _hci_cmd_sync_cancel_entry() does not free entry->data when there is no destroy callback. hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered.
Free the buffer from a destroy callback, and in the caller when the entry could not be queued at all.
--- net/bluetooth/hci_sync.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
net/bluetooth/hci_sync.c +9 -3
@@ -540,8 +540,6 @@ static int adv_timeout_expire_sync(struct hci_dev *hdev, void *data) {u8 instance = *(u8 *)data; -kfree (data); -hci_clear_adv_instance_sync (hdev,NULL , instance, false);if (list_empty (&hdev->adv_instances))
@@ -550,6 +548,12 @@ static int adv_timeout_expire_sync(struct hci_dev *hdev, void *data)return 0 ; } +static void adv_timeout_expire_destroy (struct hci_dev *hdev,void *data, +int err) +{ +kfree (data); +} +static void adv_timeout_expire (struct work_struct *work) {u8 *inst_ptr;
@@ -570,7 +574,9 @@ static void adv_timeout_expire(struct work_struct *work) goto unlock; *inst_ptr = hdev->cur_adv_instance; -hci_cmd_sync_queue (hdev, adv_timeout_expire_sync, inst_ptr,NULL ); +if (hci_cmd_sync_queue (hdev, adv_timeout_expire_sync, inst_ptr, + adv_timeout_expire_destroy) <0 ) +kfree (inst_ptr); unlock:hci_dev_unlock (hdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 989/1376 Bluetooth: MGMT: free the mesh send cancel command when it is cancelled
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
[ Upstream commit 3c742feda8fcabf741a17bcf668b63c8f606f9c5 ]
mesh_send_cancel() queues the pending command with a NULL destroy callback, so it is only freed if send_cancel() runs. A cancelled entry is leaked, as _hci_cmd_sync_cancel_entry() does not release entry->data when there is no destroy callback, and hci_cmd_sync_clear() cancels every pending entry when the controller is unregistered. Nothing else reclaims it either: mgmt_pending_new() does not put the command on hdev->mgmt_pending.
The leak also pins the socket reference taken by mgmt_pending_new(), so the mgmt socket is never released.
Free the command from a destroy callback.
--- net/bluetooth/mgmt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
net/bluetooth/mgmt.c +7 -2
@@ -2411,11 +2411,15 @@ static int send_cancel(struct hci_dev *hdev, void *data)mgmt_cmd_complete (cmd->sk, hdev->id,MGMT_OP_MESH_SEND_CANCEL ,0 ,NULL ,0 ); -mgmt_pending_free (cmd);return 0 ; } +static void send_cancel_destroy (struct hci_dev *hdev,void *data,int err) +{ +mgmt_pending_free (data); +} +static int mesh_send_cancel (struct sock *sk,struct hci_dev *hdev,void *data,u16 len) {
@@ -2436,7 +2440,8 @@ static int mesh_send_cancel(struct sock *sk, struct hci_dev *hdev,if (!cmd) err = -ENOMEM ;else - err =hci_cmd_sync_queue (hdev, send_cancel, cmd,NULL ); + err =hci_cmd_sync_queue (hdev, send_cancel, cmd, + send_cancel_destroy);if (err <0 ) { err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_MESH_SEND_CANCEL,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 990/1376 mmc: sdio: add MediaTek MT7902 SDIO device ID
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Wang <[email protected]>
[ Upstream commit cde32a92d4562b686f730fc08d4d558ecc99d516 ]
Add SDIO device ID (0x790a) for MediaTek MT7902 to sdio_ids.h.
Stable-dep-of: b0c0b3794011 ("Bluetooth: btmtksdio: fix usage_count leak when autosuspend_delay is negative")
--- include/linux/mmc/sdio_ids.h | 1 + 1 file changed, 1 insertion(+)
include/linux/mmc/sdio_ids.h +1 -0
@@ -110,6 +110,7 @@#define SDIO_VENDOR_ID_MEDIATEK 0x037a#define SDIO_DEVICE_ID_MEDIATEK_MT7663 0x7663#define SDIO_DEVICE_ID_MEDIATEK_MT7668 0x7668 +#define SDIO_DEVICE_ID_MEDIATEK_MT7902 0x790a#define SDIO_DEVICE_ID_MEDIATEK_MT7961 0x7961#define SDIO_VENDOR_ID_MICROCHIP_WILC 0x0296
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 991/1376 Bluetooth: btmtk: add MT7902 MCU support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Wang <[email protected]>
[ Upstream commit aab25984e55972e53f3e58821cb85a7101876056 ]
Add MT7902 device ID and firmware filename to enable MCU firmware loading.
Stable-dep-of: b0c0b3794011 ("Bluetooth: btmtksdio: fix usage_count leak when autosuspend_delay is negative")
--- drivers/bluetooth/btmtk.c | 1 + drivers/bluetooth/btmtk.h | 1 + 2 files changed, 2 insertions(+)
drivers/bluetooth/btmtk.c +1 -0
@@ -1335,6 +1335,7 @@ int btmtk_usb_setup(struct hci_dev *hdev)case 0x7922 :case 0x7925 :case 0x7961 : +case 0x7902 :btmtk_fw_get_filename (fw_bin_name,sizeof (fw_bin_name), dev_id, fw_version, fw_flavor);
drivers/bluetooth/btmtk.h +1 -0
@@ -5,6 +5,7 @@#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin" +#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 992/1376 Bluetooth: btmtk: add MT7902 SDIO support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Wang <[email protected]>
[ Upstream commit 7f2c3c49ba0d3fead557a8026a021ebe23f919d6 ]
Add MT7902 Bluetooth SDIO support by introducing chip data and registering the device ID.
Runtime PM is not yet supported by the driver, but normal operation is unaffected.
Stable-dep-of: b0c0b3794011 ("Bluetooth: btmtksdio: fix usage_count leak when autosuspend_delay is negative")
--- drivers/bluetooth/btmtksdio.c | 42 ++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-)
drivers/bluetooth/btmtksdio.c +29 -13
@@ -42,24 +42,35 @@ struct btmtksdio_data {const char *fwname;u16 chipid;bool lp_mbox_supported; +bool pm_runtime_supported; };static const struct btmtksdio_data mt7663_data = { .fwname =FIRMWARE_MT7663 , .chipid =0x7663 , .lp_mbox_supported = false, + .pm_runtime_supported = true, };static const struct btmtksdio_data mt7668_data = { .fwname =FIRMWARE_MT7668 , .chipid =0x7668 , .lp_mbox_supported = false, + .pm_runtime_supported = true, };static const struct btmtksdio_data mt7921_data = { .fwname =FIRMWARE_MT7961 , .chipid =0x7921 , .lp_mbox_supported = true, + .pm_runtime_supported = true, +}; + +static const struct btmtksdio_data mt7902_data = { + .fwname =FIRMWARE_MT7902 , + .chipid =0x7902 , + .lp_mbox_supported = false, + .pm_runtime_supported = false, };static const struct sdio_device_id btmtksdio_table[] = {
@@ -69,6 +80,8 @@ static const struct sdio_device_id btmtksdio_table[] = { .driver_data = (kernel_ulong_t)&mt7668_data }, {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7961), .driver_data = (kernel_ulong_t)&mt7921_data }, + {SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, SDIO_DEVICE_ID_MEDIATEK_MT7902), + .driver_data = (kernel_ulong_t)&mt7902_data }, { }/* Terminating entry */ };MODULE_DEVICE_TABLE (sdio, btmtksdio_table);
@@ -1091,6 +1104,7 @@ static int btmtksdio_setup(struct hci_dev *hdev)set_bit (BTMTKSDIO_HW_TX_READY , &bdev->tx_state);switch (bdev->data->chipid) { +case 0x7902 :case 0x7921 :if (test_bit (BTMTKSDIO_HW_RESET_ACTIVE , &bdev->tx_state)) { err = btmtksdio_mtk_reg_read(hdev, MT7921_DLSTATUS,
@@ -1168,22 +1182,24 @@ static int btmtksdio_setup(struct hci_dev *hdev) delta =ktime_sub (rettime, calltime); duration = (unsigned long long )ktime_to_ns (delta) >>10 ; -pm_runtime_set_autosuspend_delay (bdev->dev, -MTKBTSDIO_AUTOSUSPEND_DELAY ); -pm_runtime_use_autosuspend (bdev->dev); +if (bdev->data->pm_runtime_supported) { +pm_runtime_set_autosuspend_delay (bdev->dev, +MTKBTSDIO_AUTOSUSPEND_DELAY ); +pm_runtime_use_autosuspend (bdev->dev); - err =pm_runtime_set_active (bdev->dev); -if (err <0 ) -return err; + err =pm_runtime_set_active (bdev->dev); +if (err <0 ) +return err; -/* Default forbid runtime auto suspend, that can be allowed by -* enable_autosuspend flag or the PM runtime entry under sysfs. -*/ -pm_runtime_forbid (bdev->dev); -pm_runtime_enable (bdev->dev); +/* Default forbid runtime auto suspend, that can be allowed by +* enable_autosuspend flag or the PM runtime entry under sysfs. +*/ +pm_runtime_forbid (bdev->dev); +pm_runtime_enable (bdev->dev); -if (enable_autosuspend) -pm_runtime_allow (bdev->dev); +if (enable_autosuspend) +pm_runtime_allow (bdev->dev); + }bt_dev_info (hdev,"Device setup in %llu usecs" , duration);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 993/1376 Bluetooth: btmtksdio: fix usage_count leak when autosuspend_delay is negative
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit b0c0b37940115383e7ea65d4d988f9b9e613ab92 ]
btmtksdio_setup() calls pm_runtime_use_autosuspend() when runtime PM is supported, but btmtksdio_remove() does not call the matching pm_runtime_dont_use_autosuspend() when removing the device.
If the autosuspend delay is set to a negative value while autosuspend is enabled, the runtime PM core increments usage_count to prevent runtime suspend. Without calling pm_runtime_dont_use_autosuspend() during driver teardown, this reference is not dropped and usage_count remains unbalanced.
Add the missing pm_runtime_dont_use_autosuspend() call in the remove path before restoring the runtime PM usage reference.
This issue was found by manual code inspection.
--- drivers/bluetooth/btmtksdio.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/bluetooth/btmtksdio.c +3 -0
@@ -1468,6 +1468,9 @@ static void btmtksdio_remove(struct sdio_func *func)if (test_bit (BTMTKSDIO_FUNC_ENABLED , &bdev->tx_state))btmtksdio_close (hdev); +if (bdev->data->pm_runtime_supported) +pm_runtime_dont_use_autosuspend (bdev->dev); +/* Be consistent the state in btmtksdio_probe */ pm_runtime_get_noresume (bdev->dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 994/1376 Bluetooth: MSFT: validate evt_prefix_len against the response length
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
[ Upstream commit 0079e1a944634ab2dc1c7cdec1144486d096407e ]
read_supported_features() only checks that the response covers the fixed part of struct msft_rp_read_supported_features, which is 11 bytes:
if (skb->len < sizeof(*rp)) {
bt_dev_err(hdev, "MSFT supported features length mismatch");
goto failed;
}evt_prefix[] is a flexible array member and rp->evt_prefix_len is an unvalidated u8 taken straight out of that response, so
msft->evt_prefix = kmemdup(rp->evt_prefix, rp->evt_prefix_len, GFP_KERNEL);
copies up to 255 bytes from a reply that may have carried none of them. What is copied is data the controller never sent, and it is then used to match incoming vendor events in msft_vendor_evt().
This is not an out-of-bounds access. An skb data allocation always has at least SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) bytes past the payload, which is more than the 255 byte maximum, so the read stays inside the allocation and KASAN does not report it. It is still a read of bytes the host was never given, with the length fully controlled by the controller.
Reject a response that is too short for the prefix it declares.
Verified with an emulated controller over /dev/vhci on a KASAN kernel, with vhci made to advertise an MSFT opcode the way btintel, btqca, btmtk and btrtl do unconditionally. A reply of exactly 11 bytes declaring evt_prefix_len = 255 reaches kmemdup and copies 255 bytes ("skb->len=11 evt_prefix_len=255", with the copied buffer dumped); since the reply ends at the fixed part, all 255 come from past the end of the response. No KASAN report is produced, as expected from the allocation slack described above. With this patch the response is rejected with "MSFT event prefix length mismatch" and msft->evt_prefix is left unset.
--- net/bluetooth/msft.c | 5 +++++ 1 file changed, 5 insertions(+)
net/bluetooth/msft.c +5 -0
@@ -165,6 +165,11 @@ static bool read_supported_features(struct hci_dev *hdev,if (rp->sub_opcode !=MSFT_OP_READ_SUPPORTED_FEATURES ) goto failed; +if (skb->len <sizeof (*rp) + rp->evt_prefix_len) { +bt_dev_err (hdev,"MSFT event prefix length mismatch" ); + goto failed; + } +if (rp->evt_prefix_len >0 ) { msft->evt_prefix =kmemdup (rp->evt_prefix, rp->evt_prefix_len,GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 995/1376 cgroup: Add bpf prog revisions to struct cgroup_bpf
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonghong Song <[email protected]>
[ Upstream commit 9b8367b604c739947ec308874f087fe0eb80f412 ]
One of key items in mprog API is revision for prog list. The revision number will be increased if the prog list changed, e.g., attach, detach or replace.
Add 'revisions' field to struct cgroup_bpf, representing revisions for all cgroup related attachment types. The initial revision value is set to 1, the same as kernel mprog implementations.
Stable-dep-of: 3f562c537e9e ("bpf, cgroup: Fix storage null-ptr-deref after replacing prog")
--- include/linux/bpf-cgroup-defs.h | 1 + kernel/cgroup/cgroup.c | 5 +++++ 2 files changed, 6 insertions(+)
include/linux/bpf-cgroup-defs.h +1 -0
@@ -63,6 +63,7 @@ struct cgroup_bpf {*/ struct hlist_head progs[MAX_CGROUP_BPF_ATTACH_TYPE ];u8 flags[MAX_CGROUP_BPF_ATTACH_TYPE ]; +u64 revisions[MAX_CGROUP_BPF_ATTACH_TYPE ];/* list of cgroup shared storages */ struct list_head storages;
kernel/cgroup/cgroup.c +5 -0
@@ -2081,6 +2081,11 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)for_each_subsys (ss, ssid)INIT_LIST_HEAD (&cgrp->e_csets[ssid]); +#ifdef CONFIG_CGROUP_BPF +for (int i =0 ; i <ARRAY_SIZE (cgrp->bpf.revisions); i++) + cgrp->bpf.revisions[i] =1 ; +#endif +init_waitqueue_head (&cgrp->offline_waitq);INIT_WORK (&cgrp->release_agent_work, cgroup1_release_agent); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 996/1376 bpf: Implement mprog API on top of existing cgroup progs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yonghong Song <[email protected]>
[ Upstream commit 1209339844601ec1766f4ff430673fbcfe42bb51 ]
Current cgroup prog ordering is appending at attachment time. This is not ideal. In some cases, users want specific ordering at a particular cgroup level. To address this, the existing mprog API seems an ideal solution with supporting BPF_F_BEFORE and BPF_F_AFTER flags.
But there are a few obstacles to directly use kernel mprog interface. Currently cgroup bpf progs already support prog attach/detach/replace and link-based attach/detach/replace. For example, in struct bpf_prog_array_item, the cgroup_storage field needs to be together with bpf prog. But the mprog API struct bpf_mprog_fp only has bpf_prog as the member, which makes it difficult to use kernel mprog interface.
In another case, the current cgroup prog detach tries to use the same flag as in attach. This is different from mprog kernel interface which uses flags passed from user space.
So to avoid modifying existing behavior, I made the following changes to support mprog API for cgroup progs:
- The support is for prog list at cgroup level. Cross-level prog list (a.k.a. effective prog list) is not supported.
- Previously, BPF_F_PREORDER is supported only for prog attach, now BPF_F_PREORDER is also supported by link-based attach.
- For attach, BPF_F_BEFORE/BPF_F_AFTER/BPF_F_ID/BPF_F_LINK is supported similar to kernel mprog but with different implementation.
- For detach and replace, use the existing implementation.
- For attach, detach and replace, the revision for a particular prog list, associated with a particular attach type, will be updated by increasing count by 1.
Stable-dep-of: 3f562c537e9e ("bpf, cgroup: Fix storage null-ptr-deref after replacing prog")
--- include/uapi/linux/bpf.h | 7 ++ kernel/bpf/cgroup.c | 182 +++++++++++++++++++++++++++++---- kernel/bpf/syscall.c | 46 ++++++--- tools/include/uapi/linux/bpf.h | 7 ++ 4 files changed, 205 insertions(+), 37 deletions(-)
include/uapi/linux/bpf.h +7 -0
@@ -1779,6 +1779,13 @@ union bpf_attr { };__u64 expected_revision; } netkit; +struct { +union { +__u32 relative_fd; +__u32 relative_id; + }; +__u64 expected_revision; + } cgroup; }; } link_create;
kernel/bpf/cgroup.c +160 -22
326 lines not on this page · raw message
kernel/bpf/syscall.c +31 -15
82 lines not on this page · raw message
tools/include/uapi/linux/bpf.h +7 -0
@@ -1779,6 +1779,13 @@ union bpf_attr { };__u64 expected_revision; } netkit; +struct { +union { +__u32 relative_fd; +__u32 relative_id; + }; +__u64 expected_revision; + } cgroup; }; } link_create;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 997/1376 bpf, cgroup: Fix storage null-ptr-deref after replacing prog
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pu Lehui <[email protected]>
[ Upstream commit 3f562c537e9ecf4bc5e206cfffc2cc047f1b7e94 ]
Syzkaller reported a storage null-ptr-deref issue after replacing prog. This occurs in the following scenario:
1. prog A, an empty prog, is attached to a cgrp.
2. prog B uses BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE and calls the bpf_get_local_storage helper.
3. link_update is called to replace prog A with prog B.
The reason is that __cgroup_bpf_replace fails to alloc and assign the required cgrp storage for the incoming replacement prog. Consequently, the new prog inherits an uninit storage, leading to null-ptr-deref panic when kick the new prog.
Fix this by rejecting a link update if new_prog's cgroup storage is incompatible with link->prog.
--- kernel/bpf/cgroup.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
kernel/bpf/cgroup.c +17 -0
@@ -972,6 +972,20 @@ static void replace_effective_prog(struct cgroup *cgrp, } } +static bool cgroup_bpf_storages_compatible (struct bpf_prog *old_prog, +struct bpf_prog *new_prog) +{ +enum bpf_cgroup_storage_type stype; + +for_each_cgroup_storage_type (stype) { +if (old_prog->aux->cgroup_storage[stype] != + new_prog->aux->cgroup_storage[stype]) +return false; + } + +return true; +} +/** * __cgroup_bpf_replace() - Replace link's program and propagate the change * to descendants
@@ -1010,6 +1024,9 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,if (!found)return -ENOENT ; +if (!cgroup_bpf_storages_compatible (link->link.prog, new_prog)) +return -EINVAL ; + cgrp->bpf.revisions[atype] +=1 ; old_prog =xchg (&link->link.prog, new_prog);replace_effective_prog (cgrp, atype, pl);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 998/1376 iio: light: gp2ap002: Fix unbalanced runtime PM on repeated event writes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
[ Upstream commit 579c049b4cb6fc72ce2c505fc5334540be0efcd3 ]
The IIO core does not filter duplicate writes to the event enable attribute, so writing the same value twice invokes write_event_config() twice. Enabling twice leaks a runtime PM reference, preventing the device from ever suspending again; disabling twice underflows the usage count and triggers a "Runtime PM usage count underflow" warning.
Bail out early when the requested state matches the current state. While at it, switch to pm_runtime_resume_and_get() so a failed resume is propagated to userspace instead of silently marking the event enabled.
--- drivers/iio/light/gp2ap002.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/iio/light/gp2ap002.c +10 -3
@@ -343,6 +343,10 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev, int state) {struct gp2ap002 *gp2ap002 =iio_priv (indio_dev); +int ret; + +if (state == gp2ap002->enabled) +return 0 ;if (state) {/*
@@ -350,14 +354,17 @@ static int gp2ap002_write_event_config(struct iio_dev *indio_dev,* already) and reintialize the sensor by using runtime_pm * callbacks. */ -pm_runtime_get_sync (gp2ap002->dev); - gp2ap002->enabled = true; + ret =pm_runtime_resume_and_get (gp2ap002->dev); +if (ret) +return ret; + }else {pm_runtime_mark_last_busy (gp2ap002->dev);pm_runtime_put_autosuspend (gp2ap002->dev); - gp2ap002->enabled = false; } + gp2ap002->enabled = state; +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 999/1376 iio: light: gp2ap002: re-enable irq if runtime suspend fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil Gautam <[email protected]>
[ Upstream commit 5d89e7cbac40057f5241a0832a86ce0fe97e4818 ]
gp2ap002_runtime_suspend() disables the irq before writing OPMOD. If the write fails, the callback returns an error with the irq still disabled while the PM core marks the device active again.
re-enable the irq before returning the error so the irq state matches the active state the PM core restores.
--- drivers/iio/light/gp2ap002.c | 1 + 1 file changed, 1 insertion(+)
drivers/iio/light/gp2ap002.c +1 -0
@@ -651,6 +651,7 @@ static int gp2ap002_runtime_suspend(struct device *dev)/* Disable chip and IRQ, everything off */ ret =regmap_write (gp2ap002->map,GP2AP002_OPMOD ,0x00 );if (ret) { +enable_irq (gp2ap002->irq);dev_err (gp2ap002->dev,"error setting up operation mode\n" );return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1000/1376 net/sched: cls_api: fix teardown of an adopted proto on insert-race loss
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit d4e359b3608a0e184bbe8d61a5c3b50d0831c44a ]
In tc_new_tfilter() the create branch sets tp_created = 1 before calling tcf_chain_tp_insert_unique(). When the caller loses the race (another request inserted a proto at the same chain/prio first), insert_unique() destroys the caller's own tp_new and returns the winner's proto with an extra reference. tp_created was never cleared, so the loser's errout path treated the winner's live proto as its own and called tcf_chain_tp_delete_empty() on it, silently unlinking an active classifier that the winning request already advertised via RTM_NEWTFILTER.
Track the outcome of the insert step in a single tri-state variable so each errout path reacts correctly:
- TP_NOT_CREATED: no proto created; pursue the old path.
- TP_CREATED: proto inserted successfully; same code path as before.
- TP_NOT_OWNED: New - lost the insert race; tp is another request's proto (chain ref already released by tp_new's destroy)
Both errout reactions are single expressions derived from the state.
This fix is motivated by the Sashiko's automated review of Patch (net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers) [1][2]. The review identified the silent-unlink behaviour of an adopted proto's teardown when a request loses the tcf_chain_tp_insert_unique() race.
[1] https://sashiko.dev/#/patchset/20260801125632.360365-1-jhs%40mojatatu.com
[2] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260801125632.360365-1-jhs%40mojatatu.com
--- net/sched/cls_api.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-)
net/sched/cls_api.c +13 -5
@@ -2242,6 +2242,12 @@ static bool is_ingress_or_clsact(struct tcf_block *block, struct Qdisc *q)return tcf_block_shared (block) || (q && !!(q->flags &TCQ_F_INGRESS )); } +enum tcf_tp_insert_state { +TP_NOT_CREATED =0 ,/* did not create and insert a new tp */ +TP_CREATED ,/* created and inserted a new tp */ +TP_NOT_OWNED ,/* created a proto but failed to insert */ +}; +static int tc_new_tfilter (struct sk_buff *skb,struct nlmsghdr *n,struct netlink_ext_ack *extack) {
@@ -2262,12 +2268,12 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,unsigned long cl;void *fh;int err; -int tp_created; +enum tcf_tp_insert_state tp_state;bool rtnl_held = false;u32 flags; replay: - tp_created =0 ; + tp_state =TP_NOT_CREATED ; err =nlmsg_parse_deprecated (n,sizeof (*t), tca,TCA_MAX , rtm_tca_policy, extack);
@@ -2390,13 +2396,15 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, goto errout_tp; } - tp_created =1 ; + tp_state =TP_CREATED ; tp =tcf_chain_tp_insert_unique (chain, tp_new, protocol, prio, rtnl_held);if (IS_ERR (tp)) { err =PTR_ERR (tp); goto errout_tp; } +if (tp != tp_new) + tp_state =TP_NOT_OWNED ; }else {mutex_unlock (&chain->filter_chain_lock); }
@@ -2450,13 +2458,13 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, } errout: -if (err && tp_created) +if (err && tp_state ==TP_CREATED )tcf_chain_tp_delete_empty (chain, tp, rtnl_held,NULL ); errout_tp:if (chain) {if (tp && !IS_ERR (tp))tcf_proto_put (tp, rtnl_held,NULL ); -if (!tp_created) +if (tp_state ==TP_NOT_CREATED )tcf_chain_put (chain); }tcf_block_release (q, block, rtnl_held);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1001/1376 riscv: cpufeature: Clarify ISA spec version for canonical order
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guodong Xu <[email protected]>
[ Upstream commit fdef048705daa3d4ed1fa212ee071bcbdac02d80 ]
Specify that chapter 27 refers to version 20191213 of the RISC-V ISA Unprivileged Architecture. The chapter numbering differs across specification versions - for example, in version 20250508, the ISA Extension Naming Conventions is chapter 36, not chapter 27.
Historical versions of the RISC-V specification can be found via Link [1].
--- arch/riscv/kernel/cpufeature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/riscv/kernel/cpufeature.c +2 -1
@@ -263,7 +263,8 @@ static const unsigned int riscv_c_exts[] = {/* * The canonical order of ISA extension names in the ISA string is defined in -* chapter 27 of the unprivileged specification. +* Chapter 27 of the RISC-V Instruction Set Manual Volume I Unprivileged ISA +* (Document Version 20191213). * * Ordinarily, for in-kernel data structures, this order is unimportant but * isa_ext_arr defines the order of the ISA string in /proc/cpuinfo.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1002/1376 arm64: dts: turris-mox: fix usb3 phys
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tomáš Macholda <[email protected]>
[ Upstream commit 0c2a8eed95160e41b367a1fa605a2c1b24a9639a ]
After commit 00e6d608fe80b0f6 ("arm64: dts: marvell: armada-37xx: swap PHYs' order in USB3 controller node") swapped USB3 PHY order, USB initialization breaks on Turris MOX.
This regression was exposed by commit 91ddf6f722084383 ("phy: marvell:
mvebu-a3700-utmi: fix incorrect USB2_PHY_CTRL register access") which made USB2 devices not work at all.
Fix the issue by explicitly adding all USB3 PHYs and PHY names to Turris MOX device-tree.
--- arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +2 -1
@@ -290,7 +290,8 @@ connector { &usb3 { status = "okay"; - phys = <&comphy2 0>; + phys = <&usb2_utmi_otg_phy>, <&comphy2 0>; + phy-names = "usb2-phy", "usb3-phy"; }; &mdio {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1003/1376 ARM: dts: helios4: add vcc-supply to EEPROM
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit ef65cf08bd1aa723de2854d02fb8eb8cca273c90 ]
The at24 driver requests a 'vcc' supply for the EEPROM, producing 'supply vcc not found, using dummy regulator' at boot when the property is missing.
The EEPROM sits on the Helios 4 and is powered by the same always-on 3.3V rail used by other on-board I2C devices. Add vcc-supply = <®_3p3v> to silence the warning.
--- arch/arm/boot/dts/marvell/armada-388-helios4.dts | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm/boot/dts/marvell/armada-388-helios4.dts +4 -0
@@ -201,6 +201,10 @@ temp_sensor: temp@4c { reg = <0x4c>; vcc-supply = <®_3p3v>; }; + + eeprom@53 { + vcc-supply = <®_3p3v>; + }; }; i2c@11100 {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1004/1376 ARM: dts: helios4: add vcc-supply to GPIO expander
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit c23988f84496e937dd255564cb30bec67608dcc6 ]
The pca953x driver requests a 'vcc' supply, producing:
pca953x 0-0020: supply vcc not found, using dummy regulator
The PCA9655 (PCA9555-compatible) expander is powered by the same always-on 3.3V rail as the other I2C devices on the bus. Add vcc-supply = <®_3p3v> to silence the warning.
--- arch/arm/boot/dts/marvell/armada-388-helios4.dts | 1 + 1 file changed, 1 insertion(+)
arch/arm/boot/dts/marvell/armada-388-helios4.dts +1 -0
@@ -169,6 +169,7 @@ expander0: gpio-expander@20 { gpio-controller; #gpio-cells = <2>; reg = <0x20>; + vcc-supply = <®_3p3v>; pinctrl-names = "default"; pinctrl-0 = <&pca0_pins>; interrupt-parent = <&gpio0>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1005/1376 ARM: dts: helios4: add SATA regulator supplies
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit 7a90520e8c9a8f48fe6f3e741cf34d8c2b6dbc61 ]
The ahci-mvebu driver and libahci_platform request three supplies on SATA controller and port nodes:
- ahci-supply (controller power)
- phy-supply (PHY power)
- target-supply (disk power per port)
Without them the regulator core prints notices at boot, e.g.:
supply ahci not found, using dummy regulator supply phy not found, using dummy regulator supply target not found, using dummy regulator
The SATA controller and PHY inside the Armada 388 SoC are powered by the 3.3V I/O rail; the four disk bays are powered by the 5V HDD rail. Wire the existing fixed regulators accordingly.
--- arch/arm/boot/dts/marvell/armada-388-helios4.dts | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/arm/boot/dts/marvell/armada-388-helios4.dts +8 -0
@@ -222,13 +222,17 @@ sata@a8000 { status = "okay"; #address-cells = <1>; #size-cells = <0>; + ahci-supply = <®_3p3v>; + phy-supply = <®_3p3v>; sata0: sata-port@0 { reg = <0>; + target-supply = <®_5p0v_hdd>; }; sata1: sata-port@1 { reg = <1>; + target-supply = <®_5p0v_hdd>; }; };
@@ -236,13 +240,17 @@ sata@e0000 { status = "okay"; #address-cells = <1>; #size-cells = <0>; + ahci-supply = <®_3p3v>; + phy-supply = <®_3p3v>; sata2: sata-port@0 { reg = <0>; + target-supply = <®_5p0v_hdd>; }; sata3: sata-port@1 { reg = <1>; + target-supply = <®_5p0v_hdd>; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1006/1376 perf stat: Fix evsel_list leak in cmd_stat
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 340641a4b5fff4f4b12261c9d92169f6e2ea11f4 ]
Fix a memory leak in cmd_stat() where evsel_list is leaked if an error occurs while opening the output file.
--- tools/perf/builtin-stat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/perf/builtin-stat.c +6 -3
@@ -2648,7 +2648,8 @@ int cmd_stat(int argc, const char **argv) output =fopen (output_name, mode);if (!output) {perror ("failed to create output file" ); -return -1 ; + status =-1 ; + goto out; }if (!stat_config.json_output) {clock_gettime (CLOCK_REALTIME , &tm);
@@ -2659,7 +2660,8 @@ int cmd_stat(int argc, const char **argv) output =fdopen (output_fd, mode);if (!output) {perror ("Failed opening logfd" ); -return -errno; + status = -errno; + goto out; } }
@@ -2668,7 +2670,8 @@ int cmd_stat(int argc, const char **argv)parse_options_usage (stat_usage, stat_options,"o" ,1 );parse_options_usage (NULL , stat_options,"log-fd" ,0 );parse_options_usage (NULL , stat_options,"interval-clear" ,0 ); -return -1 ; + status =-1 ; + goto out; } stat_config.output = output;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1007/1376 perf synthetic-events: Fix uninitialized pthread_join
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 54ba44db4dddc4ca06b49bae0f9d6c5861430b18 ]
In perf_event__synthesize_threads(), fix an uninitialized pthread_join() call when thread creation fails by only joining the successfully created threads.
--- tools/perf/util/synthetic-events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/synthetic-events.c +2 -2
@@ -1091,8 +1091,8 @@ int perf_event__synthesize_threads(const struct perf_tool *tool, } err =0 ; out_join: -for (i =0 ; i < thread_nr; i++) -pthread_join (synthesize_threads[i],NULL ); +for (j =0 ; j < i; j++) +pthread_join (synthesize_threads[j],NULL );free (args); free_threads:free (synthesize_threads);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1008/1376 perf test: Introduce workloads__for_each()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 18b63d63cd0148fef02c6c3f33a596ad7ee97a9a ]
And use it in run_workload().
Testing it:
root@x1:~# perf trace -e *landlock* perf test -w landlock
0.000 ( 0.015 ms): :1274331/1274331 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_PATH_BENEATH, rule_attr: 0x7ffd3fea55e0, flags: 45) = -1 EINVAL (Invalid argument)
0.018 ( 0.003 ms): :1274331/1274331 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_NET_PORT, rule_attr: 0x7ffd3fea55f0, flags: 45) = -1 EINVAL (Invalid argument)
root@x1:~# perf test -w bla
No workload found: bla
root@x1:~#Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
tools/perf/tests/builtin-test.c +4 -3
@@ -156,6 +156,9 @@ static struct test_workload *workloads[] = { &workload__traploop, }; +#define workloads__for_each (workload) \ + for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++) +static int num_subtests (const struct test_suite *t) {int num;
@@ -505,11 +508,9 @@ static int perf_test__list(int argc, const char **argv)static int run_workload (const char *work,int argc,const char **argv) { -unsigned int i =0 ;struct test_workload *twl; -for (i =0 ; i <ARRAY_SIZE (workloads); i++) { - twl = workloads[i]; +workloads__for_each (twl) {if (!strcmp (twl->name, work))return twl->func (argc, argv); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1009/1376 perf test: Display number of active running tests
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 0e036dcad4e62b89f8df3e41402babb9345521af ]
Before polling or sleeping to wait for a test to complete, print out ": Running (<num> active)" where the number of active tests is determined by iterating over the tests and seeing which return false for check_if_command_finished. The line erasing and printing out only occur if the number of runnings tests changes to avoid the line flickering excessively. Knowing tests are running allows a user to know a test is running and in parallel mode how many of the tests are waiting to complete. If color mode is disabled then avoid displaying the "Running" message as deleting the line isn't reliable.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 93 ++++++++++++++++++++++----------- tools/perf/util/color.h | 1 + 2 files changed, 63 insertions(+), 31 deletions(-)
tools/perf/tests/builtin-test.c +62 -31
@@ -246,7 +246,10 @@ static int run_test_child(struct child_process *process)return -err; } -static int print_test_result (struct test_suite *t,int i,int subtest,int result,int width) +#define TEST_RUNNING -3 + +static int print_test_result (struct test_suite *t,int i,int subtest,int result,int width, +int running) {if (has_subtests (t)) {int subw = width >2 ? width -2 : width;
@@ -256,6 +259,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resulpr_info ("%3d: %-*s:" , i +1 , width,test_description (t, subtest));switch (result) { +case TEST_RUNNING : +color_fprintf (stderr,PERF_COLOR_YELLOW ," Running (%d active)\n" , running); +break ;case TEST_OK :pr_info (" Ok\n" );break ;
@@ -277,14 +283,17 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resulreturn 0 ; } -static int finish_test (struct child_test *child_test,int width) +static int finish_test (struct child_test **child_tests,int running_test,int child_test_num, +int width) { +struct child_test *child_test = child_tests[running_test];struct test_suite *t = child_test->test;int i = child_test->test_num;int subi = child_test->subtest;int err = child_test->process.err; -bool err_done = err <=0 ; +bool err_done = false;struct strbuf err_output =STRBUF_INIT ; +int last_running =-1 ;int ret;/*
@@ -298,7 +307,7 @@ static int finish_test(struct child_test *child_test, int width)* Busy loop reading from the child's stdout/stderr that are set to be * non-blocking until EOF. */ -if (!err_done) +if (err >0 )fcntl (err,F_SETFL ,O_NONBLOCK );if (verbose >1 ) {if (has_subtests (t))
@@ -312,38 +321,60 @@ static int finish_test(struct child_test *child_test, int width) .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, }, }; -char buf[512 ]; -ssize_t len; - -/* Poll to avoid excessive spinning, timeout set for 100ms. */ -poll (pfds,ARRAY_SIZE (pfds),/*timeout=*/ 100 ); -if (!err_done && pfds[0 ].revents) { - errno =0 ; - len =read (err, buf,sizeof (buf) -1 ); - -if (len <=0 ) { - err_done = errno !=EAGAIN ; - }else { - buf[len] ='\0' ; -if (verbose >1 ) -fprintf (stdout,"%s" , buf); -else +if (perf_use_color_default) { +int running =0 ; + +for (int y = running_test; y < child_test_num; y++) { +if (check_if_command_finished (&child_tests[y]->process) ==0 ) + running++; + } +if (running != last_running) { +if (last_running !=-1 ) { +/* +* Erase "Running (.. active)" line +* printed before poll/sleep. +*/ +fprintf (debug_file (),PERF_COLOR_DELETE_LINE ); + } +print_test_result (t, i, subi,TEST_RUNNING , width, running); + last_running = running; + } + } + + err_done = true; +if (err <=0 ) { +/* No child stderr to poll, sleep for 10ms for child to complete. */ +usleep (10 *1000 ); + }else { +/* Poll to avoid excessive spinning, timeout set for 100ms. */ +poll (pfds,ARRAY_SIZE (pfds),/*timeout=*/ 100 ); +if (pfds[0 ].revents) { +char buf[512 ]; +ssize_t len; + + len =read (err, buf,sizeof (buf) -1 ); + +if (len >0 ) { + err_done = false; + buf[len] ='\0' ;strbuf_addstr (&err_output, buf); + } } } +if (err_done) + err_done =check_if_command_finished (&child_test->process); + } +if (perf_use_color_default && last_running !=-1 ) { +/* Erase "Running (.. active)" line printed before poll/sleep. */ +fprintf (debug_file (),PERF_COLOR_DELETE_LINE ); }/* Clean up child process. */ ret =finish_command (&child_test->process); -if (verbose ==1 && ret ==TEST_FAIL ) { -/* Add header for test that was skipped above. */ -if (has_subtests (t)) -pr_info ("%3d.%1d: %s:\n" , i +1 , subi +1 ,test_description (t, subi)); -else -pr_info ("%3d: %s:\n" , i +1 ,test_description (t,-1 )); +if (verbose >1 || (verbose ==1 && ret ==TEST_FAIL ))fprintf (stderr,"%s" , err_output.buf); - } +strbuf_release (&err_output); -print_test_result (t, i, subi, ret, width); +print_test_result (t, i, subi, ret, width,/*running=*/ 0 );if (err >0 )close (err);return 0 ;
@@ -359,7 +390,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tespr_debug ("--- start ---\n" ); err =test_function (test, subi)(test, subi);pr_debug ("---- end ----\n" ); -print_test_result (test, i, subi, err, width); +print_test_result (test, i, subi, err, width,/*running=*/ 0 );return 0 ; }
@@ -384,7 +415,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes err =start_command (&(*child)->process);if (err || !sequential)return err; -return finish_test (*child, width); +return finish_test (child,/*running_test=*/ 0 ,/*child_test_num=*/ 1 , width); }#define for_each_test (j, k, t) \
@@ -469,7 +500,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) }for (i =0 ; i < child_test_num; i++) {if (!sequential) { -int ret =finish_test (child_tests[i], width); +int ret =finish_test (child_tests, i, child_test_num, width);if (ret)return ret;
tools/perf/util/color.h +1 -0
@@ -22,6 +22,7 @@#define MIN_GREEN 0.5#define MIN_RED 5.0 +#define PERF_COLOR_DELETE_LINE "\033[A\33[2K\r"/* * This variable stores the value of color.ui */
Signature · 1 line
2.53.0
Re: [PATCH 6.12 1009/1376] perf test: Display number of active running tests
Quoted 1 line · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
It's hard to see how these 6 perf test patches are stable material.
They seem at best be nice to have.
-Andi
Quoted 222 lines
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit
0e036dcad4e62b89f8df3e41402babb9345521af]Before polling or sleeping to wait for a test to complete, print out ": Running (<num> active)" where the number of active tests is determined by iterating over the tests and seeing which return false for
check_if_command_finished. The line erasing and printing out only occur if the number of runnings tests changes to avoid the line flickering excessively. Knowing tests are running allows a user to know a test is running and in parallel mode how many of the tests are waiting to complete. If color mode is disabled then avoid displaying the "Running" message as deleting the line isn't reliable.Tested-by James Clark <[email protected]>Signed-off-by Ian Rogers <[email protected]>Cc Colin Ian King <[email protected]>Cc Howard Chu <[email protected]>Cc Weilin Wang <[email protected]>Cc Ilya Leoshkevich <[email protected]>Cc Thomas Richter <[email protected]>Cc Andi Kleen <[email protected]>Cc Dapeng Mi <[email protected]>Cc Athira Jajeev <[email protected]>Cc Michael Petlan <[email protected]>Cc Veronika Molnarova <[email protected]>Signed-off-by Namhyung Kim <[email protected]>Stable-dep-of:
44e82c4d2ff3("perf test: Fix skiplist leak incmd_test")Signed-off-by Sasha Levin <[email protected]>--- tools/perf/tests/builtin-test.c | 93 ++++++++++++++++++++++----------- tools/perf/util/color.h | 1 + 2 files changed, 63 insertions(+), 31 deletions(-)tools/perf/tests/builtin-test.c +62
-31@@ -246,7 +246,10 @@ static int run_test_child(struct child_process *process)return -err; } -static int print_test_result (struct test_suite *t,int i,int subtest,int result,int width) +#define TEST_RUNNING -3 + +static int print_test_result (struct test_suite *t,int i,int subtest,int result,int width, +int running) {if (has_subtests (t)) {int subw = width >2 ? width -2 : width;@@ -256,6 +259,9 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resulpr_info ("%3d: %-*s:" , i +1 , width,test_description (t, subtest));switch (result) { +case TEST_RUNNING : +color_fprintf (stderr,PERF_COLOR_YELLOW ," Running (%d active)\n" , running); +break ;case TEST_OK :pr_info (" Ok\n" );break ;@@ -277,14 +283,17 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resulreturn 0 ; } -static int finish_test (struct child_test *child_test,int width) +static int finish_test (struct child_test **child_tests,int running_test,int child_test_num, +int width) { +struct child_test *child_test = child_tests[running_test];struct test_suite *t = child_test->test;int i = child_test->test_num;int subi = child_test->subtest;int err = child_test->process.err; -bool err_done = err <=0 ; +bool err_done = false;struct strbuf err_output =STRBUF_INIT ; +int last_running =-1 ;int ret;/* @@ -298,7 +307,7 @@ static int finish_test(struct child_test *child_test, int width)* Busy loop reading from the child's stdout/stderr that are set to be * non-blocking until EOF. */ -if (!err_done) +if (err >0 )fcntl (err,F_SETFL ,O_NONBLOCK );if (verbose >1 ) {if (has_subtests (t))@@ -312,38 +321,60 @@ static int finish_test(struct child_test *child_test, int width) .events = POLLIN | POLLERR | POLLHUP | POLLNVAL, }, }; -char buf[512 ]; -ssize_t len; - -/* Poll to avoid excessive spinning, timeout set for 100ms. */ -poll (pfds,ARRAY_SIZE (pfds),/*timeout=*/ 100 ); -if (!err_done && pfds[0 ].revents) { - errno =0 ; - len =read (err, buf,sizeof (buf) -1 ); - -if (len <=0 ) { - err_done = errno !=EAGAIN ; - }else { - buf[len] ='\0' ; -if (verbose >1 ) -fprintf (stdout,"%s" , buf); -else +if (perf_use_color_default) { +int running =0 ; + +for (int y = running_test; y < child_test_num; y++) { +if (check_if_command_finished (&child_tests[y]->process) ==0 ) + running++; + } +if (running != last_running) { +if (last_running !=-1 ) { +/* +* Erase "Running (.. active)" line +* printed before poll/sleep. +*/ +fprintf (debug_file (),PERF_COLOR_DELETE_LINE ); + } +print_test_result (t, i, subi,TEST_RUNNING , width, running); + last_running = running; + } + } + + err_done = true; +if (err <=0 ) { +/* No child stderr to poll, sleep for 10ms for child to complete. */ +usleep (10 *1000 ); + }else { +/* Poll to avoid excessive spinning, timeout set for 100ms. */ +poll (pfds,ARRAY_SIZE (pfds),/*timeout=*/ 100 ); +if (pfds[0 ].revents) { +char buf[512 ]; +ssize_t len; + + len =read (err, buf,sizeof (buf) -1 ); + +if (len >0 ) { + err_done = false; + buf[len] ='\0' ;strbuf_addstr (&err_output, buf); + } } } +if (err_done) + err_done =check_if_command_finished (&child_test->process); + } +if (perf_use_color_default && last_running !=-1 ) { +/* Erase "Running (.. active)" line printed before poll/sleep. */ +fprintf (debug_file (),PERF_COLOR_DELETE_LINE ); }/* Clean up child process. */ ret =finish_command (&child_test->process); -if (verbose ==1 && ret ==TEST_FAIL ) { -/* Add header for test that was skipped above. */ -if (has_subtests (t)) -pr_info ("%3d.%1d: %s:\n" , i +1 , subi +1 ,test_description (t, subi)); -else -pr_info ("%3d: %s:\n" , i +1 ,test_description (t,-1 )); +if (verbose >1 || (verbose ==1 && ret ==TEST_FAIL ))fprintf (stderr,"%s" , err_output.buf); - } +strbuf_release (&err_output); -print_test_result (t, i, subi, ret, width); +print_test_result (t, i, subi, ret, width,/*running=*/ 0 );if (err >0 )close (err);return 0 ;@@ -359,7 +390,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tespr_debug ("--- start ---\n" ); err =test_function (test, subi)(test, subi);pr_debug ("---- end ----\n" ); -print_test_result (test, i, subi, err, width); +print_test_result (test, i, subi, err, width,/*running=*/ 0 );return 0 ; }@@ -384,7 +415,7 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes err =start_command (&(*child)->process);if (err || !sequential)return err; -return finish_test (*child, width); +return finish_test (child,/*running_test=*/ 0 ,/*child_test_num=*/ 1 , width); }#define for_each_test (j, k, t) \@@ -469,7 +500,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) }for (i =0 ; i < child_test_num; i++) {if (!sequential) { -int ret =finish_test (child_tests[i], width); +int ret =finish_test (child_tests, i, child_test_num, width);if (ret)return ret;tools/perf/util/color.h +1
-0@@ -22,6 +22,7 @@#define MIN_GREEN 0.5#define MIN_RED 5.0 +#define PERF_COLOR_DELETE_LINE "\033[A\33[2K\r"/* * This variable stores the value of color.ui */ Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerRe: [PATCH 6.12 1009/1376] perf test: Display number of active running tests
Quoted 6 lines · Andi Kleen
Quoted 1 line · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
It's hard to see how these 6 perf test patches are stable material.
They seem at best be nice to have.
They were needed because of:
Quoted 1 line
Quoted 1 line
Stable-dep-of:
44e82c4d2ff3("perf test: Fix skiplist leak incmd_test")
thanks,
greg k-h
Re: [PATCH 6.12 1009/1376] perf test: Display number of active running tests
Quoted 6 lines · Greg Kroah-Hartman
Quoted 5 lines · Andi Kleen
Quoted 1 line · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
It's hard to see how these 6 perf test patches are stable material.
Quoted 7 lines
Quoted 1 line
They seem at best be nice to have.
They were needed because of:
Quoted 1 line
Quoted 1 line
Stable-dep-of:
44e82c4d2ff3("perf test: Fix skiplist leak incmd_test")thanks,
It's same there, I don't think anything perf test is stable material.
It's just a test suite after all.
-Andi
Greg Kroah-Hartman
maintainerPATCH 1010/1376 perf test: Add a signal handler around running a test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit a6fffc60940a903ebcd70d44f047277ba5188225 ]
Add a signal handler around running a test. If a signal occurs during the test a siglongjmp unwinds the stack and output is flushed. The global run_test_jmp_buf is either unique per forked child or not shared during sequential execution.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
tools/perf/tests/builtin-test.c +27 -1
@@ -8,6 +8,7 @@#include <errno.h> #include <poll.h> #include <unistd.h> +#include <setjmp.h> #include <string.h> #include <stdlib.h> #include <sys/types.h>
@@ -233,16 +234,41 @@ struct child_test {int subtest; }; +static jmp_buf run_test_jmp_buf; + +static void child_test_sig_handler (int sig) +{ +siglongjmp (run_test_jmp_buf, sig); +} +static int run_test_child (struct child_process *process) { - struct child_test *child = container_of(process, struct child_test, process); +const int signals[] = { +SIGABRT ,SIGBUS ,SIGFPE ,SIGILL ,SIGINT ,SIGPIPE ,SIGQUIT ,SIGSEGV ,SIGTERM , + }; +static struct child_test *child;int err; + err =sigsetjmp (run_test_jmp_buf,1 ); +if (err) { +fprintf (stderr,"\n---- unexpected signal (%d) ----\n" , err); + err = err >0 ? -err :-1 ; + goto err_out; + } + + child = container_of(process, struct child_test, process); +for (size_t i =0 ; i <ARRAY_SIZE (signals); i++) +signal (signals[i], child_test_sig_handler); +pr_debug ("--- start ---\n" );pr_debug ("test child forked, pid %d\n" ,getpid ()); err =test_function (child->test, child->subtest)(child->test, child->subtest);pr_debug ("---- end(%d) ----\n" , err); + +err_out:fflush (NULL ); +for (size_t i =0 ; i <ARRAY_SIZE (signals); i++) +signal (signals[i],SIG_DFL );return -err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1011/1376 perf test: Run parallel tests in two passes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 79e72f384d733f78cb07a9649a5ea52b78898a30 ]
In pass 1 run all tests that succeed when run in parallel. In pass 2 sequentially run all remaining tests that are flagged as "exclusive". Sequential and dont_fork tests keep to run in pass 1. Read the exclusive flag from the shell test descriptions, but remove from display to avoid >100 characters. Add error handling to finish tests if starting a later test fails. Mark the task-exit test as exclusive due to issues reported-by James Clark.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 157 +++++++++++++++++++------------ tools/perf/tests/task-exit.c | 9 +- tools/perf/tests/tests-scripts.c | 7 +- tools/perf/tests/tests.h | 9 ++ 4 files changed, 121 insertions(+), 61 deletions(-)
tools/perf/tests/builtin-test.c +98 -59
@@ -203,6 +203,14 @@ static test_fnptr test_function(const struct test_suite *t, int subtest)return t->test_cases[subtest].run_case; } +static bool test_exclusive (const struct test_suite *t,int subtest) +{ +if (subtest <=0 ) +return t->test_cases[0 ].exclusive; + +return t->test_cases[subtest].exclusive; +} +static bool perf_test__matches (const char *desc,int curr,int argc,const char *argv[]) {int i;
@@ -246,7 +254,7 @@ static int run_test_child(struct child_process *process)const int signals[] = {SIGABRT ,SIGBUS ,SIGFPE ,SIGILL ,SIGINT ,SIGPIPE ,SIGQUIT ,SIGSEGV ,SIGTERM , }; -static struct child_test *child; + struct child_test *child = container_of(process, struct child_test, process);int err; err =sigsetjmp (run_test_jmp_buf,1 );
@@ -256,7 +264,6 @@ static int run_test_child(struct child_process *process) goto err_out; } - child = container_of(process, struct child_test, process);for (size_t i =0 ; i <ARRAY_SIZE (signals); i++)signal (signals[i], child_test_sig_handler);
@@ -309,19 +316,25 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resulreturn 0 ; } -static int finish_test (struct child_test **child_tests,int running_test,int child_test_num, -int width) +static void finish_test (struct child_test **child_tests,int running_test,int child_test_num, +int width) {struct child_test *child_test = child_tests[running_test]; -struct test_suite *t = child_test->test; -int i = child_test->test_num; -int subi = child_test->subtest; -int err = child_test->process.err; +struct test_suite *t; +int i, subi, err;bool err_done = false;struct strbuf err_output =STRBUF_INIT ;int last_running =-1 ;int ret; +if (child_test ==NULL ) { +/* Test wasn't started. */ +return ; + } + t = child_test->test; + i = child_test->test_num; + subi = child_test->subtest; + err = child_test->process.err;/* * For test suites with subtests, display the suite name ahead of the * sub test names.
@@ -351,6 +364,8 @@ static int finish_test(struct child_test **child_tests, int running_test, int chint running =0 ;for (int y = running_test; y < child_test_num; y++) { +if (child_tests[y] ==NULL ) +continue ;if (check_if_command_finished (&child_tests[y]->process) ==0 ) running++; }
@@ -403,23 +418,32 @@ static int finish_test(struct child_test **child_tests, int running_test, int chprint_test_result (t, i, subi, ret, width,/*running=*/ 0 );if (err >0 )close (err); -return 0 ; +zfree (&child_tests[running_test]); }static int start_test (struct test_suite *test,int i,int subi,struct child_test **child, -int width) +int width,int pass) {int err; *child =NULL ;if (dont_fork) { -pr_debug ("--- start ---\n" ); - err =test_function (test, subi)(test, subi); -pr_debug ("---- end ----\n" ); -print_test_result (test, i, subi, err, width,/*running=*/ 0 ); +if (pass ==1 ) { +pr_debug ("--- start ---\n" ); + err =test_function (test, subi)(test, subi); +pr_debug ("---- end ----\n" ); +print_test_result (test, i, subi, err, width,/*running=*/ 0 ); + } +return 0 ; + } +if (pass ==1 && !sequential &&test_exclusive (test, subi)) { +/* When parallel, skip exclusive tests on the first pass. */ +return 0 ; + } +if (pass !=1 && (sequential || !test_exclusive (test, subi))) { +/* Sequential and non-exclusive tests were run on the first pass. */ return 0 ; } - *child =zalloc (sizeof (**child));if (!*child)return -ENOMEM ;
@@ -438,10 +462,14 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tes (*child)->process.err =-1 ; } (*child)->process.no_exec_cmd = run_test_child; - err =start_command (&(*child)->process); -if (err || !sequential) -return err; -return finish_test (child,/*running_test=*/ 0 ,/*child_test_num=*/ 1 , width); +if (sequential || pass ==2 ) { + err =start_command (&(*child)->process); +if (err) +return err; +finish_test (child,/*running_test=*/ 0 ,/*child_test_num=*/ 1 , width); +return 0 ; + } +return start_command (&(*child)->process); }#define for_each_test (j, k, t) \
@@ -451,12 +479,11 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tesstatic int __cmd_test (int argc,const char *argv[],struct intlist *skiplist) {struct test_suite *t; -unsigned int j, k; -int i =0 ;int width =0 ; +unsigned int j, k;size_t num_tests =0 ;struct child_test **child_tests; -int child_test_num =0 ; +int err =0 ;for_each_test (j, k, t) {int len =strlen (test_description (t,-1 ));
@@ -479,62 +506,73 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)if (!child_tests)return -ENOMEM ; -for_each_test (j, k, t) { -int curr = i++; - -if (!perf_test__matches (test_description (t,-1 ), curr, argc, argv)) { -bool skip = true; +/* +* In parallel mode pass 1 runs non-exclusive tests in parallel, pass 2 +* runs the exclusive tests sequentially. In other modes all tests are +* run in pass 1. +*/ +for (int pass =1 ; pass <=2 ; pass++) { +int child_test_num =0 ; +int i =0 ; + +for_each_test (j, k, t) { +int curr = i++; + +if (!perf_test__matches (test_description (t,-1 ), curr, argc, argv)) { +/* +* Test suite shouldn't be run based on +* description. See if subtest should. +*/ +bool skip = true; + +for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { +if (perf_test__matches (test_description (t, subi), + curr, argc, argv)) + skip = false; + } -for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { -if (perf_test__matches (test_description (t, subi), - curr, argc, argv)) - skip = false; +if (skip) +continue ; } -if (skip) +if (intlist__find (skiplist, i)) { +pr_info ("%3d: %-*s:" , curr +1 , width,test_description (t,-1 )); +color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip (user override)\n" );continue ; - } - -if (intlist__find (skiplist, i)) { -pr_info ("%3d: %-*s:" , curr +1 , width,test_description (t,-1 )); -color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip (user override)\n" ); -continue ; - } - -if (!has_subtests (t)) { -int err =start_test (t, curr,-1 , &child_tests[child_test_num++], width); + } -if (err) { -/* TODO: if !sequential waitpid the already forked children. */ -free (child_tests); -return err; +if (!has_subtests (t)) { + err =start_test (t, curr,-1 , &child_tests[child_test_num++], + width, pass); +if (err) + goto err_out; +continue ; } - }else {for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { -int err; -if (!perf_test__matches (test_description (t, subi), curr, argc, argv))continue ; err =start_test (t, curr, subi, &child_tests[child_test_num++], - width); + width, pass);if (err) -return err; + goto err_out; } } - } -for (i =0 ; i < child_test_num; i++) {if (!sequential) { -int ret =finish_test (child_tests, i, child_test_num, width); - -if (ret) -return ret; +/* Parallel mode starts tests but doesn't finish them. Do that now. */ +for (size_t x =0 ; x < num_tests; x++) +finish_test (child_tests, x, num_tests, width); } -free (child_tests[i]); + } +err_out: +if (err) { +pr_err ("Internal test harness failure. Completing any started tests:\n:" ); +for (size_t x =0 ; x < num_tests; x++) +finish_test (child_tests, x, num_tests, width); }free (child_tests); -return 0 ; +return err; }static int perf_test__list (int argc,const char **argv)
@@ -636,6 +674,7 @@ int cmd_test(int argc, const char **argv) symbol_conf.priv_size =sizeof (int ); symbol_conf.try_vmlinux_path = true; +if (symbol__init (NULL ) <0 )return -1 ;
tools/perf/tests/task-exit.c +8 -1
@@ -152,4 +152,11 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _return err; } -DEFINE_SUITE ("Number of exit events of a simple workload" , task_exit); +struct test_case tests__task_exit[] = { +TEST_CASE_EXCLUSIVE ("Number of exit events of a simple workload" , task_exit), + { .name =NULL , } +}; +struct test_suite suite__task_exit = { + .desc ="Number of exit events of a simple workload" , + .test_cases = tests__task_exit, +};
tools/perf/tests/tests-scripts.c +6 -1
@@ -175,6 +175,7 @@ static void append_script(int dir_fd, const char *name, char *desc,struct test_suite *test_suite, **result_tmp;struct test_case *tests;size_t len; +char *exclusive;snprintf (link,sizeof (link),"/proc/%d/fd/%d" ,getpid (), dir_fd); len =readlink (link, filename,sizeof (filename));
@@ -191,9 +192,13 @@ static void append_script(int dir_fd, const char *name, char *desc,return ; } tests[0 ].name =strdup_check (name); + exclusive =strstr (desc," (exclusive)" ); +if (exclusive !=NULL ) { + tests[0 ].exclusive = true; + exclusive[0 ] ='\0' ; + } tests[0 ].desc =strdup_check (desc); tests[0 ].run_case = shell_test__run; - test_suite =zalloc (sizeof (*test_suite));if (!test_suite) {pr_err ("Out of memory while building script test suite list\n" );
tools/perf/tests/tests.h +9 -0
@@ -36,6 +36,7 @@ struct test_case {const char *desc;const char *skip_reason;test_fnptr run_case; +bool exclusive; };struct test_suite {
@@ -62,6 +63,14 @@ struct test_suite { .skip_reason = _reason, \ } +#define TEST_CASE_EXCLUSIVE (description, _name) \ + { \ + .name = #_name, \ + .desc = description, \ + .run_case = test__##_name, \ + .exclusive = true, \ + } +#define DEFINE_SUITE (description, _name) \ struct test_case tests__##_name[] = { \ TEST_CASE(description, _name), \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1012/1376 perf test: Add a signal handler to kill forked child processes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 553d5efeb341f2f814f937e0658ed7d22f625662 ]
If the perf test process is killed the child tests continue running and may run indefinitely. Propagate SIGINT (ctrl-C) and SIGTERM (kill) signals to the running child processes so that they terminate when the parent is killed.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 37 ++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-)
tools/perf/tests/builtin-test.c +34 -3
@@ -476,13 +476,22 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tesfor (j =0 , k =0 ; j <ARRAY_SIZE (tests); j++, k =0 ) \while ((t = tests[j][k++]) !=NULL ) +/* State outside of __cmd_test for the sake of the signal handler. */ + +static size_t num_tests; +static struct child_test **child_tests; +static jmp_buf cmd_test_jmp_buf; + +static void cmd_test_sig_handler (int sig) +{ +siglongjmp (cmd_test_jmp_buf, sig); +} +static int __cmd_test (int argc,const char *argv[],struct intlist *skiplist) {struct test_suite *t; -int width =0 ; +static int width =0 ;unsigned int j, k; -size_t num_tests =0 ; -struct child_test **child_tests;int err =0 ;for_each_test (j, k, t) {
@@ -506,6 +515,26 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)if (!child_tests)return -ENOMEM ; + err =sigsetjmp (cmd_test_jmp_buf,1 ); +if (err) { +pr_err ("\nSignal (%d) while running tests.\nTerminating tests with the same signal\n" , + err); +for (size_t x =0 ; x < num_tests; x++) { +struct child_test *child_test = child_tests[x]; + +if (!child_test) +continue ; + +pr_debug3 ("Killing %d pid %d\n" , + child_test->test_num +1 , + child_test->process.pid); +kill (child_test->process.pid, err); + } + goto err_out; + } +signal (SIGINT , cmd_test_sig_handler); +signal (SIGTERM , cmd_test_sig_handler); +/* * In parallel mode pass 1 runs non-exclusive tests in parallel, pass 2 * runs the exclusive tests sequentially. In other modes all tests are
@@ -566,6 +595,8 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) } } err_out: +signal (SIGINT ,SIG_DFL ); +signal (SIGTERM ,SIG_DFL );if (err) {pr_err ("Internal test harness failure. Completing any started tests:\n:" );for (size_t x =0 ; x < num_tests; x++)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1013/1376 perf test: Sort tests placing exclusive tests last
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 7449a4d674cc14f8e689cecf7354748706d00f30 ]
This allows a uniform test numbering even though two passes are used to execute them.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 125 +++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 41 deletions(-)
tools/perf/tests/builtin-test.c +84 -41
@@ -140,12 +140,6 @@ static struct test_suite *generic_tests[] = { NULL, }; -static struct test_suite **tests[] = { - generic_tests, - arch_tests, -NULL ,/* shell tests created at runtime. */ -}; -static struct test_workload *workloads[] = { &workload__noploop, &workload__thloop,
@@ -472,10 +466,6 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tesreturn start_command (&(*child)->process); } -#define for_each_test (j, k, t) \ - for (j = 0, k = 0; j < ARRAY_SIZE(tests); j++, k = 0) \ - while ((t = tests[j][k++]) != NULL) -/* State outside of __cmd_test for the sake of the signal handler. */ static size_t num_tests;
@@ -487,22 +477,21 @@ static void cmd_test_sig_handler(int sig)siglongjmp (cmd_test_jmp_buf, sig); } -static int __cmd_test (int argc,const char *argv[],struct intlist *skiplist) +static int __cmd_test (struct test_suite **suites,int argc,const char *argv[], +struct intlist *skiplist) { -struct test_suite *t;static int width =0 ; -unsigned int j, k;int err =0 ; -for_each_test (j, k, t) { -int len =strlen (test_description (t,-1 )); +for (struct test_suite **t = suites; *t; t++) { +int len =strlen (test_description (*t,-1 ));if (width < len) width = len; -if (has_subtests (t)) { -for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { - len =strlen (test_description (t, subi)); +if (has_subtests (*t)) { +for (int subi =0 , subn =num_subtests (*t); subi < subn; subi++) { + len =strlen (test_description (*t, subi));if (width < len) width = len; num_tests++;
@@ -544,18 +533,18 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)int child_test_num =0 ;int i =0 ; -for_each_test (j, k, t) { +for (struct test_suite **t = suites; *t; t++) {int curr = i++; -if (!perf_test__matches (test_description (t,-1 ), curr, argc, argv)) { +if (!perf_test__matches (test_description (*t,-1 ), curr, argc, argv)) {/* * Test suite shouldn't be run based on * description. See if subtest should. */ bool skip = true; -for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { -if (perf_test__matches (test_description (t, subi), +for (int subi =0 , subn =num_subtests (*t); subi < subn; subi++) { +if (perf_test__matches (test_description (*t, subi), curr, argc, argv)) skip = false; }
@@ -565,24 +554,24 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) }if (intlist__find (skiplist, i)) { -pr_info ("%3d: %-*s:" , curr +1 , width,test_description (t,-1 )); +pr_info ("%3d: %-*s:" , curr +1 , width,test_description (*t,-1 ));color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip (user override)\n" );continue ; } -if (!has_subtests (t)) { - err =start_test (t, curr,-1 , &child_tests[child_test_num++], +if (!has_subtests (*t)) { + err =start_test (*t, curr,-1 , &child_tests[child_test_num++], width, pass);if (err) goto err_out;continue ; } -for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { -if (!perf_test__matches (test_description (t, subi), +for (int subi =0 , subn =num_subtests (*t); subi < subn; subi++) { +if (!perf_test__matches (test_description (*t, subi), curr, argc, argv))continue ; - err =start_test (t, curr, subi, &child_tests[child_test_num++], + err =start_test (*t, curr, subi, &child_tests[child_test_num++], width, pass);if (err) goto err_out;
@@ -606,27 +595,25 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)return err; } -static int perf_test__list (int argc,const char **argv) +static int perf_test__list (struct test_suite **suites,int argc,const char **argv) { -unsigned int j, k; -struct test_suite *t;int i =0 ; -for_each_test (j, k, t) { +for (struct test_suite **t = suites; *t; t++) {int curr = i++; -if (!perf_test__matches (test_description (t,-1 ), curr, argc, argv)) +if (!perf_test__matches (test_description (*t,-1 ), curr, argc, argv))continue ; -pr_info ("%3d: %s\n" , i,test_description (t,-1 )); +pr_info ("%3d: %s\n" , i,test_description (*t,-1 )); -if (has_subtests (t)) { -int subn =num_subtests (t); +if (has_subtests (*t)) { +int subn =num_subtests (*t);int subi;for (subi =0 ; subi < subn; subi++)pr_info ("%3d:%1d: %s\n" , i, subi +1 , -test_description (t, subi)); +test_description (*t, subi)); } }return 0 ;
@@ -654,6 +641,55 @@ static int perf_test__config(const char *var, const char *value,return 0 ; } +static struct test_suite **build_suites (void ) +{ +/* +* TODO: suites is static to avoid needing to clean up the scripts tests +* for leak sanitizer. +*/ +static struct test_suite **suites[] = { + generic_tests, + arch_tests, +NULL , + }; +struct test_suite **result; +struct test_suite *t; +size_t n =0 , num_suites =0 ; + +if (suites[2 ] ==NULL ) + suites[2 ] =create_script_test_suites (); + +#define for_each_test (t) \ + for (size_t i = 0, j = 0; i < ARRAY_SIZE(suites); i++, j = 0) \ + while ((t = suites[i][j++]) != NULL) + +for_each_test (t) + num_suites++; + + result =calloc (num_suites +1 ,sizeof (struct test_suite *)); + +for (int pass =1 ; pass <=2 ; pass++) { +for_each_test (t) { +bool exclusive = false; + +if (!has_subtests (t)) { + exclusive =test_exclusive (t,-1 ); + }else { +for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { +if (test_exclusive (t, subi)) { + exclusive = true; +break ; + } + } + } +if ((!exclusive && pass ==1 ) || (exclusive && pass ==2 )) + result[n++] = t; + } + } +return result; +#undef for_each_test +} +int cmd_test (int argc,const char **argv) {const char *test_usage[] = {
@@ -680,6 +716,7 @@ int cmd_test(int argc, const char **argv)const char *const test_subcommands[] = {"list" ,NULL };struct intlist *skiplist =NULL ;int ret =hists__init (); +struct test_suite **suites;if (ret <0 )return ret;
@@ -689,10 +726,13 @@ int cmd_test(int argc, const char **argv)/* Unbuffered output */ setvbuf (stdout,NULL , _IONBF,0 ); - tests[2 ] =create_script_test_suites (); argc =parse_options_subcommand (argc, argv, test_options, test_subcommands, test_usage,0 ); -if (argc >=1 && !strcmp (argv[0 ],"list" )) -return perf_test__list (argc -1 , argv +1 ); +if (argc >=1 && !strcmp (argv[0 ],"list" )) { + suites =build_suites (); + ret =perf_test__list (suites, argc -1 , argv +1 ); +free (suites); +return ret; + }if (workload)return run_workload (workload, argc, argv);
@@ -717,5 +757,8 @@ int cmd_test(int argc, const char **argv)*/ rlimit__bump_memlock (); -return __cmd_test (argc, argv, skiplist); + suites =build_suites (); + ret =__cmd_test (suites, argc, argv, skiplist); +free (suites); +return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1014/1376 perf test: Rename functions and variables for better clarity
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 2e47c503deeeadc1bfa66ece7f75e298a814e94f ]
The relationship between subtests and test cases is somewhat confusing, so let's do away with the notion of sub-tests and switch to just working with some number of test cases. Add a test_suite__for_each_test_case as in many cases, except the special one test case situation, the iteration can just be on all test cases. Switch variable names to be more intention revealing of what their value is.
This work was motivated by discussion with Kan where it was noted the code is becoming overly indented:
https://lore.kernel.org/lkml/[email protected]/
Unifying more of the sub-test/no-sub-tests avoids one level of indentation in a number of places.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 201 +++++++++++++++----------------- 1 file changed, 93 insertions(+), 108 deletions(-)
tools/perf/tests/builtin-test.c +93 -108
@@ -154,58 +154,51 @@ static struct test_workload *workloads[] = {#define workloads__for_each (workload) \ for (unsigned i = 0; i < ARRAY_SIZE(workloads) && ({ workload = workloads[i]; 1; }); i++) -static int num_subtests (const struct test_suite *t) +#define test_suite__for_each_test_case (suite, idx) \ + for (idx = 0; (suite)->test_cases && (suite)->test_cases[idx].name != NULL; idx++) + +static int test_suite__num_test_cases (const struct test_suite *t) {int num; -if (!t->test_cases) -return 0 ; - - num =0 ; -while (t->test_cases[num].name) - num++; +test_suite__for_each_test_case (t, num);return num; } -static bool has_subtests (const struct test_suite *t) -{ -return num_subtests (t) >1 ; -} - -static const char *skip_reason (const struct test_suite *t,int subtest) +static const char *skip_reason (const struct test_suite *t,int test_case) {if (!t->test_cases)return NULL ; -return t->test_cases[subtest >=0 ? subtest :0 ].skip_reason; +return t->test_cases[test_case >=0 ? test_case :0 ].skip_reason; } -static const char *test_description (const struct test_suite *t,int subtest) +static const char *test_description (const struct test_suite *t,int test_case) { -if (t->test_cases && subtest >=0 ) -return t->test_cases[subtest].desc; +if (t->test_cases && test_case >=0 ) +return t->test_cases[test_case].desc;return t->desc; } -static test_fnptr test_function (const struct test_suite *t,int subtest) +static test_fnptr test_function (const struct test_suite *t,int test_case) { -if (subtest <=0 ) +if (test_case <=0 )return t->test_cases[0 ].run_case; -return t->test_cases[subtest].run_case; +return t->test_cases[test_case].run_case; } -static bool test_exclusive (const struct test_suite *t,int subtest) +static bool test_exclusive (const struct test_suite *t,int test_case) { -if (subtest <=0 ) +if (test_case <=0 )return t->test_cases[0 ].exclusive; -return t->test_cases[subtest].exclusive; +return t->test_cases[test_case].exclusive; } -static bool perf_test__matches (const char *desc,int curr,int argc,const char *argv[]) +static bool perf_test__matches (const char *desc,int suite_num,int argc,const char *argv[]) {int i;
@@ -217,7 +210,7 @@ static bool perf_test__matches(const char *desc, int curr, int argc, const charlong nr =strtoul (argv[i], &end,10 );if (*end =='\0' ) { -if (nr == curr +1 ) +if (nr == suite_num +1 )return true;continue ; }
@@ -232,8 +225,8 @@ static bool perf_test__matches(const char *desc, int curr, int argc, const charstruct child_test {struct child_process process;struct test_suite *test; -int test_num; -int subtest; +int suite_num; +int test_case_num; };static jmp_buf run_test_jmp_buf;
@@ -263,7 +256,7 @@ static int run_test_child(struct child_process *process)pr_debug ("--- start ---\n" );pr_debug ("test child forked, pid %d\n" ,getpid ()); - err =test_function (child->test, child->subtest)(child->test, child->subtest); + err =test_function (child->test, child->test_case_num)(child->test, child->test_case_num);pr_debug ("---- end(%d) ----\n" , err); err_out:
@@ -275,15 +268,16 @@ static int run_test_child(struct child_process *process)#define TEST_RUNNING -3 -static int print_test_result (struct test_suite *t,int i,int subtest,int result,int width, -int running) +static int print_test_result (struct test_suite *t,int curr_suite,int curr_test_case, +int result,int width,int running) { -if (has_subtests (t)) { +if (test_suite__num_test_cases (t) >1 ) {int subw = width >2 ? width -2 : width; -pr_info ("%3d.%1d: %-*s:" , i +1 , subtest +1 , subw,test_description (t, subtest)); +pr_info ("%3d.%1d: %-*s:" , curr_suite +1 , curr_test_case +1 , subw, +test_description (t, curr_test_case)); }else -pr_info ("%3d: %-*s:" , i +1 , width,test_description (t, subtest)); +pr_info ("%3d: %-*s:" , curr_suite +1 , width,test_description (t, curr_test_case));switch (result) {case TEST_RUNNING :
@@ -293,7 +287,7 @@ static int print_test_result(struct test_suite *t, int i, int subtest, int resulpr_info (" Ok\n" );break ;case TEST_SKIP : { -const char *reason =skip_reason (t, subtest); +const char *reason =skip_reason (t, curr_test_case);if (reason)color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip (%s)\n" , reason);
@@ -315,7 +309,7 @@ static void finish_test(struct child_test **child_tests, int running_test, int c {struct child_test *child_test = child_tests[running_test];struct test_suite *t; -int i, subi, err; +int curr_suite, curr_test_case, err;bool err_done = false;struct strbuf err_output =STRBUF_INIT ;int last_running =-1 ;
@@ -326,15 +320,15 @@ static void finish_test(struct child_test **child_tests, int running_test, int creturn ; } t = child_test->test; - i = child_test->test_num; - subi = child_test->subtest; + curr_suite = child_test->suite_num; + curr_test_case = child_test->test_case_num; err = child_test->process.err;/* * For test suites with subtests, display the suite name ahead of the * sub test names. */ -if (has_subtests (t) && subi ==0 ) -pr_info ("%3d: %-*s:\n" , i +1 , width,test_description (t,-1 )); +if (test_suite__num_test_cases (t) >1 && curr_test_case ==0 ) +pr_info ("%3d: %-*s:\n" , curr_suite +1 , width,test_description (t,-1 ));/* * Busy loop reading from the child's stdout/stderr that are set to be
@@ -343,10 +337,11 @@ static void finish_test(struct child_test **child_tests, int running_test, int cif (err >0 )fcntl (err,F_SETFL ,O_NONBLOCK );if (verbose >1 ) { -if (has_subtests (t)) -pr_info ("%3d.%1d: %s:\n" , i +1 , subi +1 ,test_description (t, subi)); +if (test_suite__num_test_cases (t) >1 ) +pr_info ("%3d.%1d: %s:\n" , curr_suite +1 , curr_test_case +1 , +test_description (t, curr_test_case));else -pr_info ("%3d: %s:\n" , i +1 ,test_description (t,-1 )); +pr_info ("%3d: %s:\n" , curr_suite +1 ,test_description (t,-1 )); }while (!err_done) {struct pollfd pfds[1 ] = {
@@ -371,7 +366,8 @@ static void finish_test(struct child_test **child_tests, int running_test, int c*/ fprintf (debug_file (),PERF_COLOR_DELETE_LINE ); } -print_test_result (t, i, subi,TEST_RUNNING , width, running); +print_test_result (t, curr_suite, curr_test_case,TEST_RUNNING , + width, running); last_running = running; } }
@@ -409,14 +405,14 @@ static void finish_test(struct child_test **child_tests, int running_test, int cfprintf (stderr,"%s" , err_output.buf);strbuf_release (&err_output); -print_test_result (t, i, subi, ret, width,/*running=*/ 0 ); +print_test_result (t, curr_suite, curr_test_case, ret, width,/*running=*/ 0 );if (err >0 )close (err);zfree (&child_tests[running_test]); } -static int start_test (struct test_suite *test,int i,int subi,struct child_test **child, -int width,int pass) +static int start_test (struct test_suite *test,int curr_suite,int curr_test_case, +struct child_test **child,int width,int pass) {int err;
@@ -424,17 +420,18 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tesif (dont_fork) {if (pass ==1 ) {pr_debug ("--- start ---\n" ); - err =test_function (test, subi)(test, subi); + err =test_function (test, curr_test_case)(test, curr_test_case);pr_debug ("---- end ----\n" ); -print_test_result (test, i, subi, err, width,/*running=*/ 0 ); +print_test_result (test, curr_suite, curr_test_case, err, width, +/*running=*/ 0 ); }return 0 ; } -if (pass ==1 && !sequential &&test_exclusive (test, subi)) { +if (pass ==1 && !sequential &&test_exclusive (test, curr_test_case)) {/* When parallel, skip exclusive tests on the first pass. */ return 0 ; } -if (pass !=1 && (sequential || !test_exclusive (test, subi))) { +if (pass !=1 && (sequential || !test_exclusive (test, curr_test_case))) {/* Sequential and non-exclusive tests were run on the first pass. */ return 0 ; }
@@ -443,8 +440,8 @@ static int start_test(struct test_suite *test, int i, int subi, struct child_tesreturn -ENOMEM ; (*child)->test = test; - (*child)->test_num = i; - (*child)->subtest = subi; + (*child)->suite_num = curr_suite; + (*child)->test_case_num = curr_test_case; (*child)->process.pid =-1 ; (*child)->process.no_stdin =1 ;if (verbose <=0 ) {
@@ -484,19 +481,15 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],int err =0 ;for (struct test_suite **t = suites; *t; t++) { -int len =strlen (test_description (*t,-1 )); +int i, len =strlen (test_description (*t,-1 ));if (width < len) width = len; -if (has_subtests (*t)) { -for (int subi =0 , subn =num_subtests (*t); subi < subn; subi++) { - len =strlen (test_description (*t, subi)); -if (width < len) - width = len; - num_tests++; - } - }else { +test_suite__for_each_test_case (*t, i) { + len =strlen (test_description (*t, i)); +if (width < len) + width = len; num_tests++; } }
@@ -515,7 +508,7 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],continue ;pr_debug3 ("Killing %d pid %d\n" , - child_test->test_num +1 , + child_test->suite_num +1 , child_test->process.pid);kill (child_test->process.pid, err); }
@@ -531,47 +524,43 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],*/ for (int pass =1 ; pass <=2 ; pass++) {int child_test_num =0 ; -int i =0 ; +int curr_suite =0 ; -for (struct test_suite **t = suites; *t; t++) { -int curr = i++; +for (struct test_suite **t = suites; *t; t++, curr_suite++) { +int curr_test_case; -if (!perf_test__matches (test_description (*t,-1 ), curr, argc, argv)) { +if (!perf_test__matches (test_description (*t,-1 ), curr_suite, argc, argv)) {/* * Test suite shouldn't be run based on -* description. See if subtest should. +* description. See if any test case should. */ bool skip = true; -for (int subi =0 , subn =num_subtests (*t); subi < subn; subi++) { -if (perf_test__matches (test_description (*t, subi), - curr, argc, argv)) +test_suite__for_each_test_case (*t, curr_test_case) { +if (perf_test__matches (test_description (*t, curr_test_case), + curr_suite, argc, argv)) { skip = false; +break ; + } } -if (skip)continue ; } -if (intlist__find (skiplist, i)) { -pr_info ("%3d: %-*s:" , curr +1 , width,test_description (*t,-1 )); +if (intlist__find (skiplist, curr_suite +1 )) { +pr_info ("%3d: %-*s:" , curr_suite +1 , width, +test_description (*t,-1 ));color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip (user override)\n" );continue ; } -if (!has_subtests (*t)) { - err =start_test (*t, curr,-1 , &child_tests[child_test_num++], - width, pass); -if (err) - goto err_out; -continue ; - } -for (int subi =0 , subn =num_subtests (*t); subi < subn; subi++) { -if (!perf_test__matches (test_description (*t, subi), - curr, argc, argv)) +test_suite__for_each_test_case (*t, curr_test_case) { +if (!perf_test__matches (test_description (*t, curr_test_case), + curr_suite, argc, argv))continue ; - err =start_test (*t, curr, subi, &child_tests[child_test_num++], + err =start_test (*t, curr_suite, curr_test_case, + &child_tests[child_test_num++], width, pass);if (err) goto err_out;
@@ -597,23 +586,22 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],static int perf_test__list (struct test_suite **suites,int argc,const char **argv) { -int i =0 ; +int curr_suite =0 ; -for (struct test_suite **t = suites; *t; t++) { -int curr = i++; +for (struct test_suite **t = suites; *t; t++, curr_suite++) { +int curr_test_case; -if (!perf_test__matches (test_description (*t,-1 ), curr, argc, argv)) +if (!perf_test__matches (test_description (*t,-1 ), curr_suite, argc, argv))continue ; -pr_info ("%3d: %s\n" , i,test_description (*t,-1 )); +pr_info ("%3d: %s\n" , curr_suite +1 ,test_description (*t,-1 )); -if (has_subtests (*t)) { -int subn =num_subtests (*t); -int subi; +if (test_suite__num_test_cases (*t) <=1 ) +continue ; -for (subi =0 ; subi < subn; subi++) -pr_info ("%3d:%1d: %s\n" , i, subi +1 , -test_description (*t, subi)); +test_suite__for_each_test_case (*t, curr_test_case) { +pr_info ("%3d:%1d: %s\n" , curr_suite +1 , curr_test_case +1 , +test_description (*t, curr_test_case)); } }return 0 ;
@@ -659,27 +647,24 @@ static struct test_suite **build_suites(void)if (suites[2 ] ==NULL ) suites[2 ] =create_script_test_suites (); -#define for_each_test (t) \ +#define for_each_suite (suite) \ for (size_t i = 0, j = 0; i < ARRAY_SIZE(suites); i++, j = 0) \ - while ((t = suites[i][j++]) != NULL) + while ((suite = suites[i][j++]) != NULL) -for_each_test (t) +for_each_suite (t) num_suites++; result =calloc (num_suites +1 ,sizeof (struct test_suite *));for (int pass =1 ; pass <=2 ; pass++) { -for_each_test (t) { +for_each_suite (t) {bool exclusive = false; +int curr_test_case; -if (!has_subtests (t)) { - exclusive =test_exclusive (t,-1 ); - }else { -for (int subi =0 , subn =num_subtests (t); subi < subn; subi++) { -if (test_exclusive (t, subi)) { - exclusive = true; -break ; - } +test_suite__for_each_test_case (t, curr_test_case) { +if (test_exclusive (t, curr_test_case)) { + exclusive = true; +break ; } }if ((!exclusive && pass ==1 ) || (exclusive && pass ==2 ))
@@ -687,7 +672,7 @@ static struct test_suite **build_suites(void) } }return result; -#undef for_each_test +#undef for_each_suite }int cmd_test (int argc,const char **argv)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1015/1376 perf test: Send list output to stdout rather than stderr
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 2b7b78efc8c91430fd81a07d8fb4e0a89456aff8 ]
Follow the workload listing in using stdout rather than stderr. Correct the numbering of sub-tests to be 1.1 rather than 1:1.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/tests/builtin-test.c +4 -4
@@ -584,7 +584,7 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],return err; } -static int perf_test__list (struct test_suite **suites,int argc,const char **argv) +static int perf_test__list (FILE *fp,struct test_suite **suites,int argc,const char **argv) {int curr_suite =0 ;
@@ -594,13 +594,13 @@ static int perf_test__list(struct test_suite **suites, int argc, const char **arif (!perf_test__matches (test_description (*t,-1 ), curr_suite, argc, argv))continue ; -pr_info ("%3d: %s\n" , curr_suite +1 ,test_description (*t,-1 )); +fprintf (fp,"%3d: %s\n" , curr_suite +1 ,test_description (*t,-1 ));if (test_suite__num_test_cases (*t) <=1 )continue ;test_suite__for_each_test_case (*t, curr_test_case) { -pr_info ("%3d:%1d: %s\n" , curr_suite +1 , curr_test_case +1 , +fprintf (fp,"%3d.%1d: %s\n" , curr_suite +1 , curr_test_case +1 ,test_description (*t, curr_test_case)); } }
@@ -714,7 +714,7 @@ int cmd_test(int argc, const char **argv) argc =parse_options_subcommand (argc, argv, test_options, test_subcommands, test_usage,0 );if (argc >=1 && !strcmp (argv[0 ],"list" )) { suites =build_suites (); - ret =perf_test__list (suites, argc -1 , argv +1 ); + ret =perf_test__list (stdout, suites, argc -1 , argv +1 );free (suites);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1016/1376 perf test: Support dynamic test suites with setup callback and private data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 8c8d61c38d8e1755a4325f8acb396137bbd5371a ]
Add void *priv to struct test_case to allow passing per-test context. Add int (*setup)(struct test_suite *) to struct test_suite to allow dynamic generation of test cases. Update build_suites() to invoke the setup callback for each suite if present, ensuring dynamic cases are available before listing or running.
Stable-dep-of: 44e82c4d2ff3 ("perf test: Fix skiplist leak in cmd_test")
--- tools/perf/tests/builtin-test.c | 17 ++++++++++++++++- tools/perf/tests/tests.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-)
tools/perf/tests/builtin-test.c +16 -1
@@ -651,10 +651,21 @@ static struct test_suite **build_suites(void)for (size_t i =0 , j =0 ; i <ARRAY_SIZE (suites); i++, j =0 ) \while ((suite = suites[i][j++]) !=NULL ) -for_each_suite (t) +for_each_suite (t) { +if (t->setup) { +int ret = t->setup (t); + +if (ret <0 ) { + errno = -ret; +return NULL ; + } + } num_suites++; + } result =calloc (num_suites +1 ,sizeof (struct test_suite *)); +if (!result) +return NULL ;for (int pass =1 ; pass <=2 ; pass++) {for_each_suite (t) {
@@ -714,6 +725,8 @@ int cmd_test(int argc, const char **argv) argc =parse_options_subcommand (argc, argv, test_options, test_subcommands, test_usage,0 );if (argc >=1 && !strcmp (argv[0 ],"list" )) { suites =build_suites (); +if (!suites) +return errno ? -errno : -ENOMEM ; ret =perf_test__list (stdout, suites, argc -1 , argv +1 );free (suites);return ret;
@@ -743,6 +756,8 @@ int cmd_test(int argc, const char **argv)rlimit__bump_memlock (); suites =build_suites (); +if (!suites) +return errno ? -errno : -ENOMEM ; ret =__cmd_test (suites, argc, argv, skiplist);free (suites);return ret;
tools/perf/tests/tests.h +2 -0
@@ -37,12 +37,14 @@ struct test_case {const char *skip_reason;test_fnptr run_case;bool exclusive; +void *priv; };struct test_suite {const char *desc;struct test_case *test_cases;void *priv; +int (*setup)(struct test_suite *suite); };#define DECLARE_SUITE (name) \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1017/1376 perf test: Fix skiplist leak in cmd_test
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 44e82c4d2ff37f073946b594840fd549ab6b9fb8 ]
Fix a memory leak in cmd_test() where skiplist was not freed on exit paths.
--- tools/perf/tests/builtin-test.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/tests/builtin-test.c +7 -2
@@ -756,9 +756,14 @@ int cmd_test(int argc, const char **argv)rlimit__bump_memlock (); suites =build_suites (); -if (!suites) -return errno ? -errno : -ENOMEM ; +if (!suites) { +int err = errno; + +intlist__delete (skiplist); +return err ? -err : -ENOMEM ; + } ret =__cmd_test (suites, argc, argv, skiplist);free (suites); +intlist__delete (skiplist);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1018/1376 perf python: Remove python 2 scripting support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit e7e9943c87d857da650f228fdf6cb47b785b3ff9 ]
Python2 was deprecated 4 years ago, remove support and workarounds.
Stable-dep-of: 612aca22a978 ("perf python: Check counts_values size in set_values")
--- .../scripts/python/Perf-Trace-Util/Context.c | 18 ----- tools/perf/util/python.c | 73 +++---------------- .../scripting-engines/trace-event-python.c | 63 +--------------- 3 files changed, 15 insertions(+), 139 deletions(-)
tools/perf/scripts/python/Perf-Trace-Util/Context.c +0 -18
@@ -23,16 +23,6 @@#include "../../../util/srcline.h" #include "../../../util/srccode.h" -#if PY_MAJOR_VERSION <3 -#define _PyCapsule_GetPointer (arg1, arg2) \ - PyCObject_AsVoidPtr(arg1) -#define _PyBytes_FromStringAndSize (arg1, arg2) \ - PyString_FromStringAndSize((arg1), (arg2)) -#define _PyUnicode_AsUTF8 (arg) \ - PyString_AsString(arg) - -PyMODINIT_FUNC initperf_trace_context (void ); -#else #define _PyCapsule_GetPointer (arg1, arg2) \ PyCapsule_GetPointer((arg1), (arg2))#define _PyBytes_FromStringAndSize (arg1, arg2) \
@@ -41,7 +31,6 @@ PyMODINIT_FUNC initperf_trace_context(void);PyUnicode_AsUTF8 (arg) PyMODINIT_FUNC PyInit_perf_trace_context(void); -#endif static struct scripting_context *get_args (PyObject *args,const char *name,PyObject **arg2) {
@@ -202,12 +191,6 @@ static PyMethodDef ContextMethods[] = { { NULL, NULL, 0, NULL} }; -#if PY_MAJOR_VERSION < 3 -PyMODINIT_FUNC initperf_trace_context(void) -{ - (void) Py_InitModule("perf_trace_context", ContextMethods); -} -#elsePyMODINIT_FUNC PyInit_perf_trace_context (void ) {static struct PyModuleDef moduledef = {
@@ -229,4 +212,3 @@ PyMODINIT_FUNC PyInit_perf_trace_context(void)return mod; } -#endif
tools/perf/util/python.c +12 -61
193 lines not on this page · raw message
tools/perf/util/scripting-engines/trace-event-python.c +3 -60
113 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1019/1376 perf python: Add support for struct perf_counts_values to return counter data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gautam Menghani <[email protected]>
[ Upstream commit 3b4991dcb49e1d99129ead644858cf7f77b8fb6b ]
Add support for the perf_counts_values struct to enable the python bindings to read and return the counter data.
Committer notes:
Use T_ULONG instead of Py_T_ULONG, as all the other PyMemberDef arrays, fixing the build with older python3 versions.
Use { .name = NULL, } to finish the new PyMemberDef pyrf_counts_values_members array, again as the other arrays to please some clang versions, ditto for PyGetSetDef.
Stable-dep-of: 612aca22a978 ("perf python: Check counts_values size in set_values")
--- tools/perf/util/python.c | 92 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-)
tools/perf/util/python.c +91 -1
@@ -636,6 +636,92 @@ static int pyrf_thread_map__setup_types(void)return PyType_Ready (&pyrf_thread_map__type); } +struct pyrf_counts_values { +PyObject_HEAD + + struct perf_counts_values values; +}; + +static const char pyrf_counts_values__doc[] =PyDoc_STR ("perf counts values object." ); + +static void pyrf_counts_values__delete (struct pyrf_counts_values *pcounts_values) +{ +Py_TYPE (pcounts_values)->tp_free ((PyObject *)pcounts_values); +} + +#define counts_values_member_def (member, ptype, help) \ + { #member, ptype, \ + offsetof(struct pyrf_counts_values, values.member), \ + 0, help } + +static PyMemberDef pyrf_counts_values_members[] = { +counts_values_member_def (val,T_ULONG ,"Value of event" ), +counts_values_member_def (ena,T_ULONG ,"Time for which enabled" ), +counts_values_member_def (run,T_ULONG ,"Time for which running" ), +counts_values_member_def (id,T_ULONG ,"Unique ID for an event" ), +counts_values_member_def (lost,T_ULONG ,"Num of lost samples" ), + { .name =NULL , }, +}; + +static PyObject *pyrf_counts_values_get_values (struct pyrf_counts_values *self,void *closure) +{ +PyObject *vals =PyList_New (5 ); + +if (!vals) +return NULL ; +for (int i =0 ; i <5 ; i++) +PyList_SetItem (vals, i,PyLong_FromLong (self->values.values[i])); + +return vals; +} + +static int pyrf_counts_values_set_values (struct pyrf_counts_values *self,PyObject *list, +void *closure) +{ +Py_ssize_t size; +PyObject *item =NULL ; + +if (!PyList_Check (list)) { +PyErr_SetString (PyExc_TypeError,"Value assigned must be a list" ); +return -1 ; + } + + size =PyList_Size (list); +for (Py_ssize_t i =0 ; i < size; i++) { + item =PyList_GetItem (list, i); +if (!PyLong_Check (item)) { +PyErr_SetString (PyExc_TypeError,"List members should be numbers" ); +return -1 ; + } + self->values.values[i] =PyLong_AsLong (item); + } + +return 0 ; +} + +static PyGetSetDef pyrf_counts_values_getset[] = { + {"values" , (getter )pyrf_counts_values_get_values, (setter )pyrf_counts_values_set_values, +"Name field" ,NULL }, + { .name =NULL , }, +}; + +static PyTypeObject pyrf_counts_values__type = { +PyVarObject_HEAD_INIT (NULL ,0 ) + .tp_name ="perf.counts_values" , + .tp_basicsize =sizeof (struct pyrf_counts_values ), + .tp_dealloc = (destructor )pyrf_counts_values__delete, + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_counts_values__doc, + .tp_members = pyrf_counts_values_members, + .tp_getset = pyrf_counts_values_getset, +}; + +static int pyrf_counts_values__setup_types (void ) +{ + pyrf_counts_values__type.tp_new = PyType_GenericNew; +return PyType_Ready (&pyrf_counts_values__type); +} +struct pyrf_evsel {PyObject_HEAD
@@ -1245,7 +1331,8 @@ PyMODINIT_FUNC PyInit_perf(void)pyrf_evlist__setup_types () <0 ||pyrf_evsel__setup_types () <0 ||pyrf_thread_map__setup_types () <0 || - pyrf_cpu_map__setup_types() < 0) +pyrf_cpu_map__setup_types () <0 || + pyrf_counts_values__setup_types() < 0) return module;/* The page_size is placed in util object. */
@@ -1290,6 +1377,9 @@ PyMODINIT_FUNC PyInit_perf(void)Py_INCREF (&pyrf_cpu_map__type);PyModule_AddObject (module,"cpu_map" , (PyObject *)&pyrf_cpu_map__type); +Py_INCREF (&pyrf_counts_values__type); +PyModule_AddObject (module,"counts_values" , (PyObject *)&pyrf_counts_values__type); + dict =PyModule_GetDict (module);if (dict ==NULL ) goto error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1020/1376 perf python: Check counts_values size in set_values
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 612aca22a978d43f6e6765272676a17afdba8572 ]
The set_values function incorrectly assumed the list contained exactly 5 elements. Add a check to prevent out-of-bounds access.
--- tools/perf/util/python.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-)
tools/perf/util/python.c +30 -8
@@ -655,11 +655,11 @@ static void pyrf_counts_values__delete(struct pyrf_counts_values *pcounts_values 0, help }static PyMemberDef pyrf_counts_values_members[] = { -counts_values_member_def (val,T_ULONG ,"Value of event" ), -counts_values_member_def (ena,T_ULONG ,"Time for which enabled" ), -counts_values_member_def (run,T_ULONG ,"Time for which running" ), -counts_values_member_def (id,T_ULONG ,"Unique ID for an event" ), -counts_values_member_def (lost,T_ULONG ,"Num of lost samples" ), +counts_values_member_def (val,T_ULONGLONG ,"Value of event" ), +counts_values_member_def (ena,T_ULONGLONG ,"Time for which enabled" ), +counts_values_member_def (run,T_ULONGLONG ,"Time for which running" ), +counts_values_member_def (id,T_ULONGLONG ,"Unique ID for an event" ), +counts_values_member_def (lost,T_ULONGLONG ,"Num of lost samples" ), { .name =NULL , }, };
@@ -669,8 +669,15 @@ static PyObject *pyrf_counts_values_get_values(struct pyrf_counts_values *self,if (!vals)return NULL ; -for (int i =0 ; i <5 ; i++) -PyList_SetItem (vals, i,PyLong_FromLong (self->values.values[i])); +for (int i =0 ; i <5 ; i++) { +PyObject *val =PyLong_FromUnsignedLongLong (self->values.values[i]); + +if (!val) { +Py_DECREF (vals); +return NULL ; + } +PyList_SetItem (vals, i, val); + }return vals; }
@@ -681,19 +688,34 @@ static int pyrf_counts_values_set_values(struct pyrf_counts_values *self, PyObjePy_ssize_t size;PyObject *item =NULL ; +if (list ==NULL ) { +PyErr_SetString (PyExc_TypeError,"cannot delete attribute" ); +return -1 ; + } +if (!PyList_Check (list)) {PyErr_SetString (PyExc_TypeError,"Value assigned must be a list" );return -1 ; } size =PyList_Size (list); +if (size !=5 ) { +PyErr_SetString (PyExc_ValueError,"List must have exactly 5 entries" ); +return -1 ; + } +for (Py_ssize_t i =0 ; i < size; i++) { +unsigned long long val; + item =PyList_GetItem (list, i);if (!PyLong_Check (item)) {PyErr_SetString (PyExc_TypeError,"List members should be numbers" );return -1 ; } - self->values.values[i] =PyLong_AsLong (item); + val =PyLong_AsUnsignedLongLong (item); +if (val == (unsigned long long )-1 &&PyErr_Occurred ()) +return -1 ; + self->values.values[i] = val; }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1021/1376 perf synthetic-events: Fix divide by zero in perf_event__synthesize_threads
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 16a12a54e9a1151a37aab74914a51b86f7f58d0e ]
If scandir() finds no matching tasks in /proc, n is 0. If thread_nr is > 1, we bypass the single-thread fast path and then clamp thread_nr to n, making it 0. This results in a divide by zero when calculating num_per_thread.
Handle n <= 1 early to use the single-thread fast path and prevent the crash.
--- tools/perf/util/synthetic-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/synthetic-events.c +1 -1
@@ -1045,7 +1045,7 @@ int perf_event__synthesize_threads(const struct perf_tool *tool,else thread_nr = nr_threads_synthesize; -if (thread_nr <=1 ) { +if (thread_nr <=1 || n <=1 ) { err = __perf_event__synthesize_threads(tool, process, machine, needs_mmap, mmap_data,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1022/1376 fbdev: tdfxfb: fix PCI enable cleanup with pcim_enable_device()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit 95a627143a696f70e17be5ed3b1e733bb6724b46 ]
tdfxfb_probe() enables the PCI device with pci_enable_device(), but several failure paths after that point return without disabling it. The framebuffer_alloc() failure path returns -ENOMEM directly, and the later shared out_err path releases the framebuffer and returns -ENXIO without balancing the PCI enable state.
The successful probe path has the same imbalance because tdfxfb_remove() releases the framebuffer, mappings and regions, but never calls pci_disable_device().
Use pcim_enable_device() so the PCI device is disabled automatically on probe failure and driver detach.
This issue was identified during our ongoing static-analysis research while reviewing kernel code.
--- drivers/video/fbdev/tdfxfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/video/fbdev/tdfxfb.c +1 -1
@@ -1383,7 +1383,7 @@ static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)if (err)return err; - err =pci_enable_device (pdev); + err =pcim_enable_device (pdev);if (err) {printk (KERN_ERR "tdfxfb: Can't enable pdev: %d\n" , err);return err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1023/1376 fbdev: kyro: Validate overlay viewport coordinates
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Danila Chernetsov <[email protected]>
[ Upstream commit 7b5c7bc55e13e7f5ac7b1eaf5c6d690389ea5ee3 ]
The overlay viewport end coordinates are computed from the viewport origin and dimensions using 32-bit unsigned arithmetic. Large input values can cause these calculations to wrap around before the resulting coordinates are passed to SetOverlayViewPort().
SetOverlayViewPort() packs the viewport coordinates into 16-bit register fields. The X coordinates are additionally adjusted by +2 and +1 before being written. Validate the coordinate calculations for 32-bit wraparound and ensure that the adjusted coordinates fit within their 16-bit register fields before calling SetOverlayViewPort().
Found by Linux Verification Center (linuxtesting.org) with SVACE.
--- drivers/video/fbdev/kyro/fbdev.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
drivers/video/fbdev/kyro/fbdev.c +23 -1
@@ -369,6 +369,9 @@ static int kyro_dev_overlay_create(u32 ulWidth,static int kyro_dev_overlay_viewport_set (u32 x,u32 y,u32 ulWidth,u32 ulHeight) { +u32 right; +u32 bottom; +if (deviceInfo.ulOverlayOffset ==0 )/* probably haven't called CreateOverlay yet */ return -EINVAL ;
@@ -378,11 +381,30 @@ static int kyro_dev_overlay_viewport_set(u32 x, u32 y, u32 ulWidth, u32 ulHeight (x < 2 && ulWidth + 2 == 0))return -EINVAL ; +/* +* SetOverlayViewPort() adjusts X coordinates by +2 (left) and +1 +* (right) before packing them into 16-bit register fields. +*/ +if (x >U16_MAX -2 || y >U16_MAX ) +return -EINVAL ; + + right = x + ulWidth; + bottom = y + ulHeight; + +if (right < x || bottom < y) +return -EINVAL ; + + right--; + bottom--; + +if (right >U16_MAX -1 || bottom >U16_MAX ) +return -EINVAL ; +/* Stop Ramdac Output */ DisableRamdacOutput (deviceInfo.pSTGReg);SetOverlayViewPort (deviceInfo.pSTGReg, - x, y, x + ulWidth -1 , y + ulHeight -1 ); + x, y, right, bottom);EnableOverlayPlane (deviceInfo.pSTGReg);/* Start Ramdac Output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1024/1376 iommu/vt-d: Fix UCTP context table slot when copying root entries
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Desnes Nunes <[email protected]>
[ Upstream commit c6e63fc8e8fcefa5c32145dc0a3c82975b0ce152 ]
When translation is already enabled at boot (e.g. kdump), the vt-d driver copies context tables from the previous kernel's root table. In scalable mode, buses that only populate the upper root half (UCTP, devfn >= 0x80) should be written to ctxt_tbls[tbl_idx + 1] through copy_context_table(). However, the current copy path always uses tbl[tbl_idx + 0] in this situa- tion. Since idx wraps to 0 at devfn 0x80 due to a zeroed LCTP, new_ce for LCTP will be NULL and keep pos equals to 0. Thus, UCTP entries will be co- pied into tbl[tbl_idx + 0] instead of tbl[tbl_idx + 1], and written after- wards to root_entry[bus].lo instead of .hi in copy_translation_tables().
In short, devices on bus 0x80 with devfn >= 0x80 fail DMA with fault 0x39, which will break drivers running in kernels with translation pre-enabled. This fixes NO_PASID DMAR faults for UCTP-only buses such as:
DMAR: [DMA Read NO_PASID] Request device [80:14.0] fault addr 0xe81759000
[fault reason 0x39] SM: Present bit in Root Entry is clear
For instance, this fault yielded to locking issues between systemd and xHCI, blocking a system's reboot after a vmcore was captured with kdump:
systemd-udevd[246]: usb3: Worker [255] processing SEQNUM=2193 is taking a long time dracut-initqueue[277]: Timed out while waiting for udev queue to empty. systemd-udevd[246]: usb3: Worker [255] processing SEQNUM=2193 killed systemd-udevd[246]: usb3: Worker [255] terminated by signal 9 (KILL).
...
kdump[569]: saving vmcore complete
...
systemd-shutdown[1]: Rebooting.
INFO: task kworker/0:1:11 blocked for more than 122 seconds.
Not tainted 7.0.0-clean #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208160 flags:0x00080000
Workqueue: usb_hub_wq hub_event
Call Trace:
<TASK>
__schedule+0x299/0x5c0
schedule+0x27/0x80
schedule_timeout+0xbd/0x100
__wait_for_common+0x97/0x1b0
? __pfx_schedule_timeout+0x10/0x10
xhci_alloc_dev+0x9e/0x2b0
usb_alloc_dev+0x7a/0x3b0
hub_port_connect+0x285/0x960
hub_port_connect_change+0x94/0x290
port_event+0x4bb/0x840
hub_event+0x141/0x460
process_one_work+0x196/0x390
worker_thread+0x1af/0x320
? __pfx_worker_thread+0x10/0x10
kthread+0xe3/0x120
? __pfx_kthread+0x10/0x10
ret_from_fork+0x199/0x260
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1a/0x30
</TASK>
INFO: task systemd-shutdow:1 blocked for more than 122 seconds.
Not tainted 7.0.0-clean #1
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
task:systemd-shutdow state:D stack:0 pid:1 tgid:1 ppid:0 task_flags:0x400100 flags:0x00080000
Call Trace:
<TASK>
__schedule+0x299/0x5c0
schedule+0x27/0x80
schedule_preempt_disabled+0x15/0x30
__mutex_lock.constprop.0+0x547/0xac0
device_shutdown+0xac/0x1b0
kernel_restart+0x3a/0x70
__do_sys_reboot+0x147/0x240
do_syscall_64+0x11b/0x6a0
? handle_mm_fault+0x110/0x350
? do_user_addr_fault+0x206/0x680
? irqentry_exit+0x7a/0x4d0
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7fe2958da917
RSP: 002b:00007ffc5c458618 EFLAGS: 00000206 ORIG_RAX: 00000000000000a9
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fe2958da917
RDX: 0000000001234567 RSI: 0000000028121969 RDI: 00000000fee1dead
RBP: 00007ffc5c458790 R08: 0000000000000069 R09: 00000000ffffffff
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 0000000000000000 R14: 00007ffc5c4588b8 R15: 0000000000000000
</TASK>
INFO: task systemd-shutdow:1 is blocked on a mutex likely owned by task kworker/0:1:11.--- drivers/iommu/intel/iommu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/iommu/intel/iommu.c +6 -4
@@ -2111,7 +2111,7 @@ static int copy_context_table(struct intel_iommu *iommu,struct context_entry **tbl, int bus, bool ext) { - int tbl_idx, pos = 0, idx, devfn, ret = 0, did; + int tbl_idx, tbl_slot = 0, idx, devfn, ret = 0, did;struct context_entry *new_ce =NULL , ce;struct context_entry *old_ce =NULL ;struct root_entry re;
@@ -2127,10 +2127,9 @@ static int copy_context_table(struct intel_iommu *iommu,if (idx ==0 ) {/* First save what we may have and clean up */ if (new_ce) { - tbl[tbl_idx] = new_ce; + tbl[tbl_idx + tbl_slot] = new_ce;__iommu_flush_cache (iommu, new_ce,VTD_PAGE_SIZE ); - pos =1 ; }if (old_ce)
@@ -2152,6 +2151,9 @@ static int copy_context_table(struct intel_iommu *iommu, } } +/* Track if saving UCTP or LCTP entries in scalable mode */ + tbl_slot = ext && devfn >=0x80 ?1 :0 ; + ret = -ENOMEM ; old_ce =memremap (old_ce_phys,PAGE_SIZE ,MEMREMAP_WB );
@@ -2179,7 +2181,7 @@ static int copy_context_table(struct intel_iommu *iommu, new_ce[idx] = ce; } - tbl[tbl_idx + pos] = new_ce; + tbl[tbl_idx + tbl_slot] = new_ce;__iommu_flush_cache (iommu, new_ce,VTD_PAGE_SIZE );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1025/1376 iommu/vt-d: Clear Present bit before tearing down copied context entry
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
[ Upstream commit f532c57985b1a7d6b7e37e05506b46d413e5cca4 ]
copied_context_tear_down() zeroes the 128-bit context entry with context_clear_entry() while the Present bit is still set, and only then issues the context-cache and IOTLB invalidations. This leaves a window in which hardware can fetch a torn entry, with some fields already zeroed while Present is still set, leading to unpredictable behaviour or spurious faults. While x86 provides strong write ordering, the compiler may reorder the writes to the two 64-bit halves of the entry, and the hardware fetch is not guaranteed to be atomic with respect to multiple CPU writes.
There is no cacheline flush before the invalidation either, so on an IOMMU without coherent access to the context table the zeroed entry may not be visible to hardware at the point the invalidation is submitted.
Apply the same ownership handshake described in the VT-d spec, Section 6.5.3.3 ("Guidance to Software for Invalidations"): clear only the Present bit, flush it out to the IOMMU, perform the invalidations, and only then zero the remainder of the entry.
--- drivers/iommu/intel/iommu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/iommu/intel/iommu.c +5 -1
@@ -1607,7 +1607,8 @@ static void copied_context_tear_down(strassert_spin_locked (&iommu->lock); did_old =context_domain_id (context); -context_clear_entry (context); +context_clear_present (context); +__iommu_flush_cache (iommu, context,sizeof (*context));if (did_old <cap_ndoms (iommu->cap)) { iommu->flush.flush_context(iommu, did_old,
@@ -1618,6 +1619,9 @@ static void copied_context_tear_down(str DMA_TLB_DSI_FLUSH); } +context_clear_entry (context); +__iommu_flush_cache (iommu, context,sizeof (*context)); +clear_context_copied (iommu, bus, devfn); }
Greg Kroah-Hartman
maintainerPATCH 1026/1376 iommu/vt-d: Tear down scalable-mode context on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
[ Upstream commit c509fb73a1093a15accd7d43a61645d4b520f6ac ]
intel_pasid_setup_sm_context() walks a PCI device’s DMA aliases via pci_for_each_dma_alias() and programs a scalable-mode context entry for each RID. For a device with a dma_alias_mask, the callback is invoked once for the device’s own RID and once for each alias bit, all with the same pci_dev, so device_pasid_table_setup() runs for multiple RIDs.
pci_for_each_dma_alias() stops at the first callback error. Therefore, a failure partway through the walk can leave context entries for already processed RIDs present and still pointing to the device’s PASID table.
On this error path, intel_iommu_probe_device() currently jumps directly to intel_pasid_free_table(), which frees the PASID table without first tearing down those context entries. The IOMMU may then walk a present context entry whose PASID table pointer references freed memory.
intel_iommu_release_device() already performs teardown before freeing the table. Apply the same ordering on the probe failure path.
device_pasid_table_teardown() safely handles RIDs that were never
programmed: iommu_context_addr() returns NULL when no context table has been allocated, and clearing the Present bit of an already non-present entry is a no-op. So unwind is safe for both the alias that failed and any aliases not yet reached.
--- drivers/iommu/intel/iommu.c | 1 + 1 file changed, 1 insertion(+)
drivers/iommu/intel/iommu.c +1 -0
@@ -3997,6 +3997,7 @@ static struct iommu_device *intel_iommu_return &iommu->iommu; free_table: +intel_pasid_teardown_sm_context (dev);intel_pasid_free_table (dev); clear_rbtree:device_rbtree_remove (info);
Greg Kroah-Hartman
maintainerPATCH 1027/1376 m68k: Fix backtraces for non-running tasks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 09f71dbeb287e367beea56d9ac8a3d356ef5e02a ]
When no stack pointer is supplied, show_stack() starts at thread.esp0. This is the saved userspace register frame, not where a task was switched out. For kernel threads it points to the zeroed frame created by copy_thread(), so sched_show_task() prints no useful backtrace.
Use thread.ksp for non-current tasks. It is saved by switch_to() and is already used by __get_wchan(). For current, start at the current stack frame, as is already done when no task is supplied.
Tested on qemu-system-m68k -M virt using SysRq-t. All task dumps contained resolved frames.
--- arch/m68k/kernel/traps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/m68k/kernel/traps.c +2 -2
@@ -936,8 +936,8 @@ void show_stack(struct task_struct *task, unsigned long *stack,int i;if (!stack) { -if (task) - stack = (unsigned long *)task->thread.esp0; +if (task && task != current) + stack = (unsigned long *)task->thread.ksp;else stack = (unsigned long *)&stack; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1028/1376 xdrgen: Rename "enum yada" types as just "yada"
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 6e853dcd2d3d6f796597c1042340a2de0ce2469f ]
This simplifies the generated C code and makes way for supporting big-endian XDR enums.
Stable-dep-of: d4ca0b0a6c62 ("xdrgen: Do not declare union XDR functions in the definitions header")
--- tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 | 4 ++-- tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 | 2 +- tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 | 1 + tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 | 2 +- tools/net/sunrpc/xdrgen/xdr_ast.py | 4 ---- 5 files changed, 5 insertions(+), 8 deletions(-)
tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 +2 -2
@@ -1,4 +1,4 @@ {# SPDX-License-Identifier: GPL-2.0 #} -bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} *ptr); -bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} value); +bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr); +bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value);
tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum.j2 +1 -1
@@ -8,7 +8,7 @@ bool {% else %} static bool __maybe_unused {% endif %} -xdrgen_decode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} *ptr) +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) { u32 val;
tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 +1 -0
@@ -1,2 +1,3 @@ {# SPDX-License-Identifier: GPL-2.0 #} }; +typedef enum {{ name }} {{ name }};
tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum.j2 +1 -1
@@ -8,7 +8,7 @@ bool {% else %} static bool __maybe_unused {% endif %} -xdrgen_encode_{{ name }}(struct xdr_stream *xdr, enum {{ name }} value) +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value) { return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; }
tools/net/sunrpc/xdrgen/xdr_ast.py +0 -4
@@ -15,7 +15,6 @@ this_module = sys.modules[__name__] excluded_apis = [] header_name = "none" public_apis = [] -enums = set() structs = set() pass_by_reference = set()
@@ -294,8 +293,6 @@ class ParseToAst(Transformer): c_classifier = "" if isinstance(children[0], _XdrIdentifier): name = children[0].symbol - if name in enums: - c_classifier = "enum " if name in structs: c_classifier = "struct " return _XdrDefinedType(
@@ -320,7 +317,6 @@ class ParseToAst(Transformer): def enum(self, children): """Instantiate one _XdrEnum object""" enum_name = children[0].symbol - enums.add(enum_name) i = 0 enumerators = []
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1029/1376 xdrgen: Implement big-endian enums
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit b376d519bd142c65ba9bba35db12b6be95b46893 ]
Stable-dep-of: d4ca0b0a6c62 ("xdrgen: Do not declare union XDR functions in the definitions header")
--- include/linux/sunrpc/xdr.h | 21 ++++++++++++ tools/net/sunrpc/xdrgen/README | 17 ++++++++++ tools/net/sunrpc/xdrgen/generators/enum.py | 17 +++++++--- tools/net/sunrpc/xdrgen/generators/union.py | 34 ++++++++++++++----- tools/net/sunrpc/xdrgen/grammars/xdr.lark | 4 ++- .../templates/C/enum/decoder/enum_be.j2 | 14 ++++++++ .../templates/C/enum/definition/close_be.j2 | 3 ++ .../templates/C/enum/encoder/enum_be.j2 | 14 ++++++++ .../templates/C/union/decoder/case_spec_be.j2 | 2 ++ .../templates/C/union/encoder/case_spec_be.j2 | 2 ++ tools/net/sunrpc/xdrgen/xdr_ast.py | 3 ++ 11 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 create mode 100644 tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 create mode 100644 tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 create mode 100644 tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 create mode 100644 tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2
include/linux/sunrpc/xdr.h +21 -0
@@ -695,6 +695,27 @@ xdr_stream_decode_u32(struct xdr_stream *xdr, __u32 *ptr)return 0 ; } +/** +* xdr_stream_decode_be32 - Decode a big-endian 32-bit integer +* @xdr: pointer to xdr_stream +* @ptr: location to store integer +* +* Return values: +* %0 on success +* %-EBADMSG on XDR buffer overflow +*/ +static inline ssize_t +xdr_stream_decode_be32 (struct xdr_stream *xdr,__be32 *ptr) +{ +const size_t count =sizeof (*ptr); +__be32 *p =xdr_inline_decode (xdr, count); + +if (unlikely (!p)) +return -EBADMSG ; + *ptr = *p; +return 0 ; +} +/** * xdr_stream_decode_u64 - Decode a 64-bit integer * @xdr: pointer to xdr_stream
tools/net/sunrpc/xdrgen/README +17 -0
@@ -150,6 +150,23 @@ Pragma directives specify exceptions to the normal generation of encoding and decoding functions. Currently one directive is implemented: "public". +Pragma big_endian +------ ---------- + + pragma big_endian <enum> ; + +For variables that might contain only a small number values, it +is more efficient to avoid the byte-swap when encoding or decoding +on little-endian machines. Such is often the case with error status +codes. For example: + + pragma big_endian nfsstat3; + +In this case, when generating an XDR struct or union containing a +field of type "nfsstat3", xdrgen will make the type of that field +"__be32" instead of "enum nfsstat3". XDR unions then switch on the +non-byte-swapped value of that field. + Pragma exclude ------ -------
tools/net/sunrpc/xdrgen/generators/enum.py +13 -4
@@ -4,7 +4,7 @@ """Generate code to handle XDR enum types""" from generators import SourceGenerator, create_jinja2_environment -from xdr_ast import _XdrEnum, public_apis +from xdr_ast import _XdrEnum, public_apis, big_endian class XdrEnumGenerator(SourceGenerator):
@@ -30,15 +30,24 @@ class XdrEnumGenerator(SourceGenerator): for enumerator in node.enumerators: print(template.render(name=enumerator.name, value=enumerator.value)) - template = self.environment.get_template("definition/close.j2") + if node.name in big_endian: + template = self.environment.get_template("definition/close_be.j2") + else: + template = self.environment.get_template("definition/close.j2") print(template.render(name=node.name)) def emit_decoder(self, node: _XdrEnum) -> None: """Emit one decoder function for an XDR enum type""" - template = self.environment.get_template("decoder/enum.j2") + if node.name in big_endian: + template = self.environment.get_template("decoder/enum_be.j2") + else: + template = self.environment.get_template("decoder/enum.j2") print(template.render(name=node.name)) def emit_encoder(self, node: _XdrEnum) -> None: """Emit one encoder function for an XDR enum type""" - template = self.environment.get_template("encoder/enum.j2") + if node.name in big_endian: + template = self.environment.get_template("encoder/enum_be.j2") + else: + template = self.environment.get_template("encoder/enum.j2") print(template.render(name=node.name))
tools/net/sunrpc/xdrgen/generators/union.py +25 -9
@@ -8,7 +8,7 @@ from jinja2 import Environment from generators import SourceGenerator from generators import create_jinja2_environment, get_jinja2_template -from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid +from xdr_ast import _XdrBasic, _XdrUnion, _XdrVoid, big_endian from xdr_ast import _XdrDeclaration, _XdrCaseSpec, public_apis
@@ -77,13 +77,18 @@ def emit_union_switch_spec_decoder( print(template.render(name=node.name, type=node.spec.type_name)) -def emit_union_case_spec_decoder(environment: Environment, node: _XdrCaseSpec) -> None: +def emit_union_case_spec_decoder( + environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool +) -> None: """Emit decoder functions for an XDR union's case arm""" if isinstance(node.arm, _XdrVoid): return - template = get_jinja2_template(environment, "decoder", "case_spec") + if big_endian_discriminant: + template = get_jinja2_template(environment, "decoder", "case_spec_be") + else: + template = get_jinja2_template(environment, "decoder", "case_spec") for case in node.values: print(template.render(case=case))
@@ -136,7 +141,11 @@ def emit_union_decoder(environment: Environment, node: _XdrUnion) -> None: emit_union_switch_spec_decoder(environment, node.discriminant) for case in node.cases: - emit_union_case_spec_decoder(environment, case) + emit_union_case_spec_decoder( + environment, + case, + node.discriminant.spec.type_name in big_endian, + ) emit_union_default_spec_decoder(environment, node)
@@ -153,17 +162,21 @@ def emit_union_switch_spec_encoder( print(template.render(name=node.name, type=node.spec.type_name)) -def emit_union_case_spec_encoder(environment: Environment, node: _XdrCaseSpec) -> None: +def emit_union_case_spec_encoder( + environment: Environment, node: _XdrCaseSpec, big_endian_discriminant: bool +) -> None: """Emit encoder functions for an XDR union's case arm""" if isinstance(node.arm, _XdrVoid): return - template = get_jinja2_template(environment, "encoder", "case_spec") + if big_endian_discriminant: + template = get_jinja2_template(environment, "encoder", "case_spec_be") + else: + template = get_jinja2_template(environment, "encoder", "case_spec") for case in node.values: print(template.render(case=case)) - assert isinstance(node.arm, _XdrBasic) template = get_jinja2_template(environment, "encoder", node.arm.template) print( template.render(
@@ -192,7 +205,6 @@ def emit_union_default_spec_encoder(environment: Environment, node: _XdrUnion) - print(template.render()) return - assert isinstance(default_case.arm, _XdrBasic) template = get_jinja2_template(environment, "encoder", default_case.arm.template) print( template.render(
@@ -210,7 +222,11 @@ def emit_union_encoder(environment, node: _XdrUnion) -> None: emit_union_switch_spec_encoder(environment, node.discriminant) for case in node.cases: - emit_union_case_spec_encoder(environment, case) + emit_union_case_spec_encoder( + environment, + case, + node.discriminant.spec.type_name in big_endian, + ) emit_union_default_spec_encoder(environment, node)
tools/net/sunrpc/xdrgen/grammars/xdr.lark +3 -1
@@ -87,12 +87,14 @@ procedure_def : type_specifier identifier "(" type_specifier ")" "=" c pragma_def : "pragma" directive identifier [ identifier ] ";" -directive : exclude_directive +directive : big_endian_directive + | exclude_directive | header_directive | pages_directive | public_directive | skip_directive +big_endian_directive : "big_endian" exclude_directive : "exclude" header_directive : "header" pages_directive : "pages"
tools/net/sunrpc/xdrgen/templates/C/enum/decoder/enum_be.j2 new file +14 -0
@@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} (big-endian) */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr) +{ + return xdr_stream_decode_be32(xdr, ptr) == 0; +}
tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 new file +3 -0
@@ -0,0 +1,3 @@ +{# SPDX-License-Identifier: GPL-2.0 #} +}; +typedef __be32 {{ name }};
tools/net/sunrpc/xdrgen/templates/C/enum/encoder/enum_be.j2 new file +14 -0
@@ -0,0 +1,14 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + +{% if annotate %} +/* enum {{ name }} (big-endian) */ +{% endif %} +{% if name in public_apis %} +bool +{% else %} +static bool __maybe_unused +{% endif %} +xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value) +{ + return xdr_stream_encode_be32(xdr, value) == XDR_UNIT; +}
tools/net/sunrpc/xdrgen/templates/C/union/decoder/case_spec_be.j2 new file +2 -0
@@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case __constant_cpu_to_be32({{ case }}):
tools/net/sunrpc/xdrgen/templates/C/union/encoder/case_spec_be.j2 new file +2 -0
@@ -0,0 +1,2 @@ +{# SPDX-License-Identifier: GPL-2.0 #} + case __constant_cpu_to_be32({{ case }}):
tools/net/sunrpc/xdrgen/xdr_ast.py +3 -0
@@ -12,6 +12,7 @@ from lark.tree import Meta this_module = sys.modules[__name__] +big_endian = [] excluded_apis = [] header_name = "none" public_apis = []
@@ -480,6 +481,8 @@ class ParseToAst(Transformer): """Instantiate one _Pragma object""" directive = children[0].children[0].data match directive: + case "big_endian_directive": + big_endian.append(children[1].symbol) case "exclude_directive": excluded_apis.append(children[1].symbol) case "header_directive":
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1030/1376 xdrgen: Address some checkpatch whitespace complaints
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 4329010ad9c36775e7092e451c37c24c4f90243f ]
This is a roll-up of three template fixes that eliminate noise from checkpatch output so that it's easier to spot non-trivial problems.
To follow conventional kernel C style, when a union declaration is marked with "pragma public", there should be a blank line between the emitted "union xxx { ... };" and the decoder and encoder function declarations.
Stable-dep-of: d4ca0b0a6c62 ("xdrgen: Do not declare union XDR functions in the definitions header")
--- tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 | 1 - tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 | 1 + tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 | 1 + tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 | 1 + 4 files changed, 3 insertions(+), 1 deletion(-)
tools/net/sunrpc/xdrgen/templates/C/enum/declaration/close.j2 +0 -1
@@ -1,4 +1,3 @@ {# SPDX-License-Identifier: GPL-2.0 #} - bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, {{ name }} *ptr); bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, {{ name }} value);
tools/net/sunrpc/xdrgen/templates/C/enum/definition/close.j2 +1 -0
@@ -1,3 +1,4 @@ {# SPDX-License-Identifier: GPL-2.0 #} }; + typedef enum {{ name }} {{ name }};
tools/net/sunrpc/xdrgen/templates/C/enum/definition/close_be.j2 +1 -0
@@ -1,3 +1,4 @@ {# SPDX-License-Identifier: GPL-2.0 #} }; + typedef __be32 {{ name }};
tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 +1 -0
@@ -3,6 +3,7 @@ }; {%- if name in public_apis %} + bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *ptr); {%- endif -%}
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1031/1376 xdrgen: Do not declare union XDR functions in the definitions header
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit d4ca0b0a6c62bc12407060754df11b23a90f3e57 ]
Unlike the struct, enum, typedef, and pointer templates, the union definitions template also emits xdrgen_decode_*() and xdrgen_encode_*() prototypes for a public union into that header. Those prototypes name struct xdr_stream, which the definitions header neither includes nor forward-declares, so any translation unit that includes the definitions header without xdr.h already in scope draws -Wvisibility warnings. The same public prototypes are emitted into the declarations header, which does include <linux/sunrpc/xdr.h>, making the definitions-header copies redundant.
Drop the prototype emission from the union definitions template so it matches the other type templates. Public unions keep their encode and decode prototypes through the declarations header.
--- .../net/sunrpc/xdrgen/templates/C/union/definition/close.j2 | 6 ------ 1 file changed, 6 deletions(-)
tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 +0 -6
@@ -1,9 +1,3 @@ {# SPDX-License-Identifier: GPL-2.0 #} } u; }; -{%- if name in public_apis %} - - -bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); -bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *ptr); -{%- endif -%}
Signature · 1 line
2.53.0
Re: [PATCH 6.12 1031/1376] xdrgen: Do not declare union XDR functions in the definitions header
Quoted 36 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit
d4ca0b0a6c62bc12407060754df11b23a90f3e57]Unlike the struct, enum, typedef, and pointer templates, the union definitions template also emits xdrgen_decode_*() and xdrgen_encode_*() prototypes for a public union into that header. Those prototypes name struct
xdr_stream, which the definitions header neither includes nor forward-declares, so any translation unit that includes the definitions header withoutxdr.halready in scope draws -Wvisibility warnings. The same public prototypes are emitted into the declarations header, which does include <linux/sunrpc/xdr.h>, making the definitions-header copies redundant.Drop the prototype emission from the union definitions template so it matches the other type templates. Public unions keep their encode and decode prototypes through the declarations header.
Fixes 4b132aacb076 ("tools: Add xdrgen")Signed-off-by Chuck Lever <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- .../net/sunrpc/xdrgen/templates/C/union/definition/close.j2 | 6 ------ 1 file changed, 6 deletions(-)tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 +0
-0
tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 line 8
Quoted 8 lines
tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 +0
-5@@ -1,9 +1,3 @@ {# SPDX-License-Identifier: GPL-2.0 #} } u; }; -{%- if name in public_apis %} - - -bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr, struct {{ name }} *ptr); -bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr, const struct {{ name }} *ptr);
Hi Greg/Sasha,
I ran an AI-assisted backport review, and I have verified the report. It looks valid to me.
The patch removes public-union XDR prototypes from the definitions header, which is correct only when the declarations header emits them. On 6.12, the declarations generator requests union/declaration/close.j2, but that template is absent. Public-union generation therefore loses both prototypes and its declarations path raises TemplateNotFound.
Upstream prerequisite template:
bool xdrgen_decode_{{ name }}(struct xdr_stream *xdr,
struct {{ name }} *ptr);
bool xdrgen_encode_{{ name }}(struct xdr_stream *xdr,
const struct {{ name }} *value);
Downstream 6.12.y generator code:
template = get_jinja2_template(environment,
"declaration", "close")
The requested downstream union template does not exist.
I think 6.12.y misses f7cb94fad4e6cec354a3ea779f91fe5560fb72b6, "xdrgen:
Fix union declarations". Thoughts?
thanks,
Harshit
Quoted 1 line
tools/net/sunrpc/xdrgen/templates/C/union/definition/close.j2 +0
-1-{%- endif -%}
Re: [PATCH 6.12 1031/1376] xdrgen: Do not declare union XDR functions in the definitions header
Quoted 2 lines
I think 6.12.y misses
f7cb94fad4e6cec354a3ea779f91fe5560fb72b6, "xdrgen:
Fix union declarations". Thoughts?
Queued for 6.18 and 6.12, thanks. 6.18 had the same gap.
Signature · 2 lines
Thanks, Sasha
Re: [PATCH 6.12 1031/1376] xdrgen: Do not declare union XDR functions in the definitions header
Quoted 3 lines · Sasha Levin
Quoted 2 lines
I think 6.12.y misses
f7cb94fad4e6cec354a3ea779f91fe5560fb72b6, "xdrgen:
Fix union declarations". Thoughts?Queued for 6.18 and 6.12, thanks. 6.18 had the same gap.
thanks a lot!
Regards,
Harshit
Greg Kroah-Hartman
maintainerPATCH 1032/1376 xdrgen: Fix opaque and string encoders for unbounded members
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit daa52e37851a5a1b5890e7a250a27e94a8b9f273 ]
The variable-length opaque and string encoder templates emit an unconditional bound check, "if (value->NAME.len > MAXSIZE) return false". XDR represents an unbounded specifier (opaque foo<>, string foo<>) as a maxsize of 0, so for an unbounded member the check degenerates to "len > 0" and the generated encoder refuses every non-empty value.
The decoder does not share this defect. It delegates to xdrgen_decode_opaque() and xdrgen_decode_string(), which treat a maxlen of 0 as unbounded and skip the length check. The sibling variable-length array templates already guard their bound check with maxsize != "0".
Guard the bound check the same way in each affected template -- the struct and pointer forms of both the opaque and string encoders -- so an unbounded member encodes a payload of any length while a bounded member keeps its limit.
An explicit zero-length bound (foo<0>) parses to the same maxsize of 0 and so also skips the check; xdrgen does not distinguish it from the unbounded form, matching the decoder and the array encoders.
--- .../templates/C/pointer/encoder/variable_length_opaque.j2 | 2 ++ .../templates/C/pointer/encoder/variable_length_string.j2 | 2 ++ .../xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 | 2 ++ .../xdrgen/templates/C/struct/encoder/variable_length_string.j2 | 2 ++ 4 files changed, 8 insertions(+)
tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_opaque.j2 +2 -0
@@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length opaque) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false;
tools/net/sunrpc/xdrgen/templates/C/pointer/encoder/variable_length_string.j2 +2 -0
@@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length string) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false;
tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_opaque.j2 +2 -0
@@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length opaque) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false;
tools/net/sunrpc/xdrgen/templates/C/struct/encoder/variable_length_string.j2 +2 -0
@@ -2,7 +2,9 @@ {% if annotate %} /* member {{ name }} (variable-length string) */ {% endif %} +{% if maxsize != "0" %} if (value->{{ name }}.len > {{ maxsize }}) return false; +{% endif %} if (xdr_stream_encode_opaque(xdr, value->{{ name }}.data, value->{{ name }}.len) < 0) return false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1033/1376 arm64: Disable KCSAN instrumentation in delay.o
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marco Elver <[email protected]>
[ Upstream commit 5eaec4cf41a8f5ac1a0c69a607cdc5035a797f73 ]
KCSAN relies on udelay() for injecting delays. To avoid recursively triggering a watchpoint, where KCSAN sets up watchpoint on an address that is accessed by udelay() in the same thread, disable instrumentation in arm64's delay implementation.
Paul found a manifestation of this as follows:
| BUG: KCSAN: data-race in __delay / set_need_resched_current | | read (marked) to 0xffff000005899b48 of 8 bytes by interrupt on cpu 8: | __delay+0xb0/0x378 | __udelay+0x4c/0x60 | kcsan_setup_watchpoint+0x3b4/0x820 | __tsan_unaligned_write4+0x228/0x26c | set_need_resched_current+0x138/0x1a8 | rcu_exp_handler+0x418/0x4a0 | __flush_smp_call_function_queue+0x36c/0x4a0 | generic_smp_call_function_single_interrupt+0x20/0x30 | ipi_handler+0xec/0x558 | handle_percpu_devid_irq+0x220/0x2a0 | generic_handle_domain_irq+0x84/0xb4 | gic_handle_irq+0x64/0x144 | call_on_irq_stack+0x30/0x48 | do_interrupt_handler+0x80/0xb8 | el1_interrupt+0x3c/0x60 | el1h_64_irq_handler+0x18/0x24 | el1h_64_irq+0x6c/0x70 | smp_call_function_single+0x18c/0x25c | sync_rcu_exp_select_node_cpus+0x534/0x8bc | rcu_exp_sel_wait_wake+0x358/0xef4 | wait_rcu_exp_gp+0x30/0x44 | kthread_worker_fn+0x1b4/0x5dc | kthread+0x1d8/0x204 | ret_from_fork+0x10/0x20 | | write to 0xffff000005899b4c of 4 bytes by interrupt on cpu 8: | set_need_resched_current+0x138/0x1a8 | [...]
This matches what is already done in arch/x86/lib/Makefile.
--- arch/arm64/lib/Makefile | 4 ++++ 1 file changed, 4 insertions(+)
arch/arm64/lib/Makefile +4 -0
@@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 + +# KCSAN uses udelay for introducing watchpoint delay; avoid recursion. +KCSAN_SANITIZE_delay.o := n + lib-y := clear_user.o delay.o copy_from_user.o \ copy_to_user.o copy_page.o \ clear_page.o csum.o insn.o memchr.o memcpy.o \
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1034/1376 SUNRPC: check rpc_sockaddr2uaddr() return value in rpcb_register_inet4/6
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit fd22370226a0d8109045d0831fd5aaadee921693 ]
rpcb_register_inet4() and rpcb_register_inet6() store the result of rpc_sockaddr2uaddr() into map->r_addr without checking it for NULL. rpc_sockaddr2uaddr() returns NULL when its final kstrdup() fails, and the unchecked NULL is then carried into the synchronous RPCBPROC_SET encode path: rpcb_register_call() -> rpc_call_sync() -> rpcb_enc_getaddr() -> encode_rpcb_string(), whose first statement is strlen(string), dereferencing NULL and oopsing the kernel.
The crash reproduces under failslab on v6.12; with KASAN the NULL dereference surfaces as a fault on the shadow of address zero:
Oops: general protection fault, probably for non-canonical address
0xdffffc0000000000 [#1] PREEMPT SMP KASAN
RIP: 0010:strlen (lib/string.c:409)
Call Trace:
encode_rpcb_string (net/sunrpc/rpcb_clnt.c:890)
rpcb_enc_getaddr (net/sunrpc/rpcb_clnt.c:910)
rpcauth_wrap_req_encode (net/sunrpc/auth.c:745)
call_encode (net/sunrpc/clnt.c:1966)
__rpc_execute (net/sunrpc/sched.c:952)
rpc_run_task (net/sunrpc/clnt.c:1243)
rpc_call_sync (net/sunrpc/clnt.c:1272)
rpcb_v4_register (net/sunrpc/rpcb_clnt.c:500)
svc_generic_rpcbind_set
nfsd_rpcbind_set
svc_register
svc_setup_socket
svc_addsock
write_ports
nfsctl_transaction_write
vfs_writeThe crash is reachable when an in-kernel RPC service (nfsd, lockd, nfs-callback) registers with the local rpcbind under enough memory pressure for the small GFP_KERNEL kstrdup() in rpc_sockaddr2uaddr() to fail. The asynchronous getport path already handles this exact failure mode by returning -ENOMEM; only the two register helpers omit the check.
Mirror that handling: bail out with -ENOMEM when rpc_sockaddr2uaddr() returns NULL, before the address is fed into the encoder.
--- net/sunrpc/rpcb_clnt.c | 4 ++++ 1 file changed, 4 insertions(+)
net/sunrpc/rpcb_clnt.c +4 -0
@@ -490,6 +490,8 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,int result; map->r_addr =rpc_sockaddr2uaddr (sap,GFP_KERNEL ); +if (!map->r_addr) +return -ENOMEM ; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET ];if (port !=0 ) {
@@ -516,6 +518,8 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,int result; map->r_addr =rpc_sockaddr2uaddr (sap,GFP_KERNEL ); +if (!map->r_addr) +return -ENOMEM ; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET ];if (port !=0 ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1035/1376 sunrpc: xprtsock: annotate shared socket callbacks with READ_ONCE/WRITE_ONCE
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 33930840b5f0a79f826e7c69dc6cd78f72a67481 ]
xprtsock replaces and restores sk->sk_data_ready and sk->sk_write_space on live sockets with plain stores, and xs_udp_do_set_buffer_size() invokes sk->sk_write_space via a plain load. These callback pointers are shared with generic socket and protocol paths that may read or invoke them concurrently, so xprtsock needs the same READ_ONCE()/WRITE_ONCE() callback visibility contract that the validated 4022 family applied elsewhere.
When SUNRPC takes over an AF_LOCAL, UDP, or TCP socket and later restores the lower-socket callbacks during teardown, another CPU may still hold an earlier callback snapshot. The plain replace/restore pattern leaves the same visibility hole as the validated 4022 family, so a stale snapshot can still invoke xs_data_ready() or xs_udp_write_space() after the live callback fields have already been restored to the lower-socket handlers.
Use WRITE_ONCE() for the shared sk_data_ready and sk_write_space stores in xs_local_finish_connecting(), xs_udp_finish_connecting(), xs_tcp_finish_connecting(), and xs_restore_old_callbacks(). Use READ_ONCE() for the direct sk_write_space invocation in xs_udp_do_set_buffer_size(). This matches the required callback visibility contract while leaving adjacent sk_state_change and sk_error_report handling unchanged.
--- net/sunrpc/xprtsock.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
net/sunrpc/xprtsock.c +11 -9
@@ -1202,9 +1202,9 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk)static void xs_restore_old_callbacks (struct sock_xprt *transport,struct sock *sk) { - sk->sk_data_ready = transport->old_data_ready; +WRITE_ONCE (sk->sk_data_ready, transport->old_data_ready); sk->sk_state_change = transport->old_state_change; - sk->sk_write_space = transport->old_write_space; +WRITE_ONCE (sk->sk_write_space, transport->old_write_space); sk->sk_error_report = transport->old_error_report; }
@@ -1663,6 +1663,7 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt) { struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);struct sock *sk = transport->inet; +void (*write_space)(struct sock *sock);if (transport->rcvsize) { sk->sk_userlocks |=SOCK_RCVBUF_LOCK ;
@@ -1671,7 +1672,8 @@ static void xs_udp_do_set_buffer_size(struct rpc_xprt *xprt)if (transport->sndsize) { sk->sk_userlocks |=SOCK_SNDBUF_LOCK ; sk->sk_sndbuf = transport->sndsize * xprt->max_reqs *2 ; - sk->sk_write_space (sk); + write_space =READ_ONCE (sk->sk_write_space); +write_space (sk); } }
@@ -1987,8 +1989,8 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,xs_save_old_callbacks (transport, sk); sk->sk_user_data = xprt; - sk->sk_data_ready = xs_data_ready; - sk->sk_write_space = xs_udp_write_space; +WRITE_ONCE (sk->sk_data_ready, xs_data_ready); +WRITE_ONCE (sk->sk_write_space, xs_udp_write_space); sk->sk_state_change = xs_local_state_change; sk->sk_error_report = xs_error_report; sk->sk_use_task_frag = false;
@@ -2190,8 +2192,8 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)xs_save_old_callbacks (transport, sk); sk->sk_user_data = xprt; - sk->sk_data_ready = xs_data_ready; - sk->sk_write_space = xs_udp_write_space; +WRITE_ONCE (sk->sk_data_ready, xs_data_ready); +WRITE_ONCE (sk->sk_write_space, xs_udp_write_space); sk->sk_use_task_frag = false;xprt_set_connected (xprt);
@@ -2377,9 +2379,9 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)xs_save_old_callbacks (transport, sk); sk->sk_user_data = xprt; - sk->sk_data_ready = xs_data_ready; +WRITE_ONCE (sk->sk_data_ready, xs_data_ready); sk->sk_state_change = xs_tcp_state_change; - sk->sk_write_space = xs_tcp_write_space; +WRITE_ONCE (sk->sk_write_space, xs_tcp_write_space); sk->sk_error_report = xs_error_report; sk->sk_use_task_frag = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1036/1376 powerpc/configs: enable CONFIG_RAS to fix EDAC support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Walle <[email protected]>
[ Upstream commit 3921cfc2e8155a767235801be88cbd0e4c73508d ]
Before commit e3c4ff6d8c94 ("EDAC: Remove EDAC_MM_EDAC") EDAC_MM_EDAC selected RAS, after that commit, EDAC depends on RAS, but nobody enables it. Enable it in the config again.
--- arch/powerpc/configs/85xx-hw.config | 1 + 1 file changed, 1 insertion(+)
arch/powerpc/configs/85xx-hw.config +1 -0
@@ -90,6 +90,7 @@ CONFIG_PPC_EPAPR_HV_BYTECHAN=y CONFIG_QE_GPIO=y CONFIG_QUICC_ENGINE=y CONFIG_RAPIDIO=y +CONFIG_RAS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_CMOS=y CONFIG_RTC_DRV_DS1307=y
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1037/1376 iommu/amd: Fix incorrect device ID in invalid PASID error message
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasant Hegde <[email protected]>
[ Upstream commit 5322e19fc5acf013784207bc38191cd418a8bb48 ]
The IO page fault notifier handler logs pdev->dev.id when reporting an invalid PASID, but pdev->dev.id is the kernel-internal device ID and not the IOMMU device ID (BDF). Use dev_data->devid instead, which reflects actual devid.
--- drivers/iommu/amd/ppr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/amd/ppr.c +1 -1
@@ -140,7 +140,7 @@ static void iommu_call_iopf_notifier(struct amd_iommu *iommu, u64 *raw)if (event.fault.prm.pasid ==0 || event.fault.prm.pasid >= dev_data->max_pasids) {pr_info_ratelimited ("Invalid PASID : 0x%x, device : 0x%x\n" , - event.fault.prm.pasid, pdev->dev.id); + event.fault.prm.pasid, dev_data->devid); goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1038/1376 phy: qcom: qmp-combo: Correct pre-emphasis table for QMP v4 DP PHYs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Esteban Urrutia <[email protected]>
[ Upstream commit 481807f939077059db278edd0467e7e609b6c9a7 ]
Comparing sm8350 and sm8450 tables, this seems to be a typo.
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +1 -1
@@ -1474,7 +1474,7 @@ static const u8 qmp_dp_v4_pre_emphasis_hbr3_hbr2[4][4] = {static const u8 qmp_dp_v4_pre_emphasis_hbr_rbr[4 ][4 ] = { {0x00 ,0x0d ,0x14 ,0x1a }, {0x00 ,0x0e ,0x15 ,0xff }, - {0x00 ,0x0d ,0xff ,0xff }, + {0x00 ,0x0e ,0xff ,0xff }, {0x03 ,0xff ,0xff ,0xff } };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1039/1376 phy: qualcomm: qmp-combo: add support for SAR2130P
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Baryshkov <[email protected]>
[ Upstream commit 545069bcf39e9f025e8e3d749505e52423433e37 ]
Extend the USB+DP combo QMP PHY driver to support the SAR2130P platform. It mosly follows the SM8550 QMP PHY, but the QSERDES programming differs, most likely because of the parent clock rate differences.
NOTE: The DP part wasn't yet tested, but it is not possible to support just the USB part of the PHY. DP part might require additional fixes later.
Stable-dep-of: 8fd2b30d187f ("phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy")
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+)
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +100 -0
@@ -400,6 +400,57 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), }; +static const struct qmp_phy_init_tbl sar2130p_usb3_serdes_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1 ,0x55 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1 ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_CP_CTRL_MODE1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_PLL_RCTRL_MODE1 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_PLL_CCTRL_MODE1 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_CORECLK_DIV_MODE1 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_LOCK_CMP1_MODE1 ,0x2e ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_LOCK_CMP2_MODE1 ,0x82 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DEC_START_MODE1 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DEC_START_MSB_MODE1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DIV_FRAC_START1_MODE1 ,0x55 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DIV_FRAC_START2_MODE1 ,0xd5 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DIV_FRAC_START3_MODE1 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_HSCLK_SEL_1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_VCO_TUNE1_MODE1 ,0x25 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_VCO_TUNE2_MODE1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1 ,0xb7 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1 ,0x1e ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0xb7 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x1e ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0 ,0x55 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0 ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_CP_CTRL_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_PLL_RCTRL_MODE0 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_PLL_CCTRL_MODE0 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_LOCK_CMP1_MODE0 ,0x12 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_LOCK_CMP2_MODE0 ,0x34 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DEC_START_MODE0 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DEC_START_MSB_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DIV_FRAC_START1_MODE0 ,0x55 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DIV_FRAC_START2_MODE0 ,0xd5 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_DIV_FRAC_START3_MODE0 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_VCO_TUNE1_MODE0 ,0x25 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_VCO_TUNE2_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_BG_TIMER ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_EN_CENTER ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_PER1 ,0x31 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SSC_PER2 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SYSCLK_BUF_ENABLE ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_SYSCLK_EN_SEL ,0x1a ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_LOCK_CMP_CFG ,0x14 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_VCO_TUNE_MAP ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_CORE_CLK_EN ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_CMN_CONFIG_1 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_1 ,0xb6 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_2 ,0x4b ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_3 ,0x37 ), +QMP_PHY_INIT_CFG (QSERDES_V6_COM_ADDITIONAL_MISC ,0x0c ), +}; +static const struct qmp_phy_init_tbl sm6350_usb3_rx_tbl[] = {QMP_PHY_INIT_CFG (QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN ,0x0b ),QMP_PHY_INIT_CFG (QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2 ,0x0f ),
@@ -1730,6 +1781,51 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = { .dp_dp_phy = 0x2200, }; +static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + + .serdes_tbl = sar2130p_usb3_serdes_tbl, + .serdes_tbl_num =ARRAY_SIZE (sar2130p_usb3_serdes_tbl), + .tx_tbl = sm8550_usb3_tx_tbl, + .tx_tbl_num =ARRAY_SIZE (sm8550_usb3_tx_tbl), + .rx_tbl = sm8550_usb3_rx_tbl, + .rx_tbl_num =ARRAY_SIZE (sm8550_usb3_rx_tbl), + .pcs_tbl = sm8550_usb3_pcs_tbl, + .pcs_tbl_num =ARRAY_SIZE (sm8550_usb3_pcs_tbl), + .pcs_usb_tbl = sm8550_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num =ARRAY_SIZE (sm8550_usb3_pcs_usb_tbl), + + .dp_serdes_tbl = qmp_v6_dp_serdes_tbl, + .dp_serdes_tbl_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl), + .dp_tx_tbl = qmp_v6_dp_tx_tbl, + .dp_tx_tbl_num =ARRAY_SIZE (qmp_v6_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v6_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v6_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v6_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v6_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_hbr3), + + .swing_hbr_rbr = &qmp_dp_v5_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, + + .dp_aux_init = qmp_v4_dp_aux_init, + .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_phy = qmp_v4_configure_dp_phy, + .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, + + .regs = qmp_v6_usb3phy_regs_layout, + .reset_list = msm8996_usb3phy_reset_l, + .num_resets =ARRAY_SIZE (msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs =ARRAY_SIZE (qmp_phy_vreg_l), +}; +static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = { .offsets = &qmp_combo_offsets_v3,
@@ -3767,6 +3863,10 @@ static int qmp_combo_probe(struct platform_device *pdev) }static const struct of_device_id qmp_combo_of_match_table[] = { + { + .compatible ="qcom,sar2130p-qmp-usb3-dp-phy" , + .data = &sar2130p_usb3dpphy_cfg, + }, { .compatible ="qcom,sc7180-qmp-usb3-dp-phy" , .data = &sc7180_usb3dpphy_cfg,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1040/1376 phy: qcom: qmp-combo: Add new PHY sequences for SM8750
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wesley Cheng <[email protected]>
[ Upstream commit c4364048baf4878c270e94aa224bb114b445704d ]
Add new register offsets and PHY values for SM8750. Some of the previous definitions can be leveraged from older PHY versions as offsets within registers have not changed. This also adds the required PHY sequence that is recommended after running hardware characterization.
Stable-dep-of: 8fd2b30d187f ("phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy")
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 221 ++++++++++++++++++ .../phy/qualcomm/phy-qcom-qmp-pcs-usb-v8.h | 38 +++ drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8.h | 32 +++ .../qualcomm/phy-qcom-qmp-qserdes-com-v8.h | 64 +++++ .../qualcomm/phy-qcom-qmp-qserdes-txrx-v8.h | 68 ++++++ drivers/phy/qualcomm/phy-qcom-qmp.h | 5 + 6 files changed, 428 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v8.h
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +221 -0
@@ -32,6 +32,7 @@#include "phy-qcom-qmp-pcs-usb-v4.h" #include "phy-qcom-qmp-pcs-usb-v5.h" #include "phy-qcom-qmp-pcs-usb-v6.h" +#include "phy-qcom-qmp-pcs-usb-v8.h" #include "phy-qcom-qmp-dp-com-v3.h"
@@ -212,6 +213,28 @@ static const unsigned int qmp_v6_n4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V6_N4_TX_TRANSCEIVER_BIAS_EN, }; +static const unsigned int qmp_v8_usb3phy_regs_layout[QPHY_LAYOUT_SIZE ] = { + [QPHY_SW_RESET ] =QPHY_V8_PCS_SW_RESET , + [QPHY_START_CTRL ] =QPHY_V8_PCS_START_CONTROL , + [QPHY_PCS_STATUS ] =QPHY_V8_PCS_PCS_STATUS1 , + [QPHY_PCS_POWER_DOWN_CONTROL ] =QPHY_V8_PCS_POWER_DOWN_CONTROL , + +/* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL ] =QPHY_V8_PCS_USB_AUTONOMOUS_MODE_CTRL , + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR ] =QPHY_V8_PCS_USB_LFPS_RXTERM_IRQ_CLEAR , + + [QPHY_COM_RESETSM_CNTRL ] =QSERDES_V8_COM_RESETSM_CNTRL , + [QPHY_COM_C_READY_STATUS ] =QSERDES_V8_COM_C_READY_STATUS , + [QPHY_COM_CMN_STATUS ] =QSERDES_V8_COM_CMN_STATUS , + [QPHY_COM_BIAS_EN_CLKBUFLR_EN ] =QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN , + + [QPHY_TX_TX_POL_INV ] =QSERDES_V8_TX_TX_POL_INV , + [QPHY_TX_TX_DRV_LVL ] =QSERDES_V8_TX_TX_DRV_LVL , + [QPHY_TX_TX_EMP_POST1_LVL ] =QSERDES_V8_TX_TX_EMP_POST1_LVL , + [QPHY_TX_HIGHZ_DRVR_EN ] =QSERDES_V8_TX_HIGHZ_DRVR_EN , + [QPHY_TX_TRANSCEIVER_BIAS_EN ] =QSERDES_V8_TX_TRANSCEIVER_BIAS_EN , +}; +static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {QMP_PHY_INIT_CFG (QSERDES_V3_COM_PLL_IVCO ,0x07 ),QMP_PHY_INIT_CFG (QSERDES_V3_COM_SYSCLK_EN_SEL ,0x14 ),
@@ -1471,6 +1494,139 @@ static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_EQ_CONFIG5, 0x10), }; +static const struct qmp_phy_init_tbl sm8750_usb3_serdes_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_STEP_SIZE1_MODE1 ,0xc0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_STEP_SIZE2_MODE1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_CP_CTRL_MODE1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_PLL_RCTRL_MODE1 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_PLL_CCTRL_MODE1 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_CORECLK_DIV_MODE1 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_LOCK_CMP1_MODE1 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_LOCK_CMP2_MODE1 ,0x41 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DEC_START_MODE1 ,0x41 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DEC_START_MSB_MODE1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DIV_FRAC_START1_MODE1 ,0x55 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DIV_FRAC_START2_MODE1 ,0x75 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DIV_FRAC_START3_MODE1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_HSCLK_SEL_1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_VCO_TUNE1_MODE1 ,0x25 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_VCO_TUNE2_MODE1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE1 ,0x5c ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE1 ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0x5c ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_STEP_SIZE1_MODE0 ,0xc0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_STEP_SIZE2_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_CP_CTRL_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_PLL_RCTRL_MODE0 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_PLL_CCTRL_MODE0 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_LOCK_CMP1_MODE0 ,0x08 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_LOCK_CMP2_MODE0 ,0x1a ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DEC_START_MODE0 ,0x41 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DEC_START_MSB_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DIV_FRAC_START1_MODE0 ,0x55 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DIV_FRAC_START2_MODE0 ,0x75 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_DIV_FRAC_START3_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_VCO_TUNE1_MODE0 ,0x25 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_VCO_TUNE2_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_BG_TIMER ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_EN_CENTER ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_PER1 ,0x62 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SSC_PER2 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SYSCLK_BUF_ENABLE ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_SYSCLK_EN_SEL ,0x1a ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_LOCK_CMP_CFG ,0x14 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_VCO_TUNE_MAP ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_CORE_CLK_EN ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_CMN_CONFIG_1 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_1 ,0xb6 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_2 ,0x4a ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_AUTO_GAIN_ADJ_CTRL_3 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_COM_ADDITIONAL_MISC ,0x0c ), +}; + +static const struct qmp_phy_init_tbl sm8750_usb3_tx_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_TX_RES_CODE_LANE_TX ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_RES_CODE_LANE_RX ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_RES_CODE_LANE_OFFSET_TX ,0x1f ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_RES_CODE_LANE_OFFSET_RX ,0x09 ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_LANE_MODE_1 ,0xf5 ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_LANE_MODE_3 ,0x11 ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_LANE_MODE_4 ,0x31 ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_LANE_MODE_5 ,0x5f ), +QMP_PHY_INIT_CFG (QSERDES_V8_TX_RCV_DETECT_LVL_2 ,0x12 ), +QMP_PHY_INIT_CFG_LANE (QSERDES_V8_TX_PI_QEC_CTRL ,0x21 ,1 ), +QMP_PHY_INIT_CFG_LANE (QSERDES_V8_TX_PI_QEC_CTRL ,0x05 ,2 ), +}; + +static const struct qmp_phy_init_tbl sm8750_usb3_rx_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_FO_GAIN ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_SO_GAIN ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_FASTLOCK_FO_GAIN ,0x2f ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_SO_SATURATION_AND_ENABLE ,0x7f ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_FASTLOCK_COUNT_LOW ,0xff ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_FASTLOCK_COUNT_HIGH ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_PI_CONTROLS ,0x99 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_SB2_THRESH1 ,0x08 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_SB2_THRESH2 ,0x08 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_SB2_GAIN1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_UCDR_SB2_GAIN2 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_AUX_DATA_TCOARSE_TFINE ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_VGA_CAL_CNTRL1 ,0x54 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_VGA_CAL_CNTRL2 ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_GM_CAL ,0x13 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_EQU_ADAPTOR_CNTRL2 ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_EQU_ADAPTOR_CNTRL3 ,0x4a ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_EQU_ADAPTOR_CNTRL4 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_IDAC_TSETTLE_LOW ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_IDAC_TSETTLE_HIGH ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 ,0x27 ), + +QMP_PHY_INIT_CFG (QSERDES_V8_RX_SIGDET_ENABLES ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_SIGDET_CNTRL ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_SIGDET_DEGLITCH_CNTRL ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_00_LOW ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_00_HIGH ,0xbf ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_00_HIGH2 ,0xff ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_00_HIGH3 ,0xdf ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_00_HIGH4 ,0xed ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_01_LOW ,0x19 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_01_HIGH ,0x09 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_01_HIGH2 ,0x91 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_01_HIGH3 ,0xb7 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_RX_MODE_01_HIGH4 ,0xaa ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_DFE_EN_TIMER ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_DFE_CTLE_POST_CAL_OFFSET ,0x38 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_DCC_CTRL1 ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_VTH_CODE ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_SIGDET_CAL_CTRL1 ,0x14 ), +QMP_PHY_INIT_CFG (QSERDES_V8_RX_SIGDET_CAL_TRIM ,0x08 ), +}; + +static const struct qmp_phy_init_tbl sm8750_usb3_pcs_tbl[] = { +QMP_PHY_INIT_CFG (QPHY_V8_PCS_LOCK_DETECT_CONFIG1 ,0xc4 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_LOCK_DETECT_CONFIG2 ,0x89 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_LOCK_DETECT_CONFIG3 ,0x20 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_LOCK_DETECT_CONFIG6 ,0x13 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_REFGEN_REQ_CONFIG1 ,0x21 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_RX_SIGDET_LVL ,0x55 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_RCVR_DTCT_DLY_P1U2_L ,0xe7 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_RCVR_DTCT_DLY_P1U2_H ,0x03 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_CDR_RESET_TIME ,0x0a ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_ALIGN_DETECT_CONFIG1 ,0x88 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_ALIGN_DETECT_CONFIG2 ,0x13 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_PCS_TX_RX_CONFIG ,0x0c ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_EQ_CONFIG1 ,0x4b ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_EQ_CONFIG5 ,0x10 ), +}; + +static const struct qmp_phy_init_tbl sm8750_usb3_pcs_usb_tbl[] = { +QMP_PHY_INIT_CFG (QPHY_V8_PCS_USB_LFPS_DET_HIGH_COUNT_VAL ,0xf8 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_USB_RXEQTRAINING_DFE_TIME_S2 ,0x07 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_USB_RCVR_DTCT_DLY_U3_L ,0x40 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_USB_RCVR_DTCT_DLY_U3_H ,0x00 ), +}; +static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_usb_tbl[] = {QMP_PHY_INIT_CFG (QPHY_V6_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL ,0xf8 ),QMP_PHY_INIT_CFG (QPHY_V6_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 ,0x07 ),
@@ -1781,6 +1937,22 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = { .dp_dp_phy = 0x2200, }; +static const struct qmp_combo_offsets qmp_combo_offsets_v8 = { + .com =0x0000 , + .txa =0x1400 , + .rxa =0x1600 , + .txb =0x1800 , + .rxb =0x1a00 , + .usb3_serdes =0x1000 , + .usb3_pcs_misc =0x1c00 , + .usb3_pcs =0x1e00 , + .usb3_pcs_usb =0x2100 , + .dp_serdes =0x3000 , + .dp_txa =0x3400 , + .dp_txb =0x3800 , + .dp_dp_phy =0x3c00 , +}; +static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = { .offsets = &qmp_combo_offsets_v3,
@@ -2280,6 +2452,51 @@ static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), }; +static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v8, + + .serdes_tbl = sm8750_usb3_serdes_tbl, + .serdes_tbl_num =ARRAY_SIZE (sm8750_usb3_serdes_tbl), + .tx_tbl = sm8750_usb3_tx_tbl, + .tx_tbl_num =ARRAY_SIZE (sm8750_usb3_tx_tbl), + .rx_tbl = sm8750_usb3_rx_tbl, + .rx_tbl_num =ARRAY_SIZE (sm8750_usb3_rx_tbl), + .pcs_tbl = sm8750_usb3_pcs_tbl, + .pcs_tbl_num =ARRAY_SIZE (sm8750_usb3_pcs_tbl), + .pcs_usb_tbl = sm8750_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num =ARRAY_SIZE (sm8750_usb3_pcs_usb_tbl), + + .dp_serdes_tbl = qmp_v6_dp_serdes_tbl, + .dp_serdes_tbl_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl), + .dp_tx_tbl = qmp_v6_dp_tx_tbl, + .dp_tx_tbl_num =ARRAY_SIZE (qmp_v6_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v6_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v6_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v6_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v6_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num =ARRAY_SIZE (qmp_v6_dp_serdes_tbl_hbr3), + + .swing_hbr_rbr = &qmp_dp_v6_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, + + .dp_aux_init = qmp_v4_dp_aux_init, + .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_phy = qmp_v4_configure_dp_phy, + .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, + + .regs = qmp_v8_usb3phy_regs_layout, + .reset_list = msm8996_usb3phy_reset_l, + .num_resets =ARRAY_SIZE (msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs =ARRAY_SIZE (qmp_phy_vreg_l), +}; +static int qmp_combo_dp_serdes_init (struct qmp_combo *qmp) {const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -3915,6 +4132,10 @@ static const struct of_device_id qmp_combo_of_match_table[] = { .compatible = "qcom,sm8650-qmp-usb3-dp-phy", .data = &sm8650_usb3dpphy_cfg, }, + { + .compatible = "qcom,sm8750-qmp-usb3-dp-phy", + .data = &sm8750_usb3dpphy_cfg, + }, { .compatible = "qcom,x1e80100-qmp-usb3-dp-phy", .data = &x1e80100_usb3dpphy_cfg,
drivers/phy/qualcomm/phy-qcom-qmp-pcs-usb-v8.h new file +38 -0
@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_PCS_USB_V8_H_ +#define QCOM_PHY_QMP_PCS_USB_V8_H_ + +#define QPHY_V8_PCS_USB_POWER_STATE_CONFIG1 0x00 +#define QPHY_V8_PCS_USB_AUTONOMOUS_MODE_STATUS 0x04 +#define QPHY_V8_PCS_USB_AUTONOMOUS_MODE_CTRL 0x08 +#define QPHY_V8_PCS_USB_AUTONOMOUS_MODE_CTRL2 0x0c +#define QPHY_V8_PCS_USB_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x10 +#define QPHY_V8_PCS_USB_LFPS_RXTERM_IRQ_CLEAR 0x14 +#define QPHY_V8_PCS_USB_LFPS_DET_HIGH_COUNT_VAL 0x18 +#define QPHY_V8_PCS_USB_LFPS_TX_ECSTART 0x1c +#define QPHY_V8_PCS_USB_LFPS_PER_TIMER_VAL 0x20 +#define QPHY_V8_PCS_USB_LFPS_TX_END_CNT_U3_START 0x24 +#define QPHY_V8_PCS_USB_LFPS_CONFIG1 0x28 +#define QPHY_V8_PCS_USB_RXEQTRAINING_LOCK_TIME 0x2c +#define QPHY_V8_PCS_USB_RXEQTRAINING_WAIT_TIME 0x30 +#define QPHY_V8_PCS_USB_RXEQTRAINING_CTLE_TIME 0x34 +#define QPHY_V8_PCS_USB_RXEQTRAINING_WAIT_TIME_S2 0x38 +#define QPHY_V8_PCS_USB_RXEQTRAINING_DFE_TIME_S2 0x3c +#define QPHY_V8_PCS_USB_RCVR_DTCT_DLY_U3_L 0x40 +#define QPHY_V8_PCS_USB_RCVR_DTCT_DLY_U3_H 0x44 +#define QPHY_V8_PCS_USB_ARCVR_DTCT_EN_PERIOD 0x48 +#define QPHY_V8_PCS_USB_ARCVR_DTCT_CM_DLY 0x4c +#define QPHY_V8_PCS_USB_TXONESZEROS_RUN_LENGTH 0x50 +#define QPHY_V8_PCS_USB_ALFPS_DEGLITCH_VAL 0x54 +#define QPHY_V8_PCS_USB_SIGDET_STARTUP_TIMER_VAL 0x58 +#define QPHY_V8_PCS_USB_TEST_CONTROL 0x5c +#define QPHY_V8_PCS_USB_RXTERMINATION_DLY_SEL 0x60 +#define QPHY_V8_PCS_USB_POWER_STATE_CONFIG2 0x64 +#define QPHY_V8_PCS_USB_POWER_STATE_CONFIG3 0x68 +#define QPHY_V8_PCS_USB_POWER_STATE_CONFIG4 0x6c + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-pcs-v8.h new file +32 -0
@@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_PCS_V8_H_ +#define QCOM_PHY_QMP_PCS_V8_H_ + +/* Only for QMP V8 PHY - USB/PCIe PCS registers */ +#define QPHY_V8_PCS_SW_RESET 0x000 +#define QPHY_V8_PCS_PCS_STATUS1 0x014 +#define QPHY_V8_PCS_POWER_DOWN_CONTROL 0x040 +#define QPHY_V8_PCS_START_CONTROL 0x044 +#define QPHY_V8_PCS_POWER_STATE_CONFIG1 0x090 +#define QPHY_V8_PCS_LOCK_DETECT_CONFIG1 0x0c4 +#define QPHY_V8_PCS_LOCK_DETECT_CONFIG2 0x0c8 +#define QPHY_V8_PCS_LOCK_DETECT_CONFIG3 0x0cc +#define QPHY_V8_PCS_LOCK_DETECT_CONFIG6 0x0d8 +#define QPHY_V8_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V8_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V8_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 +#define QPHY_V8_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 +#define QPHY_V8_PCS_RATE_SLEW_CNTRL1 0x198 +#define QPHY_V8_PCS_CDR_RESET_TIME 0x1b0 +#define QPHY_V8_PCS_ALIGN_DETECT_CONFIG1 0x1c0 +#define QPHY_V8_PCS_ALIGN_DETECT_CONFIG2 0x1c4 +#define QPHY_V8_PCS_PCS_TX_RX_CONFIG 0x1d0 +#define QPHY_V8_PCS_EQ_CONFIG1 0x1dc +#define QPHY_V8_PCS_EQ_CONFIG2 0x1e0 +#define QPHY_V8_PCS_EQ_CONFIG5 0x1ec + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v8.h new file +64 -0
64 lines not on this page · raw message
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v8.h new file +68 -0
68 lines not on this page · raw message
drivers/phy/qualcomm/phy-qcom-qmp.h +5 -0
@@ -30,6 +30,9 @@#include "phy-qcom-qmp-qserdes-com-v7.h" #include "phy-qcom-qmp-qserdes-txrx-v7.h" +#include "phy-qcom-qmp-qserdes-com-v8.h" +#include "phy-qcom-qmp-qserdes-txrx-v8.h" +#include "phy-qcom-qmp-qserdes-pll.h" #include "phy-qcom-qmp-pcs-v2.h"
@@ -52,6 +55,8 @@#include "phy-qcom-qmp-pcs-v7.h" +#include "phy-qcom-qmp-pcs-v8.h" +/* QPHY_SW_RESET bit */ #define SW_RESET BIT(0)/* QPHY_POWER_DOWN_CONTROL */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1041/1376 phy: qcom-qmp-combo: Use regulator_bulk_data with init_load_uA for regulator setup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Faisal Hassan <[email protected]>
[ Upstream commit 81d75558406609f311766a37ec4b2c74d7b11ea0 ]
Replace the custom qmp_regulator_data structure with the standard regulator_bulk_data and use the init_load_uA field to set regulator load during initialization.
This change simplifies the regulator setup by removing manual allocation and load configuration logic, and leverages devm_regulator_bulk_get_const() to automatically apply load settings before enabling regulators.
Stable-dep-of: 8fd2b30d187f ("phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy")
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 49 +++-------------------- 1 file changed, 6 insertions(+), 43 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +6 -43
@@ -1633,14 +1633,9 @@ static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_usb_tbl[] = { };/* list of regulators */ -struct qmp_regulator_data { -const char *name; -unsigned int enable_load; -}; - -static struct qmp_regulator_data qmp_phy_vreg_l[] = { - { .name ="vdda-phy" , .enable_load =21800 }, - { .name ="vdda-pll" , .enable_load =36000 }, +static struct regulator_bulk_data qmp_phy_vreg_l[] = { + { .supply ="vdda-phy" , .init_load_uA =21800 , }, + { .supply ="vdda-pll" , .init_load_uA =36000 , }, };static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4 ][4 ] = {
@@ -1798,7 +1793,7 @@ struct qmp_phy_cfg {const char *const *reset_list;int num_resets;/* regulators to be requested */ -const struct qmp_regulator_data *vreg_list; +const struct regulator_bulk_data *vreg_list;int num_vregs;/* array of registers with different offsets */
@@ -3400,39 +3395,6 @@ static const struct dev_pm_ops qmp_combo_pm_ops = { qmp_combo_runtime_resume, NULL) }; -static int qmp_combo_vreg_init (struct qmp_combo *qmp) -{ -const struct qmp_phy_cfg *cfg = qmp->cfg; -struct device *dev = qmp->dev; -int num = cfg->num_vregs; -int ret, i; - - qmp->vregs =devm_kcalloc (dev, num,sizeof (*qmp->vregs),GFP_KERNEL ); -if (!qmp->vregs) -return -ENOMEM ; - -for (i =0 ; i < num; i++) - qmp->vregs[i].supply = cfg->vreg_list[i].name; - - ret =devm_regulator_bulk_get (dev, num, qmp->vregs); -if (ret) { -dev_err (dev,"failed at devm_regulator_bulk_get\n" ); -return ret; - } - -for (i =0 ; i < num; i++) { - ret =regulator_set_load (qmp->vregs[i].consumer, - cfg->vreg_list[i].enable_load); -if (ret) { -dev_err (dev,"failed to set load at %s\n" , - qmp->vregs[i].supply); -return ret; - } - } - -return 0 ; -} -static int qmp_combo_reset_init (struct qmp_combo *qmp) {const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -4000,7 +3962,8 @@ static int qmp_combo_probe(struct platform_device *pdev)if (ret)return ret; - ret =qmp_combo_vreg_init (qmp); + ret =devm_regulator_bulk_get_const (dev, qmp->cfg->num_vregs, + qmp->cfg->vreg_list, &qmp->vregs);if (ret)return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1042/1376 phy: qualcomm: Update the QMP clamp register for V6
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wesley Cheng <[email protected]>
[ Upstream commit c9543cca9417d83f8ca6a8ce0a5279a3fba7a02b ]
QMP combo phy V6 and above use the clamp register from the PCS always on (AON) address space. Update the driver accordingly.
Stable-dep-of: 8fd2b30d187f ("phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy")
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 38 ++++++++++++++++--- .../phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h | 12 ++++++ .../phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h | 12 ++++++ 3 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +33 -5
@@ -28,7 +28,10 @@#include "phy-qcom-qmp-common.h" #include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-aon-v6.h" #include "phy-qcom-qmp-pcs-misc-v3.h" +#include "phy-qcom-qmp-pcs-misc-v4.h" +#include "phy-qcom-qmp-pcs-misc-v5.h" #include "phy-qcom-qmp-pcs-usb-v4.h" #include "phy-qcom-qmp-pcs-usb-v5.h" #include "phy-qcom-qmp-pcs-usb-v6.h"
@@ -71,6 +74,7 @@ enum qphy_reg_layout {QPHY_PCS_AUTONOMOUS_MODE_CTRL ,QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR ,QPHY_PCS_POWER_DOWN_CONTROL , +QPHY_PCS_CLAMP_ENABLE ,QPHY_COM_RESETSM_CNTRL , QPHY_COM_C_READY_STATUS,
@@ -98,6 +102,8 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE, + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V3_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V3_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V3_COM_CMN_STATUS,
@@ -123,6 +129,8 @@ static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_CLAMP_ENABLE] = QPHY_V4_PCS_MISC_CLAMP_ENABLE, + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V4_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V4_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V4_COM_CMN_STATUS,
@@ -148,6 +156,8 @@ static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V5_PCS_USB3_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V5_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_CLAMP_ENABLE] = QPHY_V5_PCS_MISC_CLAMP_ENABLE, + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V5_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V5_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V5_COM_CMN_STATUS,
@@ -173,6 +183,8 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V6_PCS_USB3_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V6_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_CLAMP_ENABLE] = QPHY_V6_PCS_AON_CLAMP_ENABLE, + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS,
@@ -198,6 +210,8 @@ static const unsigned int qmp_v6_n4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V6_PCS_USB3_AUTONOMOUS_MODE_CTRL, [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V6_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_CLAMP_ENABLE] = QPHY_V6_PCS_AON_CLAMP_ENABLE, + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS,
@@ -1740,6 +1754,7 @@ struct qmp_combo_offsets {u16 usb3_serdes;u16 usb3_pcs_misc;u16 usb3_pcs; +u16 usb3_pcs_aon;u16 usb3_pcs_usb;u16 dp_serdes;u16 dp_txa;
@@ -1821,6 +1836,7 @@ struct qmp_combo {void __iomem *tx2;void __iomem *rx2;void __iomem *pcs_misc; +void __iomem *pcs_aon;void __iomem *pcs_usb;void __iomem *dp_serdes;
@@ -1941,6 +1957,7 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v8 = { .usb3_serdes = 0x1000, .usb3_pcs_misc = 0x1c00, .usb3_pcs = 0x1e00, + .usb3_pcs_aon = 0x2000, .usb3_pcs_usb = 0x2100, .dp_serdes = 0x3000, .dp_txa = 0x3400,
@@ -3301,6 +3318,7 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp)const struct qmp_phy_cfg *cfg = qmp->cfg;void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;void __iomem *pcs_misc = qmp->pcs_misc; +void __iomem *pcs_aon = qmp->pcs_aon;u32 intr_mask; if (qmp->mode == PHY_MODE_USB_HOST_SS ||
@@ -3320,9 +3338,14 @@ static void qmp_combo_enable_autonomous_mode(struct qmp_combo *qmp)/* Enable required PHY autonomous mode interrupts */ qphy_setbits (pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL ], intr_mask); -/* Enable i/o clamp_n for autonomous mode */ -if (pcs_misc) -qphy_clrbits (pcs_misc,QPHY_V3_PCS_MISC_CLAMP_ENABLE ,CLAMP_EN ); +/* +* Enable i/o clamp_n for autonomous mode +* V6 and later versions use pcs aon clamp register +*/ +if (pcs_aon) +qphy_clrbits (pcs_aon, cfg->regs[QPHY_PCS_CLAMP_ENABLE ],CLAMP_EN ); +else if (pcs_misc) +qphy_clrbits (pcs_misc, cfg->regs[QPHY_PCS_CLAMP_ENABLE ],CLAMP_EN ); }static void qmp_combo_disable_autonomous_mode (struct qmp_combo *qmp)
@@ -3330,10 +3353,13 @@ static void qmp_combo_disable_autonomous_mode(struct qmp_combo *qmp)const struct qmp_phy_cfg *cfg = qmp->cfg;void __iomem *pcs_usb = qmp->pcs_usb ?: qmp->pcs;void __iomem *pcs_misc = qmp->pcs_misc; +void __iomem *pcs_aon = qmp->pcs_aon;/* Disable i/o clamp_n on resume for normal mode */ -if (pcs_misc) -qphy_setbits (pcs_misc,QPHY_V3_PCS_MISC_CLAMP_ENABLE ,CLAMP_EN ); +if (pcs_aon) +qphy_setbits (pcs_aon, cfg->regs[QPHY_PCS_CLAMP_ENABLE ],CLAMP_EN ); +else if (pcs_misc) +qphy_setbits (pcs_misc, cfg->regs[QPHY_PCS_CLAMP_ENABLE ],CLAMP_EN );qphy_clrbits (pcs_usb, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL ],ARCVR_DTCT_EN |ARCVR_DTCT_EVENT_SEL |ALFPS_DTCT_EN );
@@ -3893,6 +3919,8 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp) qmp->serdes = base + offs->usb3_serdes; qmp->pcs_misc = base + offs->usb3_pcs_misc; qmp->pcs = base + offs->usb3_pcs; +if (offs->usb3_pcs_aon) + qmp->pcs_aon = base + offs->usb3_pcs_aon; qmp->pcs_usb = base + offs->usb3_pcs_usb; qmp->dp_serdes = base + offs->dp_serdes;
drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v6.h new file +12 -0
@@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_PCS_AON_V6_H_ +#define QCOM_PHY_QMP_PCS_AON_V6_H_ + +/* Only for QMP V6 PHY - PCS_AON registers */ +#define QPHY_V6_PCS_AON_CLAMP_ENABLE 0x00 + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v5.h new file +12 -0
@@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_PCS_MISC_V5_H_ +#define QCOM_PHY_QMP_PCS_MISC_V5_H_ + +/* Only for QMP V5 PHY - PCS_MISC registers */ +#define QPHY_V5_PCS_MISC_CLAMP_ENABLE 0x0c + +#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1043/1376 phy: qualcomm: qmp-combo: Update QMP PHY with Glymur settings
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wesley Cheng <[email protected]>
[ Upstream commit 5b289913959b9bc93bab9e0beeab269c33c969b7 ]
For SuperSpeed USB to work properly, there is a set of HW settings that need to be programmed into the USB blocks within the QMP PHY. Ensure that these settings follow the latest settings mentioned in the HW programming guide. The QMP USB PHY on Glymur is a USB43 based PHY that will have some new ways to define certain registers, such as the replacement of TXA/RXA and TXB/RXB register sets. This was replaced with the LALB register set.
There are also some PHY init updates to modify the PCS MISC register space. Without these, the QMP PHY PLL locking fails.
Stable-dep-of: 8fd2b30d187f ("phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy")
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 285 ++++++++ .../phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h | 17 + .../phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h | 12 + .../qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h | 639 ++++++++++++++++++ .../phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h | 33 + .../phy-qcom-qmp-usb43-qserdes-com-v8.h | 224 ++++++ drivers/phy/qualcomm/phy-qcom-qmp.h | 2 + 7 files changed, 1212 insertions(+) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-usb43-qserdes-com-v8.h
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +285 -0
@@ -29,9 +29,11 @@#include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-aon-v6.h" +#include "phy-qcom-qmp-pcs-aon-v8.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-misc-v4.h" #include "phy-qcom-qmp-pcs-misc-v5.h" +#include "phy-qcom-qmp-pcs-misc-v8.h" #include "phy-qcom-qmp-pcs-usb-v4.h" #include "phy-qcom-qmp-pcs-usb-v5.h" #include "phy-qcom-qmp-pcs-usb-v6.h"
@@ -45,6 +47,8 @@#include "phy-qcom-qmp-dp-phy-v5.h" #include "phy-qcom-qmp-dp-phy-v6.h" +#include "phy-qcom-qmp-usb43-pcs-v8.h" +/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ /* DP PHY soft reset */ #define SW_DPPHY_RESET BIT(0)
@@ -90,6 +94,7 @@ enum qphy_reg_layout {QPHY_TX_HIGHZ_DRVR_EN ,QPHY_TX_TRANSCEIVER_BIAS_EN , +QPHY_AON_TOGGLE_ENABLE ,/* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE };
@@ -249,6 +254,233 @@ static const unsigned int qmp_v8_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V8_TX_TRANSCEIVER_BIAS_EN, }; +static const unsigned int qmp_v8_n3_usb43dpphy_regs_layout[QPHY_LAYOUT_SIZE ] = { + [QPHY_SW_RESET ] =QPHY_V8_USB43_PCS_SW_RESET , + [QPHY_START_CTRL ] =QPHY_V8_USB43_PCS_START_CONTROL , + [QPHY_PCS_STATUS ] =QPHY_V8_USB43_PCS_PCS_STATUS1 , + [QPHY_PCS_POWER_DOWN_CONTROL ] =QPHY_V8_USB43_PCS_POWER_DOWN_CONTROL , + +/* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL ] =QPHY_V8_PCS_USB_AUTONOMOUS_MODE_CTRL , + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR ] =QPHY_V8_PCS_USB_LFPS_RXTERM_IRQ_CLEAR , + + [QPHY_PCS_CLAMP_ENABLE ] =QPHY_V8_PCS_AON_USB3_AON_CLAMP_ENABLE , + [QPHY_AON_TOGGLE_ENABLE ] =QPHY_V8_PCS_AON_USB3_AON_TOGGLE_ENABLE , + + [QPHY_COM_RESETSM_CNTRL ] =QSERDES_V8_COM_RESETSM_CNTRL , + [QPHY_COM_C_READY_STATUS ] =QSERDES_V8_COM_C_READY_STATUS , + [QPHY_COM_CMN_STATUS ] =QSERDES_V8_COM_CMN_STATUS , + [QPHY_COM_BIAS_EN_CLKBUFLR_EN ] =QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN , + + [QPHY_TX_TX_DRV_LVL ] =QSERDES_V8_LALB_TX0_DRV_LVL , + [QPHY_TX_TX_EMP_POST1_LVL ] =QSERDES_V8_LALB_TX0_EMP_POST1_LVL , + [QPHY_TX_HIGHZ_DRVR_EN ] =QSERDES_V8_LALB_HIGHZ_DRVR_EN , + [QPHY_TX_TRANSCEIVER_BIAS_EN ] =QSERDES_V8_LALB_TRANSMITTER_EN_CTRL , +}; + +static const struct qmp_phy_init_tbl glymur_usb43dp_serdes_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE1 ,0xe1 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CP_CTRL_MODE1 ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_RCTRL_MODE1 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_CCTRL_MODE1 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORECLK_DIV_MODE1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP1_MODE1 ,0x1a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP2_MODE1 ,0x41 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MODE1 ,0x41 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MSB_MODE1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE1 ,0xab ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE1 ,0xaa ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_HSCLK_SEL_1 ,0x13 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE1 ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE1_MODE1 ,0x4d ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE2_MODE1 ,0x03 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE1 ,0x95 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE1 ,0x1e ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0x4b ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0 ,0xe1 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CP_CTRL_MODE0 ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0 ,0x1a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MODE0 ,0x41 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MSB_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0 ,0xab ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0 ,0xaa ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_HSCLK_HS_SWITCH_SEL_1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0 ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0 ,0x4d ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0 ,0x03 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BG_TIMER ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_EN_CENTER ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_PER1 ,0x62 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_PER2 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_IVCO ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_IVCO_MODE1 ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYSCLK_EN_SEL ,0x1a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP_EN ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP_CFG ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE_CTRL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE_MAP ,0x14 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORE_CLK_EN ,0xa0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_CONFIG_1 ,0x76 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_SPARE_FOR_ECO ,0x40 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DCC_CAL_1 ,0x40 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DCC_CAL_2 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DCC_CAL_3 ,0x60 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PSM_CAL_EN ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1 ,0x33 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL ,0xaf ), +}; + +static const struct qmp_phy_init_tbl glymur_usb43dp_pcs_misc_tbl[] = { +QMP_PHY_INIT_CFG (QPHY_V8_PCS_MISC_PCS_MISC_CONFIG1 ,0x01 ), +}; + +static const struct qmp_phy_init_tbl glymur_usb43dp_pcs_tbl[] = { +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG1 ,0xc4 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG2 ,0x89 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG3 ,0x20 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG6 ,0x13 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_REFGEN_REQ_CONFIG1 ,0x21 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_RX_SIGDET_LVL ,0x55 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_L ,0xe7 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_H ,0x03 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_TSYNC_RSYNC_TIME ,0xa4 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_RX_CONFIG ,0x0a ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_TSYNC_DLY_TIME ,0x04 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG1 ,0xd4 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG2 ,0x30 ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_PCS_TX_RX_CONFIG ,0x0c ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_EQ_CONFIG1 ,0x4b ), +QMP_PHY_INIT_CFG (QPHY_V8_USB43_PCS_EQ_CONFIG5 ,0x10 ), +}; + +static const struct qmp_phy_init_tbl glymur_usb43dp_pcs_usb_tbl[] = { +QMP_PHY_INIT_CFG (QPHY_V8_PCS_USB_LFPS_DET_HIGH_COUNT_VAL ,0xf8 ), +QMP_PHY_INIT_CFG (QPHY_V8_PCS_USB_RXEQTRAINING_DFE_TIME_S2 ,0x07 ), +}; + +static const struct qmp_phy_init_tbl glymur_usb43dp_lalb_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CLKBUF_ENABLE ,0x81 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX_LVL_UPDATE_CTRL ,0x0d ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL3 ,0x80 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_PCIE5_TOP_LDO_CODE_CTRL4 ,0x8D ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TRANSMITTER_EN_CTRL ,0x13 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_1 ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_3 ,0x11 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_4 ,0x11 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_RESTRIM_CAL_CTRL ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_RESTRIM_CAL_CTRL ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_RESTRIM_POST_CAL_OFFSET ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_RESTRIM_VREF_SEL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_RESTRIM_VREF_SEL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_ANA_INTERFACE_SELECT2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_PCS_INTERFACE_SELECT1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B0 ,0xa4 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B1 ,0xa2 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B2 ,0x6e ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B3 ,0x51 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B4 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B5 ,0x26 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B6 ,0x12 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE_0_1_B7 ,0x2a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B0 ,0x4c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B1 ,0xc4 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B2 ,0x38 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B3 ,0x64 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B4 ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B5 ,0x4b ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B6 ,0x12 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_MODE_RATE2_B7 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX_DCC_ANA_CTRL2 ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE1 ,0x26 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE1 ,0x26 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT1_RATE2 ,0x26 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_CTUNE_MEAS_CNT2_RATE2 ,0x26 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_INIT_RATE_0_1 ,0x11 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_INIT_RATE_2_3 ,0x11 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE1 ,0x03 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_CODE_OVRD_RATE2 ,0x03 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE1 ,0x15 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF1_RATE2 ,0x22 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KVCO_IDEAL_FREQ_DIFF2_RATE2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CODE_OVRD_RATE_2_3 ,0x22 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE1 ,0xff ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND1_RATE2 ,0xff ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CAL_UPPER_FREQ_DIFF_BND2_RATE2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE1 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_KP_CAL_LOWER_FREQ_DIFF_BND_RATE2 ,0x09 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_SUMMER_CAL_SPD_MODE_RATE_0123 ,0x2f ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_IVCM_CAL_CODE_OVERRIDE_RATE2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_IVCM_CAL_CTRL2 ,0x85 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_IVCM_CAL_CTRL3 ,0x45 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_IVCM_POSTCAL_OFFSET_RATE2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_ENABLES ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_CNTRL ,0xa3 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_LVL ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_DEGLITCH_CNTRL ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_CAL_CTRL1 ,0x14 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_CAL_CTRL2_AND_CDR_LOCK_EDGE ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_SIGDET_CAL_TRIM ,0x66 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE1 ,0xff ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_FREQ_LOCK_DET_DLY_RATE2 ,0x32 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE1 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_CP_CUR_FLL_RATE2 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_CP_CUR_PLL_RATE2 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE_01 ,0x76 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_CCODE_RATE_23 ,0x67 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE_0_1 ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_RCODE_FAST_RATE_2_3 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE_0_1 ,0x33 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_RCODE_FLL_RATE_2_3 ,0x43 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE_0_1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_RCODE_PLL_RATE_2_3 ,0x51 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_FLL_DIV_RATIO_RATE_0123 ,0xe5 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_CAP_CODE_RATE_0123 ,0xf5 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_TYPE_CONFIG ,0x1f ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_EN_LOWFREQ ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_LOOP_FUNC_CTRL ,0xd0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_GM_CAL_EN ,0x1f ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_GM_CAL_RES_RATE0_1 ,0x88 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_GM_CAL_RES_RATE2_3 ,0x88 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_AUX_CLK_CTRL ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_EOM_CTRL1 ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL2 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL3 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RX_EQU_ADAPTOR_CNTRL4 ,0xaa ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CTLE_POST_CAL_OFFSET_RATE_0_1_2 ,0x77 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_VGA_CAL_CNTRL1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE0_1 ,0xdd ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_VGA_CAL_MAN_VAL_RATE2_3 ,0xd8 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_DFE_TAP1_DAC_ENABLE ,0x1c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_DFE_TAP2_DAC_ENABLE ,0x1c ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_DFE_TAP345_DAC_ENABLE ,0x18 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_DFE_TAP67_DAC_ENABLE ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_IQTUNE_CTRL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_IQTUNE_MAN_INDEX ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_IQTUNE_DIV2_CTRL_RATE0123 ,0x1C ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CDR_VCO_CAP_CODE_OVRD_MUXES ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_DIG_BKUP_CTRL16 ,0x37 ), +}; +static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = {QMP_PHY_INIT_CFG (QSERDES_V3_COM_PLL_IVCO ,0x07 ),QMP_PHY_INIT_CFG (QSERDES_V3_COM_SYSCLK_EN_SEL ,0x14 ),
@@ -1652,6 +1884,12 @@ static struct regulator_bulk_data qmp_phy_vreg_l[] = { { .supply = "vdda-pll", .init_load_uA = 36000, }, }; +static struct regulator_bulk_data qmp_phy_vreg_refgen[] = { + { .supply ="vdda-phy" , .init_load_uA =21800 }, + { .supply ="vdda-pll" , .init_load_uA =36000 }, + { .supply ="refgen" , .init_load_uA =3270 }, +}; +static const u8 qmp_dp_v3_pre_emphasis_hbr3_hbr2[4 ][4 ] = { {0x00 ,0x0c ,0x15 ,0x1a }, {0x02 ,0x0e ,0x16 ,0xff },
@@ -1776,6 +2014,8 @@ struct qmp_phy_cfg {int pcs_tbl_num;const struct qmp_phy_init_tbl *pcs_usb_tbl;int pcs_usb_tbl_num; +const struct qmp_phy_init_tbl *pcs_misc_tbl; +int pcs_misc_tbl_num;const struct qmp_phy_init_tbl *dp_serdes_tbl;int dp_serdes_tbl_num;
@@ -1965,6 +2205,19 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v8 = { .dp_dp_phy = 0x3c00, }; +static const struct qmp_combo_offsets qmp_combo_usb43dp_offsets_v8 = { + .com =0x0000 , + .usb3_pcs_aon =0x0100 , + .usb3_serdes =0x1000 , + .usb3_pcs_misc =0x1400 , + .usb3_pcs =0x1600 , + .usb3_pcs_usb =0x1900 , + .dp_serdes =0x2000 , + .dp_dp_phy =0x2400 , + .txa =0x4000 , + .txb =0x5000 , +}; +static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = { .offsets = &qmp_combo_offsets_v3,
@@ -2509,6 +2762,27 @@ static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), }; +static const struct qmp_phy_cfg glymur_usb3dpphy_cfg = { + .offsets = &qmp_combo_usb43dp_offsets_v8, + + .serdes_tbl = glymur_usb43dp_serdes_tbl, + .serdes_tbl_num =ARRAY_SIZE (glymur_usb43dp_serdes_tbl), + .tx_tbl = glymur_usb43dp_lalb_tbl, + .tx_tbl_num =ARRAY_SIZE (glymur_usb43dp_lalb_tbl), + .pcs_tbl = glymur_usb43dp_pcs_tbl, + .pcs_tbl_num =ARRAY_SIZE (glymur_usb43dp_pcs_tbl), + .pcs_usb_tbl = glymur_usb43dp_pcs_usb_tbl, + .pcs_usb_tbl_num =ARRAY_SIZE (glymur_usb43dp_pcs_usb_tbl), + .pcs_misc_tbl = glymur_usb43dp_pcs_misc_tbl, + .pcs_misc_tbl_num =ARRAY_SIZE (glymur_usb43dp_pcs_misc_tbl), + + .regs = qmp_v8_n3_usb43dpphy_regs_layout, + .reset_list = msm8996_usb3phy_reset_l, + .num_resets =ARRAY_SIZE (msm8996_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_refgen, + .num_vregs =ARRAY_SIZE (qmp_phy_vreg_refgen), +}; +static int qmp_combo_dp_serdes_init (struct qmp_combo *qmp) {const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -3005,6 +3279,7 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) {const struct qmp_phy_cfg *cfg = qmp->cfg;void __iomem *com = qmp->com; +void __iomem *pcs_aon = qmp->pcs_aon;int ret;u32 val;
@@ -3040,6 +3315,10 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)SW_DPPHY_RESET_MUX |SW_DPPHY_RESET | SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); +/* override hardware control for reset of qmp phy */ +if (pcs_aon && cfg->regs[QPHY_AON_TOGGLE_ENABLE ]) +qphy_clrbits (pcs_aon, cfg->regs[QPHY_AON_TOGGLE_ENABLE ],0x1 ); +/* Use software based port select and switch on typec orientation */ val =SW_PORTSELECT_MUX ;if (qmp->orientation ==TYPEC_ORIENTATION_REVERSE )
@@ -3192,6 +3471,8 @@ static int qmp_combo_usb_power_on(struct phy *phy)qmp_configure_lane (qmp->dev, rx2, cfg->rx_tbl, cfg->rx_tbl_num,2 );qmp_configure (qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); +qmp_configure (qmp->dev, qmp->pcs_misc, cfg->pcs_misc_tbl, cfg->pcs_misc_tbl_num); +if (pcs_usb) qmp_configure(qmp->dev, pcs_usb, cfg->pcs_usb_tbl,
@@ -4071,6 +4352,10 @@ static int qmp_combo_probe(struct platform_device *pdev) }static const struct of_device_id qmp_combo_of_match_table[] = { + { + .compatible ="qcom,glymur-qmp-usb3-dp-phy" , + .data = &glymur_usb3dpphy_cfg, + }, { .compatible ="qcom,sar2130p-qmp-usb3-dp-phy" , .data = &sar2130p_usb3dpphy_cfg,
drivers/phy/qualcomm/phy-qcom-qmp-pcs-aon-v8.h new file +17 -0
@@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025, Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_PCS_AON_V8_H_ +#define QCOM_PHY_QMP_PCS_AON_V8_H_ + +/* Only for QMP V8 PHY - PCS_AON registers */ +#define QPHY_V8_PCS_AON_USB3_AON_CLAMP_ENABLE 0x00 +#define QPHY_V8_PCS_AON_USB4_AON_CLAMP_ENABLE 0x04 +#define QPHY_V8_PCS_AON_USB3_AON_TOGGLE_ENABLE 0x08 +#define QPHY_V8_PCS_AON_USB4_AON_TOGGLE_ENABLE 0x0c +#define QPHY_V8_PCS_AON_DP_AON_TOGGLE_ENABLE 0x10 +#define QPHY_V8_PCS_AON_DUMMY_STATUS 0x14 + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-pcs-misc-v8.h new file +12 -0
@@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_PCS_MISC_V8_H_ +#define QCOM_PHY_QMP_PCS_MISC_V8_H_ + +/* Only for QMP V8 PHY - PCS_MISC registers */ +#define QPHY_V8_PCS_MISC_PCS_MISC_CONFIG1 0x08 + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-qserdes-lalb-v8.h new file +639 -0
639 lines not on this page · raw message
drivers/phy/qualcomm/phy-qcom-qmp-usb43-pcs-v8.h new file +33 -0
@@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_USB43_PCS_V8_H_ +#define QCOM_PHY_QMP_USB43_PCS_V8_H_ + +#define QPHY_V8_USB43_PCS_SW_RESET 0x000 +#define QPHY_V8_USB43_PCS_PCS_STATUS1 0x014 +#define QPHY_V8_USB43_PCS_POWER_DOWN_CONTROL 0x040 +#define QPHY_V8_USB43_PCS_START_CONTROL 0x044 +#define QPHY_V8_USB43_PCS_POWER_STATE_CONFIG1 0x090 +#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG1 0x0c4 +#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG2 0x0c8 +#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG3 0x0cc +#define QPHY_V8_USB43_PCS_LOCK_DETECT_CONFIG6 0x0d8 +#define QPHY_V8_USB43_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V8_USB43_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 +#define QPHY_V8_USB43_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 +#define QPHY_V8_USB43_PCS_RATE_SLEW_CNTRL1 0x198 +#define QPHY_V8_USB43_PCS_TSYNC_RSYNC_TIME 0x1ac +#define QPHY_V8_USB43_PCS_RX_CONFIG 0x1b0 +#define QPHY_V8_USB43_PCS_TSYNC_DLY_TIME 0x1b4 +#define QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG1 0x1c0 +#define QPHY_V8_USB43_PCS_ALIGN_DETECT_CONFIG2 0x1c4 +#define QPHY_V8_USB43_PCS_PCS_TX_RX_CONFIG 0x1d0 +#define QPHY_V8_USB43_PCS_EQ_CONFIG1 0x1dc +#define QPHY_V8_USB43_PCS_EQ_CONFIG2 0x1e0 +#define QPHY_V8_USB43_PCS_EQ_CONFIG5 0x1ec + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-usb43-qserdes-com-v8.h new file +224 -0
224 lines not on this page · raw message
drivers/phy/qualcomm/phy-qcom-qmp.h +2 -0
@@ -31,7 +31,9 @@#include "phy-qcom-qmp-qserdes-txrx-v7.h" #include "phy-qcom-qmp-qserdes-com-v8.h" +#include "phy-qcom-qmp-usb43-qserdes-com-v8.h" #include "phy-qcom-qmp-qserdes-txrx-v8.h" +#include "phy-qcom-qmp-qserdes-lalb-v8.h" #include "phy-qcom-qmp-qserdes-pll.h"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1044/1376 phy: qualcomm: qmp-combo: Add DP offsets and settings for Glymur platforms
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abel Vesa <[email protected]>
[ Upstream commit d10736db98d25c97bdffacaca69ae0a8d7ca64e3 ]
Starting with Glymur, the PCIe and DP PHYs qserdes register offsets differ for the same version number. So in order to be able to differentiate between them, add these ones with DP prefix.
Add the necessary PHY setting tables for enabling the DP path within the QMP subsystem. Introduced some new callbacks for v8 specific sequences, such as for clock configurations based on the different link speeds.
Wesley Cheng added some updated settings from the hardware programming guides on existing PHY tables and clock settings.
Stable-dep-of: 8fd2b30d187f ("phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy")
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 355 +++++++++++++++++- drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h | 25 ++ .../qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h | 52 +++ 3 files changed, 428 insertions(+), 4 deletions(-) create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +351 -4
@@ -46,6 +46,7 @@#include "phy-qcom-qmp-dp-phy-v4.h" #include "phy-qcom-qmp-dp-phy-v5.h" #include "phy-qcom-qmp-dp-phy-v6.h" +#include "phy-qcom-qmp-dp-phy-v8.h" #include "phy-qcom-qmp-usb43-pcs-v8.h"
@@ -95,6 +96,7 @@ enum qphy_reg_layout {QPHY_TX_TRANSCEIVER_BIAS_EN ,QPHY_AON_TOGGLE_ENABLE , +QPHY_DP_AON_TOGGLE_ENABLE ,/* Keep last to ensure regs_layout arrays are properly initialized */ QPHY_LAYOUT_SIZE };
@@ -266,12 +268,16 @@ static const unsigned int qmp_v8_n3_usb43dpphy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_CLAMP_ENABLE] = QPHY_V8_PCS_AON_USB3_AON_CLAMP_ENABLE, [QPHY_AON_TOGGLE_ENABLE] = QPHY_V8_PCS_AON_USB3_AON_TOGGLE_ENABLE, + [QPHY_DP_AON_TOGGLE_ENABLE] = QPHY_V8_PCS_AON_DP_AON_TOGGLE_ENABLE, [QPHY_COM_RESETSM_CNTRL] = QSERDES_V8_COM_RESETSM_CNTRL, [QPHY_COM_C_READY_STATUS] = QSERDES_V8_COM_C_READY_STATUS, [QPHY_COM_CMN_STATUS] = QSERDES_V8_COM_CMN_STATUS, [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V8_COM_BIAS_EN_CLKBUFLR_EN, + [QPHY_DP_PHY_STATUS] = QSERDES_V8_DP_PHY_STATUS, + [QPHY_DP_PHY_VCO_DIV] = QSERDES_V8_DP_PHY_VCO_DIV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V8_LALB_TX0_DRV_LVL, [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V8_LALB_TX0_EMP_POST1_LVL, [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V8_LALB_HIGHZ_DRVR_EN,
@@ -1367,6 +1373,38 @@ static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x0f), }; +static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CP_CTRL_MODE0 ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_RCTRL_MODE1 ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_CCTRL_MODE1 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0 ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0 ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BG_TIMER ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_EN_CENTER ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_ADJ_PER1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_PER1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_PER2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_ENABLE1 ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYS_CLK_CTRL ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_IVCO ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYSCLK_EN_SEL ,0x3b ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP_EN ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE_CTRL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE_MAP ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_SELECT ,0x30 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORE_CLK_EN ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_CONFIG_1 ,0x56 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL ,0x15 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_MODE_CONTD1 ,0x24 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DCC_CAL_1 ,0x40 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DCC_CAL_3 ,0x60 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PSM_CAL_EN ,0x01 ), +}; +static const struct qmp_phy_init_tbl qmp_v6_dp_tx_tbl[] = {QMP_PHY_INIT_CFG (QSERDES_V6_TX_VMODE_CTRL1 ,0x40 ),QMP_PHY_INIT_CFG (QSERDES_V6_TX_PRE_STALL_LDO_BOOST_EN ,0x30 ),
@@ -1394,6 +1432,33 @@ static const struct qmp_phy_init_tbl qmp_v6_n4_dp_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_TX_BAND, 0x1), }; +static const struct qmp_phy_init_tbl qmp_v8_n3p_dp_tx_tbl[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TRANSMITTER_EN_CTRL ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_VMODE_CTRL1 ,0x40 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_ANA_INTERFACE_SELECT1 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_ANA_INTERFACE_SELECT2 ,0x18 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_PCS_INTERFACE_SELECT1 ,0x50 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_1 ,0x0d ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_CLKBUF_ENABLE ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_RESET_TSYNC_EN_CTRL ,0x0a ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX_LVL_UPDATE_CTRL ,0x0f ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TRAN_DRVR_EMP_EN ,0x5f ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_EMP_POST1_LVL ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_EMP_POST1_LVL ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_PRE1_EMPH ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_PRE1_EMPH ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_DRV_LVL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_DRV_LVL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_HIGHZ_DRVR_EN ,0x30 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_2 ,0x50 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_LANE_MODE_3 ,0x51 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX_DCC_ANA_CTRL2 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_RESTRIM_CAL_CTRL ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_RESTRIM_CAL_CTRL ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX0_RESTRIM_POST_CAL_OFFSET ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_LALB_TX1_RESTRIM_POST_CAL_OFFSET ,0x10 ), +}; +static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_rbr[] = {QMP_PHY_INIT_CFG (QSERDES_V6_COM_HSCLK_SEL_1 ,0x05 ),QMP_PHY_INIT_CFG (QSERDES_V6_COM_DEC_START_MODE0 ,0x34 ),
@@ -1510,6 +1575,109 @@ static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl_hbr3[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), }; +static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_rbr[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_HSCLK_SEL_1 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0x7a ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0 ,0x83 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0 ,0x37 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MODE0 ,0x54 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0 ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0 ,0xfe ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_MODE_CONTD3 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1 ,0x30 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL ,0xa4 ), +}; + +static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_hbr[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_HSCLK_SEL_1 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0x21 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0 ,0x18 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MODE0 ,0x46 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0 ,0xae ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1 ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_MODE_CONTD3 ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1 ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL ,0xa3 ), +}; + +static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_hbr2[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_HSCLK_SEL_1 ,0x03 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0xf6 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0 ,0x0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0 ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0 ,0x0e ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MODE0 ,0x46 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0 ,0xae ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL ,0xbf ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIAS_EN_CLKBUFLR_EN ,0x1c ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_RESETSM_CNTRL ,0x20 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_MODE_CONTD3 ,0x03 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1 ,0x3f ), +}; + +static const struct qmp_phy_init_tbl qmp_v8_dp_serdes_tbl_hbr3[] = { +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_HSCLK_SEL_1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE1_MODE0 ,0x63 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_CMP_CODE2_MODE0 ,0x0c ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE1_MODE0 ,0x5b ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_STEP_SIZE2_MODE0 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CP_CTRL_MODE0 ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_RCTRL_MODE0 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_CCTRL_MODE0 ,0x36 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORECLK_DIV_MODE0 ,0x0a ), + +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP1_MODE0 ,0x17 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_LOCK_CMP2_MODE0 ,0x15 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DEC_START_MODE0 ,0x4f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START1_MODE0 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START2_MODE0 ,0xa0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_DIV_FRAC_START3_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_INTEGLOOP_GAIN0_MODE0 ,0x3f ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_INTEGLOOP_GAIN1_MODE0 ,0x00 ), + +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE1_MODE0 ,0xa0 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE2_MODE0 ,0x01 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_ADJ_PER1 ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_PER1 ,0x6b ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SSC_PER2 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_ENABLE1 ,0x0c ), + +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYS_CLK_CTRL ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYSCLK_BUF_ENABLE ,0x06 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_PLL_IVCO ,0x07 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SYSCLK_EN_SEL ,0x04 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE_CTRL ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_VCO_TUNE_MAP ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_SELECT ,0x30 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CORE_CLK_EN ,0x00 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_CONFIG_1 ,0x16 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_SVS_MODE_CLK_SEL ,0x15 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CLK_FWD_CONFIG_1 ,0x30 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIAS_EN_CLKBUFLR_EN ,0x10 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_MODE_CONTD3 ,0x05 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_CMN_MODE_CONTD1 ,0x24 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_BIN_VCOCAL_HSCLK_SEL_1 ,0x02 ), +QMP_PHY_INIT_CFG (QSERDES_V8_USB43_COM_IP_CTRL_AND_DP_SEL ,0x84 ), +}; +static const struct qmp_phy_init_tbl sc8280xp_usb43dp_serdes_tbl[] = {QMP_PHY_INIT_CFG (QSERDES_V5_COM_SSC_EN_CENTER ,0x01 ),QMP_PHY_INIT_CFG (QSERDES_V5_COM_SSC_PER1 ,0x31 ),
@@ -2039,6 +2207,7 @@ struct qmp_phy_cfg {const u8 (*pre_emphasis_hbr3_hbr2)[4 ][4 ];/* DP PHY callbacks */ +int (*configure_dp_clocks)(struct qmp_combo *qmp);int (*configure_dp_phy)(struct qmp_combo *qmp);void (*configure_dp_tx)(struct qmp_combo *qmp);int (*calibrate_dp_phy)(struct qmp_combo *qmp);
@@ -2112,6 +2281,7 @@ struct qmp_combo {static void qmp_v3_dp_aux_init (struct qmp_combo *qmp);static void qmp_v3_configure_dp_tx (struct qmp_combo *qmp); +static int qmp_v3_configure_dp_clocks (struct qmp_combo *qmp);static int qmp_v3_configure_dp_phy (struct qmp_combo *qmp);static int qmp_v3_calibrate_dp_phy (struct qmp_combo *qmp);
@@ -2120,6 +2290,10 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp);static int qmp_v4_configure_dp_phy (struct qmp_combo *qmp);static int qmp_v4_calibrate_dp_phy (struct qmp_combo *qmp); +static void qmp_v8_dp_aux_init (struct qmp_combo *qmp); +static int qmp_v8_configure_dp_clocks (struct qmp_combo *qmp); +static int qmp_v8_configure_dp_phy (struct qmp_combo *qmp); +static inline void qphy_setbits (void __iomem *base,u32 offset,u32 val) {u32 reg;
@@ -2253,6 +2427,7 @@ static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2388,6 +2563,7 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2434,6 +2610,7 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2479,6 +2656,7 @@ static const struct qmp_phy_cfg x1e80100_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2567,6 +2745,7 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2615,6 +2794,7 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2662,6 +2842,7 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2707,6 +2888,7 @@ static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2752,6 +2934,7 @@ static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = { .dp_aux_init = qmp_v4_dp_aux_init, .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
@@ -2776,6 +2959,31 @@ static const struct qmp_phy_cfg glymur_usb3dpphy_cfg = { .pcs_misc_tbl = glymur_usb43dp_pcs_misc_tbl, .pcs_misc_tbl_num = ARRAY_SIZE(glymur_usb43dp_pcs_misc_tbl), + .dp_serdes_tbl = qmp_v8_dp_serdes_tbl, + .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl), + .dp_tx_tbl = qmp_v8_n3p_dp_tx_tbl, + .dp_tx_tbl_num = ARRAY_SIZE(qmp_v8_n3p_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v8_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v8_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v8_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v8_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v8_dp_serdes_tbl_hbr3), + + .swing_hbr_rbr = &qmp_dp_v6_voltage_swing_hbr_rbr, + .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr, + .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2, + .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2, + + .dp_aux_init = qmp_v8_dp_aux_init, + .configure_dp_tx = qmp_v4_configure_dp_tx, + .configure_dp_clocks = qmp_v8_configure_dp_clocks, + .configure_dp_phy = qmp_v8_configure_dp_phy, + .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, + .regs = qmp_v8_n3_usb43dpphy_regs_layout, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2945,7 +3153,7 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)return reverse; } -static int qmp_combo_configure_dp_clocks (struct qmp_combo *qmp) +static int qmp_v3_configure_dp_clocks (struct qmp_combo *qmp) {const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;u32 phy_vco_div;
@@ -2992,7 +3200,7 @@ static int qmp_v3_configure_dp_phy(struct qmp_combo *qmp)writel (0x05 , qmp->dp_dp_phy +QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL );writel (0x05 , qmp->dp_dp_phy +QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL ); - ret =qmp_combo_configure_dp_clocks (qmp); + ret =qmp_v3_configure_dp_clocks (qmp);if (ret)return ret;
@@ -3078,6 +3286,35 @@ static void qmp_v4_dp_aux_init(struct qmp_combo *qmp) qmp->dp_dp_phy + QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK); } +static void qmp_v8_dp_aux_init (struct qmp_combo *qmp) +{ +const struct qmp_phy_cfg *cfg = qmp->cfg; + +writel (DP_PHY_PD_CTL_PWRDN |DP_PHY_PD_CTL_PSR_PWRDN |DP_PHY_PD_CTL_AUX_PWRDN | +DP_PHY_PD_CTL_PLL_PWRDN |DP_PHY_PD_CTL_DP_CLAMP_EN , + qmp->dp_dp_phy +QSERDES_DP_PHY_PD_CTL ); + +/* Turn on BIAS current for PHY/PLL */ +writel (0x1c , qmp->dp_serdes + cfg->regs[QPHY_COM_BIAS_EN_CLKBUFLR_EN ]); + +writel (0x00 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG0 ); +writel (0x13 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG1 ); +writel (0x06 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG2 ); +writel (0x00 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG3 ); +writel (0x0a , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG4 ); +writel (0x26 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG5 ); +writel (0x0a , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG6 ); +writel (0x03 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG7 ); +writel (0xb7 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG8 ); +writel (0x03 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG9 ); + qmp->dp_aux_cfg =0 ; + +writel (PHY_AUX_STOP_ERR_MASK |PHY_AUX_DEC_ERR_MASK | +PHY_AUX_SYNC_ERR_MASK |PHY_AUX_ALIGN_ERR_MASK | +PHY_AUX_REQ_ERR_MASK , + qmp->dp_dp_phy +QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK ); +} +static void qmp_v4_configure_dp_tx (struct qmp_combo *qmp) {const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -3092,6 +3329,58 @@ static void qmp_v4_configure_dp_tx(struct qmp_combo *qmp)qmp_combo_configure_dp_swing (qmp); } +static int qmp_v8_configure_dp_clocks (struct qmp_combo *qmp) +{ +const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; +u32 phy_vco_div; +unsigned long pixel_freq; +const struct qmp_phy_cfg *cfg = qmp->cfg; + +switch (dp_opts->link_rate) { +case 1620 : + phy_vco_div =0x4 ; + pixel_freq =1620000000UL /2 ; +break ; +case 2700 : + phy_vco_div =0x2 ; + pixel_freq =2700000000UL /2 ; +break ; +case 5400 : + phy_vco_div =0x4 ; + pixel_freq =5400000000UL /4 ; +break ; +case 8100 : + phy_vco_div =0x3 ; + pixel_freq =8100000000UL /6 ; +break ; +default : +/* Other link rates aren't supported */ +return -EINVAL ; + } +writel (phy_vco_div, qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_VCO_DIV ]); + +/* disable core reset tsync */ +writel (0x09 , qmp->dp_dp_phy +QSERDES_DP_PHY_CFG ); + +writel (0x04 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_AUXLESS_SETUP_CYC ); +writel (0x08 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_AUXLESS_SILENCE_CYC ); +writel (0x08 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_LFPS_CYC ); +writel (0x11 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_LFPS_PERIOD ); + +writel (0x3e , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_TSYNC_OVRD ); +writel (0x05 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_TX2_TX3_LANE_CTL ); +writel (0x05 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_TX0_TX1_LANE_CTL ); +writel (0x01 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_AUXLESS_CFG1 ); +writel (0x11 , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_LFPS_PERIOD ); +writel (0x1f , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_LN0_DRV_LVL ); +writel (0x1f , qmp->dp_dp_phy +QSERDES_V8_DP_PHY_LN1_DRV_LVL ); + +clk_set_rate (qmp->dp_link_hw.clk, dp_opts->link_rate *100000 ); +clk_set_rate (qmp->dp_pixel_hw.clk, pixel_freq); + +return 0 ; +} +static int qmp_v456_configure_dp_phy (struct qmp_combo *qmp) {const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -3108,7 +3397,7 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp)writel (0x05 , qmp->dp_dp_phy +QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL );writel (0x05 , qmp->dp_dp_phy +QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL ); - ret =qmp_combo_configure_dp_clocks (qmp); + ret = qmp->cfg->configure_dp_clocks (qmp);if (ret)return ret;
@@ -3222,6 +3511,62 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp)return 0 ; } +static int qmp_v8_configure_dp_phy (struct qmp_combo *qmp) +{ +const struct qmp_phy_cfg *cfg = qmp->cfg; +bool reverse = (qmp->orientation ==TYPEC_ORIENTATION_REVERSE ); +const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; +u32 bias0_en, drvr0_en, bias1_en, drvr1_en; +u32 status; +int ret; + + ret =qmp_v456_configure_dp_phy (qmp); +if (ret <0 ) +return ret; + +if (dp_opts->lanes ==1 ) { + bias0_en = reverse ?0x3e :0x15 ; + bias1_en = reverse ?0x15 :0x3e ; + drvr0_en = reverse ?0x13 :0x10 ; + drvr1_en = reverse ?0x10 :0x13 ; + }else if (dp_opts->lanes ==2 ) { + bias0_en = reverse ?0x3f :0x15 ; + bias1_en = reverse ?0x15 :0x3f ; + drvr0_en =0x10 ; + drvr1_en =0x10 ; + }else { + bias0_en =0x3f ; + bias1_en =0x3f ; + drvr0_en =0x34 ; + drvr1_en =0x34 ; + } + +writel (drvr0_en, qmp->dp_tx + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN ]); +writel (bias0_en, qmp->dp_tx + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN ]); +writel (drvr1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_HIGHZ_DRVR_EN ]); +writel (bias1_en, qmp->dp_tx2 + cfg->regs[QPHY_TX_TRANSCEIVER_BIAS_EN ]); + +writel (0x08 , qmp->dp_dp_phy +QSERDES_DP_PHY_CFG ); +udelay (100 ); +writel (0x09 , qmp->dp_dp_phy +QSERDES_DP_PHY_CFG ); +udelay (500 ); + +if (readl_poll_timeout (qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_STATUS ], + status, + ((status &BIT (1 )) >0 ), +500 , +10000 )) +return -ETIMEDOUT ; + +writel (0x00 , qmp->dp_tx + cfg->regs[QPHY_TX_TX_DRV_LVL ]); +writel (0x00 , qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_DRV_LVL ]); + +writel (0x2b , qmp->dp_tx + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL ]); +writel (0x2b , qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL ]); + +return 0 ; +} +/* * We need to calibrate the aux setting here as many times * as the caller tries
@@ -3316,8 +3661,10 @@ static int qmp_combo_com_init(struct qmp_combo *qmp, bool force) SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);/* override hardware control for reset of qmp phy */ -if (pcs_aon && cfg->regs[QPHY_AON_TOGGLE_ENABLE ]) +if (pcs_aon && cfg->regs[QPHY_AON_TOGGLE_ENABLE ]) {qphy_clrbits (pcs_aon, cfg->regs[QPHY_AON_TOGGLE_ENABLE ],0x1 ); +qphy_clrbits (pcs_aon, cfg->regs[QPHY_DP_AON_TOGGLE_ENABLE ],0x1 ); + }/* Use software based port select and switch on typec orientation */ val =SW_PORTSELECT_MUX ;
drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v8.h new file +25 -0
@@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Copyright (c) 2017, The Linux Foundation. All rights reserved. +*/ + +#ifndef QCOM_PHY_QMP_DP_PHY_V8_H_ +#define QCOM_PHY_QMP_DP_PHY_V8_H_ + +/* Only for QMP V8 PHY - DP PHY registers */ +#define QSERDES_V8_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V8_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 +#define QSERDES_V8_DP_PHY_TSYNC_OVRD 0x074 +#define QSERDES_V8_DP_PHY_TX0_TX1_LANE_CTL 0x078 +#define QSERDES_V8_DP_PHY_TX2_TX3_LANE_CTL 0x0bc +#define QSERDES_V8_DP_PHY_AUXLESS_CFG1 0x0c8 +#define QSERDES_V8_DP_PHY_LFPS_PERIOD 0x0d0 +#define QSERDES_V8_DP_PHY_LFPS_CYC 0x0d4 +#define QSERDES_V8_DP_PHY_AUXLESS_SETUP_CYC 0x0d8 +#define QSERDES_V8_DP_PHY_AUXLESS_SILENCE_CYC 0x0d8 +#define QSERDES_V8_DP_PHY_LN0_DRV_LVL 0x0e0 +#define QSERDES_V8_DP_PHY_LN1_DRV_LVL 0x0e4 +#define QSERDES_V8_DP_PHY_STATUS 0x114 + + +#endif
drivers/phy/qualcomm/phy-qcom-qmp-dp-qserdes-com-v8.h new file +52 -0
52 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1045/1376 phy: qcom: qmp-combo: Drop qmp_v4_calibrate_dp_phy
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Esteban Urrutia <[email protected]>
[ Upstream commit 8fd2b30d187fa33e5dd30699d3e3a3662c1610c9 ]
There are no downstream device trees that specify five values in the qcom,aux-cfg1-settings array.
Plus, after cross referencing both downstream device trees and entries which refer this function, only 0x13 is specified.
Since 0x13 is written at initialization time, drop this function as a whole, and remove now unused variable assignations.
--- drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 31 ----------------------- 1 file changed, 31 deletions(-)
drivers/phy/qualcomm/phy-qcom-qmp-combo.c +0 -31
@@ -2288,7 +2288,6 @@ static int qmp_v3_calibrate_dp_phy(struct qmp_combo *qmp);static void qmp_v4_dp_aux_init (struct qmp_combo *qmp);static void qmp_v4_configure_dp_tx (struct qmp_combo *qmp);static int qmp_v4_configure_dp_phy (struct qmp_combo *qmp); -static int qmp_v4_calibrate_dp_phy (struct qmp_combo *qmp);static void qmp_v8_dp_aux_init (struct qmp_combo *qmp);static int qmp_v8_configure_dp_clocks (struct qmp_combo *qmp);
@@ -2429,7 +2428,6 @@ static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v6_usb3phy_regs_layout, .reset_list = msm8996_usb3phy_reset_l,
@@ -2565,7 +2563,6 @@ static const struct qmp_phy_cfg sc8180x_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2612,7 +2609,6 @@ static const struct qmp_phy_cfg sc8280xp_usb43dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2658,7 +2654,6 @@ static const struct qmp_phy_cfg x1e80100_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2747,7 +2742,6 @@ static const struct qmp_phy_cfg sm8250_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2796,7 +2790,6 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .reset_list = msm8996_usb3phy_reset_l, .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
@@ -2844,7 +2837,6 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v6_usb3phy_regs_layout, .reset_list = msm8996_usb3phy_reset_l,
@@ -2890,7 +2882,6 @@ static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v6_usb3phy_regs_layout, .reset_list = msm8996_usb3phy_reset_l,
@@ -2936,7 +2927,6 @@ static const struct qmp_phy_cfg sm8750_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v3_configure_dp_clocks, .configure_dp_phy = qmp_v4_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v8_usb3phy_regs_layout, .reset_list = msm8996_usb3phy_reset_l,
@@ -2982,7 +2972,6 @@ static const struct qmp_phy_cfg glymur_usb3dpphy_cfg = { .configure_dp_tx = qmp_v4_configure_dp_tx, .configure_dp_clocks = qmp_v8_configure_dp_clocks, .configure_dp_phy = qmp_v8_configure_dp_phy, - .calibrate_dp_phy = qmp_v4_calibrate_dp_phy, .regs = qmp_v8_n3_usb43dpphy_regs_layout, .reset_list = msm8996_usb3phy_reset_l,
@@ -3278,7 +3267,6 @@ static void qmp_v4_dp_aux_init(struct qmp_combo *qmp)writel (0x03 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG7 );writel (0xb7 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG8 );writel (0x03 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG9 ); - qmp->dp_aux_cfg =0 ; writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
@@ -3307,7 +3295,6 @@ static void qmp_v8_dp_aux_init(struct qmp_combo *qmp)writel (0x03 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG7 );writel (0xb7 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG8 );writel (0x03 , qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG9 ); - qmp->dp_aux_cfg =0 ; writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK |
@@ -3567,24 +3554,6 @@ static int qmp_v8_configure_dp_phy(struct qmp_combo *qmp)return 0 ; } -/* -* We need to calibrate the aux setting here as many times -* as the caller tries -*/ -static int qmp_v4_calibrate_dp_phy (struct qmp_combo *qmp) -{ -static const u8 cfg1_settings[] = {0x20 ,0x13 ,0x23 ,0x1d }; -u8 val; - - qmp->dp_aux_cfg++; - qmp->dp_aux_cfg %=ARRAY_SIZE (cfg1_settings); - val = cfg1_settings[qmp->dp_aux_cfg]; - -writel (val, qmp->dp_dp_phy +QSERDES_DP_PHY_AUX_CFG1 ); - -return 0 ; -} -static int qmp_combo_dp_configure (struct phy *phy,union phy_configure_opts *opts) {const struct phy_configure_opts_dp *dp_opts = &opts->dp;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1046/1376 spi: sprd-adi: Fix probe succeeding without registering the controller
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Babanpreet Singh <[email protected]>
[ Upstream commit f092e1c935015ee0a0fea1a0374f4cab7b71953c ]
With CONFIG_HWSPINLOCK=n the of_hwspin_lock_get_id() stub returns 0 unconditionally. In sprd_adi_probe() the guard
if (ret > 0 || (IS_ENABLED(CONFIG_HWSPINLOCK) && ret == 0))
is false for that 0, so it takes the else branch, where the switch has no case for 0 and lands in
default: return dev_err_probe(&pdev->dev, ret, "failed to find hwlock id\n");
dev_err_probe() returns its err argument unchanged, so probe logs "failed to find hwlock id" and then returns 0, reporting success. sprd_adi_hw_init(), the restart handler and devm_spi_register_controller() are all skipped: the device binds but no SPI controller is ever registered.
The hardware spinlock is optional for this controller and the -ENOENT arm already covers "no hardware spinlock supplied". Treat the stub's 0 the same way and continue without a lock; all four users of sadi->hwlock already test it for NULL.
This is not reachable on production kernels. Kconfig has
depends on HWSPINLOCK || (COMPILE_TEST && !HWSPINLOCK)
so the affected configuration exists only under COMPILE_TEST, where no real hardware is present.
Found by smatch:drivers/spi/spi-sprd-adi.c:560 sprd_adi_probe() warn: passing zero to 'dev_err_probe'
--- drivers/spi/spi-sprd-adi.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/spi/spi-sprd-adi.c +6 -0
@@ -553,6 +553,12 @@ static int sprd_adi_probe(struct platform_device *pdev)return -ENXIO ; }else {switch (ret) { +case 0 : +/* +* Only reachable with CONFIG_HWSPINLOCK=n, where the +* of_hwspin_lock_get_id() stub returns 0. +*/ + fallthrough;case -ENOENT :dev_info (&pdev->dev,"no hardware spinlock supplied\n" );break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1047/1376 ASoC: qcom: q6apm: keep the graph start count in sync with the DSP
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jorijn van der Graaf <[email protected]>
[ Upstream commit daa7ffd765ae67a83e77dae32c66ce2d6d995d19 ]
q6apm_graph_start() increments start_count even when APM_CMD_GRAPH_START fails, leaving the graph counted as running while the DSP never started it. A later start - a retried prepare, or a resume after a failed start - then finds a non-zero count, skips the command and returns success with no data flowing.
Count the graph only once the DSP has accepted the start. The count then stays at zero for a graph that never started, so also stop decrementing below zero in q6apm_graph_stop(): the compressed free path stops unconditionally, and a negative count would make the next start skip the command in the same way.
--- sound/soc/qcom/qdsp6/q6apm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
sound/soc/qcom/qdsp6/q6apm.c +9 -3
@@ -697,14 +697,17 @@ EXPORT_SYMBOL_GPL(q6apm_graph_prepare);int q6apm_graph_start (struct q6apm_graph *graph) {struct audioreach_graph *ar_graph = graph->ar_graph; -int ret =0 ; +int ret; -if (ar_graph->start_count ==0 ) +if (ar_graph->start_count ==0 ) { ret =audioreach_graph_mgmt_cmd (ar_graph,APM_CMD_GRAPH_START ); +if (ret) +return ret; + } ar_graph->start_count++; -return ret; +return 0 ; }EXPORT_SYMBOL_GPL (q6apm_graph_start);
@@ -712,6 +715,9 @@ int q6apm_graph_stop(struct q6apm_graph *graph) {struct audioreach_graph *ar_graph = graph->ar_graph; +if (ar_graph->start_count ==0 ) +return 0 ; +if (--ar_graph->start_count >0 )return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1048/1376 powerpc/vdso: Add a page for non-time data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christophe Leroy <[email protected]>
[ Upstream commit c39b1dcf055d420a498d1047c645b776e4d1a7aa ]
The page containing VDSO time data is swapped with the one containing TIME namespace data when a process uses a non-root time namespace. For other data like powerpc specific data and RNG data, it means tracking whether time namespace is the root one or not to know which page to use.
Simplify the logic behind by moving time data out of first data page so that the first data page which contains everything else always remains the first page. Time data is in the second or third page depending on selected time namespace.
While we are playing with get_datapage macro, directly take into account the data offset inside the macro instead of adding that offset afterwards.
Stable-dep-of: 3f7c9f9c36b4 ("s390/irqflags: Add out-of-line definitions of arch_local_irq_*() for KMSAN")
--- arch/powerpc/include/asm/vdso_datapage.h | 24 +++++++----------------- arch/powerpc/kernel/vdso.c | 16 ++++++++++------ arch/powerpc/kernel/vdso/cacheflush.S | 2 +- arch/powerpc/kernel/vdso/datapage.S | 4 ++-- arch/powerpc/kernel/vdso/getrandom.S | 3 +-- arch/powerpc/kernel/vdso/gettimeofday.S | 5 ++--- arch/powerpc/kernel/vdso/vdso32.lds.S | 2 +- arch/powerpc/kernel/vdso/vdso64.lds.S | 2 +- 8 files changed, 25 insertions(+), 33 deletions(-)
arch/powerpc/include/asm/vdso_datapage.h +7 -17
@@ -82,8 +82,9 @@ struct vdso_arch_data {__u32 syscall_map[SYSCALL_MAP_SIZE ];/* Map of syscalls */ __u32 compat_syscall_map[SYSCALL_MAP_SIZE ];/* Map of compat syscalls */ -struct vdso_data data[CS_BASES ];struct vdso_rng_data rng_data; + + struct vdso_data data[CS_BASES] __aligned(1 << CONFIG_PAGE_SHIFT); };#else /* CONFIG_PPC64 */
@@ -95,8 +96,9 @@ struct vdso_arch_data {__u64 tb_ticks_per_sec;/* Timebase tics / sec 0x38 */ __u32 syscall_map[SYSCALL_MAP_SIZE ];/* Map of syscalls */ __u32 compat_syscall_map[0 ];/* No compat syscalls on PPC32 */ -struct vdso_data data[CS_BASES ];struct vdso_rng_data rng_data; + + struct vdso_data data[CS_BASES] __aligned(1 << CONFIG_PAGE_SHIFT); };#endif /* CONFIG_PPC64 */
@@ -105,29 +107,17 @@ extern struct vdso_arch_data *vdso_data;#else /* __ASSEMBLY__ */ -.macro get_datapage ptr +.macro get_datapage ptr offset=0 bcl 20, 31, .+4 999: mflr \ptr - addis \ptr, \ptr, (_vdso_datapage - 999b)@ha - addi \ptr, \ptr, (_vdso_datapage - 999b)@l + addis \ptr, \ptr, (_vdso_datapage - 999b + \offset)@ha + addi \ptr, \ptr, (_vdso_datapage - 999b + \offset)@l .endm#include <asm/asm-offsets.h> #include <asm/page.h> -.macro get_realdatapage ptr scratch - get_datapage \ptr -#ifdef CONFIG_TIME_NS - lwz \scratch, VDSO_CLOCKMODE_OFFSET(\ptr) - xoris \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@h - xori \scratch, \scratch, VDSO_CLOCKMODE_TIMENS@l - cntlzw \scratch, \scratch - rlwinm \scratch, \scratch, PAGE_SHIFT - 5, 1 << PAGE_SHIFT - add \ptr, \ptr, \scratch -#endif -.endm -#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */
arch/powerpc/kernel/vdso.c +10 -6
@@ -48,12 +48,13 @@ long sys_ni_syscall(void);*/ static union {struct vdso_arch_data data; -u8 page[PAGE_SIZE ]; +u8 page[2 *PAGE_SIZE ]; } vdso_data_store __page_aligned_data;struct vdso_arch_data *vdso_data = &vdso_data_store.data;enum vvar_pages { -VVAR_DATA_PAGE_OFFSET , +VVAR_BASE_PAGE_OFFSET , +VVAR_TIME_PAGE_OFFSET ,VVAR_TIMENS_PAGE_OFFSET ,VVAR_NR_PAGES , };
@@ -119,7 +120,7 @@ static struct vm_special_mapping vdso64_spec __ro_after_init = {#ifdef CONFIG_TIME_NS struct vdso_data *arch_get_vdso_data (void *vvar_page) { -return ((struct vdso_arch_data *)vvar_page)->data; +return vvar_page; }/*
@@ -153,11 +154,14 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,unsigned long pfn;switch (vmf->pgoff) { -case VVAR_DATA_PAGE_OFFSET : +case VVAR_BASE_PAGE_OFFSET : + pfn =virt_to_pfn (vdso_data); +break ; +case VVAR_TIME_PAGE_OFFSET :if (timens_page) pfn =page_to_pfn (timens_page);else - pfn =virt_to_pfn (vdso_data); + pfn =virt_to_pfn (vdso_data->data);break ;#ifdef CONFIG_TIME_NS case VVAR_TIMENS_PAGE_OFFSET :
@@ -170,7 +174,7 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,*/ if (!timens_page)return VM_FAULT_SIGBUS ; - pfn =virt_to_pfn (vdso_data); + pfn =virt_to_pfn (vdso_data->data);break ;#endif /* CONFIG_TIME_NS */ default :
arch/powerpc/kernel/vdso/cacheflush.S +1 -1
@@ -30,7 +30,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) #ifdef CONFIG_PPC64 mflr r12 .cfi_register lr,r12 - get_realdatapage r10, r11 + get_datapage r10 mtlr r12 .cfi_restore lr #endif
arch/powerpc/kernel/vdso/datapage.S +2 -2
@@ -28,7 +28,7 @@ V_FUNCTION_BEGIN(__kernel_get_syscall_map) mflr r12 .cfi_register lr,r12 mr. r4,r3 - get_realdatapage r3, r11 + get_datapage r3 mtlr r12 #ifdef __powerpc64__ addi r3,r3,CFG_SYSCALL_MAP64
@@ -52,7 +52,7 @@ V_FUNCTION_BEGIN(__kernel_get_tbfreq) .cfi_startproc mflr r12 .cfi_register lr,r12 - get_realdatapage r3, r11 + get_datapage r3 #ifndef __powerpc64__ lwz r4,(CFG_TB_TICKS_PER_SEC + 4)(r3) #endif
arch/powerpc/kernel/vdso/getrandom.S +1 -2
@@ -31,8 +31,7 @@ PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT #endif - get_realdatapage r8, r11 - addi r8, r8, VDSO_RNG_DATA_OFFSET + get_datapage r8 VDSO_RNG_DATA_OFFSET bl CFUNC(DOTSYM(\funct)) PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1) #ifdef __powerpc64__
arch/powerpc/kernel/vdso/gettimeofday.S +2 -3
@@ -32,11 +32,10 @@ PPC_STL r2, PPC_MIN_STKFRM + STK_GOT(r1) .cfi_rel_offset r2, PPC_MIN_STKFRM + STK_GOT #endif - get_datapage r5 .ifeq \call_time - addi r5, r5, VDSO_DATA_OFFSET + get_datapage r5 VDSO_DATA_OFFSET .else - addi r4, r5, VDSO_DATA_OFFSET + get_datapage r4 VDSO_DATA_OFFSET .endif bl CFUNC(DOTSYM(\funct)) PPC_LL r0, PPC_MIN_STKFRM + PPC_LR_STKOFF(r1)
arch/powerpc/kernel/vdso/vdso32.lds.S +1 -1
@@ -16,7 +16,7 @@ OUTPUT_ARCH(powerpc:common) SECTIONS { - PROVIDE(_vdso_datapage = . - 2 * PAGE_SIZE); + PROVIDE(_vdso_datapage = . - 3 * PAGE_SIZE); . = SIZEOF_HEADERS; .hash : { *(.hash) } :text
arch/powerpc/kernel/vdso/vdso64.lds.S +1 -1
@@ -16,7 +16,7 @@ OUTPUT_ARCH(powerpc:common64) SECTIONS { - PROVIDE(_vdso_datapage = . - 2 * PAGE_SIZE); + PROVIDE(_vdso_datapage = . - 3 * PAGE_SIZE); . = SIZEOF_HEADERS; .hash : { *(.hash) } :text
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 1049/1376 powerpc: Use str_enabled_disabled() helper function
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 19e0a70e6c3c1bf800b8ce9eb45864aa9e1e2781 ]
Remove hard-coded strings by using the str_enabled_disabled() helper function.
Stable-dep-of: 3f7c9f9c36b4 ("s390/irqflags: Add out-of-line definitions of arch_local_irq_*() for KMSAN")
--- arch/powerpc/kernel/secure_boot.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/powerpc/kernel/secure_boot.c +3 -2
@@ -5,6 +5,7 @@*/ #include <linux/types.h> #include <linux/of.h> +#include <linux/string_choices.h> #include <asm/secure_boot.h> static struct device_node *get_ppc_fw_sb_node (void )
@@ -38,7 +39,7 @@ bool is_ppc_secureboot_enabled(void)of_node_put (node); out: -pr_info ("Secure boot mode %s\n" , enabled ?"enabled" :"disabled" ); +pr_info ("Secure boot mode %s\n" ,str_enabled_disabled (enabled));return enabled; }
@@ -62,7 +63,7 @@ bool is_ppc_trustedboot_enabled(void)of_node_put (node); out: -pr_info ("Trusted boot mode %s\n" , enabled ?"enabled" :"disabled" ); +pr_info ("Trusted boot mode %s\n" ,str_enabled_disabled (enabled));return enabled; }
Signature · 1 line
2.53.0